Index: openacs-4/packages/xowiki/tcl/form-field-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/form-field-procs.tcl,v
diff -u -r1.145 -r1.146
--- openacs-4/packages/xowiki/tcl/form-field-procs.tcl 3 Apr 2009 15:21:29 -0000 1.145
+++ openacs-4/packages/xowiki/tcl/form-field-procs.tcl 8 Apr 2009 10:59:42 -0000 1.146
@@ -1398,7 +1398,7 @@
if {![my exists options]} {my options [list]}
}
select instproc render_input {} {
- set atts [my get_attributes id name disabled]
+ set atts [my get_attributes id name disabled {CSSclass class}]
if {[my multiple]} {lappend atts multiple [my multiple]}
set options [my options]
if {![my required]} {
@@ -1466,6 +1466,59 @@
}
}
+ abstract_page instproc render_input {} {
+ if {[my multiple]} {
+ # utilities.js aggregates "yahoo, dom, event, connection, animation, dragdrop"
+ set ajaxhelper 0
+ ::xowiki::Includelet require_YUI_JS -ajaxhelper $ajaxhelper "utilities/utilities.js"
+ ::xowiki::Includelet require_YUI_JS -ajaxhelper $ajaxhelper "selector/selector-min.js"
+ ::xo::Page requireJS "/resources/xowiki/yui-selection-area.js"
+
+ set js ""
+ foreach o [my options] {
+ foreach {label rep} $o break
+ set js_label [::xowiki::Includelet js_encode $label]
+ set js_rep [::xowiki::Includelet js_encode $rep]
+ append js "YAHOO.xo_sel_area.DDApp.values\['$js_label'\] = '$js_rep';\n"
+ append js "YAHOO.xo_sel_area.DDApp.dict\['$js_rep'\] = '$js_label';\n"
+ }
+
+ ::html::div -class workarea {
+ ::html::h3 { ::html::t "Selection"}
+ set values ""
+ foreach v [my value] {
+ append values $v \n
+ set __values($v) 1
+ }
+ my CSSclass selection
+ my set cols 30
+ set atts [my get_attributes id name disabled {CSSclass class}]
+ # TODO what todo with DISABLED?
+ ::html::textarea [my get_attributes id name cols rows style {CSSclass class} disabled] {
+ ::html::t $values
+ }
+ }
+ ::html::div -class workarea {
+ ::html::h3 { ::html::t "Candidates"}
+ ::html::ul -id [my id]_candidates -class region {
+ #my msg [my options]
+ foreach o [my options] {
+ foreach {label rep} $o break
+ # Don't show current values under candidates
+ if {[info exists __values($rep)]} continue
+ ::html::li -class candidates {::html::t $rep}
+ }
+ }
+ }
+ ::html::div -class visual-clear {
+ ;# maybe some comment
+ }
+ ::html::script { html::t $js }
+ } else {
+ next
+ }
+ }
+
###########################################################
#
# ::xowiki::formfield::form_page
Index: openacs-4/packages/xowiki/tcl/includelet-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/includelet-procs.tcl,v
diff -u -r1.103 -r1.104
--- openacs-4/packages/xowiki/tcl/includelet-procs.tcl 3 Apr 2009 15:16:24 -0000 1.103
+++ openacs-4/packages/xowiki/tcl/includelet-procs.tcl 8 Apr 2009 10:59:43 -0000 1.104
@@ -97,6 +97,10 @@
return [string map [list : _ # _] $name]
}
+ ::xowiki::Includelet proc js_encode {string} {
+ string map [list \n \\n \" {\"} ' {\'}] $string
+ }
+
::xowiki::Includelet proc html_id {name} {
# Construct a valid HTML id or name.
# For details, see http://www.w3.org/TR/html4/types.html
@@ -129,30 +133,6 @@
return $link
}
- ::xowiki::Includelet proc incr_page_order {p} {
- regexp {^(.*[.]?)([^.])$} $p _ prefix suffix
- if {[string is integer -strict $suffix]} {
- incr suffix
- } elseif {[string is lower -strict $suffix]} {
- regexp {^(.*)(.)$} $suffix _ before last
- if {$last eq "z"} {
- set last "aa"
- } else {
- set last [format %c [expr {[scan $last %c] + 1}]]
- }
- set suffix $before$last
- } elseif {[string is upper -strict $suffix]} {
- regexp {^(.*)(.)$} $suffix _ before last
- if {$last eq "Z"} {
- set last "AA"
- } else {
- set last [format %c [expr {[scan $last %c] + 1}]]
- }
- set suffix $before$last
- }
- return $prefix$suffix
- }
-
::xowiki::Includelet proc publish_status_clause {{-base_table ci} value} {
if {$value eq "all"} {
# legacy
@@ -2305,6 +2285,7 @@
{-menu_buttons edit}
{-locale ""}
{-range ""}
+ {-allow_reorder ""}
}}
}
@@ -2315,6 +2296,23 @@
lappend ::xowiki_page_item_id_rendered [$__including_page item_id]
$__including_page set __is_book_page 1
+ if {$allow_reorder ne ""} {
+ set granted [$package_id check_permissions \
+ -user_id [[$package_id context] user_id] \
+ -package_id $package_id \
+ $package_id change_page_order]
+ #my msg "granted=$granted"
+ if {$granted} {
+ set ajaxhelper 0
+ ::xowiki::Includelet require_YUI_JS -ajaxhelper $ajaxhelper "utilities/utilities.js"
+ ::xowiki::Includelet require_YUI_JS -ajaxhelper $ajaxhelper "selector/selector-min.js"
+ ::xo::Page requireJS "/resources/xowiki/yui-page-order-region.js"
+ } else {
+ # the user has not enough permissions, so disallow
+ set allow_reorder ""
+ }
+ }
+
set extra_where_clause ""
set cnames ""
if {[info exists category_id]} {
@@ -2350,11 +2348,53 @@
}
}
+ if {$allow_reorder ne ""} {
+ set js "YAHOO.xo_page_order_region.DDApp.report_link = '[$package_id package_url]';\n"
+ set last_level 0
+ set ID [my js_name]
+ if {[string is integer -strict $allow_reorder]} {
+ set min_level $allow_reorder
+ } else {
+ set min_level 1
+ }
+ }
+
foreach o [$pages children] {
$o instvar page_order title page_id name title
- set level [expr {[regsub -all {[.]} $page_order . page_order] + 1}]
- set p [::xo::db::CrClass get_instance_from_db -item_id 0 -revision_id $page_id]
+ set level [expr {[regsub -all {[.]} $page_order _ page_order_js] + 1}]
+ if {$allow_reorder ne ""} {
+ #
+ # Build a (nested) list structure mirroring the hierarchy
+ # implied by the page_order. In essence, we provide CSS
+ # classes for the ULs and provide IDs for ULs and LI elements,
+ # and pass the associated page_order to javascript.
+ #
+ if {![regexp {^(.*)[.][^.]+$} $page_order _ prefix]} {set prefix ""}
+
+ # First, insert the appropriate opening and closing of ULs. We
+ # could handle here prefix changes as well as different lists
+ # (e.g. 1.1 1.2 2.1)
+ #
+ if {$last_level != $level} {
+ for {set l $last_level} {$l > $level} {incr l -1} {append output "\n" }
+ for {set l $last_level} {$l < $level} {incr l} {
+ regsub -all {[.]} $prefix _ prefix_js
+ set id ${ID}__l${level}_${prefix_js}
+ set css_class [expr {$l+1 >= $min_level ? "page_order_region" : "page_order_region_no_target"}]
+ append output "
\n"
+ }
+ set last_level $level
+ set last_prefix $prefix
+ }
+ # Pass the page_order for the element to javascript.
+ append js "YAHOO.xo_page_order_region.DDApp.cd\['${ID}_$page_order_js'\] = '$page_order';\n"
+ # Finally, add the li element for the section
+ append output "- "
+ }
+
+ set p [::xo::db::CrClass get_instance_from_db -item_id 0 -revision_id $page_id]
+
$p set unresolved_references 0
#$p set render_adp 0
switch [$p info class] {
@@ -2385,6 +2425,12 @@
"$page_order $title" \
$content
}
+
+ if {$allow_reorder ne ""} {
+ for {set l $last_level} {$l > 0} {incr l -1} {append output "
\n" }
+ append output "\n"
+ }
+
return $output
}
}
@@ -2528,7 +2574,7 @@
my get_parameters
my instvar __including_page return_url
set page [expr {[info exists page_id] ? $page_id : $__including_page}]
- set page_order [::xowiki::Includelet incr_page_order [$page page_order]]
+ set page_order [::xowiki::utility incr_page_order [$page page_order]]
if {[$page istype ::xowiki::FormPage]} {
set template [$page page_template]
return [my render_button \
Index: openacs-4/packages/xowiki/tcl/package-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/package-procs.tcl,v
diff -u -r1.168 -r1.169
--- openacs-4/packages/xowiki/tcl/package-procs.tcl 26 Mar 2009 13:19:31 -0000 1.168
+++ openacs-4/packages/xowiki/tcl/package-procs.tcl 8 Apr 2009 10:59:43 -0000 1.169
@@ -609,8 +609,8 @@
#
set exported [[my set policy] defined_methods Package]
foreach m $exported {
- #my msg "--QP my exists_query_parameter $m = [my exists_query_parameter $m]"
- if {[my exists_query_parameter $m]} {
+ #my log "--QP my exists_query_parameter $m = [my exists_query_parameter $m] || [my exists_form_parameter $m]"
+ if {[my exists_query_parameter $m] || [my exists_form_parameter $m]} {
set method $m ;# determining the method, similar file extensions
return [self]
}
@@ -971,6 +971,93 @@
}
#
+ # change_page_order (normally called via ajax POSTs)
+ #
+ Package ad_instproc change_page_order {} {
+ change_page_order for pages
+ } {
+ my instvar folder_id
+ set to [string trim [my form_parameter to ""]]
+ set from [string trim [my form_parameter from ""]]
+ set clean [string trim [my form_parameter clean ""]] ;# only for inserts
+
+ #set from {1.2 1.3 1.4}; set to {1.3 1.4 1.2}; set clean {...}
+ #set from {1.2 1.3 1.4}; set to {1.3 1.4 2.1 1.2}; set clean {2.1}
+ #set from {1 2}; set to {1 1.2 2}; set clean {1.2 1.3 1.4}
+
+ if {$from eq "" || $to eq "" || [llength $to]-[llength $from] >1 || [llength $to]-[llength $from]<0} {
+ my log "unreasonable request from='$from', to='$to'"
+ return
+ }
+ my log "--cpo from=$from, to=$to, clean=$clean"
+ set gap_renames [list]
+ #
+ # We distinguish two cases:
+ # - pure reordering: length(to) == length(from)
+ # - insert from another section: length(to) == length(from)+1
+ #
+ if {[llength $to] == [llength $from]} {
+ my log "--cpo reorder"
+ } elseif {[llength $clean] > 1} {
+ my log "--cpo insert"
+ #
+ # We have to fill the gap. First, find the newly inserted
+ # element in $to.
+ #
+ foreach e $to {
+ if {[lsearch -exact $from $e] == -1} {
+ set inserted $e
+ break
+ }
+ }
+ if {![info exists inserted]} {error "invalid 'to' list (no inserted element detected)"}
+ #
+ # compute the remaining list
+ #
+ set remaining [list]
+ foreach e $clean {if {$e ne $inserted} {lappend remaining $e}}
+ #
+ # compute rename rename commands for it
+ #
+ set gap_renames [::xowiki::utility page_order_renames -parent_id $folder_id \
+ -start [lindex $clean 0] -from $remaining -to $remaining]
+ foreach {page_id item_id name old_page_order new_page_order} $gap_renames {
+ my log "--cpo gap $page_id (name) rename $old_page_order to $new_page_order"
+ }
+ }
+ #
+ # Compute the rename commands for the drop target
+ #
+ set drop_renames [::xowiki::utility page_order_renames -parent_id $folder_id \
+ -start [lindex $from 0] -from $from -to $to]
+ #my log "--cpo drops l=[llength $drop_renames]"
+ foreach {page_id item_id name old_page_order new_page_order} $drop_renames {
+ my log "--cpo drop $page_id ($name) rename $old_page_order to $new_page_order"
+ }
+
+ #
+ # Perform the actual renames
+ #
+ set temp_obj [::xowiki::Page new -name dummy -volatile]
+ set slot [$temp_obj find_slot page_order]
+ db_transaction {
+ foreach {page_id item_id name old_page_order new_page_order} [concat $drop_renames $gap_renames] {
+ #my log "--cpo UPDATE $page_id new_page_order $new_page_order"
+ $temp_obj update_attribute_from_slot -revision_id $page_id $slot $new_page_order
+ ::xo::clusterwide ns_cache flush xotcl_object_cache ::$item_id
+ ::xo::clusterwide ns_cache flush xotcl_object_cache ::$page_id
+ }
+ }
+ #
+ # Flush the page fragement caches (page fragments based on page_order might be sufficient)
+ my flush_page_fragment_cache -scope agg
+
+ ns_return 200 text/plain ok
+ }
+
+
+
+ #
# RSS 2.0 support
#
Package ad_instproc rss {
@@ -1177,7 +1264,7 @@
if {![string is integer -strict $object_id]} { return [my error_msg "No valid object_id provided!"] }
# flush could be made more precise in the future
- [my id] flush_page_fragment_cache -scope agg
+ my flush_page_fragment_cache -scope agg
my returnredirect [site_node::get_package_url -package_key categories]cadmin/object-map?ctx_id=$object_id&object_id=$object_id
}
@@ -1193,7 +1280,7 @@
if {![string is integer -strict $tree_id]} { return [my error_msg "No valid tree_id provided!"] }
# flush could be made more precise in the future
- [my id] flush_page_fragment_cache -scope agg
+ my flush_page_fragment_cache -scope agg
my returnredirect [site_node::get_package_url -package_key categories]cadmin/tree-view?tree_id=$tree_id&ctx_id=$object_id&object_id=$object_id
}
@@ -1308,7 +1395,7 @@
switch -- $scope {
agg {set key PF-[my id]-agg-*}
all {set key PF-[my id]-*}
- default {error "unknown cope for flushing page fragment cache"}
+ default {error "unknown scope for flushing page fragment cache"}
}
foreach entry [ns_cache names xowiki_cache $key] {
ns_log notice "::xo::clusterwide ns_cache flush xowiki_cache $entry"
@@ -1350,6 +1437,7 @@
Class Package -array set require_permission {
reindex swa
+ change_page_order {{id admin}}
import_prototype_page swa
rss none
google-sitemap none
@@ -1406,6 +1494,7 @@
rss none
google-sitemap none
google-sitemapindex none
+ change_page_order {{id admin}}
manage-categories {{id admin}}
edit-category-tree {{id admin}}
delete swa
@@ -1459,6 +1548,7 @@
rss none
google-sitemap none
google-sitemapindex none
+ change_page_order {{id admin}}
manage-categories {{id admin}}
edit-category-tree {{id admin}}
delete swa
@@ -1515,6 +1605,7 @@
rss none
google-sitemap none
google-sitemapindex none
+ change_page_order {{id admin}}
manage-categories {{id admin}}
edit-category-tree {{id admin}}
delete swa
Index: openacs-4/packages/xowiki/tcl/xowiki-utility-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/xowiki-utility-procs.tcl,v
diff -u -r1.1 -r1.2
--- openacs-4/packages/xowiki/tcl/xowiki-utility-procs.tcl 6 Jan 2009 01:10:59 -0000 1.1
+++ openacs-4/packages/xowiki/tcl/xowiki-utility-procs.tcl 8 Apr 2009 10:59:43 -0000 1.2
@@ -308,4 +308,100 @@
return $msg
}
+ ::xowiki::utility proc incr_page_order {p} {
+ regexp {^(.*[.]?)([^.])$} $p _ prefix suffix
+ if {[string is integer -strict $suffix]} {
+ incr suffix
+ } elseif {[string is lower -strict $suffix]} {
+ regexp {^(.*)(.)$} $suffix _ before last
+ if {$last eq "z"} {
+ set last "aa"
+ } else {
+ set last [format %c [expr {[scan $last %c] + 1}]]
+ }
+ set suffix $before$last
+ } elseif {[string is upper -strict $suffix]} {
+ regexp {^(.*)(.)$} $suffix _ before last
+ if {$last eq "Z"} {
+ set last "AA"
+ } else {
+ set last [format %c [expr {[scan $last %c] + 1}]]
+ }
+ set suffix $before$last
+ }
+ return $prefix$suffix
+ }
+
+ ::xowiki::utility proc page_order_compute_new_names {start page_orders} {
+ lappend pairs [lindex $page_orders 0] $start
+ foreach p [lrange $page_orders 1 end] {
+ lappend pairs $p [set start [my incr_page_order $start]]
+ }
+ return $pairs
+ }
+
+ ::xowiki::utility proc get_page_order_items {-parent_id page_orders} {
+ set likes [list]
+ foreach page_order $page_orders {
+ if {[::xo::db::has_ltree]} {
+ lappend likes "p.page_order <@ '$page_order'"
+ } else {
+ lappend likes "p.page_order = '$page_order'" "p.page_order like '$page_order.%'"
+ }
+ }
+ set sql "select p.page_order, p.page_id, cr.item_id, ci.name
+ from xowiki_page p, cr_items ci, cr_revisions cr \
+ where p.page_id = ci.live_revision \
+ and p.page_id = cr.revision_id \
+ and ci.publish_status <> 'production' \
+ and ci.parent_id = $parent_id \
+ and ([join $likes { or }])"
+ my log $sql
+ set pages [db_list_of_lists [my qn get_pages_with_page_order] $sql]
+ return $pages
+ }
+
+ ::xowiki::utility proc page_order_renames {-parent_id -start -from -to} {
+ set pages [my get_page_order_items -parent_id $parent_id $to]
+ my log "pages=$pages"
+ array set npo [::xowiki::utility page_order_compute_new_names $start $to]
+ my log npo=[array get npo]=>to='$to'
+ set renames [list]
+ foreach tuple $pages {
+ foreach {old_page_order page_id item_id name} $tuple break
+ if {[info exists npo($old_page_order)]} {
+ #
+ # We have a name in the translation list
+ #
+ if {$npo($old_page_order) eq $old_page_order} {
+ # Nothing to do
+ #my log "--cpo name $old_page_order not changed"
+ } else {
+ #my log "--cpo name $old_page_order changed to '$npo($old_page_order)'"
+ lappend renames $page_id $item_id $name $old_page_order $npo($old_page_order)
+ }
+ } else {
+ #
+ # We have no translation in the list. This must be an item
+ # from a subtree of changed page_orders.
+ #
+ #my log "--cpo no translation for $old_page_order, check prefix"
+ foreach new_name [array names npo] {
+ if {[string match $new_name.* $old_page_order]} {
+ #
+ # The name matches. Add to the rename list if the prefix name actually changed.
+ #
+ if {$npo($new_name) ne $new_name} {
+ set l [string length $new_name]
+ set new_page_order "$npo($new_name)[string range $old_page_order $l end]"
+ my log "--cpo tree name $old_page_order changed to '$new_page_order'"
+ lappend renames $page_id $item_id $name $old_page_order $new_page_order
+ }
+ break
+ }
+ }
+ }
+ }
+ return $renames
+ }
}
Index: openacs-4/packages/xowiki/www/resources/xowiki.css
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/www/resources/xowiki.css,v
diff -u -r1.44 -r1.45
--- openacs-4/packages/xowiki/www/resources/xowiki.css 16 Feb 2009 12:11:55 -0000 1.44
+++ openacs-4/packages/xowiki/www/resources/xowiki.css 8 Apr 2009 10:59:43 -0000 1.45
@@ -314,7 +314,65 @@
margin: 0px; padding: 0px;
}
-/* child selectors are apparently not supported by IE 5 and 6,
+/* for yui dnd stuff */
+div.xowiki-content div.workarea { padding-right: 10px; float:left; }
+div.xowiki-content div.workarea h3 { margin-top: 0px; margin-bottom: 0.5ex;}
+
+div.xowiki-content ul.region {
+ border: 1px solid gray;
+ position: relative;
+ width: 300px;
+ list-style: none;
+ margin:0;
+ padding:0;
+ /*
+ The bottom padding provides the cushion that makes the empty
+ list targetable. Alternatively, we could leave the padding
+ off by default, adding it when we detect that the list is empty.
+ */
+ padding-bottom:3ex;
+}
+
+div.xowiki-content ul.region li {
+ margin: 1px;
+ cursor: move;
+}
+
+div.xowiki-content li.candidates {
+ background-color: #D1E6EC;
+ border:1px solid #7EA6B2;
+}
+
+div.xowiki-content li.selection {
+ background-color: #D8D4E2;
+ border:1px solid #6B4C86;
+}
+
+div.xowiki-content div.book ul.page_order_region {
+ border: 0px solid gray;
+ width: 100%;
+ list-style: none;
+ margin: 10px;
+ padding:0;
+ /*
+ The bottom padding provides the cushion that makes the empty
+ list targetable. Alternatively, we could leave the padding
+ off by default, adding it when we detect that the list is empty.
+ */
+ padding-bottom:3ex;
+}
+div.xowiki-content div.book ul.page_order_region_no_target {
+ border: 0px solid gray;
+ width: 100%;
+ list-style: none;
+ margin: 10px;
+ padding: 0;
+}
+
+/*
+ Handling hidden field-sets:
+
+ child selectors are apparently not supported by IE 5 and 6,
but the content is usable in IE anyhow; maybe we have to use the
parent-node hack
Index: openacs-4/packages/xowiki/www/resources/yui-page-order-region.js
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/www/resources/yui-page-order-region.js,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/xowiki/www/resources/yui-page-order-region.js 8 Apr 2009 10:59:43 -0000 1.1
@@ -0,0 +1,284 @@
+/*
+ * A simple drag and drop handler based on YUI for lists to be used
+ * e.g. with the book includelet.
+ *
+ * The handler knows about the two CSS
+ * classes page_order_region and page_order_region_no_target, where
+ * page_order_regions are used for drag and drop. The handler
+ * maintains client data (cd) associated with the list items, which
+ * has to be initialized by the application.
+ *
+ * Note: it might not be a good idea to use this with large list
+ * structures asi it is, since the drag-proxy might be quite large.
+ *
+ * Example usage with the book includelet:
+ *
+ * {{book -menu_buttons "edit create delete" -allow_reorder 2}}
+ *
+ * which means: only support drag&drop starting with the 2nd level
+ *
+ * Gustaf Neumann fecit April 2009
+ */
+
+YAHOO.namespace('xo_page_order_region');
+
+YAHOO.xo_page_order_region.DragnDrop = function() {
+
+ var Dom = YAHOO.util.Dom;
+ var Event = YAHOO.util.Event;
+ var DDM = YAHOO.util.DragDropMgr;
+
+YAHOO.xo_page_order_region.DDApp = {
+ with_DDTarget: 1,
+
+ report_link: "",
+ cd: new Array(),
+ source_region: new Array(),
+ level: new Array(),
+ highest_level: 0,
+ highest_region: 0,
+
+ init: function() {
+ // Ok, now we use standard drag and drop, modeled around the
+ // example from YUI dnd. We have now two HTML lists to be
+ // handled as regions for drag and drop.
+ //var regions = YAHOO.util.Selector.query('ul.page_order_region');
+ var regions = YAHOO.util.Selector.query('ul.page_order_region, ul.page_order_region_no_target');
+ for (var i = 0; i < regions.length; i++) {
+
+ if (this.with_DDTarget) {
+ new YAHOO.util.DDTarget(regions[i].id);
+ }
+
+ // compute the order of items per region
+ var order = "";
+ var items = regions[i].childNodes;
+
+ for (var j = 0; j < items.length; j++) {
+ if (items[j].nodeName != 'LI') {continue;}
+
+ // add the DDList only for list items in UL with class
+ // "page_order_region"
+ if (YAHOO.util.Dom.hasClass(regions[i],"page_order_region")) {
+ new YAHOO.xo_page_order_region.DDList(iid);
+ }
+
+ var iid = items[j].id;
+ // console.log(iid + " => " + this.cd[iid] );
+ order += this.cd[iid] + " ";
+ // Keep as well the source regions
+ this.source_region[iid] = regions[i];
+ }
+ // finally, remeber the level and store the original order
+ this.level[regions[i].id] = this.cd[iid].split(/[.]/g).length;
+ this.cd[regions[i].id] = order;
+ //console.log("initial region: " + regions[i].id + " => " + order);
+ }
+ },
+
+ report_level: function(id, e) {
+ if (this.level[id] != undefined) {
+ // Keep the highest level in case we drop on nested targets
+ if (this.highest_level < this.level[id]) {
+ this.highest_level = this.level[id];
+ this.highest_region = id;
+ }
+ }
+ },
+
+ finish: function(e) {
+
+ //console.log("finish " + this.highest_region);
+ // if we have no highest_region, the drop was not on a drop target
+ if (this.highest_region == 0) {
+ // get the ul via the provided element. This might not be the
+ // list you are expecting, if there are nested lists.
+ var ul = document.getElementById(e.id).parentNode;
+ //console.info(ul);
+ } else {
+ // The variable highest_region is only used, if ul's are
+ // defined as DDTargets
+ var ul = document.getElementById(this.highest_region);
+ }
+
+ //console.log(this.cd[e.id] + " landed in region "+ ul.id + " => " + this.cd[ul.id]);
+
+ // Process childNodes of the ul simply to avoid to include
+ // nested items
+ var order = "";
+ var items = ul.childNodes;
+
+ for (var j = 0; j < items.length; j++) {
+ if (items[j].nodeName != 'LI') {continue;}
+ var iid = items[j].id;
+ order += this.cd[iid] + " ";
+ //console.log(iid + " => " + this.cd[iid]);
+ }
+
+ //console.log(this.cd[ul.id] + " => " + order + " => " + this.cd[this.source_region[e.id].id]);
+
+ if (this.report_link != '' && order != '') {
+ this.callback = {
+ success: function(o) {
+ //window.location.href=window.location.href;
+ window.location.reload();
+ }
+ }
+ YAHOO.util.Connect.asyncRequest('POST', this.report_link, this.callback,
+ 'change_page_order=1' +
+ '&from=' + escape(this.cd[ul.id]) +
+ '&to=' + escape(order) +
+ '&clean=' + escape(this.cd[this.source_region[e.id].id]));
+ }
+ },
+
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// custom drag and drop implementation
+//////////////////////////////////////////////////////////////////////////////
+
+YAHOO.xo_page_order_region.DDList = function(id, sGroup, config) {
+
+ YAHOO.xo_page_order_region.DDList.superclass.constructor.call(this, id, sGroup, config);
+
+ var el = this.getDragEl();
+ Dom.setStyle(el, "opacity", 0.67); // The proxy is slightly transparent
+
+ this.goingUp = false;
+ this.lastY = 0;
+};
+
+YAHOO.extend(YAHOO.xo_page_order_region.DDList, YAHOO.util.DDProxy, {
+
+ startDrag: function(x, y) {
+
+ // make the proxy look like the source element
+ var dragEl = this.getDragEl();
+ var clickEl = this.getEl();
+ Dom.setStyle(clickEl, "visibility", "hidden");
+
+ dragEl.innerHTML = clickEl.innerHTML;
+
+ Dom.setStyle(dragEl, "color", Dom.getStyle(clickEl, "color"));
+ Dom.setStyle(dragEl, "backgroundColor", Dom.getStyle(clickEl, "backgroundColor"));
+ Dom.setStyle(dragEl, "border", "2px solid gray");
+
+ // make sure, this is always initialized
+ YAHOO.xo_page_order_region.DDApp.highest_region = 0;
+ },
+
+ endDrag: function(e) {
+ //console.log("endDrag");
+ var srcEl = this.getEl();
+ var proxy = this.getDragEl();
+
+ // Show the proxy element and animate it to the src element's location
+ Dom.setStyle(proxy, "visibility", "");
+ var a = new YAHOO.util.Motion(
+ proxy, {
+ points: {
+ to: Dom.getXY(srcEl)
+ }
+ },
+ 0.2,
+ YAHOO.util.Easing.easeOut
+ )
+ var proxyid = proxy.id;
+ var thisid = this.id;
+
+ // Hide the proxy and show the source element when finished with the animation
+ a.onComplete.subscribe(function() {
+ Dom.setStyle(proxyid, "visibility", "hidden");
+ Dom.setStyle(thisid, "visibility", "");
+ });
+ a.animate();
+ YAHOO.xo_page_order_region.DDApp.finish(this);
+ },
+
+ onDragDrop: function(e, id) {
+ //console.log("onDragDrop");
+ // If there is one drop interaction, the li was dropped either on the list,
+ // or it was dropped on the current location of the source element.
+ if (DDM.interactionInfo.drop.length === 1) {
+
+ // The position of the cursor at the time of the drop (YAHOO.util.Point)
+ var pt = DDM.interactionInfo.point;
+
+ // The region occupied by the source element at the time of the drop
+ var region = DDM.interactionInfo.sourceRegion;
+
+ // Check to see if we are over the source element's location. We will
+ // append to the bottom of the list once we are sure it was a drop in
+ // the negative space (the area of the list without any list items)
+ if (!region.intersect(pt)) {
+ var destEl = Dom.get(id);
+ var destDD = DDM.getDDById(id);
+ destEl.appendChild(this.getEl());
+ destDD.isEmpty = false;
+ DDM.refreshCache();
+ //console.log('no intersect');
+ } else {
+ // console.log('intersect');
+ }
+ } else {
+ // console.log('interactions l=' + DDM.interactionInfo.drop.length);
+ }
+ YAHOO.xo_page_order_region.DDApp.report_level(id, this);
+ },
+
+ onDrag: function(e) {
+
+ // Keep track of the direction of the drag for use during onDragOver
+ var y = Event.getPageY(e);
+
+ if (y < this.lastY) {
+ this.goingUp = true;
+ } else if (y > this.lastY) {
+ this.goingUp = false;
+ }
+
+ this.lastY = y;
+ },
+
+ onDragEnter: function(e, id) {
+ var destEl = Dom.get(id);
+ var p = destEl.parentNode;
+ Dom.setStyle(p, "border", "1px dotted green");
+ Dom.setStyle(p, "margin", "10px");
+ },
+
+ onDragOut: function(e, id) {
+ var destEl = Dom.get(id);
+ var p = destEl.parentNode;
+ Dom.setStyle(p, "border", "0px");
+ Dom.setStyle(p, "margin", "0px");
+ },
+
+ onDragOver: function(e, id) {
+
+ var srcEl = this.getEl();
+ var destEl = Dom.get(id);
+
+ // We are only concerned with list items, we ignore the dragover
+ // notifications for the list.
+ if (destEl.nodeName.toLowerCase() == "li") {
+ var orig_p = srcEl.parentNode;
+ var p = destEl.parentNode;
+
+ if (this.goingUp) {
+ p.insertBefore(srcEl, destEl); // insert above
+ } else {
+ p.insertBefore(srcEl, destEl.nextSibling); // insert below
+ }
+
+ DDM.refreshCache();
+ }
+ }
+});
+
+Event.onDOMReady(YAHOO.xo_page_order_region.DDApp.init, YAHOO.xo_page_order_region.DDApp, true);
+};
+
+YAHOO.xo_page_order_region.DragnDrop();
+
Index: openacs-4/packages/xowiki/www/resources/yui-selection-area.js
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/www/resources/Attic/yui-selection-area.js,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/xowiki/www/resources/yui-selection-area.js 8 Apr 2009 10:59:43 -0000 1.1
@@ -0,0 +1,237 @@
+/*
+ * A simple drag and drop handler based on YUI for lists to be used
+ * e.g. with the the form-fields of type abstract_page (e.g. form_page
+ * or page) with mutliple entries.
+ *
+ * The handler knows about the CSS class textarea.selection, makes it
+ * invisible and replaces it by a list (selected items). It handles
+ * actually ULs of class region which are treated as candidates. The
+ * candidates list is build by the application. On drag and drop, this code
+ * maintains the entries in textarea.
+ *
+ *
+ * Gustaf Neumann fecit April 2009
+ */
+YAHOO.namespace('xo_sel_area');
+
+YAHOO.xo_sel_area.DragnDrop = function() {
+
+ var Dom = YAHOO.util.Dom;
+ var Event = YAHOO.util.Event;
+ var DDM = YAHOO.util.DragDropMgr;
+
+YAHOO.xo_sel_area.DDApp = {
+ dict: new Array(),
+ values: new Array(),
+
+ init: function() {
+ // console.log("init called");
+ // console.info(this);
+ //
+ // Find all textareas which class selection (maybe further restrict in the future)
+ var textareas = YAHOO.util.Selector.query('textarea.selection');
+ for (var i = 0; i < textareas.length; i++) {
+ var textarea = textareas[i];
+ // We found such an textarea. The lines of the textarea are
+ // treated as the selected values (internal representations).
+ var items = textarea.value.split(/\n/g);
+ var selected_LIs = "";
+ // For all these items, build an HTML list with the labels
+ // (external representations).
+ for (var j = 0; j < items.length; j++) {
+ var o = items[j];
+ if (o == "") continue;
+ selected_LIs += "" + this.dict[o] + "\n";
+ }
+
+ // Map in the candidates the internal representation to an
+ // external one.
+ var candidates = document.getElementById(textarea.id + "_candidates");
+ var items = candidates.getElementsByTagName("li");
+ for (var j = 0; j < items.length; j++) {
+ items[j].innerHTML = this.dict[items[j].innerHTML];
+ }
+
+ // Insert the generated HTML list and hide the textarea
+ var html = "\n";
+ textarea.style.display = "none";
+ var div = document.createElement('div');
+ div.innerHTML = html;
+ Dom.insertBefore(div,textarea);
+ //console.log(html);
+ }
+
+ // Ok, now we use standard drag and drop, modeled around the
+ // example from YUI dnd. We have now two HTML lists to be
+ // handled as regions for drag and drop.
+ var regions = YAHOO.util.Selector.query('ul.region');
+ for (var i = 0; i < regions.length; i++) {
+ new YAHOO.util.DDTarget(regions[i].id);
+ var items = regions[i].getElementsByTagName("li");
+ for (var j = 0; j < items.length; j++) {
+ var id = regions[i].id + '__' + j;
+ // setting the ids (note: will overwrite prexising ids on dnd items)
+ items[j].id = id;
+ new YAHOO.xo_sel_area.DDList(id);
+ }
+ }
+ },
+
+ build_selection: function(id) {
+ // We get called with the id of the drop target (the list)
+ var selection_id;
+ if (id.match(/_selection$/)) {
+ selection_id = id.replace(/_selection$/,"");
+ } else {
+ selection_id = id.replace(/_candidates$/,"");
+ }
+ // console.log("selection_id " + selection_id);
+
+ var textarea = document.getElementById(selection_id);
+ var selection_list = document.getElementById(selection_id + "_selection");
+ var items = selection_list.getElementsByTagName("li");
+ var values = "";
+ for (var j = 0; j < items.length; j++) {
+ var item = items[j];
+ if (this.values[item.innerHTML] == undefined ) {
+ console.log(" undefined : "+ item.innerHTML);
+ console.info(this);
+ console.info(YAHOO.xo_sel_area.DDApp);
+ for (var i = 0; i < this.values.length; i++) {
+ console.log(" defined : "+ this.values[i]);
+ }
+ } else {
+ values += this.values[item.innerHTML] + "\n";
+ }
+ }
+ textarea.value = values;
+ },
+
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// custom drag and drop implementation
+//////////////////////////////////////////////////////////////////////////////
+
+YAHOO.xo_sel_area.DDList = function(id, sGroup, config) {
+
+ YAHOO.xo_sel_area.DDList.superclass.constructor.call(this, id, sGroup, config);
+
+ var el = this.getDragEl();
+ Dom.setStyle(el, "opacity", 0.67); // The proxy is slightly transparent
+
+ this.goingUp = false;
+ this.lastY = 0;
+};
+
+YAHOO.extend(YAHOO.xo_sel_area.DDList, YAHOO.util.DDProxy, {
+
+ startDrag: function(x, y) {
+
+ // make the proxy look like the source element
+ var dragEl = this.getDragEl();
+ var clickEl = this.getEl();
+ Dom.setStyle(clickEl, "visibility", "hidden");
+
+ dragEl.innerHTML = clickEl.innerHTML;
+
+ Dom.setStyle(dragEl, "color", Dom.getStyle(clickEl, "color"));
+ Dom.setStyle(dragEl, "backgroundColor", Dom.getStyle(clickEl, "backgroundColor"));
+ Dom.setStyle(dragEl, "border", "2px solid gray");
+ },
+
+ endDrag: function(e) {
+
+ var srcEl = this.getEl();
+ var proxy = this.getDragEl();
+
+ // Show the proxy element and animate it to the src element's location
+ Dom.setStyle(proxy, "visibility", "");
+ var a = new YAHOO.util.Motion(
+ proxy, {
+ points: {
+ to: Dom.getXY(srcEl)
+ }
+ },
+ 0.2,
+ YAHOO.util.Easing.easeOut
+ )
+ var proxyid = proxy.id;
+ var thisid = this.id;
+
+ // Hide the proxy and show the source element when finished with the animation
+ a.onComplete.subscribe(function() {
+ Dom.setStyle(proxyid, "visibility", "hidden");
+ Dom.setStyle(thisid, "visibility", "");
+ });
+ a.animate();
+ },
+
+ onDragDrop: function(e, id) {
+
+ // If there is one drop interaction, the li was dropped either on the list,
+ // or it was dropped on the current location of the source element.
+ if (DDM.interactionInfo.drop.length === 1) {
+
+ // The position of the cursor at the time of the drop (YAHOO.util.Point)
+ var pt = DDM.interactionInfo.point;
+
+ // The region occupied by the source element at the time of the drop
+ var region = DDM.interactionInfo.sourceRegion;
+
+ // Check to see if we are over the source element's location. We will
+ // append to the bottom of the list once we are sure it was a drop in
+ // the negative space (the area of the list without any list items)
+ if (!region.intersect(pt)) {
+ var destEl = Dom.get(id);
+ var destDD = DDM.getDDById(id);
+ destEl.appendChild(this.getEl());
+ destDD.isEmpty = false;
+ DDM.refreshCache();
+ }
+
+ }
+ YAHOO.xo_sel_area.DDApp.build_selection(id);
+ },
+
+ onDrag: function(e) {
+
+ // Keep track of the direction of the drag for use during onDragOver
+ var y = Event.getPageY(e);
+
+ if (y < this.lastY) {
+ this.goingUp = true;
+ } else if (y > this.lastY) {
+ this.goingUp = false;
+ }
+
+ this.lastY = y;
+ },
+
+ onDragOver: function(e, id) {
+
+ var srcEl = this.getEl();
+ var destEl = Dom.get(id);
+
+ // We are only concerned with list items, we ignore the dragover
+ // notifications for the list.
+ if (destEl.nodeName.toLowerCase() == "li") {
+ var orig_p = srcEl.parentNode;
+ var p = destEl.parentNode;
+
+ if (this.goingUp) {
+ p.insertBefore(srcEl, destEl); // insert above
+ } else {
+ p.insertBefore(srcEl, destEl.nextSibling); // insert below
+ }
+
+ DDM.refreshCache();
+ }
+ }
+});
+
+Event.onDOMReady(YAHOO.xo_sel_area.DDApp.init, YAHOO.xo_sel_area.DDApp, true);
+};
+
+YAHOO.xo_sel_area.DragnDrop();
+