Browse Source

Support `data-*` attributes for configuration

The documentation is included, along with a few tests, which
explains the general rules for how it is parsed.
Kevin Brown 10 years ago
parent
commit
14db3fc801

+ 61 - 3
dist/js/select2.amd.full.js

@@ -3286,8 +3286,9 @@ define('select2/defaults',[
 });
 
 define('select2/options',[
+  'jquery',
   './defaults'
-], function (Defaults) {
+], function ($, Defaults) {
   function Options (options, $element) {
     this.options = options;
 
@@ -3299,8 +3300,65 @@ define('select2/options',[
   }
 
   Options.prototype.fromElement = function ($e) {
-    if (this.options.multiple == null) {
-      this.options.multiple = $e.prop('multiple');
+    var fromProperties = ['multiple'];
+    var excludedData = ['select2'];
+
+    for (var p = 0; p < fromProperties.length; p++) {
+      var prop = fromProperties[p];
+
+      if (this.options[prop] == null) {
+        this.options[prop] = $e.prop(prop);
+      }
+    }
+
+    var data = $e.data();
+
+    function convertData (data) {
+      for (var originalKey in data) {
+        var keys = originalKey.split('-');
+
+        var dataLevel = data;
+
+        if (keys.length === 1) {
+          continue;
+        }
+
+        for (var k = 0; k < keys.length; k++) {
+          var key = keys[k];
+
+          // Lowercase the first letter
+          // By default, dash-separated becomes camelCase
+          key = key.substring(0, 1).toLowerCase() + key.substring(1);
+
+          if (!(key in dataLevel)) {
+            dataLevel[key] = {};
+          }
+
+          if (k == keys.length - 1) {
+            dataLevel[key] = data[originalKey];
+          }
+
+          dataLevel = dataLevel[key];
+        }
+
+        delete data[originalKey];
+      }
+
+      return data;
+    }
+
+    data = convertData(data);
+
+    for (var key in data) {
+      if (excludedData.indexOf(key) > -1) {
+        continue;
+      }
+
+      if ($.isPlainObject(this.options[key])) {
+        $.extend(this.options[key], data[key]);
+      } else {
+        this.options[key] = data[key];
+      }
     }
 
     return this;

+ 61 - 3
dist/js/select2.amd.js

@@ -3286,8 +3286,9 @@ define('select2/defaults',[
 });
 
 define('select2/options',[
+  'jquery',
   './defaults'
-], function (Defaults) {
+], function ($, Defaults) {
   function Options (options, $element) {
     this.options = options;
 
@@ -3299,8 +3300,65 @@ define('select2/options',[
   }
 
   Options.prototype.fromElement = function ($e) {
-    if (this.options.multiple == null) {
-      this.options.multiple = $e.prop('multiple');
+    var fromProperties = ['multiple'];
+    var excludedData = ['select2'];
+
+    for (var p = 0; p < fromProperties.length; p++) {
+      var prop = fromProperties[p];
+
+      if (this.options[prop] == null) {
+        this.options[prop] = $e.prop(prop);
+      }
+    }
+
+    var data = $e.data();
+
+    function convertData (data) {
+      for (var originalKey in data) {
+        var keys = originalKey.split('-');
+
+        var dataLevel = data;
+
+        if (keys.length === 1) {
+          continue;
+        }
+
+        for (var k = 0; k < keys.length; k++) {
+          var key = keys[k];
+
+          // Lowercase the first letter
+          // By default, dash-separated becomes camelCase
+          key = key.substring(0, 1).toLowerCase() + key.substring(1);
+
+          if (!(key in dataLevel)) {
+            dataLevel[key] = {};
+          }
+
+          if (k == keys.length - 1) {
+            dataLevel[key] = data[originalKey];
+          }
+
+          dataLevel = dataLevel[key];
+        }
+
+        delete data[originalKey];
+      }
+
+      return data;
+    }
+
+    data = convertData(data);
+
+    for (var key in data) {
+      if (excludedData.indexOf(key) > -1) {
+        continue;
+      }
+
+      if ($.isPlainObject(this.options[key])) {
+        $.extend(this.options[key], data[key]);
+      } else {
+        this.options[key] = data[key];
+      }
     }
 
     return this;

+ 61 - 3
dist/js/select2.full.js

@@ -12821,8 +12821,9 @@ define('select2/defaults',[
 });
 
 define('select2/options',[
+  'jquery',
   './defaults'
-], function (Defaults) {
+], function ($, Defaults) {
   function Options (options, $element) {
     this.options = options;
 
@@ -12834,8 +12835,65 @@ define('select2/options',[
   }
 
   Options.prototype.fromElement = function ($e) {
-    if (this.options.multiple == null) {
-      this.options.multiple = $e.prop('multiple');
+    var fromProperties = ['multiple'];
+    var excludedData = ['select2'];
+
+    for (var p = 0; p < fromProperties.length; p++) {
+      var prop = fromProperties[p];
+
+      if (this.options[prop] == null) {
+        this.options[prop] = $e.prop(prop);
+      }
+    }
+
+    var data = $e.data();
+
+    function convertData (data) {
+      for (var originalKey in data) {
+        var keys = originalKey.split('-');
+
+        var dataLevel = data;
+
+        if (keys.length === 1) {
+          continue;
+        }
+
+        for (var k = 0; k < keys.length; k++) {
+          var key = keys[k];
+
+          // Lowercase the first letter
+          // By default, dash-separated becomes camelCase
+          key = key.substring(0, 1).toLowerCase() + key.substring(1);
+
+          if (!(key in dataLevel)) {
+            dataLevel[key] = {};
+          }
+
+          if (k == keys.length - 1) {
+            dataLevel[key] = data[originalKey];
+          }
+
+          dataLevel = dataLevel[key];
+        }
+
+        delete data[originalKey];
+      }
+
+      return data;
+    }
+
+    data = convertData(data);
+
+    for (var key in data) {
+      if (excludedData.indexOf(key) > -1) {
+        continue;
+      }
+
+      if ($.isPlainObject(this.options[key])) {
+        $.extend(this.options[key], data[key]);
+      } else {
+        this.options[key] = data[key];
+      }
     }
 
     return this;

File diff suppressed because it is too large
+ 0 - 0
dist/js/select2.full.min.js


+ 61 - 3
dist/js/select2.js

@@ -3714,8 +3714,9 @@ define('select2/defaults',[
 });
 
 define('select2/options',[
+  'jquery',
   './defaults'
-], function (Defaults) {
+], function ($, Defaults) {
   function Options (options, $element) {
     this.options = options;
 
@@ -3727,8 +3728,65 @@ define('select2/options',[
   }
 
   Options.prototype.fromElement = function ($e) {
-    if (this.options.multiple == null) {
-      this.options.multiple = $e.prop('multiple');
+    var fromProperties = ['multiple'];
+    var excludedData = ['select2'];
+
+    for (var p = 0; p < fromProperties.length; p++) {
+      var prop = fromProperties[p];
+
+      if (this.options[prop] == null) {
+        this.options[prop] = $e.prop(prop);
+      }
+    }
+
+    var data = $e.data();
+
+    function convertData (data) {
+      for (var originalKey in data) {
+        var keys = originalKey.split('-');
+
+        var dataLevel = data;
+
+        if (keys.length === 1) {
+          continue;
+        }
+
+        for (var k = 0; k < keys.length; k++) {
+          var key = keys[k];
+
+          // Lowercase the first letter
+          // By default, dash-separated becomes camelCase
+          key = key.substring(0, 1).toLowerCase() + key.substring(1);
+
+          if (!(key in dataLevel)) {
+            dataLevel[key] = {};
+          }
+
+          if (k == keys.length - 1) {
+            dataLevel[key] = data[originalKey];
+          }
+
+          dataLevel = dataLevel[key];
+        }
+
+        delete data[originalKey];
+      }
+
+      return data;
+    }
+
+    data = convertData(data);
+
+    for (var key in data) {
+      if (excludedData.indexOf(key) > -1) {
+        continue;
+      }
+
+      if ($.isPlainObject(this.options[key])) {
+        $.extend(this.options[key], data[key]);
+      } else {
+        this.options[key] = data[key];
+      }
     }
 
     return this;

File diff suppressed because it is too large
+ 0 - 0
dist/js/select2.min.js


+ 59 - 0
docs/options.html

@@ -43,6 +43,65 @@ $.fn.select2.amd.require(
       note what adapter is given.
     </p>
 
+    <h2 id="data-attributes">
+      Declaring configuration in the <code>data-*</code> attributes
+    </h2>
+
+    <p>
+      It is recommended that you declare your configuration options for Select2
+      when initializing Select2. You can also define your configuration options
+      by using the HTML5 <code>data-*</code> attributes, which will override
+      any options set when initializing Select2 and any defaults.
+    </p>
+
+    <p>
+      This means that if you declare your <code>&lt;select&gt;</code> tag as...
+    </p>
+
+<pre class="prettyprint linenums">
+&lt;select data-tags="true" data-placeholder="Select an option"&gt;&lt;/select&gt;
+</pre>
+
+    <p>
+      Will be interpreted the same as initializing Select2 as...
+    </p>
+
+<pre class="prettyprint linenums">
+$("select").select2({
+  tags: "true",
+  placeholder: "Select an option"
+});
+</pre>
+
+    <p>
+      You can also define nested configurations, which are typically needed for
+      options such as AJAX. Each level of nesting should be separated by two
+      dashes (<code>--</code>) instead of one.
+    </p>
+
+<pre class="prettyprint linenums">
+&lt;select data-ajax--url="http://example.org/api/test" data-ajax--cache="true"&gt;&lt;/select&gt;
+</pre>
+
+    <p>
+      Which will be interpreted the same as initializing Select2 with...
+    </p>
+
+<pre class="prettyprint linenums">
+  $("select").select2({
+    ajax: {
+      url: "http://example.org/api/test",
+      cache: "true"
+    }
+  });
+</pre>
+
+    <p>
+      The value of the option is subject to jQuery's
+      <a href="https://api.jquery.com/data/#data-html5">parsing rules</a> for
+      HTML5 data attributes.
+    </p>
+
     <h2>
       Display
     </h2>

+ 61 - 3
src/js/select2/options.js

@@ -1,6 +1,7 @@
 define([
+  'jquery',
   './defaults'
-], function (Defaults) {
+], function ($, Defaults) {
   function Options (options, $element) {
     this.options = options;
 
@@ -12,8 +13,65 @@ define([
   }
 
   Options.prototype.fromElement = function ($e) {
-    if (this.options.multiple == null) {
-      this.options.multiple = $e.prop('multiple');
+    var fromProperties = ['multiple'];
+    var excludedData = ['select2'];
+
+    for (var p = 0; p < fromProperties.length; p++) {
+      var prop = fromProperties[p];
+
+      if (this.options[prop] == null) {
+        this.options[prop] = $e.prop(prop);
+      }
+    }
+
+    var data = $e.data();
+
+    function convertData (data) {
+      for (var originalKey in data) {
+        var keys = originalKey.split('-');
+
+        var dataLevel = data;
+
+        if (keys.length === 1) {
+          continue;
+        }
+
+        for (var k = 0; k < keys.length; k++) {
+          var key = keys[k];
+
+          // Lowercase the first letter
+          // By default, dash-separated becomes camelCase
+          key = key.substring(0, 1).toLowerCase() + key.substring(1);
+
+          if (!(key in dataLevel)) {
+            dataLevel[key] = {};
+          }
+
+          if (k == keys.length - 1) {
+            dataLevel[key] = data[originalKey];
+          }
+
+          dataLevel = dataLevel[key];
+        }
+
+        delete data[originalKey];
+      }
+
+      return data;
+    }
+
+    data = convertData(data);
+
+    for (var key in data) {
+      if (excludedData.indexOf(key) > -1) {
+        continue;
+      }
+
+      if ($.isPlainObject(this.options[key])) {
+        $.extend(this.options[key], data[key]);
+      } else {
+        this.options[key] = data[key];
+      }
     }
 
     return this;

+ 20 - 0
tests/options/data-tests.js

@@ -0,0 +1,20 @@
+module('Options - Attributes');
+
+var Options = require('select2/options');
+
+test('no nesting', function (assert) {
+  var $test = $('<select data-test="test"></select>');
+
+  var options = new Options({}, $test);
+
+  assert.equal(options.get('test'), 'test');
+});
+
+test('with nesting', function (assert) {
+  var $test = $('<select data-first--second="test"></select>');
+
+  var options = new Options({}, $test);
+
+  assert.ok(!(options.get('first-Second')));
+  assert.equal(options.get('first').second, 'test');
+});

+ 18 - 0
tests/options/data.html

@@ -0,0 +1,18 @@
+<!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>
+    <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="data-tests.js" type="text/javascript"></script>
+  </body>
+</html>

Some files were not shown because too many files changed in this diff