浏览代码

Added back the `width` option

In past versions of Select2, the `width` option could be used to
tell Select2 how to determine the width of the container generated
by Select2.

**Breaking change:** The default value for the `width` option has
been changed from `copy` to `resolve.`

**Breaking change:** The old option called `copy` has been renamed
to `style` to better reflect what the width is generated from.

This fixes https://github.com/select2/select2/pull/2090.
This fixes https://github.com/select2/select2/issues/2911.
Kevin Brown 10 年之前
父节点
当前提交
af1f35176b

+ 53 - 2
dist/js/select2.amd.full.js

@@ -3619,7 +3619,8 @@ define('select2/defaults',[
       templateSelection: function (selection) {
         return selection.text;
       },
-      theme: 'default'
+      theme: 'default',
+      width: 'resolve'
     };
   };
 
@@ -3868,7 +3869,57 @@ define('select2/core',[
 
   Select2.prototype._placeContainer = function ($container) {
     $container.insertAfter(this.$element);
-    $container.width(this.$element.outerWidth(false));
+
+    var width = this._resolveWidth(this.$element, this.options.get('width'));
+
+    if (width != null) {
+      $container.css('width', width);
+    }
+  };
+
+  Select2.prototype._resolveWidth = function ($element, method) {
+    var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
+
+    if (method == 'resolve') {
+      var styleWidth = this._resolveWidth($element, 'style');
+
+      if (styleWidth != null) {
+        return styleWidth;
+      }
+
+      return this._resolveWidth($element, 'element');
+    }
+
+    if (method == 'element') {
+      var elementWidth = $element.outerWidth(false);
+
+      if (elementWidth <= 0) {
+        return 'auto';
+      }
+
+      return elementWidth + 'px';
+    }
+
+    if (method == 'style') {
+      var style = $element.attr('style');
+
+      if (typeof(style) !== 'string') {
+        return null;
+      }
+
+      var attrs = style.split(';');
+
+      for (i = 0, l = attrs.length; i < l; i = i + 1) {
+        attr = attrs[i].replace(/\s/g, '');
+        var matches = attr.match(WIDTH);
+
+        if (matches !== null && matches.length >= 1) {
+          return matches[1];
+        }
+      }
+    }
+
+    return method;
   };
 
   Select2.prototype._bindAdapters = function () {

+ 53 - 2
dist/js/select2.amd.js

@@ -3619,7 +3619,8 @@ define('select2/defaults',[
       templateSelection: function (selection) {
         return selection.text;
       },
-      theme: 'default'
+      theme: 'default',
+      width: 'resolve'
     };
   };
 
@@ -3868,7 +3869,57 @@ define('select2/core',[
 
   Select2.prototype._placeContainer = function ($container) {
     $container.insertAfter(this.$element);
-    $container.width(this.$element.outerWidth(false));
+
+    var width = this._resolveWidth(this.$element, this.options.get('width'));
+
+    if (width != null) {
+      $container.css('width', width);
+    }
+  };
+
+  Select2.prototype._resolveWidth = function ($element, method) {
+    var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
+
+    if (method == 'resolve') {
+      var styleWidth = this._resolveWidth($element, 'style');
+
+      if (styleWidth != null) {
+        return styleWidth;
+      }
+
+      return this._resolveWidth($element, 'element');
+    }
+
+    if (method == 'element') {
+      var elementWidth = $element.outerWidth(false);
+
+      if (elementWidth <= 0) {
+        return 'auto';
+      }
+
+      return elementWidth + 'px';
+    }
+
+    if (method == 'style') {
+      var style = $element.attr('style');
+
+      if (typeof(style) !== 'string') {
+        return null;
+      }
+
+      var attrs = style.split(';');
+
+      for (i = 0, l = attrs.length; i < l; i = i + 1) {
+        attr = attrs[i].replace(/\s/g, '');
+        var matches = attr.match(WIDTH);
+
+        if (matches !== null && matches.length >= 1) {
+          return matches[1];
+        }
+      }
+    }
+
+    return method;
   };
 
   Select2.prototype._bindAdapters = function () {

+ 53 - 2
dist/js/select2.full.js

@@ -13154,7 +13154,8 @@ define('select2/defaults',[
       templateSelection: function (selection) {
         return selection.text;
       },
-      theme: 'default'
+      theme: 'default',
+      width: 'resolve'
     };
   };
 
@@ -13403,7 +13404,57 @@ define('select2/core',[
 
   Select2.prototype._placeContainer = function ($container) {
     $container.insertAfter(this.$element);
-    $container.width(this.$element.outerWidth(false));
+
+    var width = this._resolveWidth(this.$element, this.options.get('width'));
+
+    if (width != null) {
+      $container.css('width', width);
+    }
+  };
+
+  Select2.prototype._resolveWidth = function ($element, method) {
+    var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
+
+    if (method == 'resolve') {
+      var styleWidth = this._resolveWidth($element, 'style');
+
+      if (styleWidth != null) {
+        return styleWidth;
+      }
+
+      return this._resolveWidth($element, 'element');
+    }
+
+    if (method == 'element') {
+      var elementWidth = $element.outerWidth(false);
+
+      if (elementWidth <= 0) {
+        return 'auto';
+      }
+
+      return elementWidth + 'px';
+    }
+
+    if (method == 'style') {
+      var style = $element.attr('style');
+
+      if (typeof(style) !== 'string') {
+        return null;
+      }
+
+      var attrs = style.split(';');
+
+      for (i = 0, l = attrs.length; i < l; i = i + 1) {
+        attr = attrs[i].replace(/\s/g, '');
+        var matches = attr.match(WIDTH);
+
+        if (matches !== null && matches.length >= 1) {
+          return matches[1];
+        }
+      }
+    }
+
+    return method;
   };
 
   Select2.prototype._bindAdapters = function () {

文件差异内容过多而无法显示
+ 0 - 0
dist/js/select2.full.min.js


+ 53 - 2
dist/js/select2.js

@@ -4047,7 +4047,8 @@ define('select2/defaults',[
       templateSelection: function (selection) {
         return selection.text;
       },
-      theme: 'default'
+      theme: 'default',
+      width: 'resolve'
     };
   };
 
@@ -4296,7 +4297,57 @@ define('select2/core',[
 
   Select2.prototype._placeContainer = function ($container) {
     $container.insertAfter(this.$element);
-    $container.width(this.$element.outerWidth(false));
+
+    var width = this._resolveWidth(this.$element, this.options.get('width'));
+
+    if (width != null) {
+      $container.css('width', width);
+    }
+  };
+
+  Select2.prototype._resolveWidth = function ($element, method) {
+    var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
+
+    if (method == 'resolve') {
+      var styleWidth = this._resolveWidth($element, 'style');
+
+      if (styleWidth != null) {
+        return styleWidth;
+      }
+
+      return this._resolveWidth($element, 'element');
+    }
+
+    if (method == 'element') {
+      var elementWidth = $element.outerWidth(false);
+
+      if (elementWidth <= 0) {
+        return 'auto';
+      }
+
+      return elementWidth + 'px';
+    }
+
+    if (method == 'style') {
+      var style = $element.attr('style');
+
+      if (typeof(style) !== 'string') {
+        return null;
+      }
+
+      var attrs = style.split(';');
+
+      for (i = 0, l = attrs.length; i < l; i = i + 1) {
+        attr = attrs[i].replace(/\s/g, '');
+        var matches = attr.match(WIDTH);
+
+        if (matches !== null && matches.length >= 1) {
+          return matches[1];
+        }
+      }
+    }
+
+    return method;
   };
 
   Select2.prototype._bindAdapters = function () {

文件差异内容过多而无法显示
+ 0 - 0
dist/js/select2.min.js


+ 64 - 4
docs/options.html

@@ -248,10 +248,70 @@ placeholder: {
       <dd>boolean (<code>true</code> or <code>false</code>)</dd>
     </dl>
 
-    This option will determine what the <code>SelectAdapter</code> (used by
-    default) should use to set the value of the underlying <code>select</code>
-    element. It will also determine if the <code>MultipleSelection</code>
-    adapter should be used.
+    <p>
+      This option will determine what the <code>SelectAdapter</code> (used by
+      default) should use to set the value of the underlying <code>select</code>
+      element. It will also determine if the <code>MultipleSelection</code>
+      adapter should be used.
+    </p>
+
+    <h3 id="width">
+      Container width
+    </h3>
+
+    <p>
+      Select2 will try to match the width of the original element as closely as
+      possible. Sometimes this isn't perfect, which is what you can tell Select2
+      how to determine the width.
+    </p>
+
+    <div class="row">
+      <div class="col-sm-8">
+        <table class="table table-striped table-bordered">
+          <thead>
+            <tr>
+              <th>Value</th>
+              <th>Description</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <td><code>"element"</code></td>
+              <td>
+                Uses javascript to calculate the width of the source element.
+              </td>
+            </tr>
+            <tr>
+              <td><code>"style"</code></td>
+              <td>
+                Copies the value of the width <code>style</code> attribute set on the source element.
+              </td>
+            </tr>
+            <tr>
+              <td><code>"resolve"</code></td>
+              <td>
+                Tries to use <code>style</code> to determine the width, falling back to <code>element</code>.
+              </td>
+            </tr>
+            <tr>
+              <td>Anything else</td>
+              <td>
+                The value of the <code>width</code> option is diretly set as the width of the container.
+              </td>
+            </tr>
+          </tbody>
+        </table>
+      </div>
+      <div class="col-sm-4">
+        <dl class="dl-horizontal">
+          <dt>Key</dt>
+          <dd><code>width</code></dd>
+
+          <dt>Value</dt>
+          <dd>string</dd>
+        </dl>
+      </div>
+    </div>
 
     <h3 id="language">
       Internationalization (Language support)

+ 51 - 1
src/js/select2/core.js

@@ -103,7 +103,57 @@ define([
 
   Select2.prototype._placeContainer = function ($container) {
     $container.insertAfter(this.$element);
-    $container.width(this.$element.outerWidth(false));
+
+    var width = this._resolveWidth(this.$element, this.options.get('width'));
+
+    if (width != null) {
+      $container.css('width', width);
+    }
+  };
+
+  Select2.prototype._resolveWidth = function ($element, method) {
+    var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
+
+    if (method == 'resolve') {
+      var styleWidth = this._resolveWidth($element, 'style');
+
+      if (styleWidth != null) {
+        return styleWidth;
+      }
+
+      return this._resolveWidth($element, 'element');
+    }
+
+    if (method == 'element') {
+      var elementWidth = $element.outerWidth(false);
+
+      if (elementWidth <= 0) {
+        return 'auto';
+      }
+
+      return elementWidth + 'px';
+    }
+
+    if (method == 'style') {
+      var style = $element.attr('style');
+
+      if (typeof(style) !== 'string') {
+        return null;
+      }
+
+      var attrs = style.split(';');
+
+      for (i = 0, l = attrs.length; i < l; i = i + 1) {
+        attr = attrs[i].replace(/\s/g, '');
+        var matches = attr.match(WIDTH);
+
+        if (matches !== null && matches.length >= 1) {
+          return matches[1];
+        }
+      }
+    }
+
+    return method;
   };
 
   Select2.prototype._bindAdapters = function () {

+ 2 - 1
src/js/select2/defaults.js

@@ -264,7 +264,8 @@ define([
       templateSelection: function (selection) {
         return selection.text;
       },
-      theme: 'default'
+      theme: 'default',
+      width: 'resolve'
     };
   };
 

+ 54 - 0
tests/options/width-tests.js

@@ -0,0 +1,54 @@
+module('Options - Width');
+
+var Select2 = require('select2/core');
+var select = new Select2($('<select></select>'));
+
+test('string passed as width', function (assert) {
+  var $test = $('<select></select>');
+
+  var width = select._resolveWidth($test, '80%');
+
+  assert.equal(width, '80%');
+});
+
+test('width from style attribute', function (assert) {
+  var $test = $('<select style="width: 50%;"></selct>');
+
+  var width = select._resolveWidth($test, 'style');
+
+  assert.equal(width, '50%');
+});
+
+test('width from style returns null if nothing is found', function (assert) {
+  var $test = $('<select></selct>');
+
+  var width = select._resolveWidth($test, 'style');
+
+  assert.equal(width, null);
+});
+
+test('width from computer element width', function (assert) {
+  var $test = $('<select class="css-set-width"></select>');
+  $('#qunit-fixture').append($test);
+
+  var width = select._resolveWidth($test, 'element');
+
+  assert.equal(width, '500px');
+});
+
+test('resolve gets the style if it is there', function (assert) {
+  var $test = $('<select style="width: 20%;"></selct>');
+
+  var width = select._resolveWidth($test, 'resolve');
+
+  assert.equal(width, '20%');
+});
+
+test('resolve falls back to element if there is no style', function (assert) {
+  var $test = $('<select class="css-set-width"></select>');
+  $('#qunit-fixture').append($test);
+
+  var width = select._resolveWidth($test, 'resolve');
+
+  assert.equal(width, '500px');
+});

+ 24 - 0
tests/options/width.html

@@ -0,0 +1,24 @@
+<!doctype html>
+<html>
+  <head>
+    <link rel="stylesheet" href="../vendor/qunit-1.14.0.css" type="text/css" />
+    <link rel="stylesheet" href="../../dist/css/select2.css" type="text/css" />
+  </head>
+  <body>
+    <style type="text/css">
+    .css-set-width {
+      width: 500px;
+    }
+    </style>
+
+    <div id="qunit"></div>
+    <div id="qunit-fixture"></div>
+
+    <script src="../vendor/qunit-1.14.0.js" type="text/javascript"></script>
+    <script src="../../vendor/almond-0.2.9.js" type="text/javascript"></script>
+    <script src="../../vendor/jquery-2.1.0.js" type="text/javascript"></script>
+    <script src="../../dist/js/select2.amd.js" type="text/javascript"></script>
+
+    <script src="width-tests.js" type="text/javascript"></script>
+  </body>
+</html>

部分文件因为文件数量过多而无法显示