Pārlūkot izejas kodu

FIX Restore multiselect (selection of prospect level)

Laurent Destailleur 4 gadi atpakaļ
vecāks
revīzija
6380a294fc

+ 3 - 2
htdocs/core/class/html.form.class.php

@@ -6461,11 +6461,12 @@ class Form
 							 	templateSelection: formatSelection		/* For 4.0 */
 							});
 						});'."\n";
-			} elseif ($addjscombo == 2)
+			} elseif ($addjscombo == 2 && ! defined('DISABLE_MULTISELECT'))
 			{
 				// Add other js lib
 				// TODO external lib multiselect/jquery.multi-select.js must have been loaded to use this multiselect plugin
 				// ...
+				$out .= 'console.log(\'addjscombo=2 for htmlname='.$htmlname.'\');';
 				$out .= '$(document).ready(function () {
 							$(\'#'.$htmlname.'\').multiSelect({
 								containerHTML: \'<div class="multi-select-container">\',
@@ -7158,7 +7159,7 @@ class Form
 		}
 
 		//if ($conf->browser->layout == 'phone') $ret.='<div class="clearboth"></div>';
-		$ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 refid'.(($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '').'">';
+		$ret .= '<div class="inline-block floatleft valignmiddle maxwidth750 marginbottomonly refid'.(($shownav && ($previous_ref || $next_ref)) ? ' refidpadding' : '').'">';
 
 		// For thirdparty, contact, user, member, the ref is the id, so we show something else
 		if ($object->element == 'societe')

+ 12 - 3
htdocs/core/lib/functions.lib.php

@@ -1350,19 +1350,28 @@ function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab
 	{
 		$left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
 		$right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
+		$widthofpopup = 200;
 
 		$tabsname = $moretabssuffix;
 		if (empty($tabsname)) { $tabsname = str_replace("@", "", $picto); }
 		$out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem">';
-		$out .= '<a href="#" class="tab moretab inline-block tabunactive reposition">'.$langs->trans("More").'... ('.$nbintab.')</a>';
-		$out .= '<div id="moretabsList'.$tabsname.'" style="position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
+		$out .= '<a href="#" class="tab moretab inline-block tabunactive">'.$langs->trans("More").'... ('.$nbintab.')</a>';	// Do not use "reposition" class in the "More".
+		$out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
 		$out .= $outmore;
 		$out .= '</div>';
 		$out .= '<div></div>';
 		$out .= "</div>\n";
 
 		$out .= "<script>";
-		$out .= "$('#moretabs".$tabsname."').mouseenter( function() { console.log('mouseenter ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','auto');});";
+		$out .= "$('#moretabs".$tabsname."').mouseenter( function() {
+			var x = this.offsetLeft, y = this.offsetTop;
+			console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
+			if ((window.innerWidth - x) < ".($widthofpopup+10).") {
+				$('#moretabsList".$tabsname."').css('".$right."','8px');
+			}
+			$('#moretabsList".$tabsname."').css('".$left."','auto');
+			});
+		";
 		$out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
 		$out .= "</script>";
 	}

+ 360 - 0
htdocs/includes/jquery/plugins/multiselect/jquery.multi-select.js

@@ -0,0 +1,360 @@
+// jquery.multi-select.js
+// by mySociety
+// https://github.com/mysociety/jquery-multi-select
+
+;(function($) {
+
+  "use strict";
+
+  var pluginName = "multiSelect",
+    defaults = {
+      'containerHTML': '<div class="multi-select-container">',
+      'menuHTML': '<div class="multi-select-menu">',
+      'buttonHTML': '<span class="multi-select-button">',
+      'menuItemsHTML': '<div class="multi-select-menuitems">',
+      'menuItemHTML': '<label class="multi-select-menuitem">',
+      'presetsHTML': '<div class="multi-select-presets">',
+      'activeClass': 'multi-select-container--open',
+      'noneText': '-- Select --',
+      'allText': undefined,
+      'presets': undefined,
+      'positionedMenuClass': 'multi-select-container--positioned',
+      'positionMenuWithin': undefined,
+      'viewportBottomGutter': 20,
+      'menuMinHeight': 200
+    };
+
+  /**
+   * @constructor
+   */
+  function MultiSelect(element, options) {
+    this.element = element;
+    this.$element = $(element);
+    this.settings = $.extend( {}, defaults, options );
+    this._defaults = defaults;
+    this._name = pluginName;
+    this.init();
+  }
+
+  function arraysAreEqual(array1, array2) {
+    if ( array1.length != array2.length ){
+      return false;
+    }
+
+    array1.sort();
+    array2.sort();
+
+    for ( var i = 0; i < array1.length; i++ ){
+      if ( array1[i] !== array2[i] ){
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  $.extend(MultiSelect.prototype, {
+
+    init: function() {
+      this.checkSuitableInput();
+      this.findLabels();
+      this.constructContainer();
+      this.constructButton();
+      this.constructMenu();
+
+      this.setUpBodyClickListener();
+      this.setUpLabelsClickListener();
+
+      this.$element.hide();
+    },
+
+    checkSuitableInput: function(text) {
+      if ( this.$element.is('select[multiple]') === false ) {
+        throw new Error('$.multiSelect only works on <select multiple> elements');
+      }
+    },
+
+    findLabels: function() {
+      this.$labels = $('label[for="' + this.$element.attr('id') + '"]');
+    },
+
+    constructContainer: function() {
+      this.$container = $(this.settings['containerHTML']);
+      this.$element.data('multi-select-container', this.$container);
+      this.$container.insertAfter(this.$element);
+    },
+
+    constructButton: function() {
+      var _this = this;
+      this.$button = $(this.settings['buttonHTML']);
+      this.$button.attr({
+        'role': 'button',
+        'aria-haspopup': 'true',
+        'tabindex': 0,
+        'aria-label': this.$labels.eq(0).text()
+      })
+      .on('keydown.multiselect', function(e) {
+        var key = e.which;
+        var returnKey = 13;
+        var spaceKey = 32;
+        if ((key === returnKey) || (key === spaceKey)) {
+          _this.$button.click();
+        }
+      }).on('click.multiselect', function(e) {
+        _this.menuToggle();
+      })
+      .appendTo(this.$container);
+
+      this.$element.on('change.multiselect', function() {
+        _this.updateButtonContents();
+      });
+
+      this.updateButtonContents();
+    },
+
+    updateButtonContents: function() {
+      var _this = this;
+      var options = [];
+      var selected = [];
+
+      this.$element.children('option').each(function() {
+        var text = /** @type string */ ($(this).text());
+        options.push(text);
+        if ($(this).is(':selected')) {
+          selected.push( $.trim(text) );
+        }
+      });
+
+      this.$button.empty();
+
+      if (selected.length == 0) {
+        this.$button.text( this.settings['noneText'] );
+      } else if ( (selected.length === options.length) && this.settings['allText']) {
+        this.$button.text( this.settings['allText'] );
+      } else {
+        this.$button.text( selected.join(', ') );
+      }
+    },
+
+    constructMenu: function() {
+      var _this = this;
+
+      this.$menu = $(this.settings['menuHTML']);
+      this.$menu.attr({
+        'role': 'menu'
+      }).on('keyup.multiselect', function(e){
+        var key = e.which;
+        var escapeKey = 27;
+        if (key === escapeKey) {
+          _this.menuHide();
+        }
+      })
+      .appendTo(this.$container);
+
+      this.constructMenuItems();
+
+      if ( this.settings['presets'] ) {
+        this.constructPresets();
+      }
+    },
+
+    constructMenuItems: function() {
+      var _this = this;
+
+      this.$menuItems = $(this.settings['menuItemsHTML']);
+      this.$menu.append(this.$menuItems);
+
+      this.$element.on('change.multiselect', function(e, internal) {
+        // Don't need to update the menu items if this
+        // change event was fired by our tickbox handler.
+        if(internal !== true){
+          _this.updateMenuItems();
+        }
+      });
+
+      this.updateMenuItems();
+    },
+
+    updateMenuItems: function() {
+      var _this = this;
+      this.$menuItems.empty();
+
+      this.$element.children('option').each(function(option_index, option) {
+        var $item = _this.constructMenuItem($(option), option_index);
+        _this.$menuItems.append($item);
+      });
+    },
+
+    constructPresets: function() {
+      var _this = this;
+      this.$presets = $(this.settings['presetsHTML']);
+      this.$menu.prepend(this.$presets);
+
+      $.each(this.settings['presets'], function(i, preset){
+        var unique_id = _this.$element.attr('name') + '_preset_' + i;
+        var $item = $(_this.settings['menuItemHTML'])
+          .attr({
+            'for': unique_id,
+            'role': 'menuitem'
+          })
+          .text(' ' + preset.name)
+          .appendTo(_this.$presets);
+
+        var $input = $('<input>')
+          .attr({
+            'type': 'radio',
+            'name': _this.$element.attr('name') + '_presets',
+            'id': unique_id
+          })
+          .prependTo($item);
+
+        $input.on('change.multiselect', function(){
+          _this.$element.val(preset.options);
+          _this.$element.trigger('change');
+        });
+      });
+
+      this.$element.on('change.multiselect', function() {
+        _this.updatePresets();
+      });
+
+      this.updatePresets();
+    },
+
+    updatePresets: function() {
+      var _this = this;
+
+      $.each(this.settings['presets'], function(i, preset){
+        var unique_id = _this.$element.attr('name') + '_preset_' + i;
+        var $input = _this.$presets.find('#' + unique_id);
+
+        if ( arraysAreEqual(preset.options || [], _this.$element.val() || []) ){
+          $input.prop('checked', true);
+        } else {
+          $input.prop('checked', false);
+        }
+      });
+    },
+
+    constructMenuItem: function($option, option_index) {
+      var unique_id = this.$element.attr('name') + '_' + option_index;
+      var $item = $(this.settings['menuItemHTML'])
+        .attr({
+          'for': unique_id,
+          'role': 'menuitem'
+        })
+        .text(' ' + $option.text());
+
+      var $input = $('<input>')
+        .attr({
+          'type': 'checkbox',
+          'id': unique_id,
+          'value': $option.val()
+        })
+        .prependTo($item);
+
+      if ( $option.is(':disabled') ) {
+        $input.attr('disabled', 'disabled');
+      }
+      if ( $option.is(':selected') ) {
+        $input.prop('checked', 'checked');
+      }
+
+      $input.on('change.multiselect', function() {
+        if ($(this).prop('checked')) {
+          $option.prop('selected', true);
+        } else {
+          $option.prop('selected', false);
+        }
+
+        // .prop() on its own doesn't generate a change event.
+        // Other plugins might want to do stuff onChange.
+        $option.trigger('change', [true]);
+      });
+
+      return $item;
+    },
+
+    setUpBodyClickListener: function() {
+      var _this = this;
+
+      // Hide the $menu when you click outside of it.
+      $('html').on('click.multiselect', function(){
+        _this.menuHide();
+      });
+
+      // Stop click events from inside the $button or $menu from
+      // bubbling up to the body and closing the menu!
+      this.$container.on('click.multiselect', function(e){
+        e.stopPropagation();
+      });
+    },
+
+    setUpLabelsClickListener: function() {
+      var _this = this;
+      this.$labels.on('click.multiselect', function(e) {
+        e.preventDefault();
+        e.stopPropagation();
+        _this.menuToggle();
+      });
+    },
+
+    menuShow: function() {
+      $('html').trigger('click.multiselect'); // Close any other open menus
+      this.$container.addClass(this.settings['activeClass']);
+
+      if ( this.settings['positionMenuWithin'] && this.settings['positionMenuWithin'] instanceof $ ) {
+        var menuLeftEdge = this.$menu.offset().left + this.$menu.outerWidth();
+        var withinLeftEdge = this.settings['positionMenuWithin'].offset().left +
+          this.settings['positionMenuWithin'].outerWidth();
+
+        if ( menuLeftEdge > withinLeftEdge ) {
+          this.$menu.css( 'width', (withinLeftEdge - this.$menu.offset().left) );
+          this.$container.addClass(this.settings['positionedMenuClass']);
+        }
+      }
+
+      var menuBottom = this.$menu.offset().top + this.$menu.outerHeight();
+      var viewportBottom = $(window).scrollTop() + $(window).height();
+      if ( menuBottom > viewportBottom - this.settings['viewportBottomGutter'] ) {
+        this.$menu.css({
+          'maxHeight': Math.max(
+            viewportBottom - this.settings['viewportBottomGutter'] - this.$menu.offset().top,
+            this.settings['menuMinHeight']
+          ),
+          'overflow': 'scroll'
+        });
+      } else {
+        this.$menu.css({
+          'maxHeight': '',
+          'overflow': ''
+        });
+      }
+    },
+
+    menuHide: function() {
+      this.$container.removeClass(this.settings['activeClass']);
+      this.$container.removeClass(this.settings['positionedMenuClass']);
+      this.$menu.css('width', 'auto');
+    },
+
+    menuToggle: function() {
+      if ( this.$container.hasClass(this.settings['activeClass']) ) {
+        this.menuHide();
+      } else {
+        this.menuShow();
+      }
+    }
+
+  });
+
+  $.fn[ pluginName ] = function(options) {
+    return this.each(function() {
+      if ( !$.data(this, "plugin_" + pluginName) ) {
+        $.data(this, "plugin_" + pluginName,
+          new MultiSelect(this, options) );
+      }
+    });
+  };
+
+})(jQuery);

+ 9 - 0
htdocs/includes/jquery/plugins/multiselect/jquery.multi-select.min.js

@@ -0,0 +1,9 @@
+(function(c){function f(b,a){this.b=c(b);this.a=c.extend({},g,a);this.H()}var g={containerHTML:'<div class="multi-select-container">',menuHTML:'<div class="multi-select-menu">',buttonHTML:'<span class="multi-select-button">',menuItemsHTML:'<div class="multi-select-menuitems">',menuItemHTML:'<label class="multi-select-menuitem">',presetsHTML:'<div class="multi-select-presets">',activeClass:"multi-select-container--open",noneText:"-- Select --",allText:void 0,presets:void 0,positionedMenuClass:"multi-select-container--positioned",
+positionMenuWithin:void 0,viewportBottomGutter:20,menuMinHeight:200};c.extend(f.prototype,{H:function(){this.v();this.G();this.A();this.w();this.B();this.J();this.K();this.b.hide()},v:function(){if(!1===this.b.is("select[multiple]"))throw Error("$.multiSelect only works on <select multiple> elements");},G:function(){this.l=c('label[for="'+this.b.attr("id")+'"]')},A:function(){this.f=c(this.a.containerHTML);this.b.data("multi-select-container",this.f);this.f.insertAfter(this.b)},w:function(){var b=
+this;this.g=c(this.a.buttonHTML);this.g.attr({role:"button","aria-haspopup":"true",tabindex:0,"aria-label":this.l.eq(0).text()}).on("keydown.multiselect",function(a){a=a.which;13!==a&&32!==a||b.g.click()}).on("click.multiselect",function(){b.m()}).appendTo(this.f);this.b.on("change.multiselect",function(){b.o()});this.o()},o:function(){var b=[],a=[];this.b.children("option").each(function(){var d=c(this).text();b.push(d);c(this).is(":selected")&&a.push(c.trim(d))});this.g.empty();0==a.length?this.g.text(this.a.noneText):
+a.length===b.length&&this.a.allText?this.g.text(this.a.allText):this.g.text(a.join(", "))},B:function(){var b=this;this.c=c(this.a.menuHTML);this.c.attr({role:"menu"}).on("keyup.multiselect",function(a){27===a.which&&b.j()}).appendTo(this.f);this.D();this.a.presets&&this.F()},D:function(){var b=this;this.h=c(this.a.menuItemsHTML);this.c.append(this.h);this.b.on("change.multiselect",function(a,c){!0!==c&&b.s()});this.s()},s:function(){var b=this;this.h.empty();this.b.children("option").each(function(a,
+d){a=b.C(c(d),a);b.h.append(a)})},F:function(){var b=this;this.i=c(this.a.presetsHTML);this.c.prepend(this.i);c.each(this.a.presets,function(a,d){a=b.b.attr("name")+"_preset_"+a;var h=c(b.a.menuItemHTML).attr({"for":a,role:"menuitem"}).text(" "+d.name).appendTo(b.i);c("<input>").attr({type:"radio",name:b.b.attr("name")+"_presets",id:a}).prependTo(h).on("change.multiselect",function(){b.b.val(d.options);b.b.trigger("change")})});this.b.on("change.multiselect",function(){b.u()});this.u()},u:function(){var b=
+this;c.each(this.a.presets,function(a,c){a=b.b.attr("name")+"_preset_"+a;a=b.i.find("#"+a);a:{c=c.options||[];var d=b.b.val()||[];if(c.length!=d.length)c=!1;else{c.sort();d.sort();for(var e=0;e<c.length;e++)if(c[e]!==d[e]){c=!1;break a}c=!0}}c?a.prop("checked",!0):a.prop("checked",!1)})},C:function(b,a){var d=this.b.attr("name")+"_"+a;a=c(this.a.menuItemHTML).attr({"for":d,role:"menuitem"}).text(" "+b.text());d=c("<input>").attr({type:"checkbox",id:d,value:b.val()}).prependTo(a);b.is(":disabled")&&
+d.attr("disabled","disabled");b.is(":selected")&&d.prop("checked","checked");d.on("change.multiselect",function(){c(this).prop("checked")?b.prop("selected",!0):b.prop("selected",!1);b.trigger("change",[!0])});return a},J:function(){var b=this;c("html").on("click.multiselect",function(){b.j()});this.f.on("click.multiselect",function(a){a.stopPropagation()})},K:function(){var b=this;this.l.on("click.multiselect",function(a){a.preventDefault();a.stopPropagation();b.m()})},I:function(){c("html").trigger("click.multiselect");
+this.f.addClass(this.a.activeClass);if(this.a.positionMenuWithin&&this.a.positionMenuWithin instanceof c){var b=this.c.offset().left+this.c.outerWidth(),a=this.a.positionMenuWithin.offset().left+this.a.positionMenuWithin.outerWidth();b>a&&(this.c.css("width",a-this.c.offset().left),this.f.addClass(this.a.positionedMenuClass))}b=this.c.offset().top+this.c.outerHeight();a=c(window).scrollTop()+c(window).height();b>a-this.a.viewportBottomGutter?this.c.css({maxHeight:Math.max(a-this.a.viewportBottomGutter-
+this.c.offset().top,this.a.menuMinHeight),overflow:"scroll"}):this.c.css({maxHeight:"",overflow:""})},j:function(){this.f.removeClass(this.a.activeClass);this.f.removeClass(this.a.positionedMenuClass);this.c.css("width","auto")},m:function(){this.f.hasClass(this.a.activeClass)?this.j():this.I()}});c.fn.multiSelect=function(b){return this.each(function(){c.data(this,"plugin_multiSelect")||c.data(this,"plugin_multiSelect",new f(this,b))})}})(jQuery);

+ 4 - 0
htdocs/main.inc.php

@@ -1388,6 +1388,10 @@ function top_htmlhead($head, $title = '', $disablejs = 0, $disablehead = 0, $arr
                 // jQuery plugin "mutiselect", "multiple-select", "select2", ...
             	$tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ?constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
             	print '<script src="'.DOL_URL_ROOT.'/includes/jquery/plugins/'.$tmpplugin.'/dist/js/'.$tmpplugin.'.full.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n"; // We include full because we need the support of containerCssClass
+            }
+            if (! defined('DISABLE_MULTISELECT'))     // jQuery plugin "mutiselect" to select with checkboxes. Can be removed once we have an enhanced search tool
+            {
+            	print '<script src="'.DOL_URL_ROOT.'/includes/jquery/plugins/multiselect/jquery.multi-select.js'.($ext?'?'.$ext:'').'"></script>'."\n";
             }
 		}
 

+ 6 - 9
htdocs/theme/eldy/global.inc.php

@@ -1275,9 +1275,6 @@ table[summary="list_of_modules"] .fa-cog {
 /* Force values for small screen 767 */
 @media only screen and (max-width: 767px)
 {
-	body {
-		font-size: <?php print is_numeric($fontsize) ? ($fontsize + 3).'px' : $fontsize; ?>;
-	}
 	div.refidno {
 		font-size: <?php print is_numeric($fontsize) ? ($fontsize + 3).'px' : $fontsize; ?> !important;
 	}
@@ -1311,10 +1308,6 @@ table[summary="list_of_modules"] .fa-cog {
 /* Force values for small screen 570 */
 @media only screen and (max-width: 570px)
 {
-	body {
-		font-size: <?php print is_numeric($fontsize) ? ($fontsize + 3).'px' : $fontsize; ?>;
-	}
-
 	.box-flex-item {
 		margin: 3px 2px 3px 2px !important;
 	}
@@ -2815,8 +2808,8 @@ div.popuptabset {
 	border: 1px solid #888;
 }
 div.popuptab {
-	padding-top: 5px;
-	padding-bottom: 5px;
+	padding-top: 8px;
+	padding-bottom: 8px;
 	padding-left: 5px;
 	padding-right: 5px;
 }
@@ -5593,6 +5586,10 @@ span.noborderoncategories {
 /*  External lib multiselect with checkbox                                        */
 /* ============================================================================== */
 
+.multi-select-menu {
+	z-index: 10;
+}
+
 .multi-select-container {
   display: inline-block;
   position: relative;

+ 4 - 0
htdocs/theme/md/style.css.php

@@ -5427,6 +5427,10 @@ span.noborderoncategories {
 /*  External lib multiselect with checkbox                                        */
 /* ============================================================================== */
 
+.multi-select-menu {
+	z-index: 10;
+}
+
 .multi-select-container {
   display: inline-block;
   position: relative;