All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.emul.java.util.InternalJsMapFactory Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * Copyright 2014 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package java.util;

import com.google.gwt.core.client.JavaScriptObject;

/**
 * A factory to create JavaScript Map instances.
 */
class InternalJsMapFactory {

  private static final JavaScriptObject jsMapCtor = getJsMapConstructor();

  private static native JavaScriptObject getJsMapConstructor() /*-{
    // Firefox 24 & 25 throws StopIteration to signal the end of iteration.
    function isCorrectIterationProtocol() {
      try {
        return new Map().entries().next().done;
      } catch(e) {
        return false;
      }
    }

    if (typeof Map === 'function' && Map.prototype.entries && isCorrectIterationProtocol()) {
      return Map;
    } else {
      return @InternalJsMapFactory::getJsMapPolyFill()();
    }
  }-*/;

  public static native  InternalJsMap newJsMap() /*-{
    return new @InternalJsMapFactory::jsMapCtor;
  }-*/;

  /**
   * Returns a partial polyfill for Map that can handle String keys.
   * 

Implementation notes: *

String keys are mapped to their values via a JS associative map. String keys could collide * with intrinsic properties (like watch, constructor). To avoid that; the polyfill uses * {@code Object.create(null)} so it doesn't inherit any properties. *

For legacy browsers where {@code Object.create} is not available or handling of * {@code __proto__} is broken, the polyfill is patched to prepend each key with a ':' while * storing. */ private static native JavaScriptObject getJsMapPolyFill() /*-{ function Stringmap() { this.obj = this.createObject(); }; Stringmap.prototype.createObject = function(key) { return Object.create(null); } Stringmap.prototype.get = function(key) { return this.obj[key]; }; Stringmap.prototype.set = function(key, value) { this.obj[key] = value; }; Stringmap.prototype['delete'] = function(key) { delete this.obj[key]; }; Stringmap.prototype.keys = function() { return Object.getOwnPropertyNames(this.obj); }; Stringmap.prototype.entries = function() { var keys = this.keys(); var map = this; var nextIndex = 0; return { next: function() { if (nextIndex >= keys.length) return {done: true}; var key = keys[nextIndex++]; return {value: [key, map.get(key)], done: false}; } }; }; if (!@InternalJsMapFactory::canHandleObjectCreateAndProto()()) { // Patches the polyfill to drop Object.create(null) and prefix each key with ':" so it will // not interfere with intrinsic fields. Stringmap.prototype.createObject = function() { return {}; }; Stringmap.prototype.get = function(key) { return this.obj[':' + key]; }; Stringmap.prototype.set = function(key, value) { this.obj[':' + key] = value; }; Stringmap.prototype['delete'] = function(key) { delete this.obj[':' + key]; }; Stringmap.prototype.keys = function() { var result = []; for (var key in this.obj) { // char code for ':' is 58 if (key.charCodeAt(0) == 58) { result.push(key.substring(1)); } } return result; }; } return Stringmap; }-*/; /** * Return {@code true} if the browser is modern enough to handle Object.create and also properly * handles '__proto__' field with Object.create(null). (Safari 5, Android, old Firefox) */ private static native boolean canHandleObjectCreateAndProto() /*-{ if (!Object.create || !Object.getOwnPropertyNames) { return false; } var protoField = "__proto__"; var map = Object.create(null); if (map[protoField] !== undefined) { return false; } var keys = Object.getOwnPropertyNames(map); if (keys.length != 0) { return false; } map[protoField] = 42; if (map[protoField] !== 42) { return false; } // For old Firefox version who doesn't have native Map. See the Firefox bug: // https://bugzilla.mozilla.org/show_bug.cgi?id=837630 if (Object.getOwnPropertyNames(map).length == 0) { return false; } // Looks like the browser has a workable handling of proto field. return true; }-*/; private InternalJsMapFactory() { // Hides the constructor. } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy