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 -N -r1.239.2.10 -r1.239.2.11 --- openacs-4/packages/xowiki/tcl/includelet-procs.tcl 10 May 2019 22:53:10 -0000 1.239.2.10 +++ openacs-4/packages/xowiki/tcl/includelet-procs.tcl 12 May 2019 20:02:46 -0000 1.239.2.11 @@ -1411,7 +1411,6 @@ my-tags instproc render {} { :get_parameters - ::xo::Page requireJS urn:ad:js:get-http-object set p_link [${:__including_page} pretty_link] set return_url [::xo::cc url]?[::xo::cc actual_query] @@ -1867,7 +1866,10 @@ # includelets based on order # Class create PageReorderSupport - PageReorderSupport instproc page_reorder_check_allow {{-with_head_entries true} allow_reorder} { + PageReorderSupport instproc page_reorder_check_allow { + {-with_head_entries true} + allow_reorder + } { if {$allow_reorder ne ""} { set granted [::${:package_id} check_permissions \ -user_id [[::${:package_id} context] user_id] \ @@ -1876,10 +1878,11 @@ #:msg "granted=$granted" if {$granted} { if {$with_head_entries} { - set ajaxhelper 1 - ::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" + #set ajaxhelper 1 + #::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" + ::xo::Page requireJS "/resources/xowiki/listdnd.js" } } else { # the user has not enough permissions, so disallow @@ -1891,7 +1894,7 @@ PageReorderSupport instproc page_reorder_init_vars {-allow_reorder js_ last_level_ ID_ min_level_} { :upvar $js_ js $last_level_ last_level $ID_ ID $min_level_ min_level - set js "YAHOO.xo_page_order_region.DDApp.package_url = '[::${:package_id} package_url]';\n" + #set js "YAHOO.xo_page_order_region.DDApp.package_url = '[::${:package_id} package_url]';\n" set last_level 0 set ID [:js_name] if {[string is integer -strict $allow_reorder]} { @@ -1911,13 +1914,17 @@ set key :__count($prefix_js) set p [incr $key] set id ${ID}_${prefix_js}_$p - append js "YAHOO.xo_page_order_region.DDApp.cd\['$id'\] = '$page_order';\n" + #append js "YAHOO.xo_page_order_region.DDApp.cd\['$id'\] = '$page_order';\n" return $id } # # toc -- Table of contents # + # The "toc" includelet renders the page titles of the current files + # based on the value of the "page_order" attributes. Only those + # pages are rendered that have a non-empty "page_order" field. + # ::xowiki::IncludeletClass create toc \ -superclass ::xowiki::Includelet \ -instmixin PageReorderSupport \ @@ -2260,22 +2267,32 @@ toc instproc render_tree {{-full false} pages} { :get_parameters - set tree [::xowiki::Tree new -destroy_on_cleanup -orderby pos -id [:id] -verbose 1] + set tree [::xowiki::Tree new -destroy_on_cleanup \ + -orderby pos \ + -id [:id] \ + -verbose 0 \ + -owner [self]] $tree array set open_node [array get :open_node] $tree add_pages -full $full -remove_levels $remove_levels \ -book_mode $book_mode -open_page $open_page \ -owner [self] \ $pages - set HTML [$tree render -style ${:renderer}] + if {$allow_reorder ne ""} { + set allow_reorder [:page_reorder_check_allow -with_head_entries false $allow_reorder] + } + + if {$allow_reorder ne ""} { + :page_reorder_init_vars -allow_reorder $allow_reorder js last_level ID min_level + #:log "=== call tree render [list $tree render -style listdnd] min_level=$min_level" + set HTML [$tree render -style listdnd -context [list min_level $min_level]] + } else { + set HTML [$tree render -style list] + } #:log "render_tree HTML => $HTML" return $HTML } - toc instproc parent_id {} { - ${:__including_page} parent_id - } - toc instproc render_list {{-full false} pages} { :get_parameters @@ -2292,15 +2309,16 @@ } set tree [::xowiki::Tree new -destroy_on_cleanup -orderby pos -id [:id]] $tree array set open_node [array get :open_node] - $tree add_pages -full $full -remove_levels $remove_levels \ + $tree add_pages -full $full \ + -remove_levels $remove_levels \ -book_mode $book_mode -open_page $open_page -expand_all $expand_all \ -owner [self] \ $pages if {$allow_reorder ne ""} { :page_reorder_init_vars -allow_reorder $allow_reorder js last_level ID min_level - set js "\nYAHOO.xo_page_order_region.DDApp.package_url = '[::$package_id package_url]';" - set HTML [$tree render -style listdnd -js $js -context [list min_level $min_level]] + #set js "\nYAHOO.xo_page_order_region.DDApp.package_url = '[::$package_id package_url]';" + set HTML [$tree render -style listdnd -context [list min_level $min_level]] } else { set HTML [$tree render -style list] } @@ -2389,7 +2407,7 @@ # of the toc-specific renderers, but first we have to check, if # these are fully feature-compatible. # - + #:log "=== toc render with <${:renderer}> treerenderer ${:use_tree_renderer} list_mode <${:list_mode}>" if {${:renderer} eq "none"} { } elseif {${:use_tree_renderer}} { return [:render_tree -full 1 $pages] Index: openacs-4/packages/xowiki/tcl/tree-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/tree-procs.tcl,v diff -u -N -r1.23 -r1.23.2.1 --- openacs-4/packages/xowiki/tcl/tree-procs.tcl 11 Jul 2018 13:46:15 -0000 1.23 +++ openacs-4/packages/xowiki/tcl/tree-procs.tcl 12 May 2019 20:02:46 -0000 1.23.2.1 @@ -17,6 +17,7 @@ -superclass ::xo::OrderedComposite \ -parameter { {name ""} + {owner} {verbose 0} id } @@ -172,7 +173,9 @@ append content [:render_node -open true $cat_content] } - if {${:verbose}} {:log "TreeNode items [:isobject [self]::items] render open_requests ${:open_requests} -> $content"} + if {${:verbose}} { + :log "TreeNode items [:isobject [self]::items] render open_requests ${:open_requests} -> $content" + } return $content } @@ -259,8 +262,10 @@ set h_atts [lindex [$cl highlight_atts] [expr {${:highlight} ? 0 : 1}]] set u_atts "" - if {[info exists :li_id]} {append o_atts " id='${:li_id}'"} - if {[info exists :ul_id]} {append u_atts " id='${:ul_id}'"} + if {[info exists :li_id]} {append o_atts " id='${:li_id}'"} + if {[info exists :li_atts]} {append o_atts " ${:li_atts}"} + if {[info exists :ul_id]} {append u_atts " id='${:ul_id}'"} + if {[info exists :ul_atts]} {append u_atts " ${:ul_atts}"} if {[info exists :ul_class]} {append u_atts " class='${:ul_class}'"} set label [::xowiki::Includelet html_encode [:label]] @@ -281,7 +286,7 @@ } else { set content "" } - return "
  • ${:prefix} $entry$content" + return "
  • ${:prefix} $entry$content
  • " } #-------------------------------------------------------------------------------- @@ -419,42 +424,87 @@ #-------------------------------------------------------------------------------- - # list-specific render with YUI drag and drop functionality + # list-specific render with drag and drop functionality #-------------------------------------------------------------------------------- TreeRenderer create TreeRenderer=listdnd \ -superclass TreeRenderer=list \ -li_expanded_atts [list "" ""] TreeRenderer=listdnd proc include_head_entries {args} { - set ajaxhelper 0 - ::xo::Page requireJS urn:ad:js:yui2:utilities/utilities - ::xo::Page requireJS urn:ad:js:yui2:selector/selector-min - ::xo::Page requireJS "/resources/xowiki/yui-page-order-region.js" + ::xo::Page requireJS "/resources/xowiki/listdnd.js" } + TreeRenderer=listdnd proc min_level {} { + if {[dict exists ${:context} min_level]} { + return [dict get ${:context} min_level] + } + return "" + } + TreeRenderer=listdnd proc add_handler {-id -event} { + template::add_event_listener \ + -id $id \ + -event $event \ + -preventdefault=false \ + -script "listdnd_${event}_handler(event);" + } + TreeRenderer=listdnd proc render {tree} { - array set "" ${:context} - if {[info exists (min_level)] && $(min_level) == 1} { - set css_class "page_order_region" + #:log "=== TreeRenderer=listdnd render $tree" + # + # Do we allow reorder on the toplevel? + # + if {[:min_level] == 1} { + set css_class "page_order_region" + set id [$tree id]-topul + foreach event {drop dragover dragleave} { + :add:handler -id $id -event $event + } } else { set css_class "page_order_region_no_target" } - return "
    " + :log "=== TreeRenderer=listdnd render $tree min_level <[:min_level]>" + if {[$tree exists owner]} { + # + # assume, the "owner" is an includelet. + set owner [$tree set owner] + set page [$owner set __including_page] + set package_url [::[$page package_id] package_url] + set package_url_data " data-package_url='$package_url' data-folder_id='[$page parent_id]'" + } else { + set package_url_data "" + } + + return [subst {
    +
    + }] } TreeRenderer=listdnd instproc render_node {{-open:boolean false} cat_content} { + #:log "=== TreeRenderer=listdnd render_node $cat_content" #set open_state [expr {${:open_requests} > 0 ?"class='liOpen'" : "class='liClosed'"}] - #set cl [lindex [:info precedence] 0] - set obj ${:object} - set o [:owner] - $obj instvar page_order - set :li_id [::xowiki::Includelet js_name [$o set id]_$page_order] - set :ul_id [::xowiki::Includelet js_name [$o set id]__l${:level}_$page_order] + ${:object} instvar page_order - set cl [self class] - $cl append js "\nYAHOO.xo_page_order_region.DDApp.cd\['${:li_id}'\] = '$page_order';" + set :li_id [::xowiki::Includelet js_name [${:owner} set id]_$page_order] + set :ul_id [::xowiki::Includelet js_name [${:owner} set id]__l${:level}_$page_order] + + set min_level [[self class] min_level] + set reorder_child [expr {$min_level ne "" && ${:level} >= $min_level}] + set reorder_self [expr {$min_level ne "" && ${:level} > $min_level}] + :log "=== render_node $page_order min_level $min_level level ${:level} reorder_child $reorder_child reorder_self $reorder_self" - array set "" [$cl set context] - set :ul_class [expr {[info exists (min_level)] && ${:level} >= $(min_level) ? - "page_order_region" : "page_order_region_no_target"}] + if {$reorder_child} { + foreach event {drop dragover dragleave} { + [self class] add_handler -id ${:ul_id} -event $event + } + set :ul_class "page_order_region" + } else { + set :ul_class "page_order_region_no_target" + } + if {$reorder_self} { + set :li_atts [subst {data-value='$page_order' draggable='true'}] + [self class] add_handler -id ${:li_id} -event dragstart + } + set :ul_id [::xowiki::Includelet js_name [${:owner} set id]__l${:level}_$page_order] + return [next] } Index: openacs-4/packages/xowiki/www/resources/listdnd.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/www/resources/Attic/listdnd.js,v diff -u -N --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/xowiki/www/resources/listdnd.js 12 May 2019 20:02:46 -0000 1.1.2.1 @@ -0,0 +1,157 @@ +/* + * Drag and drop for reordering table of contents (toc) items based on + * the tree renderer "listdnd" using HTML5. This code is intended to + * behave similar as the previous solution based on YUI2. + * + * The CSS part of this handler is placed in xowiki.css, using the + * classes "page_order_region", "page_order_region_no_target", + * "mark-above", "mark-below". + * + * In essence, the implementation uses darag and drop of list items + * between potentially different lists and issues AJAX requests to the + * backend to reflect these changes in the database. Since the order + * of the items in a "toc" is determiend by the "page_order" attribute + * in the database, it reports the changed lists of page_orders back. + * + * The implementation uses the following data attributes: + * -
  • data-value (containing page_order) + * -
    data-folder_id data-package_url (for reporting to the backend) + * + * Gustaf Neumann fecit May 2019 + */ + +function listdnd_get_parent( target, nodeName ) { + while ( target.nodeName != nodeName && target.nodeName != 'BODY' ) { + target = target.parentNode; + } + if ( target.nodeName == 'BODY' ) { + return false; + } else { + return target; + } +} + +function listdnd_page_orders( element ) { + // + // Collect the page_orders of the LI items below the given element + // and return it in form of an array. + // + var items = element.getElementsByTagName('LI'); + var result = []; + + for (var j = 0; j < items.length; j++) { + var page_order = items[j].dataset.value; + if (page_order != '') { + result.push(page_order); + } + } + return result; +} + +function listdnd_dragstart_handler(ev) { + // Add the target element's id to the data transfer object + var target = listdnd_get_parent( ev.target, 'LI' ); + ev.dataTransfer.setData("text/plain", target.id); + ev.dataTransfer.dropEffect = "move"; + //console.log("listdnd_dragstart_handler on " + target.id); +} + +function listdnd_dragover_handler(ev) { + ev.preventDefault(); + ev.dataTransfer.dropEffect = "move" + var target = listdnd_get_parent( ev.target, 'LI' ); + var value = target.dataset.value; + if (typeof value !== 'undefined') { + var bounding = target.getBoundingClientRect() + var offset = bounding.y + (bounding.height/2); + if ( event.clientY - offset > 0 ) { + target.classList.add('mark-below') + target.classList.remove('mark-above') + } else { + target.classList.add('mark-above') + target.classList.remove('mark-below') + } + } +} + +function listdnd_dragleave_handler(ev) { + ev.preventDefault(); + // Set the dropEffect to move + ev.dataTransfer.dropEffect = "move" + var target = listdnd_get_parent( ev.target, 'LI' ); + target.classList.remove('mark-above', 'mark-below'); +} + + +function listdnd_drop_handler(ev) { + ev.preventDefault(); + //console.log("drop_handler on " + ev.target.nodeName); + + // Get the dropped element based on the transferred ID. + var sourceElement = document.getElementById(ev.dataTransfer.getData("text/plain")) + + // We want to allow only drops on elements having a "data-value" + // attribute set (because of desisred reorderings of the page_order) + var target = listdnd_get_parent( ev.target, 'LI'); + + var value = target.dataset.value; + if (typeof value !== 'undefined') { + + // Used variables: + // - dropul: The target ul, which should be updated with + // the dropped item. + // - div: The outer did, needed for obtaining "folder_id" + // and "package_url". + // - before: collection of "page_orders" before drop. + // - after: collection of "page_orders" after drop. + // + var dropul = target.parentNode; + var div = listdnd_get_parent( target.parentNode, 'DIV'); + var before = listdnd_page_orders(dropul); + + if ( target.classList.contains('mark-above') ) { + target.classList.remove('mark-above') + target.parentNode.insertBefore(sourceElement, target); + } else { + target.classList.remove('mark-below') + target.parentNode.insertBefore(sourceElement, target.nextSibling); + } + + var after = listdnd_page_orders(dropul); + var diff = after.filter(x => !before.includes(x) ); + + //console.log('drop before <' + before + '> after <' + after + '> diff <' + diff + '>'); + + var data = 'change-page-order=1' + + '&from=' + escape(before.join(' ')) + + '&to=' + escape(after.join(' ')) + + '&clean=' + escape(diff.join(' ')) + + '&folder_id=' + escape(div.dataset.folder_id) + + ''; + + //console.log('package_url <' + div.dataset.package_url + '>'); + if (1) { + var request = new XMLHttpRequest(); + request.onload = function(e) { + // There seems no good way to handle redirects (301 or + // 302) in XHR. Since we know valid results (just the + // "OK"), everything else must have been a + // redirect. We could be brutal and display the + // returned page, but not sure, if this would be + // desirable either. + if (this.getResponseHeader["Content-Length"] > 10) { + // there must have happened a redirect + alert("Refresh your login and redo update"); + window.location.href = div.dataset.package_url + + "?refresh-login&return_url=" + + escape(window.location.href); + } else { + window.location.reload(); + } + }; + request.open('POST', div.dataset.package_url, true); + request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); + request.send(data); + } + } +} 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 -N -r1.64.2.1 -r1.64.2.2 --- openacs-4/packages/xowiki/www/resources/xowiki.css 10 May 2019 22:53:10 -0000 1.64.2.1 +++ openacs-4/packages/xowiki/www/resources/xowiki.css 12 May 2019 20:02:46 -0000 1.64.2.2 @@ -55,86 +55,6 @@ padding-right: 14px; } -/* appearance of item-buttons */ -/* -div.xowiki-content a.edit-item-button { - background: url(/resources/acs-subsite/Edit16.gif) right center no-repeat; - padding-right: 16px; -} -div.xowiki-content a.delete-item-button { - background: url(/resources/acs-subsite/Delete16.gif) right center no-repeat; - padding-right: 16px; -} -div.xowiki-content a.view-item-button { - background: url(/resources/acs-subsite/Zoom16.gif) right center no-repeat; - padding-right: 16px; -} -div.xowiki-content a.create-item-button { - background: url( /resources/acs-subsite/Add16.gif) right center no-repeat; - padding-right: 16px; -} -div.xowiki-content a.copy-item-button { - background: url(/resources/acs-subsite/Copy16.gif) right center no-repeat; - padding-right: 16px; -} -div.xowiki-content a.copy-item-button { - background: url(/resources/acs-subsite/Copy16.gif) right center no-repeat; - padding-right: 16px; -} -*/ -/* positions - Add16 -2,-1 - Copy16 -2,-22 - Delete16 -2,-44 - Edit16 -2,-66 - New16 -2,-88 - Open16 -2,-110 - Preferences16 -2,-132 - Properties16 -2,-154 - Zoom16 -2,-176 - ZoomIn16 -2,-198 - ZoomOut16 -2,-220 - email.png -2,-242 - external.png -2,-264 - file.png -2,-286 - transparent.png -1,-308 -*/ -div.xowiki-content a.edit-item-button { - background: transparent url(/resources/xowiki/sprite16.png) -2px -66px no-repeat; - padding-right: 16px; - text-decoration: none; -} -div.xowiki-content a.delete-item-button { - background: transparent url(/resources/xowiki/sprite16.png) -2px -44px no-repeat; - padding-right: 16px; - text-decoration: none; -} -div.xowiki-content a.view-item-button { - background: transparent url(/resources/xowiki/sprite16.png) -2px -176px no-repeat; - padding-right: 16px; - text-decoration: none; -} -div.xowiki-content a.create-item-button { - background: transparent url(/resources/xowiki/sprite16.png) -2px -1px no-repeat; - padding-right: 16px; - text-decoration: none; -} -div.xowiki-content a.copy-item-button { - background: transparent url(/resources/xowiki/sprite16.png) -2px -22px no-repeat; - padding-right: 16px; - text-decoration: none; - width: 16px; height: 16px; -} -div.xowiki-content a.add-item-button { - background: transparent url(/resources/xowiki/sprite16.png) -2px -1px no-repeat; - padding-right: 16px; - text-decoration: none; -} -div.xowiki-content a.notification-image-button { - background: transparent url(/resources/xowiki/sprite16.png) -4px -248px no-repeat; /* 6px more */ - padding-right: 16px; - text-decoration: none; -} /* headings */ div.xowiki-content h1 { @@ -416,9 +336,16 @@ list targetable. Alternatively, we could leave the padding off by default, adding it when we detect that the list is empty. */ - padding-bottom:3ex; + padding-bottom:1ex; } +div.xowiki-content ul.page_order_region li.mark-above { + border-top: solid 4px #428bca; +} +div.xowiki-content ul.page_order_region li.mark-below { + border-bottom: solid 4px #428bca; +} + /* Handling hidden field-sets: