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;
+};