This repository was archived by the owner on Sep 6, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Enable opening of remote(http|https) files in Brackets #14153
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
bcc8913
Enable opening of remote(http|https) files in Brackets
b21c5e9
Adding jasmine tests
3e56f06
Hooking to QuickOpen for remote file open
4ce8d63
Remove console statements
a5bcabf
Address code review comments
90e4a26
Providing additional checks
f0d02a4
Merge branch 'master' of https://github.com/adobe/brackets into swmit…
7135ed8
Unifying file existense check in MRU
2beea4a
Include Remote file entries in MROF display list by stubbing existenc…
516bc4c
Handle image viewer and pixel mapping
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
/* | ||
* Copyright (c) 2018 - present Adobe Systems Incorporated. All rights reserved. | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a | ||
* copy of this software and associated documentation files (the "Software"), | ||
* to deal in the Software without restriction, including without limitation | ||
* the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
* and/or sell copies of the Software, and to permit persons to whom the | ||
* Software is furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in | ||
* all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
* DEALINGS IN THE SOFTWARE. | ||
* | ||
*/ | ||
|
||
define(function (require, exports, module) { | ||
"use strict"; | ||
|
||
var FileSystemError = brackets.getModule("filesystem/FileSystemError"), | ||
FileSystemStats = brackets.getModule("filesystem/FileSystemStats"); | ||
|
||
var SESSION_START_TIME = new Date(); | ||
|
||
/** | ||
* Create a new file stat. See the FileSystemStats class for more details. | ||
* | ||
* @param {!string} fullPath The full path for this File. | ||
* @return {FileSystemStats} stats. | ||
*/ | ||
function _getStats(uri) { | ||
return new FileSystemStats({ | ||
isFile: true, | ||
mtime: SESSION_START_TIME.toISOString(), | ||
size: 0, | ||
realPath: uri, | ||
hash: uri | ||
}); | ||
} | ||
|
||
/** | ||
* Model for a RemoteFile. | ||
* | ||
* This class should *not* be instantiated directly. Use FileSystem.getFileForPath | ||
* | ||
* See the FileSystem class for more details. | ||
* | ||
* @constructor | ||
* @param {!string} fullPath The full path for this File. | ||
* @param {!FileSystem} fileSystem The file system associated with this File. | ||
*/ | ||
function RemoteFile(protocol, fullPath, fileSystem) { | ||
this._isFile = true; | ||
this._isDirectory = false; | ||
this._path = fullPath; | ||
this._stat = _getStats(fullPath); | ||
this._id = fullPath; | ||
this._name = fullPath.split('/').pop(); | ||
this._fileSystem = fileSystem; | ||
this.donotWatch = true; | ||
this.protocol = protocol; | ||
this.encodedPath = fullPath; | ||
} | ||
|
||
// Add "fullPath", "name", "parent", "id", "isFile" and "isDirectory" getters | ||
Object.defineProperties(RemoteFile.prototype, { | ||
"fullPath": { | ||
get: function () { return this._path; }, | ||
set: function () { throw new Error("Cannot set fullPath"); } | ||
}, | ||
"name": { | ||
get: function () { return this._name; }, | ||
set: function () { throw new Error("Cannot set name"); } | ||
}, | ||
"parentPath": { | ||
get: function () { return this._parentPath; }, | ||
set: function () { throw new Error("Cannot set parentPath"); } | ||
}, | ||
"id": { | ||
get: function () { return this._id; }, | ||
set: function () { throw new Error("Cannot set id"); } | ||
}, | ||
"isFile": { | ||
get: function () { return this._isFile; }, | ||
set: function () { throw new Error("Cannot set isFile"); } | ||
}, | ||
"isDirectory": { | ||
get: function () { return this._isDirectory; }, | ||
set: function () { throw new Error("Cannot set isDirectory"); } | ||
}, | ||
"_impl": { | ||
get: function () { return this._fileSystem._impl; }, | ||
set: function () { throw new Error("Cannot set _impl"); } | ||
} | ||
}); | ||
|
||
/** | ||
* Helpful toString for debugging and equality check purposes | ||
*/ | ||
RemoteFile.prototype.toString = function () { | ||
return "[RemoteFile " + this._path + "]"; | ||
}; | ||
|
||
/** | ||
* Returns the stats for the remote entry. | ||
* | ||
* @param {function (?string, FileSystemStats=)} callback Callback with a | ||
* FileSystemError string or FileSystemStats object. | ||
*/ | ||
RemoteFile.prototype.stat = function (callback) { | ||
if (this._stat) { | ||
callback(null, this._stat); | ||
} else { | ||
callback(FileSystemError.NOT_FOUND); | ||
} | ||
}; | ||
|
||
RemoteFile.prototype.constructor = RemoteFile; | ||
|
||
/** | ||
* Cached contents of this file. This value is nullable but should NOT be undefined. | ||
* @private | ||
* @type {?string} | ||
*/ | ||
RemoteFile.prototype._contents = null; | ||
|
||
|
||
/** | ||
* @private | ||
* @type {?string} | ||
*/ | ||
RemoteFile.prototype._encoding = "utf8"; | ||
|
||
/** | ||
* @private | ||
* @type {?bool} | ||
*/ | ||
RemoteFile.prototype._preserveBOM = false; | ||
|
||
|
||
/** | ||
* Clear any cached data for this file. Note that this explicitly does NOT | ||
* clear the file's hash. | ||
* @private | ||
*/ | ||
RemoteFile.prototype._clearCachedData = function () { | ||
// no-op | ||
}; | ||
|
||
/** | ||
* Reads a remote file. | ||
* | ||
* @param {Object=} options Currently unused. | ||
* @param {function (?string, string=, FileSystemStats=)} callback Callback that is passed the | ||
* FileSystemError string or the file's contents and its stats. | ||
*/ | ||
RemoteFile.prototype.read = function (options, callback) { | ||
if (typeof (options) === "function") { | ||
callback = options; | ||
} | ||
this._encoding = "utf8"; | ||
|
||
if (this._contents !== null && this._stat) { | ||
callback(null, this._contents, this._encoding, this._stat); | ||
return; | ||
} | ||
|
||
var self = this; | ||
$.ajax({ | ||
url: this.fullPath | ||
}) | ||
.done(function (data) { | ||
self._contents = data; | ||
callback(null, data, self._encoding, self._stat); | ||
}) | ||
.fail(function (e) { | ||
callback(FileSystemError.NOT_FOUND); | ||
}); | ||
}; | ||
|
||
/** | ||
* Write a file. | ||
* | ||
* @param {string} data Data to write. | ||
* @param {object=} options Currently unused. | ||
* @param {function (?string, FileSystemStats=)=} callback Callback that is passed the | ||
* FileSystemError string or the file's new stats. | ||
*/ | ||
RemoteFile.prototype.write = function (data, encoding, callback) { | ||
if (typeof (encoding) === "function") { | ||
callback = encoding; | ||
} | ||
callback(FileSystemError.NOT_FOUND); | ||
}; | ||
|
||
RemoteFile.prototype.exists = function (callback) { | ||
callback(null, true); | ||
}; | ||
|
||
RemoteFile.prototype.unlink = function (callback) { | ||
callback(FileSystemError.NOT_FOUND); | ||
}; | ||
|
||
RemoteFile.prototype.rename = function (newName, callback) { | ||
callback(FileSystemError.NOT_FOUND); | ||
}; | ||
|
||
RemoteFile.prototype.moveToTrash = function (callback) { | ||
callback(FileSystemError.NOT_FOUND); | ||
}; | ||
|
||
// Export this class | ||
module.exports = RemoteFile; | ||
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/* | ||
* Copyright (c) 2018 - present Adobe Systems Incorporated. All rights reserved. | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a | ||
* copy of this software and associated documentation files (the "Software"), | ||
* to deal in the Software without restriction, including without limitation | ||
* the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
* and/or sell copies of the Software, and to permit persons to whom the | ||
* Software is furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in | ||
* all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
* DEALINGS IN THE SOFTWARE. | ||
* | ||
*/ | ||
|
||
define(function (require, exports, module) { | ||
"use strict"; | ||
|
||
var AppInit = brackets.getModule("utils/AppInit"), | ||
FileSystem = brackets.getModule("filesystem/FileSystem"), | ||
QuickOpen = brackets.getModule("search/QuickOpen"), | ||
PathUtils = brackets.getModule("thirdparty/path-utils/path-utils"), | ||
CommandManager = brackets.getModule("command/CommandManager"), | ||
Commands = brackets.getModule("command/Commands"), | ||
RemoteFile = require("RemoteFile"); | ||
|
||
var HTTP_PROTOCOL = "http:", | ||
HTTPS_PROTOCOL = "https:"; | ||
|
||
AppInit.htmlReady(function () { | ||
var protocolAdapter = { | ||
priority: 0, // Default priority | ||
fileImpl: RemoteFile, | ||
canRead: function (filePath) { | ||
return true; // Always claim true, we are the default adpaters | ||
} | ||
}; | ||
|
||
// Register the custom object as HTTP and HTTPS protocol adapter | ||
FileSystem.registerProtocolAdapter(HTTP_PROTOCOL, protocolAdapter); | ||
FileSystem.registerProtocolAdapter(HTTPS_PROTOCOL, protocolAdapter); | ||
|
||
// Register as quick open plugin for file URI's having HTTP:|HTTPS: protocol | ||
QuickOpen.addQuickOpenPlugin( | ||
{ | ||
name: "Remote file URI input", | ||
languageIds: [], // for all language modes | ||
search: function () { | ||
return $.Deferred().resolve([arguments[0]]); | ||
}, | ||
match: function (query) { | ||
var protocol = PathUtils.parseUrl(query).protocol; | ||
return [HTTP_PROTOCOL, HTTPS_PROTOCOL].indexOf(protocol) !== -1; | ||
}, | ||
itemFocus: function (query) { | ||
}, // no op | ||
itemSelect: function () { | ||
CommandManager.execute(Commands.FILE_OPEN, {fullPath: arguments[0]}); | ||
} | ||
} | ||
); | ||
}); | ||
|
||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is an extension shouldn't the definition of ProtocolAdapter be provided by Brackets-Core for consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vickramdhawal Sorry for the confusion.
protocolAdapter
is just a variable to hold the custom imprint of the adapter definition to be passed as protocol adapters forHTTP:
andHTTPS:
. Registration happens by invoking this part -I can't really define an interface (which if was possible, would have been part of core) and
Duck Typing
would be a gimmick as type checking is not something what we are interested about here.For better understanding I have added a JSDoc @typedef