You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ft...@apache.org on 2015/09/17 17:28:30 UTC

[15/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/filesaver.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/filesaver.js b/externs/GCL/externs/goog/fs/filesaver.js
new file mode 100644
index 0000000..8d441c4
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/filesaver.js
@@ -0,0 +1,166 @@
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview A wrapper for the HTML5 FileSaver object.
+ *
+ */
+
+goog.provide('goog.fs.FileSaver');
+goog.provide('goog.fs.FileSaver.EventType');
+goog.provide('goog.fs.FileSaver.ReadyState');
+
+goog.require('goog.events.EventTarget');
+goog.require('goog.fs.Error');
+goog.require('goog.fs.ProgressEvent');
+
+
+
+/**
+ * An object for monitoring the saving of files. This emits ProgressEvents of
+ * the types listed in {@link goog.fs.FileSaver.EventType}.
+ *
+ * This should not be instantiated directly. Instead, its subclass
+ * {@link goog.fs.FileWriter} should be accessed via
+ * {@link goog.fs.FileEntry#createWriter}.
+ *
+ * @param {!FileSaver} fileSaver The underlying FileSaver object.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.fs.FileSaver = function(fileSaver) {
+  goog.fs.FileSaver.base(this, 'constructor');
+
+  /**
+   * The underlying FileSaver object.
+   *
+   * @type {!FileSaver}
+   * @private
+   */
+  this.saver_ = fileSaver;
+
+  this.saver_.onwritestart = goog.bind(this.dispatchProgressEvent_, this);
+  this.saver_.onprogress = goog.bind(this.dispatchProgressEvent_, this);
+  this.saver_.onwrite = goog.bind(this.dispatchProgressEvent_, this);
+  this.saver_.onabort = goog.bind(this.dispatchProgressEvent_, this);
+  this.saver_.onerror = goog.bind(this.dispatchProgressEvent_, this);
+  this.saver_.onwriteend = goog.bind(this.dispatchProgressEvent_, this);
+};
+goog.inherits(goog.fs.FileSaver, goog.events.EventTarget);
+
+
+/**
+ * Possible states for a FileSaver.
+ *
+ * @enum {number}
+ */
+goog.fs.FileSaver.ReadyState = {
+  /**
+   * The object has been constructed, but there is no pending write.
+   */
+  INIT: 0,
+  /**
+   * Data is being written.
+   */
+  WRITING: 1,
+  /**
+   * The data has been written to the file, the write was aborted, or an error
+   * occurred.
+   */
+  DONE: 2
+};
+
+
+/**
+ * Events emitted by a FileSaver.
+ *
+ * @enum {string}
+ */
+goog.fs.FileSaver.EventType = {
+  /**
+   * Emitted when the writing begins. readyState will be WRITING.
+   */
+  WRITE_START: 'writestart',
+  /**
+   * Emitted when progress has been made in saving the file. readyState will be
+   * WRITING.
+   */
+  PROGRESS: 'progress',
+  /**
+   * Emitted when the data has been successfully written. readyState will be
+   * WRITING.
+   */
+  WRITE: 'write',
+  /**
+   * Emitted when the writing has been aborted. readyState will be WRITING.
+   */
+  ABORT: 'abort',
+  /**
+   * Emitted when an error is encountered or the writing has been aborted.
+   * readyState will be WRITING.
+   */
+  ERROR: 'error',
+  /**
+   * Emitted when the writing is finished, whether successfully or not.
+   * readyState will be DONE.
+   */
+  WRITE_END: 'writeend'
+};
+
+
+/**
+ * Abort the writing of the file.
+ */
+goog.fs.FileSaver.prototype.abort = function() {
+  try {
+    this.saver_.abort();
+  } catch (e) {
+    throw new goog.fs.Error(e, 'aborting save');
+  }
+};
+
+
+/**
+ * @return {goog.fs.FileSaver.ReadyState} The current state of the FileSaver.
+ */
+goog.fs.FileSaver.prototype.getReadyState = function() {
+  return /** @type {goog.fs.FileSaver.ReadyState} */ (this.saver_.readyState);
+};
+
+
+/**
+ * @return {goog.fs.Error} The error encountered while writing, if any.
+ */
+goog.fs.FileSaver.prototype.getError = function() {
+  return this.saver_.error &&
+      new goog.fs.Error(this.saver_.error, 'saving file');
+};
+
+
+/**
+ * Wrap a progress event emitted by the underlying file saver and re-emit it.
+ *
+ * @param {!ProgressEvent} event The underlying event.
+ * @private
+ */
+goog.fs.FileSaver.prototype.dispatchProgressEvent_ = function(event) {
+  this.dispatchEvent(new goog.fs.ProgressEvent(event, this));
+};
+
+
+/** @override */
+goog.fs.FileSaver.prototype.disposeInternal = function() {
+  delete this.saver_;
+  goog.fs.FileSaver.base(this, 'disposeInternal');
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/filesystem.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/filesystem.js b/externs/GCL/externs/goog/fs/filesystem.js
new file mode 100644
index 0000000..b120b92
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/filesystem.js
@@ -0,0 +1,41 @@
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview A wrapper for the HTML5 FileSystem object.
+ *
+ */
+
+goog.provide('goog.fs.FileSystem');
+
+
+
+/**
+ * A local filesystem.
+ *
+ * @interface
+ */
+goog.fs.FileSystem = function() {};
+
+
+/**
+ * @return {string} The name of the filesystem.
+ */
+goog.fs.FileSystem.prototype.getName = function() {};
+
+
+/**
+ * @return {!goog.fs.DirectoryEntry} The root directory of the filesystem.
+ */
+goog.fs.FileSystem.prototype.getRoot = function() {};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/filesystemimpl.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/filesystemimpl.js b/externs/GCL/externs/goog/fs/filesystemimpl.js
new file mode 100644
index 0000000..b5ebb33
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/filesystemimpl.js
@@ -0,0 +1,65 @@
+// Copyright 2013 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview Concrete implementation of the goog.fs.FileSystem interface
+ *     using an HTML FileSystem object.
+ */
+goog.provide('goog.fs.FileSystemImpl');
+
+goog.require('goog.fs.DirectoryEntryImpl');
+goog.require('goog.fs.FileSystem');
+
+
+
+/**
+ * A local filesystem.
+ *
+ * This shouldn't be instantiated directly. Instead, it should be accessed via
+ * {@link goog.fs.getTemporary} or {@link goog.fs.getPersistent}.
+ *
+ * @param {!FileSystem} fs The underlying FileSystem object.
+ * @constructor
+ * @implements {goog.fs.FileSystem}
+ * @final
+ */
+goog.fs.FileSystemImpl = function(fs) {
+  /**
+   * The underlying FileSystem object.
+   *
+   * @type {!FileSystem}
+   * @private
+   */
+  this.fs_ = fs;
+};
+
+
+/** @override */
+goog.fs.FileSystemImpl.prototype.getName = function() {
+  return this.fs_.name;
+};
+
+
+/** @override */
+goog.fs.FileSystemImpl.prototype.getRoot = function() {
+  return new goog.fs.DirectoryEntryImpl(this, this.fs_.root);
+};
+
+
+/**
+ * @return {!FileSystem} The underlying FileSystem object.
+ */
+goog.fs.FileSystemImpl.prototype.getBrowserFileSystem = function() {
+  return this.fs_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/filewriter.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/filewriter.js b/externs/GCL/externs/goog/fs/filewriter.js
new file mode 100644
index 0000000..1709846
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/filewriter.js
@@ -0,0 +1,111 @@
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview A wrapper for the HTML5 FileWriter object.
+ *
+ * When adding or modifying functionality in this namespace, be sure to update
+ * the mock counterparts in goog.testing.fs.
+ *
+ */
+
+goog.provide('goog.fs.FileWriter');
+
+goog.require('goog.fs.Error');
+goog.require('goog.fs.FileSaver');
+
+
+
+/**
+ * An object for monitoring the saving of files, as well as other fine-grained
+ * writing operations.
+ *
+ * This should not be instantiated directly. Instead, it should be accessed via
+ * {@link goog.fs.FileEntry#createWriter}.
+ *
+ * @param {!FileWriter} writer The underlying FileWriter object.
+ * @constructor
+ * @extends {goog.fs.FileSaver}
+ * @final
+ */
+goog.fs.FileWriter = function(writer) {
+  goog.fs.FileWriter.base(this, 'constructor', writer);
+
+  /**
+   * The underlying FileWriter object.
+   *
+   * @type {!FileWriter}
+   * @private
+   */
+  this.writer_ = writer;
+};
+goog.inherits(goog.fs.FileWriter, goog.fs.FileSaver);
+
+
+/**
+ * @return {number} The byte offset at which the next write will occur.
+ */
+goog.fs.FileWriter.prototype.getPosition = function() {
+  return this.writer_.position;
+};
+
+
+/**
+ * @return {number} The length of the file.
+ */
+goog.fs.FileWriter.prototype.getLength = function() {
+  return this.writer_.length;
+};
+
+
+/**
+ * Write data to the file.
+ *
+ * @param {!Blob} blob The data to write.
+ */
+goog.fs.FileWriter.prototype.write = function(blob) {
+  try {
+    this.writer_.write(blob);
+  } catch (e) {
+    throw new goog.fs.Error(e, 'writing file');
+  }
+};
+
+
+/**
+ * Set the file position at which the next write will occur.
+ *
+ * @param {number} offset An absolute byte offset into the file.
+ */
+goog.fs.FileWriter.prototype.seek = function(offset) {
+  try {
+    this.writer_.seek(offset);
+  } catch (e) {
+    throw new goog.fs.Error(e, 'seeking in file');
+  }
+};
+
+
+/**
+ * Changes the length of the file to that specified.
+ *
+ * @param {number} size The new size of the file, in bytes.
+ */
+goog.fs.FileWriter.prototype.truncate = function(size) {
+  try {
+    this.writer_.truncate(size);
+  } catch (e) {
+    throw new goog.fs.Error(e, 'truncating file');
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/fs.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/fs.js b/externs/GCL/externs/goog/fs/fs.js
new file mode 100644
index 0000000..6081f6e
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/fs.js
@@ -0,0 +1,278 @@
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview Wrappers for the HTML5 File API. These wrappers closely mirror
+ * the underlying APIs, but use Closure-style events and Deferred return values.
+ * Their existence also makes it possible to mock the FileSystem API for testing
+ * in browsers that don't support it natively.
+ *
+ * When adding public functions to anything under this namespace, be sure to add
+ * its mock counterpart to goog.testing.fs.
+ *
+ */
+
+goog.provide('goog.fs');
+
+goog.require('goog.array');
+goog.require('goog.async.Deferred');
+goog.require('goog.fs.Error');
+goog.require('goog.fs.FileReader');
+goog.require('goog.fs.FileSystemImpl');
+goog.require('goog.fs.url');
+goog.require('goog.userAgent');
+
+
+/**
+ * Get a wrapped FileSystem object.
+ *
+ * @param {goog.fs.FileSystemType_} type The type of the filesystem to get.
+ * @param {number} size The size requested for the filesystem, in bytes.
+ * @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an
+ *     error occurs, the errback is called with a {@link goog.fs.Error}.
+ * @private
+ */
+goog.fs.get_ = function(type, size) {
+  var requestFileSystem = goog.global.requestFileSystem ||
+      goog.global.webkitRequestFileSystem;
+
+  if (!goog.isFunction(requestFileSystem)) {
+    return goog.async.Deferred.fail(new Error('File API unsupported'));
+  }
+
+  var d = new goog.async.Deferred();
+  requestFileSystem(type, size, function(fs) {
+    d.callback(new goog.fs.FileSystemImpl(fs));
+  }, function(err) {
+    d.errback(new goog.fs.Error(err, 'requesting filesystem'));
+  });
+  return d;
+};
+
+
+/**
+ * The two types of filesystem.
+ *
+ * @enum {number}
+ * @private
+ */
+goog.fs.FileSystemType_ = {
+  /**
+   * A temporary filesystem may be deleted by the user agent at its discretion.
+   */
+  TEMPORARY: 0,
+  /**
+   * A persistent filesystem will never be deleted without the user's or
+   * application's authorization.
+   */
+  PERSISTENT: 1
+};
+
+
+/**
+ * Returns a temporary FileSystem object. A temporary filesystem may be deleted
+ * by the user agent at its discretion.
+ *
+ * @param {number} size The size requested for the filesystem, in bytes.
+ * @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an
+ *     error occurs, the errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.getTemporary = function(size) {
+  return goog.fs.get_(goog.fs.FileSystemType_.TEMPORARY, size);
+};
+
+
+/**
+ * Returns a persistent FileSystem object. A persistent filesystem will never be
+ * deleted without the user's or application's authorization.
+ *
+ * @param {number} size The size requested for the filesystem, in bytes.
+ * @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an
+ *     error occurs, the errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.getPersistent = function(size) {
+  return goog.fs.get_(goog.fs.FileSystemType_.PERSISTENT, size);
+};
+
+
+/**
+ * Creates a blob URL for a blob object.
+ * Throws an error if the browser does not support Object Urls.
+ *
+ * TODO(user): Update references to this method to use
+ * goog.fs.url.createObjectUrl instead.
+ *
+ * @param {!Blob} blob The object for which to create the URL.
+ * @return {string} The URL for the object.
+ */
+goog.fs.createObjectUrl = function(blob) {
+  return goog.fs.url.createObjectUrl(blob);
+};
+
+
+/**
+ * Revokes a URL created by {@link goog.fs.createObjectUrl}.
+ * Throws an error if the browser does not support Object Urls.
+ *
+ * TODO(user): Update references to this method to use
+ * goog.fs.url.revokeObjectUrl instead.
+ *
+ * @param {string} url The URL to revoke.
+ */
+goog.fs.revokeObjectUrl = function(url) {
+  goog.fs.url.revokeObjectUrl(url);
+};
+
+
+/**
+ * Checks whether this browser supports Object Urls. If not, calls to
+ * createObjectUrl and revokeObjectUrl will result in an error.
+ *
+ * TODO(user): Update references to this method to use
+ * goog.fs.url.browserSupportsObjectUrls instead.
+ *
+ * @return {boolean} True if this browser supports Object Urls.
+ */
+goog.fs.browserSupportsObjectUrls = function() {
+  return goog.fs.url.browserSupportsObjectUrls();
+};
+
+
+/**
+ * Concatenates one or more values together and converts them to a Blob.
+ *
+ * @param {...(string|!Blob|!ArrayBuffer)} var_args The values that will make up
+ *     the resulting blob.
+ * @return {!Blob} The blob.
+ */
+goog.fs.getBlob = function(var_args) {
+  var BlobBuilder = goog.global.BlobBuilder || goog.global.WebKitBlobBuilder;
+
+  if (goog.isDef(BlobBuilder)) {
+    var bb = new BlobBuilder();
+    for (var i = 0; i < arguments.length; i++) {
+      bb.append(arguments[i]);
+    }
+    return bb.getBlob();
+  } else {
+    return goog.fs.getBlobWithProperties(goog.array.toArray(arguments));
+  }
+};
+
+
+/**
+ * Creates a blob with the given properties.
+ * See https://developer.mozilla.org/en-US/docs/Web/API/Blob for more details.
+ *
+ * @param {Array<string|!Blob>} parts The values that will make up the
+ *     resulting blob.
+ * @param {string=} opt_type The MIME type of the Blob.
+ * @param {string=} opt_endings Specifies how strings containing newlines are to
+ *     be written out.
+ * @return {!Blob} The blob.
+ */
+goog.fs.getBlobWithProperties = function(parts, opt_type, opt_endings) {
+  var BlobBuilder = goog.global.BlobBuilder || goog.global.WebKitBlobBuilder;
+
+  if (goog.isDef(BlobBuilder)) {
+    var bb = new BlobBuilder();
+    for (var i = 0; i < parts.length; i++) {
+      bb.append(parts[i], opt_endings);
+    }
+    return bb.getBlob(opt_type);
+  } else if (goog.isDef(goog.global.Blob)) {
+    var properties = {};
+    if (opt_type) {
+      properties['type'] = opt_type;
+    }
+    if (opt_endings) {
+      properties['endings'] = opt_endings;
+    }
+    return new Blob(parts, properties);
+  } else {
+    throw Error('This browser doesn\'t seem to support creating Blobs');
+  }
+};
+
+
+/**
+ * Converts a Blob or a File into a string. This should only be used when the
+ * blob is known to be small.
+ *
+ * @param {!Blob} blob The blob to convert.
+ * @param {string=} opt_encoding The name of the encoding to use.
+ * @return {!goog.async.Deferred} The deferred string. If an error occurrs, the
+ *     errback is called with a {@link goog.fs.Error}.
+ * @deprecated Use {@link goog.fs.FileReader.readAsText} instead.
+ */
+goog.fs.blobToString = function(blob, opt_encoding) {
+  return goog.fs.FileReader.readAsText(blob, opt_encoding);
+};
+
+
+/**
+ * Slices the blob. The returned blob contains data from the start byte
+ * (inclusive) till the end byte (exclusive). Negative indices can be used
+ * to count bytes from the end of the blob (-1 == blob.size - 1). Indices
+ * are always clamped to blob range. If end is omitted, all the data till
+ * the end of the blob is taken.
+ *
+ * @param {!Blob} blob The blob to be sliced.
+ * @param {number} start Index of the starting byte.
+ * @param {number=} opt_end Index of the ending byte.
+ * @return {Blob} The blob slice or null if not supported.
+ */
+goog.fs.sliceBlob = function(blob, start, opt_end) {
+  if (!goog.isDef(opt_end)) {
+    opt_end = blob.size;
+  }
+  if (blob.webkitSlice) {
+    // Natively accepts negative indices, clamping to the blob range and
+    // range end is optional. See http://trac.webkit.org/changeset/83873
+    return blob.webkitSlice(start, opt_end);
+  } else if (blob.mozSlice) {
+    // Natively accepts negative indices, clamping to the blob range and
+    // range end is optional. See https://developer.mozilla.org/en/DOM/Blob
+    // and http://hg.mozilla.org/mozilla-central/rev/dae833f4d934
+    return blob.mozSlice(start, opt_end);
+  } else if (blob.slice) {
+    // Old versions of Firefox and Chrome use the original specification.
+    // Negative indices are not accepted, only range end is clamped and
+    // range end specification is obligatory.
+    // See http://www.w3.org/TR/2009/WD-FileAPI-20091117/
+    if ((goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('13.0')) ||
+        (goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('537.1'))) {
+      if (start < 0) {
+        start += blob.size;
+      }
+      if (start < 0) {
+        start = 0;
+      }
+      if (opt_end < 0) {
+        opt_end += blob.size;
+      }
+      if (opt_end < start) {
+        opt_end = start;
+      }
+      return blob.slice(start, opt_end - start);
+    }
+    // IE and the latest versions of Firefox and Chrome use the new
+    // specification. Natively accepts negative indices, clamping to the blob
+    // range and range end is optional.
+    // See http://dev.w3.org/2006/webapi/FileAPI/
+    return blob.slice(start, opt_end);
+  }
+  return null;
+};
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/progressevent.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/progressevent.js b/externs/GCL/externs/goog/fs/progressevent.js
new file mode 100644
index 0000000..b0695be
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/progressevent.js
@@ -0,0 +1,69 @@
+// Copyright 2011 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview A wrapper for the HTML5 File ProgressEvent objects.
+ *
+ */
+goog.provide('goog.fs.ProgressEvent');
+
+goog.require('goog.events.Event');
+
+
+
+/**
+ * A wrapper for the progress events emitted by the File APIs.
+ *
+ * @param {!ProgressEvent} event The underlying event object.
+ * @param {!Object} target The file access object emitting the event.
+ * @extends {goog.events.Event}
+ * @constructor
+ * @final
+ */
+goog.fs.ProgressEvent = function(event, target) {
+  goog.fs.ProgressEvent.base(this, 'constructor', event.type, target);
+
+  /**
+   * The underlying event object.
+   * @type {!ProgressEvent}
+   * @private
+   */
+  this.event_ = event;
+};
+goog.inherits(goog.fs.ProgressEvent, goog.events.Event);
+
+
+/**
+ * @return {boolean} Whether or not the total size of the of the file being
+ *     saved is known.
+ */
+goog.fs.ProgressEvent.prototype.isLengthComputable = function() {
+  return this.event_.lengthComputable;
+};
+
+
+/**
+ * @return {number} The number of bytes saved so far.
+ */
+goog.fs.ProgressEvent.prototype.getLoaded = function() {
+  return this.event_.loaded;
+};
+
+
+/**
+ * @return {number} The total number of bytes in the file being saved.
+ */
+goog.fs.ProgressEvent.prototype.getTotal = function() {
+  return this.event_.total;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/url.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/url.js b/externs/GCL/externs/goog/fs/url.js
new file mode 100644
index 0000000..083c066
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/url.js
@@ -0,0 +1,105 @@
+// Copyright 2015 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview Wrapper for URL and its createObjectUrl and revokeObjectUrl
+ * methods that are part of the HTML5 File API.
+ */
+
+goog.provide('goog.fs.url');
+
+
+/**
+ * Creates a blob URL for a blob object.
+ * Throws an error if the browser does not support Object Urls.
+ *
+ * @param {!Blob} blob The object for which to create the URL.
+ * @return {string} The URL for the object.
+ */
+goog.fs.url.createObjectUrl = function(blob) {
+  return goog.fs.url.getUrlObject_().createObjectURL(blob);
+};
+
+
+/**
+ * Revokes a URL created by {@link goog.fs.url.createObjectUrl}.
+ * Throws an error if the browser does not support Object Urls.
+ *
+ * @param {string} url The URL to revoke.
+ */
+goog.fs.url.revokeObjectUrl = function(url) {
+  goog.fs.url.getUrlObject_().revokeObjectURL(url);
+};
+
+
+/**
+ * @typedef {{createObjectURL: (function(!Blob): string),
+ *            revokeObjectURL: function(string): void}}
+ */
+goog.fs.url.UrlObject_;
+
+
+/**
+ * Get the object that has the createObjectURL and revokeObjectURL functions for
+ * this browser.
+ *
+ * @return {goog.fs.url.UrlObject_} The object for this browser.
+ * @private
+ */
+goog.fs.url.getUrlObject_ = function() {
+  var urlObject = goog.fs.url.findUrlObject_();
+  if (urlObject != null) {
+    return urlObject;
+  } else {
+    throw Error('This browser doesn\'t seem to support blob URLs');
+  }
+};
+
+
+/**
+ * Finds the object that has the createObjectURL and revokeObjectURL functions
+ * for this browser.
+ *
+ * @return {?goog.fs.url.UrlObject_} The object for this browser or null if the
+ *     browser does not support Object Urls.
+ * @private
+ */
+goog.fs.url.findUrlObject_ = function() {
+  // This is what the spec says to do
+  // http://dev.w3.org/2006/webapi/FileAPI/#dfn-createObjectURL
+  if (goog.isDef(goog.global.URL) &&
+      goog.isDef(goog.global.URL.createObjectURL)) {
+    return /** @type {goog.fs.url.UrlObject_} */ (goog.global.URL);
+  // This is what Chrome does (as of 10.0.648.6 dev)
+  } else if (goog.isDef(goog.global.webkitURL) &&
+             goog.isDef(goog.global.webkitURL.createObjectURL)) {
+    return /** @type {goog.fs.url.UrlObject_} */ (goog.global.webkitURL);
+  // This is what the spec used to say to do
+  } else if (goog.isDef(goog.global.createObjectURL)) {
+    return /** @type {goog.fs.url.UrlObject_} */ (goog.global);
+  } else {
+    return null;
+  }
+};
+
+
+/**
+ * Checks whether this browser supports Object Urls. If not, calls to
+ * createObjectUrl and revokeObjectUrl will result in an error.
+ *
+ * @return {boolean} True if this browser supports Object Urls.
+ */
+goog.fs.url.browserSupportsObjectUrls = function() {
+  return goog.fs.url.findUrlObject_() != null;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/functions/functions.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/functions/functions.js b/externs/GCL/externs/goog/functions/functions.js
new file mode 100644
index 0000000..d7ccf40
--- /dev/null
+++ b/externs/GCL/externs/goog/functions/functions.js
@@ -0,0 +1,332 @@
+// Copyright 2008 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview Utilities for creating functions. Loosely inspired by the
+ * java classes: http://goo.gl/GM0Hmu and http://goo.gl/6k7nI8.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+
+goog.provide('goog.functions');
+
+
+/**
+ * Creates a function that always returns the same value.
+ * @param {T} retValue The value to return.
+ * @return {function():T} The new function.
+ * @template T
+ */
+goog.functions.constant = function(retValue) {
+  return function() {
+    return retValue;
+  };
+};
+
+
+/**
+ * Always returns false.
+ * @type {function(...): boolean}
+ */
+goog.functions.FALSE = goog.functions.constant(false);
+
+
+/**
+ * Always returns true.
+ * @type {function(...): boolean}
+ */
+goog.functions.TRUE = goog.functions.constant(true);
+
+
+/**
+ * Always returns NULL.
+ * @type {function(...): null}
+ */
+goog.functions.NULL = goog.functions.constant(null);
+
+
+/**
+ * A simple function that returns the first argument of whatever is passed
+ * into it.
+ * @param {T=} opt_returnValue The single value that will be returned.
+ * @param {...*} var_args Optional trailing arguments. These are ignored.
+ * @return {T} The first argument passed in, or undefined if nothing was passed.
+ * @template T
+ */
+goog.functions.identity = function(opt_returnValue, var_args) {
+  return opt_returnValue;
+};
+
+
+/**
+ * Creates a function that always throws an error with the given message.
+ * @param {string} message The error message.
+ * @return {!Function} The error-throwing function.
+ */
+goog.functions.error = function(message) {
+  return function() {
+    throw Error(message);
+  };
+};
+
+
+/**
+ * Creates a function that throws the given object.
+ * @param {*} err An object to be thrown.
+ * @return {!Function} The error-throwing function.
+ */
+goog.functions.fail = function(err) {
+  return function() {
+    throw err;
+  }
+};
+
+
+/**
+ * Given a function, create a function that keeps opt_numArgs arguments and
+ * silently discards all additional arguments.
+ * @param {Function} f The original function.
+ * @param {number=} opt_numArgs The number of arguments to keep. Defaults to 0.
+ * @return {!Function} A version of f that only keeps the first opt_numArgs
+ *     arguments.
+ */
+goog.functions.lock = function(f, opt_numArgs) {
+  opt_numArgs = opt_numArgs || 0;
+  return function() {
+    return f.apply(this, Array.prototype.slice.call(arguments, 0, opt_numArgs));
+  };
+};
+
+
+/**
+ * Creates a function that returns its nth argument.
+ * @param {number} n The position of the return argument.
+ * @return {!Function} A new function.
+ */
+goog.functions.nth = function(n) {
+  return function() {
+    return arguments[n];
+  };
+};
+
+
+/**
+ * Given a function, create a new function that swallows its return value
+ * and replaces it with a new one.
+ * @param {Function} f A function.
+ * @param {T} retValue A new return value.
+ * @return {function(...?):T} A new function.
+ * @template T
+ */
+goog.functions.withReturnValue = function(f, retValue) {
+  return goog.functions.sequence(f, goog.functions.constant(retValue));
+};
+
+
+/**
+ * Creates a function that returns whether its arguement equals the given value.
+ *
+ * Example:
+ * var key = goog.object.findKey(obj, goog.functions.equalTo('needle'));
+ *
+ * @param {*} value The value to compare to.
+ * @param {boolean=} opt_useLooseComparison Whether to use a loose (==)
+ *     comparison rather than a strict (===) one. Defaults to false.
+ * @return {function(*):boolean} The new function.
+ */
+goog.functions.equalTo = function(value, opt_useLooseComparison) {
+  return function(other) {
+    return opt_useLooseComparison ? (value == other) : (value === other);
+  };
+};
+
+
+/**
+ * Creates the composition of the functions passed in.
+ * For example, (goog.functions.compose(f, g))(a) is equivalent to f(g(a)).
+ * @param {function(...?):T} fn The final function.
+ * @param {...Function} var_args A list of functions.
+ * @return {function(...?):T} The composition of all inputs.
+ * @template T
+ */
+goog.functions.compose = function(fn, var_args) {
+  var functions = arguments;
+  var length = functions.length;
+  return function() {
+    var result;
+    if (length) {
+      result = functions[length - 1].apply(this, arguments);
+    }
+
+    for (var i = length - 2; i >= 0; i--) {
+      result = functions[i].call(this, result);
+    }
+    return result;
+  };
+};
+
+
+/**
+ * Creates a function that calls the functions passed in in sequence, and
+ * returns the value of the last function. For example,
+ * (goog.functions.sequence(f, g))(x) is equivalent to f(x),g(x).
+ * @param {...Function} var_args A list of functions.
+ * @return {!Function} A function that calls all inputs in sequence.
+ */
+goog.functions.sequence = function(var_args) {
+  var functions = arguments;
+  var length = functions.length;
+  return function() {
+    var result;
+    for (var i = 0; i < length; i++) {
+      result = functions[i].apply(this, arguments);
+    }
+    return result;
+  };
+};
+
+
+/**
+ * Creates a function that returns true if each of its components evaluates
+ * to true. The components are evaluated in order, and the evaluation will be
+ * short-circuited as soon as a function returns false.
+ * For example, (goog.functions.and(f, g))(x) is equivalent to f(x) && g(x).
+ * @param {...Function} var_args A list of functions.
+ * @return {function(...?):boolean} A function that ANDs its component
+ *      functions.
+ */
+goog.functions.and = function(var_args) {
+  var functions = arguments;
+  var length = functions.length;
+  return function() {
+    for (var i = 0; i < length; i++) {
+      if (!functions[i].apply(this, arguments)) {
+        return false;
+      }
+    }
+    return true;
+  };
+};
+
+
+/**
+ * Creates a function that returns true if any of its components evaluates
+ * to true. The components are evaluated in order, and the evaluation will be
+ * short-circuited as soon as a function returns true.
+ * For example, (goog.functions.or(f, g))(x) is equivalent to f(x) || g(x).
+ * @param {...Function} var_args A list of functions.
+ * @return {function(...?):boolean} A function that ORs its component
+ *    functions.
+ */
+goog.functions.or = function(var_args) {
+  var functions = arguments;
+  var length = functions.length;
+  return function() {
+    for (var i = 0; i < length; i++) {
+      if (functions[i].apply(this, arguments)) {
+        return true;
+      }
+    }
+    return false;
+  };
+};
+
+
+/**
+ * Creates a function that returns the Boolean opposite of a provided function.
+ * For example, (goog.functions.not(f))(x) is equivalent to !f(x).
+ * @param {!Function} f The original function.
+ * @return {function(...?):boolean} A function that delegates to f and returns
+ * opposite.
+ */
+goog.functions.not = function(f) {
+  return function() {
+    return !f.apply(this, arguments);
+  };
+};
+
+
+/**
+ * Generic factory function to construct an object given the constructor
+ * and the arguments. Intended to be bound to create object factories.
+ *
+ * Example:
+ *
+ * var factory = goog.partial(goog.functions.create, Class);
+ *
+ * @param {function(new:T, ...)} constructor The constructor for the Object.
+ * @param {...*} var_args The arguments to be passed to the constructor.
+ * @return {T} A new instance of the class given in {@code constructor}.
+ * @template T
+ */
+goog.functions.create = function(constructor, var_args) {
+  /**
+   * @constructor
+   * @final
+   */
+  var temp = function() {};
+  temp.prototype = constructor.prototype;
+
+  // obj will have constructor's prototype in its chain and
+  // 'obj instanceof constructor' will be true.
+  var obj = new temp();
+
+  // obj is initialized by constructor.
+  // arguments is only array-like so lacks shift(), but can be used with
+  // the Array prototype function.
+  constructor.apply(obj, Array.prototype.slice.call(arguments, 1));
+  return obj;
+};
+
+
+/**
+ * @define {boolean} Whether the return value cache should be used.
+ *    This should only be used to disable caches when testing.
+ */
+goog.define('goog.functions.CACHE_RETURN_VALUE', true);
+
+
+/**
+ * Gives a wrapper function that caches the return value of a parameterless
+ * function when first called.
+ *
+ * When called for the first time, the given function is called and its
+ * return value is cached (thus this is only appropriate for idempotent
+ * functions).  Subsequent calls will return the cached return value. This
+ * allows the evaluation of expensive functions to be delayed until first used.
+ *
+ * To cache the return values of functions with parameters, see goog.memoize.
+ *
+ * @param {!function():T} fn A function to lazily evaluate.
+ * @return {!function():T} A wrapped version the function.
+ * @template T
+ */
+goog.functions.cacheReturnValue = function(fn) {
+  var called = false;
+  var value;
+
+  return function() {
+    if (!goog.functions.CACHE_RETURN_VALUE) {
+      return fn();
+    }
+
+    if (!called) {
+      value = fn();
+      called = true;
+    }
+
+    return value;
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/abstractdragdrop.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/abstractdragdrop.js b/externs/GCL/externs/goog/fx/abstractdragdrop.js
new file mode 100644
index 0000000..afd4af8
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/abstractdragdrop.js
@@ -0,0 +1,1540 @@
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview Abstract Base Class for Drag and Drop.
+ *
+ * Provides functionality for implementing drag and drop classes. Also provides
+ * support classes and events.
+ *
+ * @author eae@google.com (Emil A Eklund)
+ */
+
+goog.provide('goog.fx.AbstractDragDrop');
+goog.provide('goog.fx.AbstractDragDrop.EventType');
+goog.provide('goog.fx.DragDropEvent');
+goog.provide('goog.fx.DragDropItem');
+
+goog.require('goog.asserts');
+goog.require('goog.dom');
+goog.require('goog.dom.classlist');
+goog.require('goog.events');
+goog.require('goog.events.Event');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.fx.Dragger');
+goog.require('goog.math.Box');
+goog.require('goog.math.Coordinate');
+goog.require('goog.style');
+
+
+
+/**
+ * Abstract class that provides reusable functionality for implementing drag
+ * and drop functionality.
+ *
+ * This class also allows clients to define their own subtargeting function
+ * so that drop areas can have finer granularity then a singe element. This is
+ * accomplished by using a client provided function to map from element and
+ * coordinates to a subregion id.
+ *
+ * This class can also be made aware of scrollable containers that contain
+ * drop targets by calling addScrollableContainer. This will cause dnd to
+ * take changing scroll positions into account while a drag is occuring.
+ *
+ * @extends {goog.events.EventTarget}
+ * @constructor
+ */
+goog.fx.AbstractDragDrop = function() {
+  goog.fx.AbstractDragDrop.base(this, 'constructor');
+
+  /**
+   * List of items that makes up the drag source or drop target.
+   * @type {Array<goog.fx.DragDropItem>}
+   * @protected
+   * @suppress {underscore|visibility}
+   */
+  this.items_ = [];
+
+  /**
+   * List of associated drop targets.
+   * @type {Array<goog.fx.AbstractDragDrop>}
+   * @private
+   */
+  this.targets_ = [];
+
+  /**
+   * Scrollable containers to account for during drag
+   * @type {Array<goog.fx.ScrollableContainer_>}
+   * @private
+   */
+  this.scrollableContainers_ = [];
+
+};
+goog.inherits(goog.fx.AbstractDragDrop, goog.events.EventTarget);
+
+
+/**
+ * Minimum size (in pixels) for a dummy target. If the box for the target is
+ * less than the specified size it's not created.
+ * @type {number}
+ * @private
+ */
+goog.fx.AbstractDragDrop.DUMMY_TARGET_MIN_SIZE_ = 10;
+
+
+/**
+ * Flag indicating if it's a drag source, set by addTarget.
+ * @type {boolean}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.isSource_ = false;
+
+
+/**
+ * Flag indicating if it's a drop target, set when added as target to another
+ * DragDrop object.
+ * @type {boolean}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.isTarget_ = false;
+
+
+/**
+ * Subtargeting function accepting args:
+ * (goog.fx.DragDropItem, goog.math.Box, number, number)
+ * @type {Function}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.subtargetFunction_;
+
+
+/**
+ * Last active subtarget.
+ * @type {Object}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.activeSubtarget_;
+
+
+/**
+ * Class name to add to source elements being dragged. Set by setDragClass.
+ * @type {?string}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.dragClass_;
+
+
+/**
+ * Class name to add to source elements. Set by setSourceClass.
+ * @type {?string}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.sourceClass_;
+
+
+/**
+ * Class name to add to target elements. Set by setTargetClass.
+ * @type {?string}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.targetClass_;
+
+
+/**
+ * The SCROLL event target used to make drag element follow scrolling.
+ * @type {EventTarget}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.scrollTarget_;
+
+
+/**
+ * Dummy target, {@see maybeCreateDummyTargetForPosition_}.
+ * @type {goog.fx.ActiveDropTarget_}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.dummyTarget_;
+
+
+/**
+ * Whether the object has been initialized.
+ * @type {boolean}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.initialized_ = false;
+
+
+/**
+ * Constants for event names
+ * @const
+ */
+goog.fx.AbstractDragDrop.EventType = {
+  DRAGOVER: 'dragover',
+  DRAGOUT: 'dragout',
+  DRAG: 'drag',
+  DROP: 'drop',
+  DRAGSTART: 'dragstart',
+  DRAGEND: 'dragend'
+};
+
+
+/**
+ * Constant for distance threshold, in pixels, an element has to be moved to
+ * initiate a drag operation.
+ * @type {number}
+ */
+goog.fx.AbstractDragDrop.initDragDistanceThreshold = 5;
+
+
+/**
+ * Set class to add to source elements being dragged.
+ *
+ * @param {string} className Class to be added.  Must be a single, valid
+ *     classname.
+ */
+goog.fx.AbstractDragDrop.prototype.setDragClass = function(className) {
+  this.dragClass_ = className;
+};
+
+
+/**
+ * Set class to add to source elements.
+ *
+ * @param {string} className Class to be added.  Must be a single, valid
+ *     classname.
+ */
+goog.fx.AbstractDragDrop.prototype.setSourceClass = function(className) {
+  this.sourceClass_ = className;
+};
+
+
+/**
+ * Set class to add to target elements.
+ *
+ * @param {string} className Class to be added.  Must be a single, valid
+ *     classname.
+ */
+goog.fx.AbstractDragDrop.prototype.setTargetClass = function(className) {
+  this.targetClass_ = className;
+};
+
+
+/**
+ * Whether the control has been initialized.
+ *
+ * @return {boolean} True if it's been initialized.
+ */
+goog.fx.AbstractDragDrop.prototype.isInitialized = function() {
+  return this.initialized_;
+};
+
+
+/**
+ * Add item to drag object.
+ *
+ * @param {Element|string} element Dom Node, or string representation of node
+ *     id, to be used as drag source/drop target.
+ * @throws Error Thrown if called on instance of abstract class
+ */
+goog.fx.AbstractDragDrop.prototype.addItem = goog.abstractMethod;
+
+
+/**
+ * Associate drop target with drag element.
+ *
+ * @param {goog.fx.AbstractDragDrop} target Target to add.
+ */
+goog.fx.AbstractDragDrop.prototype.addTarget = function(target) {
+  this.targets_.push(target);
+  target.isTarget_ = true;
+  this.isSource_ = true;
+};
+
+
+/**
+ * Sets the SCROLL event target to make drag element follow scrolling.
+ *
+ * @param {EventTarget} scrollTarget The element that dispatches SCROLL events.
+ */
+goog.fx.AbstractDragDrop.prototype.setScrollTarget = function(scrollTarget) {
+  this.scrollTarget_ = scrollTarget;
+};
+
+
+/**
+ * Initialize drag and drop functionality for sources/targets already added.
+ * Sources/targets added after init has been called will initialize themselves
+ * one by one.
+ */
+goog.fx.AbstractDragDrop.prototype.init = function() {
+  if (this.initialized_) {
+    return;
+  }
+  for (var item, i = 0; item = this.items_[i]; i++) {
+    this.initItem(item);
+  }
+
+  this.initialized_ = true;
+};
+
+
+/**
+ * Initializes a single item.
+ *
+ * @param {goog.fx.DragDropItem} item Item to initialize.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.initItem = function(item) {
+  if (this.isSource_) {
+    goog.events.listen(item.element, goog.events.EventType.MOUSEDOWN,
+                       item.mouseDown_, false, item);
+    if (this.sourceClass_) {
+      goog.dom.classlist.add(
+          goog.asserts.assert(item.element), this.sourceClass_);
+    }
+  }
+
+  if (this.isTarget_ && this.targetClass_) {
+    goog.dom.classlist.add(
+        goog.asserts.assert(item.element), this.targetClass_);
+  }
+};
+
+
+/**
+ * Called when removing an item. Removes event listeners and classes.
+ *
+ * @param {goog.fx.DragDropItem} item Item to dispose.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.disposeItem = function(item) {
+  if (this.isSource_) {
+    goog.events.unlisten(item.element, goog.events.EventType.MOUSEDOWN,
+                         item.mouseDown_, false, item);
+    if (this.sourceClass_) {
+      goog.dom.classlist.remove(
+          goog.asserts.assert(item.element), this.sourceClass_);
+    }
+  }
+  if (this.isTarget_ && this.targetClass_) {
+    goog.dom.classlist.remove(
+        goog.asserts.assert(item.element), this.targetClass_);
+  }
+  item.dispose();
+};
+
+
+/**
+ * Removes all items.
+ */
+goog.fx.AbstractDragDrop.prototype.removeItems = function() {
+  for (var item, i = 0; item = this.items_[i]; i++) {
+    this.disposeItem(item);
+  }
+  this.items_.length = 0;
+};
+
+
+/**
+ * Starts a drag event for an item if the mouse button stays pressed and the
+ * cursor moves a few pixels. Allows dragging of items without first having to
+ * register them with addItem.
+ *
+ * @param {goog.events.BrowserEvent} event Mouse down event.
+ * @param {goog.fx.DragDropItem} item Item that's being dragged.
+ */
+goog.fx.AbstractDragDrop.prototype.maybeStartDrag = function(event, item) {
+  item.maybeStartDrag_(event, item.element);
+};
+
+
+/**
+ * Event handler that's used to start drag.
+ *
+ * @param {goog.events.BrowserEvent} event Mouse move event.
+ * @param {goog.fx.DragDropItem} item Item that's being dragged.
+ */
+goog.fx.AbstractDragDrop.prototype.startDrag = function(event, item) {
+
+  // Prevent a new drag operation from being started if another one is already
+  // in progress (could happen if the mouse was released outside of the
+  // document).
+  if (this.dragItem_) {
+    return;
+  }
+
+  this.dragItem_ = item;
+
+  // Dispatch DRAGSTART event
+  var dragStartEvent = new goog.fx.DragDropEvent(
+      goog.fx.AbstractDragDrop.EventType.DRAGSTART, this, this.dragItem_);
+  if (this.dispatchEvent(dragStartEvent) == false) {
+    this.dragItem_ = null;
+    return;
+  }
+
+  // Get the source element and create a drag element for it.
+  var el = item.getCurrentDragElement();
+  this.dragEl_ = this.createDragElement(el);
+  var doc = goog.dom.getOwnerDocument(el);
+  doc.body.appendChild(this.dragEl_);
+
+  this.dragger_ = this.createDraggerFor(el, this.dragEl_, event);
+  this.dragger_.setScrollTarget(this.scrollTarget_);
+
+  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.DRAG,
+                     this.moveDrag_, false, this);
+
+  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.END,
+                     this.endDrag, false, this);
+
+  // IE may issue a 'selectstart' event when dragging over an iframe even when
+  // default mousemove behavior is suppressed. If the default selectstart
+  // behavior is not suppressed, elements dragged over will show as selected.
+  goog.events.listen(doc.body, goog.events.EventType.SELECTSTART,
+                     this.suppressSelect_);
+
+  this.recalculateDragTargets();
+  this.recalculateScrollableContainers();
+  this.activeTarget_ = null;
+  this.initScrollableContainerListeners_();
+  this.dragger_.startDrag(event);
+
+  event.preventDefault();
+};
+
+
+/**
+ * Recalculates the geometry of this source's drag targets.  Call this
+ * if the position or visibility of a drag target has changed during
+ * a drag, or if targets are added or removed.
+ *
+ * TODO(user): this is an expensive operation;  more efficient APIs
+ * may be necessary.
+ */
+goog.fx.AbstractDragDrop.prototype.recalculateDragTargets = function() {
+  this.targetList_ = [];
+  for (var target, i = 0; target = this.targets_[i]; i++) {
+    for (var itm, j = 0; itm = target.items_[j]; j++) {
+      this.addDragTarget_(target, itm);
+    }
+  }
+  if (!this.targetBox_) {
+    this.targetBox_ = new goog.math.Box(0, 0, 0, 0);
+  }
+};
+
+
+/**
+ * Recalculates the current scroll positions of scrollable containers and
+ * allocates targets. Call this if the position of a container changed or if
+ * targets are added or removed.
+ */
+goog.fx.AbstractDragDrop.prototype.recalculateScrollableContainers =
+    function() {
+  var container, i, j, target;
+  for (i = 0; container = this.scrollableContainers_[i]; i++) {
+    container.containedTargets_ = [];
+    container.savedScrollLeft_ = container.element_.scrollLeft;
+    container.savedScrollTop_ = container.element_.scrollTop;
+    var pos = goog.style.getPageOffset(container.element_);
+    var size = goog.style.getSize(container.element_);
+    container.box_ = new goog.math.Box(pos.y, pos.x + size.width,
+                                       pos.y + size.height, pos.x);
+  }
+
+  for (i = 0; target = this.targetList_[i]; i++) {
+    for (j = 0; container = this.scrollableContainers_[j]; j++) {
+      if (goog.dom.contains(container.element_, target.element_)) {
+        container.containedTargets_.push(target);
+        target.scrollableContainer_ = container;
+      }
+    }
+  }
+};
+
+
+/**
+ * Creates the Dragger for the drag element.
+ * @param {Element} sourceEl Drag source element.
+ * @param {Element} el the element created by createDragElement().
+ * @param {goog.events.BrowserEvent} event Mouse down event for start of drag.
+ * @return {!goog.fx.Dragger} The new Dragger.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.createDraggerFor =
+    function(sourceEl, el, event) {
+  // Position the drag element.
+  var pos = this.getDragElementPosition(sourceEl, el, event);
+  el.style.position = 'absolute';
+  el.style.left = pos.x + 'px';
+  el.style.top = pos.y + 'px';
+  return new goog.fx.Dragger(el);
+};
+
+
+/**
+ * Event handler that's used to stop drag. Fires a drop event if over a valid
+ * target.
+ *
+ * @param {goog.fx.DragEvent} event Drag event.
+ */
+goog.fx.AbstractDragDrop.prototype.endDrag = function(event) {
+  var activeTarget = event.dragCanceled ? null : this.activeTarget_;
+  if (activeTarget && activeTarget.target_) {
+    var clientX = event.clientX;
+    var clientY = event.clientY;
+    var scroll = this.getScrollPos();
+    var x = clientX + scroll.x;
+    var y = clientY + scroll.y;
+
+    var subtarget;
+    // If a subtargeting function is enabled get the current subtarget
+    if (this.subtargetFunction_) {
+      subtarget = this.subtargetFunction_(activeTarget.item_,
+          activeTarget.box_, x, y);
+    }
+
+    var dragEvent = new goog.fx.DragDropEvent(
+        goog.fx.AbstractDragDrop.EventType.DRAG, this, this.dragItem_,
+        activeTarget.target_, activeTarget.item_, activeTarget.element_,
+        clientX, clientY, x, y);
+    this.dispatchEvent(dragEvent);
+
+    var dropEvent = new goog.fx.DragDropEvent(
+        goog.fx.AbstractDragDrop.EventType.DROP, this, this.dragItem_,
+        activeTarget.target_, activeTarget.item_, activeTarget.element_,
+        clientX, clientY, x, y, subtarget);
+    activeTarget.target_.dispatchEvent(dropEvent);
+  }
+
+  var dragEndEvent = new goog.fx.DragDropEvent(
+      goog.fx.AbstractDragDrop.EventType.DRAGEND, this, this.dragItem_);
+  this.dispatchEvent(dragEndEvent);
+
+  goog.events.unlisten(this.dragger_, goog.fx.Dragger.EventType.DRAG,
+                       this.moveDrag_, false, this);
+  goog.events.unlisten(this.dragger_, goog.fx.Dragger.EventType.END,
+                       this.endDrag, false, this);
+  var doc = goog.dom.getOwnerDocument(this.dragItem_.getCurrentDragElement());
+  goog.events.unlisten(doc.body, goog.events.EventType.SELECTSTART,
+                       this.suppressSelect_);
+
+
+  this.afterEndDrag(this.activeTarget_ ? this.activeTarget_.item_ : null);
+};
+
+
+/**
+ * Called after a drag operation has finished.
+ *
+ * @param {goog.fx.DragDropItem=} opt_dropTarget Target for successful drop.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.afterEndDrag = function(opt_dropTarget) {
+  this.disposeDrag();
+};
+
+
+/**
+ * Called once a drag operation has finished. Removes event listeners and
+ * elements.
+ *
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.disposeDrag = function() {
+  this.disposeScrollableContainerListeners_();
+  this.dragger_.dispose();
+
+  goog.dom.removeNode(this.dragEl_);
+  delete this.dragItem_;
+  delete this.dragEl_;
+  delete this.dragger_;
+  delete this.targetList_;
+  delete this.activeTarget_;
+};
+
+
+/**
+ * Event handler for drag events. Determines the active drop target, if any, and
+ * fires dragover and dragout events appropriately.
+ *
+ * @param {goog.fx.DragEvent} event Drag event.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.moveDrag_ = function(event) {
+  var position = this.getEventPosition(event);
+  var x = position.x;
+  var y = position.y;
+
+  // Check if we're still inside the bounds of the active target, if not fire
+  // a dragout event and proceed to find a new target.
+  var activeTarget = this.activeTarget_;
+
+  var subtarget;
+  if (activeTarget) {
+    // If a subtargeting function is enabled get the current subtarget
+    if (this.subtargetFunction_ && activeTarget.target_) {
+      subtarget = this.subtargetFunction_(activeTarget.item_,
+          activeTarget.box_, x, y);
+    }
+
+    if (activeTarget.box_.contains(position) &&
+        subtarget == this.activeSubtarget_) {
+      return;
+    }
+
+    if (activeTarget.target_) {
+      var sourceDragOutEvent = new goog.fx.DragDropEvent(
+          goog.fx.AbstractDragDrop.EventType.DRAGOUT, this, this.dragItem_,
+          activeTarget.target_, activeTarget.item_, activeTarget.element_);
+      this.dispatchEvent(sourceDragOutEvent);
+
+      // The event should be dispatched the by target DragDrop so that the
+      // target DragDrop can manage these events without having to know what
+      // sources this is a target for.
+      var targetDragOutEvent = new goog.fx.DragDropEvent(
+          goog.fx.AbstractDragDrop.EventType.DRAGOUT,
+          this,
+          this.dragItem_,
+          activeTarget.target_,
+          activeTarget.item_,
+          activeTarget.element_,
+          undefined,
+          undefined,
+          undefined,
+          undefined,
+          this.activeSubtarget_);
+      activeTarget.target_.dispatchEvent(targetDragOutEvent);
+    }
+    this.activeSubtarget_ = subtarget;
+    this.activeTarget_ = null;
+  }
+
+  // Check if inside target box
+  if (this.targetBox_.contains(position)) {
+    // Search for target and fire a dragover event if found
+    activeTarget = this.activeTarget_ = this.getTargetFromPosition_(position);
+    if (activeTarget && activeTarget.target_) {
+      // If a subtargeting function is enabled get the current subtarget
+      if (this.subtargetFunction_) {
+        subtarget = this.subtargetFunction_(activeTarget.item_,
+            activeTarget.box_, x, y);
+      }
+      var sourceDragOverEvent = new goog.fx.DragDropEvent(
+          goog.fx.AbstractDragDrop.EventType.DRAGOVER, this, this.dragItem_,
+          activeTarget.target_, activeTarget.item_, activeTarget.element_);
+      sourceDragOverEvent.subtarget = subtarget;
+      this.dispatchEvent(sourceDragOverEvent);
+
+      // The event should be dispatched by the target DragDrop so that the
+      // target DragDrop can manage these events without having to know what
+      // sources this is a target for.
+      var targetDragOverEvent = new goog.fx.DragDropEvent(
+          goog.fx.AbstractDragDrop.EventType.DRAGOVER, this, this.dragItem_,
+          activeTarget.target_, activeTarget.item_, activeTarget.element_,
+          event.clientX, event.clientY, undefined, undefined, subtarget);
+      activeTarget.target_.dispatchEvent(targetDragOverEvent);
+
+    } else if (!activeTarget) {
+      // If no target was found create a dummy one so we won't have to iterate
+      // over all possible targets for every move event.
+      this.activeTarget_ = this.maybeCreateDummyTargetForPosition_(x, y);
+    }
+  }
+};
+
+
+/**
+ * Event handler for suppressing selectstart events. Selecting should be
+ * disabled while dragging.
+ *
+ * @param {goog.events.Event} event The selectstart event to suppress.
+ * @return {boolean} Whether to perform default behavior.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.suppressSelect_ = function(event) {
+  return false;
+};
+
+
+/**
+ * Sets up listeners for the scrollable containers that keep track of their
+ * scroll positions.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.initScrollableContainerListeners_ =
+    function() {
+  var container, i;
+  for (i = 0; container = this.scrollableContainers_[i]; i++) {
+    goog.events.listen(container.element_, goog.events.EventType.SCROLL,
+        this.containerScrollHandler_, false, this);
+  }
+};
+
+
+/**
+ * Cleans up the scrollable container listeners.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.disposeScrollableContainerListeners_ =
+    function() {
+  for (var i = 0, container; container = this.scrollableContainers_[i]; i++) {
+    goog.events.unlisten(container.element_, 'scroll',
+        this.containerScrollHandler_, false, this);
+    container.containedTargets_ = [];
+  }
+};
+
+
+/**
+ * Makes drag and drop aware of a target container that could scroll mid drag.
+ * @param {Element} element The scroll container.
+ */
+goog.fx.AbstractDragDrop.prototype.addScrollableContainer = function(element) {
+  this.scrollableContainers_.push(new goog.fx.ScrollableContainer_(element));
+};
+
+
+/**
+ * Removes all scrollable containers.
+ */
+goog.fx.AbstractDragDrop.prototype.removeAllScrollableContainers = function() {
+  this.disposeScrollableContainerListeners_();
+  this.scrollableContainers_ = [];
+};
+
+
+/**
+ * Event handler for containers scrolling.
+ * @param {goog.events.Event} e The event.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.containerScrollHandler_ = function(e) {
+  for (var i = 0, container; container = this.scrollableContainers_[i]; i++) {
+    if (e.target == container.element_) {
+      var deltaTop = container.savedScrollTop_ - container.element_.scrollTop;
+      var deltaLeft =
+          container.savedScrollLeft_ - container.element_.scrollLeft;
+      container.savedScrollTop_ = container.element_.scrollTop;
+      container.savedScrollLeft_ = container.element_.scrollLeft;
+
+      // When the container scrolls, it's possible that one of the targets will
+      // move to the region contained by the dummy target. Since we don't know
+      // which sides (if any) of the dummy target are defined by targets
+      // contained by this container, we are conservative and just shrink it.
+      if (this.dummyTarget_ && this.activeTarget_ == this.dummyTarget_) {
+        if (deltaTop > 0) {
+          this.dummyTarget_.box_.top += deltaTop;
+        } else {
+          this.dummyTarget_.box_.bottom += deltaTop;
+        }
+        if (deltaLeft > 0) {
+          this.dummyTarget_.box_.left += deltaLeft;
+        } else {
+          this.dummyTarget_.box_.right += deltaLeft;
+        }
+      }
+      for (var j = 0, target; target = container.containedTargets_[j]; j++) {
+        var box = target.box_;
+        box.top += deltaTop;
+        box.left += deltaLeft;
+        box.bottom += deltaTop;
+        box.right += deltaLeft;
+
+        this.calculateTargetBox_(box);
+      }
+    }
+  }
+  this.dragger_.onScroll_(e);
+};
+
+
+/**
+ * Set a function that provides subtargets. A subtargeting function
+ * returns an arbitrary identifier for each subtarget of an element.
+ * DnD code will generate additional drag over / out events when
+ * switching from subtarget to subtarget. This is useful for instance
+ * if you are interested if you are on the top half or the bottom half
+ * of the element.
+ * The provided function will be given the DragDropItem, box, x, y
+ * box is the current window coordinates occupied by element
+ * x, y is the mouse position in window coordinates
+ *
+ * @param {Function} f The new subtarget function.
+ */
+goog.fx.AbstractDragDrop.prototype.setSubtargetFunction = function(f) {
+  this.subtargetFunction_ = f;
+};
+
+
+/**
+ * Creates an element for the item being dragged.
+ *
+ * @param {Element} sourceEl Drag source element.
+ * @return {Element} The new drag element.
+ */
+goog.fx.AbstractDragDrop.prototype.createDragElement = function(sourceEl) {
+  var dragEl = this.createDragElementInternal(sourceEl);
+  goog.asserts.assert(dragEl);
+  if (this.dragClass_) {
+    goog.dom.classlist.add(dragEl, this.dragClass_);
+  }
+
+  return dragEl;
+};
+
+
+/**
+ * Returns the position for the drag element.
+ *
+ * @param {Element} el Drag source element.
+ * @param {Element} dragEl The dragged element created by createDragElement().
+ * @param {goog.events.BrowserEvent} event Mouse down event for start of drag.
+ * @return {!goog.math.Coordinate} The position for the drag element.
+ */
+goog.fx.AbstractDragDrop.prototype.getDragElementPosition =
+    function(el, dragEl, event) {
+  var pos = goog.style.getPageOffset(el);
+
+  // Subtract margin from drag element position twice, once to adjust the
+  // position given by the original node and once for the drag node.
+  var marginBox = goog.style.getMarginBox(el);
+  pos.x -= (marginBox.left || 0) * 2;
+  pos.y -= (marginBox.top || 0) * 2;
+
+  return pos;
+};
+
+
+/**
+ * Returns the dragger object.
+ *
+ * @return {goog.fx.Dragger} The dragger object used by this drag and drop
+ *     instance.
+ */
+goog.fx.AbstractDragDrop.prototype.getDragger = function() {
+  return this.dragger_;
+};
+
+
+/**
+ * Creates copy of node being dragged.
+ *
+ * @param {Element} sourceEl Element to copy.
+ * @return {!Element} The clone of {@code sourceEl}.
+ * @deprecated Use goog.fx.Dragger.cloneNode().
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.cloneNode_ = function(sourceEl) {
+  return goog.fx.Dragger.cloneNode(sourceEl);
+};
+
+
+/**
+ * Generates an element to follow the cursor during dragging, given a drag
+ * source element.  The default behavior is simply to clone the source element,
+ * but this may be overridden in subclasses.  This method is called by
+ * {@code createDragElement()} before the drag class is added.
+ *
+ * @param {Element} sourceEl Drag source element.
+ * @return {!Element} The new drag element.
+ * @protected
+ * @suppress {deprecated}
+ */
+goog.fx.AbstractDragDrop.prototype.createDragElementInternal =
+    function(sourceEl) {
+  return this.cloneNode_(sourceEl);
+};
+
+
+/**
+ * Add possible drop target for current drag operation.
+ *
+ * @param {goog.fx.AbstractDragDrop} target Drag handler.
+ * @param {goog.fx.DragDropItem} item Item that's being dragged.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.addDragTarget_ = function(target, item) {
+
+  // Get all the draggable elements and add each one.
+  var draggableElements = item.getDraggableElements();
+  var targetList = this.targetList_;
+  for (var i = 0; i < draggableElements.length; i++) {
+    var draggableElement = draggableElements[i];
+
+    // Determine target position and dimension
+    var box = this.getElementBox(item, draggableElement);
+
+    targetList.push(
+        new goog.fx.ActiveDropTarget_(box, target, item, draggableElement));
+
+    this.calculateTargetBox_(box);
+  }
+};
+
+
+/**
+ * Calculates the position and dimension of a draggable element.
+ *
+ * @param {goog.fx.DragDropItem} item Item that's being dragged.
+ * @param {Element} element The element to calculate the box.
+ *
+ * @return {!goog.math.Box} Box describing the position and dimension
+ *     of element.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.getElementBox = function(item, element) {
+  var pos = goog.style.getPageOffset(element);
+  var size = goog.style.getSize(element);
+  return new goog.math.Box(pos.y, pos.x + size.width, pos.y + size.height,
+      pos.x);
+};
+
+
+/**
+ * Calculate the outer bounds (the region all targets are inside).
+ *
+ * @param {goog.math.Box} box Box describing the position and dimension
+ *     of a drag target.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.calculateTargetBox_ = function(box) {
+  if (this.targetList_.length == 1) {
+    this.targetBox_ = new goog.math.Box(box.top, box.right,
+                                        box.bottom, box.left);
+  } else {
+    var tb = this.targetBox_;
+    tb.left = Math.min(box.left, tb.left);
+    tb.right = Math.max(box.right, tb.right);
+    tb.top = Math.min(box.top, tb.top);
+    tb.bottom = Math.max(box.bottom, tb.bottom);
+  }
+};
+
+
+/**
+ * Creates a dummy target for the given cursor position. The assumption is to
+ * create as big dummy target box as possible, the only constraints are:
+ * - The dummy target box cannot overlap any of real target boxes.
+ * - The dummy target has to contain a point with current mouse coordinates.
+ *
+ * NOTE: For performance reasons the box construction algorithm is kept simple
+ * and it is not optimal (see example below). Currently it is O(n) in regard to
+ * the number of real drop target boxes, but its result depends on the order
+ * of those boxes being processed (the order in which they're added to the
+ * targetList_ collection).
+ *
+ * The algorithm.
+ * a) Assumptions
+ * - Mouse pointer is in the bounding box of real target boxes.
+ * - None of the boxes have negative coordinate values.
+ * - Mouse pointer is not contained by any of "real target" boxes.
+ * - For targets inside a scrollable container, the box used is the
+ *   intersection of the scrollable container's box and the target's box.
+ *   This is because the part of the target that extends outside the scrollable
+ *   container should not be used in the clipping calculations.
+ *
+ * b) Outline
+ * - Initialize the fake target to the bounding box of real targets.
+ * - For each real target box - clip the fake target box so it does not contain
+ *   that target box, but does contain the mouse pointer.
+ *   -- Project the real target box, mouse pointer and fake target box onto
+ *      both axes and calculate the clipping coordinates.
+ *   -- Only one coordinate is used to clip the fake target box to keep the
+ *      fake target as big as possible.
+ *   -- If the projection of the real target box contains the mouse pointer,
+ *      clipping for a given axis is not possible.
+ *   -- If both clippings are possible, the clipping more distant from the
+ *      mouse pointer is selected to keep bigger fake target area.
+ * - Save the created fake target only if it has a big enough area.
+ *
+ *
+ * c) Example
+ * <pre>
+ *        Input:           Algorithm created box:        Maximum box:
+ * +---------------------+ +---------------------+ +---------------------+
+ * | B1      |        B2 | | B1               B2 | | B1               B2 |
+ * |         |           | |   +-------------+   | |+-------------------+|
+ * |---------x-----------| |   |             |   | ||                   ||
+ * |         |           | |   |             |   | ||                   ||
+ * |         |           | |   |             |   | ||                   ||
+ * |         |           | |   |             |   | ||                   ||
+ * |         |           | |   |             |   | ||                   ||
+ * |         |           | |   +-------------+   | |+-------------------+|
+ * | B4      |        B3 | | B4               B3 | | B4               B3 |
+ * +---------------------+ +---------------------+ +---------------------+
+ * </pre>
+ *
+ * @param {number} x Cursor position on the x-axis.
+ * @param {number} y Cursor position on the y-axis.
+ * @return {goog.fx.ActiveDropTarget_} Dummy drop target.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.maybeCreateDummyTargetForPosition_ =
+    function(x, y) {
+  if (!this.dummyTarget_) {
+    this.dummyTarget_ = new goog.fx.ActiveDropTarget_(this.targetBox_.clone());
+  }
+  var fakeTargetBox = this.dummyTarget_.box_;
+
+  // Initialize the fake target box to the bounding box of DnD targets.
+  fakeTargetBox.top = this.targetBox_.top;
+  fakeTargetBox.right = this.targetBox_.right;
+  fakeTargetBox.bottom = this.targetBox_.bottom;
+  fakeTargetBox.left = this.targetBox_.left;
+
+  // Clip the fake target based on mouse position and DnD target boxes.
+  for (var i = 0, target; target = this.targetList_[i]; i++) {
+    var box = target.box_;
+
+    if (target.scrollableContainer_) {
+      // If the target has a scrollable container, use the intersection of that
+      // container's box and the target's box.
+      var scrollBox = target.scrollableContainer_.box_;
+
+      box = new goog.math.Box(
+          Math.max(box.top, scrollBox.top),
+          Math.min(box.right, scrollBox.right),
+          Math.min(box.bottom, scrollBox.bottom),
+          Math.max(box.left, scrollBox.left));
+    }
+
+    // Calculate clipping coordinates for horizontal and vertical axis.
+    // The clipping coordinate is calculated by projecting fake target box,
+    // the mouse pointer and DnD target box onto an axis and checking how
+    // box projections overlap and if the projected DnD target box contains
+    // mouse pointer. The clipping coordinate cannot be computed and is set to
+    // a negative value if the projected DnD target contains the mouse pointer.
+
+    var horizontalClip = null; // Assume mouse is above or below the DnD box.
+    if (x >= box.right) { // Mouse is to the right of the DnD box.
+      // Clip the fake box only if the DnD box overlaps it.
+      horizontalClip = box.right > fakeTargetBox.left ?
+          box.right : fakeTargetBox.left;
+    } else if (x < box.left) { // Mouse is to the left of the DnD box.
+      // Clip the fake box only if the DnD box overlaps it.
+      horizontalClip = box.left < fakeTargetBox.right ?
+          box.left : fakeTargetBox.right;
+    }
+    var verticalClip = null;
+    if (y >= box.bottom) {
+      verticalClip = box.bottom > fakeTargetBox.top ?
+          box.bottom : fakeTargetBox.top;
+    } else if (y < box.top) {
+      verticalClip = box.top < fakeTargetBox.bottom ?
+          box.top : fakeTargetBox.bottom;
+    }
+
+    // If both clippings are possible, choose one that gives us larger distance
+    // to mouse pointer (mark the shorter clipping as impossible, by setting it
+    // to null).
+    if (!goog.isNull(horizontalClip) && !goog.isNull(verticalClip)) {
+      if (Math.abs(horizontalClip - x) > Math.abs(verticalClip - y)) {
+        verticalClip = null;
+      } else {
+        horizontalClip = null;
+      }
+    }
+
+    // Clip none or one of fake target box sides (at most one clipping
+    // coordinate can be active).
+    if (!goog.isNull(horizontalClip)) {
+      if (horizontalClip <= x) {
+        fakeTargetBox.left = horizontalClip;
+      } else {
+        fakeTargetBox.right = horizontalClip;
+      }
+    } else if (!goog.isNull(verticalClip)) {
+      if (verticalClip <= y) {
+        fakeTargetBox.top = verticalClip;
+      } else {
+        fakeTargetBox.bottom = verticalClip;
+      }
+    }
+  }
+
+  // Only return the new fake target if it is big enough.
+  return (fakeTargetBox.right - fakeTargetBox.left) *
+         (fakeTargetBox.bottom - fakeTargetBox.top) >=
+         goog.fx.AbstractDragDrop.DUMMY_TARGET_MIN_SIZE_ ?
+      this.dummyTarget_ : null;
+};
+
+
+/**
+ * Returns the target for a given cursor position.
+ *
+ * @param {goog.math.Coordinate} position Cursor position.
+ * @return {Object} Target for position or null if no target was defined
+ *     for the given position.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.getTargetFromPosition_ = function(position) {
+  for (var target, i = 0; target = this.targetList_[i]; i++) {
+    if (target.box_.contains(position)) {
+      if (target.scrollableContainer_) {
+        // If we have a scrollable container we will need to make sure
+        // we account for clipping of the scroll area
+        var box = target.scrollableContainer_.box_;
+        if (box.contains(position)) {
+          return target;
+        }
+      } else {
+        return target;
+      }
+    }
+  }
+
+  return null;
+};
+
+
+/**
+ * Checks whatever a given point is inside a given box.
+ *
+ * @param {number} x Cursor position on the x-axis.
+ * @param {number} y Cursor position on the y-axis.
+ * @param {goog.math.Box} box Box to check position against.
+ * @return {boolean} Whether the given point is inside {@code box}.
+ * @protected
+ * @deprecated Use goog.math.Box.contains.
+ */
+goog.fx.AbstractDragDrop.prototype.isInside = function(x, y, box) {
+  return x >= box.left &&
+         x < box.right &&
+         y >= box.top &&
+         y < box.bottom;
+};
+
+
+/**
+ * Gets the scroll distance as a coordinate object, using
+ * the window of the current drag element's dom.
+ * @return {!goog.math.Coordinate} Object with scroll offsets 'x' and 'y'.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.getScrollPos = function() {
+  return goog.dom.getDomHelper(this.dragEl_).getDocumentScroll();
+};
+
+
+/**
+ * Get the position of a drag event.
+ * @param {goog.fx.DragEvent} event Drag event.
+ * @return {!goog.math.Coordinate} Position of the event.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.getEventPosition = function(event) {
+  var scroll = this.getScrollPos();
+  return new goog.math.Coordinate(event.clientX + scroll.x,
+                                  event.clientY + scroll.y);
+};
+
+
+/** @override */
+goog.fx.AbstractDragDrop.prototype.disposeInternal = function() {
+  goog.fx.AbstractDragDrop.base(this, 'disposeInternal');
+  this.removeItems();
+};
+
+
+
+/**
+ * Object representing a drag and drop event.
+ *
+ * @param {string} type Event type.
+ * @param {goog.fx.AbstractDragDrop} source Source drag drop object.
+ * @param {goog.fx.DragDropItem} sourceItem Source item.
+ * @param {goog.fx.AbstractDragDrop=} opt_target Target drag drop object.
+ * @param {goog.fx.DragDropItem=} opt_targetItem Target item.
+ * @param {Element=} opt_targetElement Target element.
+ * @param {number=} opt_clientX X-Position relative to the screen.
+ * @param {number=} opt_clientY Y-Position relative to the screen.
+ * @param {number=} opt_x X-Position relative to the viewport.
+ * @param {number=} opt_y Y-Position relative to the viewport.
+ * @param {Object=} opt_subtarget The currently active subtarget.
+ * @extends {goog.events.Event}
+ * @constructor
+ */
+goog.fx.DragDropEvent = function(type, source, sourceItem,
+                                 opt_target, opt_targetItem, opt_targetElement,
+                                 opt_clientX, opt_clientY, opt_x, opt_y,
+                                 opt_subtarget) {
+  // TODO(eae): Get rid of all the optional parameters and have the caller set
+  // the fields directly instead.
+  goog.fx.DragDropEvent.base(this, 'constructor', type);
+
+  /**
+   * Reference to the source goog.fx.AbstractDragDrop object.
+   * @type {goog.fx.AbstractDragDrop}
+   */
+  this.dragSource = source;
+
+  /**
+   * Reference to the source goog.fx.DragDropItem object.
+   * @type {goog.fx.DragDropItem}
+   */
+  this.dragSourceItem = sourceItem;
+
+  /**
+   * Reference to the target goog.fx.AbstractDragDrop object.
+   * @type {goog.fx.AbstractDragDrop|undefined}
+   */
+  this.dropTarget = opt_target;
+
+  /**
+   * Reference to the target goog.fx.DragDropItem object.
+   * @type {goog.fx.DragDropItem|undefined}
+   */
+  this.dropTargetItem = opt_targetItem;
+
+  /**
+   * The actual element of the drop target that is the target for this event.
+   * @type {Element|undefined}
+   */
+  this.dropTargetElement = opt_targetElement;
+
+  /**
+   * X-Position relative to the screen.
+   * @type {number|undefined}
+   */
+  this.clientX = opt_clientX;
+
+  /**
+   * Y-Position relative to the screen.
+   * @type {number|undefined}
+   */
+  this.clientY = opt_clientY;
+
+  /**
+   * X-Position relative to the viewport.
+   * @type {number|undefined}
+   */
+  this.viewportX = opt_x;
+
+  /**
+   * Y-Position relative to the viewport.
+   * @type {number|undefined}
+   */
+  this.viewportY = opt_y;
+
+  /**
+   * The subtarget that is currently active if a subtargeting function
+   * is supplied.
+   * @type {Object|undefined}
+   */
+  this.subtarget = opt_subtarget;
+};
+goog.inherits(goog.fx.DragDropEvent, goog.events.Event);
+
+
+
+/**
+ * Class representing a source or target element for drag and drop operations.
+ *
+ * @param {Element|string} element Dom Node, or string representation of node
+ *     id, to be used as drag source/drop target.
+ * @param {Object=} opt_data Data associated with the source/target.
+ * @throws Error If no element argument is provided or if the type is invalid
+ * @extends {goog.events.EventTarget}
+ * @constructor
+ */
+goog.fx.DragDropItem = function(element, opt_data) {
+  goog.fx.DragDropItem.base(this, 'constructor');
+
+  /**
+   * Reference to drag source/target element
+   * @type {Element}
+   */
+  this.element = goog.dom.getElement(element);
+
+  /**
+   * Data associated with element.
+   * @type {Object|undefined}
+   */
+  this.data = opt_data;
+
+  /**
+   * Drag object the item belongs to.
+   * @type {goog.fx.AbstractDragDrop?}
+   * @private
+   */
+  this.parent_ = null;
+
+  /**
+   * Event handler for listeners on events that can initiate a drag.
+   * @type {!goog.events.EventHandler<!goog.fx.DragDropItem>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+  this.registerDisposable(this.eventHandler_);
+
+  if (!this.element) {
+    throw Error('Invalid argument');
+  }
+};
+goog.inherits(goog.fx.DragDropItem, goog.events.EventTarget);
+
+
+/**
+ * The current element being dragged. This is needed because a DragDropItem can
+ * have multiple elements that can be dragged.
+ * @type {Element}
+ * @private
+ */
+goog.fx.DragDropItem.prototype.currentDragElement_ = null;
+
+
+/**
+ * Get the data associated with the source/target.
+ * @return {Object|null|undefined} Data associated with the source/target.
+ */
+goog.fx.DragDropItem.prototype.getData = function() {
+  return this.data;
+};
+
+
+/**
+ * Gets the element that is actually draggable given that the given target was
+ * attempted to be dragged. This should be overriden when the element that was
+ * given actually contains many items that can be dragged. From the target, you
+ * can determine what element should actually be dragged.
+ *
+ * @param {Element} target The target that was attempted to be dragged.
+ * @return {Element} The element that is draggable given the target. If
+ *     none are draggable, this will return null.
+ */
+goog.fx.DragDropItem.prototype.getDraggableElement = function(target) {
+  return target;
+};
+
+
+/**
+ * Gets the element that is currently being dragged.
+ *
+ * @return {Element} The element that is currently being dragged.
+ */
+goog.fx.DragDropItem.prototype.getCurrentDragElement = function() {
+  return this.currentDragElement_;
+};
+
+
+/**
+ * Gets all the elements of this item that are potentially draggable/
+ *
+ * @return {!Array<Element>} The draggable elements.
+ */
+goog.fx.DragDropItem.prototype.getDraggableElements = function() {
+  return [this.element];
+};
+
+
+/**
+ * Event handler for mouse down.
+ *
+ * @param {goog.events.BrowserEvent} event Mouse down event.
+ * @private
+ */
+goog.fx.DragDropItem.prototype.mouseDown_ = function(event) {
+  if (!event.isMouseActionButton()) {
+    return;
+  }
+
+  // Get the draggable element for the target.
+  var element = this.getDraggableElement(/** @type {Element} */ (event.target));
+  if (element) {
+    this.maybeStartDrag_(event, element);
+  }
+};
+
+
+/**
+ * Sets the dragdrop to which this item belongs.
+ * @param {goog.fx.AbstractDragDrop} parent The parent dragdrop.
+ */
+goog.fx.DragDropItem.prototype.setParent = function(parent) {
+  this.parent_ = parent;
+};
+
+
+/**
+ * Adds mouse move, mouse out and mouse up handlers.
+ *
+ * @param {goog.events.BrowserEvent} event Mouse down event.
+ * @param {Element} element Element.
+ * @private
+ */
+goog.fx.DragDropItem.prototype.maybeStartDrag_ = function(event, element) {
+  var eventType = goog.events.EventType;
+  this.eventHandler_.
+      listen(element, eventType.MOUSEMOVE, this.mouseMove_, false).
+      listen(element, eventType.MOUSEOUT, this.mouseMove_, false);
+
+  // Capture the MOUSEUP on the document to ensure that we cancel the start
+  // drag handlers even if the mouse up occurs on some other element. This can
+  // happen for instance when the mouse down changes the geometry of the element
+  // clicked on (e.g. through changes in activation styling) such that the mouse
+  // up occurs outside the original element.
+  var doc = goog.dom.getOwnerDocument(element);
+  this.eventHandler_.listen(doc, eventType.MOUSEUP, this.mouseUp_, true);
+
+  this.currentDragElement_ = element;
+
+  this.startPosition_ = new goog.math.Coordinate(
+      event.clientX, event.clientY);
+
+  event.preventDefault();
+};
+
+
+/**
+ * Event handler for mouse move. Starts drag operation if moved more than the
+ * threshold value.
+ *
+ * @param {goog.events.BrowserEvent} event Mouse move or mouse out event.
+ * @private
+ */
+goog.fx.DragDropItem.prototype.mouseMove_ = function(event) {
+  var distance = Math.abs(event.clientX - this.startPosition_.x) +
+      Math.abs(event.clientY - this.startPosition_.y);
+  // Fire dragStart event if the drag distance exceeds the threshold or if the
+  // mouse leave the dragged element.
+  // TODO(user): Consider using the goog.fx.Dragger to track the distance
+  // even after the mouse leaves the dragged element.
+  var currentDragElement = this.currentDragElement_;
+  var distanceAboveThreshold =
+      distance > goog.fx.AbstractDragDrop.initDragDistanceThreshold;
+  var mouseOutOnDragElement = event.type == goog.events.EventType.MOUSEOUT &&
+      event.target == currentDragElement;
+  if (distanceAboveThreshold || mouseOutOnDragElement) {
+    this.eventHandler_.removeAll();
+    this.parent_.startDrag(event, this);
+  }
+};
+
+
+/**
+ * Event handler for mouse up. Removes mouse move, mouse out and mouse up event
+ * handlers.
+ *
+ * @param {goog.events.BrowserEvent} event Mouse up event.
+ * @private
+ */
+goog.fx.DragDropItem.prototype.mouseUp_ = function(event) {
+  this.eventHandler_.removeAll();
+  delete this.startPosition_;
+  this.currentDragElement_ = null;
+};
+
+
+
+/**
+ * Class representing an active drop target
+ *
+ * @param {goog.math.Box} box Box describing the position and dimension of the
+ *     target item.
+ * @param {goog.fx.AbstractDragDrop=} opt_target Target that contains the item
+       associated with position.
+ * @param {goog.fx.DragDropItem=} opt_item Item associated with position.
+ * @param {Element=} opt_element Element of item associated with position.
+ * @constructor
+ * @private
+ */
+goog.fx.ActiveDropTarget_ = function(box, opt_target, opt_item, opt_element) {
+
+  /**
+   * Box describing the position and dimension of the target item
+   * @type {goog.math.Box}
+   * @private
+   */
+  this.box_ = box;
+
+  /**
+   * Target that contains the item associated with position
+   * @type {goog.fx.AbstractDragDrop|undefined}
+   * @private
+   */
+  this.target_ = opt_target;
+
+  /**
+   * Item associated with position
+   * @type {goog.fx.DragDropItem|undefined}
+   * @private
+   */
+  this.item_ = opt_item;
+
+  /**
+   * The draggable element of the item associated with position.
+   * @type {Element|undefined}
+   * @private
+   */
+  this.element_ = opt_element;
+};
+
+
+/**
+ * If this target is in a scrollable container this is it.
+ * @type {goog.fx.ScrollableContainer_}
+ * @private
+ */
+goog.fx.ActiveDropTarget_.prototype.scrollableContainer_ = null;
+
+
+
+/**
+ * Class for representing a scrollable container
+ * @param {Element} element the scrollable element.
+ * @constructor
+ * @private
+ */
+goog.fx.ScrollableContainer_ = function(element) {
+
+  /**
+   * The targets that lie within this container.
+   * @type {Array<goog.fx.ActiveDropTarget_>}
+   * @private
+   */
+  this.containedTargets_ = [];
+
+  /**
+   * The element that is this container
+   * @type {Element}
+   * @private
+   */
+  this.element_ = element;
+
+  /**
+   * The saved scroll left location for calculating deltas.
+   * @type {number}
+   * @private
+   */
+  this.savedScrollLeft_ = 0;
+
+  /**
+   * The saved scroll top location for calculating deltas.
+   * @type {number}
+   * @private
+   */
+  this.savedScrollTop_ = 0;
+
+  /**
+   * The space occupied by the container.
+   * @type {goog.math.Box}
+   * @private
+   */
+  this.box_ = null;
+};