Index: openacs-4/packages/dotlrn-messages/tcl/apm-callback-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-messages/tcl/apm-callback-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/dotlrn-messages/tcl/apm-callback-procs.tcl 31 Aug 2010 21:32:23 -0000 1.1 @@ -0,0 +1,57 @@ +ad_library { + Procedures for registering implementations for the + dotLRN Messages package. + + @creation-date 2010-01-20 + @author Pedro Castellanos (pedro@viaro.net) +} + +namespace eval dotlrn_messages {} + +ad_proc -public dotlrn_messages::install {} { + dotLRN messages package install proc +} { + register_portal_datasource_impl +} + +ad_proc -public dotlrn_messages::uninstall {} { + dotLRN messages package uninstall proc +} { + unregister_portal_datasource_impl +} + +ad_proc -public dotlrn_messages::register_portal_datasource_impl {} { + Register the service contract implementation for the dotlrn_applet service contract +} { + set spec { + name "dotlrn_messages" + contract_name "dotlrn_applet" + owner "dotlrn-messages" + aliases { + GetPrettyName dotlrn_messages::get_pretty_name + AddApplet dotlrn_messages::add_applet + RemoveApplet dotlrn_messages::remove_applet + AddAppletToCommunity dotlrn_messages::add_applet_to_community + RemoveAppletFromCommunity dotlrn_messages::remove_applet_from_community + AddUser dotlrn_messages::add_user + RemoveUser dotlrn_messages::remove_user + AddUserToCommunity dotlrn_messages::add_user_to_community + RemoveUserFromCommunity dotlrn_messages::remove_user_from_community + AddPortlet dotlrn_messages::add_portlet + RemovePortlet dotlrn_messages::remove_portlet + Clone dotlrn_messages::clone + ChangeEventHandler dotlrn_messages::change_event_handler + } + } + + acs_sc::impl::new_from_spec -spec $spec +} + +ad_proc -public dotlrn_messages::unregister_portal_datasource_impl {} { + Unregister service contract implementations +} { + acs_sc::impl::delete \ + -contract_name "dotlrn_applet" \ + -impl_name "dotlrn_messages" +} + Index: openacs-4/packages/dotlrn-messages/tcl/dotlrn-messages-procs-oracle.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-messages/tcl/dotlrn-messages-procs-oracle.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/dotlrn-messages/tcl/dotlrn-messages-procs-oracle.xql 31 Aug 2010 21:32:23 -0000 1.1 @@ -0,0 +1,24 @@ +<?Xml version="1.0"?> + +<queryset> +<rdbms><type>oracle</type><version>8.1.6</version></rdbms> + + +<fullquery name="dotlrn_messages::remove_applet.delete_applet_from_communities"> + <querytext> + + delete from dotlrn_community_applets where applet_id = :applet_id + + </querytext> +</fullquery> + +<fullquery name="dotlrn_messages::remove_applet.delete_applet"> + <querytext> + + delete from dotlrn_applets where applet_id = :applet_id + + </querytext> +</fullquery> + +</queryset> + Index: openacs-4/packages/dotlrn-messages/tcl/dotlrn-messages-procs-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-messages/tcl/dotlrn-messages-procs-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/dotlrn-messages/tcl/dotlrn-messages-procs-postgresql.xql 31 Aug 2010 21:32:23 -0000 1.1 @@ -0,0 +1,24 @@ +<?Xml version="1.0"?> + +<queryset> +<rdbms><type>postgresql</type><version>7.1</version></rdbms> + + +<fullquery name="dotlrn_messages::remove_applet.delete_applet_from_communities"> + <querytext> + + delete from dotlrn_community_applets where applet_id = :applet_id + + </querytext> +</fullquery> + +<fullquery name="dotlrn_messages::remove_applet.delete_applet"> + <querytext> + + delete from dotlrn_applets where applet_id = :applet_id + + </querytext> +</fullquery> + +</queryset> + Index: openacs-4/packages/dotlrn-messages/tcl/dotlrn-messages-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-messages/tcl/dotlrn-messages-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/dotlrn-messages/tcl/dotlrn-messages-procs.tcl 31 Aug 2010 21:32:23 -0000 1.1 @@ -0,0 +1,201 @@ +ad_library { + + Procs to set up the dotLRN messages applet + + @author Pedro Castellanos (pedro@viaro.net) + @creation-date 2010-01-20 +} + +namespace eval dotlrn_messages {} + +ad_proc -public dotlrn_messages::applet_key {} { + What's my applet key? +} { + return dotlrn_messages +} + +ad_proc -public dotlrn_messages::package_key {} { + What package do I deal with? +} { + return "messages" +} + +ad_proc -public dotlrn_messages::my_package_key {} { + What package do I deal with? +} { + return "dotlrn-messages" +} + +ad_proc -public dotlrn_messages::get_pretty_name {} { + returns the pretty name +} { + return "#messages.messages#" +} + +ad_proc -public dotlrn_messages::add_applet {} { + One time init - must be repeatable! +} { + dotlrn_applet::add_applet_to_dotlrn -applet_key [applet_key] -package_key [my_package_key] +} + +ad_proc -public dotlrn_messages::remove_applet {} { + One time destroy. +} { + set applet_id [dotlrn_applet::get_applet_id_from_key [my_package_key]] + db_exec_plsql delete_applet_from_communities { *SQL* } + db_exec_plsql delete_applet { *SQL* } +} + +ad_proc -public dotlrn_messages::add_applet_to_community { + community_id +} { + Add the messages applet to a specifc dotlrn community +} { + set portal_id [dotlrn_community::get_portal_id -community_id $community_id] + + # create the messages package instance + set package_id [dotlrn::instantiate_and_mount $community_id [package_key]] + + # set up the admin portal + set admin_portal_id [dotlrn_community::get_admin_portal_id \ + -community_id $community_id + ] + + #messages_admin_portlet::add_self_to_page \ + #-portal_id $admin_portal_id \ + #-package_id $package_id + +# AR: There will be no portlet, just the admin one + set args [ns_set create] + ns_set put $args package_id $package_id + add_portlet_helper $portal_id $args + + return $package_id +} + +ad_proc -public dotlrn_messages::remove_applet_from_community { + community_id +} { + remove the applet from the community +} { + ad_return_complaint 1 "[applet_key] remove_applet_from_community not implimented!" +} + +ad_proc -public dotlrn_messages::add_user { + user_id +} { + one time user-specifuc init +} { + # noop +} + +ad_proc -public dotlrn_messages::remove_user { + user_id +} { +} { + # noop +} + +ad_proc -public dotlrn_messages::add_user_to_community { + community_id + user_id +} { + Add a user to a specifc dotlrn community +} { + set package_id [dotlrn_community::get_applet_package_id -community_id $community_id -applet_key [applet_key]] + set portal_id [dotlrn::get_portal_id -user_id $user_id] + + # use "append" here since we want to aggregate +# AR: There will be no portlet, just the admin one + set args [ns_set create] + ns_set put $args package_id $package_id + ns_set put $args param_action append + add_portlet_helper $portal_id $args +} + +ad_proc -public dotlrn_messages::remove_user_from_community { + community_id + user_id +} { + Remove a user from a community +} { + set package_id [dotlrn_community::get_applet_package_id -community_id $community_id -applet_key [applet_key]] + set portal_id [dotlrn::get_portal_id -user_id $user_id] + +# AR: There will be no portlet, just the admin one + set args [ns_set create] + ns_set put $args package_id $package_id + + remove_portlet $portal_id $args +} + +ad_proc -public dotlrn_messages::add_portlet { + portal_id +} { + A helper proc to add the underlying portlet to the given portal. + + @param portal_id +} { + # simple, no type specific stuff, just set some dummy values +# AR: There will be no portlet, just the admin one + set args [ns_set create] + ns_set put $args package_id 0 + ns_set put $args param_action overwrite + add_portlet_helper $portal_id $args +} + +ad_proc -public dotlrn_messages::add_portlet_helper { + portal_id + args +} { + A helper proc to add the underlying portlet to the given portal. + + @param portal_id + @param args an ns_set +} { +# AR: There will be no portlet, just the admin one + messages_portlet::add_self_to_page \ + -portal_id $portal_id \ + -package_id [ns_set get $args package_id] \ + -param_action [ns_set get $args param_action] +} + +ad_proc -public dotlrn_messages::remove_portlet { + portal_id + args +} { + A helper proc to remove the underlying portlet from the given portal. + + @param portal_id + @param args A list of key-value pairs (possibly user_id, community_id, and more) +} { + messages_portlet::remove_self_from_page \ + -portal_id $portal_id \ + -package_id [ns_set get $args package_id] +} + +ad_proc -public dotlrn_messages::clone { + old_community_id + new_community_id +} { + Clone this applet's content from the old community to the new one +} { + ns_log notice "Cloning: [applet_key]" + set new_package_id [add_applet_to_community $new_community_id] + set old_package_id [dotlrn_community::get_applet_package_id \ + -community_id $old_community_id \ + -applet_key [applet_key] + ] + + return $new_package_id +} + +ad_proc -public dotlrn_messages::change_event_handler { + community_id + event + old_value + new_value +} { + listens for the following events: +} { +} Index: openacs-4/packages/messages/catalog/messages.en_US.ISO-8859-1.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/catalog/messages.en_US.ISO-8859-1.xml,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/catalog/messages.en_US.ISO-8859-1.xml 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<message_catalog package_key="messages" locale="en_US" charset="ISO-8859-1"> + + <msg key="add">Add</msg> + <msg key="add_attachment">Add attachment</msg> + <msg key="as_read">Mark as read</msg> + <msg key="as_unread">Mark as unread</msg> + <msg key="at">At</msg> + <msg key="attachments">Attachments</msg> + <msg key="back"><< Back</msg> + <msg key="back_folders">Back Folders</msg> + <msg key="body_empty">Send this message without text in the body?</msg> + <msg key="body_mail">%user_name% has sent you a message: + +------------------------------------- + +%subject% + +%msg_content% + +------------------------------------- + + +You can see from the following link: + +http://yourpage.com/%message_url%</msg> + <msg key="cancel">Cancel</msg> + <msg key="close_window">Close Window</msg> + <msg key="community">Community</msg> + <msg key="compose_mail">Compose Mail</msg> + <msg key="configuration">Configuration</msg> + <msg key="confirm_send_msg">Your message has been sent</msg> + <msg key="confirm_trash_empty">All messages in the Trash have been deleted forever</msg> + <msg key="create">Create</msg> + <msg key="date">Date</msg> + <msg key="delete">Delete</msg> + <msg key="delete_confirm">Do you want to continue?</msg> + <msg key="discard">Discard</msg> + <msg key="drafts">Drafts</msg> + <msg key="edit_folder">To edit the name click on the name of the folder</msg> + <msg key="edit_name_folder">Edit</msg> + <msg key="empty_trash">Empty Trash now</msg> + <msg key="folder_create_successfully">Folder created successfully</msg> + <msg key="folder_name">Folder name</msg> + <msg key="folder_trash_msg">(messages that have been in Trash more than 15 days will be automatically deleted)</msg> + <msg key="folders">Folders</msg> + <msg key="folders_created">Folders created</msg> + <msg key="forward">Forward</msg> + <msg key="from">From</msg> + <msg key="has_been_moved_to">The conversation has been moved to</msg> + <msg key="hide_details">Hide details</msg> + <msg key="important">Important</msg> + <msg key="inbox">Inbox</msg> + <msg key="insert_signature">Insert signature</msg> + <msg key="lt_folder_name_error">The name of the folder may not be longer than 20 characters</msg> + <msg key="max_show_messages">Conversations per page</msg> + <msg key="me">me</msg> + <msg key="message">Message</msg> + <msg key="message_sent_by">Message sent by</msg> + <msg key="messages">Messages</msg> + <msg key="more_actions">More actions</msg> + <msg key="more_msg_moved_to">conversations have been moved to</msg> + <msg key="more_msg_read">conversations have been marked as read.</msg> + <msg key="more_msg_unread">conversations have been marked as unread.</msg> + <msg key="move_to">Move to</msg> + <msg key="msg_cancel">The information be lost. Do you want to continue?</msg> + <msg key="msg_continue_empty">This action will affect %total_messages% conversation(s) in Trash. Are you sure you want to continue?</msg> + <msg key="msg_delete_folder">The folder is deleted, the messages are moved out to receive. Are sure to continue?</msg> + <msg key="msg_has_been_sent">Your message has been sent.</msg> + <msg key="msg_invalid_number">You must enter valid number in size of folder</msg> + <msg key="msg_invalid_user">is an invalid user. </msg> + <msg key="msg_loading">Loading</msg> + <msg key="msg_read">The conversation has been marked as read.</msg> + <msg key="msg_select_msg">You must select at least one message</msg> + <msg key="msg_subject_forward">fwd</msg> + <msg key="msg_subject_reply">Re</msg> + <msg key="msg_system">Messaging system: to send messages to people who belong to this group if you want to send messages to a person belonging to another group, you ought to go to that course/community and send from there.</msg> + <msg key="msg_unread">The conversation has been marked as unread.</msg> + <msg key="name_new_folder">Write the name of the new Folder</msg> + <msg key="new_folder">New Folder</msg> + <msg key="new_folder_name_error">Please, write a name of the new folder</msg> + <msg key="newer">< Newer</msg> + <msg key="newer_msg">Newer</msg> + <msg key="newest"><< Newest</msg> + <msg key="no">No</msg> + <msg key="no_members_found">No members found</msg> + <msg key="no_messages_found">You don't have any messages here.</msg> + <msg key="no_subject">no subject</msg> + <msg key="normal">Normal</msg> + <msg key="of">Of</msg> + <msg key="older">Older ></msg> + <msg key="older_msg">Older</msg> + <msg key="oldest">Oldest >></msg> + <msg key="other_msg_reply">You are answering another message.</msg> + <msg key="print">Print</msg> + <msg key="range_messages_show">%first_row% -- %last_number% Of %total_messages%</msg> + <msg key="recipients">Recipients</msg> + <msg key="recipients_empty">Please specify at least one recipient.</msg> + <msg key="reply">Reply</msg> + <msg key="reply_all">Reply all</msg> + <msg key="save">Save</msg> + <msg key="save_info">Save</msg> + <msg key="save_sent_message">Save sent message</msg> + <msg key="search">Search</msg> + <msg key="send">Send</msg> + <msg key="send_to_all">Send to everyone</msg> + <msg key="sending">Sending</msg> + <msg key="sent">Sent</msg> + <msg key="show_details">Show details</msg> + <msg key="signature">Signature</msg> + <msg key="subject">Subject</msg> + <msg key="subject_empty">Send message without a subject?</msg> + <msg key="subject_mail">%user_name% has sent you a message in the community "%community_name%"</msg> + <msg key="sucsessful_create_folder">Sucsessful create folder</msg> + <msg key="to">To</msg> + <msg key="to_help">[i] If you know the name and/or last name of the user that sends the message, type it into the text field and will show to users who match the writing in this field</msg> + <msg key="today">Today</msg> + <msg key="trash">Trash</msg> + <msg key="view_messages">View messages</msg> + <msg key="write_message">Write message</msg> + <msg key="write_message_to">Writing message to</msg> + <msg key="yes">Yes</msg> +</message_catalog> Index: openacs-4/packages/messages/catalog/messages.es_ES.ISO-8859-1.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/catalog/messages.es_ES.ISO-8859-1.xml,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/catalog/messages.es_ES.ISO-8859-1.xml 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<message_catalog package_key="messages" locale="es_ES" charset="ISO-8859-1"> + + <msg key="add">Agregar</msg> + <msg key="add_attachment">Adjuntar archivo</msg> + <msg key="as_read">Marcar como leido</msg> + <msg key="as_unread">Marcar como no le�do</msg> + <msg key="at">de</msg> + <msg key="attachments">Archivos adjuntos</msg> + <msg key="back">&lt;&lt; Regresar</msg> + <msg key="back_folders">Regresar a Carpetas</msg> + <msg key="body_empty">�Deseas enviar este mensaje sin texto?</msg> + <msg key="body_mail">%user_name% te ha enviado un mensaje: + +------------------------------------- + +%subject% + +%msg_content% + +------------------------------------- + +lo puedes ver en el siguiente enlace: + +http://yourpage.com/%message_url% + +</msg> + <msg key="cancel">Cancelar</msg> + <msg key="close_window">Cerrar Ventana</msg> + <msg key="community">Comunidad</msg> + <msg key="compose_mail">Redactar Correo</msg> + <msg key="configuration">Configuraci�n</msg> + <msg key="confirm_send_msg">Tu mensaje ha sido enviado.</msg> + <msg key="confirm_trash_empty">Todos los mensajes de la papelera se han suprimido definitivamente</msg> + <msg key="create">Crear</msg> + <msg key="date">Fecha</msg> + <msg key="delete">Borrar</msg> + <msg key="delete_confirm">�Desea continuar?</msg> + <msg key="discard">Descartar</msg> + <msg key="drafts">Borradores</msg> + <msg key="edit_folder">Para editar el nombre, haga click sobre el nombre del folder.</msg> + <msg key="edit_name_folder">Editar</msg> + <msg key="empty_trash">Vaciar la Papelera ahora</msg> + <msg key="folder_create_successfully">El folder se ha creado satisfactoriamente</msg> + <msg key="folder_name">Nombre del Folder</msg> + <msg key="folder_trash_msg">(los mensajes que se encuentren en la Papelera durante m�s de 15 d�as se suprimir�n autom�ticamente)</msg> + <msg key="folders">Carpetas</msg> + <msg key="folders_created">Carpetas creadas</msg> + <msg key="forward">Reenviar</msg> + <msg key="from">De</msg> + <msg key="has_been_moved_to">La conversaci�n se ha movido a</msg> + <msg key="hide_details">Ocultar Detalles</msg> + <msg key="important">Importante</msg> + <msg key="inbox">Recibidos</msg> + <msg key="insert_signature">Insertar firma</msg> + <msg key="lt_folder_name_error">El nombre del folder no puede ser mayor a 20 caracteres.</msg> + <msg key="max_show_messages">Mensajes por p�gina</msg> + <msg key="me">Usuario</msg> + <msg key="message">Mensaje</msg> + <msg key="message_sent_by">Mensaje enviado por</msg> + <msg key="messages">Mensajes</msg> + <msg key="more_actions">M�s acciones</msg> + <msg key="more_msg_moved_to">conversaciones se han movido a</msg> + <msg key="more_msg_read">conversaciones se han marcado como le�das.</msg> + <msg key="more_msg_unread">conversaciones se han marcado como no le�das.</msg> + <msg key="move_to">Mover a</msg> + <msg key="msg_cancel">La informaci�n se perder�. �Desea continuar?</msg> + <msg key="msg_continue_empty">Esta acci�n afectara a %total_messages% conversaci�n(es) en Papelera. �Esta seguro de que deseas continuar?</msg> + <msg key="msg_delete_folder">La carpeta se elimina, los mensajes se mover�n a Recibidos. �Est� seguro de continuar?</msg> + <msg key="msg_has_been_sent">Tu mensaje ha sido enviado.</msg> + <msg key="msg_invalid_number">Debe de ingresar n�mero v�lido en mensajes por folder</msg> + <msg key="msg_invalid_user">es un usuario no v�lido.</msg> + <msg key="msg_loading">Cargando</msg> + <msg key="msg_read">La conversaci�n se ha marcado como le�da.</msg> + <msg key="msg_select_msg">Debe de seleccionar al menos un mensaje</msg> + <msg key="msg_subject_forward">Rv</msg> + <msg key="msg_subject_reply">Re</msg> + <msg key="msg_system">Sistema de env�o de mensajes: permite enviar mensajes a las personas que pertenecen a este grupo, si deseas enviar mensajes a una persona que pertenece a otro grupo, debeis ir a dicho curso/comunidad y enviar el mensaje desde alli.</msg> + <msg key="msg_unread">La conversaci�n se ha marcado como no le�da.</msg> + <msg key="name_new_folder">Escribir el nombre del nuevo folder</msg> + <msg key="new_folder">Nuevo Folder</msg> + <msg key="new_folder_name_error">Por favor, escriba el nombre del nuevo folder</msg> + <msg key="newer">&lt; Anterior</msg> + <msg key="newer_msg">Anterior</msg> + <msg key="newest">&lt;&lt; Primera p�gina </msg> + <msg key="no">No</msg> + <msg key="no_members_found">No se ha encontrado ning�n miembro.</msg> + <msg key="no_messages_found">Usted no tiene ning�n mensaje.</msg> + <msg key="no_subject">sin asunto</msg> + <msg key="normal">Normal</msg> + <msg key="of">De</msg> + <msg key="older">Siguiente &gt;</msg> + <msg key="older_msg">Posterior</msg> + <msg key="oldest">�ltima p�gina &gt;&gt;</msg> + <msg key="other_msg_reply">Usted est� respondiendo un mensaje.</msg> + <msg key="print">Imprimir</msg> + <msg key="range_messages_show">%first_row% -- %last_number% De %total_messages%</msg> + <msg key="recipients">Destinatarios</msg> + <msg key="recipients_empty">Especifica al menos un destinatario.</msg> + <msg key="reply">Responder</msg> + <msg key="reply_all">Responder a todos</msg> + <msg key="save">Guardados</msg> + <msg key="save_info">Guardar</msg> + <msg key="save_sent_message">Guardar mensaje enviado</msg> + <msg key="search">Buscar</msg> + <msg key="send">Enviar</msg> + <msg key="send_to_all">Enviar a todos</msg> + <msg key="sending">Enviando</msg> + <msg key="sent">Enviados</msg> + <msg key="show_details">Mostrar detalles</msg> + <msg key="signature">Firma</msg> + <msg key="subject">Asunto</msg> + <msg key="subject_empty">�Deseas enviar este mensaje sin asunto?</msg> + <msg key="subject_mail">%user_name% te ha enviado un mensaje en la comunidad "%community_name%"</msg> + <msg key="sucsessful_create_folder">Folder creado satisfactoriamente</msg> + <msg key="to">Para</msg> + <msg key="to_help">[i] Si conoce el nombre y/o apellidos del usuario al que le envia el mensaje, escr�balo en el campo de texto Para y se le mostrar�n aquellos usuarios que coincidan con lo escrito en dicho campo</msg> + <msg key="today">Hoy</msg> + <msg key="trash">Papelera</msg> + <msg key="view_messages">Ver mensajes</msg> + <msg key="write_message">Redactar correo</msg> + <msg key="yes">Si</msg> +</message_catalog> Index: openacs-4/packages/messages/sql/oracle/messages-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/sql/oracle/messages-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/sql/oracle/messages-create.sql 31 Aug 2010 21:29:50 -0000 1.1 @@ -0,0 +1,114 @@ +-- +-- Assessment Package +-- +-- @author pedro@viaro.net +-- @creation-date 2009-10-30 +-- + + +create sequence messages_msg_sequence start with 1; +--messages +create table messages_messages ( + msg_id integer not null + constraint messages_messages_msg_id_pk + primary key, + owner_id integer not null, + community_id integer not null, + sent_date date default sysdate not null, + parent_id integer, + mime_type varchar2(200) default 'text/plain', + subject varchar2(200), + msg_content clob +); + +create index messages_community_id_index on messages_messages(community_id); +create index messages_parent_id_index on messages_messages(parent_id); + +--recipients mail + +create table messages_recipients ( + msg_id integer not null + constraint recipients_party_id_fk + references messages_messages(msg_id) + on delete cascade, + party_id integer not null + constraint recipients_msg_id_fk + references parties(party_id) + on delete cascade, + constraint messages_recipients_pk primary key (msg_id, party_id) +); + +create table messages_recipients_roles ( + msg_id integer not null + constraint recipients_roles_msg_id_fk + references messages_messages(msg_id) + on delete cascade, + rel_id varchar(100) not null + constraint recipients_rel_id_fk + references acs_rel_types (rel_type) + on delete cascade, + constraint messages_recipients_rel_pk primary key (msg_id, rel_id) +); + +--Attachments +create table messages_attachments ( + msg_id integer not null + constraint messages_attachment_msg_id_fk + references messages_messages + on delete cascade, + attachment_id integer not null, + attachment_item_id integer not null, + constraint msg_attachment_pk primary key (msg_id,attachment_id) +); + +--user messages to specific folder +create table messages_user_messages ( + msg_id integer not null + constraint user_messages_msg_id_fk + references messages_messages + on delete cascade, + user_id integer not null + constraint user_messages_user_id_fk + references users + on delete cascade, + parent_id integer + constraint user_msg_parent_id_fk + references messages_messages(msg_id) + on delete cascade, + folder_id integer default 0, + new_p char default 't' + check (new_p in ('t','f')), + constraint messages_user_messages_pk primary key (msg_id,user_id,folder_id) +); + +create index user_messages_user_id_index on messages_user_messages(user_id); + +--user folders +create sequence messages_folders_sequence start with 5; +create table messages_folders ( + user_id integer + constraint messages_folders_user_id_fk + references users + on delete cascade, + folder_id integer not null, + folder_name varchar(50) not null +); + +insert into messages_folders values(0,0,'#messages.inbox#'); +insert into messages_folders values(0,1,'#messages.sent#'); +insert into messages_folders values(0,2,'#messages.save#'); +insert into messages_folders values(0,3,'#messages.trash#'); + + +--message configuration +create table messages_options ( + user_id integer + constraint messages_options_pk + primary key + constraint messages_options_user_fk + references users, + max_messages integer default 50, + save_sent_p integer default 1, + signature_p integer default 0, + signature varchar2(1000) default '' +); Index: openacs-4/packages/messages/sql/oracle/messages-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/sql/oracle/messages-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/sql/oracle/messages-drop.sql 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,9 @@ +drop sequence messages_msg_sequence; +drop table messages_recipients +drop table messages_attachments; +drop table messages_user_messages; +drop index messages_user_messages_index; +drop sequence messages_folders_sequence; +drop table messages_folders; +drop table messages_options; +drop table messages_messages; \ No newline at end of file Index: openacs-4/packages/messages/sql/postgresql/messages-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/sql/postgresql/messages-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/sql/postgresql/messages-create.sql 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,137 @@ +-- +-- Assessment Package +-- +-- @author pedro@viaro.net +-- @creation-date 2009-10-30 +-- + + +create sequence messages_msg_sequence start with 1; +--messages +create table messages_messages ( + msg_id integer not null + constraint messages_messages_msg_id_pk + primary key, + owner_id integer not null, + community_id integer not null, + sent_date timestamp default now() not null, + parent_id integer, + mime_type varchar(200) default 'text/plain', + subject varchar(200), + msg_content text +); + +create index messages_community_id_index on messages_messages(community_id); +create index messages_parent_id_index on messages_messages(parent_id); + +--recipients mail + +create table messages_recipients ( + msg_id integer not null + constraint recipients_party_id_fk + references messages_messages(msg_id) + on delete cascade, + party_id integer not null + constraint recipients_msg_id_fk + references parties(party_id) + on delete cascade, + constraint messages_recipients_pk primary key (msg_id, party_id) +); + +create table messages_recipients_roles ( + msg_id integer not null + constraint recipients_roles_msg_id_fk + references messages_messages(msg_id) + on delete cascade, + rel_id varchar(100) not null + constraint recipients_rel_id_fk + references acs_rel_types (rel_type) + on delete cascade, + constraint messages_recipients_rel_pk primary key (msg_id, rel_id) +); + +--Attachments +create table messages_attachments ( + msg_id integer not null + constraint messages_attachment_msg_id_fk + references messages_messages + on delete cascade, + attachment_id integer not null, + attachment_item_id integer not null, + constraint msg_attachment_pk primary key (msg_id,attachment_id) +); + +--user messages to specific folder +create table messages_user_messages ( + msg_id integer not null + constraint user_messages_msg_id_fk + references messages_messages + on delete cascade, + user_id integer not null + constraint user_messages_user_id_fk + references users + on delete cascade, + parent_id integer + constraint user_msg_parent_id_fk + references messages_messages(msg_id) + on delete cascade, + folder_id integer default 0, + new_p char default 't' + check (new_p in ('t','f')), + constraint messages_user_messages_pk primary key (msg_id,user_id,folder_id) +); + +create index user_messages_user_id_index on messages_user_messages(user_id); + +--user folders +create sequence messages_folders_sequence start with 5; +create table messages_folders ( + user_id integer + constraint messages_folders_user_id_fk + references users + on delete cascade, + folder_id integer not null, + folder_name varchar(50) not null +); + +insert into messages_folders values(0,0,'#messages.inbox#'); +insert into messages_folders values(0,1,'#messages.sent#'); +insert into messages_folders values(0,2,'#messages.save#'); +insert into messages_folders values(0,3,'#messages.trash#'); + + +--message configuration +create table messages_options ( + user_id integer + constraint messages_options_pk + primary key + constraint messages_options_user_fk + references users, + max_messages integer default 50, + save_sent_p integer default 1, + signature_p integer default 0, + signature varchar(1000) default '' +); + + +CREATE FUNCTION concat (text, text) RETURNS text AS $$ + DECLARE + t text; + BEGIN + IF character_length($1) > 0 THEN + t = $1 ||', '|| $2; + ELSE + t = $2; + END IF; + RETURN t; + END; +$$ LANGUAGE plpgsql; + + +CREATE AGGREGATE concat ( + BASETYPE = text, + SFUNC = textcat, + STYPE = text, + INITCOND = '' +); + Index: openacs-4/packages/messages/sql/postgresql/messages-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/sql/postgresql/messages-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/sql/postgresql/messages-drop.sql 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,12 @@ +drop sequence messages_msg_sequence; +drop index messages_community_id_index; +drop index messages_parent_id_index; +drop table messages_recipients; +drop table messages_recipients_roles; +drop table messages_attachments; +drop table messages_user_messages; +drop index user_messages_user_id_index; +drop sequence messages_folders_sequence; +drop table messages_folders; +drop table messages_options; +drop table messages_messages cascade; \ No newline at end of file Index: openacs-4/packages/messages/tcl/apm-callback-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/tcl/apm-callback-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/tcl/apm-callback-procs.tcl 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,43 @@ +# /packages/messages/tcl/apm-callback-procs.tcl + +ad_library { + + Messages Package APM callbacks library + + Procedures that deal with installing, instantiating, mounting. + + @author pedro@viaro.net + @creation-date 2009-11-26 + +} + +namespace eval messages {} +namespace eval messages::apm {} + +ad_proc -public messages::apm::package_install { + +} { + Does the integration whith the notifications package. +} { + db_transaction { + #Create the conten types + content::type::new -content_type {messages_attachments} -supertype {content_revision} -pretty_name {Message Attachment} -pretty_plural {Message Attachments} -table_name {messages_attachments} -id_column {attachment_id} + + #Create content type attributes for content type messages + content::type::attribute::new -content_type {messages_attachments} -attribute_name {attachment_item_id} -datatype {number} -pretty_name {Attachment Item ID} -column_spec {integer} + content::type::attribute::new -content_type {messages_attachments} -attribute_name {msg_id} -datatype {number} -pretty_name {Message ID} -column_spec {integer} + } +} + +ad_proc -public messages::apm::package_instantiate { + -package_id:required +} { + + Define Message folders + +} { + # create a content folder + set folder_id [content::folder::new -name "messages_attachments_$package_id" -label "messages_attachments_$package_id" -package_id $package_id ] + # register the allowed content types for a folder + content::folder::register_content_type -folder_id $folder_id -content_type messages_attachments -include_subtypes t +} \ No newline at end of file Index: openacs-4/packages/messages/tcl/messages-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/tcl/messages-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/tcl/messages-procs.tcl 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,285 @@ +ad_library { + Procedures in the messages namespace. + + @creation-date 12-28-2009 + @author pedro@viaro.net +} + +namespace eval messages {} + +ad_proc -public messages::send_mail { + -contacts_ids + -community_id + -owner_id + -subject + {-message_url ""} + {-parent_id ""} + {-count_attachment 0} + {-message ""} + {-rel_types ""} +} { + Send mail to diferent users +} { + set community_name [dotlrn_community::get_community_name $community_id] + set user_id [ad_conn user_id] + set user_name [acs_user::get_element -user_id $user_id -element name] + if { ![exists_and_not_null parent_id] } { + set parent_id "" + } + db_transaction { + set msg_id [db_nextval messages_msg_sequence] + db_dml send_mail {} + } + + if { ![empty_string_p $rel_types] } { + set rel_types "'[join $rel_types "','"]'" + set rel_types_user_ids_list [db_list get_rel_types_user_ids {}] + if { [empty_string_p $contacts_ids] } { + append contacts_ids_roles [join $rel_types_user_ids_list ","] + } else { + append contacts_ids_roles "," [join $rel_types_user_ids_list ","] + } + } else { + set contacts_ids_roles "" + } + + set party_id_list [lsort -unique [split $contacts_ids ","]] + if { ![empty_string_p $contacts_ids_roles] } { + set party_id_list_roles [lsort -unique [split $contacts_ids_roles ","]] + } else { + set party_id_list_roles [list] + } + + foreach party_id $party_id_list { + set email_user [acs_user::get_element -user_id $party_id -element email] + set package_id [dotlrn_community::get_package_id_from_package_key -package_key kernel -community_id 0] + set from_addr [parameter::get -parameter "OutgoingSender" -package_id $package_id] + ## E-mail notification is disabled by default, to enable just uncomment the following line in every place in this file + #acs_mail_lite::send -send_immediately -to_addr $email_user -from_addr $from_addr -subject [encoding convertto iso8859-15 [_ messages.subject_mail]] -body [_ messages.body_mail] + db_dml recipients {} + db_dml user_messages {} + } + if { ![empty_string_p $rel_types] } { + foreach party_id $party_id_list_roles { + if { [lsearch $party_id_list $party_id] == -1 && ![empty_string_p $party_id]} { + set email_user [acs_user::get_element -user_id $party_id -element email] + set package_id [dotlrn_community::get_package_id_from_package_key -package_key kernel -community_id 0] + set from_addr [parameter::get -parameter "OutgoingSender" -package_id $package_id] + ## E-mail notification is disabled by default, to enable just uncomment the following line in every place in this file + #acs_mail_lite::send -send_immediately -to_addr $email_user -from_addr $from_addr -subject [encoding convertto iso8859-15 [_ messages.subject_mail]] -body [_ messages.body_mail] + db_dml user_messages {} + } + } + set rel_types [split $rel_types ","] + foreach rel_type $rel_types { + db_dml recipients_roles {} + } + + } + set save_sent_p [db_string get_save_sent {} -default 1] + + if { $save_sent_p } { + db_dml sent_message {} + } + return $msg_id + ad_script_abort +} + +ad_proc -public messages::reply_mail { + -general_parent_id + -contacts_ids + -community_id + -owner_id + -subject + {-message_url ""} + {-parent_id ""} + {-count_attachment 0} + {-message ""} + {-msg_id_old ""} + {-attachment_ids ""} + {-rel_types ""} +} { + Send reply, reply-all and forward mail to diferent users +} { + set message [list "$message" "text/html"] + set community_name [dotlrn_community::get_community_name $community_id] + set user_id [ad_conn user_id] + set user_name [acs_user::get_element -user_id $user_id -element name] + #set subject [db_string get_subject {}] + db_transaction { + set msg_id [db_nextval messages_msg_sequence] + if { !$general_parent_id } { + set lang [string range [lang::conn::locale -package_id [ad_conn package_id]] 0 2] + set subject "[_ messages.msg_subject_forward]: $subject" + db_dml send_mail_forward {} + if { ![empty_string_p $attachment_ids] } { + set attachment_ids_clause "and attachment_id in ($attachment_ids)" + } else { + set attachment_ids_clause "" + } + set attachment_list [db_list_of_lists get_attachment_id { *SQL*}] + foreach attachment $attachment_list { + set attachment_id [lindex $attachment 0] + set attachment_item_id [lindex $attachment 1] + db_dml attachment_files {} + } + } else { + set subject "[_ messages.msg_subject_reply]: $subject" + if { [string equal $contacts_ids ""] } { + set contacts_ids "$user_id" + } else { + append contacts_ids ",$user_id" + } + db_dml send_mail {} + } + } + if { ![empty_string_p $rel_types] } { + set rel_types "'[join $rel_types "','"]'" + set rel_types_user_ids_list [db_list get_rel_types_user_ids {}] + if { [empty_string_p $contacts_ids] } { + append contacts_ids_roles [join $rel_types_user_ids_list ","] + } else { + append contacts_ids_roles "," [join $rel_types_user_ids_list ","] + } + } else { + set contacts_ids_roles "" + } + set party_id_list [lsort -unique [split $contacts_ids ","]] + set party_id_list_roles [lsort -unique [split $contacts_ids_roles ","]] + foreach party_id $party_id_list { + set email_user [acs_user::get_element -user_id $party_id -element email] + set package_id [dotlrn_community::get_package_id_from_package_key -package_key kernel -community_id 0] + set from_addr [parameter::get -parameter "OutgoingSender" -package_id $package_id] + ## E-mail notification is disabled by default, to enable just uncomment the following line in every place in this file + #acs_mail_lite::send -send_immediately -to_addr $email_user -from_addr $from_addr -subject [encoding convertto iso8859-15 [_ messages.subject_mail]] -body [_ messages.body_mail] + db_dml recipients {} + if { !$general_parent_id } { + db_dml user_messages_forward {} + } else { + db_dml user_messages {} + } + } + if { ![empty_string_p $rel_types] } { + foreach party_id $party_id_list_roles { + if { [lsearch $party_id_list $party_id] == -1 && ![empty_string_p $party_id]} { + set email_user [acs_user::get_element -user_id $party_id -element email] + set package_id [dotlrn_community::get_package_id_from_package_key -package_key kernel -community_id 0] + set from_addr [parameter::get -parameter "OutgoingSender" -package_id $package_id] + ## E-mail notification is disabled by default, to enable just uncomment the following line in every place in this file + #acs_mail_lite::send -send_immediately -to_addr $email_user -from_addr $from_addr -subject [encoding convertto iso8859-15 [_ messages.subject_mail]] -body [_ messages.body_mail] + if { !$general_parent_id } { + db_dml user_messages_forward {} + } else { + db_dml user_messages {} + } + } + } + set rel_types [split $rel_types ","] + foreach rel_type $rel_types { + db_dml recipients_roles {} + } + } + set party_id [ad_conn user_id] + set save_sent_p [db_string get_save_sent {} -default 1] + if { $save_sent_p } { + if { !$general_parent_id } { + db_dml sent_message_forward {} + } else { + db_dml sent_message {} + } + } + return $msg_id + ad_script_abort +} + +ad_proc -public messages::delete_trash_messages { + +} { + Delete all messages in the thash folder +} { + set folder_id [messages::get_folder_id -folder_name "trash"] + set limit_days_in_trash 15 + db_transaction { + db_dml delete_messages {} + } +} + +ad_proc -public messages::get_folder_id { + -folder_name +} { + Get the folder id to standar folders to users. +} { + switch $folder_name { + inbox { + return 0 + } + sent { + return 1 + } + save { + return 2 + } + trash { + return 3 + } + } +} + + +ad_proc -public messages::get_history_conversation { + -parent_id + -msg_id + -user_id +} { + Get the history conversation until the message forward +} { + set blockquote_conversation_begin "<blockquote style='border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;'><br/><br/>" + set blockquote_conversation_end "</blockquote>" + set conversation "<br><div id=\"history_conversation\">" + set count_messages 0 + append not_folder_ids [messages::get_folder_id -folder_name "sent"] "," \ + [messages::get_folder_id -folder_name "trash"] + db_multirow messages get_history_conversation { *SQL* } { + set day_recive [lc_time_fmt $sent_date "%d %b, %Y" ] + set ansi_time "$day_recive - $time" + set msg_content [template::util::richtext::get_property contents $msg_content] + append conversation "$blockquote_conversation_begin + El $day_recive, a las $time, [acs_user::get_element -user_id $owner_id -element name] escribio: <br><br> + $msg_content<br><br>" + incr count_messages + } + for {set i 0} {$i <= $count_messages} {incr i} { + append blockqoute_end $blockquote_conversation_end + } + append conversation "$blockqoute_end </div>" + return $conversation +} + +ad_proc -public messages::get_community_users_fb { + -community_id +} { + Memoize de members of the community +} { + #Recipients are obtained and placed in the form autocomplete style + set contacts_list [join [db_list members { *SQL* }] ","] + return $contacts_list +} + +ad_proc -public messages::string_truncate_middle { + {-ellipsis "..."} + {-len "100"} + -string +} { + cut middle part of a string in case it is to long copied from xotcl-request-monitor +} { + set string [string trim $string] + if {[string length $string]>$len} { + set half [expr {($len-2)/2}] + set left [string trimright [string range $string 0 $half]] + set right [string trimleft [string range $string end-$half end]] + return $left$ellipsis$right + } + return $string + +} + Index: openacs-4/packages/messages/tcl/messages-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/tcl/messages-procs.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/tcl/messages-procs.xql 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,203 @@ +<?xml version="1.0"?> + +<queryset> + +<fullquery name="messages::send_mail.send_mail"> + <querytext> + insert into messages_messages (msg_id, owner_id, community_id, subject, msg_content) + values (:msg_id,:owner_id,:community_id,:subject,:message) + </querytext> +</partialquery> + + <fullquery name="messages::send_mail.recipients"> + <querytext> + insert into messages_recipients (msg_id, party_id) + values (:msg_id,:party_id) + </querytext> + </fullquery> + + <fullquery name="messages::send_mail.recipients_roles"> + <querytext> + insert into messages_recipients_roles (msg_id, rel_id) + values (:msg_id,$rel_type) + </querytext> + </fullquery> + + <fullquery name="messages::send_mail.user_messages"> + <querytext> + insert into messages_user_messages (msg_id, user_id, folder_id, new_p,parent_id) + values (:msg_id,:party_id,0,'t',:msg_id) + </querytext> + </fullquery> + + <fullquery name="messages::send_mail.get_save_sent"> + <querytext> + select save_sent_p + from messages_options + where user_id = :user_id + </querytext> + </fullquery> + + <fullquery name="messages::send_mail.sent_message"> + <querytext> + insert into messages_user_messages (msg_id, user_id, folder_id, new_p,parent_id) + values (:msg_id,:owner_id,1,'t',:msg_id) + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.update_new"> + <querytext> + update messages_user_messages + set new_p = 't' + where msg_id = :msg_id + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.get_attachment_id"> + <querytext> + select attachment_id, attachment_item_id + from messages_attachments + where msg_id = :msg_id_old + $attachment_ids_clause + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.send_mail_forward"> + <querytext> + insert into messages_messages (msg_id, owner_id, community_id, subject, msg_content) + values (:msg_id,:owner_id,:community_id,:subject,:message) + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.send_mail"> + <querytext> + insert into messages_messages (msg_id, owner_id, community_id, subject, msg_content,parent_id) + values (:msg_id,:owner_id,:community_id,:subject,:message,:general_parent_id) + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.recipients"> + <querytext> + insert into messages_recipients (msg_id, party_id) + values ($msg_id,$party_id) + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.recipients_roles"> + <querytext> + insert into messages_recipients_roles (msg_id, rel_id) + values (:msg_id,$rel_type) + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.user_messages_forward"> + <querytext> + insert into messages_user_messages (msg_id, user_id, folder_id, new_p,parent_id) + values (:msg_id,:party_id,0,'t',:msg_id) + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.sent_message_forward"> + <querytext> + insert into messages_user_messages (msg_id, user_id, folder_id, new_p,parent_id) + values (:msg_id,:owner_id,1,'t',:msg_id) + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.get_save_sent"> + <querytext> + select save_sent_p + from messages_options + where user_id = :user_id + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.attachment_files"> + <querytext> + insert into messages_attachments values (:msg_id,:attachment_id,:attachment_item_id) + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.sent_message"> + <querytext> + insert into messages_user_messages (msg_id, user_id, folder_id, new_p,parent_id) + values (:msg_id,:owner_id,1,'t',:parent_id) + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.user_messages"> + <querytext> + insert into messages_user_messages (msg_id, user_id, folder_id, new_p,parent_id) + values (:msg_id,:party_id,0,'t',:parent_id) + </querytext> + </fullquery> + + <fullquery name="messages::delete_trash_mails.delete_messages"> + <querytext> + delete from messages_user_messages + where msg_id in ( select um.msg_id + from (select parent_id,msg_id from messages_user_messages where folder_id = :folder_id and msg_id = parent_id) um, + (select msg_id,to_char(sent_date, 'DD-MM-YYYY') as sent_date from messages_messages where sent_date < (SELECT sysdate - :limit_days_in_trash FROM dual)) m + where um.msg_id = m.msg_id + ) + </querytext> + </fullquery> + + <fullquery name="messages::delete_trash_mails.get_msg_ids_users"> + <querytext> + select msg_id, user_id from messages_user_messages where folder_id = :folder_id + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.get_subject"> + <querytext> + select subject from messages_messages where msg_id = :msg_id_old + </querytext> + </fullquery> + + <fullquery name="messages::send_mail.get_rel_types_user_ids"> + <querytext> + select user_id + from dotlrn_member_rels_approved + where community_id = :community_id + and rel_type in ($rel_types) + </querytext> + </fullquery> + + <fullquery name="messages::reply_mail.get_rel_types_user_ids"> + <querytext> + select user_id + from dotlrn_member_rels_approved + where community_id = :community_id + and rel_type in ($rel_types) + </querytext> + </fullquery> + + <fullquery name="messages::get_history_conversation.get_history_conversation"> + <querytext> + select msg_content, owner_id, subject, + sent_date, to_char(sent_date, 'HH24:MI:SS') as time + from messages_messages + where msg_id in (select msg_id + from messages_user_messages + where user_id = :user_id + and folder_id not in ($not_folder_ids) + and parent_id = :parent_id) + and msg_id <= :msg_id + order by msg_id desc + + </querytext> + </fullquery> + + <fullquery name="messages::get_community_users_fb.members"> + <querytext> + select '{name:"'||name.party_name||'", p:"'||name.person_id||'"}' + from (select persons.first_names||' '||persons.last_name as party_name, persons.person_id + from persons,dotlrn_member_rels_approved + where dotlrn_member_rels_approved.community_id = :community_id + and dotlrn_member_rels_approved.user_id = persons.person_id + order by party_name) as name + </querytext> + </fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/contacts.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/contacts.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/contacts.adp 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,19 @@ +<if @option@ eq "reply"> + <span id=span_@contact_id@ class="token"> + <span><span><span><span> + <input type="hidden" value=@contact_id@ name="ids[]">@contact_name@ + <span class="x" onclick=id_delete(@contact_id@)> </span> + </span></span></span></span> + </span> +</if> +<if @option@ eq "reply_all"> + <multiple name="contact"> + <span id=span_@contact.party_id@ class="token"> + <span><span><span><span> + <input type="hidden" value=@contact.party_id@ name="ids[]"/>@contact.party_name@ + <span class="x" onclick=id_delete(@contact.party_id@)> </span> + </span></span></span></span> + </span> + </multiple> +</if> +<if @option@ eq "forward">forward</if> \ No newline at end of file Index: openacs-4/packages/messages/www/contacts.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/contacts.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/contacts.tcl 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,27 @@ +ad_page_contract { + Update numbers of new messages in the menu + + @author pedro@viaro.net + @creation-date 2009-11-17 + @cvs-id $Id: contacts.tcl,v 1.1 2010/08/31 21:30:45 alvaror Exp $ +} { + msg_id + {option ""} +} + +set community_id [dotlrn_community::get_community_id] + +if { [string equal $option "reply"]} { + db_1row owner_info {} +} + +if { [string equal $option "reply_all"]} { + #gets all the recipients included in the message + db_multirow contact recipient_ids { *SQL* } { } +} + +if { [string equal $option "forward"]} { + #when select forward, return only forward because in the javascript, + #this option is write nothing in the recipients. + set contacts_reply "forward" +} \ No newline at end of file Index: openacs-4/packages/messages/www/contacts.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/contacts.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/contacts.xql 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,28 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="owner_info"> + <querytext> + select acs_users_all.first_names||' '||acs_users_all.last_name as contact_name, + acs_users_all.party_id as contact_id + from acs_users_all, + dotlrn_member_rels_approved + where dotlrn_member_rels_approved.community_id = :community_id + and dotlrn_member_rels_approved.user_id = acs_users_all.user_id + and acs_users_all.user_id in (select owner_id from messages_messages where msg_id = :msg_id) + </querytext> + </fullquery> + + <fullquery name="recipient_ids"> + <querytext> + select acs_users_all.first_names||' '||acs_users_all.last_name as party_name, + acs_users_all.party_id + from acs_users_all, + dotlrn_member_rels_approved + where dotlrn_member_rels_approved.community_id = :community_id + and dotlrn_member_rels_approved.user_id = acs_users_all.user_id + and acs_users_all.user_id in (select party_id from messages_recipients where msg_id = :msg_id) + </querytext> + </fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/create-folder.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/create-folder.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/create-folder.adp 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1 @@ +@response@ \ No newline at end of file Index: openacs-4/packages/messages/www/create-folder.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/create-folder.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/create-folder.tcl 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,26 @@ +ad_page_contract { + Create a New folder. + + @author pedro@viaro.net + @creation-date 2009-11-17 + @cvs-id $Id: create-folder.tcl,v 1.1 2010/08/31 21:30:42 alvaror Exp $ +} { + folder_name +} + +set user_id [ad_conn user_id] +set folder_id [db_nextval messages_folders_sequence] +set folder_name [string trim "$folder_name"] +#create a new folder but not is create when folder_name is empty or greater than 20 characteres. +if { [empty_string_p $folder_name] || [string length $folder_name] > 20} { + if { [empty_string_p $folder_name] } { + set response "[_ messages.new_folder_name_error]" + } else { + set response "[_ messages.lt_folder_name_error]" + } +} else { + db_transaction { + db_dml create_new_folder {} + } + set response [_ messages.sucsessful_create_folder] +} \ No newline at end of file Index: openacs-4/packages/messages/www/create-folder.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/create-folder.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/create-folder.xql 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="create_new_folder"> + <querytext> + insert into + messages_folders (user_id,folder_id,folder_name) + values(:user_id,:folder_id,:folder_name) + </querytext> + </fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/delete-message.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/delete-message.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/delete-message.adp 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1 @@ +complete Index: openacs-4/packages/messages/www/delete-message.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/delete-message.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/delete-message.tcl 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,17 @@ +ad_page_contract { + Delete selected messages in the trash folder + + @author pedro@viaro.net + @creation-date 2009-11-24 + @cvs-id $Id: delete-message.tcl,v 1.1 2010/08/31 21:30:43 alvaror Exp $ +} { + msg_ids +} + +set folder_id [messages::get_folder_id -folder_name "trash"] +set community_id [dotlrn_community::get_community_id] +set user_id [ad_conn user_id] + +db_transaction { + db_dml delete_messages {} +} Index: openacs-4/packages/messages/www/delete-message.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/delete-message.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/delete-message.xql 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="delete_messages"> + <querytext> + delete from messages_user_messages + where folder_id = :folder_id + and user_id = :user_id + and msg_id in ($msg_ids) + + </querytext> + </fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/empty-trash.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/empty-trash.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/empty-trash.adp 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1 @@ +@folder_id@ \ No newline at end of file Index: openacs-4/packages/messages/www/empty-trash.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/empty-trash.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/empty-trash.tcl 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,16 @@ +ad_page_contract { + Empty Trash + + @author pedro@viaro.net + @creation-date 2010-01-22 + @cvs-id $Id: empty-trash.tcl,v 1.1 2010/08/31 21:30:43 alvaror Exp $ +} { + +} + +set user_id [ad_conn user_id] +set community_id [dotlrn_community::get_community_id] +set folder_id [messages::get_folder_id -folder_name "trash"] +db_transaction { + db_dml empty_trash {} +} \ No newline at end of file Index: openacs-4/packages/messages/www/empty-trash.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/empty-trash.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/empty-trash.xql 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,11 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="empty_trash"> + <querytext> + delete from messages_user_messages + where folder_id = :folder_id and user_id = :user_id + </querytext> + </fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/inbox-oracle.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/inbox-oracle.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/inbox-oracle.xql 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,52 @@ +<?xml version="1.0"?> + +<queryset> + <rdbms><type>oracle</type><version>8.1.6</version></rdbms> + +<fullquery name="get_messages"> + <querytext> + select mm.last_msg_id, mm.msg_id, mm.number_conversation, mm.subject, wm_concat(distinct(p.first_names||' '||p.last_name)) as contacts, count(distinct(p.first_names)) as total_contacs, mm.owner_id + from persons p, + (select max(um.msg_id) as last_msg_id, um.parent_id as msg_id, count(um.msg_id) as number_conversation, m.subject, m.owner_id + from (select parent_id,msg_id from messages_user_messages where user_id = :user_id and folder_id = :folder_id) um, + (select msg_id,subject,owner_id from messages_messages where community_id = :community_id and msg_id in ($msg_ids)) m + where um.parent_id = m.msg_id + group by um.parent_id, m.subject, m.owner_id) mm + where p.person_id = mm.owner_id + group by mm.msg_id, mm.subject, mm.last_msg_id, mm.number_conversation, mm.owner_id + order by mm.last_msg_id desc + </querytext> +</fullquery> + +<fullquery name="get_contacts"> + <querytext> + select distinct(owner_id) + from messages_messages + where parent_id = :msg_id + or msg_id = :msg_id + and rownum < 4 + </querytext> +</fullquery> + +<fullquery name="get_msg_ids"> + <querytext> + select msg_id, last_msg_id + from (select paginate.*, rownum rowsub + from (select max(m.msg_id) as last_msg_id, m.parent_id as msg_id, count(m.msg_id) as number_conversation + from (select msg_id, coalesce(parent_id,msg_id) as parent_id + from messages_messages + where community_id = :community_id + and msg_id in (select parent_id + from messages_user_messages + where user_id = :user_id + and folder_id = :folder_id)) m + group by m.parent_id + order by last_msg_id desc + ) paginate + where rownum <= :last_row) + where rowsub >= :first_row + + </querytext> +</fullquery> + +</queryset> Index: openacs-4/packages/messages/www/inbox-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/inbox-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/inbox-postgresql.xql 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,51 @@ +<?xml version="1.0"?> +<queryset> + <rdbms><type>postgresql</type><version>7.3</version></rdbms> + +<fullquery name="get_messages"> + <querytext> + select mm.last_msg_id, mm.msg_id, mm.number_conversation, mm.subject, ARRAY_TO_STRING(ARRAY(select first_names||' '||last_name from persons where person_id = mm.owner_id),',') as contacts, count(distinct p.first_names) as total_contacs, mm.owner_id + from persons p, + (select max(um.msg_id) as last_msg_id, um.parent_id as msg_id, count(um.msg_id) as number_conversation, m.subject, m.owner_id + from (select parent_id,msg_id from messages_user_messages where user_id = :user_id and folder_id = :folder_id) um, + (select msg_id,subject,owner_id from messages_messages where community_id = :community_id and msg_id in ($msg_ids)) m + where um.parent_id = m.msg_id + group by um.parent_id, m.subject, m.owner_id) mm + where p.person_id = mm.owner_id + group by mm.msg_id, mm.subject, mm.last_msg_id, mm.number_conversation, mm.owner_id + order by mm.last_msg_id desc + </querytext> +</fullquery> + +<fullquery name="get_contacts"> + <querytext> + select distinct(owner_id) + from messages_messages + where parent_id = :msg_id + or msg_id = :msg_id + LIMIT 4 + </querytext> +</fullquery> + +<fullquery name="get_msg_ids"> + <querytext> + select messages.msg_id, messages.last_msg_id + from (select paginate.* + from (select max(m.msg_id) as last_msg_id, m.parent_id as msg_id, count(m.msg_id) as number_conversation + from (select msg_id, coalesce(parent_id,msg_id) as parent_id + from messages_messages + where community_id = :community_id + and msg_id in (select parent_id + from messages_user_messages + where user_id = :user_id + and folder_id = :folder_id)) m + group by m.parent_id + order by last_msg_id desc + ) paginate + LIMIT :last_row) messages + OFFSET :first_row - 1 + + </querytext> +</fullquery> + +</queryset> Index: openacs-4/packages/messages/www/inbox.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/inbox.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/inbox.adp 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,44 @@ +<input type="hidden" id="page_number" value=@page_number@> +<input type="hidden" id="folder_id" value=@folder_id@> +<input type="hidden" id="folder_id_state" value="@folder_id@"> +<input type="hidden" id="msg_continue_empty" value="#messages.msg_continue_empty#"> +<input type="hidden" id="number_messages" value=@total_messages@> + +<div align="right"> + <if @total_messages@ gt @show_messages@> + <if @page_number@ eq 2> + <a href="#" onClick="paginate(@folder_id@,@page_number@,'newer');update_numbers(@folder_id@,@user_id@)">#messages.newer# </a> + </if> + <if @page_number@ ge 3> + <a href="#" onClick="paginate(@folder_id@,1,'newest');update_numbers(@folder_id@,@user_id@)">#messages.newest# </a> + <a href="#" onClick="paginate(@folder_id@,@page_number@,'newer');update_numbers(@folder_id@,@user_id@)">#messages.newer# </a> + </if> + #messages.range_messages_show# + <if @page_number@ lt @total_pages@> + <a href="#" onClick="paginate(@folder_id@,@page_number@,'older');update_numbers(@folder_id@,@user_id@)">#messages.older# </a> + <if @page_number@ ne @oldest_page@> + <if @page_number@ lt @oldest_page@> + <a href="#" onClick="paginate(@folder_id@,@total_pages@,'oldest');update_numbers(@folder_id@,@user_id@)">#messages.oldest# </a> + </if> + </if> + </if> + </if> + <else> + <if @total_messages@ ne 0> #messages.range_messages_show# </if> + </else> +</div> +<if @folder_id@ eq 3> + <div id="folder_trash_msg" style="font-size:12px;" align="center"> + + <if @total_messages@ ne 0> + <a href="#" onclick="empty_trash()">#messages.empty_trash#</a> + </if> + #messages.folder_trash_msg# + </div> +</if> + +<form name="messages_list" method="GET"> + <div id="list_messages" style="weight:100%"> + <listtemplate name="messages"></listtemplate> + </div> +</form> \ No newline at end of file Index: openacs-4/packages/messages/www/inbox.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/inbox.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/inbox.tcl 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,201 @@ +ad_page_contract { + Inbox Page + + @author pedro@viaro.net + @creation-date 2009-11-11 + @cvs-id $Id: inbox.tcl,v 1.1 2010/08/31 21:30:43 alvaror Exp $ +} { + {folder_id ""} + {page_number ""} +} + +set user_id [ad_conn user_id] +set community_id [dotlrn_community::get_community_id] +if {[empty_string_p $page_number]} { + set page_number 1 +} + +if {[empty_string_p $folder_id]} { + set folder_id 0 +} + +##################################################################### +#get the total messages and calculate how many pages have in folder show +#First and last row are calculate based on the total messages show per page +set total_messages [db_string get_total_messages {} -default 0] +set show_messages [db_string get_max_show_msg {} -default 25] +#Round to the next integer because the las page include some messages. +set total_pages [expr ceil([expr [expr $total_messages + 0.0] / [expr $show_messages + 0.0]])] +set oldest_page [expr $total_pages - 1] +set count_messages 0 +if { $page_number != 1} { + set first_row [expr [expr [expr $page_number - 1] * $show_messages] + 1] + set last_row [expr [expr $first_row + $show_messages] - 1] +} else { + set first_row [expr [expr $page_number - 1] * $show_messages] + set last_row [expr $first_row + $show_messages] + set first_row [expr $first_row + 1] +} +###################################################################### + +set elements [list msg_ids \ + [list label { <input type="checkbox" id="checkbox_general" name="_dummy" onclick="select_all(this.form,this.checked);" title="[_ acs-templating.lt_Checkuncheck_all_rows]">} \ + display_template {<input type="checkbox" id="check_box_msg.@messages.msg_id@" name="subject_id" value="@messages.msg_id@" id="msg_ids.@messages.msg_id@" title="[_ acs-templating.lt_Checkuncheck_this_row]" onclick="more_actions_select();">} \ + sub_class {narrow} \ + html { align center }] \ + ] + +lappend elements contacts \ + [list html { align left style "font-size: smaller; width:20%"} \ + label [_ messages.from] \ + display_template { <a href="#@messages.msg_id@a${folder_id}a${page_number}" onclick="read_message(@messages.msg_id@,$folder_id,$page_number)"> <if @messages.new_p@>\ + <span id="new_p.@messages.msg_id@"><span id="new_p_style.@messages.msg_id@" style="font-weight: bold;">@messages.contacts@ \ + <if $folder_id ne 1> (@messages.number_conversation@) </if></span>\ + </if><else><span id="new_p_style.@messages.msg_id@" style="font-weight:;">@messages.contacts@ (@messages.number_conversation@)</span></else></a>} \ + ] \ + rel_type \ + [list html { align left style "font-size: smaller; width:5%;"} \ + label "" \ + display_template { <if @messages.rel_type@ ne ""> \ + <a href="#@messages.msg_id@a${folder_id}a${page_number}" style="background-color:#F06040;color:white;padding:2px;" onclick="read_message(@messages.msg_id@,$folder_id,$page_number)">@messages.rel_type@</a></if> } \ + ] \ + attachmet_mail \ + [list html { align center style "font-size: smaller; width:3%"} \ + label "" \ + display_template { <a href="#@messages.msg_id@a${folder_id}a${page_number}" onclick="read_message(@messages.msg_id@,$folder_id,$page_number)">\ + <if @messages.attachment_p@ gt 0><span style="font-weight: bold;"><img src="/resources/messages/attachment.png" width="20" height="20"></span> \ + </if></a>} \ + ] \ + subject_mail \ + [list html { align left style "font-size: smaller; width:62%"} \ + label [_ messages.subject] \ + display_template { <a href="#@messages.msg_id@a${folder_id}a${page_number}" onclick="read_message(@messages.msg_id@,$folder_id,$page_number)">\ + <if @messages.new_p@><span id="new_p_sub.@messages.msg_id@" style="font-weight: bold;">@messages.subject_mail@</span> \ + </if><else><span id="new_p_sub.@messages.msg_id@" style="font-weight:;">@messages.subject_mail@</span></else></a>} \ + ] \ + date \ + [list html { align left style "font-size: smaller;width:12%"} \ + label [_ messages.date] \ + display_template { <a href="#@messages.msg_id@a${folder_id}a${page_number}" onclick="read_message(@messages.msg_id@,$folder_id,$page_number)">\ + <if @messages.new_p@><span id="new_p_date.@messages.msg_id@" style="font-weight: bold;">@messages.date@</span> \ + </if><else><span id="new_p_date.@messages.msg_id@" style="font-weight:;">@messages.date@</span></else></a>} \ + ] + +template::list::create \ + -name messages \ + -multirow messages \ + -main_class "list-table" \ + -html { width=100% } \ + -orderby_name orderby \ + -no_data "[_ messages.no_messages_found]" \ + -elements $elements + + +set msg_id_list [list] +set last_msg_ids_list [list] +db_foreach get_msg_ids { *SQL* } { + set last_msg_ids_array($msg_id) $last_msg_id + lappend last_msg_ids_list $last_msg_id + lappend msg_id_list $msg_id +} + +set msg_ids [join $msg_id_list ","] +set last_msg_ids [join $last_msg_ids_list ","] + +if { [empty_string_p $msg_ids] } { + set msg_ids 0 +} + +if { [empty_string_p $last_msg_ids] } { + set last_msg_ids 0 +} + +db_foreach get_attachment_p { } { + set get_attachment_array($parent_id) $count_attachment +} + +db_foreach get_new_p {} { + set new_p_array($parent_id) $new_p +} + +db_foreach get_msg_info {} { + set msg_content_array($parent_id) $msg_content + set date_sent_array($parent_id) $sent_date_ansi +} + +##Roles: se estable los roles que existen y se obtienen lo usuarios y sus roles +set roles [dotlrn_community::get_roles -community_id $community_id] +set rel_types [list] +foreach role $roles { + lappend rel_types [lindex $role 0] +} +set rel_types [join $rel_types "','"] +set rel_type_case "case " +foreach {rel_type role pretty_name pretty_plural} [eval concat $roles] { + if { [string equal $rel_type "dotlrn_student_rel"] } { + append rel_type_case "when rel_type = '$rel_type' then '' " + } else { + append rel_type_case "when rel_type = '$rel_type' then '$pretty_name' " + } +} +append rel_type_case " end" + +### + +foreach msg_id $msg_id_list { + set contacts_ids [db_list get_contacts {}] + set owner_id [db_string get_owner_id {}] + set member_ids_rel_type($owner_id) [db_string get_members_ids_rel_type {}] + if { [llength $contacts_ids] > 1} { + set contacts "" + foreach contact_id $contacts_ids { + append contacts [db_string get_name {}] "," + } + set contacts [string range $contacts 0 end-1] + set msg_contacts($msg_id) $contacts + } +} + +db_multirow -extend { rel_type subject_mail date attachment_p new_p} messages get_messages { *SQL* } { + if { [info exists get_attachment_array($msg_id)]} { + set attachment_p $get_attachment_array($msg_id) + } else { + set attachment_p 0 + } + if { [info exists member_ids_rel_type($owner_id)]} { + set rel_type [lang::util::localize $member_ids_rel_type($owner_id)] + } else { + set rel_type "" + } + + if { [info exists msg_contacts($msg_id)]} { + set contacts $msg_contacts($msg_id) + } + set msg_content $msg_content_array($msg_id) + set sent_date_ansi $date_sent_array($msg_id) + set content [ad_html_to_text [template::util::richtext::get_property contents $msg_content]] + if { [empty_string_p $subject] } { + set subject "[_ messages.no_subject] " + } + append subject_mail $subject "-" [string_truncate -len 80 -ellipsis "..." " $content"] + set cur_time [clock format [clock seconds] -format "%Y %m %d"] + set sent_time_seconds [clock format [clock scan $sent_date_ansi] -format "%Y %m %d"] + #compare the sent date whith the current date and display the message according to the date. + if { [lindex $cur_time 0] > [lindex $sent_time_seconds 0]} { + set date [lc_time_fmt $sent_date_ansi "%D"] + } else { + if {[lindex $cur_time 1] >= [lindex $sent_time_seconds 1] && [lindex $cur_time 2] == [lindex $sent_time_seconds 2]} { + set date [_ messages.today] + } else { + set date [lc_time_fmt $sent_date_ansi "%d,%b,%Y %H:%M"] + } + } + if { [info exists new_p_array($msg_id)]} { + set new_p $new_p_array($msg_id) + } else { + set new_p 0 + } + incr count_messages +} + +set last_number [expr [expr $count_messages + $first_row] - 1] Index: openacs-4/packages/messages/www/inbox.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/inbox.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/inbox.xql 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,96 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="get_name"> + <querytext> + select acs_users_all.last_name||' '||acs_users_all.first_names + from acs_users_all, + dotlrn_member_rels_approved + where dotlrn_member_rels_approved.community_id = :community_id + and dotlrn_member_rels_approved.user_id = acs_users_all.user_id + and acs_users_all.user_id = :party_id + </querytext> + </fullquery> + + <fullquery name="get_msg_info"> + <querytext> + select coalesce(parent_id,msg_id) as parent_id, msg_content, to_char(sent_date, 'YYYY-MM-DD HH24:MI:SS') as sent_date_ansi + from messages_messages + where msg_id in ($last_msg_ids) + </querytext> + </fullquery> + + <fullquery name="get_total_messages"> + <querytext> + select count(um.msg_id) as total + from (select distinct(mum.parent_id) as msg_id + from (select * from messages_user_messages where user_id = :user_id) as mum + where user_id = :user_id + and msg_id in (select msg_id + from messages_messages + where community_id = :community_id) + and folder_id = :folder_id) um + </querytext> + </fullquery> + + <fullquery name="get_max_show_msg"> + <querytext> + select max_messages + from messages_options + where user_id = :user_id + </querytext> + </fullquery> + + <fullquery name="get_attachment_p"> + <querytext> + select um.parent_id, count(*) as count_attachment + from messages_attachments ma, + (select msg_id, parent_id + from messages_user_messages + where user_id = :user_id + and folder_id = :folder_id + and parent_id in ($msg_ids) + ) um + where ma.msg_id = um.msg_id + group by um.parent_id + </querytext> + </fullquery> + + <fullquery name="get_new_p"> + <querytext> + select parent_id, new_p + from messages_user_messages + where parent_id in ($last_msg_ids) + and folder_id = :folder_id + and user_id = :user_id + </querytext> + </fullquery> + + <fullquery name="get_owner_id"> + <querytext> + select owner_id + from messages_messages + where msg_id = :msg_id + and community_id = :community_id + </querytext> + </fullquery> + + <fullquery name="get_members_ids_rel_type"> + <querytext> + select $rel_type_case as rel_type + from acs_rels map + where map.object_id_one = :community_id + and map.rel_type in ('$rel_types') + and object_id_two = :owner_id + </querytext> + </fullquery> + + <fullquery name="get_name"> + <querytext> + select first_names + from persons + where person_id = :contact_id + </querytext> + </fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/index.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/index.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/index.adp 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1 @@ +redirect \ No newline at end of file Index: openacs-4/packages/messages/www/index.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/index.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/index.tcl 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,11 @@ +ad_page_contract { + Redirect to messages + + @author pedro@viaro.net + @creation-date 2009-11-17 + @cvs-id $Id: index.tcl,v 1.1 2010/08/31 21:30:43 alvaror Exp $ +} { + +} + +ad_returnredirect "messages" \ No newline at end of file Index: openacs-4/packages/messages/www/members-rol.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/members-rol.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/members-rol.adp 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,13 @@ +<if @data_search@ eq ""> + <input type="text" id="search_name" > + <input type="button" id="search_button" value="#messages.search#" onclick="search_members_rel_type();"> + <input type="hidden" id="rel_type" value="@rel_type@"> +</if> +<div id="members_list_div"> + <form name="members_list" method="GET"> + <div id="list_members" style="weight:100%"> + <listtemplate name="members"></listtemplate> + </div> + <input type="hidden" id="total_rel_members" value="@rowscount@"> + </form> +</div> Index: openacs-4/packages/messages/www/members-rol.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/members-rol.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/members-rol.tcl 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,59 @@ +ad_page_contract { + Inbox Page + + @author pedro@viaro.net + @creation-date 2010-05-17 + @cvs-id $Id: members-rol.tcl,v 1.1 2010/08/31 21:30:45 alvaror Exp $ +} { + {rel_type ""} + {data_search ""} +} + +set user_id [ad_conn user_id] +set community_id [dotlrn_community::get_community_id] + + +if { [exists_and_not_null data_search] && ![string equal $data_search "none"]} { + set data_search_list [string trim [split $data_search " "]] + set count 0 + foreach data_search $data_search_list { + set sql_keyword "%[string tolower $data_search]%" + if { $count == 0 } { + append where_clause_user "lower(first_names || ' ' || last_name) like '$sql_keyword'" + } else { + append where_clause_user " or lower(first_names || ' ' || last_name) like '$sql_keyword'" + } + incr count + } + set where_clause_user "and ($where_clause_user)" +} else { + set where_clause_user "" + set search_clause "" +} + +set elements [list msg_ids \ + [list label { <input type="checkbox" id="checkbox_general" name="_dummy" onclick="select_all(this.form,this.checked);" title="[_ acs-templating.lt_Checkuncheck_all_rows]">} \ + display_template {<input type="checkbox" id="check_box_msg.@members.person_id@" name="subject_id" value="@members.person_id@" id="person_id.@members.person_id@" title="[_ acs-templating.lt_Checkuncheck_this_row]">} \ + sub_class {narrow} \ + html { align center }] \ + ] + +lappend elements party_name \ + [list html { align left style "font-size: smaller; width:95%"} \ + label [_ messages.from] \ + display_template {<input type="hidden" value="@members.party_name@" id="party_name.@members.person_id@"> @members.party_name@} \ + ] + + + +template::list::create \ + -name members \ + -multirow members \ + -main_class "list-table" \ + -html { width=100% } \ + -orderby_name orderby \ + -no_data "[_ messages.no_members_found]" \ + -elements $elements + +set rowscount 0 +db_multirow -extend { } members get_members { *SQL* } { incr rowscount} Index: openacs-4/packages/messages/www/members-rol.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/members-rol.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/members-rol.xql 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="get_members"> + <querytext> + select p.first_names||' '||p.last_name as party_name, + p.person_id + from persons p, + acs_rels map + where map.object_id_one = :community_id + and map.object_id_two = p.person_id + and map.rel_type = :rel_type + $where_clause_user + order by party_name + </querytext> + </fullquery> + +</queryset> + Index: openacs-4/packages/messages/www/message-option.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/message-option.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/message-option.adp 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,42 @@ +<master> +<property name="title">@page_title;noquote@</property> +<property name="context">@context;noquote@</property> +<include src="messages-actions"> +<br> +<div class="yui-skin-sam"> + <div> + <a class="button" id="show" style="cursor:pointer">#messages.new_folder#</a> + </div> + <div id="dialog1" class="yui-pe-content"> + <div class="hd">#messages.name_new_folder#</div> + <div class="bd"> + <form method="GET" action="create-folder"> + <label for="folder_name">#messages.folder_name#:</label><input type="text" name="folder_name" /> + </form> + </div> + </div> +</div> +<br> +<if @folder:rowcount@ gt 0> + <strong> #messages.folders_created# </strong><br>#messages.edit_folder#<br><br> +</if> + +<multiple name="folder"> + <span id="span_folder_@folder.folder_id@" onclick="convert_input('@folder.folder_id@')"> + <img src="/resources/messages/folder.png" width="20" height="20"> + <span id="folder_@folder.folder_id@"> + @folder.folder_name@ + </span> + </span> + <span id="span_folder_delete_@folder.folder_id@"> + <a href="javascript:delete_folder();" title="Borrar"> + <img src="/resources/messages/Delete16-on.gif"> + <span class="class="button" onclick="update_folder(@folder.folder_id@,'delete')"> + #messages.delete# + </span> + </a> + </span> + <br> +</multiple> +<br><br> +<formtemplate id="options_mail"></formtemplate> \ No newline at end of file Index: openacs-4/packages/messages/www/message-option.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/message-option.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/message-option.tcl 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,87 @@ +ad_page_contract { + Message Options + + @author pedro@viaro.net + @creation-date 2009-11-13 + @cvs-id $Id: message-option.tcl,v 1.1 2010/08/31 21:30:43 alvaror Exp $ +} { + {return_url "messages"} +} + +set page_title "[_ messages.configuration]" +set context [list "[_ messages.configuration]"] +set owner_id [ad_conn user_id] +set user_id [ad_conn user_id] +set community_id [dotlrn_community::get_community_id] +set save_sent_p 1 +set signature_p 0 +set signature "" +set max_messages "25" + +append folders_id_standar [messages::get_folder_id -folder_name "inbox"] ","\ + [messages::get_folder_id -folder_name "sent"] ","\ + [messages::get_folder_id -folder_name "save"] ","\ + [messages::get_folder_id -folder_name "trash"] + +db_multirow -extend { folder_p } folder get_folders_data { *SQL* } { } + +if { ![db_0or1row select_options {} ] } { + db_dml create_options {} +} + +set signature [ad_html_to_text $signature] + +if { [empty_string_p $signature] } { + set signature "" +} else { + set signature [string trim $signature] +} + +ad_form -name options_mail -cancel_url "messages" -form { + {max_messages:naturalnum {label "[_ messages.max_show_messages]:"} + {html {size 3}} {value $max_messages} + } + {save_sent_p:text(radio) {label "[_ messages.save_sent_message]:"} + {options {{[_ messages.yes] 1} {[_ messages.no] 0}}} {value $save_sent_p} + } + {signature_p:text(radio) {label "[_ messages.insert_signature]:"} + {options {{[_ messages.yes] 1} {No 0}}} {value $signature_p} + } + {signature_text:richtext(richtext),optional,nospell {label "[_ messages.signature]:"} + {options {editor xinha }} + {value "$signature"} {html {id "signature" cols 80 rows 3 onload "loadEditors('advancedMessagesEditor'); return false;"}} + } +} -on_submit { + set signature [string trim [ad_convert_to_html $signature_text]] + db_dml update_options {} +} -after_submit { + ad_returnredirect "$return_url" + ad_script_abort +} + +template::head::add_javascript -src "/resources/ajaxhelper/yui/yahoo/yahoo-min.js" -order "-3" +template::head::add_javascript -src "/resources/ajaxhelper/yui/yahoo-dom-event/yahoo-dom-event.js" -order "-1" +template::head::add_javascript -src "/resources/ajaxhelper/yui/element/element-beta-min.js" -order "-2" +template::head::add_javascript -src "/resources/ajaxhelper/yui/event/event-min.js" -order "-4" +template::head::add_javascript -src "/resources/ajaxhelper/yui/dom/dom-min.js" -order "-5" +template::head::add_javascript -src "/resources/ajaxhelper/yui/button/button-beta-min.js" -order "-7" +template::head::add_javascript -src "/resources/ajaxhelper/yui/utilities/utilities.js" -order "-8" +template::head::add_javascript -src "/resources/ajaxhelper/yui/connection/connection-min.js" -order "-9" +template::head::add_javascript -src "/resources/ajaxhelper/yui/button/button-min.js" +template::head::add_javascript -src "/resources/ajaxhelper/yui/dragdrop/dragdrop-min.js" +template::head::add_javascript -src "/resources/ajaxhelper/yui/container/container-min.js" +template::head::add_javascript -src "/resources/ajaxhelper/yui/yuiloader/yuiloader-min.js" +template::head::add_javascript -src "/resources/messages/folder-new.js" +template::head::add_css -href "/resources/ajaxhelper/yui/button/assets/skins/sam/button.css" -order "-3" +template::head::add_css -href "/resources/ajaxhelper/yui/container/assets/skins/sam/container.css" -order "-4" +template::head::add_css -href "/resources/ajaxhelper/yui/fonts/fonts-min.css" +template::head::add_css -href "/resources/ajaxhelper/yui/button/assets/skins/sam/button.css" +template::head::add_css -href "/resources/ajaxhelper/yui/assets/skins/sam/container.css" +template::head::add_javascript -src "/resources/messages/messages.js" -order "3" +template::head::add_javascript -src "/resources/messages/message-option.js" -order "4" + + +set ::acs_blank_master(xinha) 1 +set ::acs_blank_master(xinha.plugins) "'OacsFs'" +set ::acs_blank_master(xinha.options) "" +set ::acs_blank_master__htmlareas "" \ No newline at end of file Index: openacs-4/packages/messages/www/message-option.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/message-option.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/message-option.xql 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,37 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="get_folders_data"> + <querytext> + select folder_id, folder_name + from messages_folders + where user_id = :user_id + or user_id = 0 + and folder_id not in ($folders_id_standar) + order by folder_id asc + </querytext> + </fullquery> + + <fullquery name="select_options"> + <querytext> + select max_messages, save_sent_p, signature_p, signature + from messages_options + where user_id = :user_id + </querytext> + </fullquery> + + <fullquery name="create_options"> + <querytext> + insert into messages_options values (:user_id,25,:save_sent_p,:signature_p,:signature) + </querytext> + </fullquery> + + <fullquery name="update_options"> + <querytext> + update messages_options + set max_messages = :max_messages,save_sent_p = :save_sent_p, signature_p = :signature_p, signature = :signature + where user_id = :user_id + </querytext> + </fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/messages-actions.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/messages-actions.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/messages-actions.adp 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,52 @@ +<input type="hidden" id="new_folder_name_error" value="#messages.new_folder_name_error#"> +<input type="hidden" id="delete_confirm" value="#messages.delete_confirm#"> +<input type="hidden" id="subject_empty" value="#messages.subject_empty#"> +<input type="hidden" id="confirm_trash_empty" value="#messages.confirm_trash_empty#"> +<input type="hidden" id="recipients_empty" value="#messages.recipients_empty#"> +<input type="hidden" id="msg_read" value="#messages.msg_read#"> +<input type="hidden" id="msg_unread" value="#messages.msg_unread#"> +<input type="hidden" id="msg_delete" value="#messages.msg_delete#"> +<input type="hidden" id="more_msg_unread" value="#messages.more_msg_unread#"> +<input type="hidden" id="more_msg_read" value="#messages.more_msg_read#"> +<input type="hidden" id="msg_moved_to" value="#messages.has_been_moved_to#"> +<input type="hidden" id="msg_cancel" value="#messages.msg_cancel#"> +<input type="hidden" id="cancel" value="#messages.cancel#"> +<input type="hidden" id="other_msg_reply" value="#messages.other_msg_reply#"> +<input type="hidden" id="send_msg" value="#messages.send#"> +<input type="hidden" id="msg_invalid_user" value="#messages.msg_invalid_user#"> +<input type="hidden" id="more_msg_moved_to" value="#messages.more_msg_moved_to#"> +<input type="hidden" id="msg_select_msg" value="#messages.msg_select_msg#"> +<input type="hidden" id="msg_loading" value="#messages.msg_loading#"> +<input type="hidden" id="msg_yes" value="#messages.yes#"> +<input type="hidden" id="msg_create" value="#messages.create#"> +<input type="hidden" id="msg_id_reply" value=""> +<input type="hidden" id="option_reply" value=""> +<input type="hidden" id="msg_action_send_p" value="f"> +<input type="hidden" id="msg_id_new_send" value=""> +<input type="hidden" id="msg_active_reply" value=""> +<input type="hidden" id="msg_action_p" value="f"> +<input type="hidden" id="more_actions_option" value="f"> +<input type="hidden" id="more_actions_p" value="f"> +<input type="hidden" id="ids_length" value=0> +<input type="hidden" id="folder_active" value=0> +<input type="hidden" id="option_move_to" value=> +<input type="hidden" id="move_to_p" value="f"> +<input type="hidden" id="inbox_select_p" value="f"> +<input type="hidden" id="option_action" value=> +<input type="hidden" id="option" value=0> +<input type="hidden" id="message_action_p" value="t"> +<input type="hidden" id="location_href" value="t"> +<input type="hidden" id="reply_dialog_active" value="f"> +<input type="hidden" id="count_msg_ids" value=0> +<input type="hidden" id="folder_name" value=0> +<input type="hidden" id="ids_more_actions" value=""> +<input type="hidden" id="msg_invalid_number" value="#messages.msg_invalid_number#"> +<input type="hidden" id="save_info" value="#messages.save_info#"> +<input type="hidden" id="msg_delete_folder" value="#messages.msg_delete_folder#"> +<input type="hidden" id="active" value="f"> +<input type="hidden" id="name_cancel" value=""> +<input type="hidden" id="cancel_p" value="f"> +<input type="hidden" id="delete_p" value="f"> +<input type="hidden" id="page_number" value="1"> +<input type="hidden" id="total_messages" value="0"> +<input type="hidden" id="msg_id_action_reply" value="0"> \ No newline at end of file Index: openacs-4/packages/messages/www/messages-folders.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/messages-folders.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/messages-folders.adp 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,153 @@ +<input type="hidden" id="add" value="#messages.add#"> +<input type="hidden" id="contacts" value="@contacts_list;noquote@"> +<input type="hidden" id="owner_id" value="@user_id;noquote@"> +<input type="hidden" id="not_permision_read" value="#messages.not_permision_read#"> +<span id="scroll_top"></span> + +<div id="autocomplete_loding" style="display:none"> + <div tabindex="-1" id="ids" class="clearfix tokenizer" onclick="$('autocomplete_input').focus()"> + <span class="tokenizer_stretcher">^_^</span> + <span class="tab_stop"><input type="text" id="hidden_input" tabindex="-1"></span> + <span id=contact_reply> + </span> + <div id="autocomplete_display" class="tokenizer_input"> + <input type="text" size="1" tabindex="" id="autocomplete_input" /> + </div> + </div> + <div id="autocomplete_populate" class="clearfix autocomplete typeahead_list" style="width: 358px; height: auto; overflow-y: hidden;display:none"> + <div class="typeahead_message">Type the name of a member</div> + </div> +</div> + +<script type="text/javascript"> + update_numbers(); + var contacts = [@contacts_list;noquote@]; + var typeahead = new Autocompleter.LocalAdvanced('autocomplete_input', 'autocomplete_populate', contacts, { + frequency: 0.1, + updateElement: addContactToList, + search_field: "name" + }); + var hidden_input = new HiddenInput('hidden_input',typeahead); + function contact_users() { + var typeahead = new Autocompleter.LocalAdvanced('autocomplete_input', 'autocomplete_populate', contacts, { + frequency: 0.1, + updateElement: addContactToList, + search_field: "name" + }); + var hidden_input = new HiddenInput('hidden_input',typeahead); + } + +</script> + +<div style="height:auto;text-align:center"> + <span id="msg_system"> + </span> + <span id="msg_action" style="display:none"> + <span class="alert"> + <strong> + <span id="msg_actions"></span> + </strong> + </span> + </span> +</div> +<br> +<table cellspacing="0" cellpadding="0" border="0" width="100%"> + <tr> + <th></th> + <th valign="top"> + <div id="top_menu"> + <div class="menuBar"> + <span id="return" style="display:none"> + <span onclick="return_msg(@user_id@);" style="cursor:pointer;">#messages.back#</span> + </span> + <span id="delete"> + <span class="yui-skin-sam"> + <span id="container"> + <input id="show_delete" type="button" value="#messages.delete#"> + </span> + </span> + </span> + <span id="delete_message_trash" style="display:none"> + <span class="yui-skin-sam"> + <span id="container"> + <input id="show_delete_trash" type="button" value="#messages.delete#" onclick="delete_select_msg()"> + </span> + </span> + </span> + <span id="delete_message" style="display:none"> + <a class="menuButton" href="" onclick="return move_to(3);"></a> + </span> + <span id="select_msg" style="position:absolute;right:0;display:none;align:right"> + <span id="msg_newer" style="text-align:right;cursor:pointer;"> + <span class="menuButton" onclick="select_message('newer');">#messages.newer# </span> + </span> + <span id="msg_older" style="text-align:right;cursor:pointer;"> + <span class="menuButton" onclick="select_message('older');"> #messages.older#</span> + </span> + </span> + <span> + <span id="move_to" sytle="display:true;"> + <input type="button" href="" onclick="show_div('fileMenu');return buttonClick(event, 'fileMenu');show_div('fileMenu');" value="#messages.move_to# ↓"> + </span> + </span> + <span id="more_actions_span"> + <input type="button" href="" onclick="show_div('more_actions');return buttonClick(event, 'more_actions');show_div('more_actions');" value="#messages.more_actions# ↓"> + </span> + <span id="search" class="menu"> + <input type="text" size="40" id="search_data" onKeyUp="valid_search(this.value);" onKeyPress="checkKey(event,this.value);" title="#messages.search_tooltip_text#"> + <input type="button" id="search_button" href="" onclick="search();" value="#messages.search#" disabled> + </span> + </div> + <div id="fileMenu" class="menu" onmouseover="menuMouseover(event);"> + <multiple name="folders"> + <if @folders.folder_id@ ne 1 and @folders.folder_id@ ne 4> + <a class="menuItem" href="javascript:onClick=move_to(@folders.folder_id@)" id="@folders.folder_id@">@folders.folder_name@</a> + </if> + </multiple> + </div> + <div id="more_actions" class="menu" onmouseover="menuMouseover(event);"> + <span id="action_as_unread" align="left"> + <a class="menuItem" href="javascript:more_actions('t',@folder_id@,@user_id@);" id="as_unread">#messages.as_unread#</a> + </span> + <span id="action_as_read"> + <a class="menuItem" href="javascript:more_actions('f',@folder_id@,@user_id@);" id="as_read">#messages.as_read#</a> + </span> + </div> + </div> + </th> + </tr> +</table> +<table cellspacing="0" cellpadding="0" border="0" width="100%"> + <tr> + <td valign="top"> + <br><br> + <b><u><a href="send" >#messages.compose_mail#</a></u></b><br><br> + <multiple name="folders"> + <div id="background_@folders.folder_id@" style="background-color:@folders.color@;weigth=100%;"> + <a href="javascript:get_messages_folder(@folders.folder_id@);update_numbers(@folders.folder_id@,@user_id@);"> + @folders.folder_name@ + <input type="hidden" value="@folders.total_new_msg@" id="new_msg_folder_@folders.folder_id@"> + <span id="number_@folders.folder_id@"> + </span> + </a> + </div> + </multiple> + <br> + <a class="button" href="message-option" >#messages.configuration#</a><br><br> + </td> + <td width="88%" valign="top" style="padding-left:10px"> + <script type="text/javascript"> + if (window.location.hash == "") { + get_messages_folder(0); + } else { + var url_msg = window.location.hash.split('a'); + var msg_id = url_msg[0].substring(1,url_msg[0].length); + read_message(msg_id,url_msg[1],url_msg[2]); + } + </script> + <span id="folder_section_display"> + </span> + </td> + </tr> +</table> + Index: openacs-4/packages/messages/www/messages-folders.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/messages-folders.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/messages-folders.tcl 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,26 @@ +ad_page_contract { + General page, list inbox, sent, draft, trash. + + @author pedro@viaro.net + @creation-date 2009-11-12 + @cvs-id $Id: messages-folders.tcl,v 1.1 2010/08/31 21:30:44 alvaror Exp $ +} { + {community_id ""} + {page_number ""} +} + +set page_title "[_ messages.folders]" +set context [list $page_title] +set user_id [ad_conn user_id] +set community_id [dotlrn_community::get_community_id] + +set contacts_list [util_memoize [list messages::get_community_users_fb -community_id $community_id] 86400] + +db_multirow -extend { color total_new_msg} folders get_folders_user { *SQL* } { + if { $folder_id == 0 } { + set color "#C0C0C0" + } else { + set color "#FFFFFF" + } +} + Index: openacs-4/packages/messages/www/messages-folders.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/messages-folders.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/messages-folders.xql 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="get_folders_user"> + <querytext> + select folder_id, folder_name + from messages_folders + where (user_id = :user_id + or user_id = 0) + order by folder_id asc + </querytext> + </fullquery> + +</queryset> Index: openacs-4/packages/messages/www/messages.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/messages.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/messages.adp 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,43 @@ +<master> +<property name="title">@page_title;noquote@</property> +<property name="context">@context;noquote@</property> +<script type="text/javascript"> +document.documentElement.className = "yui-pe"; +document.body.className += 'yui-skin-sam'; +</script> +<input type="hidden" id="dialog_rol_set" value="0"> +<script type="text/javascript" src="/resources/messages/dispatcher.js"></script> +<script type="text/javascript" src="/resources/messages/rol-dialog.js"></script> +<script type="text/javascript" src="/resources/messages/message-dialog-roles.js"></script> + +<include src="messages-actions"> +<input type="hidden" id="add" value="#messages.add#"> +<input type="hidden" id="owner_id" value="@user_id;noquote@"> +<input type="hidden" id="not_permision_read" value="#messages.not_permision_read#"> +<span id="scroll_top"></span> + + +<div id="mydynamicarea"> + <div style="height:auto;text-align:center"> + <span id="msg_action" style="display:none"> + <span class="alert"> + <strong> + <span id="msg_actions"></span> + </strong> + </span> + </span> + </div> +</div> + +<script type="text/javascript"> + loading(); + YAHOO.plugin.Dispatcher.fetch ( 'mydynamicarea', 'messages-folders' ); +</script> + +<div id="dialog1" class="yui-pe-content"> + <div class="bd"> + <div id="info_members_rols" "style="width:28em;height:30em;overflow:auto"> + </div> + </div> +</div> + \ No newline at end of file Index: openacs-4/packages/messages/www/messages.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/messages.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/messages.tcl 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,55 @@ +ad_page_contract { + General page, list inbox, sent, draft, trash. + + @author pedro@viaro.net + @creation-date 2009-11-12 + @cvs-id $Id: messages.tcl,v 1.1 2010/08/31 21:30:45 alvaror Exp $ +} { + {community_id ""} + {page_number ""} +} + +set page_title "[_ messages.folders]" +set context [list $page_title] +set user_id [ad_conn user_id] +set community_id [dotlrn_community::get_community_id] + +set ::acs_blank_master(xinha) 1 +set ::acs_blank_master(xinha.plugins) "'OacsFs'" +set ::acs_blank_master(xinha.options) "" +set ::acs_blank_master__htmlareas "" + +template::head::add_javascript -src "/resources/ajaxhelper/yui/yahoo-dom-event/yahoo-dom-event.js" -order "-1" +template::head::add_javascript -src "/resources/ajaxhelper/yui/yahoo/yahoo-min.js" -order "-14" +template::head::add_javascript -src "/resources/ajaxhelper/yui/element/element-beta-min.js" -order "-13" +template::head::add_javascript -src "/resources/ajaxhelper/yui/event/event-min.js" -order "-15" +template::head::add_javascript -src "/resources/ajaxhelper/yui/dom/dom-min.js" -order "-16" +template::head::add_javascript -src "/resources/ajaxhelper/yui/button/button-beta-min.js" -order "-17" +template::head::add_javascript -src "/resources/ajaxhelper/yui/utilities/utilities.js" -order "-18" +template::head::add_javascript -src "/resources/ajaxhelper/yui/history/history-beta-min.js" -order "-19" +template::head::add_javascript -src "/resources/ajaxhelper/yui/button/button-min.js" -order "-2" +template::head::add_javascript -src "/resources/ajaxhelper/yui/dragdrop/dragdrop-min.js" -order "2" +template::head::add_javascript -src "/resources/ajaxhelper/yui/container/container-min.js" -order "3" +template::head::add_javascript -src "/resources/messages/prototype.js" -order "4" +template::head::add_javascript -src "/resources/messages/effects.js" -order "5" +template::head::add_javascript -src "/resources/ajaxhelper/yui/dragdrop/dragdrop.js" -order "6" +template::head::add_javascript -src "/resources/messages/controls.js" -order "7" +template::head::add_javascript -src "/resources/messages/builder.js" -order "8" +template::head::add_javascript -src "/resources/messages/application.js" -order "9" +template::head::add_javascript -src "/resources/messages/messages.js" -order "10" +template::head::add_javascript -src "/resources/messages/dispatcher.js" +template::head::add_javascript -src "/resources/messages/dispatcher-min.js" +template::head::add_javascript -src "/resources/messages/menu.js" -order "11" +template::head::add_javascript -src "/resources/messages/delete-dialog.js" -order "12" +template::head::add_javascript -src "/resources/messages/message-attachment.js" -order "13" +template::head::add_css -href "/resources/messages/menu.css" -order "-2" +template::head::add_css -href "/resources/ajaxhelper/yui/fonts/fonts-min.css" -order "-3" +template::head::add_css -href "/resources/ajaxhelper/yui/button/assets/skins/sam/button.css" -order "-4" +template::head::add_css -href "/resources/ajaxhelper/yui/container/assets/skins/sam/container.css" -order "-5" +template::head::add_css -href "/resources/messages/messages.css" -order "-6" +template::head::add_css -href "/resources/messages/send.css" -order "1" +template::head::add_javascript -src "/resources/ajaxhelper/yui/connection/connection-min.js" + + + + Index: openacs-4/packages/messages/www/messages.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/messages.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/messages.xql 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="get_folders_user"> + <querytext> + select folder_id, folder_name + from messages_folders + where (user_id = :user_id + or user_id = 0) + order by folder_id asc + </querytext> + </fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/more-actions.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/more-actions.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/more-actions.adp 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1 @@ +@option_select@ \ No newline at end of file Index: openacs-4/packages/messages/www/more-actions.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/more-actions.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/more-actions.tcl 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,16 @@ +ad_page_contract { + Update numbers of new messages in the menu + + @author pedro@viaro.net + @creation-date 2009-11-24 + @cvs-id $Id: more-actions.tcl,v 1.1 2010/08/31 21:30:45 alvaror Exp $ +} { + msg_ids + option_select +} + +set community_id [dotlrn_community::get_community_id] +set user_id [ad_conn user_id] +db_transaction { + db_dml update_status_msg {} +} \ No newline at end of file Index: openacs-4/packages/messages/www/more-actions.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/more-actions.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/more-actions.xql 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="update_status_msg"> + <querytext> + update messages_user_messages + set new_p = :option_select + where parent_id in ($msg_ids) and user_id = :user_id + </querytext> + </fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/move-to.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/move-to.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/move-to.adp 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1 @@ +@folder_id;noquote@ \ No newline at end of file Index: openacs-4/packages/messages/www/move-to.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/move-to.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/move-to.tcl 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,17 @@ +ad_page_contract { + General page, list inbox, sent, draft, trash. + + @author pedro@viaro.net + @creation-date 2009-11-13 + @cvs-id $Id: move-to.tcl,v 1.1 2010/08/31 21:30:43 alvaror Exp $ +} { + {msg_ids ""} + {folder_id ""} +} + +set user_id [ad_conn user_id] +set folder_id_sent [messages::get_folder_id -folder_name "sent"] +set community_id [dotlrn_community::get_community_id] +db_transaction { + db_dml update_folder {} +} \ No newline at end of file Index: openacs-4/packages/messages/www/move-to.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/move-to.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/move-to.xql 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,11 @@ +<?xml version="1.0"?> +<queryset> + <fullquery name="update_folder"> + <querytext> + update messages_user_messages set folder_id = :folder_id + where parent_id in ($msg_ids) + and user_id = :user_id + and folder_id != :folder_id_sent + </querytext> + </fullquery> +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/new-folder.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/new-folder.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/new-folder.adp 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,26 @@ +<body bgcolor="#E0ECF8"> + +<script type="text/javascript" src="/resources/ajaxhelper/yui/yahoo-dom-event/yahoo-dom-event.js"></script> +<script type="text/javascript" src="/resources/ajaxhelper/yui/container/container_core.js"></script> +<script type="text/javascript" src="/resources/ajaxhelper/yui/menu/menu.js"></script> +<script type="text/javascript" src="/resources/ajaxhelper/yui/element/element-beta-min.js"></script> +<script type="text/javascript" src="/resources/ajaxhelper/yui/yahoo/yahoo-min.js"></script> +<script type="text/javascript" src="/resources/ajaxhelper/yui/event/event-min.js"></script> +<script type="text/javascript" src="/resources/ajaxhelper/yui/dom/dom-min.js"></script> +<script type="text/javascript" src="/resources/ajaxhelper/yui/button/button-beta-min.js"></script> + +<script type="text/javascript" src="/resources/ajaxhelper/yui/utilities/utilities.js"></script> +<script type="text/javascript" src="/resources/ajaxhelper/yui/connection/connection-min.js"></script> + + + +<script src="/resources/messages/messages.js" type="text/javascript"></script> +<input type=hidden id=new_folder_name_error value="#messages.new_folder_name_error#"> +<div align=center> + <form> + <label>#messages.name_new_folder#:</label><br> + <input type=text id=new_folder_name><br><br> + <input class="button" name="send_button" value="#messages.create#" type="button" onclick=create_new_folder(); > + <input class="button" name="cancel_button" value="#messages.cancel#" type="button" onclick=window.close()> + </form> +</div> \ No newline at end of file Index: openacs-4/packages/messages/www/print-message.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/print-message.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/print-message.adp 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,31 @@ +<script type="text/javascript"> + window.print(); +</script> + +<property name="title">@page_title;noquote@</property> +<property name="context">@context;noquote@</property> + +<span style="float:left;text-align:left;"> </span> + <span style="float:right;font-size:small;"><a class=button href="javascript:window.close()">#messages.close_window#</a></span><br> + <span style="float: right;text-align:right;">@owner_name@</span> +<br><br><br> +<hr> + <span style="float:left;text-align:left;font-size: large;">@subject@</span> +<br><br> + <span style="float:left;text-align:left;font-size: x-small;">#messages.messages#:@print:rowcount@</span> +<br> +<hr> +<multiple name="print"> + <span style="float:left;text-align:left;font-size: small;"> + <strong> @print.contact_names@ </strong> + </span> + <span style="float:right;text-align:left;font-size: small;"> + @print.ansi_time@ + </span> + <br><br> + @print.content;noquote@ + <br><hr> +</multiple> + + + Index: openacs-4/packages/messages/www/print-message.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/print-message.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/print-message.tcl 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,40 @@ +ad_page_contract { + Print the messages. + + @author pedro@viaro.net + @creation-date 2009-11-13 + @cvs-id $Id: print-message.tcl,v 1.1 2010/08/31 21:30:42 alvaror Exp $ +} { + {msg_id ""} +} + +set page_title "[_ messages.print]" +set context [list $page_title] +set user_id [ad_conn user_id] +set community_id [dotlrn_community::get_community_id] +set contact_names [db_list_of_lists get_contact_names {}] + +foreach contact $contact_names { + if { [lsearch -exact $contact $user_id] } { + set owner_name "[lindex $contact 0] <[lindex $contact 2]>" + break + } +} + +db_0or1row data_msg { *SQL* } + +set data_msg [db_list_of_lists get_data_msg {}] +set total_msg [llength $data_msg] + +db_multirow -extend { contact_names ansi_time content} print get_data_msg { *SQL* } { + set contact_list [db_list_of_lists get_contacts {}] + set contact_names [list] + foreach party_id $contact_list { + set contact_name [acs_user::get_element -user_id $party_id -element first_names] + lappend contact_names $contact_name + } + set contact_names [join $contact_names ","] + set day_recive [lc_time_fmt $sent_date "%d %b, %Y" ] + set ansi_time "$day_recive - $time" + set content [template::util::richtext::get_property content $msg_content] +} \ No newline at end of file Index: openacs-4/packages/messages/www/print-message.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/print-message.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/print-message.xql 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,56 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="get_contact_names"> + <querytext> + select acs_users_all.last_name||' '||acs_users_all.first_names as party_name, + acs_users_all.party_id, acs_users_all.email + from acs_users_all, + dotlrn_member_rels_approved + where dotlrn_member_rels_approved.community_id = :community_id + and dotlrn_member_rels_approved.user_id = acs_users_all.user_id + and acs_users_all.user_id = :user_id + </querytext> + </fullquery> + + <fullquery name="data_msg"> + <querytext> + select subject + from messages_messages + where msg_id = :msg_id + </querytext> + </fullquery> + + <fullquery name="get_data_msg"> + <querytext> + select msg_content, owner_id, community_id,parent_id, + sent_date, to_char(sent_date, 'HH24:MI:SS') as time,msg_id + from messages_messages + where msg_id in (select msg_id + from messages_user_messages + where user_id = :user_id + and parent_id = :msg_id) + order by msg_id asc + </querytext> + </fullquery> + + <fullquery name="get_contacts"> + <querytext> + select party_id + from messages_recipients + where msg_id = :msg_id + </querytext> + </fullquery> + + <fullquery name="get_name"> + <querytext> + select acs_users_all.last_name||' '||acs_users_all.first_names, acs_users_all.email + from acs_users_all, + dotlrn_member_rels_approved + where dotlrn_member_rels_approved.community_id = :community_id + and dotlrn_member_rels_approved.user_id = acs_users_all.user_id + and acs_users_all.user_id = :party_id + </querytext> + </fullquery> + +</queryset> Index: openacs-4/packages/messages/www/read-message.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/read-message.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/read-message.adp 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,36 @@ +<if @permition_read_p@ eq "f">false</if> +<else> + <input type="hidden" id="folder_id" value="@folder_id@"> + <input type="hidden" id="msg_id" value="@msg_id@"> + <input type="hidden" id="older_msg_id" value="@older_msg_id@"> + <input type="hidden" id="oldest_msg_id" value="@oldest_msg_id@"> + <input type="hidden" id="newer_msg_id" value="@newer_msg_id@"> + <input type="hidden" id="newest_msg_id" value="@newest_msg_id@"> + <input type="hidden" id="new_page_number" value="@new_page_number@"> + <br> + <div style="margin-left:10px"> + <input type="hidden" id="subject_field" value="@subject@"> + <table width="100%"> + <tr> + <th align="left"> + <strong style="font-size:15px"> + @subject@ + <input type="hidden" id="subject_fw" value="@subject@"> + <br> + </strong> + </th> + <th> + <span style="float: right;text-align:right;"> + <a href="print-message?msg_id=@msg_id@" target="_blank"> + <img src="/resources/messages/icono_imprimir.png" width="20" height="20">#messages.print# + </a> + </span> + </th> + </tr> + </table> + <span style="margin-right:10px;"> + <include src="read" folder_id="@folder_id@" page_number="@page_number@"> + </span> + </div> + <br> +</else> \ No newline at end of file Index: openacs-4/packages/messages/www/read-message.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/read-message.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/read-message.tcl 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,62 @@ +ad_page_contract { + Read the messages. + + @author pedro@viaro.net + @creation-date 2009-11-13 + @cvs-id $Id: read-message.tcl,v 1.1 2010/08/31 21:30:43 alvaror Exp $ +} { + {msg_id ""} + {folder_id ""} + {page_number ""} + {total_messages ""} +} + +set user_id [ad_conn user_id] +set community_id [dotlrn_community::get_community_id] +set parents_ids [db_list_of_lists get_parents_ids {}] +set get_max_messages [db_string get_max_messages {} -default 25] +set permition_read [db_string exist_msg {} -default 0] + +if { $permition_read == 0 } { + set permition_read_p "f" +} else { + set permition_read_p "t" +} + +########################################### +#get message ids around the message view +#and set range messages, before or after message display acording to message view. +set msg_before [expr [lsearch $parents_ids $msg_id] - 2] +set msg_after [expr [lsearch $parents_ids $msg_id] + 2] +set parents_ids [lrange $parents_ids $msg_before $msg_after] +set newer_msg_id [lindex $parents_ids [expr [lsearch $parents_ids $msg_id] - 1]] +############################################ +if {[empty_string_p $newer_msg_id]} { + set newer_msg_id "-1" +} +set newest_msg_id [lindex $parents_ids [expr [lsearch $parents_ids $msg_id] - 2]] +if {[empty_string_p $newest_msg_id]} { + set newest_msg_id "-1" +} +set older_msg_id [lindex $parents_ids [expr [lsearch $parents_ids $msg_id] + 1]] +if {[empty_string_p $older_msg_id]} { + set older_msg_id "-1" +} +set oldest_msg_id [lindex $parents_ids [expr [lsearch $parents_ids $msg_id] + 2]] +if {[empty_string_p $oldest_msg_id]} { + set oldest_msg_id "-1" +} + +set number_total_pages [expr [expr ceil([expr [expr $total_messages + 0.0] / [expr $get_max_messages + 0.0]])] - 1] + +if { !$number_total_pages } { + set new_page_number 1 +} else { + set new_page_number [expr [format %0.0f [expr ceil([lsearch $parents_ids $msg_id]/ $get_max_messages)]] + 1] +} + +db_0or1row data_msg { *SQL* } + +if { [empty_string_p $subject] } { + set subject "[_ messages.no_subject] " +} \ No newline at end of file Index: openacs-4/packages/messages/www/read-message.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/read-message.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/read-message.xql 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,81 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="data_msg"> + <querytext> + select subject, owner_id + from messages_messages + where msg_id = :msg_id + and community_id = :community_id + </querytext> + </fullquery> + + <fullquery name="get_parents_ids"> + <querytext> + select messages.msg_id + from (select max(m.msg_id) as last_msg_id, m.parent_id as msg_id, count(m.msg_id) as number_conversation + from (select msg_id, coalesce(parent_id,msg_id) as parent_id + from messages_messages + where community_id = :community_id + and msg_id in (select parent_id + from messages_user_messages + where user_id = :user_id + and folder_id = :folder_id)) m + group by m.parent_id + order by last_msg_id desc) messages + </querytext> + </fullquery> + + <fullquery name="get_max_messages"> + <querytext> + select max_messages + from messages_options + where user_id = :user_id + </querytext> + </fullquery> + + <fullquery name="get_attachment_id"> + <querytext> + select attachment_id + from messages_attachments + where msg_id in (select msg_id from messages_messages where community_id = :community_id and parent_id = :msg_id or msg_id = :msg_id) + </querytext> + </fullquery> + + <fullquery name="get_sol_info"> + <querytext> + select crr.title as content, + crr.title, + crr.item_id, + cri.storage_type, + crr.revision_id, + crr.content_length, + crr.mime_type, + crr.title + from cr_items cri, cr_revisions crr + where crr.revision_id = :attachment_id + and crr.item_id = cri.item_id + </querytext> + </fullquery> + + <fullquery name="exist_msg"> + <querytext> + select count(*) + from messages_user_messages + where user_id = :user_id + and parent_id = :msg_id + </querytext> + </fullquery> + + <fullquery name="get_members_ids_rel_type"> + <querytext> + select $rel_type_case as rel_type + from acs_rels + where object_id_one = :community_id + and object_id_two = :owner_id + </querytext> + </fullquery> + + +</queryset> + Index: openacs-4/packages/messages/www/read-oracle.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/read-oracle.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/read-oracle.xql 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,41 @@ +<?xml version="1.0"?> + +<queryset> + <rdbms><type>oracle</type><version>8.1.6</version></rdbms> + + <fullquery name="get_messages_info"> + <querytext> + select msg_content, owner_id, community_id,parent_id, subject, + sent_date, to_char(sent_date, 'HH24:MI:SS') as time, msg_id + from messages_messages + where msg_id in ($msg_ids) + order by msg_id asc + </querytext> + </fullquery> + + <fullquery name="get_contacts_ids"> + <querytext> + select msg_id,wm_concat(party_id) as contacts + from messages_recipients + where msg_id in ($msg_ids) + group by msg_id + </querytext> + </fullquery> + + <fullquery name="get_sol_info"> + <querytext> + select crr.title as content, + crr.title, + crr.item_id, + cri.storage_type, + crr.revision_id, + crr.content_length, + crr.mime_type, + crr.filename + from cr_items cri, cr_revisions crr + where crr.revision_id = :attachment_id + and crr.item_id = cri.item_id + </querytext> + </fullquery> + +</queryset> Index: openacs-4/packages/messages/www/read-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/read-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/read-postgresql.xql 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,48 @@ +<?xml version="1.0"?> +<queryset> + <rdbms><type>postgresql</type><version>7.3</version></rdbms> + + <fullquery name="get_contacts_ids"> + <querytext> + select msg_id, concat(distinct(party_id)||',') as contacts + from messages_recipients + where msg_id in ($msg_ids) + group by msg_id + </querytext> + </fullquery> + + <fullquery name="get_contacts_ids_roles"> + <querytext> + select msg_id, concat(distinct(rel_id)||',') as contacts + from messages_recipients_roles + where msg_id in ($msg_ids) + group by msg_id + </querytext> + </fullquery> + + <fullquery name="get_messages_info"> + <querytext> + select msg_content, owner_id, community_id,parent_id, subject, + to_char(sent_date, 'YYYY-MM-DD HH24:MI:SS') as sent_date, to_char(sent_date, 'HH24:MI:SS') as time, msg_id + from messages_messages + where msg_id in ($msg_ids) + order by msg_id asc + </querytext> + </fullquery> + + <fullquery name="get_sol_info"> + <querytext> + select crr.title as content, + crr.title, + crr.item_id, + cri.storage_type, + crr.revision_id, + crr.content_length, + crr.mime_type + from cr_items cri, cr_revisions crr + where crr.revision_id = :attachment_id + and crr.item_id = cri.item_id + </querytext> + </fullquery> + +</queryset> Index: openacs-4/packages/messages/www/read.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/read.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/read.adp 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,88 @@ +<script src="/resources/messages/messages.js" type="text/javascript"></script> +<input type="hidden" id="folder_id" value="@folder_id@"> +<input type="hidden" id="read" value="true"> +<input type="hidden" id="msg_reply" value=""> +<input type="hidden" id="parent_id_reply" value=""> +<input type="hidden" id="msg_action_id" value=""> +<multiple name="messages"> + <span id="msg_action_@messages.msg_id@" style="display:none"> + <span id=alert-message> + <span class="alert"> + <strong>#messages.msg_has_been_sent#</strong> + </span> + </span> + </span> + <div style="border-style:ridge;border-width:1px;"> + <table width="98%" valign="top" style="margin-left:10px;margin-left:15px;"> + <tr> + <th valign="top" align="left"> + <span id="from_@messages.msg_id@" style="float: left;text-align:left;display:none;"> <font color="#888888">#messages.from#: </font></span> + <strong>@messages.name_user@</strong> + <if @messages.rel_type_user@ ne ""> + <span style="background-color:#F06040;color:white;padding:2px;font-size:10px;"> #messages.message_sent_by#: @messages.rel_type_user@ </span> + </if> + <div style="overflow:hidden;width:100%;height:20px;" id="contact_list_@messages.msg_id@"> + <font color="#888888">#messages.to# @messages.first_name_contacts@ </font> + </div> + <span style="text-align:left;display:none;font-size: x-small;" id="details_@messages.msg_id@" > + <font color="#888888"> + <br> + #messages.to#: @messages.contact_names;noquote@ <br> + #messages.date#: @messages.ansi_time@ <br> + #messages.subject#: @messages.subject@ + </font> + </span> + <span style="margin-left:20px;font-size: 12px;color:#6E6E6E"> + <br><br> + @messages.msg_content;noquote@ + <br> + </span> + </th> + <th width="20%" valign="top" align="left"> + <div style="margin-left:20px;margin-left:18px;"> + <span class="margin-form"> + <span style="float: right;text-align:right;"> + @date@ + </span> + <span style="float: right;text-align:right;" id="show_details_@messages.msg_id@"> + <a href="javascript:mostrardiv(@messages.msg_id@);"> #messages.show_details#</a> + </span> + <span style="float: right;text-align:right;display:none;" id="close_details_@messages.msg_id@"> + <br> + <a href="javascript:close_dialog(@messages.msg_id@);">#messages.hide_details#</a> + </span> + </span> + <br><br> + <span> + @messages.download_file;noquote@ + </span> + </div> + </th> + </tr> + </table> + <br> + <span id="scroll_message_@messages.msg_id@"></span> + <div style="background-color:@color@"> + <table> + <th> + <td id="reply_@messages.msg_id@" style="background-color:@color@;"> + <a href="javascript:reply_dialog('reply',@messages.msg_id@,@general_parent_id@);update_numbers(@folder_id@,@user_id@);"><img src="/resources/messages/reply.png" width="15px" height="15px">#messages.reply# </a> + </td> + <if @messages.total_recipients@ gt 1> + <td id="reply_all_@messages.msg_id@" style="background-color:@color@;"> + <a href="javascript:reply_dialog('reply_all',@messages.msg_id@,@general_parent_id@);update_numbers(@folder_id@,@user_id@);"><img src="/resources/messages/reply-all.png" width="15px" height="15px">#messages.reply_all#</a> + </td> + </if> + <td id="forward_@messages.msg_id@" style=background-color:@color@;> + <a href="javascript:reply_dialog('forward',@messages.msg_id@,@general_parent_id@);update_numbers(@folder_id@,@user_id@);"><img src="/resources/messages/forward.png" width="15px" height="15px">#messages.forward#</a> + </td> + </th> + </table> + </div> + <span id=response_reply_mail_@messages.msg_id@ style="display:;"> + </span> + </div> + <br> +</multiple> + +<input type="hidden" id="rel_types_checked" value="@rel_types_checked@"> Index: openacs-4/packages/messages/www/read.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/read.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/read.tcl 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,131 @@ +ad_page_contract { + Read the messages. + + @author pedro@viaro.net + @creation-date 2009-11-13 + @cvs-id $Id: read.tcl,v 1.1 2010/08/31 21:30:45 alvaror Exp $ +} { + {msg_id ""} +} + +set general_parent_id $msg_id +set community_id [dotlrn_community::get_community_id] +set user_id [ad_conn user_id] +set color "#C0C0C0" +set msg_id_list [list] +db_dml update_status {} + +db_foreach get_msg_ids {} { + lappend msg_id_list $msg_id +} + +if { [llength $msg_id_list] > 0 } { + set msg_ids [join $msg_id_list ","] +} else { + set msg_ids "" +} + +db_foreach get_contacts_ids {} { + set contacts_ids_array($msg_id) $contacts +} + +db_foreach get_contacts_ids_roles {} { + set contacts_ids_array_roles($msg_id) $contacts +} + +##Roles: se estable los roles que existen y se obtienen lo usuarios y sus roles +set roles [dotlrn_community::get_roles -community_id $community_id] +set rel_types [list] +foreach role $roles { + lappend rel_types [lindex $role 0] +} +set rel_types [join $rel_types "','"] +set rel_type_case "case " +foreach {rel_type role pretty_name pretty_plural} [eval concat $roles] { + append rel_type_case "when rel_type = '$rel_type' then '$pretty_name' " +} +append rel_type_case " end" +### + +db_multirow -extend { rel_type_user to first_name_contacts name_user total_recipients contact_names download_file ansi_time } messages get_messages_info { *SQL* } { + ##Roles: se estable los roles que existen y se obtienen lo usuarios y sus roles + set rel_type_user [lang::util::localize [db_string get_members_ids_rel_type {}]] + + ### + set name_user [acs_user::get_element -user_id $owner_id -element name] + set download_file "" + set attachment [db_list_of_lists get_attachment_id {}] + + if { [llength $attachment] != 0} { + foreach attachment_info $attachment { + set attachment_id [lindex $attachment_info 0] + set attachment_item_id [lindex $attachment_info 1] + db_1row get_sol_info { *SQL* } + set position [string first . "$content" 1] + if { $position == "-1" } { + set position [string length $content] + } + append download_file "<img width=20 height=20 src=\"/resources/messages/attachment.png\"/><a style=\"font-size: 8pt\" target=\"_blank\" href=\"view/$title?file%5fid=$attachment_item_id\"> \ + [messages::string_truncate_middle -len 15 -string $title]</a><br>" + } + + } else { + set download_file "" + } + + set contact_names "" + set first_name_contacts "" + if { [array exists contacts_ids_array] != -1 } { + if { [lsearch [array name contacts_ids_array] $msg_id] == -1 } { + set contact_list "" + } else { + set contact_list [split $contacts_ids_array($msg_id) ","] + } + } else { + set contact_list "" + } + + + set total_recipients [llength $contact_list] + set name_to_p 0 + foreach party_id $contact_list { + if { ![empty_string_p $party_id] } { + set name [acs_user::get_element -user_id $party_id -element name] + if {$party_id == $owner_id} { + append contact_names $name ",<br> " + } else { + set name_to_p 1 + append first_name_contacts [string range $name 0 [expr [string first " " $name 0] - 1]] ", " + append contact_names $name ",<br> " + } + } + } + set rel_types [db_list get_rel_types {}] + set rel_types_checked [join $rel_types ","] + foreach rel_type $rel_types { + set pretty_name [dotlrn_community::get_role_pretty_plural -rel_type $rel_type] + append first_name_contacts $pretty_name ", " + append contact_names $pretty_name ",<br> " + } + if { $name_to_p } { + set to [string tolower [_ messages.to] 0 1] + } else { + set to "" + } + set first_name_contacts [string range $first_name_contacts 0 [expr [string length $first_name_contacts] - 3]] + set contact_names [string range $contact_names 0 [expr [string length $contact_names] - 60]] + set cur_time [clock format [clock seconds] -format "%Y %m %d"] + set sent_time_seconds [clock format [clock scan $sent_date] -format "%Y %m %d"]] + set day_recive [lc_time_fmt $sent_date "%d %b, %Y" ] + set ansi_time "$day_recive - $time" + set msg_content [template::util::richtext::get_property contents $msg_content] + if { [lindex $cur_time 0] > [lindex $sent_time_seconds 0]} { + set date [lc_time_fmt $sent_date "%D"] + } else { + if { ([lindex $cur_time 1] >= [lindex $sent_time_seconds 1]) && ([lindex $cur_time 2] == [lindex $sent_time_seconds 2] ) } { + set date [_ messages.today] + } else { + set date [lc_time_fmt $sent_date "%d %b" ] + } + } +} \ No newline at end of file Index: openacs-4/packages/messages/www/read.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/read.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/read.xql 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,95 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="get_msg_ids"> + <querytext> + select distinct(msg_id) + from messages_user_messages + where user_id = :user_id + and parent_id = :msg_id + </querytext> + </fullquery> + + <fullquery name="count_recipients"> + <querytext> + select count(party_id) + from messages_recipients + where msg_id = :msg_id + </querytext> + </fullquery> + + <fullquery name="update_status"> + <querytext> + update messages_user_messages + set new_p = 'f' + where parent_id = :msg_id + and user_id = :user_id + and new_p != 'f' + </querytext> + </fullquery> + + <fullquery name="get_name"> + <querytext> + select acs_users_all.last_name||' '||acs_users_all.first_names + from acs_users_all, + dotlrn_member_rels_approved + where dotlrn_member_rels_approved.community_id = :community_id + and dotlrn_member_rels_approved.user_id = acs_users_all.user_id + and acs_users_all.user_id = :party_id + </querytext> + </fullquery> + + <fullquery name="get_attachment_id"> + <querytext> + select attachment_id, attachment_item_id + from messages_attachments + where msg_id = :msg_id + </querytext> + </fullquery> + + <fullquery name="get_rel_types"> + <querytext> + select rel_id + from messages_recipients_roles + where msg_id = :msg_id + </querytext> + </fullquery> + + <fullquery name="get_messages_info"> + <querytext> + select msg_content, owner_id, community_id,parent_id, subject, + to_char(sent_date, 'YYYY-MM-DD HH24:MI:SS') as sent_date, to_char(sent_date, 'HH24:MI:SS') as time, msg_id + from messages_messages + where msg_id in ($msg_ids) + order by msg_id asc + </querytext> + </fullquery> + + <fullquery name="get_contacts_ids"> + <querytext> + select msg_id,wm_concat(party_id) as contacts + from messages_recipients + where msg_id in ($msg_ids) + group by msg_id + </querytext> + </fullquery> + + <fullquery name="get_contacts_ids_roles"> + <querytext> + select msg_id, wm_concat(distinct(rel_id)) as contacts + from messages_recipients_roles + where msg_id in ($msg_ids) + group by msg_id + </querytext> + </fullquery> + + <fullquery name="get_members_ids_rel_type"> + <querytext> + select $rel_type_case as rel_type + from acs_rels + where object_id_one = :community_id + and object_id_two = :owner_id + </querytext> + </fullquery> + +</queryset> Index: openacs-4/packages/messages/www/search-oracle.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/search-oracle.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/search-oracle.xql 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,53 @@ +<?xml version="1.0"?> + +<queryset> + <rdbms><type>oracle</type><version>8.1.6</version></rdbms> + + <fullquery name="get_msg_ids"> + <querytext> + select msg_id, last_msg_id + from (select paginate.*, rownum rowsub + from ( select max(msg_id) as last_msg_id, parent_id as msg_id, folder_id, count(msg_id) as number_conversation + from messages_user_messages + where user_id = :user_id + and msg_id in (select msg_id + from messages_messages + where community_id = :community_id + and (owner_id in (select person_id + from persons + $where_clause_user) + or msg_id in (select msg_id + from messages_recipients + where party_id in (select person_id + from persons + $where_clause_user)) + $search_clause)) + group by parent_id, folder_id + order by last_msg_id desc + ) paginate + where rownum <= :last_row) + where rowsub >= :first_row + </querytext> + </fullquery> + + + <fullquery name="get_messages"> + <querytext> + select mm.last_msg_id, mm.msg_id, mm.number_conversation, mm.subject, wm_concat(distinct(p.first_names)) as contacts, mm.folder_id + from persons p, + (select max(um.msg_id) as last_msg_id, um.parent_id as msg_id, count(um.msg_id) as number_conversation, m.subject, m.owner_id, um.folder_id + from (select parent_id,msg_id, folder_id + from messages_user_messages + where user_id = :user_id) um, + (select msg_id,subject,owner_id + from messages_messages + where community_id = :community_id + and msg_id in ($msg_ids)) m + where um.parent_id = m.msg_id + group by um.parent_id, m.subject, m.owner_id, um.folder_id) mm + where p.person_id = mm.owner_id + group by mm.msg_id, mm.subject, mm.last_msg_id, mm.number_conversation, mm.folder_id + order by mm.last_msg_id desc + </querytext> + </fullquery> +</queryset> Index: openacs-4/packages/messages/www/search-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/search-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/search-postgresql.xql 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,54 @@ +<?xml version="1.0"?> +<queryset> + <rdbms><type>postgresql</type><version>7.3</version></rdbms> + + <fullquery name="get_msg_ids"> + <querytext> + select msg_id, last_msg_id + from (select paginate.* + from ( select max(msg_id) as last_msg_id, parent_id as msg_id, folder_id, count(msg_id) as number_conversation + from messages_user_messages + where user_id = :user_id + and msg_id in (select msg_id + from messages_messages + where community_id = :community_id + and (owner_id in (select person_id + from persons + $where_clause_user) + or msg_id in (select msg_id + from messages_recipients + where party_id in (select person_id + from persons + $where_clause_user)) + $search_clause)) + group by parent_id, folder_id + order by last_msg_id desc + ) paginate + LIMIT :last_row) messages + OFFSET :first_row - 1 + </querytext> + </fullquery> + + <fullquery name="get_messages"> + <querytext> + select mm.last_msg_id, mm.msg_id, mm.number_conversation, mm.subject, concat(distinct(p.first_names)||',') as contacts, mm.folder_id + from persons p, + (select max(um.msg_id) as last_msg_id, um.parent_id as msg_id, count(um.msg_id) as number_conversation, m.subject, m.owner_id, um.folder_id + from (select parent_id,msg_id, folder_id + from messages_user_messages + where user_id = :user_id) um, + (select msg_id,subject,owner_id + from messages_messages + where community_id = :community_id + and msg_id in ($msg_ids)) m + where um.parent_id = m.msg_id + group by um.parent_id, m.subject, m.owner_id, um.folder_id) mm + where p.person_id = mm.owner_id + group by mm.msg_id, mm.subject, mm.last_msg_id, mm.number_conversation, mm.folder_id + order by mm.last_msg_id desc + </querytext> + </fullquery> + + +</queryset> + Index: openacs-4/packages/messages/www/search.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/search.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/search.adp 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,44 @@ +<input type="hidden" id="page_number" value=@page_number@> +<input type="hidden" id="folder_id" value=@folder_id@> +<input type="hidden" id="folder_id_state" value="@folder_id@"> +<input type="hidden" id="msg_continue_empty" value="#messages.msg_continue_empty#"> +<input type="hidden" id="number_messages" value=@total_messages@> + +<div align="right"> + <if @total_messages@ gt @show_messages@> + <if @page_number@ eq 2> + <a href="#" onClick="paginate(@folder_id@,@page_number@,'newer');update_numbers(@folder_id@,@user_id@)">#messages.newer# </a> + </if> + <if @page_number@ ge 3> + <a href="#" onClick="paginate(@folder_id@,1,'newest');update_numbers(@folder_id@,@user_id@)">#messages.newest# </a> + <a href="#" onClick="paginate(@folder_id@,@page_number@,'newer');update_numbers(@folder_id@,@user_id@)">#messages.newer# </a> + </if> + #messages.range_messages_show# + <if @page_number@ lt @total_pages@> + <a href="#" onClick="paginate(@folder_id@,@page_number@,'older');update_numbers(@folder_id@,@user_id@)">#messages.older# </a> + <if @page_number@ ne @oldest_page@> + <if @page_number@ lt @oldest_page@> + <a href="#" onClick="paginate(@folder_id@,@total_pages@,'oldest');update_numbers(@folder_id@,@user_id@)">#messages.oldest# </a> + </if> + </if> + </if> + </if> + <else> + <if @total_messages@ ne 0> #messages.range_messages_show# </if> + </else> +</div> +<if @folder_id@ eq 3> + <div id="folder_trash_msg" style="font-size:12px;" align="center"> + + <if @total_messages@ ne 0> + <a href="#" onclick="empty_trash()">#messages.empty_trash#</a> + </if> + #messages.folder_trash_msg# + </div> +</if> + +<form name="messages_list" method="GET"> + <div id="list_messages" style="weight:100%"> + <listtemplate name="messages"></listtemplate> + </div> +</form> Index: openacs-4/packages/messages/www/search.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/search.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/search.tcl 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,176 @@ +ad_page_contract { + Inbox Page + + @author pedro@viaro.net + @creation-date 2009-11-11 + @cvs-id $Id: search.tcl,v 1.1 2010/08/31 21:30:44 alvaror Exp $ +} { + {page_number ""} + {data_search ""} +} + +set user_id [ad_conn user_id] +set community_id [dotlrn_community::get_community_id] + +if {[empty_string_p $page_number]} { + set page_number 1 +} + +if { [exists_and_not_null data_search] } { + set data_search_list [string trim [split $data_search " "]] + set count 0 + foreach data_search $data_search_list { + set sql_keyword "%[string tolower $data_search]%" + if { $count == 0 } { + append where_clause_user "lower(first_names || ' ' || last_name) like '$sql_keyword'" + } else { + append where_clause_user " or lower(first_names || ' ' || last_name) like '$sql_keyword'" + } + incr count + append search_clause "or lower(msg_content) like '%'||lower('$data_search')||'%'" + append search_clause " or lower(subject) like '%'||lower('$data_search')||'%'" + } + set where_clause_user "where $where_clause_user" +} else { + set where_clause_user "" + set search_clause "" +} + +##################################################################### +#get the total messages and calculate how many pages have in folder show +#First and last row are calculate based on the total messages show per page +set total_messages [db_string get_total_messages {}] +set show_messages [db_string get_max_show_msg {} -default 25] +#Round to the next integer because the las page include some messages. +set total_pages [expr ceil([expr [expr $total_messages + 0.0] / [expr $show_messages + 0.0]])] +set oldest_page [expr $total_pages - 1] +set count_messages 0 +if { $page_number != 1} { + set first_row [expr [expr [expr $page_number - 1] * $show_messages] + 1] + set last_row [expr [expr $first_row + $show_messages] - 1] +} else { + set first_row [expr [expr $page_number - 1] * $show_messages] + set last_row [expr $first_row + $show_messages] + set first_row [expr $first_row + 1] +} +###################################################################### + +set elements [list msg_ids \ + [list label { <input type="checkbox" id="checkbox_general" name="_dummy" onclick="select_all(this.form,this.checked);" title="[_ acs-templating.lt_Checkuncheck_all_rows]">} \ + display_template {<input type="checkbox" id="check_box_msg.@messages.msg_id@" name="subject_id" value="@messages.msg_id@" id="msg_ids.@messages.msg_id@" title="[_ acs-templating.lt_Checkuncheck_this_row]" onclick="more_actions_select();">} \ + sub_class {narrow} \ + html { align center }] \ + ] + +lappend elements contacts \ + [list html { align left style "font-size: smaller; width:20%"} \ + label [_ messages.from] \ + display_template { <a href="#" onclick="read_message(@messages.msg_id@,@messages.folder_id@,$page_number)"> <if @messages.new_p@>\ + <span id="new_p.@messages.msg_id@"><span id="new_p_style.@messages.msg_id@" style="font-weight: bold;">@messages.contacts@ \ + <if @messages.folder_id@ ne 1> (@messages.number_conversation@) </if></span>\ + </if><else><span id="new_p_style.@messages.msg_id@" style="font-weight:;">@messages.contacts@ (@messages.number_conversation@)</span></else></a>} \ + ] \ + folder_id \ + [list html { align center style "font-size: smaller; width:5%"} \ + label "" \ + display_template { <input type="button" value="@messages.folder_name@" href="#" onclick="read_message(@messages.msg_id@,@messages.folder_id@,$page_number)"> }] \ + attachmet_mail \ + [list html { align center style "font-size: smaller; width:5%"} \ + label "" \ + display_template { <a href="#" onclick="read_message(@messages.msg_id@,@messages.folder_id@,$page_number)">\ + <if @messages.attachment_p@ gt 0><span style="font-weight: bold;"><img src="/resources/messages/attachment.png" width="20" height="20"></span> \ + </if></a>} \ + ] \ + subject_mail \ + [list html { align left style "font-size: smaller; width:65%"} \ + label [_ messages.subject] \ + display_template { <a href="#" onclick="read_message(@messages.msg_id@,@messages.folder_id@,$page_number)">\ + <if @messages.new_p@><span id="new_p_sub.@messages.msg_id@" style="font-weight: bold;">@messages.subject_mail@</span> \ + </if><else><span id="new_p_sub.@messages.msg_id@" style="font-weight:;">@messages.subject_mail@</span></else></a>} \ + ] \ + date \ + [list html { align left style "font-size: smaller;width:10%"} \ + label [_ messages.date] \ + display_template { <a href="#" onclick="read_message(@messages.msg_id@,@messages.folder_id@,$page_number)">\ + <if @messages.new_p@><span id="new_p_date.@messages.msg_id@" style="font-weight: bold;">@messages.date@</span> \ + </if><else><span id="new_p_date.@messages.msg_id@" style="font-weight:;">@messages.date@</span></else></a>} \ + ] + + +template::list::create \ + -name messages \ + -multirow messages \ + -main_class "list-table" \ + -html { width=100% } \ + -orderby_name orderby \ + -no_data "[_ messages.no_messages_found]" \ + -elements $elements + +set msg_id_list [list] +set last_msg_ids_list [list] +db_foreach get_msg_ids {} { + set last_msg_ids_array($msg_id) $last_msg_id + lappend last_msg_ids_list $last_msg_id + lappend msg_id_list $msg_id +} + +set msg_ids [join $msg_id_list ","] +set last_msg_ids [join $last_msg_ids_list ","] + +if { ![exists_and_not_null $msg_ids] } { + set folder_id 0 +} + +if { [empty_string_p $msg_ids] } { + set msg_ids 0 +} + +if { [empty_string_p $last_msg_ids] } { + set last_msg_ids 0 +} + +db_foreach get_attachment_p { } { + set get_attachment_array($parent_id) $count_attachment +} + +db_foreach get_new_p {} { + set new_p_array($parent_id) $new_p +} + +db_foreach get_msg_info {} { + set msg_content_array($parent_id) $msg_content + set date_sent_array($parent_id) $sent_date_ansi +} + +db_multirow -extend { subject_mail date attachment_p new_p folder_name} messages get_messages { *SQL* } { + set folder_name [db_string get_folder_name {}] + if { [info exists get_attachment_array($msg_id)]} { + set attachment_p $get_attachment_array($msg_id) + } else { + set attachment_p 0 + } + set msg_content $msg_content_array($msg_id) + set sent_date_ansi $date_sent_array($msg_id) + set content [ad_html_to_text [template::util::richtext::get_property contents $msg_content]] + append subject_mail $subject "-" [string_truncate -len 80 -ellipsis "..." " $content"] + set cur_time [clock format [clock seconds] -format "%Y %m %d"] + set sent_time_seconds [clock format [clock scan $sent_date_ansi] -format "%Y %m %d"] + #compare the sent date whith the current date and display the message according to the date. + if { [lindex $cur_time 0] > [lindex $sent_time_seconds 0]} { + set date [lc_time_fmt $sent_date_ansi "%D"] + } else { + if {[lindex $cur_time 1] >= [lindex $sent_time_seconds 1] && [lindex $cur_time 2] == [lindex $sent_time_seconds 2]} { + set date [_ messages.today] + } else { + set date [lc_time_fmt $sent_date_ansi "%d,%b,%Y %H:%M"] + } + } + if { [info exists new_p_array($msg_id)]} { + set new_p $new_p_array($msg_id) + } else { + set new_p 0 + } + incr count_messages +} + +set last_number [expr [expr $count_messages + $first_row] - 1] \ No newline at end of file Index: openacs-4/packages/messages/www/search.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/search.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/search.xql 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,93 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="get_name"> + <querytext> + select acs_users_all.last_name||' '||acs_users_all.first_names + from acs_users_all, + dotlrn_member_rels_approved + where dotlrn_member_rels_approved.community_id = :community_id + and dotlrn_member_rels_approved.user_id = acs_users_all.user_id + and acs_users_all.user_id = :party_id + </querytext> + </fullquery> + + <fullquery name="get_msg_info"> + <querytext> + select coalesce(parent_id,msg_id) as parent_id, msg_content, to_char(sent_date, 'YYYY-MM-DD HH24:MI:SS') as sent_date_ansi + from messages_messages + where msg_id in ($last_msg_ids) + </querytext> + </fullquery> + + <fullquery name="get_total_messages"> + <querytext> + select count(*) + from (select parent_id, folder_id + from messages_user_messages + where user_id = :user_id + and msg_id in (select msg_id + from messages_messages + where community_id = :community_id + and (owner_id in (select person_id + from persons + $where_clause_user) + or msg_id in (select msg_id + from messages_recipients + where party_id in (select person_id + from persons + $where_clause_user)) + $search_clause)) + group by parent_id,folder_id) as messages + </querytext> + </fullquery> + + <fullquery name="get_max_show_msg"> + <querytext> + select max_messages + from messages_options + where user_id = :user_id + </querytext> + </fullquery> + + <fullquery name="get_attachment_p"> + <querytext> + select um.parent_id, count(*) as count_attachment + from messages_attachments ma, + (select msg_id, parent_id + from messages_user_messages + where user_id = :user_id + and parent_id in ($msg_ids) + ) um + where ma.msg_id = um.msg_id + group by um.parent_id + </querytext> + </fullquery> + + <fullquery name="get_new_p"> + <querytext> + select parent_id, new_p + from messages_user_messages + where msg_id in ($last_msg_ids) + and user_id = :user_id + </querytext> + </fullquery> + + <fullquery name="get_owner_id"> + <querytext> + select owner_id + from messages_messages + where msg_id = :msg_id + and community_id = :community_id + </querytext> + </fullquery> + + <fullquery name="get_folder_name"> + <querytext> + select folder_name + from messages_folders + where folder_id = :folder_id + </querytext> + </fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/send-mail-oracle.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/send-mail-oracle.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/send-mail-oracle.xql 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,49 @@ +<?xml version="1.0"?> + +<queryset> + <rdbms><type>oracle</type><version>8.1.6</version></rdbms> + + <fullquery name="set_file_content"> + <querytext> + + update cr_revisions + set filename = :file_name, + mime_type = :mime_type, + content_length = :content_length + where revision_id = :revision_id + + </querytext> + </fullquery> + + <fullquery name="lob_content"> + <querytext> + + update cr_revisions + set content = empty_blob(), + filename = :filename + where revision_id = :revision_id + returning content into :1 + + </querytext> + </fullquery> + + + <fullquery name="get_sol_info"> + <querytext> + + select crr.title as content, + crr.title, + crr.item_id, + cri.storage_type, + crr.revision_id, + crr.content_length, + crr.mime_type + crr.filename + from cr_items cri, cr_revisions crr + where crr.revision_id = :attachment_id + and crr.item_id = cri.item_id + + </querytext> + </fullquery> + +</queryset> Index: openacs-4/packages/messages/www/send-mail-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/send-mail-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/send-mail-postgresql.xql 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,45 @@ +<?xml version="1.0"?> + +<queryset> + <rdbms><type>postgresql</type><version>7.3</version></rdbms> + +<fullquery name="set_file_content"> + <querytext> + + update cr_revisions + set content = :file_name, + mime_type = :mime_type, + content_length = :content_length + where revision_id = :revision_id + + </querytext> +</fullquery> + +<fullquery name="lob_content"> + <querytext> + + update cr_revisions + set lob = [set __lob_id [db_string get_lob_id "select empty_lob()"]] + where revision_id = :revision_id + + </querytext> +</fullquery> + +<fullquery name="get_sol_info"> + <querytext> + + select crr.title as content, + crr.title, + crr.item_id, + cri.storage_type, + crr.revision_id, + crr.content_length, + crr.mime_type + from cr_items cri, cr_revisions crr + where crr.revision_id = :attachment_id + and crr.item_id = cri.item_id + + </querytext> +</fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/send-mail.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/send-mail.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/send-mail.adp 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1 @@ +@msg_id;noquote@ \ No newline at end of file Index: openacs-4/packages/messages/www/send-mail.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/send-mail.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/send-mail.tcl 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,114 @@ +ad_page_contract { + Page send mail + + @author pedro@viaro.net + @creation-date 2009-11-11 + @cvs-id $Id: send-mail.tcl,v 1.1 2010/08/31 21:30:44 alvaror Exp $ +} { + {msg_id ""} + {subject ""} + {parent_id ""} + {contacts_ids ""} + {total_attachment 0} + {reply ""} + {content_msg ""} + {message:html ""} + {attachment_item_id ""} + {general_parent_id ""} + {msg_id_old ""} + {rel_types:multiple "" } + {attachment_ids ""} +} + +set community_id [dotlrn_community::get_community_id] +set owner_id [ad_conn user_id] +set community_name [dotlrn_community::get_community_name $community_id] +set contact_info "" +set rel_types_html "" +set fs_package_id [dotlrn_community::get_package_id_from_package_key -package_key file-storage -community_id $community_id] +set fs_folder_id [fs::get_root_folder -package_id $fs_package_id] +set attachment_item_id "" +set package_id [ad_conn package_id] +set admin_p [permission::permission_p -party_id $owner_id -object_id $package_id -privilege admin] + +if { $admin_p } { + set roles [dotlrn_community::get_roles -community_id $community_id] + foreach {rel_type role pretty_name pretty_plural} [eval concat $roles] { + append rel_types_html "<input type=checkbox value=\"$rel_type\" name=\"rel_types\" id=\"$rel_type\"> [lang::util::localize $pretty_plural] " + } + append rel_types_html "<input type=checkbox value=[_ messages.send_to_all] name=rel_types_all onclick=select_all_rel_types(this.checked)> [_ messages.send_to_all]" +} + +ad_form -html { enctype multipart/form-data } -name compose_message -form { } + +ad_form -extend -name compose_message -form { + +} -on_submit { + set count_attachment [expr $total_attachment + 1] + if { ![exists_and_not_null parent_id] } { + set parent_id "" + } + set base_url [dotlrn_community::get_community_url $community_id] + set message_url [export_vars -base "${base_url}messages/messages"] + set msg_id [messages::reply_mail -parent_id $parent_id -count_attachment $count_attachment \ + -contacts_ids $contacts_ids -community_id $community_id \ + -owner_id $owner_id -subject $subject -message $message -general_parent_id $general_parent_id \ + -message_url $message_url -msg_id_old $msg_id_old -attachment_ids $attachment_ids -rel_types $rel_types] + + for {set x 1} {$x < $count_attachment} {incr x} { + set name_attachment "upload_file_${x}" + ad_form -extend -name compose_message -form { + {upload_file_$x:file,optional + {label ""} + } + } + set upload_file [set $name_attachment] + if { ![empty_string_p $upload_file] } { + db_transaction { + set attachment_item_id "" + if { ![regexp {[^//\\]+$} $upload_file filename] } { + # no match + set filename $upload_file + } + set community_id [dotlrn_community::get_community_id] + set package_id [dotlrn_community::get_package_id_from_package_key -package_key messages -community_id $community_id] + set title [template::util::file::get_property filename $upload_file] + set item_name "[clock seconds]-${title}" + set mime_type [cr_filename_to_mime_type -create $title] + set folder_id [content::item::get_id -item_path "messages_attachments_${package_id}" -resolve_index f] + set creation_user [ad_conn user_id] + set creation_ip [ad_conn peeraddr] + # set storage_type to its default value according to a db constraint + set storage_type file + set attachment_item_id [content::item::new \ + -parent_id $folder_id \ + -name $item_name \ + -context_id $package_id \ + -content_type messages_attachments \ + -mime_type $mime_type \ + -storage_type $storage_type \ + -creation_user $creation_user \ + -creation_ip $creation_ip] + + set revision_id [content::revision::new -item_id $attachment_item_id \ + -mime_type $mime_type \ + -title $title \ + -content_type messages_attachments \ + -creation_user $creation_user \ + -creation_ip $creation_ip \ + -attributes [list [list msg_id $msg_id]\ + [list attachment_item_id $attachment_item_id] \ + ] ] + + content::item::set_live_revision -revision_id $revision_id + if { ![empty_string_p $upload_file] } { + set tmp_file [template::util::file::get_property tmp_filename $upload_file] + set content_length [file size $tmp_file] + # create the new item + set file_name [cr_create_content_file $attachment_item_id $revision_id $tmp_file] + db_dml set_file_content { *SQL* } + } + } + } + } +} \ No newline at end of file Index: openacs-4/packages/messages/www/send-mail.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/send-mail.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/send-mail.xql 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,13 @@ +<?xml version="1.0"?> + +<queryset> + +<fullquery name="lob_size"> + <querytext> + update cr_revisions + set content_length = :content_length + where revision_id = :revision_id + </querytext> +</fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/send-oracle.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/send-oracle.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/send-oracle.xql 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,49 @@ +<?xml version="1.0"?> + +<queryset> + <rdbms><type>oracle</type><version>8.1.6</version></rdbms> + + <fullquery name="set_file_content"> + <querytext> + + update cr_revisions + set filename = :file_name, + mime_type = :mime_type, + content_length = :content_length + where revision_id = :revision_id + + </querytext> + </fullquery> + + <fullquery name="lob_content"> + <querytext> + + update cr_revisions + set content = empty_blob(), + filename = :filename + where revision_id = :revision_id + returning content into :1 + + </querytext> + </fullquery> + + + <fullquery name="get_sol_info"> + <querytext> + + select crr.title as content, + crr.title, + crr.item_id, + cri.storage_type, + crr.revision_id, + crr.content_length, + crr.mime_type + crr.filename + from cr_items cri, cr_revisions crr + where crr.revision_id = :attachment_id + and crr.item_id = cri.item_id + + </querytext> + </fullquery> + +</queryset> Index: openacs-4/packages/messages/www/send-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/send-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/send-postgresql.xql 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,45 @@ +<?xml version="1.0"?> + +<queryset> + <rdbms><type>postgresql</type><version>7.3</version></rdbms> + +<fullquery name="set_file_content"> + <querytext> + + update cr_revisions + set content = :file_name, + mime_type = :mime_type, + content_length = :content_length + where revision_id = :revision_id + + </querytext> +</fullquery> + +<fullquery name="lob_content"> + <querytext> + + update cr_revisions + set lob = [set __lob_id [db_string get_lob_id "select empty_lob()"]] + where revision_id = :revision_id + + </querytext> +</fullquery> + +<fullquery name="get_sol_info"> + <querytext> + + select crr.title as content, + crr.title, + crr.item_id, + cri.storage_type, + crr.revision_id, + crr.content_length, + crr.mime_type + from cr_items cri, cr_revisions crr + where crr.revision_id = :attachment_id + and crr.item_id = cri.item_id + + </querytext> +</fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/send.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/send.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/send.adp 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,150 @@ +<if @reply_p@> + <master src="/packages/messages/www/xinha-master"> + <input type="hidden" id="dialog_rol_set" value="0"> +</if><else> + <master> + <property name="title">@page_title;noquote@</property> + <property name="context">@context;noquote@</property> + <input type="hidden" id="dialog_rol_set" value="1"> + <script type="text/javascript" src="/resources/ajaxhelper/yui/button/button-min.js"></script> + <script type="text/javascript" src="/resources/messages/rol-dialog.js"></script> + <style> + .composer{padding-top:10px;padding-left:10px;padding:10px 0 10px 10px;background:#FFFFFF;} + </style> + <a class="button" href="messages">#messages.back_folders#</a> +</else> + + +<span id="send_mail_loading" style="display:none"> + <span id=alert-message> + <span class="alert"> + <strong> + <span id=send_mail_wait style=text-align:center></span> + </strong> + </span> + </span> +</span> + +<input type=hidden id="sending" value="#messages.sending#"> +<input type=hidden id="add" value="#messages.add#"> +<input type=hidden id="delete_confirm" value="#messages.delete_confirm#"> +<input type="hidden" id="attachment_delete" value="#messages.delete#"> +<input type="hidden" id="contacts_list" value=""> +<input type=hidden id="subject_empty" value="#messages.subject_empty#"> +<input type=hidden id="body_empty" value="#messages.body_empty#"> +<span style='display:none' id="history_conversation">@history_conversation;noquote@</span> +<span style='display:none' id="signature">@signature;noquote@</span> +<if @reply_p@> + <div id=background style="background-color:#FFFFFF"> +</if> +<else> + <div id=background style="background-color:#E0F8F7"> +</else> + <div id="autocomplete"> + <div class="composer"> + <form id="compose_message" name="compose_message" enctype="multipart/form-data" action="@action_send@" method="POST"> + <formtemplate id="compose_message"> + @rel_types_html;noquote@ + <if @reply_p@ eq 0> + <input type="hidden" id="total_attachment" name="total_attachment" value="0"> + <input type="hidden" id="contacts_ids" name="contacts_ids" value=""> + <input type="hidden" id="subject" name="subject" value=""> + </if> + <br><br> + <dl class="clearfix"> + <table width="100%" style="font-size:10px"> + <tr> + <th width="5%" align="left"> + <label>#messages.to#:</label> + </th> + <th align="left"> + <div tabindex="-1" id="ids" class="clearfix tokenizer" onclick="$('autocomplete_input').focus()" width="600px"> + <span class="tokenizer_stretcher">^_^</span> + <span class="tab_stop"><input type="text" id="hidden_input" tabindex="-1"></span> + <span id=contact_reply></span> + <div id="autocomplete_display" class="tokenizer_input"> + <input type="text" size="1" tabindex="" id="autocomplete_input" onblur="delete_text_input(this.name)" /> + </div> + </div> + </th> + </tr> + </table> + <div id="autocomplete_populate" class="clearfix autocomplete typeahead_list" style="width: 358px; height: auto; overflow-y: hidden;display:none; z-index: 1000;"> + <div class="typeahead_message">Type the name of a member</div> + </div> + <script type="text/javascript"> + (new Image()).src='inbox/images/token.gif'; + (new Image()).src='inbox/images/token_selected.gif'; + (new Image()).src='inbox/images/token_hover.gif'; + (new Image()).src='inbox/images/token_x.gif'; + <if @reply_p@ eq 0> + var contacts = [@contacts_list;noquote@]; + </if> + var typeahead = new Autocompleter.LocalAdvanced('autocomplete_input', 'autocomplete_populate', contacts, { + frequency: 0.1, + updateElement: addContactToList, + search_field: "name" + }); + var hidden_input = new HiddenInput('hidden_input',typeahead); + </script> + <label style="font-size:8pt">#messages.to_help#</label> + <br> + <if @reply_p@ eq 0> + <br> + <input type=hidden id="recipients_empty" value="#messages.recipients_empty#"> + <table width="100%" style="font-size:12px"> + <tr> + <th width="5%" align="left"> + <label>#messages.subject#:</label> + </th> + <th align="left" width="95%"> + <input width="600px" class="subject" id="subject_field"> + </th> + </tr> + </table> + </if> + <else> + <input type=hidden id=@msg_id@_recipients_empty value="#messages.recipients_empty#"> + </else> + <br> + <label>#messages.message#:</label> + <dd class="field"> + <formwidget id=message> + </dd> + <dd> + <label>#messages.attachments#:</label> + <div id=attachment_forward style="display:none"> + @download_file;noquote@ + </div> + <a onclick="addField()" class="button">#messages.add_attachment#</a> + </dd> + <dd><div id="files"></div></dd><br> + <dd class="submits"> + <div class="submits_wrap"> + <if @reply_p@ ne 0> + <span id=submit_reply> + <a class="button" name="send_button" value="Send" type="button" onclick="submit_reply(@msg_id@,@general_parent_id@);Effect.ScrollTo('reply_@msg_id@');" >#messages.send#</a> + </span> + <a href="javascript:cancel(@msg_id@);" class="button" name="cancel_button" value="Cancel" type="button" >#messages.discard#</a> + </if> + <else> + <a class="button" name="send_button" value="Send" type="button" href="#" onclick="submit_normal();Effect.ScrollTo('send_mail_loading');" >#messages.send#</a> + <a href="messages" class="button" name="cancel_button" value="Cancel" type="button" >#messages.discard#</a> + </else> + </div> + <div class="sub_controls"></div> + </dd> + </dl> + </formtemplate> + </form> + </div> + </div> + +<if @reply_p@ eq 0> + <div id="dialog2" class="yui-pe-content"> + <div class="bd"> + <div id="info_members_rols" "style="width:28em;height:30em;overflow:auto"> + </div> + </div> + </div> +</if> \ No newline at end of file Index: openacs-4/packages/messages/www/send.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/send.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/send.tcl 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,216 @@ +ad_page_contract { + Send the message with attachment to users in the community. + +} { + {msg_id "" } + {subject ""} + {contacts_ids ""} + {total_attachment 0} + {reply ""} + {reply_p 0} + {general_parent_id ""} + {rel_types:multiple "" } + {reply_option ""} +} + +set page_title "[_ messages.messages]" +set context [list "[_ messages.compose_mail]"] +set community_id [dotlrn_community::get_community_id] +set rel_types_html "" +set owner_id [ad_conn user_id] +set package_id [ad_conn package_id] +set admin_p [permission::permission_p -party_id $owner_id -object_id $package_id -privilege admin] +#Set file javascript to members functions +if { $reply_p == 1 } { + set action_send "send-mail" + #when send message reply + set member_js "show_members_rol_index" +} else { + set action_send "send" + #When send a new message + set member_js "show_members_rol" +} + +set roles [dotlrn_community::get_roles -community_id $community_id] +if { $admin_p } { + foreach {rel_type role pretty_name pretty_plural} [eval concat $roles] { + if {![string equal $rel_type "dotlrn_student_rel"]} { + append rel_types_html "<input type=\"checkbox\" value=\"$rel_type\" name=\"rel_types\" id=\"$rel_type\"> <a onclick=\"${member_js}('$rel_type')\"><img src=\"/resources/messages/add.png\"></a> [lang::util::localize $pretty_plural] |" + } else { + append rel_types_html "<input type=\"checkbox\" value=\"$rel_type\" name=\"rel_types\" id=\"$rel_type\" onclick=\"${member_js}(this.id,this.checked)\"> [lang::util::localize $pretty_plural] |" + } + } + append rel_types_html "<input type=\"checkbox\" value=\"[_ messages.send_to_all]\" name=\"rel_types_all\" onclick=\"select_all_rel_types(this.checked);\"> [_ messages.send_to_all]" +} else { + foreach {rel_type role pretty_name pretty_plural} [eval concat $roles] { + if {[string equal $rel_type "dotlrn_ca_rel"] || [string equal $rel_type "dotlrn_instructor_rel"] } { + if {![string equal $rel_type "dotlrn_student_rel"]} { + append rel_types_html "<input type=\"checkbox\" value=\"$rel_type\" name=\"rel_types\" id=\"$rel_type\"> <a onclick=\"${member_js}('$rel_type')\"><img src=\"/resources/messages/add.png\"></a> [lang::util::localize $pretty_plural] |" + } else { + append rel_types_html "<input type=\"checkbox\" value=\"$rel_type\" name=\"rel_types\" id=\"$rel_type\" onclick=\"${member_js}(this.id,this.checked)\"> [lang::util::localize $pretty_plural] |" + } + } + } +} + +if {![exists_and_not_null show_master_p]} { + set show_master_p 1 + set reply_send 0 +} else { + set reply_send 1 +} + +if {![exists_and_not_null option]} { + set option "" +} + +set community_id [dotlrn_community::get_community_id] +if { !$reply_p } { + set contacts_list [util_memoize [list messages::get_community_users_fb -community_id $community_id] 86400] +} + +set signature_p [db_string signature_p {} -default 0] + +if { $signature_p } { + set signature [db_string get_signature {}] + set signature [ad_html_to_text [lindex $signature 0]] + set signature "<div id=signature><font color=\"#888888\"> -- <br> $signature</font></div>" +} else { + set signature "" +} + +if { [empty_string_p $signature] } { + set signature "" +} else { + set signature [string trim $signature] +} + +set attachment [db_list_of_lists get_attachment_id {}] +if { [llength $attachment] != 0} { + foreach attachment_info $attachment { + set attachment_id [lindex $attachment_info 0] + set attachment_item_id [lindex $attachment_info 1] + db_1row get_sol_info { *SQL* } + set position [string first . "$content" 1] + if { $position == "-1" } { + set position [string length $content] + } + append download_file "<input type=checkbox checked name=attachment_checkbox id=${attachment_id}>[string range $title 0 [expr $position - 1]]<br>" + } +} else { + set download_file "" +} + +set fs_package_id [dotlrn_community::get_package_id_from_package_key -package_key file-storage -community_id $community_id] +set fs_folder_id [fs::get_root_folder -package_id $fs_package_id] +set attachment_item_id "" + +set history_conversation [messages::get_history_conversation -parent_id $general_parent_id -msg_id $msg_id -user_id $owner_id] +set content_message_conversation "<br>$history_conversation $signature" + +if { ![string equal $reply_option "forward"] } { + set content_message_conversation "<p> </p><p> </p> $signature" +} + +ad_form -html { enctype multipart/form-data } -export { signature } -name compose_message -form { + {message:richtext(richtext),optional,nospell {label ""} {options {width "99%"}} {value "[list \"$content_message_conversation\" \"text/html\"]"} + {html {id "comments" rows 25 cols 50 onload "loadEditors('advancedMessagesEditor'); return false;"}} + } +} -on_submit { + set count_attachment [expr $total_attachment + 1] + if { ![exists_and_not_null parent_id] } { + set parent_id "" + } + + set base_url [dotlrn_community::get_community_url $community_id] + set message_url [export_vars -base "${base_url}messages/messages"] + set msg_id [messages::send_mail -parent_id $parent_id -count_attachment $count_attachment \ + -contacts_ids $contacts_ids -community_id $community_id \ + -owner_id $owner_id -subject $subject -message $message -message_url $message_url -rel_types $rel_types] + + for {set x 1} {$x < $count_attachment} {incr x} { + set name_attachment "upload_file_${x}" + ad_form -extend -name compose_message -form { + {upload_file_$x:file,optional + {label ""} + } + } + set upload_file [set $name_attachment] + if { ![empty_string_p $upload_file] } { + db_transaction { + set attachment_item_id "" + if { ![regexp {[^//\\]+$} $upload_file filename] } { + # no match + set filename ${x}_$upload_file + } + set community_id [dotlrn_community::get_community_id] + set package_id [dotlrn_community::get_package_id_from_package_key -package_key messages -community_id $community_id] + set title [template::util::file::get_property filename $upload_file] + set item_id [db_nextval acs_object_id_seq] + set item_name "${item_id}-${title}" + set mime_type [cr_filename_to_mime_type -create $title] + set folder_id [content::item::get_id -item_path "messages_attachments_${package_id}" -resolve_index f] + set creation_user [ad_conn user_id] + set creation_ip [ad_conn peeraddr] + # set storage_type to its default value according to a db constraint + set storage_type file + set attachment_item_id [content::item::new \ + -item_id $item_id \ + -parent_id $folder_id \ + -name $item_name \ + -context_id $package_id \ + -content_type messages_attachments \ + -mime_type $mime_type \ + -storage_type $storage_type \ + -creation_user $creation_user \ + -creation_ip $creation_ip] + + set revision_id [content::revision::new -item_id $attachment_item_id \ + -mime_type $mime_type \ + -title $title \ + -content_type messages_attachments \ + -creation_user $creation_user \ + -creation_ip $creation_ip \ + -attributes [list [list msg_id $msg_id]\ + [list attachment_item_id $attachment_item_id] \ + ] ] + + content::item::set_live_revision -revision_id $revision_id + if { ![empty_string_p $upload_file] } { + set tmp_file [template::util::file::get_property tmp_filename $upload_file] + set content_length [file size $tmp_file] + # create the new item + set file_name [cr_create_content_file $attachment_item_id $revision_id $tmp_file] + db_dml set_file_content { *SQL* } + } + } + } + } +} -after_submit { + ad_returnredirect "messages" + ad_script_abort +} + +template::head::add_javascript -src "/resources/ajaxhelper/yui/yahoo-dom-event/yahoo-dom-event.js" -order "-1" +template::head::add_javascript -src "/resources/ajaxhelper/yui/yahoo/yahoo-min.js" -order "-14" +template::head::add_javascript -src "/resources/ajaxhelper/yui/element/element-beta-min.js" -order "-13" +template::head::add_javascript -src "/resources/ajaxhelper/yui/event/event-min.js" -order "-15" +template::head::add_javascript -src "/resources/ajaxhelper/yui/dom/dom-min.js" -order "-16" +template::head::add_javascript -src "/resources/ajaxhelper/yui/button/button-beta-min.js" -order "-17" +template::head::add_javascript -src "/resources/ajaxhelper/yui/utilities/utilities.js" -order "-18" +template::head::add_javascript -src "/resources/ajaxhelper/yui/history/history-beta-min.js" -order "-19" +template::head::add_javascript -src "/resources/messages/prototype.js" -order "2" +template::head::add_javascript -src "/resources/messages/effects.js" -order "3" +template::head::add_javascript -src "/resources/ajaxhelper/yui/dragdrop/dragdrop.js" -order "4" +template::head::add_javascript -src "/resources/messages/controls.js" -order "5" +template::head::add_javascript -src "/resources/messages/builder.js" -order "7" +template::head::add_javascript -src "/resources/messages/application.js" -order "8" +template::head::add_javascript -src "/resources/messages/messages.js" -order "10" +template::head::add_javascript -src "/resources/messages/message-attachment.js" -order "11" +template::head::add_css -href "/resources/messages/send.css" +template::head::add_javascript -src "/resources/ajaxhelper/yui/container/container-min.js" +template::head::add_css -href "/resources/ajaxhelper/yui/fonts/fonts-min.css" +template::head::add_css -href "/resources/ajaxhelper/yui/button/assets/skins/sam/button.css" +template::head::add_css -href "/resources/ajaxhelper/yui/container/assets/skins/sam/container.css" + +template::head::add_javascript -src "/resources/ajaxhelper/yui/connection/connection-min.js" \ No newline at end of file Index: openacs-4/packages/messages/www/send.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/send.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/send.xql 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,62 @@ +<?xml version="1.0"?> + +<queryset> + + <fullquery name="members"> + <querytext> + select persons.first_names||' '||persons.last_name as party_name, + persons.person_id + from persons, + dotlrn_member_rels_approved + where dotlrn_member_rels_approved.community_id = :community_id + and dotlrn_member_rels_approved.user_id = persons.person_id + order by party_name + </querytext> + </fullquery> + + <fullquery name="signature_p"> + <querytext> + select signature_p + from messages_options + where user_id = :owner_id + </querytext> + </fullquery> + + <fullquery name="get_signature"> + <querytext> + select signature + from messages_options + where user_id = :owner_id + </querytext> + </fullquery> + + + <fullquery name="get_attachment_id"> + <querytext> + select attachment_id, attachment_item_id + from messages_attachments + where msg_id = :msg_id + </querytext> + </fullquery> + + <fullquery name="lob_size"> + <querytext> + update cr_revisions + set content_length = :content_length + where revision_id = :revision_id + </querytext> + </fullquery> + +<fullquery name="set_file_content"> + <querytext> + + update cr_revisions + set title = :title, + mime_type = :mime_type, + content_length = :content_length + where revision_id = :revision_id + + </querytext> +</fullquery> + +</queryset> Index: openacs-4/packages/messages/www/test.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/test.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/test.adp 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,2 @@ +<master> +@contacts_list@ Index: openacs-4/packages/messages/www/test.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/test.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/test.tcl 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,26 @@ +ad_page_contract { + General page, list inbox, sent, draft, trash. + + @author pedro@viaro.net + @creation-date 2009-11-12 + @cvs-id $Id: test.tcl,v 1.1 2010/08/31 21:30:42 alvaror Exp $ +} { + {community_id ""} + {page_number ""} +} + +set page_title "[_ messages.folders]" +set context [list $page_title] +set user_id [ad_conn user_id] +set community_id [dotlrn_community::get_community_id] + +set count_members [db_string count_members {}] + +for {set i 0} { $i < $count_members} {set i [expr $i + 1500] } { + ns_log notice ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ciclo for $i" + set limit [expr $i + 1500] + append contacts_list [join [db_list members { *SQL* }] ","] +} + +ns_log notice ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> count_members $count_members" + Index: openacs-4/packages/messages/www/test.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/test.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/test.xql 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="get_folders_user"> + <querytext> + select folder_id, folder_name + from messages_folders + where (user_id = :user_id + or user_id = 0) + order by folder_id asc + </querytext> + </fullquery> + + <fullquery name="members"> + <querytext> + select concat('{n:"'||to_clob(party_name)||'", p:"'||to_clob(person_id)||'"}') as contact + from (select persons.first_names||' '||persons.last_name as party_name, persons.person_id + from persons,dotlrn_member_rels_approved + where dotlrn_member_rels_approved.community_id = :community_id + and dotlrn_member_rels_approved.user_id = persons.person_id and rownum <= $limit and rownum > $i + order by party_name) + </querytext> + </fullquery> + + <fullquery name="members2"> + <querytext> + select '{n:"'||party_name||'", p:"'||person_id||'"}' as contact + from (select persons.first_names||' '||persons.last_name as party_name, persons.person_id + from persons,dotlrn_member_rels_approved + where dotlrn_member_rels_approved.community_id = :community_id + and dotlrn_member_rels_approved.user_id = persons.person_id and rownum > 1500 + order by party_name) + </querytext> + </fullquery> + + <fullquery name="count_members"> + <querytext> + select count(*) + from persons,dotlrn_member_rels_approved + where dotlrn_member_rels_approved.community_id = :community_id + and dotlrn_member_rels_approved.user_id = persons.person_id + </querytext> + </fullquery> + +</queryset> Index: openacs-4/packages/messages/www/update-name.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/update-name.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/update-name.adp 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1 @@ +@folder_id;noquote@ \ No newline at end of file Index: openacs-4/packages/messages/www/update-name.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/update-name.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/update-name.tcl 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,24 @@ +ad_page_contract { + Update the folder name + + @author pedro@viaro.net + @creation-date 2010-01-19 + @cvs-id $Id: update-name.tcl,v 1.1 2010/08/31 21:30:43 alvaror Exp $ +} { + {name ""} + {delete "f"} + folder_id +} + +set user_id [ad_conn user_id] +set folder_id_inbox [messages::get_folder_id -folder_name "inbox"] +if { [string equal $delete "t"] } { + db_transaction { + db_dml update_messages { *SQL* } + db_dml delete_folder { *SQL* } + } +} elseif {![empty_string_p $name]} { + db_transaction { + db_dml update_name { *SQL* } + } +} \ No newline at end of file Index: openacs-4/packages/messages/www/update-name.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/update-name.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/update-name.xql 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,23 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="update_name"> + <querytext> + update messages_folders set folder_name = :name where folder_id = :folder_id + </querytext> + </fullquery> + + <fullquery name="delete_folder"> + <querytext> + delete from messages_folders where folder_id = :folder_id + </querytext> + </fullquery> + + <fullquery name="update_messages"> + <querytext> + update messages_user_messages set folder_id = :folder_id_inbox + where folder_id = :folder_id and user_id = :user_id + </querytext> + </fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/update-numbers.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/update-numbers.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/update-numbers.adp 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1 @@ +@numbers;noquote@ \ No newline at end of file Index: openacs-4/packages/messages/www/update-numbers.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/update-numbers.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/update-numbers.tcl 31 Aug 2010 21:30:42 -0000 1.1 @@ -0,0 +1,28 @@ +ad_page_contract { + Update numbers of new messages in the menu + + @author pedro@viaro.net + @creation-date 2009-11-17 + @cvs-id $Id: update-numbers.tcl,v 1.1 2010/08/31 21:30:42 alvaror Exp $ +} { + +} + +append not_folder_ids [messages::get_folder_id -folder_name "sent"] "," \ + [messages::get_folder_id -folder_name "trash"] + +set user_id [ad_conn user_id] +set community_id [dotlrn_community::get_community_id] +set folders_info [db_list_of_lists count_new_messages {}] +set numbers [list] +foreach folder $folders_info { + lappend numbers [lindex $folder 0] + lappend numbers [lindex $folder 1] + lappend numbers [lindex $folder 2] +} + +if { [llength $numbers] } { + set numbers [join $numbers ","] +} else { + set numbers " " +} Index: openacs-4/packages/messages/www/update-numbers.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/update-numbers.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/update-numbers.xql 31 Aug 2010 21:30:43 -0000 1.1 @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="count_new_messages"> + <querytext> + select count (case when um.new_p = 't' then 1 end ) as new_t, um.folder_id, + count (um.new_p) as total + from (select distinct(parent_id) as msg_id,folder_id,new_p + from messages_user_messages + where user_id = :user_id + and msg_id in (select msg_id + from messages_messages + where community_id = :community_id) + and folder_id not in ($not_folder_ids)) um + group by um.folder_id + order by folder_id + </querytext> + </fullquery> + +</queryset> \ No newline at end of file Index: openacs-4/packages/messages/www/xinha-master.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/xinha-master.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/xinha-master.adp 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,18 @@ +<slave> +<p id="advancedMessagesEditor" style="display: none;"> +xinha_editors = null; +xinha_init = null; +xinha_config = null; +xinha_plugins = [@xinha_plugins@]; +Xinha.loadPlugins(xinha_plugins,null); +xinha_editors = xinha_editors ? xinha_editors :[ @htmlarea_ids@ ]; +xinha_config = xinha_config ? xinha_config() : new Xinha.Config(); +@xinha_params@ +@xinha_options@ +xinha_editors = +Xinha.makeEditors(xinha_editors, xinha_config, xinha_plugins); +Xinha.startEditors(xinha_editors); +</p> +<p id="advancedMessagesIds" style="display: none;"> +@htmlarea_ids@ +</p> \ No newline at end of file Index: openacs-4/packages/messages/www/xinha-master.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/xinha-master.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/xinha-master.tcl 31 Aug 2010 21:30:44 -0000 1.1 @@ -0,0 +1,11 @@ + set ::xinha_dir /resources/acs-templating/xinha-nightly/ + set ::xinha_lang [lang::conn::language] + + # We could add site wide Xinha configurations (.js code) into xinha_params + set xinha_params "" + + # Per call configuration + set xinha_plugins $::acs_blank_master(xinha.plugins) + set xinha_options $::acs_blank_master(xinha.options) + # HTML ids of the textareas used for Xinha + set htmlarea_ids '[join $::acs_blank_master__htmlareas "','"]' Index: openacs-4/packages/messages/www/resources/Delete16-on.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/Delete16-on.gif,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/add.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/add.png,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/application.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/application.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/application.js 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1,338 @@ +validate_party_id = function(party_id) { + var regexparty_id = /^(("[\w-\s]+")|([\w-]+(?:\.[\w-]+)*)|("[\w-\s]+")([\w-]+(?:\.[\w-]+)*))(@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][0-9]\.|1[0-9]{2}\.|[0-9]{1,2}\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\]?$)/i + return regexparty_id.test(party_id); + +} + +Autocompleter.LocalAdvanced = Class.create(Autocompleter.Base, { + initialize: function(element, update, array, options) { + this.baseInitialize(element, update, options); + this.options.array = array; + this.wrapper = $(this.element.parentNode); + + if (!this.element.hacks) { + this.element.should_use_borderless_hack = Prototype.Browser.WebKit; + this.element.should_use_shadow_hack = Prototype.Browser.IE || Prototype.Browser.Opera; + this.element.hacks = true; + } + if (this.element.should_use_borderless_hack || this.element.should_use_shadow_hack) { this.wrapper.addClassName('tokenizer_input_borderless'); } + + this.options.onShow = function(element,update) { + Position.clone(element.parentNode.parentNode, update, { + setHeight: false, + setWidth: false, + offsetTop: element.parentNode.parentNode.offsetHeight + }); + update.show(); + + } + this.options.onHide = function(element, update){ update.hide() }; + + + }, +getUpdatedChoices: function() { + this.updateChoices(this.options.selector(this)); + + }, + +onBlur: function($super, event) { + $super(); + //move itself back to the end on blur + if (this.wrapper.nextSiblings().length > 0) { + this.wrapper.nextSiblings().last().insert({ + after: this.wrapper + }); + + } + + }, +set_input_size: function(size) { + size = size || 20; + this.element.setStyle({width: size + "px"}); +}, +onKeyPress: function(event) { + //dynamically resize the input field + var new_size = 20 + (this.element.value.length * 7); + if (new_size <= 340) { + this.set_input_size(new_size); + } else { + this.set_input_size(340); + } + //active is when there's suggesitons found + if (this.active) + switch (event.keyCode) { + case Event.KEY_TAB: + case Event.KEY_RETURN: + this.selectEntry(); + Event.stop(event); + case Event.KEY_ESC: + this.hide(); + this.active = false; + Event.stop(event); + return; + case Event.KEY_LEFT: + case Event.KEY_RIGHT: + return; + case Event.KEY_UP: + this.markPrevious(); + this.render(); + Event.stop(event); + return; + case Event.KEY_DOWN: + this.markNext(); + this.render(); + Event.stop(event); + return; + + } + else { + if (event.keyCode == Event.KEY_TAB || event.keyCode == Event.KEY_RETURN || + (Prototype.Browser.WebKit > 0 && event.keyCode == 0) || event.keyCode == 44 /* , comma */ || event.keyCode == 188 ) { + var party_id_addr = this.element.value.strip().sub(',', '') + //recognise party_id format + if (validate_party_id(party_id_addr)) { + addparty_idToList(party_id_addr); + Event.stop(event); + } + this.element.value = ""; + this.set_input_size(); + return false; + + } + switch (event.keyCode) { + //jump left to token + case Event.KEY_LEFT: + case Event.KEY_BACKSPACE: + if (this.element.value == "" && typeof this.wrapper.previous().token != "undefined") { + this.wrapper.previous().token.select(); + + } + return; + //jump right to token + case Event.KEY_RIGHT: + if (this.element.value == "" && this.wrapper.next() && typeof this.wrapper.next().token != "undefined") { + this.wrapper.next().token.select(); + + } + + } + + } + + this.changed = true; + this.hasFocus = true; + + if (this.observer) clearTimeout(this.observer); + this.observer = + setTimeout(this.onObserverEvent.bind(this), this.options.frequency * 1000); + + }, + +setOptions: function(options) { + this.options = Object.extend({ + choices: 10, + partialSearch: true, + partialChars: 2, + ignoreCase: true, + fullSearch: false, + selector: function(instance) { + var ret = []; + // Beginning matches + var partial = []; + // Inside matches + var entry = instance.getToken(); + var count = 0; + + for (var i = 0; i < instance.options.array.length && + ret.length < instance.options.choices; i++) { + + var elem = instance.options.array[i]; + var elem_name = elem[instance.options.search_field]; + var foundPos = instance.options.ignoreCase ? + elem_name.toLowerCase().indexOf(entry.toLowerCase()) : + elem_name.indexOf(entry); + + while (foundPos != -1) { + + if (foundPos == 0 && elem_name.length != entry.length) { + var value = "<strong>" + elem_name.substr(0, entry.length) + "</strong>" + elem_name.substr(entry.length); + ret.push( + "<li value='" + i + "'>" + "<div>" + value + "</div>" + + "<div style=display:none>" + elem.p + "</div>" + "</li>" + ); + break; + + } else if (entry.length >= instance.options.partialChars && instance.options.partialSearch && foundPos != -1) { + if (instance.options.fullSearch || /\s/.test(elem_name.substr(foundPos - 1, 1))) { + var value = elem_name.substr(0, foundPos) + "<strong>" + + elem_name.substr(foundPos, entry.length) + "</strong>" + elem_name.substr( + foundPos + entry.length) + + partial.push( + "<li value='" + i + "'>" + "<div>" + value + "</div>" + + "<div style=display:none>" + elem.p + "</div>" + "</li>" + ); + break; + + } + + } + foundPos = instance.options.ignoreCase ? + elem_name.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : + elem_name.indexOf(entry, foundPos + 1); + + + } + + } + if (partial.length) + ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)); + return "<ul>" + ret.join('') + "</ul>"; + + } + + }, + options || {}); + + } + +}); +HiddenInput = Class.create({ + initialize: function(element, auto_complete) { + this.element = $(element); + this.auto_complete = auto_complete; + this.token; + Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); + + }, + onKeyPress: function(event) { + if (this.token.selected) { + switch (event.keyCode) { + case Event.KEY_LEFT: + this.token.element.insert({ + before: + this.auto_complete.wrapper + }) + this.token.deselect(); + this.auto_complete.element.focus(); + return false; + case Event.KEY_RIGHT: + this.token.element.insert({ + after: + this.auto_complete.wrapper + }) + this.token.deselect(); + this.auto_complete.element.focus(); + return false; + case Event.KEY_BACKSPACE: + case Event.KEY_DELETE: + this.token.element.remove(); + this.auto_complete.element.focus(); + return false; + + } + + } + + } + + +}) + Token = Class.create({ + initialize: function(element, hidden_input) { + this.element = $(element); + this.hidden_input = hidden_input; + this.element.token = this; + this.selected = false; + Event.observe(document, 'click', this.onclick.bindAsEventListener(this)); + + }, + select: function() { + this.hidden_input.token = this; + this.hidden_input.element.activate(); + this.selected = true; + this.element.addClassName('token_selected'); + + }, + deselect: function() { + this.hidden_input.token = "undefined"; + this.selected = false; + this.element.removeClassName('token_selected') + + }, + onclick: function(event) { + if (this.detect(event) && !this.selected) { + this.select(); + + } else { + this.deselect(); + + } + + }, + detect: function(e) { + //find the event object + var eventTarget = e.target ? e.target: e.srcElement; + var token = eventTarget.token; + var candidate = eventTarget; + while (token == null && candidate.parentNode) { + candidate = candidate.parentNode; + token = candidate.token; + + } + return token != null && token.element == this.element; + + } + +}); + + +addContactToList = function(item) { + $('autocomplete_input').value = ""; + var token = Builder.node('a', { + "class": 'token', + href: "#", + tabindex: "-1" + }, + Builder.node('span', + Builder.node('span', + Builder.node('span', + Builder.node('span', {}, + [Builder.node('input', { type: "hidden", name: "ids[]", + value: item.lastChild.innerHTML + }), + contacts[Element.readAttribute(item,'value')].name, + Builder.node('span',{"class":'x',onmouseout:"this.className='x'",onmouseover:"this.className='x_hover'", + onclick:"this.parentNode.parentNode.parentNode.parentNode.parentNode.remove(true); return false;"}," ") + ] + ) + ) + ) + ) + ); + $(token).down(4).next().innerHTML = " "; + new Token(token,hidden_input); + $('autocomplete_display').insert({before:token}); +} +addparty_idToList = function(party_id) { +/* $('autocomplete_input').value = "";*/ + var token = Builder.node('a',{"class":'token',href:"#",tabindex:"-1"}, + Builder.node('span', + Builder.node('span', + Builder.node('span', + Builder.node('span',{},[ + Builder.node('input',{type:"hidden",name:"party_ids[]",value: party_id} ) , + party_id, + Builder.node('span',{"class":'x',onmouseout:"this.className='x'",onmouseover:"this.className='x_hover'", + onclick:"this.parentNode.parentNode.parentNode.parentNode.parentNode.remove(true); return false;"}," ") + ] + ) + ) + ) + ) + ); + $(token).down(4).next().innerHTML = " "; + new Token(token,hidden_input); + $('autocomplete_display').insert({before:token}); +} + Index: openacs-4/packages/messages/www/resources/arrow_down.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/arrow_down.gif,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/arrow_down.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/arrow_down.png,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/attachment.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/attachment.png,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/before_arr.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/before_arr.gif,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/builder.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/builder.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/builder.js 31 Aug 2010 21:30:50 -0000 1.1 @@ -0,0 +1,129 @@ +var Builder = { + NODEMAP: { + AREA: 'map', + CAPTION: 'table', + COL: 'table', + COLGROUP: 'table', + LEGEND: 'fieldset', + OPTGROUP: 'select', + OPTION: 'select', + PARAM: 'object', + TBODY: 'table', + TD: 'table', + TFOOT: 'table', + TH: 'table', + THEAD: 'table', + TR: 'table' + }, + // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken, + // due to a Firefox bug + node: function(elementName) { + elementName = elementName.toUpperCase(); + + // try innerHTML approach + var parentTag = this.NODEMAP[elementName] || 'div'; + var parentElement = document.createElement(parentTag); + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" + elementName + "></" + elementName + ">"; + } catch(e) {} + var element = parentElement.firstChild || null; + + // see if browser added wrapping tags + if(element && (element.tagName.toUpperCase() != elementName)) + element = element.getElementsByTagName(elementName)[0]; + + // fallback to createElement approach + if(!element) element = document.createElement(elementName); + + // abort if nothing could be created + if(!element) return; + + // attributes (or text) + if(arguments[1]) + if(this._isStringOrNumber(arguments[1]) || + (arguments[1] instanceof Array) || + arguments[1].tagName) { + this._children(element, arguments[1]); + } else { + var attrs = this._attributes(arguments[1]); + if(attrs.length) { + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" +elementName + " " + + attrs + "></" + elementName + ">"; + } catch(e) {} + element = parentElement.firstChild || null; + // workaround firefox 1.0.X bug + if(!element) { + element = document.createElement(elementName); + for(attr in arguments[1]) + element[attr == 'class' ? 'className' : attr] = arguments[1][attr]; + } + if(element.tagName.toUpperCase() != elementName) + element = parentElement.getElementsByTagName(elementName)[0]; + } + } + + // text, or array of children + if(arguments[2]) + this._children(element, arguments[2]); + + return element; + }, + _text: function(text) { + return document.createTextNode(text); + }, + + ATTR_MAP: { + 'className': 'class', + 'htmlFor': 'for' + }, + + _attributes: function(attributes) { + var attrs = []; + for(attribute in attributes) + attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) + + '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'"') + '"'); + return attrs.join(" "); + }, + _children: function(element, children) { + if(children.tagName) { + element.appendChild(children); + return; + } + if(typeof children=='object') { // array can hold nodes and text + children.flatten().each( function(e) { + if(typeof e=='object') + element.appendChild(e); + else + if(Builder._isStringOrNumber(e)) + element.appendChild(Builder._text(e)); + }); + } else + if(Builder._isStringOrNumber(children)) + element.appendChild(Builder._text(children)); + }, + _isStringOrNumber: function(param) { + return(typeof param=='string' || typeof param=='number'); + }, + build: function(html) { + var element = this.node('div'); + $(element).update(html.strip()); + return element.down(); + }, + dump: function(scope) { + if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope + + var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " + + "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " + + "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+ + "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+ + "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+ + "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/); + + tags.each( function(tag){ + scope[tag] = function() { + return Builder.node.apply(Builder, [tag].concat($A(arguments))); + }; + }); + } +}; Index: openacs-4/packages/messages/www/resources/controls.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/controls.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/controls.js 31 Aug 2010 21:30:50 -0000 1.1 @@ -0,0 +1,926 @@ +if(typeof Effect == 'undefined') + throw("controls.js requires including script.aculo.us' effects.js library"); + +var Autocompleter = { }; +Autocompleter.Base = Class.create({ + baseInitialize: function(element, update, options) { + element = $(element); + this.element = element; + this.update = $(update); + this.hasFocus = false; + this.changed = false; + this.active = false; + this.index = 0; + this.entryCount = 0; + this.oldElementValue = this.element.value; + if(this.setOptions) + this.setOptions(options); + else + this.options = options || { }; + + this.options.paramName = this.options.paramName || this.element.name; + this.options.tokens = this.options.tokens || []; + this.options.frequency = this.options.frequency || 0.4; + this.options.minChars = this.options.minChars || 1; + this.options.onShow = this.options.onShow || + function(element, update){ + if(!$(update).getStyle('position') || $(update).getStyle('position')=='absolute') { + $(update).setStyle({position : 'absolute'}); + Position.clone(element, update, { + setHeight: false, + offsetTop: element.offsetHeight + }); + } + Effect.Appear(update,{duration:0.15}); + }; + this.options.onHide = this.options.onHide || + function(element, update){ new Effect.Fade(update,{duration:0.15}) }; + + if(typeof(this.options.tokens) == 'string') + this.options.tokens = new Array(this.options.tokens); + // Force carriage returns as token delimiters anyway + if (!this.options.tokens.include('\n')) + this.options.tokens.push('\n'); + + this.observer = null; + + this.element.setAttribute('autocomplete','off'); + + Element.hide(this.update); + + Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); + Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); + }, + + show: function() { + if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); + if(!this.iefix && + (Prototype.Browser.IE) && + (Element.getStyle(this.update, 'position')=='absolute')) { + new Insertion.After(this.update, + '<iframe id="' + this.update.id + '_iefix" '+ + 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' + + 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>'); + this.iefix = $(this.update.id+'_iefix'); + } + if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); + }, + + fixIEOverlapping: function() { + Position.clone(this.update, this.iefix, {setTop:(!this.update.getStyle("height"))}); + $(this.iefix).setStyle({zIndex : 1}); + this.update.setStyle({zIndex:2}); + Element.show(this.iefix); + }, + + hide: function() { + this.stopIndicator(); + if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); + if(this.iefix) Element.hide(this.iefix); + }, + + startIndicator: function() { + if(this.options.indicator) Element.show(this.options.indicator); + }, + + stopIndicator: function() { + if(this.options.indicator) Element.hide(this.options.indicator); + }, + + onKeyPress: function(event) { + if(this.active) + switch(event.keyCode) { + case Event.KEY_TAB: + case Event.KEY_RETURN: + this.selectEntry(); + Event.stop(event); + case Event.KEY_ESC: + this.hide(); + this.active = false; + Event.stop(event); + return; + case Event.KEY_LEFT: + case Event.KEY_RIGHT: + return; + case Event.KEY_UP: + this.markPrevious(); + this.render(); + Event.stop(event); + return; + case Event.KEY_DOWN: + this.markNext(); + this.render(); + Event.stop(event); + return; + } + else + if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || + (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; + + this.changed = true; + this.hasFocus = true; + + if(this.observer) clearTimeout(this.observer); + this.observer = + setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); + }, + + activate: function() { + this.changed = false; + this.hasFocus = true; + this.getUpdatedChoices(); + }, + + onHover: function(event) { + var element = Event.findElement(event, 'LI'); + if(this.index != element.autocompleteIndex) + { + this.index = element.autocompleteIndex; + this.render(); + } + Event.stop(event); + }, + + onClick: function(event) { + var element = Event.findElement(event, 'LI'); + this.index = element.autocompleteIndex; + this.selectEntry(); + this.hide(); + }, + + onBlur: function(event) { + // needed to make click events working + setTimeout(this.hide.bind(this), 250); + this.hasFocus = false; + this.active = false; + }, + + render: function() { + if(this.entryCount > 0) { + for (var i = 0; i < this.entryCount; i++) + this.index==i ? + Element.addClassName(this.getEntry(i),"selected") : + Element.removeClassName(this.getEntry(i),"selected"); + if(this.hasFocus) { + this.show(); + this.active = true; + } + } else { + this.active = false; + this.hide(); + } + }, + + markPrevious: function() { + if(this.index > 0) this.index--; + else this.index = this.entryCount-1; + this.getEntry(this.index).scrollIntoView(true); + }, + + markNext: function() { + if(this.index < this.entryCount-1) this.index++; + else this.index = 0; + this.getEntry(this.index).scrollIntoView(false); + }, + + getEntry: function(index) { + return this.update.firstChild.childNodes[index]; + }, + + getCurrentEntry: function() { + return this.getEntry(this.index); + }, + + selectEntry: function() { + this.active = false; + this.updateElement(this.getCurrentEntry()); + }, + + updateElement: function(selectedElement) { + if (this.options.updateElement) { + this.options.updateElement(selectedElement); + return; + } + var value = ''; + if (this.options.select) { + var nodes = $(selectedElement).select('.' + this.options.select) || []; + if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); + } else + value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); + + var bounds = this.getTokenBounds(); + if (bounds[0] != -1) { + var newValue = this.element.value.substr(0, bounds[0]); + var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); + if (whitespace) + newValue += whitespace[0]; + this.element.value = newValue + value + this.element.value.substr(bounds[1]); + } else { + this.element.value = value; + } + this.oldElementValue = this.element.value; + this.element.focus(); + + if (this.options.afterUpdateElement) + this.options.afterUpdateElement(this.element, selectedElement); + }, + + updateChoices: function(choices) { + if(!this.changed && this.hasFocus) { + this.update.innerHTML = choices; + Element.cleanWhitespace(this.update); + Element.cleanWhitespace(this.update.down()); + + if(this.update.firstChild && this.update.down().childNodes) { + this.entryCount = + this.update.down().childNodes.length; + for (var i = 0; i < this.entryCount; i++) { + var entry = this.getEntry(i); + entry.autocompleteIndex = i; + this.addObservers(entry); + } + } else { + this.entryCount = 0; + } + + this.stopIndicator(); + this.index = 0; + + if(this.entryCount==1 && this.options.autoSelect) { + this.selectEntry(); + this.hide(); + } else { + this.render(); + } + } + }, + + addObservers: function(element) { + Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); + Event.observe(element, "click", this.onClick.bindAsEventListener(this)); + }, + + onObserverEvent: function() { + this.changed = false; + this.tokenBounds = null; + if(this.getToken().length>=this.options.minChars) { + this.getUpdatedChoices(); + } else { + this.active = false; + this.hide(); + } + this.oldElementValue = this.element.value; + }, + + getToken: function() { + var bounds = this.getTokenBounds(); + return this.element.value.substring(bounds[0], bounds[1]).strip(); + }, + + getTokenBounds: function() { + if (null != this.tokenBounds) return this.tokenBounds; + var value = this.element.value; + if (value.strip().empty()) return [-1, 0]; + var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); + var offset = (diff == this.oldElementValue.length ? 1 : 0); + var prevTokenPos = -1, nextTokenPos = value.length; + var tp; + for (var index = 0, l = this.options.tokens.length; index < l; ++index) { + tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); + if (tp > prevTokenPos) prevTokenPos = tp; + tp = value.indexOf(this.options.tokens[index], diff + offset); + if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; + } + return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); + } +}); + +Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { + var boundary = Math.min(newS.length, oldS.length); + for (var index = 0; index < boundary; ++index) + if (newS[index] != oldS[index]) + return index; + return boundary; +}; + +Ajax.Autocompleter = Class.create(Autocompleter.Base, { + initialize: function(element, update, url, options) { + this.baseInitialize(element, update, options); + this.options.asynchronous = true; + this.options.onComplete = this.onComplete.bind(this); + this.options.defaultParams = this.options.parameters || null; + this.url = url; + }, + + getUpdatedChoices: function() { + this.startIndicator(); + + var entry = encodeURIComponent(this.options.paramName) + '=' + + encodeURIComponent(this.getToken()); + + this.options.parameters = this.options.callback ? + this.options.callback(this.element, entry) : entry; + + if(this.options.defaultParams) + this.options.parameters += '&' + this.options.defaultParams; + + new Ajax.Request(this.url, this.options); + }, + + onComplete: function(request) { + this.updateChoices(request.responseText); + } +}); + +// The local array autocompleter. Used when you'd prefer to +// inject an array of autocompletion options into the page, rather +// than sending out Ajax queries, which can be quite slow sometimes. +// +// The constructor takes four parameters. The first two are, as usual, +// the id of the monitored textbox, and id of the autocompletion menu. +// The third is the array you want to autocomplete from, and the fourth +// is the options block. +// +// Extra local autocompletion options: +// - choices - How many autocompletion choices to offer +// +// - partialSearch - If false, the autocompleter will match entered +// text only at the beginning of strings in the +// autocomplete array. Defaults to true, which will +// match text at the beginning of any *word* in the +// strings in the autocomplete array. If you want to +// search anywhere in the string, additionally set +// the option fullSearch to true (default: off). +// +// - fullSsearch - Search anywhere in autocomplete array strings. +// +// - partialChars - How many characters to enter before triggering +// a partial match (unlike minChars, which defines +// how many characters are required to do any match +// at all). Defaults to 2. +// +// - ignoreCase - Whether to ignore case when autocompleting. +// Defaults to true. +// +// It's possible to pass in a custom function as the 'selector' +// option, if you prefer to write your own autocompletion logic. +// In that case, the other options above will not apply unless +// you support them. + +Autocompleter.Local = Class.create(Autocompleter.Base, { + initialize: function(element, update, array, options) { + this.baseInitialize(element, update, options); + this.options.array = array; + }, + + getUpdatedChoices: function() { + this.updateChoices(this.options.selector(this)); + }, + + setOptions: function(options) { + this.options = Object.extend({ + choices: 10, + partialSearch: true, + partialChars: 2, + ignoreCase: true, + fullSearch: false, + selector: function(instance) { + var ret = []; // Beginning matches + var partial = []; // Inside matches + var entry = instance.getToken(); + var count = 0; + + for (var i = 0; i < instance.options.array.length && + ret.length < instance.options.choices ; i++) { + + var elem = instance.options.array[i]; + var foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase()) : + elem.indexOf(entry); + + while (foundPos != -1) { + if (foundPos == 0 && elem.length != entry.length) { + ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" + + elem.substr(entry.length) + "</li>"); + break; + } else if (entry.length >= instance.options.partialChars && + instance.options.partialSearch && foundPos != -1) { + if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { + partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" + + elem.substr(foundPos, entry.length) + "</strong>" + elem.substr( + foundPos + entry.length) + "</li>"); + break; + } + } + + foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : + elem.indexOf(entry, foundPos + 1); + + } + } + if (partial.length) + ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)); + return "<ul>" + ret.join('') + "</ul>"; + } + }, options || { }); + } +}); + +// AJAX in-place editor and collection editor +// Full rewrite by Christophe Porteneuve <tdd@tddsworld.com> (April 2007). + +// Use this if you notice weird scrolling problems on some browsers, +// the DOM might be a bit confused when this gets called so do this +// waits 1 ms (with setTimeout) until it does the activation +Field.scrollFreeActivate = function(field) { + setTimeout(function() { + Field.activate(field); + }, 1); +}; + +Ajax.InPlaceEditor = Class.create({ + initialize: function(element, url, options) { + this.url = url; + this.element = element = $(element); + this.prepareOptions(); + this._controls = { }; + arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! + Object.extend(this.options, options || { }); + if (!this.options.formId && this.element.id) { + this.options.formId = this.element.id + '-inplaceeditor'; + if ($(this.options.formId)) + this.options.formId = ''; + } + if (this.options.externalControl) + this.options.externalControl = $(this.options.externalControl); + if (!this.options.externalControl) + this.options.externalControlOnly = false; + this._originalBackground = this.element.getStyle('background-color') || 'transparent'; + this.element.title = this.options.clickToEditText; + this._boundCancelHandler = this.handleFormCancellation.bind(this); + this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); + this._boundFailureHandler = this.handleAJAXFailure.bind(this); + this._boundSubmitHandler = this.handleFormSubmission.bind(this); + this._boundWrapperHandler = this.wrapUp.bind(this); + this.registerListeners(); + }, + checkForEscapeOrReturn: function(e) { + if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; + if (Event.KEY_ESC == e.keyCode) + this.handleFormCancellation(e); + else if (Event.KEY_RETURN == e.keyCode) + this.handleFormSubmission(e); + }, + createControl: function(mode, handler, extraClasses) { + var control = this.options[mode + 'Control']; + var text = this.options[mode + 'Text']; + if ('button' == control) { + var btn = document.createElement('input'); + btn.type = 'submit'; + btn.value = text; + btn.className = 'editor_' + mode + '_button'; + if ('cancel' == mode) + btn.onclick = this._boundCancelHandler; + this._form.appendChild(btn); + this._controls[mode] = btn; + } else if ('link' == control) { + var link = document.createElement('a'); + link.href = '#'; + link.appendChild(document.createTextNode(text)); + link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; + link.className = 'editor_' + mode + '_link'; + if (extraClasses) + link.className += ' ' + extraClasses; + this._form.appendChild(link); + this._controls[mode] = link; + } + }, + createEditField: function() { + var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); + var fld; + if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { + fld = document.createElement('input'); + fld.type = 'text'; + var size = this.options.size || this.options.cols || 0; + if (0 < size) fld.size = size; + } else { + fld = document.createElement('textarea'); + fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); + fld.cols = this.options.cols || 40; + } + fld.name = this.options.paramName; + fld.value = text; // No HTML breaks conversion anymore + fld.className = 'editor_field'; + if (this.options.submitOnBlur) + fld.onblur = this._boundSubmitHandler; + this._controls.editor = fld; + if (this.options.loadTextURL) + this.loadExternalText(); + this._form.appendChild(this._controls.editor); + }, + createForm: function() { + var ipe = this; + function addText(mode, condition) { + var text = ipe.options['text' + mode + 'Controls']; + if (!text || condition === false) return; + ipe._form.appendChild(document.createTextNode(text)); + }; + this._form = $(document.createElement('form')); + this._form.id = this.options.formId; + this._form.addClassName(this.options.formClassName); + this._form.onsubmit = this._boundSubmitHandler; + this.createEditField(); + if ('textarea' == this._controls.editor.tagName.toLowerCase()) + this._form.appendChild(document.createElement('br')); + if (this.options.onFormCustomization) + this.options.onFormCustomization(this, this._form); + addText('Before', this.options.okControl || this.options.cancelControl); + this.createControl('ok', this._boundSubmitHandler); + addText('Between', this.options.okControl && this.options.cancelControl); + this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); + addText('After', this.options.okControl || this.options.cancelControl); + }, + destroy: function() { + if (this._oldInnerHTML) + this.element.innerHTML = this._oldInnerHTML; + this.leaveEditMode(); + this.unregisterListeners(); + }, + enterEditMode: function(e) { + if (this._saving || this._editing) return; + this._editing = true; + this.triggerCallback('onEnterEditMode'); + if (this.options.externalControl) + this.options.externalControl.hide(); + this.element.hide(); + this.createForm(); + this.element.parentNode.insertBefore(this._form, this.element); + if (!this.options.loadTextURL) + this.postProcessEditField(); + if (e) Event.stop(e); + }, + enterHover: function(e) { + if (this.options.hoverClassName) + this.element.addClassName(this.options.hoverClassName); + if (this._saving) return; + this.triggerCallback('onEnterHover'); + }, + getText: function() { + return this.element.innerHTML; + }, + handleAJAXFailure: function(transport) { + this.triggerCallback('onFailure', transport); + if (this._oldInnerHTML) { + this.element.innerHTML = this._oldInnerHTML; + this._oldInnerHTML = null; + } + }, + handleFormCancellation: function(e) { + this.wrapUp(); + if (e) Event.stop(e); + }, + handleFormSubmission: function(e) { + var form = this._form; + var value = $F(this._controls.editor); + this.prepareSubmission(); + var params = this.options.callback(form, value) || ''; + if (Object.isString(params)) + params = params.toQueryParams(); + params.editorId = this.element.id; + if (this.options.htmlResponse) { + var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); + Object.extend(options, { + parameters: params, + onComplete: this._boundWrapperHandler, + onFailure: this._boundFailureHandler + }); + new Ajax.Updater({ success: this.element }, this.url, options); + } else { + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: params, + onComplete: this._boundWrapperHandler, + onFailure: this._boundFailureHandler + }); + new Ajax.Request(this.url, options); + } + if (e) Event.stop(e); + }, + leaveEditMode: function() { + this.element.removeClassName(this.options.savingClassName); + this.removeForm(); + this.leaveHover(); + this.element.setStyle({backgroundColor : this._originalBackground}); + this.element.show(); + if (this.options.externalControl) + this.options.externalControl.show(); + this._saving = false; + this._editing = false; + this._oldInnerHTML = null; + this.triggerCallback('onLeaveEditMode'); + }, + leaveHover: function(e) { + if (this.options.hoverClassName) + this.element.removeClassName(this.options.hoverClassName); + if (this._saving) return; + this.triggerCallback('onLeaveHover'); + }, + loadExternalText: function() { + this._form.addClassName(this.options.loadingClassName); + this._controls.editor.disabled = true; + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + this._form.removeClassName(this.options.loadingClassName); + var text = transport.responseText; + if (this.options.stripLoadedTextTags) + text = text.stripTags(); + this._controls.editor.value = text; + this._controls.editor.disabled = false; + this.postProcessEditField(); + }.bind(this), + onFailure: this._boundFailureHandler + }); + new Ajax.Request(this.options.loadTextURL, options); + }, + postProcessEditField: function() { + var fpc = this.options.fieldPostCreation; + if (fpc) + $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate'](); + }, + prepareOptions: function() { + this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); + Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); + [this._extraDefaultOptions].flatten().compact().each(function(defs) { + Object.extend(this.options, defs); + }.bind(this)); + }, + prepareSubmission: function() { + this._saving = true; + this.removeForm(); + this.leaveHover(); + this.showSaving(); + }, + registerListeners: function() { + this._listeners = { }; + var listener; + $H(Ajax.InPlaceEditor.Listeners).each(function(pair) { + listener = this[pair.value].bind(this); + this._listeners[pair.key] = listener; + if (!this.options.externalControlOnly) + this.element.observe(pair.key, listener); + if (this.options.externalControl) + this.options.externalControl.observe(pair.key, listener); + }.bind(this)); + }, + removeForm: function() { + if (!this._form) return; + this._form.remove(); + this._form = null; + this._controls = { }; + }, + showSaving: function() { + this._oldInnerHTML = this.element.innerHTML; + this.element.innerHTML = this.options.savingText; + this.element.addClassName(this.options.savingClassName); + this.element.setStyle({backgroundColor: this._originalBackground}); + this.element.show(); + }, + triggerCallback: function(cbName, arg) { + if ('function' == typeof this.options[cbName]) { + this.options[cbName](this, arg); + } + }, + unregisterListeners: function() { + $H(this._listeners).each(function(pair) { + if (!this.options.externalControlOnly) + this.element.stopObserving(pair.key, pair.value); + if (this.options.externalControl) + this.options.externalControl.stopObserving(pair.key, pair.value); + }.bind(this)); + }, + wrapUp: function(transport) { + this.leaveEditMode(); + // Can't use triggerCallback due to backward compatibility: requires + // binding + direct element + this._boundComplete(transport, this.element); + } +}); + +Object.extend(Ajax.InPlaceEditor.prototype, { + dispose: Ajax.InPlaceEditor.prototype.destroy +}); + +Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, { + initialize: function($super, element, url, options) { + this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions; + $super(element, url, options); + }, + + createEditField: function() { + var list = document.createElement('select'); + list.name = this.options.paramName; + list.size = 1; + this._controls.editor = list; + this._collection = this.options.collection || []; + if (this.options.loadCollectionURL) + this.loadCollection(); + else + this.checkForExternalText(); + this._form.appendChild(this._controls.editor); + }, + + loadCollection: function() { + this._form.addClassName(this.options.loadingClassName); + this.showLoadingText(this.options.loadingCollectionText); + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + var js = transport.responseText.strip(); + if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check + throw('Server returned an invalid collection representation.'); + this._collection = eval(js); + this.checkForExternalText(); + }.bind(this), + onFailure: this.onFailure + }); + new Ajax.Request(this.options.loadCollectionURL, options); + }, + + showLoadingText: function(text) { + this._controls.editor.disabled = true; + var tempOption = this._controls.editor.firstChild; + if (!tempOption) { + tempOption = document.createElement('option'); + tempOption.value = ''; + this._controls.editor.appendChild(tempOption); + tempOption.selected = true; + } + tempOption.update((text || '').stripScripts().stripTags()); + }, + + checkForExternalText: function() { + this._text = this.getText(); + if (this.options.loadTextURL) + this.loadExternalText(); + else + this.buildOptionList(); + }, + + loadExternalText: function() { + this.showLoadingText(this.options.loadingText); + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + this._text = transport.responseText.strip(); + this.buildOptionList(); + }.bind(this), + onFailure: this.onFailure + }); + new Ajax.Request(this.options.loadTextURL, options); + }, + + buildOptionList: function() { + this._form.removeClassName(this.options.loadingClassName); + this._collection = this._collection.map(function(entry) { + return 2 === entry.length ? entry : [entry, entry].flatten(); + }); + var marker = ('value' in this.options) ? this.options.value : this._text; + var textFound = this._collection.any(function(entry) { + return entry[0] == marker; + }.bind(this)); + this._controls.editor.update(''); + var option; + this._collection.each(function(entry, index) { + option = document.createElement('option'); + option.value = entry[0]; + option.selected = textFound ? entry[0] == marker : 0 == index; + option.appendChild(document.createTextNode(entry[1])); + this._controls.editor.appendChild(option); + }.bind(this)); + this._controls.editor.disabled = false; + Field.scrollFreeActivate(this._controls.editor); + } +}); + +//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! **** +//**** This only exists for a while, in order to let **** +//**** users adapt to the new API. Read up on the new **** +//**** API and convert your code to it ASAP! **** + +Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) { + if (!options) return; + function fallback(name, expr) { + if (name in options || expr === undefined) return; + options[name] = expr; + }; + fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' : + options.cancelLink == options.cancelButton == false ? false : undefined))); + fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' : + options.okLink == options.okButton == false ? false : undefined))); + fallback('highlightColor', options.highlightcolor); + fallback('highlightEndColor', options.highlightendcolor); +}; + +Object.extend(Ajax.InPlaceEditor, { + DefaultOptions: { + ajaxOptions: { }, + autoRows: 3, // Use when multi-line w/ rows == 1 + cancelControl: 'link', // 'link'|'button'|false + cancelText: 'cancel', + clickToEditText: 'Click to edit', + externalControl: null, // id|elt + externalControlOnly: false, + fieldPostCreation: 'activate', // 'activate'|'focus'|false + formClassName: 'inplaceeditor-form', + formId: null, // id|elt + highlightColor: '#ffff99', + highlightEndColor: '#ffffff', + hoverClassName: '', + htmlResponse: true, + loadingClassName: 'inplaceeditor-loading', + loadingText: 'Loading...', + okControl: 'button', // 'link'|'button'|false + okText: 'ok', + paramName: 'value', + rows: 1, // If 1 and multi-line, uses autoRows + savingClassName: 'inplaceeditor-saving', + savingText: 'Saving...', + size: 0, + stripLoadedTextTags: false, + submitOnBlur: false, + textAfterControls: '', + textBeforeControls: '', + textBetweenControls: '' + }, + DefaultCallbacks: { + callback: function(form) { + return Form.serialize(form); + }, + onComplete: function(transport, element) { + // For backward compatibility, this one is bound to the IPE, and passes + // the element directly. It was too often customized, so we don't break it. + new Effect.Highlight(element, { + startcolor: this.options.highlightColor, keepBackgroundImage: true }); + }, + onEnterEditMode: null, + onEnterHover: function(ipe) { + $(ipe.element).setStyle({backgroundColor : ipe.options.highlightColor}); + if (ipe._effect) + ipe._effect.cancel(); + }, + onFailure: function(transport, ipe) { + alert('Error communication with the server: ' + transport.responseText.stripTags()); + }, + onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls. + onLeaveEditMode: null, + onLeaveHover: function(ipe) { + ipe._effect = new Effect.Highlight(ipe.element, { + startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor, + restorecolor: ipe._originalBackground, keepBackgroundImage: true + }); + } + }, + Listeners: { + click: 'enterEditMode', + keydown: 'checkForEscapeOrReturn', + mouseover: 'enterHover', + mouseout: 'leaveHover' + } +}); + +Ajax.InPlaceCollectionEditor.DefaultOptions = { + loadingCollectionText: 'Loading options...' +}; + +// Delayed observer, like Form.Element.Observer, +// but waits for delay after last key input +// Ideal for live-search fields + +Form.Element.DelayedObserver = Class.create({ + initialize: function(element, delay, callback) { + this.delay = delay || 0.5; + this.element = $(element); + this.callback = callback; + this.timer = null; + this.lastValue = $F(this.element); + Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); + }, + delayedListener: function(event) { + if(this.lastValue == $F(this.element)) return; + if(this.timer) clearTimeout(this.timer); + this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); + this.lastValue = $F(this.element); + }, + onTimerEvent: function() { + this.timer = null; + this.callback(this.element, $F(this.element)); + } +}); Index: openacs-4/packages/messages/www/resources/delete-dialog.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/delete-dialog.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/delete-dialog.js 31 Aug 2010 21:30:50 -0000 1.1 @@ -0,0 +1,57 @@ +//----------------- dialog delete + +YAHOO.namespace("delete_msg.container"); +function init_delete() { + // Define various event handlers for Dialog + var handleYes = function() { + document.getElementById('msg_system').style.display = 'none'; + var formObject = document.getElementsByName('messages_list'); + var form = formObject[0]; + var elements = form.elements; + var break_p = 0; + for ( var i = 0; i < elements.length ; i++){ + if (elements[i].name == 'subject_id' && elements[i].checked) { + break_p = 1; + break; + } + } + if (break_p) { + document.getElementById('msg_action_p').value = 't'; + move_to(3); + this.hide(); + } else { + document.getElementById('msg_action_p').value = 'f'; + document.getElementById('msg_action').style.display = ''; + document.getElementById('msg_actions').innerHTML = document.getElementById('msg_select_msg').value; + var folder_id_state = document.getElementById('folder_id').value; + if (document.getElementById('folder_id_state') != null ) { + var folder_id_state = document.getElementById('folder_id_state').value; + } + get_messages_folder('more_actions'); + this.hide(); + } + }; + var handleNo = function() { + document.getElementById('msg_system').style.display = 'none'; + this.hide(); + }; + + // Instantiate the Dialog + YAHOO.delete_msg.container.delete_dialog = new YAHOO.widget.SimpleDialog("delete_dialog", + { modal: true, + visible: false, + fixedcenter: true, + constraintoviewport: true, + iframe: true, + close: false, + width: "300px", + text: document.getElementById('delete_confirm').value, + buttons: [ { text:document.getElementById('msg_yes').value, handler:handleYes, isDefault:true }, + { text:"No", handler:handleNo } ] + } ); + // Render the Dialog + YAHOO.delete_msg.container.delete_dialog.render("container"); + YAHOO.util.Event.addListener("show_delete", "click", YAHOO.delete_msg.container.delete_dialog.show, null,YAHOO.delete_msg.container.delete_dialog); +} + +YAHOO.util.Event.addListener(window, "load", init_delete); \ No newline at end of file Index: openacs-4/packages/messages/www/resources/dispatcher-min.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/dispatcher-min.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/dispatcher-min.js 31 Aug 2010 21:30:52 -0000 1.1 @@ -0,0 +1,8 @@ +/* +Copyright (c) 2008, Bubbling Library Team. All rights reserved. +Portions Copyright (c) 2008, Yahoo!, Inc. All rights reserved. +Code licensed under the BSD License: +http://www.bubbling-library.com/eng/licence +version: 2.1 +*/ +YAHOO.namespace("plugin");(function(){var I=YAHOO.util.Connect,D=YAHOO.lang,F=YAHOO.util.Event,H=YAHOO.util.Dom,E=YAHOO.util.Dom.get;var N={LOADING:1,DISPATCHED:2,ERROR:3,EMPTY:4,proxy:"/dispatcher.php?uri=",CSSNODE:1,JSNODE:2};var L=/<script([^>]*)>([\s\S]*?)<\/script>/igm,A=/src=(['"]?)([^"']*)\1/i,M=/rel=(['"]?)([^"']*)\1/i,C=/<link([^>]*)(>[\s]*<\/link>|>)/igm,K=/href=(['"]?)([^"']*)\1/i,O=/<style([^>]*)>([\s\S]*?)<\/style>/igm,B=new RegExp("([\\w-.]+)\\s*=\\s*(\".*?\"|'.*?'|\\w+)*","im");var J=new RegExp("url\\s*\\(([^\\)]*)","igm");var G=new RegExp("^((?:http|https)://)((?:\\w+[.|-]?)*\\w+)(/.*)$","i");YAHOO.plugin.Dispatcher=function(){var W={},S={},j=[],P={relative:false,baseURI:document.location.toString()},b="loading",c="yui-dispatchable",T={key:["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],q:{name:"queryKey",parser:/(?:^|&)([^&=]*)=?([^&]*)/g},parser:{strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}},a=/^\s+|\s+$/g;function h(s,p){var r=T,l=r.parser[p?"strict":"loose"].exec(s),q={},n=14;while(n--){q[r.key[n]]=l[n]||""}q[r.q.name]={};q[r.key[12]].replace(r.q.parser,function(o,m,t){if(m){q[r.q.name][m]=t}});return q}function e(l){var n=document.getElementsByTagName("head")[0]||document.documentElement,m=document.createElement("script");l=l.replace(a,"");if(l){m.type="text/javascript";if(YAHOO.env.ua.ie){m.text=l}else{m.appendChild(document.createTextNode(l))}n.insertBefore(m,n.firstChild);n.removeChild(m)}}function Y(l){if(D.isString(l)){l=l.replace(/^\s*(\S*(\s+\S+)*)\s*$/,"$1");l=l.replace(/^(['|"])*(\S*(?:\s+\S+)*)\1$/,"$2")}return l}function Q(o,l){var n=null,m={};l=l||{};if(D.isString(o)){while(n=B.exec(o)){n[2]=(l.hasOwnProperty(n[1])?l[n[1]]:n[2]);if(n[2]){m[n[1]]=Y(n[2])}o=o.replace(B,"")}}return m}function U(l){l=((D.isString(l)&&(l.indexOf("/")>-1))?l:P.baseURI)+"";return l.substr(0,l.lastIndexOf("/")+1)}function k(m,l){if(l&&!G.test(l)&&(l.indexOf("/")!==0)){l=m+l}return l}function R(l){if(l.element&&l.element.setAttribute){l.element.setAttribute("aria-live","polite");l.element.setAttribute("aria-atomic","true");l.element.setAttribute("aria-relevant","all");l.element.setAttribute("aria-busy","true")}l.onStart=l.before||l.onStart;if(D.isFunction(l.onStart)){l.onStart.apply(l,[l.element]);l.onStart=null}if(!l.underground&&YAHOO.Bubbling){YAHOO.Bubbling.fire("onAsyncRequestStart",{element:l.element})}}function g(l,m){if(D.isFunction(l.onChange)){m=m||l.element;l.onChange.apply(l,[m])}}function V(l){l.onLoad=l.after||l.onLoad;if(D.isFunction(l.onLoad)){l.onLoad.apply(l,[l.element])}if(!l.underground&&YAHOO.Bubbling){YAHOO.Bubbling.fire("onAsyncRequestEnd",{element:l.element})}if(l.element&&l.element.setAttribute){l.element.setAttribute("aria-busy","false")}}function i(q,m){var r=null,l=true,p=null,o="",n=0;m=m||{};if(W.isAlive(q)){p=S[q].chunks.shift();if(D.isObject(p)&&p.src){m.hash=j.length;for(n=0;n<j.length;n++){if(j[n].uri==p.src){if((j[n].status==N.DISPATCHED)&&!m.override){l=false}else{}m.hash=n;break}}if(l){o=W.firewall(p.src,m,true);if(D.isString(o)&&(o!=="")){j[m.hash]={uri:p.src,proxy:o,status:N.LOADING};if(p.type===N.JSNODE){W.area=q;W.destroyer=S[q].destroyer;m.handle=YAHOO.util.Get.script(o,{onSuccess:function(){j[m.hash].status=N.DISPATCHED;if(m.rel&&YAHOO.Bubbling){YAHOO.Bubbling.fire("onScriptReady",{module:p.rel,src:p.src,uri:o,hash:m.hash})}m.hash=null;i(q,m)},onFailure:function(){i(q,m)},scope:W,data:m})}else{if(p.type===N.CSSNODE){YAHOO.util.Get.css(o,{});j[m.hash].status=N.DISPATCHED;i(q,m)}}}}else{i(q,m)}}else{m.hash=null;Z(q,p.content,m)}}else{W.kill(q);V(m)}}function Z(o,p,m){var l=N.EMPTY;if(p&&(p!=="")){try{l=N.DISPATCHED;if(!m.hash||(j[m.hash].status!=N.DISPATCHED)){W.area=o;W.destroyer=S[o].destroyer;if(D.isFunction(m.evalRoutine)){m.evalRoutine(p,m)}else{e(p)}}}catch(n){l=N.ERROR;if(D.isFunction(m.error)){m.error.apply(m,[o,p,j,n])}else{throw new Error("Dispacher: Script Execution Error ("+n+")")}}}if(D.isNumber(m.hash)){j[m.hash].status=l;m.hash=null}i(o,m)}function d(m,q,l){l.action=(l.action?l.action:"replace");switch(l.action){case"tabview":f(m.get("contentEl"),l);try{m.set("content",q)}catch(p){return false}g(l,m.get("contentEl"));break;case"update":q=m.innerHTML+q;try{m.innerHTML=q}catch(o){return false}g(l,m);break;case"replace":case"layout":default:f(m,l);try{m.innerHTML=q}catch(n){return false}g(l,m);break}return true}function f(n,l){var o=l.guid,m=0;if(D.isObject(S[o].destroyer)){S[o].destroyer.fire(n,l)}if(H.inDocument(n)){for(m=0;m<n.childNodes.length;m++){F.purgeElement(n.childNodes[m],true)}H.addClass(n,c)}S[o].destroyer=new YAHOO.util.CustomEvent("destroyer");if(D.isFunction(l.onDestroy)){S[o].destroyer.subscribe(l.onDestroy)}}function X(r,p,o){o=o||{};o.uri=o.uri||null;o.relative=o.relative||P.relative;var n=true,l=false,q=U(o.uri);p=p.replace(O,function(w,v,t,u,m){if(t){W.applyCSS(t,Q(v),o)}return""});p=p.replace(C,function(w,v,t,u,m){if(v){l=v.match(K);if(l){if(o.relative){l[2]=k(q,l[2])}S[r].chunks.push({src:l[2],content:"",type:N.CSSNODE,params:Q(v)})}}return""});p=p.replace(L,function(x,w,u,v,t){if(w){l=w.match(A);if(l){var m=w.match(M);m=(m?m[2]:null);if(o.relative){l[2]=k(q,l[2])}S[r].chunks.push({src:l[2],content:"",type:N.JSNODE,rel:m,params:Q(w)})}}if(u){S[r].chunks.push({src:null,content:u,type:N.JSNODE,params:Q(w)})}return""});return p}if(YAHOO.Bubbling){YAHOO.Bubbling.on("onScriptReady",function(){if(this.src&&!this.hash){j[this.hash].status=N.DISPATCHED}})}W.area=null;W.strictMode=true;W.destroyer=null;W.fetch=function(n,o,m){m=m||{};m.uri=o;var q=null,l=null,p={success:function(r){if(r.responseText!="undefined"){W.process(n,r.responseText,m,true)}H.removeClass(n,b)},failure:function(r){if(D.isFunction(m.onError)){m.onError.apply(m,[m.element,r])}H.removeClass(n,b)}};if((D.isObject(n)||(n=E(n)))&&o){l=W.firewall(o,m);H.addClass(n,b);m.handle=I.asyncRequest("GET",l,p);m.element=n;R(m);if(YAHOO.Bubbling){q=m.guid||F.generateId(n);YAHOO.Bubbling.fire("onNavigate",{state:q+escape(o),control:"dispatcher",element:n,uri:o,config:m,restore:function(){W.fetch(n,o,m)}})}return m.handle}return null};W.process=function(n,o,m,l){var p=null;m=m||{};if(D.isObject(n)||(n=E(n))){p=m.guid||F.generateId(n);this.kill(p);m.element=n;m.content=o;m.guid=p;if(!l){R(m)}if(d(n,X(p,o,m),m)){i(p,m)}}return p};W.delegate=function(m,n,l){l=l||{};l.action="tabview";l.uri=m.get("dataSrc")||null;l.tab=m;m.loadHandler.success=function(q){var p=m.get("contentEl");l.tab=p;l.underground=true;W.process(m,q.responseText,l);if(YAHOO.Bubbling){YAHOO.Bubbling.fire("onAsyncRequestEnd",{element:p})}};m.on("activeChange",function(){if(YAHOO.Bubbling&&this.get("active")&&m.get("dataSrc")&&!this.get("cacheData")){YAHOO.Bubbling.fire("onAsyncRequestStart",{element:this.get("contentEl")})}});if(D.isObject(n)){n.addTab(m)}};W.addUnit=function(o,n,l){var p=l||{},m;p.action="layout";if(!o||!n){return false}if(D.isString(o)){o=n.getUnitByPosition(o)}else{if(o.position&&!n.getUnitByPosition(o.position)){o=n.addUnit(o)}}if(p.uri){o.set("dataSrc",p.uri)}if((p.unit=o)&&(p.uri=p.unit.get("dataSrc"))&&(m=p.unit.body)){p.underground=true;p._dispatcherConfig=p;p.unit.loadHandler.success=function(q){W.process(this.body,q.responseText,this._dispatcherConfig);if(YAHOO.Bubbling){YAHOO.Bubbling.fire("onAsyncRequestEnd",{element:this.body})}};if(p.unit.loadContent()&&YAHOO.Bubbling){YAHOO.Bubbling.fire("onAsyncRequestStart",{element:m})}}return p.unit};W.applyCSS=function(m,r,n){r=r||{};var l=document.createElement("style"),p=r.href||"";n=n||{};var o=n.uri||P.baseURI;n.relative=n.relative||P.relative;if(n.relative){o=W.firewall(o,n,true);p=U(o);p=k(p,r.href)}p=U(p);m=m.replace(J,function(w,v,u,t){v=Y(v);v="url("+k(p,v);return v});l.type="text/css";if(D.isObject(l.styleSheet)){l.styleSheet.cssText=m}else{l.appendChild(document.createTextNode(m))}try{document.getElementsByTagName("head")[0].appendChild(l)}catch(q){throw new Error("Dispacher: CSS Processing Error ("+q+")");return false}return true};W.jsLoader=function(m,l){if(D.isString(m)&&(m!=="")){l=l||{};F.generateId(l);W.kill(l.id);S[l.id].chunks=[{src:m,content:"",type:N.JSNODE,params:{href:m}}];l.underground=true;R(l);i(l.id,l);return l.id}return null};W.cssLoader=function(m,l){if(D.isString(m)&&(m!=="")){l=l||{};F.generateId(l);W.kill(l.id);S[l.id].chunks=[{src:m,content:"",type:N.CSSNODE,params:{href:m}}];l.underground=true;R(l);i(l.id,l);return l.id}return null};W.isAlive=function(l){return(l&&D.isObject(S[l])&&(S[l].chunks.length>0))};W.kill=function(l){if(l&&!D.isObject(S[l])){S[l]={chunks:[],destroyer:null}}else{if(this.isAlive(l)){S[l].chunks=[]}}};W.destroy=function(l){this.kill(l);if(l&&!D.isObject(S[l])){S[l].destroyer.fire(E(l),{})}};W.onDestroy=function(n,l,m){var o=(m?[l,m,true]:[l]);if(D.isObject(S[n])&&D.isObject(S[n].destroyer)){if(D.isObject(m)){S[n].destroyer.subscribe(l,m,true)}else{S[n].destroyer.subscribe(l)}return true}return false};W.init=function(l){l=l||{};l.relative=l.relative||false;P=l};W.firewall=function(p,o,r){var n=null,q=null,l=null;while(p.indexOf("&")>-1){p=p.replace("&","&")}o.proxy=o.proxy||N.proxy;if(D.isFunction(o.firewall)){p=o.firewall.apply(o,[p])}else{if(!o.monolithic&&!r&&o.proxy){l=p.match(G);if(l&&(l[2]!==document.domain)){p=o.proxy+escape(p)}}}return p};W.obj2query=function(n){var l="",m;if(D.isObject(n)){for(key in n){if(n.hasOwnProperty(key)){l+=(l==""?"":"&");l+=key+"="+n[key]}}}return l};W.augmentURI=function(p,l){l=l||{};var q=h(p,this.strictMode),n="";q.queryKey=q.queryKey||{};D.augmentObject(q.queryKey,l,true);if(q.protocol){n+=q.protocol+":"}if(this.strictMode){if(/^(?:[^:\/?#]+:)?\/\//.test(q.source)){n+="//"}}else{if(/^(?:(?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?\/\//.test(q.source)){n+="//"}}if(q.authority){if(q.userInfo){if(q.user){n+=q.user}if(q.userInfo.indexOf(":")>-1){n+=":"}if(q.password){n+=q.password}n+="@"}if(q.host){n+=q.host}if(q.port){n+=":"+q.port}}if(q.relative){if(q.path){if(q.directory){n+=q.directory}if(q.file){n+=q.file}}n+="?";for(sName in q.queryKey){if(q.queryKey.hasOwnProperty(sName)){n+=sName+"="+q.queryKey[sName]+"&"}}if(q.anchor){n+="#"+q.anchor}}return n};W.toString=function(){return("YUI Dispatcher Plugin")};return W}()})();YAHOO.util.Dispatcher=YAHOO.plugin.Dispatcher;YAHOO.register("dispatcher",YAHOO.plugin.Dispatcher,{version:"2.1",build:"237"}); \ No newline at end of file Index: openacs-4/packages/messages/www/resources/dispatcher.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/dispatcher.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/dispatcher.js 31 Aug 2010 21:30:53 -0000 1.1 @@ -0,0 +1,877 @@ +YAHOO.namespace("plugin"); +(function() { + var $C = YAHOO.util.Connect, + $L = YAHOO.lang, + $E = YAHOO.util.Event, + $D = YAHOO.util.Dom, + $ = YAHOO.util.Dom.get; + + /** + * Constants + */ + var constants = { LOADING: 1, DISPATCHED: 2, ERROR: 3, EMPTY: 4, proxy: '/dispatcher.php?uri=', CSSNODE: 1, JSNODE: 2 }; + + var reScriptTag = /<script([^>]*)>([\s\S]*?)<\/script>/igm, + reScriptTagSrc = /src=(['"]?)([^"']*)\1/i, + reScriptTagRel = /rel=(['"]?)([^"']*)\1/i, + reLinkTag = /<link([^>]*)(>[\s]*<\/link>|>)/igm, + reLinkTagSrc = /href=(['"]?)([^"']*)\1/i, + reStyleTag = /<style([^>]*)>([\s\S]*?)<\/style>/igm, + reTagParams = new RegExp('([\\w-\.]+)\\s*=\\s*(".*?"|\'.*?\'|\\w+)*', 'im'); + + var reCSS3rdFile = new RegExp('url\\s*\\(([^\\)]*)', 'igm'); // [url(image.gif] - also can include quotes + + var reURI = new RegExp('^((?:http|https)://)((?:\\w+[\.|-]?)*\\w+)(/.*)$', 'i'); // full url: [http://www.domain.com/path/file.html] + + /** + * @class Dispatcher + */ + YAHOO.plugin.Dispatcher = function () { + var obj = {}, + _threads = {}, // each thread represent an area... + _hashtable = [], + _oDefaultConfig = {relative: false, baseURI:document.location.toString()}, + _loadingClass = 'loading', + _classname = 'yui-dispatchable', + _reURI = { + key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], + q: { + name: "queryKey", + parser: /(?:^|&)([^&=]*)=?([^&]*)/g + }, + parser: { + strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, + loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ + } + }, + _reTrim = /^\s+|\s+$/g; + + function _parseUri (str, strictMode) { + var o = _reURI, + m = o.parser[strictMode?"strict":"loose"].exec(str), + uri = {}, + i = 14; + + while (i--) uri[o.key[i]] = m[i] || ""; + uri[o.q.name] = {}; + uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { + if ($1) uri[o.q.name][$1] = $2; + }); + return uri; + }; + + function _globalEval (scriptString) { + var h = document.getElementsByTagName('head')[0] || document.documentElement, + s = document.createElement('script'); + scriptString = scriptString.replace (_reTrim, ''); + if (scriptString) { + s.type = "text/javascript"; + /* hack: IE doesn't support appendChild+document.createTextNode, using .text instead */ + if (YAHOO.env.ua.ie) { + s.text = scriptString; + } else { + s.appendChild( document.createTextNode( scriptString ) ); + } + h.insertBefore(s, h.firstChild); + h.removeChild(s); + } + } + + // utilities + function _eraseQuotes( str ) { + if ($L.isString(str)) { + str = str.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"); // trim + str = str.replace(/^(['|"])*(\S*(?:\s+\S+)*)\1$/, "$2"); // un-quotes + } + return str; + } + function _getParams ( str, validator ) { + var p = null, r = {}; + validator = validator || {}; + // capturing the params into an object literal (r) + if($L.isString(str)){ + while(p = reTagParams.exec(str)){ + // apply validation if exists, if the value is null will be discarted + p[2] = (validator.hasOwnProperty(p[1])?validator[p[1]]:p[2]); + if (p[2]) { + r[p[1]] = _eraseQuotes(p[2]); + } + str = str.replace(reTagParams, ''); + } + } + return r; + } + function _baseURI ( uri ) { + uri = (($L.isString(uri) && (uri.indexOf('/') > -1))?uri:_oDefaultConfig.baseURI) + ''; // the default base is the current document uri (hack to convert to string) + return uri.substr (0, uri.lastIndexOf('/')+1); // forget the file name + } + function _relativeURI( base, uri ) { + // is the url is relative (not http..., not / at the begining) + if(uri && !reURI.test(uri) && (uri.indexOf('/') !== 0)){ + uri = base+uri; + } + return uri; + } + function _onStart (config) { + /* ARIA: set as a live area */ + if (config.element && config.element.setAttribute) { + config.element.setAttribute ('aria-live', 'polite'); + config.element.setAttribute ('aria-atomic', 'true'); // the whole area will be updated + config.element.setAttribute ('aria-relevant', 'all'); // the whole area will be updated + config.element.setAttribute ('aria-busy', 'true'); // starting the loading process + } + // onStart (before the loading) + config.onStart = config.before || config.onStart; + if ($L.isFunction(config.onStart)) { + config.onStart.apply ( config, [config.element] ); + config.onStart = null; // because the process method will try to executed again... + } + // broadcasting the message + if (!config.underground && YAHOO.Bubbling) { + YAHOO.Bubbling.fire ('onAsyncRequestStart', { + element: config.element + }); + } + } + function _onChange (config, el) { + if ($L.isFunction(config.onChange)) { + el = el || config.element; + config.onChange.apply ( config, [el] ); + } + } + function _onLoad (config) { + // onLoad (after the execution) + config.onLoad = config.after || config.onLoad; + if ($L.isFunction(config.onLoad)) { + config.onLoad.apply ( config, [config.element] ); + } + //console.log ("config: ", config); + if (!config.underground && YAHOO.Bubbling) { + //console.log ('el:', (config.tab || config.element)); + YAHOO.Bubbling.fire ('onAsyncRequestEnd', { + element: config.element + }); + } + /* ARIA: set as a live area */ + if (config.element && config.element.setAttribute) { + config.element.setAttribute ('aria-busy', 'false'); // ending the loading process + } + } + // private stuff + /** + * Dispatching the next node of the handle + * @public + * @param {Object} hd Thread's handle + * @param {Object} config Used to pass the user configuration thru the chain of execution + * @return boolean + */ + function dispatch( hd, config ) { + var callback = null, flag = true, node = null, uri = '', i = 0; + config = config || {}; + if (obj.isAlive(hd)) { + node = _threads[hd].chunks.shift (); + if ($L.isObject(node) && node.src) { + // cheching the uri in the hashtable + config.hash = _hashtable.length; // default hash (at the end of the table) + for (i=0; i<_hashtable.length; i++) { + if (_hashtable[i].uri == node.src) { + if ((_hashtable[i].status == constants.DISPATCHED) && !config.override) { + // this uri was already dispatched by this plugin and will be discarted... + flag = false; + } else { + // the uri already exists in the table + } + config.hash = i; + break; + } + } + if (flag) { + // fetching the remote script using the YUI Get Utility + uri = obj.firewall (node.src, config, true); + if ($L.isString(uri) && (uri !== '')) { + _hashtable[config.hash] = {uri: node.src, proxy: uri, status: constants.LOADING}; + if (node.type === constants.JSNODE) { + obj.area = hd; + obj.destroyer = _threads[hd].destroyer; + config.handle = YAHOO.util.Get.script(uri, { + onSuccess: function() { + _hashtable[config.hash].status = constants.DISPATCHED; + // broadcasting the message + if (config.rel && YAHOO.Bubbling) { + YAHOO.Bubbling.fire ('onScriptReady', { + module: node.rel, + src: node.src, + uri: uri, + hash: config.hash + }); + } + config.hash = null; // resetting the config.hash for the next iteration... + // continue with the thread + dispatch( hd, config ); + }, + onFailure: function() { + // continue with the thread + dispatch( hd, config ); + }, + scope: obj, + data: config + }); + } else if (node.type === constants.CSSNODE) { + YAHOO.util.Get.css(uri, {}); + _hashtable[config.hash].status = constants.DISPATCHED; + // continue with the thread + dispatch( hd, config ); + } + } + } else { + // continue with the thread execution + dispatch( hd, config ); + } + } + else { + // the node represent an inline script (don't have hash value) + config.hash = null; + exec (hd, node.content, config); + } + } else { + // ending the execution thread + obj.kill(hd); + _onLoad (config); + } + } + + /** + * Executing a javascript script segment + * @public + * @param {Object} hd Thread's handle + * @param {string} c Content to execute + * @param {Object} config User configuration (useful for future implementations) + * @return boolean + */ + function exec( hd, c, config ) { + var status = constants.EMPTY; + if (c && (c !== '')) { + try{ + status = constants.DISPATCHED; + // instead send in a variable that points to this object... + if (!config.hash || (_hashtable[config.hash].status != constants.DISPATCHED)) { + obj.area = hd; + obj.destroyer = _threads[hd].destroyer; + // you can define your own evaluation routine for inline scripts + if ($L.isFunction(config.evalRoutine)) { + config.evalRoutine(c, config); + } else { + /* using the new routine to evaluate inline script, no longer using eval */ + _globalEval (c); + } + } + }catch(e){ + status = constants.ERROR; + if ($L.isFunction(config.error)) { + config.error.apply ( config, [hd, c, _hashtable, e] ); + } else { + throw new + Error ("Dispacher: Script Execution Error ("+e+")"); + } + } + } + // updating the status of the remote script in the hashtable + if ($L.isNumber(config.hash)) { + _hashtable[config.hash].status = status; + config.hash = null; // resetting the config.hash for the next iteration... + } + dispatch( hd, config ); + } + + /** + * Display the content inside the element + * @public + * @param {Object} el Element reference + * @param {string} c Content to display + * @param {Object} config User configuration (useful for future implementations) + * @return boolean + */ + function display( el, c, config ) { + config.action = (config.action?config.action:'replace'); + switch (config.action) + { + case 'tabview': + // onDestroy event... used to release the memory inside the tab... + destroy (el.get('contentEl'), config); + try { el.set('content', c); } catch (e1) {return false;} + _onChange (config, el.get('contentEl')); + break; + case 'update': + c = el.innerHTML + c; + try { el.innerHTML = c; } catch (e2) {return false;} + _onChange (config, el); + break; + case 'replace': + case 'layout': + default: + // onDestroy event... used to release the memory inside the element... + destroy (el, config); + // changing the content + try { el.innerHTML = c; } catch (e3) {return false;} + _onChange (config, el); + break; + } + return true; + } + /** + * "Destroy Custom Event" will be fired before remove the innerHTML in the displaying process + * @public + * @param {Object} el DOM Element reference + * @param {Object} config User configuration (useful for future implementations) + * @return void + */ + function destroy( el, config ) { + var hd = config.guid, i = 0; + if ($L.isObject(_threads[hd].destroyer)) { + _threads[hd].destroyer.fire (el, config); + } + if ($D.inDocument(el)) { + // purge the child elements and the events attached... + for (i=0;i<el.childNodes.length;i++) { + $E.purgeElement ( el.childNodes[i], true ); + } + $D.addClass (el, _classname); + } + _threads[hd].destroyer = new YAHOO.util.CustomEvent('destroyer'); + // checking for default onDestroy (usually passed to the methods fetch, delegate or process) + if ($L.isFunction(config.onDestroy)) { + _threads[hd].destroyer.subscribe (config.onDestroy); + } + // other subscribers can be add using: YAHOO.plugin.Dispatcher.destroyer.subscribe ( mySubscriber ); + } + /** + * Parse the string, remove the script tags, and create the execution thread... + * @public + * @param {Object} hd Element reference + * @param {string} s String with the script tags inside... + * @return string + */ + function parse( hd, s, config ) { + config = config || {}; + config.uri = config.uri || null; + config.relative = config.relative || _oDefaultConfig.relative; + var m = true, attr = false, + base = _baseURI(config.uri); // calculation of the base path... + // searching and cut out all style tags, push them into thread + // ej. <style title="" type="text/css"></style> + // not supported yet. <!--@import url("http://us.js2.yimg.com/us.js.yimg.com/lib/hdr/ygma_2.19.css");body{margin:0px 4px;}--> + s = s.replace(reStyleTag, + function (str,p1,p2,offset,s) { + // apply the inline style automatically + if (p2) { + obj.applyCSS(p2, _getParams(p1), config); + } + return ""; + } + ); + + // searching and cut out all Link tags, push them into thread + // ej. <link rel="stylesheet" type="text/css" href='/themes/bubbling/css/common.css' /> + s = s.replace(reLinkTag, + function (str,p1,p2,offset,s) { + // add a remote style to buffer + if(p1){ + attr = p1.match(reLinkTagSrc); + if(attr) { + if (config.relative) { + attr[2] = _relativeURI(base, attr[2]); // path correction process... + } + _threads[hd].chunks.push ({ + src: attr[2], + content: '', + type: constants.CSSNODE, + params: _getParams(p1) + }); + } + } + return ""; + } + ); + + // searching and cut out all script tags, push them into thread + s = s.replace(reScriptTag, + function (str,p1,p2,offset,s) { + // add a remote script to buffer + if(p1){ + attr = p1.match(reScriptTagSrc); + if(attr) { + var rel = p1.match(reScriptTagRel); + rel = (rel?rel[2]:null); + if (config.relative) { + attr[2] = _relativeURI(base, attr[2]); // path correction process... + } + _threads[hd].chunks.push ({ + src: attr[2], + content: '', + type: constants.JSNODE, + rel: rel, + params: _getParams(p1) + }); + } + } + // add a inline script to buffer + if (p2) { + _threads[hd].chunks.push ({ + src: null, + content: p2, + type: constants.JSNODE, + params: _getParams(p1) + }); + } + return ""; + } + ); + return s; + } + + // is the bubbling is available, we will define the cache listener... + if (YAHOO.Bubbling) { + YAHOO.Bubbling.on('onScriptReady', function() { + if (this.src && !this.hash) { + _hashtable[this.hash].status = constants.DISPATCHED; + } + }); + } + + // public vars + obj.area = null; // current thread, useful to get the current DOM element... + obj.strictMode = true; + obj.destroyer = null; // current destroyer, useful to add new subscriber during the execution... + // public methods + /** + * * Fetching a remote file that will be processed thru this object... + * @public + * @param {object} el {HTMLElement | String | Object} The html element that represents the dynamic area. + * @param {object} uri Remote file that will be loaded using AJAX + * @param {object} config Literal object with the user configuration vars + * @return object Reference to the connection handle + */ + obj.fetch = function( el, uri, config ){ + config = config || {}; + config.uri = uri; + var id = null, + u = null, + callback = { + success: function (o) { + if (o.responseText != 'undefined') { + obj.process( el, o.responseText, config, true ); + } + $D.removeClass(el, _loadingClass); + }, + failure:function (o) { + if ($L.isFunction(config.onError)) { + config.onError.apply ( config, [config.element, o] ); + } + $D.removeClass(el, _loadingClass); + } + }; + if (($L.isObject(el) || (el = $( el ))) && uri) { + u = obj.firewall (uri, config); + $D.addClass(el, _loadingClass); + config.handle = $C.asyncRequest('GET', u, callback); + config.element = el; + _onStart (config); + // broadcasting the message to log the navigation action into the history manager + if (YAHOO.Bubbling) { + id = config.guid || $E.generateId (el); + YAHOO.Bubbling.fire ('onNavigate', { + state: id+escape(uri), + control: 'dispatcher', + element: el, + uri: uri, + config: config, + restore: function() { + obj.fetch (el, uri, config); + } + }); + } + return config.handle; + } + return null; + }; + /** + * * Starting the process for a content... + * @public + * @param {object} el {HTMLElement | String | Object} The html element that represents the dynamic area. + * @param {string} content Content to be processed + * @param {object} config Literal object with the user configuration vars + * @param {boolean} flag If the call was internal or external + * @return object reference to the thread handle... + */ + obj.process = function( el, content, config, flag ){ + var hd = null; + config = config || {}; + if ($L.isObject(el) || (el = $( el ))) { + hd = config.guid || $E.generateId (el); // by default, one thread by element, use the GUID to discard this rule... + this.kill(hd); // kill the previous process for this handle... + config.element = el; + config.content = content; + config.guid = hd; + if (!flag) { + _onStart(config); + } + // processing + if (display(el, parse (hd, content, config), config)) { + dispatch (hd, config); // starting the execution chain + } + } + return hd; + }; + /** + * * TABVIEW: delegate the set content method... + * @public + * @param {object} tab reference to the tab... + * @param {object} tabview reference to the tabview... + * @param {object} config Literal object with the user configuration vars + * @return void + */ + obj.delegate = function ( tab, tabview, config ) { + config = config || {}; + config.action = 'tabview'; + config.uri = tab.get ('dataSrc') || null; // getting the base url for the execution... + config.tab = tab; + tab.loadHandler.success = function(o) { + var el = tab.get('contentEl'); + config.tab = el; + config.underground = true; + obj.process( tab, o.responseText, config ); + // broadcasting the message + if (YAHOO.Bubbling) { + YAHOO.Bubbling.fire ('onAsyncRequestEnd', { + element: el + }); + } + }; + tab.on("activeChange", function() { + // broadcasting the message + if (YAHOO.Bubbling && this.get('active') && tab.get ('dataSrc') && !this.get('cacheData')) { + YAHOO.Bubbling.fire ('onAsyncRequestStart', { + element: this.get('contentEl') + }); + } + }); + if ($L.isObject(tabview)) { + tabview.addTab(tab); + } + }; + /** + * * addUnit: delegate the addUnit layout method... + * @public + * @param {object} unit reference to the unit... + * @param {object} layout reference to the layout... + * @param {object} config Literal object with the user configuration vars + * @return object reference to the unit + */ + obj.addUnit = function ( unit, layout, config ) { + var c = config || {}, el; + c.action = 'layout'; + if (!unit || !layout) { + return false; + } + if ($L.isString(unit)) { + unit = layout.getUnitByPosition (unit); + } else if (unit.position && !layout.getUnitByPosition (unit.position)) { + // creating the new unit if the object is a simple literal with the position and + // the position is not filled yet in the layout manager... + unit = layout.addUnit(unit); + } + if (c.uri) { + unit.set('dataSrc', c.uri); + } + if ((c.unit = unit) && (c.uri = c.unit.get ('dataSrc')) && (el = c.unit.body)) { + c.underground = true; + c._dispatcherConfig = c; + c.unit.loadHandler.success = function(o) { + obj.process( this.body, o.responseText, this._dispatcherConfig ); + // broadcasting the message + if (YAHOO.Bubbling) { + YAHOO.Bubbling.fire ('onAsyncRequestEnd', { + element: this.body + }); + } + }; + /* starting the loading process */ + if (c.unit.loadContent() && YAHOO.Bubbling) { + // broadcasting the message + YAHOO.Bubbling.fire ('onAsyncRequestStart', { + element: el + }); + } + } + return c.unit; + }; + /** + * * Injecting CSS in the current page + * @public + * @param {string} cssCode CSS content that will be injected + * @param {object} params Literal object with the tag configuration params + * @param {object} config Literal object with the dispatcher configuration values + * @return boolean the operation result + */ + obj.applyCSS = function( cssCode, params, config ) { + params = params || {}; + var styleElement = document.createElement("style"), base = params.href || ''; + // calculation of the base path... + config = config || {}; + var uri = config.uri || _oDefaultConfig.baseURI; + config.relative = config.relative || _oDefaultConfig.relative; + if (config.relative) { + // applying the firewall routine to get the real path and load the css internal resources correctly. + uri = obj.firewall (uri, config, true); + base = _baseURI(uri); // calculation of the base path... + base = _relativeURI(base, params.href); // path correction process... + } + base = _baseURI(base); + // path correction process... + // ej: (image.gif) or ("image.gif") or ('image.gif') or (http://fullpath/image.gif) + /* In the case of DXImageTransform.Microsoft.AlphaImageLoader(src='image.png',sizingMethod='scale'); + The use of the AlphaImageLoader ultimately proved to be + an unreliable solution for IE 6 as it never handled relative paths well. + It seems like the AlphaImageLoader always expects the paths to be relative + to the page the CSS is included in, rather than relative to the CSS file itself. */ + cssCode = cssCode.replace(reCSS3rdFile, + function (str,p1,offset,s) { + p1 = _eraseQuotes (p1); + p1 = 'url('+_relativeURI(base, p1); + return p1; + } + ); + + // the CSS is ready... + styleElement.type = "text/css"; + if ($L.isObject(styleElement.styleSheet)) { + styleElement.styleSheet.cssText = cssCode; + } else { + styleElement.appendChild(document.createTextNode(cssCode)); + } + try{ + document.getElementsByTagName("head")[0].appendChild(styleElement); + }catch(e){ + throw new + Error ("Dispacher: CSS Processing Error ("+e+")"); + return false; + } + return true; + }; + /** + * * Fetching a remote javascript file that will be processed thru this object... + * @public + * @param {object} uri Remote js file that will be loaded using AJAX + * @param {object} config Literal object with the user configuration vars + * @return string ID reference to the new dispatcher's thread + */ + obj.jsLoader = function( uri, config ){ + if ($L.isString(uri) && (uri !== '')) { + config = config || {}; + $E.generateId ( config ); // generating an unique ID for the thread (config.id) + obj.kill (config.id); + // add a remote script to buffer + _threads[config.id].chunks = [{ + src: uri, + content: '', + type: constants.JSNODE, + params: {href: uri} + }]; + config.underground = true; + _onStart(config); + dispatch (config.id, config); // starting the execution chain + return config.id; + } + return null; + }; + /** + * * Fetching a remote CSS file that will be processed thru this object... + * @public + * @param {object} uri Remote CSS file that will be loaded using AJAX + * @param {object} config Literal object with the user configuration vars + * @return string ID reference to the new dispatcher's thread + */ + obj.cssLoader = function( uri, config ){ + if ($L.isString(uri) && (uri !== '')) { + config = config || {}; + $E.generateId ( config ); // generating an unique ID for the thread (config.id) + obj.kill (config.id); + // add a remote script to buffer + _threads[config.id].chunks = [{ + src: uri, + content: '', + type: constants.CSSNODE, + params: {href: uri} + }]; + config.underground = true; + _onStart(config); + dispatch (config.id, config); // starting the execution chain + return config.id; + } + return null; + }; + /** + * * Verify if the a process is still alive + * @public + * @param {object} hd Process handle + * @return boolean + */ + obj.isAlive = function ( hd ) { + return (hd && $L.isObject(_threads[hd]) && (_threads[hd].chunks.length > 0)); + }; + /** + * * Kill a process... + * @public + * @param {object} handle Process handle + * @return void + */ + obj.kill = function ( hd ) { + if (hd && !$L.isObject(_threads[hd])) { + _threads[hd] = {chunks: [], destroyer: null}; + } else if (this.isAlive (hd)) { + _threads[hd].chunks = []; // discarding the handle... + } + }; + /** + * * destroy an area... + * @public + * @param {object} handle Process handle + * @return void + */ + obj.destroy = function ( hd ) { + this.kill(hd); + if (hd && !$L.isObject(_threads[hd])) { + _threads[hd].destroyer.fire( $(hd), {} ); + } + }; + /* * onDestroy - subscribe a new destroyer for a certain area... + * @public + * @param {object} handle Process handle + * @return boolean + */ + obj.onDestroy = function ( hd, bh, scope ) { + var params = (scope?[bh, scope, true]:[bh]); // params for scope corrections + if ($L.isObject(_threads[hd]) && $L.isObject(_threads[hd].destroyer)) { + if ($L.isObject(scope)) { + _threads[hd].destroyer.subscribe(bh, scope, true); // correcting the default scope + } else { + _threads[hd].destroyer.subscribe(bh); // use the default scope + } + return true; + } + return false; + }; + obj.init = function (c) { + c = c || {}; + c.relative = c.relative || false; + _oDefaultConfig = c; + }; + /** + * Analyze the uri before start the downloading process (if the uri isn't in over the current domain name, the dispatcher can use a proxy) + * @public + * @param {String} uri Remote URL + * @param {Object} config Used to pass the user configuration thru the chain of execution + * @param {Boolean} monolitic Do not use proxy + * @return String + */ + obj.firewall = function( uri, config, monolitic ) { + var sDomain = null, + sProtocol = null, + m = null; + // AJAX url don't work with & + while (uri.indexOf ( '&' ) > -1) { + uri = uri.replace ( '&', '&' ); + } + // defining the proxy for cross-domain scripting... + config.proxy = config.proxy || constants.proxy; + if ($L.isFunction(config.firewall)) { + // external verification only... + uri = config.firewall.apply ( config, [uri] ); + } else { + // internal verification only... + // monolithic execution discard the cross-domain capabilities + if (!config.monolithic && !monolitic && config.proxy) { + m = uri.match(reURI); // checking the RE to verify if the url is external... + if (m && (m[2] !== document.domain)) { + // the uri is external, escaping especial chars and use a proxy + uri = config.proxy + escape(uri); + } + } + } + return uri; + }; + /** + * converting a literal object into a query string + * @public + * @param {object} params Literal object to create the url querystring {'param1':'value1','param2':'value2'} + * @return string + */ + obj.obj2query = function( params ) { + var u = '', indx; + if ($L.isObject(params)) { + for (key in params) { + if (params.hasOwnProperty(key)) { + u += (u==''?'':'&'); + u += key+'='+params[key]; + } + } + } + return u; + }; + /** + * augment an url with more parameters, overriding... + * @public + * @param {string} url + * @param {string|array} m MoreParams: string: param1=value1¶m2=value2 or array: {'param1':'value1','param2':'value2'} + * @return string + */ + obj.augmentURI = function( url, m ) { + m = m || {}; + var o = _parseUri(url, this.strictMode), + u = ''; + o.queryKey = o.queryKey || {}; + $L.augmentObject(o.queryKey, m, true); + if (o.protocol) u += o.protocol + ':'; + if (this.strictMode) { + if (/^(?:[^:\/?#]+:)?\/\//.test(o.source)) u += '//'; + } else { + if (/^(?:(?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?\/\//.test(o.source)) u += '//'; + } + if (o.authority) { + if (o.userInfo) { + if (o.user) u += o.user; + if (o.userInfo.indexOf(':') > -1) u += ':'; + if (o.password) u += o.password; + u += '@'; + } + if (o.host) u += o.host; + if (o.port) u += ':' + o.port; + } + if (o.relative) { + if (o.path) { + if (o.directory) u += o.directory; + if (o.file) u += o.file; + } + u += '?';// + o.query; + for (sName in o.queryKey) { + if (o.queryKey.hasOwnProperty(sName)) { + u += sName+'='+o.queryKey[sName]+'&'; + } + } + if (o.anchor) u += '#' + o.anchor; + } + return u; + }; + /** + * @method toString + * @description Returns a string representing the dispatcher plugin. + * @return {String} + */ + obj.toString = function() { + return ("YUI Dispatcher Plugin"); + }; + return obj; + }(); +})(); +YAHOO.util.Dispatcher = YAHOO.plugin.Dispatcher; // deprecated: backward compatibility issue... +YAHOO.register("dispatcher", YAHOO.plugin.Dispatcher, {version: "2.1", build: "237"}); Index: openacs-4/packages/messages/www/resources/dragdrop.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/dragdrop.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/dragdrop.js 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1,967 @@ +if(Object.isUndefined(Effect)) + throw("dragdrop.js requires including script.aculo.us' effects.js library"); + +var Droppables = { + drops: [], + + remove: function(element) { + this.drops = this.drops.reject(function(d) { return d.element==$(element) }); + }, + + add: function(element) { + element = $(element); + var options = Object.extend({ + greedy: true, + hoverclass: null, + tree: false + }, arguments[1] || { }); + + // cache containers + if(options.containment) { + options._containers = []; + var containment = options.containment; + if(Object.isArray(containment)) { + containment.each( function(c) { options._containers.push($(c)) }); + } else { + options._containers.push($(containment)); + } + } + + if(options.accept) options.accept = [options.accept].flatten(); + + Element.makePositioned(element); // fix IE + options.element = element; + + this.drops.push(options); + }, + + findDeepestChild: function(drops) { + deepest = drops[0]; + + for (i = 1; i < drops.length; ++i) + if (Element.isParent(drops[i].element, deepest.element)) + deepest = drops[i]; + + return deepest; + }, + + isContained: function(element, drop) { + var containmentNode; + if(drop.tree) { + containmentNode = element.treeNode; + } else { + containmentNode = element.parentNode; + } + return drop._containers.detect(function(c) { return containmentNode == c }); + }, + + isAffected: function(point, element, drop) { + return ( + (drop.element!=element) && + ((!drop._containers) || + this.isContained(element, drop)) && + ((!drop.accept) || + (Element.classNames(element).detect( + function(v) { return drop.accept.include(v) } ) )) && + Position.within(drop.element, point[0], point[1]) ); + }, + + deactivate: function(drop) { + if(drop.hoverclass) + Element.removeClassName(drop.element, drop.hoverclass); + this.last_active = null; + }, + + activate: function(drop) { + if(drop.hoverclass) + Element.addClassName(drop.element, drop.hoverclass); + this.last_active = drop; + }, + + show: function(point, element) { + if(!this.drops.length) return; + var drop, affected = []; + + this.drops.each( function(drop) { + if(Droppables.isAffected(point, element, drop)) + affected.push(drop); + }); + + if(affected.length>0) + drop = Droppables.findDeepestChild(affected); + + if(this.last_active && this.last_active != drop) this.deactivate(this.last_active); + if (drop) { + Position.within(drop.element, point[0], point[1]); + if(drop.onHover) + drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); + + if (drop != this.last_active) Droppables.activate(drop); + } + }, + + fire: function(event, element) { + if(!this.last_active) return; + Position.prepare(); + + if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) + if (this.last_active.onDrop) { + this.last_active.onDrop(element, this.last_active.element, event); + return true; + } + }, + + reset: function() { + if(this.last_active) + this.deactivate(this.last_active); + } +}; + +var Draggables = { + drags: [], + observers: [], + + register: function(draggable) { + if(this.drags.length == 0) { + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.updateDrag.bindAsEventListener(this); + this.eventKeypress = this.keyPress.bindAsEventListener(this); + + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + Event.observe(document, "keypress", this.eventKeypress); + } + this.drags.push(draggable); + }, + + unregister: function(draggable) { + this.drags = this.drags.reject(function(d) { return d==draggable }); + if(this.drags.length == 0) { + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + Event.stopObserving(document, "keypress", this.eventKeypress); + } + }, + + activate: function(draggable) { + if(draggable.options.delay) { + this._timeout = setTimeout(function() { + Draggables._timeout = null; + window.focus(); + Draggables.activeDraggable = draggable; + }.bind(this), draggable.options.delay); + } else { + window.focus(); // allows keypress events if window isn't currently focused, fails for Safari + this.activeDraggable = draggable; + } + }, + + deactivate: function() { + this.activeDraggable = null; + }, + + updateDrag: function(event) { + if(!this.activeDraggable) return; + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + // Mozilla-based browsers fire successive mousemove events with + // the same coordinates, prevent needless redrawing (moz bug?) + if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; + this._lastPointer = pointer; + + this.activeDraggable.updateDrag(event, pointer); + }, + + endDrag: function(event) { + if(this._timeout) { + clearTimeout(this._timeout); + this._timeout = null; + } + if(!this.activeDraggable) return; + this._lastPointer = null; + this.activeDraggable.endDrag(event); + this.activeDraggable = null; + }, + + keyPress: function(event) { + if(this.activeDraggable) + this.activeDraggable.keyPress(event); + }, + + addObserver: function(observer) { + this.observers.push(observer); + this._cacheObserverCallbacks(); + }, + + removeObserver: function(element) { // element instead of observer fixes mem leaks + this.observers = this.observers.reject( function(o) { return o.element==element }); + this._cacheObserverCallbacks(); + }, + + notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' + if(this[eventName+'Count'] > 0) + this.observers.each( function(o) { + if(o[eventName]) o[eventName](eventName, draggable, event); + }); + if(draggable.options[eventName]) draggable.options[eventName](draggable, event); + }, + + _cacheObserverCallbacks: function() { + ['onStart','onEnd','onDrag'].each( function(eventName) { + Draggables[eventName+'Count'] = Draggables.observers.select( + function(o) { return o[eventName]; } + ).length; + }); + } +}; + +/*--------------------------------------------------------------------------*/ + +var Draggable = Class.create({ + initialize: function(element) { + var defaults = { + handle: false, + reverteffect: function(element, top_offset, left_offset) { + var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; + new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, + queue: {scope:'_draggable', position:'end'} + }); + }, + endeffect: function(element) { + var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0; + new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, + queue: {scope:'_draggable', position:'end'}, + afterFinish: function(){ + Draggable._dragging[element] = false + } + }); + }, + zindex: 1000, + revert: false, + quiet: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] } + delay: 0 + }; + + if(!arguments[1] || Object.isUndefined(arguments[1].endeffect)) + Object.extend(defaults, { + starteffect: function(element) { + element._opacity = Element.getOpacity(element); + Draggable._dragging[element] = true; + new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); + } + }); + + var options = Object.extend(defaults, arguments[1] || { }); + + this.element = $(element); + + if(options.handle && Object.isString(options.handle)) + this.handle = this.element.down('.'+options.handle, 0); + + if(!this.handle) this.handle = $(options.handle); + if(!this.handle) this.handle = this.element; + + if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { + options.scroll = $(options.scroll); + this._isScrollChild = Element.childOf(this.element, options.scroll); + } + + Element.makePositioned(this.element); // fix IE + + this.options = options; + this.dragging = false; + + this.eventMouseDown = this.initDrag.bindAsEventListener(this); + Event.observe(this.handle, "mousedown", this.eventMouseDown); + + Draggables.register(this); + }, + + destroy: function() { + Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); + Draggables.unregister(this); + }, + + currentDelta: function() { + return([ + parseInt(Element.getStyle(this.element,'left') || '0'), + parseInt(Element.getStyle(this.element,'top') || '0')]); + }, + + initDrag: function(event) { + if(!Object.isUndefined(Draggable._dragging[this.element]) && + Draggable._dragging[this.element]) return; + if(Event.isLeftClick(event)) { + // abort on form elements, fixes a Firefox issue + var src = Event.element(event); + if((tag_name = src.tagName.toUpperCase()) && ( + tag_name=='INPUT' || + tag_name=='SELECT' || + tag_name=='OPTION' || + tag_name=='BUTTON' || + tag_name=='TEXTAREA')) return; + + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var pos = Position.cumulativeOffset(this.element); + this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); + + Draggables.activate(this); + Event.stop(event); + } + }, + + startDrag: function(event) { + this.dragging = true; + if(!this.delta) + this.delta = this.currentDelta(); + + if(this.options.zindex) { + this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); + this.element.style.zIndex = this.options.zindex; + } + + if(this.options.ghosting) { + this._clone = this.element.cloneNode(true); + this._originallyAbsolute = (this.element.getStyle('position') == 'absolute'); + if (!this._originallyAbsolute) + Position.absolutize(this.element); + this.element.parentNode.insertBefore(this._clone, this.element); + } + + if(this.options.scroll) { + if (this.options.scroll == window) { + var where = this._getWindowScroll(this.options.scroll); + this.originalScrollLeft = where.left; + this.originalScrollTop = where.top; + } else { + this.originalScrollLeft = this.options.scroll.scrollLeft; + this.originalScrollTop = this.options.scroll.scrollTop; + } + } + + Draggables.notify('onStart', this, event); + + if(this.options.starteffect) this.options.starteffect(this.element); + }, + + updateDrag: function(event, pointer) { + if(!this.dragging) this.startDrag(event); + + if(!this.options.quiet){ + Position.prepare(); + Droppables.show(pointer, this.element); + } + + Draggables.notify('onDrag', this, event); + + this.draw(pointer); + if(this.options.change) this.options.change(this); + + if(this.options.scroll) { + this.stopScrolling(); + + var p; + if (this.options.scroll == window) { + with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } + } else { + p = Position.page(this.options.scroll); + p[0] += this.options.scroll.scrollLeft + Position.deltaX; + p[1] += this.options.scroll.scrollTop + Position.deltaY; + p.push(p[0]+this.options.scroll.offsetWidth); + p.push(p[1]+this.options.scroll.offsetHeight); + } + var speed = [0,0]; + if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); + if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); + if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); + if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); + this.startScrolling(speed); + } + + // fix AppleWebKit rendering + if(Prototype.Browser.WebKit) window.scrollBy(0,0); + + Event.stop(event); + }, + + finishDrag: function(event, success) { + this.dragging = false; + + if(this.options.quiet){ + Position.prepare(); + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + Droppables.show(pointer, this.element); + } + + if(this.options.ghosting) { + if (!this._originallyAbsolute) + Position.relativize(this.element); + delete this._originallyAbsolute; + Element.remove(this._clone); + this._clone = null; + } + + var dropped = false; + if(success) { + dropped = Droppables.fire(event, this.element); + if (!dropped) dropped = false; + } + if(dropped && this.options.onDropped) this.options.onDropped(this.element); + Draggables.notify('onEnd', this, event); + + var revert = this.options.revert; + if(revert && Object.isFunction(revert)) revert = revert(this.element); + + var d = this.currentDelta(); + if(revert && this.options.reverteffect) { + if (dropped == 0 || revert != 'failure') + this.options.reverteffect(this.element, + d[1]-this.delta[1], d[0]-this.delta[0]); + } else { + this.delta = d; + } + + if(this.options.zindex) + this.element.style.zIndex = this.originalZ; + + if(this.options.endeffect) + this.options.endeffect(this.element); + + Draggables.deactivate(this); + Droppables.reset(); + }, + + keyPress: function(event) { + if(event.keyCode!=Event.KEY_ESC) return; + this.finishDrag(event, false); + Event.stop(event); + }, + + endDrag: function(event) { + if(!this.dragging) return; + this.stopScrolling(); + this.finishDrag(event, true); + Event.stop(event); + }, + + draw: function(point) { + var pos = Position.cumulativeOffset(this.element); + if(this.options.ghosting) { + var r = Position.realOffset(this.element); + pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; + } + + var d = this.currentDelta(); + pos[0] -= d[0]; pos[1] -= d[1]; + + if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { + pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; + pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; + } + + var p = [0,1].map(function(i){ + return (point[i]-pos[i]-this.offset[i]) + }.bind(this)); + + if(this.options.snap) { + if(Object.isFunction(this.options.snap)) { + p = this.options.snap(p[0],p[1],this); + } else { + if(Object.isArray(this.options.snap)) { + p = p.map( function(v, i) { + return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this)); + } else { + p = p.map( function(v) { + return (v/this.options.snap).round()*this.options.snap }.bind(this)); + } + }} + + var style = this.element.style; + if((!this.options.constraint) || (this.options.constraint=='horizontal')) + style.left = p[0] + "px"; + if((!this.options.constraint) || (this.options.constraint=='vertical')) + style.top = p[1] + "px"; + + if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering + }, + + stopScrolling: function() { + if(this.scrollInterval) { + clearInterval(this.scrollInterval); + this.scrollInterval = null; + Draggables._lastScrollPointer = null; + } + }, + + startScrolling: function(speed) { + if(!(speed[0] || speed[1])) return; + this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; + this.lastScrolled = new Date(); + this.scrollInterval = setInterval(this.scroll.bind(this), 10); + }, + + scroll: function() { + var current = new Date(); + var delta = current - this.lastScrolled; + this.lastScrolled = current; + if(this.options.scroll == window) { + with (this._getWindowScroll(this.options.scroll)) { + if (this.scrollSpeed[0] || this.scrollSpeed[1]) { + var d = delta / 1000; + this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); + } + } + } else { + this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; + this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; + } + + Position.prepare(); + Droppables.show(Draggables._lastPointer, this.element); + Draggables.notify('onDrag', this); + if (this._isScrollChild) { + Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); + Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; + Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; + if (Draggables._lastScrollPointer[0] < 0) + Draggables._lastScrollPointer[0] = 0; + if (Draggables._lastScrollPointer[1] < 0) + Draggables._lastScrollPointer[1] = 0; + this.draw(Draggables._lastScrollPointer); + } + + if(this.options.change) this.options.change(this); + }, + + _getWindowScroll: function(w) { + var T, L, W, H; + with (w.document) { + if (w.document.documentElement && documentElement.scrollTop) { + T = documentElement.scrollTop; + L = documentElement.scrollLeft; + } else if (w.document.body) { + T = body.scrollTop; + L = body.scrollLeft; + } + if (w.innerWidth) { + W = w.innerWidth; + H = w.innerHeight; + } else if (w.document.documentElement && documentElement.clientWidth) { + W = documentElement.clientWidth; + H = documentElement.clientHeight; + } else { + W = body.offsetWidth; + H = body.offsetHeight; + } + } + return { top: T, left: L, width: W, height: H }; + } +}); + +Draggable._dragging = { }; + +/*--------------------------------------------------------------------------*/ + +var SortableObserver = Class.create({ + initialize: function(element, observer) { + this.element = $(element); + this.observer = observer; + this.lastValue = Sortable.serialize(this.element); + }, + + onStart: function() { + this.lastValue = Sortable.serialize(this.element); + }, + + onEnd: function() { + Sortable.unmark(); + if(this.lastValue != Sortable.serialize(this.element)) + this.observer(this.element) + } +}); + +var Sortable = { + SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, + + sortables: { }, + + _findRootElement: function(element) { + while (element.tagName.toUpperCase() != "BODY") { + if(element.id && Sortable.sortables[element.id]) return element; + element = element.parentNode; + } + }, + + options: function(element) { + element = Sortable._findRootElement($(element)); + if(!element) return; + return Sortable.sortables[element.id]; + }, + + destroy: function(element){ + element = $(element); + var s = Sortable.sortables[element.id]; + + if(s) { + Draggables.removeObserver(s.element); + s.droppables.each(function(d){ Droppables.remove(d) }); + s.draggables.invoke('destroy'); + + delete Sortable.sortables[s.element.id]; + } + }, + + create: function(element) { + element = $(element); + var options = Object.extend({ + element: element, + tag: 'li', // assumes li children, override with tag: 'tagname' + dropOnEmpty: false, + tree: false, + treeTag: 'ul', + overlap: 'vertical', // one of 'vertical', 'horizontal' + constraint: 'vertical', // one of 'vertical', 'horizontal', false + containment: element, // also takes array of elements (or id's); or false + handle: false, // or a CSS class + only: false, + delay: 0, + hoverclass: null, + ghosting: false, + quiet: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + format: this.SERIALIZE_RULE, + + // these take arrays of elements or ids and can be + // used for better initialization performance + elements: false, + handles: false, + + onChange: Prototype.emptyFunction, + onUpdate: Prototype.emptyFunction + }, arguments[1] || { }); + + // clear any old sortable with same element + this.destroy(element); + + // build options for the draggables + var options_for_draggable = { + revert: true, + quiet: options.quiet, + scroll: options.scroll, + scrollSpeed: options.scrollSpeed, + scrollSensitivity: options.scrollSensitivity, + delay: options.delay, + ghosting: options.ghosting, + constraint: options.constraint, + handle: options.handle }; + + if(options.starteffect) + options_for_draggable.starteffect = options.starteffect; + + if(options.reverteffect) + options_for_draggable.reverteffect = options.reverteffect; + else + if(options.ghosting) options_for_draggable.reverteffect = function(element) { + element.style.top = 0; + element.style.left = 0; + }; + + if(options.endeffect) + options_for_draggable.endeffect = options.endeffect; + + if(options.zindex) + options_for_draggable.zindex = options.zindex; + + // build options for the droppables + var options_for_droppable = { + overlap: options.overlap, + containment: options.containment, + tree: options.tree, + hoverclass: options.hoverclass, + onHover: Sortable.onHover + }; + + var options_for_tree = { + onHover: Sortable.onEmptyHover, + overlap: options.overlap, + containment: options.containment, + hoverclass: options.hoverclass + }; + + // fix for gecko engine + Element.cleanWhitespace(element); + + options.draggables = []; + options.droppables = []; + + // drop on empty handling + if(options.dropOnEmpty || options.tree) { + Droppables.add(element, options_for_tree); + options.droppables.push(element); + } + + (options.elements || this.findElements(element, options) || []).each( function(e,i) { + var handle = options.handles ? $(options.handles[i]) : + (options.handle ? $(e).select('.' + options.handle)[0] : e); + options.draggables.push( + new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); + Droppables.add(e, options_for_droppable); + if(options.tree) e.treeNode = element; + options.droppables.push(e); + }); + + if(options.tree) { + (Sortable.findTreeElements(element, options) || []).each( function(e) { + Droppables.add(e, options_for_tree); + e.treeNode = element; + options.droppables.push(e); + }); + } + + // keep reference + this.sortables[element.id] = options; + + // for onupdate + Draggables.addObserver(new SortableObserver(element, options.onUpdate)); + + }, + + // return all suitable-for-sortable elements in a guaranteed order + findElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.tag); + }, + + findTreeElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.treeTag); + }, + + onHover: function(element, dropon, overlap) { + if(Element.isParent(dropon, element)) return; + + if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { + return; + } else if(overlap>0.5) { + Sortable.mark(dropon, 'before'); + if(dropon.previousSibling != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, dropon); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } else { + Sortable.mark(dropon, 'after'); + var nextElement = dropon.nextSibling || null; + if(nextElement != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, nextElement); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } + }, + + onEmptyHover: function(element, dropon, overlap) { + var oldParentNode = element.parentNode; + var droponOptions = Sortable.options(dropon); + + if(!Element.isParent(dropon, element)) { + var index; + + var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); + var child = null; + + if(children) { + var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); + + for (index = 0; index < children.length; index += 1) { + if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { + offset -= Element.offsetSize (children[index], droponOptions.overlap); + } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { + child = index + 1 < children.length ? children[index + 1] : null; + break; + } else { + child = children[index]; + break; + } + } + } + + dropon.insertBefore(element, child); + + Sortable.options(oldParentNode).onChange(element); + droponOptions.onChange(element); + } + }, + + unmark: function() { + if(Sortable._marker) Sortable._marker.hide(); + }, + + mark: function(dropon, position) { + // mark on ghosting only + var sortable = Sortable.options(dropon.parentNode); + if(sortable && !sortable.ghosting) return; + + if(!Sortable._marker) { + Sortable._marker = + ($('dropmarker') || Element.extend(document.createElement('DIV'))). + hide().addClassName('dropmarker').setStyle({position:'absolute'}); + document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); + } + var offsets = Position.cumulativeOffset(dropon); + Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'}); + + if(position=='after') + if(sortable.overlap == 'horizontal') + Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'}); + else + Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'}); + + Sortable._marker.show(); + }, + + _tree: function(element, options, parent) { + var children = Sortable.findElements(element, options) || []; + + for (var i = 0; i < children.length; ++i) { + var match = children[i].id.match(options.format); + + if (!match) continue; + + var child = { + id: encodeURIComponent(match ? match[1] : null), + element: element, + parent: parent, + children: [], + position: parent.children.length, + container: $(children[i]).down(options.treeTag) + }; + + /* Get the element containing the children and recurse over it */ + if (child.container) + this._tree(child.container, options, child); + + parent.children.push (child); + } + + return parent; + }, + + tree: function(element) { + element = $(element); + var sortableOptions = this.options(element); + var options = Object.extend({ + tag: sortableOptions.tag, + treeTag: sortableOptions.treeTag, + only: sortableOptions.only, + name: element.id, + format: sortableOptions.format + }, arguments[1] || { }); + + var root = { + id: null, + parent: null, + children: [], + container: element, + position: 0 + }; + + return Sortable._tree(element, options, root); + }, + + /* Construct a [i] index for a particular node */ + _constructIndex: function(node) { + var index = ''; + do { + if (node.id) index = '[' + node.position + ']' + index; + } while ((node = node.parent) != null); + return index; + }, + + sequence: function(element) { + element = $(element); + var options = Object.extend(this.options(element), arguments[1] || { }); + + return $(this.findElements(element, options) || []).map( function(item) { + return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; + }); + }, + + setSequence: function(element, new_sequence) { + element = $(element); + var options = Object.extend(this.options(element), arguments[2] || { }); + + var nodeMap = { }; + this.findElements(element, options).each( function(n) { + if (n.id.match(options.format)) + nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; + n.parentNode.removeChild(n); + }); + + new_sequence.each(function(ident) { + var n = nodeMap[ident]; + if (n) { + n[1].appendChild(n[0]); + delete nodeMap[ident]; + } + }); + }, + + serialize: function(element) { + element = $(element); + var options = Object.extend(Sortable.options(element), arguments[1] || { }); + var name = encodeURIComponent( + (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); + + if (options.tree) { + return Sortable.tree(element, arguments[1]).children.map( function (item) { + return [name + Sortable._constructIndex(item) + "[id]=" + + encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); + }).flatten().join('&'); + } else { + return Sortable.sequence(element, arguments[1]).map( function(item) { + return name + "[]=" + encodeURIComponent(item); + }).join('&'); + } + } +}; + +// Returns true if child is contained within element +Element.isParent = function(child, element) { + if (!child.parentNode || child == element) return false; + if (child.parentNode == element) return true; + return Element.isParent(child.parentNode, element); +}; + +Element.findChildren = function(element, only, recursive, tagName) { + if(!element.hasChildNodes()) return null; + tagName = tagName.toUpperCase(); + if(only) only = [only].flatten(); + var elements = []; + $A(element.childNodes).each( function(e) { + if(e.tagName && e.tagName.toUpperCase()==tagName && + (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) + elements.push(e); + if(recursive) { + var grandchildren = Element.findChildren(e, only, recursive, tagName); + if(grandchildren) elements.push(grandchildren); + } + }); + + return (elements.length>0 ? elements.flatten() : []); +}; + +Element.offsetSize = function (element, type) { + return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')]; +}; Index: openacs-4/packages/messages/www/resources/effects.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/effects.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/effects.js 31 Aug 2010 21:30:53 -0000 1.1 @@ -0,0 +1,1118 @@ + +String.prototype.parseColor = function() { + var color = '#'; + if (this.slice(0,4) == 'rgb(') { + var cols = this.slice(4,this.length-1).split(','); + var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); + } else { + if (this.slice(0,1) == '#') { + if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); + if (this.length==7) color = this.toLowerCase(); + } + } + return (color.length==7 ? color : (arguments[0] || this)); +}; + +/*--------------------------------------------------------------------------*/ + +Element.collectTextNodes = function(element) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); + }).flatten().join(''); +}; + +Element.collectTextNodesIgnoreClass = function(element, className) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? + Element.collectTextNodesIgnoreClass(node, className) : '')); + }).flatten().join(''); +}; + +Element.setContentZoom = function(element, percent) { + element = $(element); + element.setStyle({fontSize: (percent/100) + 'em'}); + if (Prototype.Browser.WebKit) window.scrollBy(0,0); + return element; +}; + +Element.getInlineOpacity = function(element){ + return $(element).style.opacity || ''; +}; + +Element.forceRerendering = function(element) { + try { + element = $(element); + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch(e) { } +}; + +/*--------------------------------------------------------------------------*/ + +var Effect = { + _elementDoesNotExistError: { + name: 'ElementDoesNotExistError', + message: 'The specified DOM element does not exist, but is required for this effect to operate' + }, + Transitions: { + linear: Prototype.K, + sinoidal: function(pos) { + return (-Math.cos(pos*Math.PI)/2) + .5; + }, + reverse: function(pos) { + return 1-pos; + }, + flicker: function(pos) { + var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4; + return pos > 1 ? 1 : pos; + }, + wobble: function(pos) { + return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5; + }, + pulse: function(pos, pulses) { + return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5; + }, + spring: function(pos) { + return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); + }, + none: function(pos) { + return 0; + }, + full: function(pos) { + return 1; + } + }, + DefaultOptions: { + duration: 1.0, // seconds + fps: 100, // 100= assume 66fps max. + sync: false, // true for combining + from: 0.0, + to: 1.0, + delay: 0.0, + queue: 'parallel' + }, + tagifyText: function(element) { + var tagifyStyle = 'position:relative'; + if (Prototype.Browser.IE) tagifyStyle += ';zoom:1'; + + element = $(element); + $A(element.childNodes).each( function(child) { + if (child.nodeType==3) { + child.nodeValue.toArray().each( function(character) { + element.insertBefore( + new Element('span', {style: tagifyStyle}).update( + character == ' ' ? String.fromCharCode(160) : character), + child); + }); + Element.remove(child); + } + }); + }, + multiple: function(element, effect) { + var elements; + if (((typeof element == 'object') || + Object.isFunction(element)) && + (element.length)) + elements = element; + else + elements = $(element).childNodes; + + var options = Object.extend({ + speed: 0.1, + delay: 0.0 + }, arguments[2] || { }); + var masterDelay = options.delay; + + $A(elements).each( function(element, index) { + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); + }); + }, + PAIRS: { + 'slide': ['SlideDown','SlideUp'], + 'blind': ['BlindDown','BlindUp'], + 'appear': ['Appear','Fade'] + }, + toggle: function(element, effect) { + element = $(element); + effect = (effect || 'appear').toLowerCase(); + var options = Object.extend({ + queue: { position:'end', scope:(element.id || 'global'), limit: 1 } + }, arguments[2] || { }); + Effect[element.visible() ? + Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); + } +}; + +Effect.DefaultOptions.transition = Effect.Transitions.sinoidal; + +/* ------------- core effects ------------- */ + +Effect.ScopedQueue = Class.create(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 = Object.isString(effect.options.queue) ? + effect.options.queue : effect.options.queue.position; + + switch(position) { + case 'front': + // move unstarted effects after this effect + this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { + e.startOn += effect.finishOn; + e.finishOn += effect.finishOn; + }); + break; + case 'with-last': + timestamp = this.effects.pluck('startOn').max() || timestamp; + break; + case 'end': + // start effect after last queued effect has finished + timestamp = this.effects.pluck('finishOn').max() || timestamp; + break; + } + + effect.startOn += timestamp; + effect.finishOn += timestamp; + + if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) + this.effects.push(effect); + + if (!this.interval) + this.interval = setInterval(this.loop.bind(this), 15); + }, + remove: function(effect) { + this.effects = this.effects.reject(function(e) { return e==effect }); + if (this.effects.length == 0) { + clearInterval(this.interval); + this.interval = null; + } + }, + loop: function() { + var timePos = new Date().getTime(); + for(var i=0, len=this.effects.length;i<len;i++) + this.effects[i] && this.effects[i].loop(timePos); + } +}); + +Effect.Queues = { + instances: $H(), + get: function(queueName) { + if (!Object.isString(queueName)) return queueName; + + return this.instances.get(queueName) || + this.instances.set(queueName, new Effect.ScopedQueue()); + } +}; +Effect.Queue = Effect.Queues.get('global'); + +Effect.Base = Class.create({ + position: null, + start: function(options) { + function codeForEvent(options,eventName){ + return ( + (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') + + (options[eventName] ? 'this.options.'+eventName+'(this);' : '') + ); + } + if (options && options.transition === false) options.transition = Effect.Transitions.linear; + 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.fromToDelta = this.options.to-this.options.from; + this.totalTime = this.finishOn-this.startOn; + this.totalFrames = this.options.fps*this.options.duration; + + this.render = (function() { + function dispatch(effect, eventName) { + if (effect.options[eventName + 'Internal']) + effect.options[eventName + 'Internal'](effect); + if (effect.options[eventName]) + effect.options[eventName](effect); + } + + return function(pos) { + if (this.state === "idle") { + this.state = "running"; + dispatch(this, 'beforeSetup'); + if (this.setup) this.setup(); + dispatch(this, 'afterSetup'); + } + if (this.state === "running") { + pos = (this.options.transition(pos) * this.fromToDelta) + this.options.from; + this.position = pos; + dispatch(this, 'beforeUpdate'); + if (this.update) this.update(pos); + dispatch(this, 'afterUpdate'); + } + } + })(); + + this.event('beforeStart'); + if (!this.options.sync) + Effect.Queues.get(Object.isString(this.options.queue) ? + '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.totalTime, + frame = (pos * this.totalFrames).round(); + if (frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + } + }, + cancel: function() { + if (!this.options.sync) + Effect.Queues.get(Object.isString(this.options.queue) ? + 'global' : this.options.queue.scope).remove(this); + this.state = 'finished'; + }, + event: function(eventName) { + if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); + if (this.options[eventName]) this.options[eventName](this); + }, + inspect: function() { + var data = $H(); + for(property in this) + if (!Object.isFunction(this[property])) data.set(property, this[property]); + return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>'; + } +}); + +Effect.Parallel = Class.create(Effect.Base, { + 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.Tween = Class.create(Effect.Base, { + initialize: function(object, from, to) { + object = Object.isString(object) ? $(object) : object; + var args = $A(arguments), method = args.last(), + options = args.length == 5 ? args[3] : null; + this.method = Object.isFunction(method) ? method.bind(object) : + Object.isFunction(object[method]) ? object[method].bind(object) : + function(value) { object[method] = value }; + this.start(Object.extend({ from: from, to: to }, options || { })); + }, + update: function(position) { + this.method(position); + } +}); + +Effect.Event = Class.create(Effect.Base, { + initialize: function() { + this.start(Object.extend({ duration: 0 }, arguments[0] || { })); + }, + update: Prototype.emptyFunction +}); + +Effect.Opacity = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + // make this work on IE on elements without 'layout' + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + var options = Object.extend({ + from: this.element.getOpacity() || 0.0, + to: 1.0 + }, arguments[1] || { }); + this.start(options); + }, + update: function(position) { + this.element.setOpacity(position); + } +}); + +Effect.Move = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + x: 0, + y: 0, + mode: 'relative' + }, arguments[1] || { }); + this.start(options); + }, + setup: function() { + this.element.makePositioned(); + this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); + this.originalTop = parseFloat(this.element.getStyle('top') || '0'); + if (this.options.mode == 'absolute') { + this.options.x = this.options.x - this.originalLeft; + this.options.y = this.options.y - this.originalTop; + } + }, + update: function(position) { + this.element.setStyle({ + left: (this.options.x * position + this.originalLeft).round() + 'px', + top: (this.options.y * position + this.originalTop).round() + '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(Effect.Base, { + initialize: function(element, percent) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or { } with provided values + scaleFrom: 100.0, + scaleTo: percent + }, arguments[2] || { }); + this.start(options); + }, + setup: function() { + this.restoreAfterFinish = this.options.restoreAfterFinish || false; + this.elementPositioning = this.element.getStyle('position'); + + this.originalStyle = { }; + ['top','left','width','height','fontSize'].each( function(k) { + this.originalStyle[k] = this.element.style[k]; + }.bind(this)); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + + var fontSize = this.element.getStyle('font-size') || '100%'; + ['em','px','%','pt'].each( function(fontSizeType) { + if (fontSize.indexOf(fontSizeType)>0) { + this.fontSize = parseFloat(fontSize); + this.fontSizeType = fontSizeType; + } + }.bind(this)); + + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; + + this.dims = null; + if (this.options.scaleMode=='box') + this.dims = [this.element.offsetHeight, this.element.offsetWidth]; + if (/^content/.test(this.options.scaleMode)) + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if (!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; + }, + update: function(position) { + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if (this.options.scaleContent && this.fontSize) + this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); + }, + finish: function(position) { + if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); + }, + setDimensions: function(height, width) { + var d = { }; + if (this.options.scaleX) d.width = width.round() + 'px'; + if (this.options.scaleY) d.height = height.round() + 'px'; + if (this.options.scaleFromCenter) { + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; + if (this.elementPositioning == 'absolute') { + if (this.options.scaleY) d.top = this.originalTop-topd + 'px'; + if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; + } else { + if (this.options.scaleY) d.top = -topd + 'px'; + if (this.options.scaleX) d.left = -leftd + 'px'; + } + } + this.element.setStyle(d); + } +}); + +Effect.Highlight = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { }); + this.start(options); + }, + setup: function() { + // Prevent executing on elements not in the layout flow + if (this.element.getStyle('display')=='none') { this.cancel(); return; } + // Disable background image during the effect + this.oldStyle = { }; + if (!this.options.keepBackgroundImage) { + this.oldStyle.backgroundImage = this.element.getStyle('background-image'); + this.element.setStyle({backgroundImage: 'none'}); + } + if (!this.options.endcolor) + this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); + if (!this.options.restorecolor) + this.options.restorecolor = this.element.getStyle('background-color'); + // init color calculations + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); + }, + update: function(position) { + this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ + return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) }); + }, + finish: function() { + this.element.setStyle(Object.extend(this.oldStyle, { + backgroundColor: this.options.restorecolor + })); + } +}); + +Effect.ScrollTo = function(element) { + var options = arguments[1] || { }, + scrollOffsets = document.viewport.getScrollOffsets(), + elementOffsets = $(element).cumulativeOffset(); + + if (options.offset) elementOffsets[1] += options.offset; + + return new Effect.Tween(null, + scrollOffsets.top, + elementOffsets[1], + options, + function(p){ scrollTo(scrollOffsets.left, p.round()) } + ); +}; + +/* ------------- combination effects ------------- */ + +Effect.Fade = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + var options = Object.extend({ + from: element.getOpacity() || 1.0, + to: 0.0, + afterFinishInternal: function(effect) { + if (effect.options.to!=0) return; + effect.element.hide().setStyle({opacity: oldOpacity}); + } + }, arguments[1] || { }); + return new Effect.Opacity(element,options); +}; + +Effect.Appear = function(element) { + element = $(element); + var options = Object.extend({ + from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), + to: 1.0, + // force Safari to render floated elements properly + afterFinishInternal: function(effect) { + effect.element.forceRerendering(); + }, + beforeSetup: function(effect) { + effect.element.setOpacity(effect.options.from).show(); + }}, arguments[1] || { }); + return new Effect.Opacity(element,options); +}; + +Effect.Puff = function(element) { + element = $(element); + var oldStyle = { + opacity: element.getInlineOpacity(), + position: element.getStyle('position'), + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height + }; + return new Effect.Parallel( + [ new Effect.Scale(element, 200, + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], + Object.extend({ duration: 1.0, + beforeSetupInternal: function(effect) { + Position.absolutize(effect.effects[0].element) + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().setStyle(oldStyle); } + }, arguments[1] || { }) + ); +}; + +Effect.BlindUp = function(element) { + element = $(element); + element.makeClipping(); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + restoreAfterFinish: true, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }, arguments[1] || { }) + ); +}; + +Effect.BlindDown = function(element) { + element = $(element); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping(); + } + }, arguments[1] || { })); +}; + +Effect.SwitchOff = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + return new Effect.Appear(element, Object.extend({ + duration: 0.4, + from: 0, + transition: Effect.Transitions.flicker, + afterFinishInternal: function(effect) { + new Effect.Scale(effect.element, 1, { + duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); + } + }) + } + }, arguments[1] || { })); +}; + +Effect.DropOut = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left'), + opacity: element.getInlineOpacity() }; + return new Effect.Parallel( + [ new Effect.Move(element, {x: 0, y: 100, sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 }) ], + Object.extend( + { duration: 0.5, + beforeSetup: function(effect) { + effect.effects[0].element.makePositioned(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); + } + }, arguments[1] || { })); +}; + +Effect.Shake = function(element) { + element = $(element); + var options = Object.extend({ + distance: 20, + duration: 0.5 + }, arguments[1] || {}); + var distance = parseFloat(options.distance); + var split = parseFloat(options.duration) / 10.0; + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left') }; + return new Effect.Move(element, + { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) { + effect.element.undoPositioned().setStyle(oldStyle); + }}) }}) }}) }}) }}) }}); +}; + +Effect.SlideDown = function(element) { + element = $(element).cleanWhitespace(); + // SlideDown need to have the content of the element wrapped in a container element with fixed height! + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: window.opera ? 0 : 1, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if (window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } + }, arguments[1] || { }) + ); +}; + +Effect.SlideUp = function(element) { + element = $(element).cleanWhitespace(); + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, window.opera ? 0 : 1, + Object.extend({ scaleContent: false, + scaleX: false, + scaleMode: 'box', + scaleFrom: 100, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if (window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({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) { + effect.element.makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }); +}; + +Effect.Grow = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.full + }, arguments[1] || { }); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = dims.width; + initialMoveY = moveY = 0; + moveX = -dims.width; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = dims.height; + moveY = -dims.height; + break; + case 'bottom-right': + initialMoveX = dims.width; + initialMoveY = dims.height; + moveX = -dims.width; + moveY = -dims.height; + break; + case 'center': + initialMoveX = dims.width / 2; + initialMoveY = dims.height / 2; + moveX = -dims.width / 2; + moveY = -dims.height / 2; + break; + } + + return new Effect.Move(element, { + x: initialMoveX, + y: initialMoveY, + duration: 0.01, + beforeSetup: function(effect) { + effect.element.hide().makeClipping().makePositioned(); + }, + afterFinishInternal: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), + new Effect.Scale(effect.element, 100, { + scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) + ], Object.extend({ + beforeSetup: function(effect) { + effect.effects[0].element.setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); + } + }, options) + ) + } + }); +}; + +Effect.Shrink = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.none + }, arguments[1] || { }); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = dims.width; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = dims.height; + break; + case 'bottom-right': + moveX = dims.width; + moveY = dims.height; + break; + case 'center': + moveX = dims.width / 2; + moveY = dims.height / 2; + break; + } + + return new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) + ], Object.extend({ + beforeStartInternal: function(effect) { + effect.effects[0].element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } + }, options) + ); +}; + +Effect.Pulsate = function(element) { + element = $(element); + var options = arguments[1] || { }, + oldOpacity = element.getInlineOpacity(), + transition = options.transition || Effect.Transitions.linear, + reverser = function(pos){ + return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5); + }; + + return new Effect.Opacity(element, + Object.extend(Object.extend({ duration: 2.0, from: 0, + afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } + }, options), {transition: reverser})); +}; + +Effect.Fold = function(element) { + element = $(element); + var oldStyle = { + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height }; + element.makeClipping(); + return new Effect.Scale(element, 5, Object.extend({ + scaleContent: false, + scaleX: false, + afterFinishInternal: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleY: false, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().setStyle(oldStyle); + } }); + }}, arguments[1] || { })); +}; + +Effect.Morph = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + style: { } + }, arguments[1] || { }); + + if (!Object.isString(options.style)) this.style = $H(options.style); + else { + if (options.style.include(':')) + this.style = options.style.parseStyle(); + else { + this.element.addClassName(options.style); + this.style = $H(this.element.getStyles()); + this.element.removeClassName(options.style); + var css = this.element.getStyles(); + this.style = this.style.reject(function(style) { + return style.value == css[style.key]; + }); + options.afterFinishInternal = function(effect) { + effect.element.addClassName(effect.options.style); + effect.transforms.each(function(transform) { + effect.element.style[transform.style] = ''; + }); + }; + } + } + this.start(options); + }, + + setup: function(){ + function parseColor(color){ + if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; + color = color.parseColor(); + return $R(0,2).map(function(i){ + return parseInt( color.slice(i*2+1,i*2+3), 16 ) + }); + } + this.transforms = this.style.map(function(pair){ + var property = pair[0], value = pair[1], unit = null; + + if (value.parseColor('#zzzzzz') != '#zzzzzz') { + value = value.parseColor(); + unit = 'color'; + } else if (property == 'opacity') { + value = parseFloat(value); + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + } else if (Element.CSS_LENGTH.test(value)) { + var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); + value = parseFloat(components[1]); + unit = (components.length == 3) ? components[2] : null; + } + + var originalValue = this.element.getStyle(property); + return { + style: property.camelize(), + originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), + targetValue: unit=='color' ? parseColor(value) : value, + unit: unit + }; + }.bind(this)).reject(function(transform){ + return ( + (transform.originalValue == transform.targetValue) || + ( + transform.unit != 'color' && + (isNaN(transform.originalValue) || isNaN(transform.targetValue)) + ) + ) + }); + }, + update: function(position) { + var style = { }, transform, i = this.transforms.length; + while(i--) + style[(transform = this.transforms[i]).style] = + transform.unit=='color' ? '#'+ + (Math.round(transform.originalValue[0]+ + (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() + + (Math.round(transform.originalValue[1]+ + (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() + + (Math.round(transform.originalValue[2]+ + (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() : + (transform.originalValue + + (transform.targetValue - transform.originalValue) * position).toFixed(3) + + (transform.unit === null ? '' : transform.unit); + this.element.setStyle(style, true); + } +}); + +Effect.Transform = Class.create({ + initialize: function(tracks){ + this.tracks = []; + this.options = arguments[1] || { }; + this.addTracks(tracks); + }, + addTracks: function(tracks){ + tracks.each(function(track){ + track = $H(track); + var data = track.values().first(); + this.tracks.push($H({ + ids: track.keys().first(), + effect: Effect.Morph, + options: { style: data } + })); + }.bind(this)); + return this; + }, + play: function(){ + return new Effect.Parallel( + this.tracks.map(function(track){ + var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options'); + var elements = [$(ids) || $$(ids)].flatten(); + return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) }); + }).flatten(), + this.options + ); + } +}); + +Element.CSS_PROPERTIES = $w( + 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + + 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + + 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + + 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + + 'fontSize fontWeight height left letterSpacing lineHeight ' + + 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ + 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + + 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + + 'right textIndent top width wordSpacing zIndex'); + +Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; + +String.__parseStyleElement = document.createElement('div'); +String.prototype.parseStyle = function(){ + var style, styleRules = $H(); + if (Prototype.Browser.WebKit) + style = new Element('div',{style:this}).style; + else { + String.__parseStyleElement.innerHTML = '<div style="' + this + '"></div>'; + style = String.__parseStyleElement.childNodes[0].style; + } + + Element.CSS_PROPERTIES.each(function(property){ + if (style[property]) styleRules.set(property, style[property]); + }); + + if (Prototype.Browser.IE && this.include('opacity')) + styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]); + + return styleRules; +}; + +if (document.defaultView && document.defaultView.getComputedStyle) { + Element.getStyles = function(element) { + var css = document.defaultView.getComputedStyle($(element), null); + return Element.CSS_PROPERTIES.inject({ }, function(styles, property) { + styles[property] = css[property]; + return styles; + }); + }; +} else { + Element.getStyles = function(element) { + element = $(element); + var css = element.currentStyle, styles; + styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) { + results[property] = css[property]; + return results; + }); + if (!styles.opacity) styles.opacity = element.getOpacity(); + return styles; + }; +} + +Effect.Methods = { + morph: function(element, style) { + element = $(element); + new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { })); + return element; + }, + visualEffect: function(element, effect, options) { + element = $(element); + var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1); + new Effect[klass](element, options); + return element; + }, + highlight: function(element, options) { + element = $(element); + new Effect.Highlight(element, options); + return element; + } +}; + +$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+ + 'pulsate shake puff squish switchOff dropOut').each( + function(effect) { + Effect.Methods[effect] = function(element, options){ + element = $(element); + Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options); + return element; + } + } +); + +$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each( + function(f) { Effect.Methods[f] = Element[f]; } +); + +Element.addMethods(Effect.Methods); Index: openacs-4/packages/messages/www/resources/folder-new.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/folder-new.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/folder-new.js 31 Aug 2010 21:30:46 -0000 1.1 @@ -0,0 +1,46 @@ + YAHOO.namespace("new_folder.container"); + YAHOO.util.Event.onDOMReady(function () { + // Define various event handlers for Dialog + var handleSubmit = function() { + this.submit(); + }; + var handleCancel = function() { + this.cancel(); + }; + var handleSuccess = function(o) { + var response = o.responseText; + response = response.split("<!")[0]; + var response_error = response.substring(0,5); + if ( response_error == 'error' ) { + alert(response.substring(5,response.length)); + } else { + //alert(response); + //document.getElementById("resp").innerHTML = response; + window.location.reload(); + } + }; + var handleFailure = function(o) { + alert("Submission failed: " + o.status); + }; + // Remove progressively enhanced content class, just before creating the module + YAHOO.util.Dom.removeClass("dialog1", "yui-pe-content"); + // Instantiate the Dialog + YAHOO.new_folder.container.dialog1 = new YAHOO.widget.Dialog("dialog1", + { modal: true, + visible: false, + fixedcenter: true, + constraintoviewport: true, + iframe: true, + close: false, + width: "300px", + buttons : [ { text:document.getElementById('msg_create').value, handler:handleSubmit, isDefault:true }, + { text:document.getElementById('cancel').value, handler:handleCancel } ] + }); + // Validate the entries in the form to require that both first and last name are entered + // Wire up the success and failure handlers + YAHOO.new_folder.container.dialog1.callback = { success: handleSuccess, + failure: handleFailure }; + // Render the Dialog + YAHOO.new_folder.container.dialog1.render("container"); + YAHOO.util.Event.addListener("show", "click", YAHOO.new_folder.container.dialog1.show, null, YAHOO.new_folder.container.dialog1); + }); Index: openacs-4/packages/messages/www/resources/folder.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/folder.png,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/forward.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/forward.png,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/icono_imprimir.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/icono_imprimir.png,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/mail.jpg =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/mail.jpg,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/menu.css =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/menu.css,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/menu.css 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,87 @@ +div.menuBar, +div.menuBar a.menuButton, +div.menu, +div.menu a.menuItem { + font-family: "MS Sans Serif", Arial, sans-serif; + font-size: 10pt; + font-style: normal; + font-weight: normal; + font-align: left; + color: #000000; +} + +div.menuBar { + background-color: #d0d0d0; + border: 2px solid; + border-color: #f0f0f0 #909090 #909090 #f0f0f0; + padding: 4px 2px 4px 2px; + text-align: left; +} + +div.menuBar a.menuButton { + background-color: transparent; + border: 1px solid #d0d0d0; + color: #000000; + cursor: default; + left: 0px; + margin: 1px; + padding: 2px 6px 2px 6px; + position: relative; + text-decoration: none; + top: 0px; + z-index: 100; +} + +div.menuBar a.menuButton:hover { + background-color: transparent; + border-color: #f0f0f0 #909090 #909090 #f0f0f0; + color: #000000; +} + +div.menuBar a.menuButtonActive, +div.menuBar a.menuButtonActive:hover { + background-color: #a0a0a0; + border-color: #909090 #f0f0f0 #f0f0f0 #909090; + color: #ffffff; + left: 1px; + top: 1px; +} + +div.menu { + background-color: #d0d0d0; + border: 2px solid; + border-color: #f0f0f0 #909090 #909090 #f0f0f0; + left: 0px; + padding: 0px 1px 1px 0px; + position: absolute; + top: 0px; + visibility: hidden; + z-index: 101; +} + +div.menu a.menuItem { + color: #000000; + cursor: default; + display: block; + padding: 3px 5px; + text-decoration: none; + white-space: nowrap; +} + +div.menu a.menuItem:hover, div.menu a.menuItemHighlight { + background-color: #000080; + color: #ffffff; +} + +div.menu a.menuItem span.menuItemText {} + +div.menu a.menuItem span.menuItemArrow { + margin-right: -.75em; +} + +div.menu div.menuItemSep { + border-top: 1px solid #909090; + border-bottom: 1px solid #f0f0f0; + margin: 4px 2px; +} + Index: openacs-4/packages/messages/www/resources/menu.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/menu.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/menu.js 31 Aug 2010 21:30:50 -0000 1.1 @@ -0,0 +1,311 @@ +function Browser() { + var ua, s, i; + this.isIE = false; + this.isNS = false; + this.version = null; + + ua = navigator.userAgent; + + s = "MSIE"; + if ((i = ua.indexOf(s)) >= 0) { + this.isIE = true; + this.version = parseFloat(ua.substr(i + s.length)); + return; + } + + s = "Netscape6/"; + if ((i = ua.indexOf(s)) >= 0) { + this.isNS = true; + this.version = parseFloat(ua.substr(i + s.length)); + return; + } + + // Treat any other "Gecko" browser as NS 6.1. + + s = "Gecko"; + if ((i = ua.indexOf(s)) >= 0) { + this.isNS = true; + this.version = 6.1; + return; + } +} + +var browser = new Browser(); + +//---------------------------------------------------------------------------- +// Code for handling the menu bar and active button. +//---------------------------------------------------------------------------- + +var activeButton = null; + +// Capture mouse clicks on the page so any active button can be +// deactivated. + +if (browser.isIE) + document.onmousedown = pageMousedown; +else + document.addEventListener("mousedown", pageMousedown, true); + +function pageMousedown(event) { + var el; + if (activeButton == null) + return; + + if (browser.isIE) + el = window.event.srcElement; + else + el = (event.target.tagName ? event.target : event.target.parentNode); + + if (el == activeButton) + return; + + if (getContainerWith(el, "DIV", "menu") == null) { + resetButton(activeButton); + activeButton = null; + } +} + +function buttonClick(event, menuId) { + var button; + + if (browser.isIE) + button = window.event.srcElement; + else + button = event.currentTarget; + + button.blur(); + + if (button.menu == null) { + button.menu = document.getElementById(menuId); + menuInit(button.menu); + } + + if (activeButton != null) + resetButton(activeButton); + + if (button != activeButton) { + depressButton(button); + activeButton = button; + } + else + activeButton = null; + + return false; +} + +function buttonMouseover(event, menuId) { + var button; + + if (browser.isIE) + button = window.event.srcElement; + else + button = event.currentTarget; + + if (activeButton != null && activeButton != button) + buttonClick(event, menuId); +} + +function depressButton(button) { + var x, y; + + button.className += " menuButtonActive"; + + x = getPageOffsetLeft(button); + y = getPageOffsetTop(button) + button.offsetHeight; + + if (browser.isIE) { + x += button.offsetParent.clientLeft; + y += button.offsetParent.clientTop; + } + + button.menu.style.left = x + "px"; + button.menu.style.top = y + "px"; + button.menu.style.visibility = "visible"; +} + +function resetButton(button) { + removeClassName(button, "menuButtonActive"); + + if (button.menu != null) { + closeSubMenu(button.menu); + button.menu.style.visibility = "hidden"; + } +} + + +function menuMouseover(event) { + var menu; + if (browser.isIE) + menu = getContainerWith(window.event.srcElement, "DIV", "menu"); + else + menu = event.currentTarget; + + if (menu.activeItem != null) + closeSubMenu(menu); +} + +function menuItemMouseover(event, menuId) { + var item, menu, x, y; + if (browser.isIE) + item = getContainerWith(window.event.srcElement, "A", "menuItem"); + else + item = event.currentTarget; + menu = getContainerWith(item, "DIV", "menu"); + + if (menu.activeItem != null) + closeSubMenu(menu); + menu.activeItem = item; + + item.className += " menuItemHighlight"; + + if (item.subMenu == null) { + item.subMenu = document.getElementById(menuId); + menuInit(item.subMenu); + } + + x = getPageOffsetLeft(item) + item.offsetWidth; + y = getPageOffsetTop(item); + + var maxX, maxY; + + if (browser.isNS) { + maxX = window.scrollX + window.innerWidth; + maxY = window.scrollY + window.innerHeight; + } + if (browser.isIE && browser.version < 6) { + maxX = document.body.scrollLeft + document.body.clientWidth; + maxY = document.body.scrollTop + document.body.clientHeight; + } + if (browser.isIE && browser.version >= 6) { + maxX = document.documentElement.scrollLeft + document.documentElement.clientWidth; + maxY = document.documentElement.scrollTop + document.documentElement.clientHeight; + } + maxX -= item.subMenu.offsetWidth; + maxY -= item.subMenu.offsetHeight; + + if (x > maxX) + x = Math.max(0, x - item.offsetWidth - item.subMenu.offsetWidth + + (menu.offsetWidth - item.offsetWidth)); + y = Math.max(0, Math.min(y, maxY)); + + item.subMenu.style.left = x + "px"; + item.subMenu.style.top = y + "px"; + item.subMenu.style.visibility = "visible"; + + if (browser.isIE) + window.event.cancelBubble = true; + else + event.stopPropagation(); +} + +function closeSubMenu(menu) { + if (menu == null || menu.activeItem == null) + return; + + if (menu.activeItem.subMenu != null) { + closeSubMenu(menu.activeItem.subMenu); + menu.activeItem.subMenu.style.visibility = "hidden"; + menu.activeItem.subMenu = null; + } + removeClassName(menu.activeItem, "menuItemHighlight"); + menu.activeItem = null; +} + +function menuInit(menu) { + var itemList, spanList + var textEl, arrowEl; + var itemWidth; + var w, dw; + var i, j; + + if (browser.isIE) { + menu.style.lineHeight = "2.5ex"; + spanList = menu.getElementsByTagName("SPAN"); + for (i = 0; i < spanList.length; i++) + if (hasClassName(spanList[i], "menuItemArrow")) { + spanList[i].style.fontFamily = "Webdings"; + spanList[i].firstChild.nodeValue = "4"; + } + } + + itemList = menu.getElementsByTagName("A"); + if (itemList.length > 0) + itemWidth = itemList[0].offsetWidth; + else + return; + + for (i = 0; i < itemList.length; i++) { + spanList = itemList[i].getElementsByTagName("SPAN") + textEl = null + arrowEl = null; + for (j = 0; j < spanList.length; j++) { + if (hasClassName(spanList[j], "menuItemText")) + textEl = spanList[j]; + if (hasClassName(spanList[j], "menuItemArrow")) + arrowEl = spanList[j]; + } + if (textEl != null && arrowEl != null) + textEl.style.paddingRight = (itemWidth + - (textEl.offsetWidth + arrowEl.offsetWidth)) + "px"; + } + + if (browser.isIE) { + w = itemList[0].offsetWidth; + itemList[0].style.width = w + "px"; + dw = itemList[0].offsetWidth - w; + w -= dw; + itemList[0].style.width = w + "px"; + } +} + +function getContainerWith(node, tagName, className) { + while (node != null) { + if (node.tagName != null && node.tagName == tagName && + hasClassName(node, className)) + return node; + node = node.parentNode; + } + + return node; +} + +function hasClassName(el, name) { + var i, list; + list = el.className.split(" "); + for (i = 0; i < list.length; i++) + if (list[i] == name) + return true; + + return false; +} + +function removeClassName(el, name) { + var i, curList, newList; + if (el.className == null) + return; + newList = new Array(); + curList = el.className.split(" "); + for (i = 0; i < curList.length; i++) + if (curList[i] != name) + newList.push(curList[i]); + el.className = newList.join(" "); +} + +function getPageOffsetLeft(el) { + var x; + x = el.offsetLeft; + if (el.offsetParent != null) + x += getPageOffsetLeft(el.offsetParent); + + return x; +} + +function getPageOffsetTop(el) { + var y; + y = el.offsetTop; + if (el.offsetParent != null) + y += getPageOffsetTop(el.offsetParent); + + return y; +} + Index: openacs-4/packages/messages/www/resources/message-attachment.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/message-attachment.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/message-attachment.js 31 Aug 2010 21:30:53 -0000 1.1 @@ -0,0 +1,51 @@ +var number = 0; + +tag= function (tag) { + return document.createElement(tag); +} + +tag_id = function (id) { + return document.getElementById(id); +} + +even = function (evt) { + return (!evt) ? event : evt; +} + +evt_src = function (evt) { + return evt.srcElement ? evt.srcElement : evt.target; +} + +addField = function () { + var container = document.getElementById('files'); + span = tag('SPAN'); + span.className = 'file'; + span.id = 'upload_file_' + (++number); + + field = tag('input'); + field.name = 'upload_file_'+ number ; + field.id = 'upload_file_' + number ; + field.type = 'file'; + + attachment = tag('A'); + attachment.name = span.id; + attachment.onclick = function(){ removeField(this.name) }; + attachment.innerHTML = " " + document.getElementById('attachment_delete').value; + + img = tag('IMG'); + img.src ="/resources/messages/Delete16-on.gif"; + + new_line = tag('br'); + + span.appendChild(field); + attachment.appendChild(img); + span.appendChild(attachment); + span.appendChild(new_line); + container.appendChild(span); +} + +removeField = function (evt) { + lnk = evt_src(even(evt)); + span = document.getElementById(evt); + span.parentNode.removeChild(span); +} \ No newline at end of file Index: openacs-4/packages/messages/www/resources/message-dialog-roles.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/message-dialog-roles.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/message-dialog-roles.js 31 Aug 2010 21:30:48 -0000 1.1 @@ -0,0 +1,82 @@ +YAHOO.namespace("example.container"); + +YAHOO.util.Event.onDOMReady(function () { + + // Define various event handlers for Dialog + var handleSubmit = function() { + var formObject = document.getElementsByName('members_list'); + var form = formObject[0]; + var elements = form.elements; + var member_ids = ""; + var count = 0; + for ( var i = 0; i < elements.length ; i++) { + if (elements[i].checked && elements[i].name != '_dummy') { + count = count + 2; + member_ids = member_ids + elements[i].value + "," + elements[i+1].value + ","; + } + } + var total_members = document.getElementById('total_rel_members').value; + member_ids = member_ids.substring(0,member_ids.length-1); + member_ids = member_ids.split(','); + var recipients = ""; + var recipients_exists = document.getElementsByName('ids[]'); + var recipients_exists_ids = ""; + for ( var i = 0; i < document.getElementsByName('ids[]').length; i++) { + recipients_exists_ids = recipients_exists_ids + document.getElementsByName('ids[]')[i].value + ","; + } + for ( var i = 0; i < count; i = i + 2 ) { + var party_id = member_ids[i]; + var party_name = member_ids[i+1]; + if (recipients_exists_ids.match(party_id) == null) { + recipients = recipients + "<span id=span_" + party_id + " class=\"token\"><span><span><span><span><input type=\"hidden\" value=" + party_id + " name=\"ids[]\"/>" + party_name + "<span class=\"x\" onclick=id_delete(" + party_id + ")> </span></span></span></span></span></span>"; + } + } + var recipients_old = document.getElementById('contact_reply').innerHTML; + document.getElementById('contact_reply').innerHTML = recipients_old + recipients; + this.cancel(); + }; + var handleCancel = function() { + this.cancel(); + }; + var handleSuccess = function(o) { + var response = o.responseText; + response = response.split("<!")[0]; + document.getElementById("resp").innerHTML = response; + }; + var handleFailure = function(o) { + alert("Submission failed: " + o.status); + }; + + // Remove progressively enhanced content class, just before creating the module + YAHOO.util.Dom.removeClass("dialog1", "yui-pe-content"); + + // Instantiate the Dialog + YAHOO.example.container.dialog1 = new YAHOO.widget.Dialog("dialog1", + { width : "30em", + fixedcenter : true, + visible : false, + constraintoviewport : true, + modal: true, + buttons : [ { text:document.getElementById('add').value, handler:handleSubmit, isDefault:true }, + { text:"Cancel", handler:handleCancel } ] + }); + + // Validate the entries in the form to require that both first and last name are entered + YAHOO.example.container.dialog1.validate = function() { + var data = this.getData(); + if (data.firstname == "" || data.lastname == "") { + alert("Please enter your first and last names."); + return false; + } else { + return true; + } + }; + + // Wire up the success and failure handlers + YAHOO.example.container.dialog1.callback = { success: handleSuccess, + failure: handleFailure }; + + // Render the Dialog + YAHOO.example.container.dialog1.render(); + +}); Index: openacs-4/packages/messages/www/resources/message-option.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/message-option.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/message-option.js 31 Aug 2010 21:30:46 -0000 1.1 @@ -0,0 +1,83 @@ +var browser = navigator.appName; + +function convert_input(folder_id) { + if (document.getElementById('active').value == 'f') { + var msg_cancel = document.getElementById('cancel').value; + var msg_save = document.getElementById('save_info').value; + var name = document.getElementById('folder_' + folder_id).innerHTML; + document.getElementById('folder_' + folder_id).innerHTML = "<input id=input_folder_" + folder_id + " value=\"" + name + "\"><a class=button name=send_button value=Send type=button href=\"#\" onclick=\"update_folder(" + folder_id + ",'save');\" > " + msg_save + "</a> <a class=button name=cancel_button value=Cancel type=button href=\"#\" onclick=\"update_folder(" + folder_id + ",'cancel');\" > " + msg_cancel + "</a>"; + document.getElementById('active').value = 't'; + document.getElementById('name_cancel').value = document.getElementById('input_folder_' + folder_id).value; + } +} + +function cancel_folder(folder_id) { + if (document.getElementById('delete_p').value == 't') { + document.getElementById('span_folder_' + folder_id).innerHTML = ''; + document.getElementById('span_folder_delete_' + folder_id).innerHTML = ''; + document.getElementById('delete_p').value == 'f'; + } else { + if (document.getElementById('cancel_p').value == 't') { + document.getElementById('folder_' + folder_id).innerHTML = document.getElementById('name_cancel').value; + } else { + if (document.getElementById('input_folder_' + folder_id) != null) { + var name = document.getElementById('input_folder_' + folder_id).value; + document.getElementById('folder_' + folder_id).innerHTML = ''; + document.getElementById('active').value = 'f'; + document.getElementById('folder_' + folder_id).innerHTML = name; + } + } + } +} + +function update_folder (folder_id,option) { + var url = "update-name" + if (option == 'save' ) { + document.getElementById('delete_p').value = 'f'; + document.getElementById('cancel_p').value == 'f'; + var postData = "name=" + document.getElementById('input_folder_' + folder_id).value + "&folder_id=" + folder_id; + } else if (option == 'cancel') { + document.getElementById('delete_p').value = 'f'; + document.getElementById('cancel_p').value = 't'; + var postData = "folder_id=" + folder_id; + } else if (option == 'delete') { + var continue_send = confirm(document.getElementById("msg_delete_folder").value); + if (!continue_send ) { + self.close + } else { + document.getElementById('delete_p').value = 't'; + var postData = "delete=t&folder_id=" + folder_id; + } + } + var request = YAHOO.util.Connect.asyncRequest('POST', url, callback, postData); +} + +var handleSuccess = function(o){ + cancel_folder(o.responseText); +}; + +var handleFailure= function(o){ +}; + +var callback = {success:handleSuccess,failure:handleFailure}; + +function delete_folder(){ + dialog1.show(); +} + +var handleYes1 = function() { + dialog1.hide(); +} +var handleNo1 = function() { dialog1.hide(); return false; } + +var dialog1 = new YAHOO.widget.Dialog("confirm_dialog1", + { width: "450px", + fixedcenter: true, + visible: true, + draggable: false, + close: false, + modal: true, + buttons: [ { text:'Confirm', handler:handleYes1 }, + { text:'Cancel', handler:handleNo1 } ] + } ); +dialog1.render(); Index: openacs-4/packages/messages/www/resources/messages.css =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/messages.css,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/messages.css 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1,13 @@ +div.menuBar { + background-color: #C0C0C0; + border-color: #F0F0F0 #909090 #909090 #F0F0F0; +} +div.menubar a.menuButton { + background-color: solid; + } + +div.menu { + background-color: #C0C0C0; + border-color: #F0F0F0 #909090 #909090 #F0F0F0; +} + Index: openacs-4/packages/messages/www/resources/messages.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/messages.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/messages.js 31 Aug 2010 21:30:50 -0000 1.1 @@ -0,0 +1,1262 @@ +//color azul #D4E4FF -- #C9D7F1 +var normal_color = '#C0C0C0'; +var select_color = '#F0F0F0'; +//hidden all messages action when the user make some action +function hidden_msg_actions () { + document.getElementById('msg_system').style.display = 'none'; + if (document.getElementById('message_action_p').value == 't' && document.getElementById('message_action') != null) { + document.getElementById('message_action').style.display = 'none'; + } + if (document.getElementById('msg_action_send_p').value == 't') { + var msg_id = document.getElementById('msg_id_new_send').value; + if (document.getElementById('msg_action_'+msg_id) != null ) { + document.getElementById('msg_action_'+msg_id).style.display = ''; + } + document.getElementById('msg_action_send_p').value = 'f'; + } + if (document.getElementById('msg_action_p').value == 'f') { + document.getElementById('msg_action').style.display = 'none'; + } +} + +//this function make a request and loading the messages in folder option +function get_messages_folder (option) { + document.getElementById('search_data').value = ""; + document.getElementById('search_button').disabled = true; + document.getElementById('option').value = option; + if (option == 'more_actions') { + var option = document.getElementById('folder_id').value; + } else { + hidden_msg_actions(); + loading(); + document.getElementById('inbox_select_p').value = 't'; + } + var folder_active_old = document.getElementById('folder_active').value; + document.getElementById('reply_dialog_active').value = 'f'; + if (document.getElementById('background_' + folder_active_old).style.background != null ) { + document.getElementById('background_' + folder_active_old).style.background = '#FFFFFF'; + } + if (document.getElementById('background_' + option) != null ) { + document.getElementById('background_' + option).style.background = normal_color; + } + document.getElementById('folder_active').value = option; + document.getElementById('delete_message').style.display = 'none'; + document.getElementById('select_msg').style.display = 'none'; + document.getElementById('top_menu').style.display = ''; + if (document.getElementById('page_number') != null && folder_active_old == option) { + var page_number = document.getElementById('page_number').value; + } else { + var page_number = 1; + } + var url = "inbox?folder_id="+option + "&page_number=" + page_number; + var request = YAHOO.util.Connect.asyncRequest('GET', url, callback_get_messages_folder); +} + + +var handleSuccess_get_messages_folder = function(o){ + window.location.hash = "#"; + if (document.getElementById('inbox_select_p') != null && document.getElementById('inbox_select_p').value == 't') { + document.getElementById('inbox_select_p').value = 'f'; + document.getElementById('msg_action').style.display = 'none'; + document.getElementById('msg_actions').innerHTML = ''; + } + document.getElementById('folder_section_display').innerHTML = o.responseText; + document.getElementById('return').style.display = 'none'; + document.getElementById('move_to').style.display = ''; + document.getElementById('more_actions_span').style.display = ''; + document.getElementById('delete_message_trash').style.display = 'none'; + if (document.getElementById('folder_id').value == 3) { + document.getElementById('delete').style.display = 'none'; + document.getElementById('delete_message_trash').style.display = ''; + } else if (document.getElementById('option').value == 1) { + document.getElementById('move_to').style.display = 'none'; + document.getElementById('delete').style.display = 'none'; + document.getElementById('delete_message_trash').style.display = 'none'; + } else { + document.getElementById('move_to').style.display = ''; + document.getElementById('more_actions_span').style.display = ''; + document.getElementById('delete').style.display = ''; + document.getElementById('delete_message_trash').style.display = 'none'; + } + if (document.getElementById('move_to_p').value == 't') { + move_to_action () + } + + if (document.getElementById('more_actions_p').value == 't') { + more_action_do () + } +}; + +var handleFailure_get_messages_folder= function(o){ }; + +var callback_get_messages_folder = {success:handleSuccess_get_messages_folder,failure:handleFailure_get_messages_folder}; + +function show_members_rol (id) { + if (id != 'dotlrn_student_rel' || id == 'rel_types_all') { + var url_rols = "members-rol"; + var postData = "rel_type=" + id + var request = YAHOO.util.Connect.asyncRequest('POST', url_rols, callback_rols,postData); + } +} + +var handleSuccess_rols = function(o) { + document.getElementById('info_members_rols').innerHTML = o.responseText; + YAHOO.roles.container_roles.dialog2.show(); +} + +var handleFailure_rols = function(o) { }; + +var callback_rols = {success:handleSuccess_rols,failure:handleFailure_rols}; + + + +function show_members_rol_index (id) { + if (id != 'dotlrn_student_rel' || id == 'rel_types_all') { + var url_rols = "members-rol"; + var postData = "rel_type=" + id + var request = YAHOO.util.Connect.asyncRequest('POST', url_rols, callback_rols_index,postData); + } +} + +var handleSuccess_rols_index = function(o) { + document.getElementById('rols_info_area').innerHTML = o.responseText; + YAHOO.example.container.rols_container.show(); +} + +var handleFailure_rols_index = function(o) { }; + +var callback_rols_index = {success:handleSuccess_rols_index,failure:handleFailure_rols_index}; + +function move_to_action () { + var count_msg_ids = document.getElementById('count_msg_ids').value; + if ( count_msg_ids != 0 ) { + document.getElementById('msg_action_p').value = 'f'; + document.getElementById('msg_action').style.display = ''; + } else { + document.getElementById('msg_action_p').value = 't'; + } + var folder_name = document.getElementById('folder_name').value; + if (count_msg_ids == 1) { + document.getElementById('msg_actions').innerHTML = document.getElementById('msg_moved_to').value + " \"" + folder_name + "\""; + } else { + document.getElementById('msg_actions').innerHTML = count_msg_ids + " "+ document.getElementById('more_msg_moved_to').value + " \"" + folder_name + "\""; + } + document.getElementById('move_to_p').value = 'f'; + document.getElementById('more_actions_p').value = 'f'; +} + +function more_action_do () { + var ids_length = document.getElementById('ids_length').value; + if (document.getElementById('more_actions_option').value == "t") { + if (ids_length == 1) { + var msg_action = document.getElementById('msg_read').value; + } else { + var msg_action = ids_length + " " + document.getElementById('more_msg_read').value; + } + } else { + if (ids_length == 1) { + var msg_action = document.getElementById('msg_unread').value; + } else { + var msg_action = ids_length + " " + document.getElementById('more_msg_unread').value; + } + } + document.getElementById('msg_actions').innerHTML = msg_action; + document.getElementById('more_actions_p').value = 'f'; +} + +//show loading image up the message send. +function showLoading(container) { + if (container == 'send_mail') { + var text_action = document.getElementById('sending').value; + } + document.getElementById(container+"_loading").style.display = ''; + document.getElementById(container+"_wait").innerHTML = text_action + " <image src=/resources/ajaxhelper/images/indicator.gif>"; +} + +//this function make de submit form when send massage +function submit_normal() { + var alert_p = 0 + var formObject = document.getElementsByName('compose_message'); + var form = formObject[0]; + var elements = form.elements; + var rel_types_checked_p = 0; + for ( var i = 0; i < elements.length ; i++) { + if (elements[i].name == 'rel_types' && elements[i].checked) { + rel_types_checked_p = 1; + break; + } + } + if (document.getElementsByName('ids[]').length == 0 && rel_types_checked_p == 0) { + var continue_send = false; + var msg_empty = document.getElementById("recipients_empty").value; + alert(msg_empty); + alert_p = 1; + var continue_send = false; + } else { + var subject = document.getElementById('subject_field').value; + if (subject.trim() == "") { + var alert_p = 1; + var continue_send = confirm(document.getElementById("subject_empty").value); + } else { + var continue_send = true; + var alert_p = 0; + } + if (alert_p == 0) { + var editor = Xinha.getEditor("message"); + var message = editor.getEditorContent(); + if (message.length == 0) { + var continue_send = confirm(document.getElementById("body_empty").value); + } else { + var continue_send = true; + } + } + } + if (!continue_send ) { + self.close + } else { + showLoading('send_mail'); + var contact_length = document.getElementsByName('ids[]').length; + var contact_ids = ""; + for (i=0; i< contact_length; i++) { + if ((i+1) == contact_length) { + contact_ids = contact_ids + document.getElementsByName('ids[]')[i].value; + } else { + contact_ids = contact_ids + document.getElementsByName('ids[]')[i].value + ","; + } + } + document.getElementById('total_attachment').value = number; + document.getElementById('contacts_ids').value = contact_ids; + document.getElementById('subject').value = subject; + document.compose_message.submit(); + } +} + +var handleSuccess_send = function(o){ + window.location = "messages"; +}; + +var handleUpload_send = function(o){ + window.location = "messages"; +} + +var handleFailure_send= function(o){ +}; + +var callback_send={success:handleSuccess_send,failure:handleFailure_send,upload:handleUpload_send}; +//finish submit function, send message normal + + +function show_div(divName) { + document.getElementById(divName).style.display = ''; +} + +//this function make the move option +function move_to(option) { + document.getElementById('msg_system').style.display = 'none'; + document.getElementById('option_move_to').value = option; + document.getElementById('fileMenu').style.display = 'none'; + if (document.getElementById('message_action') != null) { + document.getElementById('message_action').innerHTML = ''; + document.getElementById('message_action').style.display = ''; + } + var formObject = document.getElementsByName('messages_list'); + var form = formObject[0]; + var elements = form.elements; + var break_p = 0; + for ( var i = 0; i < elements.length ; i++){ + if (elements[i].name == 'subject_id' && elements[i].checked) { + break_p = 1; + break; + } + } + if (!break_p) { + document.getElementById('msg_action_p').value = 'f'; + document.getElementById('msg_action').style.display = ''; + document.getElementById('msg_actions').innerHTML = document.getElementById('msg_select_msg').value; + var folder_id_state = document.getElementById('folder_id').value; + if (document.getElementById('folder_id_state') != null ) { + var folder_id_state = document.getElementById('folder_id_state').value; + } + } else { + var msg_ids = ""; + var count_msg_ids = 0; + for ( var i = 0; i < elements.length ; i++) { + if ( elements[i].name == 'subject_id' && elements[i].checked ) { + msg_ids = msg_ids + elements[i].value + ","; + count_msg_ids = count_msg_ids + 1; + } + } + msg_ids = msg_ids.substring(0,msg_ids.length-1); + document.getElementById('count_msg_ids').value = count_msg_ids; + document.getElementById('folder_name').value = document.getElementById(option).innerHTML; + loading(); + var url_move = "move-to?msg_ids=" + msg_ids + "&folder_id=" + option; + var request = YAHOO.util.Connect.asyncRequest('GET', url_move, callback_move_to); + } +} + +var handleSuccess_move_to = function(o) { + var owner_id = document.getElementById('owner_id').value; + var folder_id_state = document.getElementById('folder_id').value; + update_numbers(); + document.getElementById('move_to_p').value = 't'; + document.getElementById('checkbox_general').checked = false; + if (document.getElementById('search_data').value == "") { + get_messages_folder('more_actions'); + } else { + var page_number = document.getElementById('page_number').value; + search(page_number) + } +}; + +var handleFailure_move_to = function(o){ +}; + +var callback_move_to={success:handleSuccess_move_to,failure:handleFailure_move_to}; + + +function update_numbers() { + var formObject = document.getElementsByName('messages'); + var url_update_numbers = "update-numbers"; + var request = YAHOO.util.Connect.asyncRequest('GET', url_update_numbers, callback_update_numbers); +} + +var handleSuccess_update_numbers = function(o){ + var response = o.responseText.split(','); + var get_messages_folder_p = 0; + if (document.getElementById('folder_id') != null) { + var active_folder = document.getElementById('folder_id').value; + } else { + var active_folder = 0; + } + if (o.responseText != "" ) { + for (var i=0; i < response.length; i= i+3) { + if ( response[i+1] == active_folder) { + get_messages_folder_p = 1 + } + if (response[i] != "" && document.getElementById('new_msg_folder_'+response[i+1]) != null) { + document.getElementById('new_msg_folder_'+response[i+1]).value = response[i]; + //if (document.getElementById('new_msg_folder_'+response[i+1]).value > 0 ) { + if ( response[i] > 0 ) { + document.getElementById('number_'+response[i+1]).innerHTML = "(<strong>" + response[i] + "</strong>/" + response[i+2] + ")"; + } else { + document.getElementById('number_'+response[i+1]).innerHTML = "(" + response[i] + "/" + response[i+2] + ")"; + } + //} else { + //document.getElementById('number_'+response[i+1]).innerHTML = ""; + //} + } + } + } + if (get_messages_folder_p == 0 ) { + if (document.getElementById('new_msg_folder_'+active_folder) != null) { + document.getElementById('new_msg_folder_'+active_folder).value = 0; + } + if (document.getElementById('number_'+active_folder) != null ) { + document.getElementById('number_'+active_folder).innerHTML = ""; + } + } +}; + +var handleFailure_update_numbers= function(o){ +}; + +var callback_update_numbers={success:handleSuccess_update_numbers,failure:handleFailure_update_numbers}; + + +function paginate(folder_id,page_number,option) { + document.getElementById('msg_action_p').value = 'f'; + hidden_msg_actions(); + loading(); + document.getElementById('inbox_select_p').value = 't'; + var formObject = document.getElementsByName('messages'); + if (option == 'newer') { + var page_number = page_number - 1; + } + if (option == 'older') { + var page_number = page_number + 1; + } + document.getElementById('page_number').value = page_number; + if (document.getElementById('search_data').value == "") { + var url_paginate = "inbox?folder_id=" + folder_id + "&page_number=" + page_number; + var request = YAHOO.util.Connect.asyncRequest('GET', url_paginate, callback_paginate); + } else { + search(page_number); + } +} + +var handleSuccess_paginate = function(o){ + if (document.getElementById('inbox_select_p') != null && document.getElementById('inbox_select_p').value == 't') { + document.getElementById('inbox_select_p').value = 'f'; + document.getElementById('msg_action').style.display = 'none'; + document.getElementById('msg_actions').innerHTML = ''; + } + document.getElementById('folder_section_display').innerHTML = o.responseText; +}; + +var handleFailure_paginate= function(o){ +}; + +var callback_paginate={success:handleSuccess_paginate,failure:handleFailure_paginate}; + +function read_message(msg_id,folder_id,page_number,action) { + if (YAHOO.env.ua.ie) { + scrollTo(0,document.getElementById('msg_action_'+msg_id).offsetTop); + } else { + if (document.getElementById('msg_action_'+msg_id) == null) { + document.getElementById('scroll_top').scrollTo(); + } else { + var msg_id_reply_action = document.getElementById('msg_id_action_reply').value; + document.getElementById('reply_'+msg_id_reply_action).scrollTo(); + } + } + if ( document.getElementById('number_messages') != null) { + var total_messages = document.getElementById('number_messages').value; + document.getElementById('total_messages').value = document.getElementById('number_messages').value; + } else { + var total_messages = document.getElementById('total_messages').value; + } + document.getElementById('more_actions_span').style.display = 'none'; + document.getElementById('msg_action_p').value = 'f'; + hidden_msg_actions(); + document.getElementById('delete_message').style.display = 'none'; + loading(); + document.getElementById('inbox_select_p').value = 't'; + document.getElementById('return').style.display = ''; + document.getElementById('delete').style.display = 'none'; + document.getElementById('move_to').style.display = 'none'; + if (action == "new_msg") { + document.getElementById('msg_action_send_p').value = 't'; + } + var url = "read-message"; + var postData = "msg_id="+msg_id+"&folder_id="+folder_id+"&page_number="+page_number+"&total_messages="+total_messages; + var request = YAHOO.util.Connect.asyncRequest('POST', url, callback_read_message,postData); +} + + +var handleSuccess_read_message = function(o){ + if (o.responseText.trim() == "false") { + alert(document.getElementById('not_permission_read').value); + get_messages_folder(0); + } else { + if (document.getElementById('msg_action_'+msg_id) != null) { + document.getElementById('msg_action_'+msg_id).style.display = 'none'; + } + if (document.getElementById('inbox_select_p') != null && document.getElementById('inbox_select_p').value == 't') { + document.getElementById('inbox_select_p').value = 'f'; + document.getElementById('msg_action').style.display = 'none'; + document.getElementById('msg_actions').innerHTML = ''; + } + document.getElementById('folder_section_display').innerHTML = o.responseText; + if (document.getElementById('option_reply').value == 'forward') { + document.getElementById('msg_action_send_p').value = 't'; + var msg_id = document.getElementById('msg_id_reply').value; + document.getElementById('option_reply').value = ''; + } else { + var msg_id = document.getElementById('msg_id_new_send').value; + } + if (document.getElementById('msg_action_send_p').value == 't') { + if (document.getElementById('msg_action_'+msg_id) != null) { + document.getElementById('msg_action_'+msg_id).style.display = ''; + document.getElementById('msg_action_id').value = msg_id; + if (YAHOO.env.ua.ie) { + scrollTo(0,document.getElementById('msg_action_'+msg_id).offsetTop); + } else { + document.getElementById('msg_action_'+msg_id).scrollTo(); + } + } + } + if (document.getElementById('older_msg_id').value == '-1') { + document.getElementById('msg_older').style.display = 'none'; + } else { + document.getElementById('msg_older').style.display = ''; + } + if (document.getElementById('newer_msg_id').value == '-1') { + document.getElementById('msg_newer').style.display = 'none'; + } else { + document.getElementById('msg_newer').style.display = ''; + } + document.getElementById('select_msg').style.display = ''; + var owner_id = document.getElementById('owner_id').value; + var folder_id_state = document.getElementById('folder_id').value; + update_numbers(); + (new Image()).src='inbox/images/token.gif'; + (new Image()).src='inbox/images/token_selected.gif'; + (new Image()).src='inbox/images/token_hover.gif'; + (new Image()).src='inbox/images/token_x.gif'; + contact_users(); + } +}; + +var handleFailure_read_message = function(o){ +}; + +var callback_read_message = {success:handleSuccess_read_message,failure:handleFailure_read_message}; + + +function mostrardiv(msg_id) { + document.getElementById('contact_list_'+msg_id).style.display = 'none'; + document.getElementById('msg_action_p').value = 'f'; + hidden_msg_actions(); + if (msg_id == undefined) { + var msg_id = document.getElementById('msg_id_new_send').value; + } + if (document.getElementById('msg_action_'+msg_id) != null ) { + document.getElementById('msg_action_'+msg_id).style.display = 'none'; + } + document.getElementById('details_'+msg_id).style.display = ''; + document.getElementById('show_details_'+msg_id).style.display = 'none'; + document.getElementById('from_'+msg_id).style.display = ''; + document.getElementById('close_details_'+msg_id).style.display = ''; +} + +function close_dialog(msg_id) { + div = document.getElementById('details_'+msg_id); + div.style.display='none'; + div = document.getElementById('close_details_'+msg_id); + div.style.display='none'; + div = document.getElementById('show_details_'+msg_id); + div.style.display = ''; + document.getElementById('from_'+msg_id).style.display = 'none'; + document.getElementById('contact_list_'+msg_id).style.display = ''; +} + +function reply_message(option,msg_id) { + document.getElementById('msg_reply').value = msg_id; + if (option != "forward") { + var url = "contacts?msg_id="+msg_id+"&option=" + option; + var request = YAHOO.util.Connect.asyncRequest('GET', url, callback_reply); + } else if (option == "forward") { + document.getElementById('contact_reply').innerHTML = ''; + var url = "contacts?msg_id="+msg_id+"&option=" + option; + var request = YAHOO.util.Connect.asyncRequest('GET', url, callback_reply); + } +} + + +var handleSuccess_reply = function(o){ + var msg_id = document.getElementById('msg_reply').value; + var parent_id = document.getElementById('parent_id_reply').value; + if (o.responseText == "forward") { + html_xinha_editor('forward'); + document.getElementById('submit_reply').innerHTML = "<a class=button name=send_button value=Send type=button href=\"javascript:submit_reply(0,0)\" >"+document.getElementById('send_msg').value+"</a>"; + } else { + html_xinha_editor('reply'); + document.getElementById('contact_reply').innerHTML = o.responseText; + document.getElementById('submit_reply').innerHTML = "<a class=button name=send_button value=Send type=button href=\"javascript:submit_reply("+msg_id+","+parent_id+");\" > " + document.getElementById('send_msg').value + "</a>"; + } + initEditors(); +} + +var handleFailure_reply = function(o){ +}; + +var callback_reply = {success:handleSuccess_reply,failure:handleFailure_reply}; + +function return_msg(owner_id) { + document.getElementById('msg_action_p').value = 'f'; + hidden_msg_actions(); + var folder_id = document.getElementById('folder_id').value; + var page_number = document.getElementById('page_number').value; + div = document.getElementById('select_msg'); + div.style.display = 'none'; + if (document.getElementById('search_data').value == "") { + var url = "inbox?page_number="+page_number+"&folder_id=" + folder_id; + var request = YAHOO.util.Connect.asyncRequest('GET', url, callback_return_msg); + } else { + search(page_number); + } +} + +var handleSuccess_return_msg = function(o){ + var folder_id = document.getElementById('folder_id').value; + if (YAHOO.env.ua.ie) { + scrollTo(0,document.getElementById('scroll_top').offsetTop); + } else { + document.getElementById('scroll_top').scrollTo(); + } + get_messages_folder(folder_id); +} + +var handleFailure_return_msg = function(o){ +}; + +var callback_return_msg = {success:handleSuccess_return_msg,failure:handleFailure_return_msg}; + +function cancel(msg_id) { + var continue_cancel = confirm (document.getElementById('msg_cancel').value); + if ( continue_cancel ) { + document.getElementById('reply_dialog_active').value = 'f'; + if (YAHOO.env.ua.ie) { + scrollTo(0,document.getElementById('show_details_'+msg_id).offsetTop); + } else { + document.getElementById('show_details_'+msg_id).scrollTo(); + } + document.getElementById('response_reply_mail_' + msg_id).innerHTML = ''; + document.getElementById('reply_' + msg_id).style.background = normal_color; + if ( document.getElementById('reply_all_' + msg_id) != null) { + document.getElementById('reply_all_'+ msg_id).style.background = normal_color; + } + document.getElementById('forward_'+ msg_id).style.background = normal_color; + } else { + self.close; + } +} + +function submit_reply(msg,parent_id) { + document.getElementById('msg_action_p').value = 't'; + hidden_msg_actions(); + document.getElementById('msg_id_action_reply').value = msg; + var subject = document.getElementById('subject_field').value; + var msg_id = document.getElementById('msg_id').value; + var editor = Xinha.getEditor("message"); + var message = editor.getEditorContent(); + var contact_length = document.getElementsByName('ids[]').length; + var formObject = document.getElementsByName('compose_message'); + var form = formObject[0]; + var elements = form.elements; + var rel_types_checked_p = 0; + for ( var i = 0; i < elements.length ; i++) { + if (elements[i].name == 'rel_types' && elements[i].checked) { + rel_types_checked_p = 1; + break; + } + } + var alert_p = 0 + if (document.getElementsByName('ids[]').length == 0 && rel_types_checked_p == 0) { + var continue_send = false; + var msg_empty = document.getElementById("recipients_empty").value; + alert(msg_empty); + alert_p = 1; + var continue_send = false; + } else { + if (message.length == 0) { + var continue_send = false; + var continue_send = confirm(document.getElementById("body_empty").value); + } else { + var continue_send = true; + } + } + if (!continue_send ) { + self.close + } else { + showLoading('send_mail'); + document.getElementById('reply_dialog_active').value = 'f'; + var contact_ids = ""; + for (i=0; i< contact_length; i++) { + if ((i+1) == contact_length) { + contact_ids = contact_ids + document.getElementsByName('ids[]')[i].value; + } else { + contact_ids = contact_ids + document.getElementsByName('ids[]')[i].value + ","; + } + } + if (YAHOO.env.ua.ie) { + YAHOO.util.Connect.setForm(form,true,true); + } else { + YAHOO.util.Connect.setForm(form,true); + } + var elements = form.elements; + var attachment_ids = ""; + for ( var i = 0; i < elements.length ; i++) { + if ( elements[i].name == 'attachment_checkbox' && elements[i].checked ) { + attachment_ids = attachment_ids + elements[i].id + ","; + } + } + attachment_ids = attachment_ids.substring(0,attachment_ids.length-1); + var msg_id_old = document.getElementById('msg_id_reply').value; + var url_send_mail = "send-mail"; + var postData= "parent_id=" + msg_id + "&contacts_ids=" + contact_ids + "&total_attachment=" + number + "&subject=" + subject+"&reply=true&general_parent_id=" + parent_id + "&msg_id_old=" + msg_id_old + "&attachment_ids=" + attachment_ids; + var request = YAHOO.util.Connect.asyncRequest('POST', url_send_mail, callback_send_mail, postData); + } +} + +var handleSuccess_send_mail = function(o){ }; + +var handleUpload_send_mail = function(o){ + document.getElementById('msg_id_new_send').value = o.responseText; + if (document.getElementById('read') == null) { + window.location = "messages"; + } else { + document.getElementById('autocomplete_loding').innerHTML = "<div tabindex=\"-1\" id=ids class=\"clearfix tokenizer\" onclick=\"$('autocomplete_input').focus()\"> <span class=\"tokenizer_stretcher\">^_^</span> <span class=\"tab_stop\"><input type=\"text\" id=\"hidden_input\" tabindex=\"-1\"></span> <span id=contact_reply> </span> <div id=\"autocomplete_display\" class=\"tokenizer_input\"> <input type=\"text\" size=\"1\" tabindex=\"\" id=\"autocomplete_input\" /> </div> </div> <div id=\"autocomplete_populate\" class=\"clearfix autocomplete typeahead_list\" style=\"width: 358px; height: auto; overflow-y: hidden;display:none\"> <div class=\"typeahead_message\">Type the name of a member</div></div>" + var msg_id = document.getElementById('msg_id').value; + var folder_id = document.getElementById('folder_id').value; + var page_number = document.getElementById('page_number'); + read_message(msg_id,folder_id,page_number,'new_msg'); + } +}; + +var handleFailure_send_mail= function(o){ }; + +var callback_send_mail={success:handleSuccess_send_mail,failure:handleFailure_send_mail,upload:handleUpload_send_mail}; + +function select_message(option) { + document.getElementById('msg_action_p').value = 'f'; + hidden_msg_actions(); + var folder_id = document.getElementById('folder_id').value; + var page_number = document.getElementById('new_page_number').value; + var div = document.getElementById('return'); + div.style.display=''; + if (option == 'older') { + var older_msg_id = document.getElementById('older_msg_id').value; + var newer_msg_id = document.getElementById('msg_id').value; + var newest_msg_id = document.getElementById('newest_msg_id').value; + var oldest_msg_id = document.getElementById('oldest_msg_id').value; + var msg_id = older_msg_id; + if (oldest_msg_id == '-1') { + document.getElementById('msg_older').style.display = 'none'; + } else { + document.getElementById('msg_older').style.display = ''; + } + if (newer_msg_id == '-1') { + document.getElementById('msg_newer').style.display = 'none'; + } else { + document.getElementById('msg_newer').style.display = ''; + } + + } else if (option == 'newer') { + var older_msg_id = document.getElementById('msg_id').value; + var newer_msg_id = document.getElementById('newer_msg_id').value; + var newest_msg_id = document.getElementById('newest_msg_id').value; + var oldest_msg_id = document.getElementById('oldest_msg_id').value; + var msg_id = newer_msg_id; + if (newest_msg_id == '-1') { + document.getElementById('msg_newer').style.display = 'none'; + } else { + document.getElementById('msg_newer').style.display = ''; + } + if (older_msg_id == '-1') { + document.getElementById('msg_older').style.display = 'none'; + } else { + document.getElementById('msg_older').style.display = ''; + } + } + loading(); + var url = "read-message?msg_id="+msg_id+"&folder_id="+folder_id+"&page_number="+page_number; + var request = YAHOO.util.Connect.asyncRequest('GET', url, callback_select_message); +} + +var handleSuccess_select_message = function(o){ + document.getElementById('folder_section_display').innerHTML = o.responseText; + var owner_id = document.getElementById('owner_id').value; + var folder_id_state = document.getElementById('folder_id').value; + update_numbers(); + (new Image()).src='inbox/images/token.gif'; + (new Image()).src='inbox/images/token_selected.gif'; + (new Image()).src='inbox/images/token_hover.gif'; + (new Image()).src='inbox/images/token_x.gif'; + contact_users(); + loading_cancel(); +}; + +var handleFailure_select_message = function(o){ }; + +var callback_select_message = {success:handleSuccess_select_message,failure:handleFailure_select_message}; + +function more_actions_select(){ + document.getElementById('msg_action_p').value = 'f'; + hidden_msg_actions(); + var formObject = document.getElementsByName('messages_list'); + var form = formObject[0]; + var elements = form.elements; + var break_p = 0; + var new_p = 0; + for ( var i = 0; i < elements.length ; i++){ + if (elements[i].name == 'subject_id' && elements[i].checked) { + break_p = 1; + if (document.getElementById('new_p.'+elements[i].value) != null) { + new_p = 1; + break; + } + } + } + if (break_p) { + if (document.getElementById('more_actions_options') != null) { + document.getElementById('action_as_unread').style.display = ''; + } + } else { + if (document.getElementById('more_actions_options') != null) { + document.getElementById('more_actions_options').style.display = 'none'; + } + } +} + +function delete_select_msg () { + document.getElementById('msg_system').style.display = 'none'; + document.getElementById('more_actions').style.display = 'none'; + document.getElementById('msg_action_p').value = 'f'; + var formObject = document.getElementsByName('messages_list'); + var form = formObject[0]; + var elements = form.elements; + var msg_ids = ""; + var count_msg_ids_select = 0 + for ( var i = 0; i < elements.length ; i++) { + if ( elements[i].name == 'subject_id' && elements[i].checked ) { + msg_ids = msg_ids + elements[i].value + ","; + count_msg_ids_select = count_msg_ids_select + 1; + } + } + if (!count_msg_ids_select) { + document.getElementById('msg_action_p').value = 'f'; + document.getElementById('msg_action').style.display = ''; + document.getElementById('msg_actions').innerHTML = document.getElementById('msg_select_msg').value; + var folder_id_state = document.getElementById('folder_id').value; + if (document.getElementById('folder_id_state') != null ) { + var folder_id_state = document.getElementById('folder_id_state').value; + } + alert("debe de seleccionar al menos un mensaje para borrar"); + } else { + msg_ids = msg_ids.substring(0,msg_ids.length-1); + document.getElementById('ids_more_actions').value = msg_ids; + var url_delete_msg = "delete-message"; + var postData = "msg_ids=" + msg_ids; + document.getElementById('msg_action').style.display = ''; + loading(); + document.getElementById('ids_length').value = count_msg_ids_select; + var request = YAHOO.util.Connect.asyncRequest('POST', url_delete_msg, callback_delete_msg,postData); + } +} + +var handleSuccess_delete_msg = function(o){ + get_messages_folder(3); + update_numbers(); +}; + +var handleFailure_delete_msg = function(o){ +}; + +var callback_delete_msg={success:handleSuccess_delete_msg,failure:handleFailure_delete_msg}; + +function more_actions(option,folder_id,owner_id) { + document.getElementById('msg_system').style.display = 'none'; + document.getElementById('more_actions').style.display = 'none'; + document.getElementById('msg_action_p').value = 'f'; + var formObject = document.getElementsByName('messages_list'); + var form = formObject[0]; + var elements = form.elements; + var msg_ids = ""; + var count_msg_ids_select = 0 + for ( var i = 0; i < elements.length ; i++) { + if ( elements[i].name == 'subject_id' && elements[i].checked ) { + msg_ids = msg_ids + elements[i].value + ","; + count_msg_ids_select = count_msg_ids_select + 1; + } + } + if (!count_msg_ids_select) { + document.getElementById('msg_action_p').value = 'f'; + document.getElementById('msg_action').style.display = ''; + document.getElementById('msg_actions').innerHTML = document.getElementById('msg_select_msg').value; + var folder_id_state = document.getElementById('folder_id').value; + if (document.getElementById('folder_id_state') != null ) { + var folder_id_state = document.getElementById('folder_id_state').value; + } + } else { + msg_ids = msg_ids.substring(0,msg_ids.length-1); + document.getElementById('ids_more_actions').value = msg_ids; + var url_more_actions = "more-actions"; + var postData = "msg_ids=" + msg_ids + "&option_select=" + option; + document.getElementById('msg_action').style.display = ''; + loading(); + document.getElementById('ids_length').value = count_msg_ids_select; + var request = YAHOO.util.Connect.asyncRequest('POST', url_more_actions, callback_more_actions,postData); + } +} + + +var handleSuccess_more_actions = function(o){ + var folder_id_state = document.getElementById('folder_id').value; + var owner_id = document.getElementById('owner_id').value; + document.getElementById('more_actions_option').value = o.responseText; + var ids = (document.getElementById('ids_more_actions').value).split(','); + if (o.responseText == 't') { + var option_style = 'bold'; + } else { + var option_style = ''; + } + var count_new_msg = 0; + var count_read_msg = 0; + for (var count=0; count < ids.length; count++) { + if (document.getElementById('new_p_style.' + ids[count]) != null) { + if (document.getElementById('new_p_style.' + ids[count]).style.fontWeight == '') { + if (o.responseText == 't') { + count_new_msg = count_new_msg+1; + } + } else { + if (o.responseText == 'f') { + count_read_msg = count_read_msg+1; + } + } + document.getElementById('new_p_style.' + ids[count]).style.fontWeight = option_style; + document.getElementById('new_p_sub.' + ids[count]).style.fontWeight = option_style; + if (document.getElementById('new_p_comm.' + ids[count]) != null ) { + document.getElementById('new_p_comm.' + ids[count]).style.fontWeight = option_style; + } + document.getElementById('new_p_date.' + ids[count]).style.fontWeight = option_style; + } + if (document.getElementById('check_box_msg.' + ids[count]) != null) { + document.getElementById('check_box_msg.' + ids[count]).checked = 0; + } + } + document.getElementById('msg_action').style.display = ''; + if (ids == "") { + document.getElementById('msg_actions').innerHTML = document.getElementById('msg_select_msg').value; + } else { + if (o.responseText == 't') { + if (count_new_msg > 1) { + document.getElementById('msg_actions').innerHTML = count_new_msg + " " + document.getElementById('more_msg_unread').value; + } else { + document.getElementById('msg_actions').innerHTML = document.getElementById('msg_unread').value; + } + } else { + if(count_read_msg > 1) { + document.getElementById('msg_actions').innerHTML = count_read_msg + " " + document.getElementById('more_msg_read').value; + } else { + document.getElementById('msg_actions').innerHTML = document.getElementById('msg_read').value; + } + } + } + var total_new_msg = document.getElementById('new_msg_folder_'+ folder_id_state).value; + if (o.responseText == 't') { + var new_messages = (parseInt(total_new_msg)+parseInt(count_new_msg)); + } else { + var new_messages = (parseInt(total_new_msg)-parseInt(count_read_msg)); + } + document.getElementById('new_msg_folder_'+ folder_id_state).value = new_messages; + document.getElementById('more_actions_p').value = 't'; + if (document.getElementById('checkbox_general') != null ) { + document.getElementById('checkbox_general').checked = false; + } + update_numbers(); +}; + +var handleFailure_more_actions= function(o){ +}; + +var callback_more_actions={success:handleSuccess_more_actions,failure:handleFailure_more_actions}; + +function loadEditors(editorTag){ + var editorContent = document.getElementById(editorTag); + if (editorContent != null && editorContent.innerHTML != "") { + var content = editorContent.innerHTML; + eval(editorContent.innerHTML); + editorContent.innerHTML = ""; + } +} + +var xinhaTimer; +var initEditorsTry = 0; +var iframe_id = ""; + +function initEditors(){ + var ids = document.getElementById('advancedMessagesIds'); + var no_ids = document.getElementById('noTabsEditors'); + if (ids != null) { + var id = ids.innerHTML; + var id = id.trim(); + var id = id.replace(/\'/g,""); + loadEditors('advancedMessagesEditor'); + } else { + if (no_ids == null && initEditorsTry < 20) { + initEditorsTry++; + xinhaTimer = window.setTimeout("initEditors()",500); + return false; + } + } + initEditorsTry = 0; + window.clearTimeout(xinhaTimer); +} + +String.prototype.trim = function () { + return this.replace(/^\s*/, "").replace(/\s*$/, ""); +} + + +function reply_dialog (option,msg_id,general_parent_id){ + var msg_action_id = document.getElementById('msg_action_id').value; + document.getElementById('msg_action_p').value = 'f'; + hidden_msg_actions(); + if (document.getElementById('msg_action_' + msg_action_id) != null ) { + document.getElementById('msg_action_' + msg_action_id).style.display = 'none'; + } + if (document.getElementById('reply_dialog_active').value == 't') { + var msg_id_reply = document.getElementById('msg_id_reply').value; + if (msg_id_reply != msg_id) { + var continue_reply = confirm(document.getElementById("other_msg_reply").value + " " + document.getElementById("msg_cancel").value); + } else { + var continue_reply = 'false'; + } + } else { + document.getElementById('reply_dialog_active').value = 't'; + var continue_reply = 'false'; + } + if (!continue_reply ) { + self.close + } else { + document.getElementById('autocomplete_loding').innerHTML = ''; + document.getElementById('msg_action_p').value = 'f'; + hidden_msg_actions(); + document.getElementById('reply_'+msg_id).focus(); + number = 0; + document.getElementById('parent_id_reply').value = general_parent_id; + document.getElementById('msg_action_' + msg_id).style.display = 'none'; + var msg_id_reply = document.getElementById('msg_id_reply').value; + //pasar lo de los colores a variables y colocarlas hasta arriba + if (msg_id_reply != msg_id && msg_id_reply != "" && document.getElementById('response_reply_mail_'+msg_id_reply) != null) { + document.getElementById('response_reply_mail_'+msg_id_reply).innerHTML = ""; + document.getElementById('reply_' + msg_id_reply).style.background = normal_color; + if ( document.getElementById('reply_all_' + msg_id_reply) != null) { + document.getElementById('reply_all_'+ msg_id_reply).style.background = normal_color; + } + document.getElementById('forward_'+ msg_id).style.background = normal_color; + } + if (option == "reply") { + document.getElementById('reply_'+msg_id).style.background = select_color; + } else { + document.getElementById('reply_'+msg_id).style.background = normal_color; + } + if (option == "reply_all") { + document.getElementById('reply_all_'+msg_id).style.background = select_color; + } else { + if ( document.getElementById('reply_all_'+msg_id) != null) { + document.getElementById('reply_all_'+msg_id).style.background = normal_color; + } + } + if (option == "forward") { + document.getElementById('forward_'+msg_id).style.background = select_color; + } else { + document.getElementById('forward_'+msg_id).style.background = normal_color; + } + document.getElementById('option_reply').value = option; + if (document.getElementById('response_reply_mail_'+msg_id).innerHTML.length < 14 ) { + document.getElementById('top_menu').style.display = 'none'; + document.getElementById('msg_id_reply').value = msg_id; + var url = "send?reply_p=1&reply_send=0&msg_id="+msg_id+ "&general_parent_id=" + general_parent_id + "&reply_option=" + option; + var request = YAHOO.util.Connect.asyncRequest('GET', url, callback_reply_dialog); + } else { + var option = document.getElementById('option_reply').value; + if (option == "forward") { + document.getElementById('attachment_forward').style.display = ''; + } else { + document.getElementById('attachment_forward').style.display = 'none'; + } + var rel_types_checked = document.getElementById('rel_types_checked').value.split(","); + if (option == "reply_all" ) { + for (var i=0;i < rel_types_checked.length; i = i + 1) { + if (document.getElementById(rel_types_checked[i]) != null) { + document.getElementById(rel_types_checked[i]).checked = true; + } + } + } else { + for (var i=0;i < rel_types_checked.length; i = i + 1) { + if (document.getElementById(rel_types_checked[i]) != null) { + document.getElementById(rel_types_checked[i]).checked = false; + } + } + } + if (YAHOO.env.ua.ie) { + var offset = document.getElementById('scroll_message_'+msg_id).offsetTop; + scrollTo(0,offset + 200); + } else { + document.getElementById('scroll_message_'+msg_id).scrollTo(); + } + reply_message(option,msg_id); + } + } +} + +var handleSuccess_reply_dialog = function(o){ + var msg_id = document.getElementById('msg_id_reply').value; + if (YAHOO.env.ua.ie) { + var offset = document.getElementById('scroll_message_'+msg_id).offsetTop; + scrollTo(0,offset + 200); + } else { + + document.getElementById('scroll_message_'+msg_id).scrollTo(); + } + var option = document.getElementById('option_reply').value; + document.getElementById('response_reply_mail_'+msg_id).innerHTML = o.responseText; + document.getElementById('top_menu').style.display = ''; + //window.location.hash = "#scroll_message_"+msg_id; + if (option == "forward") { + document.getElementById('attachment_forward').style.display = ''; + } else { + document.getElementById('attachment_forward').style.display = 'none'; + } + if (document.getElementById('rel_types_checked').value != "" ) { + var rel_types_checked = document.getElementById('rel_types_checked').value.split(","); + if (option == "reply_all" ) { + for (var i=0;i < rel_types_checked.length; i = i + 1) { + try { + document.getElementById(rel_types_checked[i]).checked = true; + } catch(err) {} + } + } else { + for (var i=0;i < rel_types_checked.length; i = i + 1) { + try { + document.getElementById(rel_types_checked[i]).checked = false; + } catch(err) {} + } + } + } + reply_message(option,msg_id); + contact_users(); + initEditors(); + (new Image()).src='inbox/images/token.gif'; + (new Image()).src='inbox/images/token_selected.gif'; + (new Image()).src='inbox/images/token_hover.gif'; + (new Image()).src='inbox/images/token_x.gif'; +}; + +var handleFailure_reply_dialog = function(o){ +}; + +var callback_reply_dialog = {success:handleSuccess_reply_dialog,failure:handleFailure_reply_dialog}; + +function valid_search(value) { + if (value != "") { + document.getElementById('search_button').disabled = false; + } else { + document.getElementById('search_button').disabled = true; + } +} + +function checkKey(key,value) { + var unicode + if (key.charCode) { + unicode=key.charCode; + } else { + unicode=key.keyCode; + } + if (unicode == 13){ + valid_search(value); + search(); + } +} + +function search(page_number) { + document.getElementById('show_delete').style.display = ''; + document.getElementById('move_to').style.display = ''; + document.getElementById('show_delete').style.display = ''; + document.getElementById('msg_system').style.display = 'none'; + var data_search = document.getElementById('search_data').value; + var url_search = "search"; + if (page_number == undefined ) { + var postData = "data_search=" + data_search; + } else { + var postData = "data_search=" + data_search + "&page_number=" + page_number; + } + document.getElementById('msg_action').style.display = ''; + loading(); + var request = YAHOO.util.Connect.asyncRequest('POST', url_search, callback_search,postData); +} + +var handleSuccess_search = function(o){ + document.getElementById('msg_action').style.display = 'none'; + document.getElementById('msg_actions').innerHTML = ''; + document.getElementById('folder_section_display').innerHTML = o.responseText; +}; + +var handleFailure_search = function(o){ +}; + +var callback_search = {success:handleSuccess_search,failure:handleFailure_search}; + + +function delete_text_input (name) { + var text_length = document.getElementById('autocomplete_input').value.length; + if ( text_length > 0 && this.focus() != undefined) { + alert(document.getElementById('autocomplete_input').value + " " + document.getElementById('msg_invalid_user').value); + } + document.getElementById('autocomplete_input').value = ''; +} + +function loading() { + document.getElementById('msg_action').style.display = ''; + var text_action = document.getElementById('msg_loading').value; + document.getElementById('msg_actions').innerHTML = text_action + " <image src=/resources/ajaxhelper/images/indicator.gif>"; +} + +function loading_cancel() { + document.getElementById('msg_action').style.display = 'none'; + document.getElementById('msg_actions').innerHTML = ''; +} + +function empty_trash() { + var continue_empty = confirm(document.getElementById("msg_continue_empty").value); + if (!continue_empty ) { + self.close + } else { + loading(); + var url = "empty-trash"; + var request = YAHOO.util.Connect.asyncRequest('GET', url, callback_empty_trash); + } +} + +var handleSuccess_empty_trash = function(o){ + document.getElementById('folder_id').value = 3; + get_messages_folder('more_actions'); + document.getElementById('msg_action_p').value = 't'; + document.getElementById('msg_action').style.display = ''; + var text_action = document.getElementById('confirm_trash_empty').value; + document.getElementById('msg_actions').innerHTML = text_action; +}; + +var handleFailure_empty_trash = function(o){ }; + +var callback_empty_trash = {success:handleSuccess_empty_trash,failure:handleFailure_empty_trash}; + +function id_delete (contact_id) { + document.getElementById('span_' + contact_id).innerHTML = ''; + var add = document.getElementById('contact_reply'); + var olddiv = document.getElementById('span_' + contact_id); + add.removeChild(olddiv); +} + +function select_all(form,option){ + var formObject = document.getElementsByName(form.name); + var form = formObject[0]; + var elements = form.elements; + for ( var i = 0; i < elements.length ; i++){ + if (elements[i].name == 'subject_id' && elements[i].type == "checkbox") { + elements[i].checked = option; + } + } +} + +function select_all_rel_types(option){ + var formObject = document.getElementsByName('compose_message'); + var form = formObject[0]; + var elements = form.elements; + var rel_types_checked_p = 0; + for ( var i = 0; i < elements.length ; i++) { + if (elements[i].name == 'rel_types') { + elements[i].checked = option; + } + } +} + +function semuestra (name) { + document.getElementById(name).style.visible = ''; +} + +function html_xinha_editor (option) { + var editor = Xinha.getEditor("message"); + if ( editor._doc != null) { + var message = editor.getEditorContent(); + var position = message.search('id="history_conversation">'); + if (option == 'forward') { + var history_conversation = document.getElementById('history_conversation').innerHTML; + var signature_text_position = message.search('id="signature"'); + if ( signature_text_position > 0) { + var message = message.substring(0,signature_text_position-5); + } + var signature = document.getElementById('signature').innerHTML; + editor._doc.body.innerHTML = history_conversation + "<br><br>" + signature; + } else { + var signature = document.getElementById('signature').innerHTML; + if ( position > 0) { + var message = message.substring(0,position-15); + } + editor._doc.body.innerHTML = "<br><br><br>" +signature; + } + } +} Index: openacs-4/packages/messages/www/resources/next_arr.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/next_arr.gif,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/prototype.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/prototype.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/prototype.js 31 Aug 2010 21:30:48 -0000 1.1 @@ -0,0 +1,4223 @@ +/* Prototype JavaScript framework, version 1.6.0.2 + * (c) 2005-2007 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * + *--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.6.0.2', + + Browser: { + IE: !!(window.attachEvent && !window.opera), + Opera: !!window.opera, + WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, + Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1, + MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) + }, + + BrowserFeatures: { + XPath: !!document.evaluate, + ElementExtensions: !!window.HTMLElement, + SpecificElementExtensions: + document.createElement('div').__proto__ && + document.createElement('div').__proto__ !== + document.createElement('form').__proto__ + }, + + ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, + K: function(x) { return x } +}; + +if (Prototype.Browser.MobileSafari) + Prototype.BrowserFeatures.SpecificElementExtensions = false; + + +/* Based on Alex Arnell's inheritance implementation. */ +var Class = { + create: function() { + var parent = null, properties = $A(arguments); + if (Object.isFunction(properties[0])) + parent = properties.shift(); + + function klass() { + this.initialize.apply(this, arguments); + } + + Object.extend(klass, Class.Methods); + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + var subclass = function() { }; + subclass.prototype = parent.prototype; + klass.prototype = new subclass; + parent.subclasses.push(klass); + } + + for (var i = 0; i < properties.length; i++) + klass.addMethods(properties[i]); + + if (!klass.prototype.initialize) + klass.prototype.initialize = Prototype.emptyFunction; + + klass.prototype.constructor = klass; + + return klass; + } +}; + +Class.Methods = { + addMethods: function(source) { + var ancestor = this.superclass && this.superclass.prototype; + var properties = Object.keys(source); + + if (!Object.keys({ toString: true }).length) + properties.push("toString", "valueOf"); + + for (var i = 0, length = properties.length; i < length; i++) { + var property = properties[i], value = source[property]; + if (ancestor && Object.isFunction(value) && + value.argumentNames().first() == "$super") { + var method = value, value = Object.extend((function(m) { + return function() { return ancestor[m].apply(this, arguments) }; + })(property).wrap(method), { + valueOf: function() { return method }, + toString: function() { return method.toString() } + }); + } + this.prototype[property] = value; + } + + return this; + } +}; + +var Abstract = { }; + +Object.extend = function(destination, source) { + for (var property in source) + destination[property] = source[property]; + return destination; +}; + +Object.extend(Object, { + inspect: function(object) { + try { + if (Object.isUndefined(object)) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : String(object); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + }, + + toJSON: function(object) { + var type = typeof object; + switch (type) { + case 'undefined': + case 'function': + case 'unknown': return; + case 'boolean': return object.toString(); + } + + if (object === null) return 'null'; + if (object.toJSON) return object.toJSON(); + if (Object.isElement(object)) return; + + var results = []; + for (var property in object) { + var value = Object.toJSON(object[property]); + if (!Object.isUndefined(value)) + results.push(property.toJSON() + ': ' + value); + } + + return '{' + results.join(', ') + '}'; + }, + + toQueryString: function(object) { + return $H(object).toQueryString(); + }, + + toHTML: function(object) { + return object && object.toHTML ? object.toHTML() : String.interpret(object); + }, + + keys: function(object) { + var keys = []; + for (var property in object) + keys.push(property); + return keys; + }, + + values: function(object) { + var values = []; + for (var property in object) + values.push(object[property]); + return values; + }, + + clone: function(object) { + return Object.extend({ }, object); + }, + + isElement: function(object) { + return object && object.nodeType == 1; + }, + + isArray: function(object) { + return object != null && typeof object == "object" && + 'splice' in object && 'join' in object; + }, + + isHash: function(object) { + return object instanceof Hash; + }, + + isFunction: function(object) { + return typeof object == "function"; + }, + + isString: function(object) { + return typeof object == "string"; + }, + + isNumber: function(object) { + return typeof object == "number"; + }, + + isUndefined: function(object) { + return typeof object == "undefined"; + } +}); + +Object.extend(Function.prototype, { + argumentNames: function() { + var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip"); + return names.length == 1 && !names[0] ? [] : names; + }, + + bind: function() { + if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } + }, + + bindAsEventListener: function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) { + return __method.apply(object, [event || window.event].concat(args)); + } + }, + + curry: function() { + if (!arguments.length) return this; + var __method = this, args = $A(arguments); + return function() { + return __method.apply(this, args.concat($A(arguments))); + } + }, + + delay: function() { + var __method = this, args = $A(arguments), timeout = args.shift() * 1000; + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); + }, + + wrap: function(wrapper) { + var __method = this; + return function() { + return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); + } + }, + + methodize: function() { + if (this._methodized) return this._methodized; + var __method = this; + return this._methodized = function() { + return __method.apply(null, [this].concat($A(arguments))); + }; + } +}); + +Function.prototype.defer = Function.prototype.delay.curry(0.01); + +Date.prototype.toJSON = function() { + return '"' + this.getUTCFullYear() + '-' + + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + + this.getUTCDate().toPaddedString(2) + 'T' + + this.getUTCHours().toPaddedString(2) + ':' + + this.getUTCMinutes().toPaddedString(2) + ':' + + this.getUTCSeconds().toPaddedString(2) + 'Z"'; +}; + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) { } + } + + return returnValue; + } +}; + +RegExp.prototype.match = RegExp.prototype.test; + +RegExp.escape = function(str) { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); +}; + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create({ + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + execute: function() { + this.callback(this); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.execute(); + } finally { + this.currentlyExecuting = false; + } + } + } +}); +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); + +Object.extend(String.prototype, { + gsub: function(pattern, replacement) { + var result = '', source = this, match; + replacement = arguments.callee.prepareReplacement(replacement); + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + }, + + sub: function(pattern, replacement, count) { + replacement = this.gsub.prepareReplacement(replacement); + count = Object.isUndefined(count) ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + }, + + scan: function(pattern, iterator) { + this.gsub(pattern, iterator); + return String(this); + }, + + truncate: function(length, truncation) { + length = length || 30; + truncation = Object.isUndefined(truncation) ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : String(this); + }, + + strip: function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }, + + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(function(script) { return eval(script) }); + }, + + escapeHTML: function() { + var self = arguments.callee; + self.text.data = this; + return self.div.innerHTML; + }, + + unescapeHTML: function() { + var div = new Element('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? (div.childNodes.length > 1 ? + $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : + div.childNodes[0].nodeValue) : ''; + }, + + toQueryParams: function(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return { }; + + return match[1].split(separator || '&').inject({ }, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var key = decodeURIComponent(pair.shift()); + var value = pair.length > 1 ? pair.join('=') : pair[0]; + if (value != undefined) value = decodeURIComponent(value); + + if (key in hash) { + if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; + hash[key].push(value); + } + else hash[key] = value; + } + return hash; + }); + }, + + toArray: function() { + return this.split(''); + }, + + succ: function() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + }, + + times: function(count) { + return count < 1 ? '' : new Array(count + 1).join(this); + }, + + camelize: function() { + var parts = this.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = this.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + }, + + capitalize: function() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + }, + + underscore: function() { + return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); + }, + + dasherize: function() { + return this.gsub(/_/,'-'); + }, + + inspect: function(useDoubleQuotes) { + var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { + var character = String.specialChar[match[0]]; + return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + }, + + toJSON: function() { + return this.inspect(true); + }, + + unfilterJSON: function(filter) { + return this.sub(filter || Prototype.JSONFilter, '#{1}'); + }, + + isJSON: function() { + var str = this; + if (str.blank()) return false; + str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); + return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); + }, + + evalJSON: function(sanitize) { + var json = this.unfilterJSON(); + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + }, + + include: function(pattern) { + return this.indexOf(pattern) > -1; + }, + + startsWith: function(pattern) { + return this.indexOf(pattern) === 0; + }, + + endsWith: function(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.lastIndexOf(pattern) === d; + }, + + empty: function() { + return this == ''; + }, + + blank: function() { + return /^\s*$/.test(this); + }, + + interpolate: function(object, pattern) { + return new Template(this, pattern).evaluate(object); + } +}); + +if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { + escapeHTML: function() { + return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); + }, + unescapeHTML: function() { + return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); + } +}); + +String.prototype.gsub.prepareReplacement = function(replacement) { + if (Object.isFunction(replacement)) return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; +}; + +String.prototype.parseQuery = String.prototype.toQueryParams; + +Object.extend(String.prototype.escapeHTML, { + div: document.createElement('div'), + text: document.createTextNode('') +}); + +with (String.prototype.escapeHTML) div.appendChild(text); + +var Template = Class.create({ + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + if (Object.isFunction(object.toTemplateReplacements)) + object = object.toTemplateReplacements(); + + return this.template.gsub(this.pattern, function(match) { + if (object == null) return ''; + + var before = match[1] || ''; + if (before == '\\') return match[2]; + + var ctx = object, expr = match[3]; + var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; + match = pattern.exec(expr); + if (match == null) return before; + + while (match != null) { + var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; + ctx = ctx[comp]; + if (null == ctx || '' == match[3]) break; + expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); + match = pattern.exec(expr); + } + + return before + String.interpret(ctx); + }); + } +}); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; + +var $break = { }; + +var Enumerable = { + each: function(iterator, context) { + var index = 0; + iterator = iterator.bind(context); + try { + this._each(function(value) { + iterator(value, index++); + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + }, + + eachSlice: function(number, iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var index = -number, slices = [], array = this.toArray(); + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.collect(iterator, context); + }, + + all: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var result = true; + this.each(function(value, index) { + result = result && !!iterator(value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var result = false; + this.each(function(value, index) { + if (result = !!iterator(value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var results = []; + this.each(function(value, index) { + results.push(iterator(value, index)); + }); + return results; + }, + + detect: function(iterator, context) { + iterator = iterator.bind(context); + var result; + this.each(function(value, index) { + if (iterator(value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator, context) { + iterator = iterator.bind(context); + var results = []; + this.each(function(value, index) { + if (iterator(value, index)) + results.push(value); + }); + return results; + }, + + grep: function(filter, iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var results = []; + + if (Object.isString(filter)) + filter = new RegExp(filter); + + this.each(function(value, index) { + if (filter.match(value)) + results.push(iterator(value, index)); + }); + return results; + }, + + include: function(object) { + if (Object.isFunction(this.indexOf)) + if (this.indexOf(object) != -1) return true; + + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inGroupsOf: function(number, fillWith) { + fillWith = Object.isUndefined(fillWith) ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + }, + + inject: function(memo, iterator, context) { + iterator = iterator.bind(context); + this.each(function(value, index) { + memo = iterator(memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var result; + this.each(function(value, index) { + value = iterator(value, index); + if (result == null || value >= result) + result = value; + }); + return result; + }, + + min: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var result; + this.each(function(value, index) { + value = iterator(value, index); + if (result == null || value < result) + result = value; + }); + return result; + }, + + partition: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var trues = [], falses = []; + this.each(function(value, index) { + (iterator(value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator, context) { + iterator = iterator.bind(context); + var results = []; + this.each(function(value, index) { + if (!iterator(value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator, context) { + iterator = iterator.bind(context); + return this.map(function(value, index) { + return {value: value, criteria: iterator(value, index)}; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.map(); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (Object.isFunction(args.last())) + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + }, + + size: function() { + return this.toArray().length; + }, + + inspect: function() { + return '#<Enumerable:' + this.toArray().inspect() + '>'; + } +}; + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + filter: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray, + every: Enumerable.all, + some: Enumerable.any +}); +function $A(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; +} + +if (Prototype.Browser.WebKit) { + $A = function(iterable) { + if (!iterable) return []; + if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') && + iterable.toArray) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; + }; +} + +Array.from = $A; + +Object.extend(Array.prototype, Enumerable); + +if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0, length = this.length; i < length; i++) + iterator(this[i]); + }, + + clear: function() { + this.length = 0; + return this; + }, + + first: function() { + return this[0]; + }, + + last: function() { + return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(Object.isArray(value) ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + reduce: function() { + return this.length > 1 ? this : this[0]; + }, + + uniq: function(sorted) { + return this.inject([], function(array, value, index) { + if (0 == index || (sorted ? array.last() != value : !array.include(value))) + array.push(value); + return array; + }); + }, + + intersect: function(array) { + return this.uniq().findAll(function(item) { + return array.detect(function(value) { return item === value }); + }); + }, + + clone: function() { + return [].concat(this); + }, + + size: function() { + return this.length; + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + }, + + toJSON: function() { + var results = []; + this.each(function(object) { + var value = Object.toJSON(object); + if (!Object.isUndefined(value)) results.push(value); + }); + return '[' + results.join(', ') + ']'; + } +}); + +// use native browser JS 1.6 implementation if available +if (Object.isFunction(Array.prototype.forEach)) + Array.prototype._each = Array.prototype.forEach; + +if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { + i || (i = 0); + var length = this.length; + if (i < 0) i = length + i; + for (; i < length; i++) + if (this[i] === item) return i; + return -1; +}; + +if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { + i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; + var n = this.slice(0, i).reverse().indexOf(item); + return (n < 0) ? n : i - n - 1; +}; + +Array.prototype.toArray = Array.prototype.clone; + +function $w(string) { + if (!Object.isString(string)) return []; + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +if (Prototype.Browser.Opera){ + Array.prototype.concat = function() { + var array = []; + for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); + for (var i = 0, length = arguments.length; i < length; i++) { + if (Object.isArray(arguments[i])) { + for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) + array.push(arguments[i][j]); + } else { + array.push(arguments[i]); + } + } + return array; + }; +} +Object.extend(Number.prototype, { + toColorPart: function() { + return this.toPaddedString(2, 16); + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + }, + + toPaddedString: function(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + }, + + toJSON: function() { + return isFinite(this) ? this.toString() : 'null'; + } +}); + +$w('abs round ceil floor').each(function(method){ + Number.prototype[method] = Math[method].methodize(); +}); +function $H(object) { + return new Hash(object); +}; + +var Hash = Class.create(Enumerable, (function() { + + function toQueryPair(key, value) { + if (Object.isUndefined(value)) return key; + return key + '=' + encodeURIComponent(String.interpret(value)); + } + + return { + initialize: function(object) { + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); + }, + + _each: function(iterator) { + for (var key in this._object) { + var value = this._object[key], pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + set: function(key, value) { + return this._object[key] = value; + }, + + get: function(key) { + return this._object[key]; + }, + + unset: function(key) { + var value = this._object[key]; + delete this._object[key]; + return value; + }, + + toObject: function() { + return Object.clone(this._object); + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + index: function(value) { + var match = this.detect(function(pair) { + return pair.value === value; + }); + return match && match.key; + }, + + merge: function(object) { + return this.clone().update(object); + }, + + update: function(object) { + return new Hash(object).inject(this, function(result, pair) { + result.set(pair.key, pair.value); + return result; + }); + }, + + toQueryString: function() { + return this.map(function(pair) { + var key = encodeURIComponent(pair.key), values = pair.value; + + if (values && typeof values == 'object') { + if (Object.isArray(values)) + return values.map(toQueryPair.curry(key)).join('&'); + } + return toQueryPair(key, values); + }).join('&'); + }, + + inspect: function() { + return '#<Hash:{' + this.map(function(pair) { + return pair.map(Object.inspect).join(': '); + }).join(', ') + '}>'; + }, + + toJSON: function() { + return Object.toJSON(this.toObject()); + }, + + clone: function() { + return new Hash(this); + } + } +})()); + +Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; +Hash.from = $H; +var ObjectRange = Class.create(Enumerable, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +}; + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +}; + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (Object.isFunction(responder[callback])) { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) { } + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { Ajax.activeRequestCount++ }, + onComplete: function() { Ajax.activeRequestCount-- } +}); + +Ajax.Base = Class.create({ + initialize: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '', + evalJSON: true, + evalJS: true + }; + Object.extend(this.options, options || { }); + + this.options.method = this.options.method.toLowerCase(); + + if (Object.isString(this.options.parameters)) + this.options.parameters = this.options.parameters.toQueryParams(); + else if (Object.isHash(this.options.parameters)) + this.options.parameters = this.options.parameters.toObject(); + } +}); + +Ajax.Request = Class.create(Ajax.Base, { + _complete: false, + + initialize: function($super, url, options) { + $super(options); + this.transport = Ajax.getTransport(); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.clone(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + // simulate other verbs over post + params['_method'] = this.method; + this.method = 'post'; + } + + this.parameters = params; + + if (params = Object.toQueryString(params)) { + // when GET, append parameters to URL + if (this.method == 'get') + this.url += (this.url.include('?') ? '&' : '?') + params; + else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + params += '&_='; + } + + try { + var response = new Ajax.Response(this); + if (this.options.onCreate) this.options.onCreate(response); + Ajax.Responders.dispatch('onCreate', this, response); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + // user-defined headers + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (Object.isFunction(extras.push)) + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + var status = this.getStatus(); + return !status || (status >= 200 && status < 300); + }, + + getStatus: function() { + try { + return this.transport.status || 0; + } catch (e) { return 0 } + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + response.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + var contentType = response.getHeader('Content-type'); + if (this.options.evalJS == 'force' + || (this.options.evalJS && this.isSameOrigin() && contentType + && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); + Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + // avoid memory leak in MSIE: clean up + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + isSameOrigin: function() { + var m = this.url.match(/^\s*https?:\/\/[^\/]*/); + return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ + protocol: location.protocol, + domain: document.domain, + port: location.port ? ':' + location.port : '' + })); + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name) || null; + } catch (e) { return null } + }, + + evalResponse: function() { + try { + return eval((this.transport.responseText || '').unfilterJSON()); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Response = Class.create({ + initialize: function(request){ + this.request = request; + var transport = this.transport = request.transport, + readyState = this.readyState = transport.readyState; + + if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { + this.status = this.getStatus(); + this.statusText = this.getStatusText(); + this.responseText = String.interpret(transport.responseText); + this.headerJSON = this._getHeaderJSON(); + } + + if(readyState == 4) { + var xml = transport.responseXML; + this.responseXML = Object.isUndefined(xml) ? null : xml; + this.responseJSON = this._getResponseJSON(); + } + }, + + status: 0, + statusText: '', + + getStatus: Ajax.Request.prototype.getStatus, + + getStatusText: function() { + try { + return this.transport.statusText || ''; + } catch (e) { return '' } + }, + + getHeader: Ajax.Request.prototype.getHeader, + + getAllHeaders: function() { + try { + return this.getAllResponseHeaders(); + } catch (e) { return null } + }, + + getResponseHeader: function(name) { + return this.transport.getResponseHeader(name); + }, + + getAllResponseHeaders: function() { + return this.transport.getAllResponseHeaders(); + }, + + _getHeaderJSON: function() { + var json = this.getHeader('X-JSON'); + if (!json) return null; + json = decodeURIComponent(escape(json)); + try { + return json.evalJSON(this.request.options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + }, + + _getResponseJSON: function() { + var options = this.request.options; + if (!options.evalJSON || (options.evalJSON != 'force' && + !(this.getHeader('Content-type') || '').include('application/json')) || + this.responseText.blank()) + return null; + try { + return this.responseText.evalJSON(options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + } +}); + +Ajax.Updater = Class.create(Ajax.Request, { + initialize: function($super, container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + }; + + options = Object.clone(options); + var onComplete = options.onComplete; + options.onComplete = (function(response, json) { + this.updateContent(response.responseText); + if (Object.isFunction(onComplete)) onComplete(response, json); + }).bind(this); + + $super(url, options); + }, + + updateContent: function(responseText) { + var receiver = this.container[this.success() ? 'success' : 'failure'], + options = this.options; + + if (!options.evalScripts) responseText = responseText.stripScripts(); + + if (receiver = $(receiver)) { + if (options.insertion) { + if (Object.isString(options.insertion)) { + var insertion = { }; insertion[options.insertion] = responseText; + receiver.insert(insertion); + } + else options.insertion(receiver, responseText); + } + else receiver.update(responseText); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { + initialize: function($super, container, url, options) { + $super(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = { }; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(response) { + if (this.options.decay) { + this.decay = (response.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = response.responseText; + } + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (Object.isString(element)) + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(Element.extend(query.snapshotItem(i))); + return results; + }; +} + +/*--------------------------------------------------------------------------*/ + +if (!window.Node) var Node = { }; + +if (!Node.ELEMENT_NODE) { + // DOM level 2 ECMAScript Language Binding + Object.extend(Node, { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }); +} + +(function() { + var element = this.Element; + this.Element = function(tagName, attributes) { + attributes = attributes || { }; + tagName = tagName.toLowerCase(); + var cache = Element.cache; + if (Prototype.Browser.IE && attributes.name) { + tagName = '<' + tagName + ' name="' + attributes.name + '">'; + delete attributes.name; + return Element.writeAttribute(document.createElement(tagName), attributes); + } + if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); + return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); + }; + Object.extend(this.Element, element || { }); +}).call(window); + +Element.cache = { }; + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + hide: function(element) { + $(element).style.display = 'none'; + return element; + }, + + show: function(element) { + $(element).style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) return element.update().insert(content); + content = Object.toHTML(content); + element.innerHTML = content.stripScripts(); + content.evalScripts.bind(content).defer(); + return element; + }, + + replace: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + else if (!Object.isElement(content)) { + content = Object.toHTML(content); + var range = element.ownerDocument.createRange(); + range.selectNode(element); + content.evalScripts.bind(content).defer(); + content = range.createContextualFragment(content.stripScripts()); + } + element.parentNode.replaceChild(content, element); + return element; + }, + + insert: function(element, insertions) { + element = $(element); + + if (Object.isString(insertions) || Object.isNumber(insertions) || + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) + insertions = {bottom:insertions}; + + var content, insert, tagName, childNodes; + + for (var position in insertions) { + content = insertions[position]; + position = position.toLowerCase(); + insert = Element._insertionTranslations[position]; + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + insert(element, content); + continue; + } + + content = Object.toHTML(content); + + tagName = ((position == 'before' || position == 'after') + ? element.parentNode : element).tagName.toUpperCase(); + + childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + + if (position == 'top' || position == 'after') childNodes.reverse(); + childNodes.each(insert.curry(element)); + + content.evalScripts.bind(content).defer(); + } + + return element; + }, + + wrap: function(element, wrapper, attributes) { + element = $(element); + if (Object.isElement(wrapper)) + $(wrapper).writeAttribute(attributes || { }); + else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); + else wrapper = new Element('div', wrapper); + if (element.parentNode) + element.parentNode.replaceChild(wrapper, element); + wrapper.appendChild(element); + return wrapper; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), attribute = pair.last(); + var value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return $(element).recursivelyCollect('parentNode'); + }, + + descendants: function(element) { + return $(element).select("*"); + }, + + firstDescendant: function(element) { + element = $(element).firstChild; + while (element && element.nodeType != 1) element = element.nextSibling; + return $(element); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return $(element).recursivelyCollect('previousSibling'); + }, + + nextSiblings: function(element) { + return $(element).recursivelyCollect('nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return element.previousSiblings().reverse().concat(element.nextSiblings()); + }, + + match: function(element, selector) { + if (Object.isString(selector)) + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(element.parentNode); + var ancestors = element.ancestors(); + return Object.isNumber(expression) ? ancestors[expression] : + Selector.findElement(ancestors, expression, index); + }, + + down: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + return Object.isNumber(expression) ? element.descendants()[expression] : + element.select(expression)[index || 0]; + }, + + previous: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); + var previousSiblings = element.previousSiblings(); + return Object.isNumber(expression) ? previousSiblings[expression] : + Selector.findElement(previousSiblings, expression, index); + }, + + next: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); + var nextSiblings = element.nextSiblings(); + return Object.isNumber(expression) ? nextSiblings[expression] : + Selector.findElement(nextSiblings, expression, index); + }, + + select: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element, args); + }, + + adjacent: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element.parentNode, args).without(element); + }, + + identify: function(element) { + element = $(element); + var id = element.readAttribute('id'), self = arguments.callee; + if (id) return id; + do { id = 'anonymous_element_' + self.counter++ } while ($(id)); + element.writeAttribute('id', id); + return id; + }, + + readAttribute: function(element, name) { + element = $(element); + if (Prototype.Browser.IE) { + var t = Element._attributeTranslations.read; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + if (name.include(':')) { + return (!element.attributes || !element.attributes[name]) ? null : + element.attributes[name].value; + } + } + return element.getAttribute(name); + }, + + writeAttribute: function(element, name, value) { + element = $(element); + var attributes = { }, t = Element._attributeTranslations.write; + + if (typeof name == 'object') attributes = name; + else attributes[name] = Object.isUndefined(value) ? true : value; + + for (var attr in attributes) { + name = t.names[attr] || attr; + value = attributes[attr]; + if (t.values[attr]) name = t.values[attr](element, value); + if (value === false || value === null) + element.removeAttribute(name); + else if (value === true) + element.setAttribute(name, name); + else element.setAttribute(name, value); + } + return element; + }, + + getHeight: function(element) { + return $(element).getDimensions().height; + }, + + getWidth: function(element) { + return $(element).getDimensions().width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + return (elementClassName.length > 0 && (elementClassName == className || + new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + if (!element.hasClassName(className)) + element.className += (element.className ? ' ' : '') + className; + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + element.className = element.className.replace( + new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + return element[element.hasClassName(className) ? + 'removeClassName' : 'addClassName'](className); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.blank(); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + var originalAncestor = ancestor; + + if (element.compareDocumentPosition) + return (element.compareDocumentPosition(ancestor) & 8) === 8; + + if (element.sourceIndex && !Prototype.Browser.Opera) { + var e = element.sourceIndex, a = ancestor.sourceIndex, + nextAncestor = ancestor.nextSibling; + if (!nextAncestor) { + do { ancestor = ancestor.parentNode; } + while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode); + } + if (nextAncestor && nextAncestor.sourceIndex) + return (e > a && e < nextAncestor.sourceIndex); + } + + while (element = element.parentNode) + if (element == originalAncestor) return true; + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = element.cumulativeOffset(); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; + if (!value) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, + + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, + + setStyle: function(element, styles) { + element = $(element); + var elementStyle = element.style, match; + if (Object.isString(styles)) { + element.style.cssText += ';' + styles; + return styles.include('opacity') ? + element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; + } + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]); + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : + property] = styles[property]; + + return element; + }, + + setOpacity: function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; + }, + + getDimensions: function(element) { + element = $(element); + var display = $(element).getStyle('display'); + if (display != 'none' && display != null) // Safari bug + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + var originalDisplay = els.display; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = 'block'; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = originalDisplay; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = Element.getStyle(element, 'overflow') || 'auto'; + if (element._overflow !== 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (element.tagName == 'BODY') break; + var p = Element.getStyle(element, 'position'); + if (p !== 'static') break; + } + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + absolutize: function(element) { + element = $(element); + if (element.getStyle('position') == 'absolute') return; + // Position.prepare(); // To be done manually by Scripty when it needs it. + + var offsets = element.positionedOffset(); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + return element; + }, + + relativize: function(element) { + element = $(element); + if (element.getStyle('position') == 'relative') return; + // Position.prepare(); // To be done manually by Scripty when it needs it. + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + return element; + }, + + cumulativeScrollOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + getOffsetParent: function(element) { + if (element.offsetParent) return $(element.offsetParent); + if (element == document.body) return $(element); + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return $(element); + + return $(document.body); + }, + + viewportOffset: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent == document.body && + Element.getStyle(element, 'position') == 'absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!Prototype.Browser.Opera || element.tagName == 'BODY') { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return Element._returnOffset(valueL, valueT); + }, + + clonePosition: function(element, source) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || { }); + + // find page position of source + source = $(source); + var p = source.viewportOffset(); + + // find coordinate system to use + element = $(element); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(element, 'position') == 'absolute') { + parent = element.getOffsetParent(); + delta = parent.viewportOffset(); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if (options.setWidth) element.style.width = source.offsetWidth + 'px'; + if (options.setHeight) element.style.height = source.offsetHeight + 'px'; + return element; + } +}; + +Element.Methods.identify.counter = 1; + +Object.extend(Element.Methods, { + getElementsBySelector: Element.Methods.select, + childElements: Element.Methods.immediateDescendants +}); + +Element._attributeTranslations = { + write: { + names: { + className: 'class', + htmlFor: 'for' + }, + values: { } + } +}; + +if (Prototype.Browser.Opera) { + Element.Methods.getStyle = Element.Methods.getStyle.wrap( + function(proceed, element, style) { + switch (style) { + case 'left': case 'top': case 'right': case 'bottom': + if (proceed(element, 'position') === 'static') return null; + case 'height': case 'width': + // returns '0px' for hidden elements; we want it to return null + if (!Element.visible(element)) return null; + + // returns the border-box dimensions rather than the content-box + // dimensions, so we subtract padding and borders from the value + var dim = parseInt(proceed(element, style), 10); + + if (dim !== element['offset' + style.capitalize()]) + return dim + 'px'; + + var properties; + if (style === 'height') { + properties = ['border-top-width', 'padding-top', + 'padding-bottom', 'border-bottom-width']; + } + else { + properties = ['border-left-width', 'padding-left', + 'padding-right', 'border-right-width']; + } + return properties.inject(dim, function(memo, property) { + var val = proceed(element, property); + return val === null ? memo : memo - parseInt(val, 10); + }) + 'px'; + default: return proceed(element, style); + } + } + ); + + Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( + function(proceed, element, attribute) { + if (attribute === 'title') return element.title; + return proceed(element, attribute); + } + ); +} + +else if (Prototype.Browser.IE) { + // IE doesn't report offsets correctly for static elements, so we change them + // to "relative" to get the values, then change them back. + Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( + function(proceed, element) { + element = $(element); + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + + $w('positionedOffset viewportOffset').each(function(method) { + Element.Methods[method] = Element.Methods[method].wrap( + function(proceed, element) { + element = $(element); + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + // Trigger hasLayout on the offset parent so that IE6 reports + // accurate offsetTop and offsetLeft values for position: fixed. + var offsetParent = element.getOffsetParent(); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + }); + + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + //console.log(element.style[style],element.style); + try { + var value = element.style[style]; + } catch (err) { + var value = ''; + } + if (!value && element.currentStyle) value = element.currentStyle[style]; + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset' + style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + function stripAlpha(filter){ + return filter.replace(/alpha\([^\)]*\)/gi,''); + } + element = $(element); + var currentStyle = element.currentStyle; + if ((currentStyle && !currentStyle.hasLayout) || + (!currentStyle && element.style.zoom == 'normal')) + element.style.zoom = 1; + + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + (filter = stripAlpha(filter)) ? + style.filter = filter : style.removeAttribute('filter'); + return element; + } else if (value < 0.00001) value = 0; + style.filter = stripAlpha(filter) + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; + + Element._attributeTranslations = { + read: { + names: { + 'class': 'className', + 'for': 'htmlFor' + }, + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _getAttrNode: function(element, attribute) { + var node = element.getAttributeNode(attribute); + return node ? node.value : ""; + }, + _getEv: function(element, attribute) { + attribute = element.getAttribute(attribute); + return attribute ? attribute.toString().slice(23, -2) : null; + }, + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + return element.title; + } + } + } + }; + + Element._attributeTranslations.write = { + names: Object.extend({ + cellpadding: 'cellPadding', + cellspacing: 'cellSpacing' + }, Element._attributeTranslations.read.names), + values: { + checked: function(element, value) { + element.checked = !!value; + }, + + style: function(element, value) { + element.style.cssText = value ? value : ''; + } + } + }; + + Element._attributeTranslations.has = {}; + + $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + + 'encType maxLength readOnly longDesc').each(function(attr) { + Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; + Element._attributeTranslations.has[attr.toLowerCase()] = attr; + }); + + (function(v) { + Object.extend(v, { + href: v._getAttr, + src: v._getAttr, + type: v._getAttr, + action: v._getAttrNode, + disabled: v._flag, + checked: v._flag, + readonly: v._flag, + multiple: v._flag, + onload: v._getEv, + onunload: v._getEv, + onclick: v._getEv, + ondblclick: v._getEv, + onmousedown: v._getEv, + onmouseup: v._getEv, + onmouseover: v._getEv, + onmousemove: v._getEv, + onmouseout: v._getEv, + onfocus: v._getEv, + onblur: v._getEv, + onkeypress: v._getEv, + onkeydown: v._getEv, + onkeyup: v._getEv, + onsubmit: v._getEv, + onreset: v._getEv, + onselect: v._getEv, + onchange: v._getEv + }); + })(Element._attributeTranslations.read.values); +} + +else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1) ? 0.999999 : + (value === '') ? '' : (value < 0.00001) ? 0 : value; + return element; + }; +} + +else if (Prototype.Browser.WebKit) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + + if (value == 1) + if(element.tagName == 'IMG' && element.width) { + element.width++; element.width--; + } else try { + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch (e) { } + + return element; + }; + + // Safari returns margins on body which is incorrect if the child is absolutely + // positioned. For performance reasons, redefine Element#cumulativeOffset for + // KHTML/WebKit only. + Element.Methods.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return Element._returnOffset(valueL, valueT); + }; +} + +if (Prototype.Browser.IE || Prototype.Browser.Opera) { + // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements + Element.Methods.update = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) return element.update().insert(content); + + content = Object.toHTML(content); + var tagName = element.tagName.toUpperCase(); + + if (tagName in Element._insertionTranslations.tags) { + $A(element.childNodes).each(function(node) { element.removeChild(node) }); + Element._getContentFromAnonymousElement(tagName, content.stripScripts()) + .each(function(node) { element.appendChild(node) }); + } + else element.innerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +if ('outerHTML' in document.createElement('div')) { + Element.Methods.replace = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + element.parentNode.replaceChild(content, element); + return element; + } + + content = Object.toHTML(content); + var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); + + if (Element._insertionTranslations.tags[tagName]) { + var nextSibling = element.next(); + var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + parent.removeChild(element); + if (nextSibling) + fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); + else + fragments.each(function(node) { parent.appendChild(node) }); + } + else element.outerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +Element._returnOffset = function(l, t) { + var result = [l, t]; + result.left = l; + result.top = t; + return result; +}; + +Element._getContentFromAnonymousElement = function(tagName, html) { + var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; + if (t) { + div.innerHTML = t[0] + html + t[1]; + t[2].times(function() { div = div.firstChild }); + } else div.innerHTML = html; + return $A(div.childNodes); +}; + +Element._insertionTranslations = { + before: function(element, node) { + element.parentNode.insertBefore(node, element); + }, + top: function(element, node) { + element.insertBefore(node, element.firstChild); + }, + bottom: function(element, node) { + element.appendChild(node); + }, + after: function(element, node) { + element.parentNode.insertBefore(node, element.nextSibling); + }, + tags: { + TABLE: ['<table>', '</table>', 1], + TBODY: ['<table><tbody>', '</tbody></table>', 2], + TR: ['<table><tbody><tr>', '</tr></tbody></table>', 3], + TD: ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4], + SELECT: ['<select>', '</select>', 1] + } +}; + +(function() { + Object.extend(this.tags, { + THEAD: this.tags.TBODY, + TFOOT: this.tags.TBODY, + TH: this.tags.TD + }); +}).call(Element._insertionTranslations); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + attribute = Element._attributeTranslations.has[attribute] || attribute; + var node = $(element).getAttributeNode(attribute); + return node && node.specified; + } +}; + +Element.Methods.ByTag = { }; + +Object.extend(Element, Element.Methods); + +if (!Prototype.BrowserFeatures.ElementExtensions && + document.createElement('div').__proto__) { + window.HTMLElement = { }; + window.HTMLElement.prototype = document.createElement('div').__proto__; + Prototype.BrowserFeatures.ElementExtensions = true; +} + +Element.extend = (function() { + if (Prototype.BrowserFeatures.SpecificElementExtensions) + return Prototype.K; + + var Methods = { }, ByTag = Element.Methods.ByTag; + + var extend = Object.extend(function(element) { + if (!element || element._extendedByPrototype || + element.nodeType != 1 || element == window) return element; + + var methods = Object.clone(Methods), + tagName = element.tagName, property, value; + + // extend methods for specific tags + if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); + + for (property in methods) { + value = methods[property]; + if (Object.isFunction(value) && !(property in element)) + element[property] = value.methodize(); + } + + element._extendedByPrototype = Prototype.emptyFunction; + return element; + + }, { + refresh: function() { + // extend methods for all tags (Safari doesn't need this) + if (!Prototype.BrowserFeatures.ElementExtensions) { + Object.extend(Methods, Element.Methods); + Object.extend(Methods, Element.Methods.Simulated); + } + } + }); + + extend.refresh(); + return extend; +})(); + +Element.hasAttribute = function(element, attribute) { + if (element.hasAttribute) return element.hasAttribute(attribute); + return Element.Methods.Simulated.hasAttribute(element, attribute); +}; + +Element.addMethods = function(methods) { + var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; + + if (!methods) { + Object.extend(Form, Form.Methods); + Object.extend(Form.Element, Form.Element.Methods); + Object.extend(Element.Methods.ByTag, { + "FORM": Object.clone(Form.Methods), + "INPUT": Object.clone(Form.Element.Methods), + "SELECT": Object.clone(Form.Element.Methods), + "TEXTAREA": Object.clone(Form.Element.Methods) + }); + } + + if (arguments.length == 2) { + var tagName = methods; + methods = arguments[1]; + } + + if (!tagName) Object.extend(Element.Methods, methods || { }); + else { + if (Object.isArray(tagName)) tagName.each(extend); + else extend(tagName); + } + + function extend(tagName) { + tagName = tagName.toUpperCase(); + if (!Element.Methods.ByTag[tagName]) + Element.Methods.ByTag[tagName] = { }; + Object.extend(Element.Methods.ByTag[tagName], methods); + } + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + for (var property in methods) { + var value = methods[property]; + if (!Object.isFunction(value)) continue; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = value.methodize(); + } + } + + function findDOMClass(tagName) { + var klass; + var trans = { + "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", + "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", + "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", + "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", + "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": + "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": + "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": + "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": + "FrameSet", "IFRAME": "IFrame" + }; + if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName.capitalize() + 'Element'; + if (window[klass]) return window[klass]; + + window[klass] = { }; + window[klass].prototype = document.createElement(tagName).__proto__; + return window[klass]; + } + + if (F.ElementExtensions) { + copy(Element.Methods, HTMLElement.prototype); + copy(Element.Methods.Simulated, HTMLElement.prototype, true); + } + + if (F.SpecificElementExtensions) { + for (var tag in Element.Methods.ByTag) { + var klass = findDOMClass(tag); + if (Object.isUndefined(klass)) continue; + copy(T[tag], klass.prototype); + } + } + + Object.extend(Element, Element.Methods); + delete Element.ByTag; + + if (Element.extend.refresh) Element.extend.refresh(); + Element.cache = { }; +}; + +document.viewport = { + getDimensions: function() { + var dimensions = { }; + var B = Prototype.Browser; + $w('width height').each(function(d) { + var D = d.capitalize(); + dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] : + (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D]; + }); + return dimensions; + }, + + getWidth: function() { + return this.getDimensions().width; + }, + + getHeight: function() { + return this.getDimensions().height; + }, + + getScrollOffsets: function() { + return Element._returnOffset( + window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, + window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); + } +}; +/* Portions of the Selector class are derived from Jack Slocum’s DomQuery, + * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style + * license. Please see http://www.yui-ext.com/ for more information. */ + +var Selector = Class.create({ + initialize: function(expression) { + this.expression = expression.strip(); + this.compileMatcher(); + }, + + shouldUseXPath: function() { + if (!Prototype.BrowserFeatures.XPath) return false; + + var e = this.expression; + + // Safari 3 chokes on :*-of-type and :empty + if (Prototype.Browser.WebKit && + (e.include("-of-type") || e.include(":empty"))) + return false; + + // XPath can't do namespaced attributes, nor can it read + // the "checked" property from DOM nodes + if ((/(\[[\w-]*?:|:checked)/).test(this.expression)) + return false; + + return true; + }, + + compileMatcher: function() { + if (this.shouldUseXPath()) + return this.compileXPathMatcher(); + + var e = this.expression, ps = Selector.patterns, h = Selector.handlers, + c = Selector.criteria, le, p, m; + + if (Selector._cache[e]) { + this.matcher = Selector._cache[e]; + return; + } + + this.matcher = ["this.matcher = function(root) {", + "var r = root, h = Selector.handlers, c = false, n;"]; + + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in ps) { + p = ps[i]; + if (m = e.match(p)) { + this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : + new Template(c[i]).evaluate(m)); + e = e.replace(m[0], ''); + break; + } + } + } + + this.matcher.push("return h.unique(n);\n}"); + eval(this.matcher.join('\n')); + Selector._cache[this.expression] = this.matcher; + }, + + compileXPathMatcher: function() { + var e = this.expression, ps = Selector.patterns, + x = Selector.xpath, le, m; + + if (Selector._cache[e]) { + this.xpath = Selector._cache[e]; return; + } + + this.matcher = ['.//*']; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in ps) { + if (m = e.match(ps[i])) { + this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : + new Template(x[i]).evaluate(m)); + e = e.replace(m[0], ''); + break; + } + } + } + + this.xpath = this.matcher.join(''); + Selector._cache[this.expression] = this.xpath; + }, + + findElements: function(root) { + root = root || document; + if (this.xpath) return document._getElementsByXPath(this.xpath, root); + return this.matcher(root); + }, + + match: function(element) { + this.tokens = []; + + var e = this.expression, ps = Selector.patterns, as = Selector.assertions; + var le, p, m; + + while (e && le !== e && (/\S/).test(e)) { + le = e; + for (var i in ps) { + p = ps[i]; + if (m = e.match(p)) { + // use the Selector.assertions methods unless the selector + // is too complex. + if (as[i]) { + this.tokens.push([i, Object.clone(m)]); + e = e.replace(m[0], ''); + } else { + // reluctantly do a document-wide search + // and look for a match in the array + return this.findElements(document).include(element); + } + } + } + } + + var match = true, name, matches; + for (var i = 0, token; token = this.tokens[i]; i++) { + name = token[0], matches = token[1]; + if (!Selector.assertions[name](element, matches)) { + match = false; break; + } + } + + return match; + }, + + toString: function() { + return this.expression; + }, + + inspect: function() { + return "#<Selector:" + this.expression.inspect() + ">"; + } +}); + +Object.extend(Selector, { + _cache: { }, + + xpath: { + descendant: "//*", + child: "/*", + adjacent: "/following-sibling::*[1]", + laterSibling: '/following-sibling::*', + tagName: function(m) { + if (m[1] == '*') return ''; + return "[local-name()='" + m[1].toLowerCase() + + "' or local-name()='" + m[1].toUpperCase() + "']"; + }, + className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", + id: "[@id='#{1}']", + attrPresence: function(m) { + m[1] = m[1].toLowerCase(); + return new Template("[@#{1}]").evaluate(m); + }, + attr: function(m) { + m[1] = m[1].toLowerCase(); + m[3] = m[5] || m[6]; + return new Template(Selector.xpath.operators[m[2]]).evaluate(m); + }, + pseudo: function(m) { + var h = Selector.xpath.pseudos[m[1]]; + if (!h) return ''; + if (Object.isFunction(h)) return h(m); + return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); + }, + operators: { + '=': "[@#{1}='#{3}']", + '!=': "[@#{1}!='#{3}']", + '^=': "[starts-with(@#{1}, '#{3}')]", + '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", + '*=': "[contains(@#{1}, '#{3}')]", + '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", + '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" + }, + pseudos: { + 'first-child': '[not(preceding-sibling::*)]', + 'last-child': '[not(following-sibling::*)]', + 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', + 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", + 'checked': "[@checked]", + 'disabled': "[@disabled]", + 'enabled': "[not(@disabled)]", + 'not': function(m) { + var e = m[6], p = Selector.patterns, + x = Selector.xpath, le, v; + + var exclusion = []; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in p) { + if (m = e.match(p[i])) { + v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); + exclusion.push("(" + v.substring(1, v.length - 1) + ")"); + e = e.replace(m[0], ''); + break; + } + } + } + return "[not(" + exclusion.join(" and ") + ")]"; + }, + 'nth-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); + }, + 'nth-last-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); + }, + 'nth-of-type': function(m) { + return Selector.xpath.pseudos.nth("position() ", m); + }, + 'nth-last-of-type': function(m) { + return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); + }, + 'first-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); + }, + 'last-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); + }, + 'only-of-type': function(m) { + var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); + }, + nth: function(fragment, m) { + var mm, formula = m[6], predicate; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + if (mm = formula.match(/^(\d+)$/)) // digit only + return '[' + fragment + "= " + mm[1] + ']'; + if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (mm[1] == "-") mm[1] = -1; + var a = mm[1] ? Number(mm[1]) : 1; + var b = mm[2] ? Number(mm[2]) : 0; + predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + + "((#{fragment} - #{b}) div #{a} >= 0)]"; + return new Template(predicate).evaluate({ + fragment: fragment, a: a, b: b }); + } + } + } + }, + + criteria: { + tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', + className: 'n = h.className(n, r, "#{1}", c); c = false;', + id: 'n = h.id(n, r, "#{1}", c); c = false;', + attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', + attr: function(m) { + m[3] = (m[5] || m[6]); + return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); + }, + pseudo: function(m) { + if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); + return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); + }, + descendant: 'c = "descendant";', + child: 'c = "child";', + adjacent: 'c = "adjacent";', + laterSibling: 'c = "laterSibling";' + }, + + patterns: { + // combinators must be listed first + // (and descendant needs to be last combinator) + laterSibling: /^\s*~\s*/, + child: /^\s*>\s*/, + adjacent: /^\s*\+\s*/, + descendant: /^\s/, + + // selectors follow + tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, + id: /^#([\w\-\*]+)(\b|$)/, + className: /^\.([\w\-\*]+)(\b|$)/, + pseudo: +/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, + attrPresence: /^\[([\w]+)\]/, + attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ + }, + + // for Selector.match and Element#match + assertions: { + tagName: function(element, matches) { + return matches[1].toUpperCase() == element.tagName.toUpperCase(); + }, + + className: function(element, matches) { + return Element.hasClassName(element, matches[1]); + }, + + id: function(element, matches) { + return element.id === matches[1]; + }, + + attrPresence: function(element, matches) { + return Element.hasAttribute(element, matches[1]); + }, + + attr: function(element, matches) { + var nodeValue = Element.readAttribute(element, matches[1]); + return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); + } + }, + + handlers: { + // UTILITY FUNCTIONS + // joins two collections + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + a.push(node); + return a; + }, + + // marks an array of nodes for counting + mark: function(nodes) { + var _true = Prototype.emptyFunction; + for (var i = 0, node; node = nodes[i]; i++) + node._countedByPrototype = _true; + return nodes; + }, + + unmark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._countedByPrototype = undefined; + return nodes; + }, + + // mark each child node with its position (for nth calls) + // "ofType" flag indicates whether we're indexing for nth-of-type + // rather than nth-child + index: function(parentNode, reverse, ofType) { + parentNode._countedByPrototype = Prototype.emptyFunction; + if (reverse) { + for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { + var node = nodes[i]; + if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + } + } else { + for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) + if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + } + }, + + // filters out duplicates and extends all nodes + unique: function(nodes) { + if (nodes.length == 0) return nodes; + var results = [], n; + for (var i = 0, l = nodes.length; i < l; i++) + if (!(n = nodes[i])._countedByPrototype) { + n._countedByPrototype = Prototype.emptyFunction; + results.push(Element.extend(n)); + } + return Selector.handlers.unmark(results); + }, + + // COMBINATOR FUNCTIONS + descendant: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName('*')); + return results; + }, + + child: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) { + for (var j = 0, child; child = node.childNodes[j]; j++) + if (child.nodeType == 1 && child.tagName != '!') results.push(child); + } + return results; + }, + + adjacent: function(nodes) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + var next = this.nextElementSibling(node); + if (next) results.push(next); + } + return results; + }, + + laterSibling: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, Element.nextSiblings(node)); + return results; + }, + + nextElementSibling: function(node) { + while (node = node.nextSibling) + if (node.nodeType == 1) return node; + return null; + }, + + previousElementSibling: function(node) { + while (node = node.previousSibling) + if (node.nodeType == 1) return node; + return null; + }, + + // TOKEN FUNCTIONS + tagName: function(nodes, root, tagName, combinator) { + var uTagName = tagName.toUpperCase(); + var results = [], h = Selector.handlers; + if (nodes) { + if (combinator) { + // fastlane for ordinary descendant combinators + if (combinator == "descendant") { + for (var i = 0, node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName(tagName)); + return results; + } else nodes = this[combinator](nodes); + if (tagName == "*") return nodes; + } + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName.toUpperCase() === uTagName) results.push(node); + return results; + } else return root.getElementsByTagName(tagName); + }, + + id: function(nodes, root, id, combinator) { + var targetNode = $(id), h = Selector.handlers; + if (!targetNode) return []; + if (!nodes && root == document) return [targetNode]; + if (nodes) { + if (combinator) { + if (combinator == 'child') { + for (var i = 0, node; node = nodes[i]; i++) + if (targetNode.parentNode == node) return [targetNode]; + } else if (combinator == 'descendant') { + for (var i = 0, node; node = nodes[i]; i++) + if (Element.descendantOf(targetNode, node)) return [targetNode]; + } else if (combinator == 'adjacent') { + for (var i = 0, node; node = nodes[i]; i++) + if (Selector.handlers.previousElementSibling(targetNode) == node) + return [targetNode]; + } else nodes = h[combinator](nodes); + } + for (var i = 0, node; node = nodes[i]; i++) + if (node == targetNode) return [targetNode]; + return []; + } + return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; + }, + + className: function(nodes, root, className, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + return Selector.handlers.byClassName(nodes, root, className); + }, + + byClassName: function(nodes, root, className) { + if (!nodes) nodes = Selector.handlers.descendant([root]); + var needle = ' ' + className + ' '; + for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { + nodeClassName = node.className; + if (nodeClassName.length == 0) continue; + if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) + results.push(node); + } + return results; + }, + + attrPresence: function(nodes, root, attr, combinator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + if (nodes && combinator) nodes = this[combinator](nodes); + var results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (Element.hasAttribute(node, attr)) results.push(node); + return results; + }, + + attr: function(nodes, root, attr, value, operator, combinator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + if (nodes && combinator) nodes = this[combinator](nodes); + var handler = Selector.operators[operator], results = []; + for (var i = 0, node; node = nodes[i]; i++) { + var nodeValue = Element.readAttribute(node, attr); + if (nodeValue === null) continue; + if (handler(nodeValue, value)) results.push(node); + } + return results; + }, + + pseudo: function(nodes, name, value, root, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + if (!nodes) nodes = root.getElementsByTagName("*"); + return Selector.pseudos[name](nodes, value, root); + } + }, + + pseudos: { + 'first-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.previousElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'last-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.nextElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'only-child': function(nodes, value, root) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) + results.push(node); + return results; + }, + 'nth-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root); + }, + 'nth-last-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true); + }, + 'nth-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, false, true); + }, + 'nth-last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true, true); + }, + 'first-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, false, true); + }, + 'last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, true, true); + }, + 'only-of-type': function(nodes, formula, root) { + var p = Selector.pseudos; + return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); + }, + + // handles the an+b logic + getIndices: function(a, b, total) { + if (a == 0) return b > 0 ? [b] : []; + return $R(1, total).inject([], function(memo, i) { + if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); + return memo; + }); + }, + + // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type + nth: function(nodes, formula, root, reverse, ofType) { + if (nodes.length == 0) return []; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + var h = Selector.handlers, results = [], indexed = [], m; + h.mark(nodes); + for (var i = 0, node; node = nodes[i]; i++) { + if (!node.parentNode._countedByPrototype) { + h.index(node.parentNode, reverse, ofType); + indexed.push(node.parentNode); + } + } + if (formula.match(/^\d+$/)) { // just a number + formula = Number(formula); + for (var i = 0, node; node = nodes[i]; i++) + if (node.nodeIndex == formula) results.push(node); + } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (m[1] == "-") m[1] = -1; + var a = m[1] ? Number(m[1]) : 1; + var b = m[2] ? Number(m[2]) : 0; + var indices = Selector.pseudos.getIndices(a, b, nodes.length); + for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { + for (var j = 0; j < l; j++) + if (node.nodeIndex == indices[j]) results.push(node); + } + } + h.unmark(nodes); + h.unmark(indexed); + return results; + }, + + 'empty': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + // IE treats comments as element nodes + if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; + results.push(node); + } + return results; + }, + + 'not': function(nodes, selector, root) { + var h = Selector.handlers, selectorType, m; + var exclusions = new Selector(selector).findElements(root); + h.mark(exclusions); + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node._countedByPrototype) results.push(node); + h.unmark(exclusions); + return results; + }, + + 'enabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node.disabled) results.push(node); + return results; + }, + + 'disabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.disabled) results.push(node); + return results; + }, + + 'checked': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.checked) results.push(node); + return results; + } + }, + + operators: { + '=': function(nv, v) { return nv == v; }, + '!=': function(nv, v) { return nv != v; }, + '^=': function(nv, v) { return nv.startsWith(v); }, + '$=': function(nv, v) { return nv.endsWith(v); }, + '*=': function(nv, v) { return nv.include(v); }, + '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, + '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } + }, + + split: function(expression) { + var expressions = []; + expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { + expressions.push(m[1].strip()); + }); + return expressions; + }, + + matchElements: function(elements, expression) { + var matches = $$(expression), h = Selector.handlers; + h.mark(matches); + for (var i = 0, results = [], element; element = elements[i]; i++) + if (element._countedByPrototype) results.push(element); + h.unmark(matches); + return results; + }, + + findElement: function(elements, expression, index) { + if (Object.isNumber(expression)) { + index = expression; expression = false; + } + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + expressions = Selector.split(expressions.join(',')); + var results = [], h = Selector.handlers; + for (var i = 0, l = expressions.length, selector; i < l; i++) { + selector = new Selector(expressions[i].strip()); + h.concat(results, selector.findElements(element)); + } + return (l > 1) ? h.unique(results) : results; + } +}); + +if (Prototype.Browser.IE) { + Object.extend(Selector.handlers, { + // IE returns comment nodes on getElementsByTagName("*"). + // Filter them out. + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + if (node.tagName !== "!") a.push(node); + return a; + }, + + // IE improperly serializes _countedByPrototype in (inner|outer)HTML. + unmark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node.removeAttribute('_countedByPrototype'); + return nodes; + } + }); +} + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} +var Form = { + reset: function(form) { + $(form).reset(); + return form; + }, + + serializeElements: function(elements, options) { + if (typeof options != 'object') options = { hash: !!options }; + else if (Object.isUndefined(options.hash)) options.hash = true; + var key, value, submitted = false, submit = options.submit; + + var data = elements.inject({ }, function(result, element) { + if (!element.disabled && element.name) { + key = element.name; value = $(element).getValue(); + if (value != null && (element.type != 'submit' || (!submitted && + submit !== false && (!submit || key == submit) && (submitted = true)))) { + if (key in result) { + // a key is already present; construct an array of values + if (!Object.isArray(result[key])) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return options.hash ? data : Object.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, options) { + return Form.serializeElements(Form.getElements(form), options); + }, + + getElements: function(form) { + return $A($(form).getElementsByTagName('*')).inject([], + function(elements, child) { + if (Form.Element.Serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + } + ); + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + Form.getElements(form).invoke('disable'); + return form; + }, + + enable: function(form) { + form = $(form); + Form.getElements(form).invoke('enable'); + return form; + }, + + findFirstElement: function(form) { + var elements = $(form).getElements().findAll(function(element) { + return 'hidden' != element.type && !element.disabled; + }); + var firstByIndex = elements.findAll(function(element) { + return element.hasAttribute('tabIndex') && element.tabIndex >= 0; + }).sortBy(function(element) { return element.tabIndex }).first(); + + return firstByIndex ? firstByIndex : elements.find(function(element) { + return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + }, + + request: function(form, options) { + form = $(form), options = Object.clone(options || { }); + + var params = options.parameters, action = form.readAttribute('action') || ''; + if (action.blank()) action = window.location.href; + options.parameters = form.serialize(true); + + if (params) { + if (Object.isString(params)) params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(action, options); + } +}; + +/*--------------------------------------------------------------------------*/ + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +}; + +Form.Element.Methods = { + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = { }; + pair[element.name] = value; + return Object.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + setValue: function(element, value) { + element = $(element); + var method = element.tagName.toLowerCase(); + Form.Element.Serializers[method](element, value); + return element; + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !['button', 'reset', 'submit'].include(element.type))) + element.select(); + } catch (e) { } + return element; + }, + + disable: function(element) { + element = $(element); + element.blur(); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; + } +}; + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; +var $F = Form.Element.Methods.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element, value) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element, value); + default: + return Form.Element.Serializers.textarea(element, value); + } + }, + + inputSelector: function(element, value) { + if (Object.isUndefined(value)) return element.checked ? element.value : null; + else element.checked = !!value; + }, + + textarea: function(element, value) { + if (Object.isUndefined(value)) return element.value; + else element.value = value; + }, + + select: function(element, index) { + if (Object.isUndefined(index)) + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + else { + var opt, value, single = !Object.isArray(index); + for (var i = 0, length = element.length; i < length; i++) { + opt = element.options[i]; + value = this.optionValue(opt); + if (single) { + if (value == index) { + opt.selected = true; + return; + } + } + else opt.selected = index.include(value); + } + } + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + // extend element because hasAttribute may not be native + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +}; + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = Class.create(PeriodicalExecuter, { + initialize: function($super, element, frequency, callback) { + $super(callback, frequency); + this.element = $(element); + this.lastValue = this.getValue(); + }, + + execute: function() { + var value = this.getValue(); + if (Object.isString(this.lastValue) && Object.isString(value) ? + this.lastValue != value : String(this.lastValue) != String(value)) { + this.callback(this.element, value); + this.lastValue = value; + } + } +}); + +Form.Element.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = Class.create({ + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback, this); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +}); + +Form.Element.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) var Event = { }; + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + KEY_INSERT: 45, + + cache: { }, + + relatedTarget: function(event) { + var element; + switch(event.type) { + case 'mouseover': element = event.fromElement; break; + case 'mouseout': element = event.toElement; break; + default: return null; + } + return Element.extend(element); + } +}); + +Event.Methods = (function() { + var isButton; + + if (Prototype.Browser.IE) { + var buttonMap = { 0: 1, 1: 4, 2: 2 }; + isButton = function(event, code) { + return event.button == buttonMap[code]; + }; + + } else if (Prototype.Browser.WebKit) { + isButton = function(event, code) { + switch (code) { + case 0: return event.which == 1 && !event.metaKey; + case 1: return event.which == 1 && event.metaKey; + default: return false; + } + }; + + } else { + isButton = function(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); + }; + } + + return { + isLeftClick: function(event) { return isButton(event, 0) }, + isMiddleClick: function(event) { return isButton(event, 1) }, + isRightClick: function(event) { return isButton(event, 2) }, + + element: function(event) { + var node = Event.extend(event).target; + return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node); + }, + + findElement: function(event, expression) { + var element = Event.element(event); + if (!expression) return element; + var elements = [element].concat(element.ancestors()); + return Selector.findElement(elements, expression, 0); + }, + + pointer: function(event) { + return { + x: event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)), + y: event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)) + }; + }, + + pointerX: function(event) { return Event.pointer(event).x }, + pointerY: function(event) { return Event.pointer(event).y }, + + stop: function(event) { + Event.extend(event); + event.preventDefault(); + event.stopPropagation(); + event.stopped = true; + } + }; +})(); + +Event.extend = (function() { + var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { + m[name] = Event.Methods[name].methodize(); + return m; + }); + + if (Prototype.Browser.IE) { + Object.extend(methods, { + stopPropagation: function() { this.cancelBubble = true }, + preventDefault: function() { this.returnValue = false }, + inspect: function() { return "[object Event]" } + }); + + return function(event) { + if (!event) return false; + if (event._extendedByPrototype) return event; + + event._extendedByPrototype = Prototype.emptyFunction; + var pointer = Event.pointer(event); + Object.extend(event, { + target: event.srcElement, + relatedTarget: Event.relatedTarget(event), + pageX: pointer.x, + pageY: pointer.y + }); + return Object.extend(event, methods); + }; + + } else { + Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__; + Object.extend(Event.prototype, methods); + return Prototype.K; + } +})(); + +Object.extend(Event, (function() { + var cache = Event.cache; + + function getEventID(element) { + if (element._prototypeEventID) return element._prototypeEventID[0]; + arguments.callee.id = arguments.callee.id || 1; + return element._prototypeEventID = [++arguments.callee.id]; + } + + function getDOMEventName(eventName) { + if (eventName && eventName.include(':')) return "dataavailable"; + return eventName; + } + + function getCacheForID(id) { + return cache[id] = cache[id] || { }; + } + + function getWrappersForEventName(id, eventName) { + var c = getCacheForID(id); + return c[eventName] = c[eventName] || []; + } + + function createWrapper(element, eventName, handler) { + var id = getEventID(element); + var c = getWrappersForEventName(id, eventName); + if (c.pluck("handler").include(handler)) return false; + + var wrapper = function(event) { + if (!Event || !Event.extend || + (event.eventName && event.eventName != eventName)) + return false; + + Event.extend(event); + handler.call(element, event); + }; + + wrapper.handler = handler; + c.push(wrapper); + return wrapper; + } + + function findWrapper(id, eventName, handler) { + var c = getWrappersForEventName(id, eventName); + return c.find(function(wrapper) { return wrapper.handler == handler }); + } + + function destroyWrapper(id, eventName, handler) { + var c = getCacheForID(id); + if (!c[eventName]) return false; + c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); + } + + function destroyCache() { + for (var id in cache) + for (var eventName in cache[id]) + cache[id][eventName] = null; + } + + if (window.attachEvent) { + window.attachEvent("onunload", destroyCache); + } + + return { + observe: function(element, eventName, handler) { + element = $(element); + var name = getDOMEventName(eventName); + + var wrapper = createWrapper(element, eventName, handler); + if (!wrapper) return element; + + if (element.addEventListener) { + element.addEventListener(name, wrapper, false); + } else { + element.attachEvent("on" + name, wrapper); + } + + return element; + }, + + stopObserving: function(element, eventName, handler) { + element = $(element); + var id = getEventID(element), name = getDOMEventName(eventName); + + if (!handler && eventName) { + getWrappersForEventName(id, eventName).each(function(wrapper) { + element.stopObserving(eventName, wrapper.handler); + }); + return element; + + } else if (!eventName) { + Object.keys(getCacheForID(id)).each(function(eventName) { + element.stopObserving(eventName); + }); + return element; + } + + var wrapper = findWrapper(id, eventName, handler); + if (!wrapper) return element; + + if (element.removeEventListener) { + element.removeEventListener(name, wrapper, false); + } else { + element.detachEvent("on" + name, wrapper); + } + + destroyWrapper(id, eventName, handler); + + return element; + }, + + fire: function(element, eventName, memo) { + element = $(element); + if (element == document && document.createEvent && !element.dispatchEvent) + element = document.documentElement; + + var event; + if (document.createEvent) { + event = document.createEvent("HTMLEvents"); + event.initEvent("dataavailable", true, true); + } else { + event = document.createEventObject(); + event.eventType = "ondataavailable"; + } + + event.eventName = eventName; + event.memo = memo || { }; + + if (document.createEvent) { + element.dispatchEvent(event); + } else { + element.fireEvent(event.eventType, event); + } + + return Event.extend(event); + } + }; +})()); + +Object.extend(Event, Event.Methods); + +Element.addMethods({ + fire: Event.fire, + observe: Event.observe, + stopObserving: Event.stopObserving +}); + +Object.extend(document, { + fire: Element.Methods.fire.methodize(), + observe: Element.Methods.observe.methodize(), + stopObserving: Element.Methods.stopObserving.methodize(), + loaded: false +}); + +(function() { + /* Support for the DOMContentLoaded event is based on work by Dan Webb, + Matthias Miller, Dean Edwards and John Resig. */ + + var timer; + + function fireContentLoadedEvent() { + if (document.loaded) return; + if (timer) window.clearInterval(timer); + document.fire("dom:loaded"); + document.loaded = true; + } + + if (document.addEventListener) { + if (Prototype.Browser.WebKit) { + timer = window.setInterval(function() { + if (/loaded|complete/.test(document.readyState)) + fireContentLoadedEvent(); + }, 0); + + Event.observe(window, "load", fireContentLoadedEvent); + + } else { + document.addEventListener("DOMContentLoaded", + fireContentLoadedEvent, false); + } + + } else { + document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>"); + $("__onDOMContentLoaded").onreadystatechange = function() { + if (this.readyState == "complete") { + this.onreadystatechange = null; + fireContentLoadedEvent(); + } + }; + } +})(); +/*------------------------------- DEPRECATED -------------------------------*/ + +Hash.toQueryString = Object.toQueryString; + +var Toggle = { display: Element.toggle }; + +Element.Methods.childOf = Element.Methods.descendantOf; + +var Insertion = { + Before: function(element, content) { + return Element.insert(element, {before:content}); + }, + + Top: function(element, content) { + return Element.insert(element, {top:content}); + }, + + Bottom: function(element, content) { + return Element.insert(element, {bottom:content}); + }, + + After: function(element, content) { + return Element.insert(element, {after:content}); + } +}; + +var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); + +// This should be moved to script.aculo.us; notice the deprecated methods +// further below, that map to the newer Element methods. +var Position = { + // set to true if needed, warning: firefox performance problems + // NOT neeeded for page scrolling, only if draggable contained in + // scrollable elements + includeScrollOffsets: false, + + // must be called before calling withinIncludingScrolloffset, every time the + // page is scrolled + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + // caches x/y coordinate pair to use with overlap + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = Element.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = Element.cumulativeScrollOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = Element.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + // within must be called directly before + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + // Deprecation layer -- use newer Element methods now (1.5.2). + + cumulativeOffset: Element.Methods.cumulativeOffset, + + positionedOffset: Element.Methods.positionedOffset, + + absolutize: function(element) { + Position.prepare(); + return Element.absolutize(element); + }, + + relativize: function(element) { + Position.prepare(); + return Element.relativize(element); + }, + + realOffset: Element.Methods.cumulativeScrollOffset, + + offsetParent: Element.Methods.getOffsetParent, + + page: Element.Methods.viewportOffset, + + clone: function(source, target, options) { + options = options || { }; + return Element.clonePosition(target, source, options); + } +}; + +/*--------------------------------------------------------------------------*/ + +if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ + function iter(name) { + return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; + } + + instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? + function(element, className) { + className = className.toString().strip(); + var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); + return cond ? document._getElementsByXPath('.//*' + cond, element) : []; + } : function(element, className) { + className = className.toString().strip(); + var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); + if (!classNames && !className) return elements; + + var nodes = $(element).getElementsByTagName('*'); + className = ' ' + className + ' '; + + for (var i = 0, child, cn; child = nodes[i]; i++) { + if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || + (classNames && classNames.all(function(name) { + return !name.toString().blank() && cn.include(' ' + name + ' '); + })))) + elements.push(Element.extend(child)); + } + return elements; + }; + + return function(className, parentElement) { + return $(parentElement || document.body).getElementsByClassName(className); + }; +}(Element.Methods); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set($A(this).concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set($A(this).without(classNameToRemove).join(' ')); + }, + + toString: function() { + return $A(this).join(' '); + } +}; + +Object.extend(Element.ClassNames.prototype, Enumerable); + +/*--------------------------------------------------------------------------*/ + +Element.addMethods(); \ No newline at end of file Index: openacs-4/packages/messages/www/resources/reply-all.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/reply-all.png,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/reply.png =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/reply.png,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/rol-dialog.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/rol-dialog.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/rol-dialog.js 31 Aug 2010 21:30:50 -0000 1.1 @@ -0,0 +1,113 @@ +//Se verifica si se debe de agregar el classname, si es mensaje de respuesta no se agrega +if ( document.getElementById('dialog_rol_set').value == 1) { + document.body.className += 'yui-skin-sam'; + document.documentElement.className = "yui-pe"; +} + +YAHOO.namespace("roles.container_roles"); + +YAHOO.util.Event.onDOMReady(function () { + + // Define various event handlers for Dialog + var handleSubmit = function() { + var formObject = document.getElementsByName('members_list'); + var form = formObject[0]; + var elements = form.elements; + var member_ids = ""; + var count = 0; + for ( var i = 0; i < elements.length ; i++) { + if (elements[i].checked && elements[i].name != '_dummy') { + count = count + 2; + member_ids = member_ids + elements[i].value + "," + elements[i+1].value + ","; + } + } + var total_members = document.getElementById('total_rel_members').value; + member_ids = member_ids.substring(0,member_ids.length-1); + member_ids = member_ids.split(','); + var recipients = ""; + var recipients_exists = document.getElementsByName('ids[]'); + var recipients_exists_ids = ""; + for ( var i = 0; i < document.getElementsByName('ids[]').length; i++) { + recipients_exists_ids = recipients_exists_ids + document.getElementsByName('ids[]')[i].value + ","; + } + for ( var i = 0; i < count; i = i + 2 ) { + var party_id = member_ids[i]; + var party_name = member_ids[i+1]; + if (recipients_exists_ids.match(party_id) == null) { + recipients = recipients + "<span id=span_" + party_id + " class=\"token\"><span><span><span><span><input type=\"hidden\" value=" + party_id + " name=\"ids[]\"/>" + party_name + "<span class=\"x\" onclick=id_delete(" + party_id + ")> </span></span></span></span></span></span>"; + } + } + var recipients_old = document.getElementById('contact_reply').innerHTML; + document.getElementById('contact_reply').innerHTML = recipients_old + recipients; + this.cancel(); + }; + + var handleCancel = function() { + this.cancel(); + }; + + var handleSuccess = function(o) { + alert("error"); + }; + var handleFailure = function(o) { + alert("Submission failed: " + o.status); + }; + + // Remove progressively enhanced content class, just before creating the module + YAHOO.util.Dom.removeClass("dialog2", "yui-pe-content"); + + // Instantiate the Dialog + YAHOO.roles.container_roles.dialog2 = new YAHOO.widget.Dialog("dialog2", + { width : "30em", + fixedcenter : true, + visible : false, + modal: true, + constraintoviewport : true, + buttons : [ { text:document.getElementById('add').value, handler:handleSubmit, isDefault:true }, + { text:"Cancel", handler:handleCancel } ] + }); + + // Validate the entries in the form to require that both first and last name are entered + YAHOO.roles.container_roles.dialog2.validate = function() { + var data = this.getData(); + if (data.firstname == "" || data.lastname == "") { + alert("Please enter your first and last names."); + return false; + } else { + return true; + } + }; + + // Wire up the success and failure handlers + YAHOO.roles.container_roles.dialog2.callback = { success: handleSuccess, + failure: handleFailure }; + + // Render the Dialog + YAHOO.roles.container_roles.dialog2.render(); + +}); + +function loading_dialog() { + document.getElementById('members_list_div').innerHTML = "<image src=/resources/ajaxhelper/images/indicator.gif>"; +} + +function search_members_rel_type () { + var data_search = document.getElementById('search_name').value; + var rel_type = document.getElementById('rel_type').value; + if (data_search == "") { + data_search = "none"; + } + var url_search = "members-rol"; + var postData = "data_search=" + data_search + "&rel_type=" + rel_type; + loading_dialog(); + var request = YAHOO.util.Connect.asyncRequest('POST', url_search, callback_rel_type,postData); +} + +var handleSuccess_rel_type = function(o){ + document.getElementById('members_list_div').innerHTML = o.responseText; +}; + +var handleFailure_rel_type = function(o){ +}; + +var callback_rel_type = {success:handleSuccess_rel_type,failure:handleFailure_rel_type}; \ No newline at end of file Index: openacs-4/packages/messages/www/resources/scriptaculous.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/scriptaculous.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/scriptaculous.js 31 Aug 2010 21:30:48 -0000 1.1 @@ -0,0 +1,35 @@ +var Scriptaculous = { + Version: '1.8.1', + require: function(libraryName) { + // inserting via DOM fails in Safari 2.0, so brute force approach + document.write('<script type="text/javascript" src="'+libraryName+'"><\/script>'); + }, + REQUIRED_PROTOTYPE: '1.6.0.2', + load: function() { + function convertVersionString(versionString) { + var v = versionString.replace(/_.*|\./g, ''); + v = parseInt(v + '0'.times(4-v.length)); + return versionString.indexOf('_') > -1 ? v-1 : v; + } + + if((typeof Prototype=='undefined') || + (typeof Element == 'undefined') || + (typeof Element.Methods=='undefined') || + (convertVersionString(Prototype.Version) < + convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE))) + throw("script.aculo.us requires the Prototype JavaScript framework >= " + + Scriptaculous.REQUIRED_PROTOTYPE); + + var js = /scriptaculous\.js(\?.*)?$/; + $$('head script[src]').findAll(function(s) { + return s.src.match(js); + }).each(function(s) { + var path = s.src.replace(js, ''), + includes = s.src.match(/\?.*load=([a-z,]*)/); + (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each( + function(include) { Scriptaculous.require(path+include+'.js') }); + }); + } +}; + +Scriptaculous.load(); \ No newline at end of file Index: openacs-4/packages/messages/www/resources/send.css =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/send.css,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/send.css 31 Aug 2010 21:30:51 -0000 1.1 @@ -0,0 +1,82 @@ +#D8D8D8 +/* common */ +body{background:#fff;font-family:"lucida grande", tahoma, verdana, arial, sans-serif;font-size:11px;margin:0px;padding:0px;text-align:left;} +a{cursor:pointer;color:black;text-decoration:none;} +a:hover{text-decoration:underline;} +.clearfix:after{content:".";display:block;clear:both;visibility:hidden;line-height:0;height:0;} +.clearfix{display:inline-block;} +html[xmlns] .clearfix{display:block;} +* html .clearfix{height:1%;} + + +.composer{padding-top:10px;padding-left:20px;padding:10px 0 10px 10px;background:#F0F0F0;} +.composer_fields { + margin:0; + width: 100%; +} +.composer_fields dt{float:left;width:65px;margin:0;padding:0 10px 0 0;text-align:right;} +.composer_fields label{display:block;padding-top:6px;} +.composer_fields .field label{padding-bottom:5px;} +.composer_fields dd{float:left;width:382px;margin:0 0 10px 0;} +.composer_fields .field input.inputtext, +.composer_fields .field textarea, +#compose_message div.tokenizer{border:1px solid #8496ba;} +#compose_message div.tokenizer{ + /*width:450px; */ +} + +.composer_fields .field #subject_field, +.composer_fields textarea{width:450px;margin:0;padding:5px 0 5px 3px;font-size:11px;} +.composer_fields textarea{height:100px;} + + +/* autcompleter.advancedlocal css */ +.tokenizer{min-height:5px;padding:0px 0px 3px 3px;width:99%;background:#fff;font-size:11px;} +.subject{min-height:5px;padding:0px 0px 3px 3px;width:99%;} +.tokenizer_locked{background:#f4f4f4;} +.tokenizer, +.tokenizer *{cursor:text} +.tokenizer input{width:100%;} +.tokenizer .tokenizer_input, +.tokenizer .token{float:left;margin-right:3px;margin-top:3px;} +.tokenizer .tab_stop, +.tokenizer .tokenizer_stretcher{display:block;float:left;overflow:hidden;width:0px;} +.tokenizer .tab_stop{height:0px;} +.tokenizer .tokenizer_stretcher{padding-top:7px;} +#autocomplete_input{width:20px;} +#autocomplete .tokenizer .tab_stop input{border:0px solid black;display:inline;position:relative;left:-500px;} +#autocomplete .tokenizer .tokenizer_input_borderless {left:4px;margin-left:-1px;overflow:hidden;position:relative;} +#autocomplete .tokenizer_input_borderless #autocomplete_input{border:3px solid white!important;border-left:none;display:block;margin:-3px 3px -4px -2px;padding:0px!important;} +/*IE6-/Win only*/ +/*\*/ * html#autocomplete .tokenizer_input_borderless #autocomplete_input { border:3px solid black;margin: -3px 3px -4px 14px:padding-left:10px; } /**/ +.tokenizer div:-moz-first-node{padding-top:1px!important;} +.tokenizer_input{max-width:450px;overflow:hidden;padding:1px 0px;} +#autocomplete .tokenizer_input input, +.tokenizer_input_shadow{border:0px solid black;outline:0;font-family:'lucida grande', tahoma, verdana, arial, sans-serif;font-size:11px;padding:0px 5px;margin:0 0 -1px 0;white-space:pre;} +.tokenizer_input_shadow{display:inline;left:-10000px;position:absolute;top:-10000px;} +.tokenizer .tokenizer_input_shadow{height:0px;display:block;left:0px;overflow:hidden;position:relative;top:0px;} +div.tokenizer .token{background-image:url('/resources/messages/inbox/images/token.gif');background-repeat:no-repeat;color:black;white-space:nowrap;} +div.tokenizer .token span{background-image:url('/resources/messages/inbox/images/token.gif');background-position:top right;background-repeat:no-repeat;display:block;} +div.tokenizer .token span span{background-position:bottom right;} +div.tokenizer .token span span span{background-position:bottom left;} +div.tokenizer .token span span span span{background-image:none;padding:2px 3px 2px 5px;} +div.tokenizer.tokenizer_locked .token span span span span{padding-right:5px;} +html div.tokenizer_locked .token:hover, +html div.tokenizer_locked .token:hover span{background-image:url('/resources/messages/inbox/images/token.gif');} +div.tokenizer .token:hover, +div.tokenizer .token:hover span{background-image:url('/resources/messages/inbox/images/token_hover.gif');text-decoration:none;} +div.tokenizer .token_selected, +div.tokenizer .token_selected span, +div.tokenizer .token_selected:hover, +div.tokenizer .token_selected:hover span{background-image:url('/resources/messages/inbox/images/token_selected.gif');color:white;text-decoration:none;} +div.tokenizer .token span.x, +div.tokenizer .token span.x_hover, +div.tokenizer .token:hover span.x, +div.tokenizer .token:hover span.x_hover{background-image:url('/resources/messages/inbox/images/token_x.gif');background-position:4px 2px;cursor:pointer;display:inline;padding:0px 6px 0px 5px;} +div.tokenizer.tokenizer_locked .token span.x, +div.tokenizer.tokenizer_locked .token span.x_hover{display:none;} +div.autocomplete { position:absolute; width:355px; background-color:white; border:1px solid #888; margin-top:-2px; padding:0px;} +div.autocomplete ul { list-style-type:none;margin:0px; padding:0px;} +div.autocomplete ul li.selected { background-color: #E0ECF8;} +div.autocomplete ul li { list-style-type:none; display:block; margin:0; padding:2px; height:32px;cursor:pointer;} +/* end of autcompleter.advancedlocal css */ \ No newline at end of file Index: openacs-4/packages/messages/www/resources/inbox/.svn/entries =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/inbox/.svn/entries,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/inbox/.svn/entries 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1,23 @@ +8 + +dir +0 +https://rorcraft.unfuddle.com/svn/rorcraft_rorcraft/website/output/autocomplete_advanced_local/inbox +https://rorcraft.unfuddle.com/svn/rorcraft_rorcraft +add + + + + + + + +svn:special svn:externals svn:needs-lock + +images +dir + + + +add + Index: openacs-4/packages/messages/www/resources/inbox/.svn/format =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/inbox/.svn/format,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/inbox/.svn/format 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1 @@ +8 Index: openacs-4/packages/messages/www/resources/inbox/images/token.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/inbox/images/token.gif,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/inbox/images/token_hover.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/inbox/images/token_hover.gif,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/inbox/images/token_selected.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/inbox/images/token_selected.gif,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/inbox/images/token_x.gif =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/inbox/images/token_x.gif,v diff -u Binary files differ Index: openacs-4/packages/messages/www/resources/inbox/images/.svn/entries =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/inbox/images/.svn/entries,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/inbox/images/.svn/entries 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1,72 @@ +8 + +dir +0 +https://rorcraft.unfuddle.com/svn/rorcraft_rorcraft/website/output/autocomplete_advanced_local/inbox/images +https://rorcraft.unfuddle.com/svn/rorcraft_rorcraft +add + + + + + + + +svn:special svn:externals svn:needs-lock + +token.gif +file + + + +add + + + + + +has-props +has-prop-mods + +token_hover.gif +file + + + +add + + + + + +has-props +has-prop-mods + +token_x.gif +file + + + +add + + + + + +has-props +has-prop-mods + +token_selected.gif +file + + + +add + + + + + +has-props +has-prop-mods + Index: openacs-4/packages/messages/www/resources/inbox/images/.svn/format =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/inbox/images/.svn/format,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/inbox/images/.svn/format 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1 @@ +8 Index: openacs-4/packages/messages/www/resources/inbox/images/.svn/props/token.gif.svn-work =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/inbox/images/.svn/props/token.gif.svn-work,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/inbox/images/.svn/props/token.gif.svn-work 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END Index: openacs-4/packages/messages/www/resources/inbox/images/.svn/props/token_hover.gif.svn-work =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/inbox/images/.svn/props/token_hover.gif.svn-work,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/inbox/images/.svn/props/token_hover.gif.svn-work 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END Index: openacs-4/packages/messages/www/resources/inbox/images/.svn/props/token_selected.gif.svn-work =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/inbox/images/.svn/props/token_selected.gif.svn-work,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/inbox/images/.svn/props/token_selected.gif.svn-work 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END Index: openacs-4/packages/messages/www/resources/inbox/images/.svn/props/token_x.gif.svn-work =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/resources/inbox/images/.svn/props/token_x.gif.svn-work,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/resources/inbox/images/.svn/props/token_x.gif.svn-work 31 Aug 2010 21:30:54 -0000 1.1 @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END Index: openacs-4/packages/messages/www/view/index.vuh =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages/www/view/index.vuh,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages/www/view/index.vuh 31 Aug 2010 21:30:45 -0000 1.1 @@ -0,0 +1,36 @@ +# packages/file-storage/www/download/index.vuh + +ad_page_contract { + + Virtual URL handler for file downloads + + @author Kevin Scaldeferri (kevin@arsdigita.com) + @author Don Baccus (simplified it by using cr utility) + @creation-date 18 December 2000 + @cvs-id $Id: index.vuh,v 1.1 2010/08/31 21:30:45 alvaror Exp $ +} { + file_id:integer,optional + version_id:integer,optional +} -validate { + either_one { + if { ! [info exists file_id] && ! [info exists version_id] } { + ad_complain "Either file_id or version_id must exist" + } + } +} + +if {![exists_and_not_null version_id] && [info exists file_id]} { + set version_id [item::get_live_revision $file_id] +} +if { ![exists_and_not_null file_id] && [info exists version_id] } { + set file_id [content::revision::item_id -revision_id $version_id] +} + +set user_id [ad_conn user_id] +permission::require_permission -party_id $user_id -object_id $version_id -privilege read + +if {[apm_package_installed_p views]} { + views::record_view -object_id $file_id -viewer_id $user_id +} + +cr_write_content -revision_id $version_id Index: openacs-4/packages/messages-portlet/tcl/apm-callback-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages-portlet/tcl/apm-callback-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages-portlet/tcl/apm-callback-procs.tcl 31 Aug 2010 21:31:49 -0000 1.1 @@ -0,0 +1,29 @@ +ad_library { + Procedures for initializing service contracts etc. for the + messages portlet package. Should only be executed + once upon installation. + + @creation-date 2010-01-20 + @author Pedro Castellanos (pedro@viaro.net) +} + +namespace eval apm::messages_portlet {} +namespace eval apm::messages_admin_portlet {} + +ad_proc -public apm::messages_portlet::after_install {} { + Create the datasources needed by the messages portlets. +} { + db_transaction { + messages_portlet::after_install + } +} + +ad_proc -public apm::messages_portlet::before_uninstall {} { + messages Portlet package uninstall proc +} { + db_transaction { + messages_portlet::uninstall + } +} + + Index: openacs-4/packages/messages-portlet/tcl/messages-portlet-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages-portlet/tcl/messages-portlet-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages-portlet/tcl/messages-portlet-procs.tcl 31 Aug 2010 21:31:49 -0000 1.1 @@ -0,0 +1,355 @@ +ad_library { + + Procedures to support the messages portlets + + @creation-date 2010-06-01 + @author Pedro Castellanos (pedro@viaro.net) + +} + +namespace eval messages_portlet {} +namespace eval messages_admin_portlet {} + + +# +# messages namespace +# + +ad_proc -private messages_portlet::get_my_name { +} { + return "messages_portlet" +} + + + +ad_proc -private messages_portlet::my_package_key { +} { + return "messages-portlet" +} + + + +ad_proc -public messages_portlet::get_pretty_name { +} { + return "#messages.messages#" +} + + + +ad_proc -public messages_portlet::link { +} { + return "" +} + + + +ad_proc -public messages_portlet::add_self_to_page { + {-portal_id:required} + {-package_id:required} + {-param_action:required} + {-force_region ""} + {-page_name "" } +} { + Adds a messages PE to the given portal. + + @param portal_id The page to add self to + @param package_id The community with the folder + + @return element_id The new element's id +} { + + ns_log Notice "portal_id:: $portal_id;; $page_name" + return [portal::add_element_parameters \ + -portal_id $portal_id \ + -portlet_name [get_my_name] \ + -value $package_id \ + -force_region $force_region \ + -page_name $page_name \ + -pretty_name [get_pretty_name] \ + -param_action $param_action + ] +} + + + +ad_proc -public messages_portlet::remove_self_from_page { + {-portal_id:required} + {-package_id:required} +} { + Removes a messages PE from the given page or the package_id of the + messages package from the portlet if there are others remaining + + @param portal_id The page to remove self from + @param package_id +} { + portal::remove_element_parameters \ + -portal_id $portal_id \ + -portlet_name [get_my_name] \ + -value $package_id +} + + + +ad_proc -public messages_portlet::show { + cf +} { + portal::show_proc_helper \ + -package_key [my_package_key] \ + -config_list $cf \ + -template_src "messages-portlet" +} + +# +# messages admin namespace +# + +ad_proc -private messages_admin_portlet::get_my_name {} { + return "messages_admin_portlet" +} + + +ad_proc -public messages_admin_portlet::get_pretty_name {} { + return "#messages.messages_Administration#" +} + + + +ad_proc -private messages_admin_portlet::my_package_key {} { + return "messages-portlet" +} + + + +ad_proc -public messages_admin_portlet::link {} { + return "" +} + + + +ad_proc -public messages_admin_portlet::add_self_to_page { + {-portal_id:required} + {-page_name ""} + {-package_id:required} +} { + Adds a messages admin PE to the given portal + + @param portal_id The page to add self to + @param package_id The package_id of the messages package + + @return element_id The new element's id +} { + return [portal::add_element_parameters \ + -portal_id $portal_id \ + -portlet_name [get_my_name] \ + -key package_id \ + -value $package_id + ] +} + +ad_proc -public messages_admin_portlet::remove_self_from_page { + {-portal_id:required} +} { + Removes a messages admin PE from the given page +} { + portal::remove_element \ + -portal_id $portal_id \ + -portlet_name [get_my_name] +} + + +ad_proc -public messages_admin_portlet::show { + cf +} { + portal::show_proc_helper \ + -package_key [my_package_key] \ + -config_list $cf \ + -template_src "messages-admin-portlet" +} + +ad_proc -private messages_portlet::after_install {} { + Create the datasources needed by the messages portlet. +} { + + db_transaction { + set ds_id [portal::datasource::new \ + -name "messages_portlet" \ + -description "Messages Portlet"] + + portal::datasource::set_def_param \ + -datasource_id $ds_id \ + -config_required_p t \ + -configured_p t \ + -key shadeable_p \ + -value t + + portal::datasource::set_def_param \ + -datasource_id $ds_id \ + -config_required_p t \ + -configured_p t \ + -key hideable_p \ + -value t + + portal::datasource::set_def_param \ + -datasource_id $ds_id \ + -config_required_p t \ + -configured_p t \ + -key user_editable_p \ + -value f + + portal::datasource::set_def_param \ + -datasource_id $ds_id \ + -config_required_p t \ + -configured_p t \ + -key shaded_p \ + -value f + + portal::datasource::set_def_param \ + -datasource_id $ds_id \ + -config_required_p t \ + -configured_p t \ + -key link_hideable_p \ + -value f + + portal::datasource::set_def_param \ + -datasource_id $ds_id \ + -config_required_p t \ + -configured_p f \ + -key package_id \ + -value "" + + register_portal_datasource_impl + + } +} + +ad_proc -private messages_portlet::register_portal_datasource_impl {} { + Create the service contracts needed by the messages portlet. +} { + set spec { + name "messages_portlet" + contract_name "portal_datasource" + owner "messages-portlet" + aliases { + GetMyName messages_portlet::get_my_name + GetPrettyName messages_portlet::get_pretty_name + Link messages_portlet::link + AddSelfToPage messages_portlet::add_self_to_page + Show messages_portlet::show + Edit messages_portlet::edit + RemoveSelfFromPage messages_portlet::remove_self_from_page + } + } + + acs_sc::impl::new_from_spec -spec $spec +} + +ad_proc -private messages_admin_portlet::after_install {} { + Create the datasources needed by the messages portlet. +} { + + db_transaction { + set ds_id [portal::datasource::new \ + -name "messages_admin_portlet" \ + -description "Messages Admin Portlet"] + + portal::datasource::set_def_param \ + -datasource_id $ds_id \ + -config_required_p t \ + -configured_p t \ + -key shadeable_p \ + -value f + + portal::datasource::set_def_param \ + -datasource_id $ds_id \ + -config_required_p t \ + -configured_p t \ + -key hideable_p \ + -value f + + portal::datasource::set_def_param \ + -datasource_id $ds_id \ + -config_required_p t \ + -configured_p t \ + -key user_editable_p \ + -value f + + portal::datasource::set_def_param \ + -datasource_id $ds_id \ + -config_required_p t \ + -configured_p t \ + -key shaded_p \ + -value f + + portal::datasource::set_def_param \ + -datasource_id $ds_id \ + -config_required_p t \ + -configured_p t \ + -key link_hideable_p \ + -value t + + portal::datasource::set_def_param \ + -datasource_id $ds_id \ + -config_required_p t \ + -configured_p f \ + -key package_id \ + -value "" + + register_portal_datasource_impl + } + +} + + + +ad_proc -private messages_admin_portlet::register_portal_datasource_impl {} { + Create the service contracts needed by the messages admin portlet. +} { + set spec { + name "messages_admin_portlet" + contract_name "portal_datasource" + owner "messages-portlet" + aliases { + GetMyName messages_admin_portlet::get_my_name + GetPrettyName messages_admin_portlet::get_pretty_name + Link messages_admin_portlet::link + AddSelfToPage messages_admin_portlet::add_self_to_page + Show messages_admin_portlet::show + Edit messages_admin_portlet::edit + RemoveSelfFromPage messages_admin_portlet::remove_self_from_page + } + } + + acs_sc::impl::new_from_spec -spec $spec +} + +ad_proc -private messages_portlet::uninstall {} { + messages Portlet package uninstall proc +} { + unregister_implementations + set ds_id [portal::get_datasource_id messages_portlet] + db_exec_plsql delete_messages_ds { *SQL* } +} + +ad_proc -private messages_admin_portlet::uninstall {} { + messages Portlet package uninstall proc +} { + unregister_implementations + set ds_id [portal::get_datasource_id messages_admin_portlet] + db_exec_plsql delete_admin_ds { *SQL* } +} + +ad_proc -private messages_portlet::unregister_implementations {} { + Unregister service contract implementations +} { + acs_sc::impl::delete \ + -contract_name "portal_datasource" \ + -impl_name "messages_portlet" +} + +ad_proc -private messages_admin_portlet::unregister_implementations {} { + Unregister service contract implementations +} { + acs_sc::impl::delete \ + -contract_name "portal_datasource" \ + -impl_name "messages_admin_portlet" +} Index: openacs-4/packages/messages-portlet/www/messages-admin-portlet.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages-portlet/www/messages-admin-portlet.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages-portlet/www/messages-admin-portlet.adp 31 Aug 2010 21:31:49 -0000 1.1 @@ -0,0 +1,5 @@ +<ul> + +</ul> + + Index: openacs-4/packages/messages-portlet/www/messages-admin-portlet.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages-portlet/www/messages-admin-portlet.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages-portlet/www/messages-admin-portlet.tcl 31 Aug 2010 21:31:49 -0000 1.1 @@ -0,0 +1,11 @@ + +ad_page_contract { + The display logic for the messages admin portlet + + @creation-date 2010-06-1 + @author Pedro Castellanos (pedro@viaro.net) +} { + +} -properties { + +} Index: openacs-4/packages/messages-portlet/www/messages-portlet.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages-portlet/www/messages-portlet.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages-portlet/www/messages-portlet.adp 31 Aug 2010 21:31:49 -0000 1.1 @@ -0,0 +1,8 @@ +<span style="margin-left:25px;font-weight: bold;">#messages.inbox# @data_info@</span> +<br> +<br> +<ul> + <li><a href="messages/messages">#messages.view_messages#</a></li> + <li><a href="messages/send">#messages.write_message#</a></li> + <li><a href="messages/message-option">#messages.configuration#</a></li> +</ul> \ No newline at end of file Index: openacs-4/packages/messages-portlet/www/messages-portlet.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages-portlet/www/messages-portlet.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages-portlet/www/messages-portlet.tcl 31 Aug 2010 21:31:49 -0000 1.1 @@ -0,0 +1,20 @@ +ad_page_contract { + The display logic for the messages portlet + + @author Pedro Castellanos (pedro@viaro.net) + @creation-date 2010-06-01 + +} { + +} + +append folder_ids [messages::get_folder_id -folder_name "inbox"] +set user_id [ad_conn user_id] +set community_id [dotlrn_community::get_community_id] +set folders_info [lindex [db_list_of_lists count_new_messages {}] 0] + +if { [llength $folders_info] } { + set data_info "([lindex $folders_info 0]/[lindex $folders_info 1])" +} else { + set data_info "" +} Index: openacs-4/packages/messages-portlet/www/messages-portlet.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/messages-portlet/www/messages-portlet.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/messages-portlet/www/messages-portlet.xql 31 Aug 2010 21:31:49 -0000 1.1 @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<queryset> + + <fullquery name="count_new_messages"> + <querytext> + select count (case when um.new_p = 't' then 1 end ) as new_t,count (um.new_p) as total + from (select distinct(parent_id) as msg_id,folder_id,new_p + from messages_user_messages + where user_id = :user_id + and folder_id not in ($folder_ids) + ) um, + (select msg_id + from messages_messages + where community_id = :community_id) m + where um.msg_id = m.msg_id + group by um.folder_id + order by folder_id + </querytext> + </fullquery> + +</queryset>