Index: openacs-4/packages/xowiki/tcl/bootstrap-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/bootstrap-procs.tcl,v diff -u -r1.3 -r1.4 --- openacs-4/packages/xowiki/tcl/bootstrap-procs.tcl 27 Apr 2015 15:28:22 -0000 1.3 +++ openacs-4/packages/xowiki/tcl/bootstrap-procs.tcl 7 Aug 2017 23:48:30 -0000 1.4 @@ -25,28 +25,54 @@ -superclass Menu \ -parameter { {autorender false} - {containerClass "container"} + {menubar} + {containerClass "container-fluid"} {navbarClass "navbar navbar-default navbar-static-top"} } BootstrapNavbar instproc init {} { ::xo::Page requireJS "/resources/xowiki/jquery/jquery.min.js" set css [parameter::get_global_value -package_key xowiki -parameter BootstrapCSS] - set js [parameter::get_global_value -package_key xowiki -parameter BootstrapJS] + set js [parameter::get_global_value -package_key xowiki -parameter BootstrapJS] + # + # TODO: We should dynamically be able to determine (some of) the + # CSP directives. However, for the time being, the urls below are + # trusted. + # + security::csp::require script-src maxcdn.bootstrapcdn.com + security::csp::require style-src maxcdn.bootstrapcdn.com + security::csp::require font-src maxcdn.bootstrapcdn.com + foreach url $css {::xo::Page requireCSS $url} foreach url $js {::xo::Page requireJS $url} next } - + + BootstrapNavbar ad_instproc render {} { http://getbootstrap.com/components/#navbar } { html::nav -class [my navbarClass] -role "navigation" { + # + # Render the pull down menues + # html::div -class [my containerClass] { - foreach dropdownmenu [my children] { - $dropdownmenu render + set rightMenuEntries {} + foreach entry [my children] { + if {[$entry istype ::xowiki::BootstrapNavbarDropdownMenu]} { + $entry render + } else { + lappend rightMenuEntries $entry + } } - } + if {[llength $rightMenuEntries] > 0} { + html::ul -class "nav navbar-nav navbar-right" { + foreach entry $rightMenuEntries { + $entry render + } + } + } + } } } @@ -65,7 +91,7 @@ BootstrapNavbarDropdownMenu ad_instproc render {} {doku} { # TODO: Add support for group-headers # get group header - set group 1 + set group " " html::ul -class "nav navbar-nav" { html::li -class "dropdown" { @@ -78,15 +104,18 @@ html::ul -class "dropdown-menu" { foreach dropdownmenuitem [my children] { if {[$dropdownmenuitem set group] ne "" && [$dropdownmenuitem set group] ne $group } { - html::li -class "divider" + if {$group ne " "} { + html::li -class "divider" + } set group [$dropdownmenuitem set group] } $dropdownmenuitem render } } } } - } + } + # # BootstrapNavbarDropdownMenuItem # @@ -98,48 +127,271 @@ } BootstrapNavbarDropdownMenuItem ad_instproc render {} {doku} { - html::li -class [expr {[my set href] eq "" ? "disabled": ""}] { - html::a [my get_attributes target href title] { + html::a [my get_attributes target href title id] { html::t [my text] } } - } + if {[my exists listener] && [my set listener] ne ""} { + lassign [my listener] type body + template::add_event_listener -event $type -id [my set id] \ + -preventdefault=false -script $body + } + } + # + # BootstrapNavbarDropzone + # + ::xo::tdom::Class create BootstrapNavbarDropzone \ + -superclass MenuComponent \ + -parameter { + {href "#"} + text + uploader + } + + BootstrapNavbarDropzone instproc js {-uploadlink:required} { + html::script -type "text/javascript" -nonce $::__csp_nonce { + html::t [subst -nocommands { + + function($) { + 'use strict'; + + var dropZone = document.getElementById('drop-zone'); + var uploadForm = document.getElementById('js-upload-form'); + var progressBar = document.getElementById('dropzone-progress-bar'); + var uploadFileRunning = 0; + + var startUpload = function(files, csrf) { + if (typeof files !== "undefined") { + for (var i=0, l=files.length; i 1} { - # we expect a dict as second list element - lassign $menu_att menu_att props1 - lappend props {*}$props1 - } - # currently we render erverthing as a dropdown - ::xowiki::BootstrapNavbarDropdownMenu \ - -brand [dict get $props brand] \ - -text [my get_prop $menu text] { - #ns_log notice "... dropdown menu_att $menu_att menu $menu" - foreach {item_att item} $menu { - if {[string match {[a-z]*} $item_att]} continue - set text [my get_prop $item text] - set url [my get_prop $item url] - set group [my get_prop $item group] - ::xowiki::BootstrapNavbarDropdownMenuItem -text $text -href $url -group $group {} + -id [my get_prop $dict id] \ + -menubar [self] { + foreach {att value} $dict { + if {$att eq "id"} continue + switch [my get_prop $value kind] { + "DropZone" { + ::xowiki::BootstrapNavbarDropzone \ + -text [my get_prop $value label] \ + -href [my get_prop $value url] \ + -uploader [my get_prop $value uploader] {} } + "ModeButton" { + template::head::add_css -href "/resources/xotcl-core/titatoggle/titatoggle-dist.css" + + ::xowiki::BootstrapNavbarModeButton \ + -text [my get_prop $value label] \ + -href [my get_prop $value url] \ + -button [my get_prop $value button admin] \ + -on [my get_prop $value on] {} + } + "MenuButton" { + # render erverthing as a dropdown + ::xowiki::BootstrapNavbarDropdownMenu \ + -text [my get_prop $value label] { + #ns_log notice "... dropdown att $att menu $value" + foreach {item_att item} $value { + if {[string match {[a-z]*} $item_att]} continue + ::xowiki::BootstrapNavbarDropdownMenuItem \ + -text [my get_prop $item label] \ + -href [my get_prop $item url] \ + -group [my get_prop $item group] \ + -listener [my get_prop $item listener] \ + {} + } + } + } } - } - }] - #ns_log notice call-mb-asHTML + }}] + #ns_log notice "call menubar asHTML" return [$mb asHTML] } } @@ -199,8 +451,41 @@ } } + BootstrapTableRenderer instproc render-bulkactions {} { + set bulkactions [[self]::__bulkactions children] + html::div -class "btn-group" -role group -aria-label "Bulk actions" { + html::t "Bulk-Actions:" + set bulkaction_container [[lindex $bulkactions 0] set __parent] + set name [$bulkaction_container set __identifier] + + foreach ba $bulkactions { + set id [::xowiki::Includelet html_id $ba] + html::ul -class compact { + html::li { + # For some reason, btn-secondary seems not to be available + # for the "a" tag, so we set the border-color manually. + html::a -class "btn btn-secondary" -rule button \ + -title [$ba tooltip] -href # \ + -style "border-color: #ccc;" \ + -id $id { + html::t [$ba label] + } + } + } + template::add_body_script -script [subst { + document.getElementById('$id').addEventListener('click', function (event) { + acs_ListBulkActionClick('$name','[$ba url]'); + }, false); + }] + } + } + } + BootstrapTableRenderer instproc render {} { - ::xo::Page requireCSS "//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" + ::xo::Page requireCSS "//maxcdn.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" + security::csp::require style-src maxcdn.bootstrapcdn.com + security::csp::require font-src maxcdn.bootstrapcdn.com + if {![my isobject [self]::__actions]} {my actions {}} if {![my isobject [self]::__bulkactions]} {my __bulkactions {}} set bulkactions [[self]::__bulkactions children] @@ -209,9 +494,21 @@ } else { set name [::xowiki::Includelet js_name [self]] } - - html::div -id [my set id]_wrapper -class "table-responsive" { - html::form -name $name -id $name -method POST { + if {[llength $bulkactions]>0} { + html::div -id [my set id]_wrapper -class "table-responsive" { + html::form -name $name -id $name -method POST { + html::div -id [my set id]_container { + html::table -id [my set id] -class [my set css.table-class] { + my render-actions + my render-body + } + if {[llength $bulkactions]>0} { my render-bulkactions } + } + } + } + } else { + #nesting forms inside a xowf page will place the action buttons at the wrong place! + html::div -id [my set id]_wrapper -class "table-responsive" { html::div -id [my set id]_container { html::table -id [my set id] -class [my set css.table-class] { my render-actions @@ -223,7 +520,6 @@ } } - #Class create BootstrapTableRenderer::AnchorField -superclass TABLE::AnchorField Class create BootstrapTableRenderer::AnchorField \ @@ -241,10 +537,14 @@ [set href [$line set $__name.href]] ne ""} { # use the CSS class rather from the Field than not the line my instvar CSSclass - $line instvar [list $__name.title title] \ - [list $__name.target target] \ - [list $__name.onclick onclick] - html::a [my get_local_attributes href title {CSSclass class} target onclick] { + $line instvar [list $__name.title title] [list $__name.target target] + if {[$line exists $__name.onclick]} { + set id [::xowiki::Includelet html_id $line] + template::add_event_listener \ + -id $id \ + -script "[$line set $__name.onclick];" + } + html::a [my get_local_attributes href title {CSSclass class} target id] { return "[next]" } }