Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 39 additions & 22 deletions src/extensions/default/UrlCodeHints/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,37 +56,42 @@ define(function (require, exports, module) {
* @return {Array.<string>|$.Deferred} The (possibly deferred) hints.
*/
UrlCodeHints.prototype._getUrlList = function (query) {
var doc,
result = [];

// site-root relative links are not yet supported, so filter them out
if (query.queryStr.length > 0 && query.queryStr[0] === "/") {
return result;
}
var directory,
doc,
docDir,
queryDir = "",
queryUrl,
result = [],
self,
targetDir,
unfiltered = [];

// get path to current document
doc = DocumentManager.getCurrentDocument();
if (!doc || !doc.file) {
return result;
}

var docDir = FileUtils.getDirectoryPath(doc.file.fullPath);
docDir = FileUtils.getDirectoryPath(doc.file.fullPath);

// get relative path from query string
// TODO: handle site-root relative
var queryDir = "";
var queryUrl = window.PathUtils.parseUrl(query.queryStr);
queryUrl = window.PathUtils.parseUrl(query.queryStr);
if (queryUrl) {
queryDir = queryUrl.directory;
}

// build target folder path
var targetDir = docDir + decodeURI(queryDir);

// get list of files from target folder
var unfiltered = [];
if (queryDir.length > 0 && queryDir[0] === "/") {
// site-root relative path
targetDir = ProjectManager.getProjectRoot().fullPath +
decodeURI(queryDir).substring(1);
} else {
// page relative path
targetDir = docDir + decodeURI(queryDir);
}

// Getting the file/folder info is an asynch operation, so it works like this:
// Get list of files from target folder. Getting the file/folder info is an
// asynch operation, so it works like this:
//
// The initial pass initiates the asynchronous retrieval of data and returns an
// empty list, so no code hints are displayed. In the async callback, the code
Expand Down Expand Up @@ -121,8 +126,8 @@ define(function (require, exports, module) {
unfiltered = this.cachedHints.unfiltered;

} else {
var directory = FileSystem.getDirectoryForPath(targetDir),
self = this;
directory = FileSystem.getDirectoryForPath(targetDir);
self = this;

if (self.cachedHints && self.cachedHints.deferred) {
self.cachedHints.deferred.reject();
Expand All @@ -133,11 +138,16 @@ define(function (require, exports, module) {
self.cachedHints.unfiltered = [];

directory.getContents(function (err, contents) {
var currentDeferred, entryStr, syncResults;

if (!err) {
contents.forEach(function (entry) {
if (ProjectManager.shouldShow(entry)) {
// convert to doc relative path
var entryStr = entry.fullPath.replace(docDir, "");
entryStr = queryDir + entry._name;
if (entry._isDirectory) {
entryStr += "/";
}

// code hints show the unencoded string so the
// choices are easier to read. The encoded string
Expand All @@ -152,11 +162,12 @@ define(function (require, exports, module) {
self.cachedHints.docDir = docDir;

if (self.cachedHints.deferred.state() !== "rejected") {
var currentDeferred = self.cachedHints.deferred;
currentDeferred = self.cachedHints.deferred;

// Since we've cached the results, the next call to _getUrlList should be synchronous.
// If it isn't, we've got a problem and should reject both the current deferred
// and any new deferred that got created on the call.
var syncResults = self._getUrlList(query);
syncResults = self._getUrlList(query);
if (syncResults instanceof Array) {
currentDeferred.resolveWith(self, [syncResults]);
} else {
Expand Down Expand Up @@ -479,8 +490,14 @@ define(function (require, exports, module) {
// Deferred hints were returned
var deferred = $.Deferred();
hints.done(function (asyncHints) {
result = $.map(asyncHints, function (item) {
if (item.indexOf(filter) === 0) {
return item;
}
}).sort(sortFunc);

deferred.resolveWith(this, [{
hints: asyncHints,
hints: result,
match: query.queryStr,
selectInitial: true,
handleWideResults: false
Expand Down
2 changes: 2 additions & 0 deletions src/extensions/default/UrlCodeHints/testfiles/test.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@
<img src=''>
<img src='subfolder/'>
<a href='results.html?id=1003'>Results</a>
<a href='../'>Page relative: up 1 folder</a>
<a href='/'>Site-root relative: root folder</a>
</body>
</html>
91 changes: 88 additions & 3 deletions src/extensions/default/UrlCodeHints/unittests.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ define(function (require, exports, module) {
"use strict";

// Modules from the SpecRunner window
var CodeHintManager = brackets.getModule("editor/CodeHintManager"),
DocumentManager = brackets.getModule("document/DocumentManager"),
var DocumentManager = brackets.getModule("document/DocumentManager"),
Editor = brackets.getModule("editor/Editor").Editor,
EditorManager = brackets.getModule("editor/EditorManager"),
FileUtils = brackets.getModule("file/FileUtils"),
Expand Down Expand Up @@ -171,13 +170,26 @@ define(function (require, exports, module) {
});
});

it("should not hint in query part of url ", function () {
it("should not hint in query part of url", function () {
runs(function () {
testEditor.setCursorPos({ line: 18, ch: 31 });
expectNoHints(UrlCodeHints.hintProvider);
});
});

it("should hint up 1 folder for '../'", function () {
runs(function () {
testEditor.setCursorPos({ line: 19, ch: 14 });
hintsObj = null;
expectAsyncHints(UrlCodeHints.hintProvider);
});

runs(function () {
var expectedFirstItem = (brackets.platform === "mac") ? "../data.json" : "../testfiles/";
verifyUrlHints(hintsObj.hints, expectedFirstItem);
});
});

// This MUST be the LAST "test"
it("should cleanup after tests", function () {
tearDownTests();
Expand Down Expand Up @@ -267,6 +279,79 @@ define(function (require, exports, module) {
});
});

describe("Project root relative Url Code Hints", function () {

var testWindow,
brackets,
workingSet = [],
CodeHintManager,
CommandManager,
Commands,
DocumentManager,
EditorManager;

it("should hint site root '/'", function () {
runs(function () {
SpecRunnerUtils.createTestWindowAndRun(this, function (w) {
testWindow = w;
brackets = testWindow.brackets;
CodeHintManager = brackets.test.CodeHintManager;
CommandManager = brackets.test.CommandManager;
Commands = brackets.test.Commands;
DocumentManager = brackets.test.DocumentManager;
EditorManager = brackets.test.EditorManager;
});
});

runs(function () {
SpecRunnerUtils.loadProjectInTestWindow(extensionPath);
});

runs(function () {
workingSet.push(testHtmlPath);
waitsForDone(SpecRunnerUtils.openProjectFiles(workingSet), "openProjectFiles");
});

runs(function () {
DocumentManager.getDocumentForPath(testHtmlPath).done(function (doc) {
testDocument = doc;
});
});

waitsFor(function () {
return (testDocument);
}, "Unable to open test document", 2000);

runs(function () {
DocumentManager.setCurrentDocument(testDocument);
testEditor = EditorManager.getCurrentFullEditor();
testEditor.setCursorPos({ line: 20, ch: 12 });
CommandManager.execute(Commands.SHOW_CODE_HINTS);
});

runs(function () {
var hintList = CodeHintManager._getCodeHintList();
expect(hintList).toBeTruthy();
expect(hintList.hints).toBeTruthy();
expect(hintList.hints).toContain("/testfiles/");
});

// cleanup
runs(function () {
testEditor = null;
testDocument = null;
testWindow = null;
brackets = null;
CodeHintManager = null;
CommandManager = null;
Commands = null;
DocumentManager = null;
EditorManager = null;
SpecRunnerUtils.closeTestWindow();
});
});
});

describe("Url Insertion", function () {

// These tests edit doc, so we need to setup/tear-down for each test
Expand Down