Преглед изворни кода

Change internal data ID generation to be more unique (#5840)

This changes the internal generation of the ID used to uniquely
identify an element to be more resistant to collisions. Previously
it was an incremented integer or the exact ID used on the element,
which for most cases was unique enough. Unfortunately if any elements
used by Select2 also had an ID that was a low number, it was almost
guaranteed to collide with an internal ID that Select2 generated.

The internal generation now relies on a prefix when the ID already
exists, similar to what we do with core IDs. It also uses a set of
4 random characters along with the incrementing ID to reduce the
chance of collisions even further.

It is definitely still possible for a collision to occur, especially
if two elements exist but one has a prefix of `data-` already, but
the chances have been greatly reduced. We'll accept it for now.
Kevin Brown пре 5 година
родитељ
комит
00aa2a59ae
2 измењених фајлова са 37 додато и 13 уклоњено
  1. 16 11
      src/js/select2/utils.js
  2. 21 2
      tests/utils/data-tests.js

+ 16 - 11
src/js/select2/utils.js

@@ -262,20 +262,25 @@ define([
   Utils.GetUniqueElementId = function (element) {
     // Get a unique element Id. If element has no id,
     // creates a new unique number, stores it in the id
-    // attribute and returns the new id.
-    // If an id already exists, it simply returns it.
+    // attribute and returns the new id with a prefix.
+    // If an id already exists, it simply returns it with a prefix.
 
     var select2Id = element.getAttribute('data-select2-id');
-    if (select2Id == null) {
-      // If element has id, use it.
-      if (element.id) {
-        select2Id = element.id;
-        element.setAttribute('data-select2-id', select2Id);
-      } else {
-        element.setAttribute('data-select2-id', ++id);
-        select2Id = id.toString();
-      }
+
+    if (select2Id != null) {
+      return select2Id;
     }
+
+    // If element has id, use it.
+    if (element.id) {
+      select2Id = 'select2-data-' + element.id;
+    } else {
+      select2Id = 'select2-data-' + (++id).toString() +
+        '-' + Utils.generateChars(4);
+    }
+
+    element.setAttribute('data-select2-id', select2Id);
+
     return select2Id;
   };
 

+ 21 - 2
tests/utils/data-tests.js

@@ -1,8 +1,27 @@
-module('Utils - RemoveData');
-
 var $ = require('jquery');
 var Utils = require('select2/utils');
 
+module('Utils - GetUniqueElementId');
+
+test('Adds a prefix to the existing ID if one exists', function (assert) {
+    var $element = $('<select id="existing-id"></select>');
+
+    var id = Utils.GetUniqueElementId($element[0]);
+
+    assert.notEqual(id, 'existing-id');
+    assert.notEqual(id.indexOf('existing-id'), -1);
+});
+
+test('Generated random ID is not a number', function (assert) {
+    var $element = $('<select></select>');
+
+    var id = Utils.GetUniqueElementId($element[0]);
+
+    assert.ok(isNaN(id));
+});
+
+module('Utils - RemoveData');
+
 test('The data-select2-id attribute is removed', function (assert) {
     var $element = $('<select data-select2-id="test"></select>');