Skip to content
This repository has been archived by the owner on Sep 6, 2021. It is now read-only.

Themes tab #8759

Merged
merged 11 commits into from
Aug 20, 2014
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
28 changes: 23 additions & 5 deletions src/extensibility/ExtensionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ define(function (require, exports, module) {
// semver.browser is an AMD-compatible module
var semver = require("extensibility/node/node_modules/semver/semver.browser");

/**
* @private
* @type {$.Deferred} Keeps track of the current registry download so that if a request is already
* in progress and another request to download the registry comes in, we don't send yet another request.
* This is primarily used when multiple view models need to download the registry at the same time.
*/
var pendingDownloadRegistry = null;

/**
* Extension status constants.
*/
Expand Down Expand Up @@ -180,7 +188,12 @@ define(function (require, exports, module) {
* or rejected if the server can't be reached.
*/
function downloadRegistry() {
var result = new $.Deferred();
if (pendingDownloadRegistry) {
return pendingDownloadRegistry.promise();
}

pendingDownloadRegistry = new $.Deferred();

$.ajax({
url: brackets.config.extension_registry,
dataType: "json",
Expand All @@ -195,12 +208,17 @@ define(function (require, exports, module) {
synchronizeEntry(id);
});
$(exports).triggerHandler("registryDownload");
result.resolve();
pendingDownloadRegistry.resolve();
})
.fail(function () {
result.reject();
pendingDownloadRegistry.reject();
})
.always(function () {
// Make sure to clean up the pending registry so that new requests can be made.
pendingDownloadRegistry = null;
});
return result.promise();

return pendingDownloadRegistry.promise();
}


Expand Down Expand Up @@ -450,7 +468,7 @@ define(function (require, exports, module) {
if (installationResult.keepFile === undefined) {
installationResult.keepFile = false;
}

var installationStatus = installationResult.installationStatus;
if (installationStatus === Package.InstallationStatuses.ALREADY_INSTALLED ||
installationStatus === Package.InstallationStatuses.NEEDS_UPDATE ||
Expand Down
1 change: 1 addition & 0 deletions src/extensibility/ExtensionManagerDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ define(function (require, exports, module) {
// Load registry only if the registry URL exists
if (context.showRegistry) {
models.push(new ExtensionManagerViewModel.RegistryViewModel());
models.push(new ExtensionManagerViewModel.ThemesViewModel());
}

models.push(new ExtensionManagerViewModel.InstalledViewModel());
Expand Down
2 changes: 1 addition & 1 deletion src/extensibility/ExtensionManagerView.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ define(function (require, exports, module) {
context.isMarkedForRemoval = ExtensionManager.isMarkedForRemoval(info.metadata.name);
context.isMarkedForUpdate = ExtensionManager.isMarkedForUpdate(info.metadata.name);

context.showInstallButton = (this.model.source === this.model.SOURCE_REGISTRY) && !context.updateAvailable;
context.showInstallButton = (this.model.source === this.model.SOURCE_REGISTRY || this.model.source === this.model.SOURCE_THEMES) && !context.updateAvailable;
context.showUpdateButton = context.updateAvailable && !context.isMarkedForUpdate && !context.isMarkedForRemoval;

context.allowInstall = context.isCompatible && !context.isInstalled;
Expand Down
78 changes: 76 additions & 2 deletions src/extensibility/ExtensionManagerViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ define(function (require, exports, module) {
*/
ExtensionManagerViewModel.prototype.SOURCE_REGISTRY = "registry";

/**
* @type {string}
* Constant indicating that this model/view should initialize from the main extension registry with only themes.
*/
ExtensionManagerViewModel.prototype.SOURCE_THEMES = "themes";

/**
* @type {string}
* Constant indicating that this model/view should initialize from the list of locally installed extensions.
Expand Down Expand Up @@ -158,7 +164,7 @@ define(function (require, exports, module) {
*/
ExtensionManagerViewModel.prototype.initialize = function () {
var self = this;

this._initializeFromSourcePromise = this._initializeFromSource().always(function () {
self._updateMessage();
});
Expand Down Expand Up @@ -326,7 +332,7 @@ define(function (require, exports, module) {
// Sort the registry by last published date and store the sorted list of IDs.
self.sortedFullSet = registry_utils.sortRegistry(self.extensions, "registryInfo")
.filter(function (entry) {
return entry.registryInfo !== undefined;
return entry.registryInfo !== undefined && entry.registryInfo.metadata.theme === undefined;
})
.map(function (entry) {
return entry.registryInfo.metadata.name;
Expand Down Expand Up @@ -495,6 +501,74 @@ define(function (require, exports, module) {
return entry;
};

/**
* The model for the ExtensionManagerView that is responsible for handling registry-based theme extensions.
* This extends ExtensionManagerViewModel.
* Must be disposed with dispose() when done.
*
* Events:
* - change - triggered when the data for a given extension changes. Second parameter is the extension id.
* - filter - triggered whenever the filtered set changes (including on initialize).
*
* @constructor
*/
function ThemesViewModel() {
ExtensionManagerViewModel.call(this);
}

// Inheritance setup
ThemesViewModel.prototype = Object.create(ExtensionManagerViewModel.prototype);
ThemesViewModel.prototype.constructor = ThemesViewModel;

/**
* @type {string}
* ThemeViewModels always have a source of SOURCE_THEMES.
*/
ThemesViewModel.prototype.source = ExtensionManagerViewModel.prototype.SOURCE_THEMES;

/**
* Initializes the model from the remote extension registry.
* @return {$.Promise} a promise that's resolved with the registry JSON data.
*/
ThemesViewModel.prototype._initializeFromSource = function () {
var self = this;
return ExtensionManager.downloadRegistry()
.done(function () {
self.extensions = ExtensionManager.extensions;

// Sort the registry by last published date and store the sorted list of IDs.
self.sortedFullSet = registry_utils.sortRegistry(self.extensions, "registryInfo")
.filter(function (entry) {
return entry.installInfo === undefined && entry.registryInfo !== undefined && entry.registryInfo.metadata.theme;
})
.map(function (entry) {
return entry.registryInfo.metadata.name;
});
self._setInitialFilter();
})
.fail(function () {
self.extensions = [];
self.sortedFullSet = [];
self.filterSet = [];
});
};

/**
* @private
* Finds the theme extension metadata by id. If there is no theme extension matching the given id,
* this returns `null`.
* @param {string} id of the theme extension
* @return {Object?} extension metadata or null if there's no matching extension
*/
ThemesViewModel.prototype._getEntry = function (id) {
var entry = this.extensions[id];
if (entry) {
return entry.registryInfo;
}
return entry;
};

exports.RegistryViewModel = RegistryViewModel;
exports.ThemesViewModel = ThemesViewModel;
exports.InstalledViewModel = InstalledViewModel;
});
1 change: 1 addition & 0 deletions src/htmlContent/extension-manager-dialog.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<ul class="nav nav-tabs">
{{#showRegistry}}
<li><a href="#registry" class="registry" data-toggle="tab"><img src="styles/images/extension-manager-registry.svg"/><br/>{{Strings.EXTENSIONS_AVAILABLE_TITLE}}</a></li>
<li><a href="#themes" class="themes" data-toggle="tab"><img src="styles/images/themes-icon.svg"/><br/>{{Strings.EXTENSIONS_THEMES_TITLE}}</a></li>
<!--<li><a href="#updates" class="updates" data-toggle="tab"><img src="styles/images/extension-manager-updates.svg"/><br/>{{Strings.EXTENSIONS_UPDATES_TITLE}}</a></li>-->
{{/showRegistry}}
<li><a href="#installed" class="installed" data-toggle="tab"><span class="notification"></span><img src="styles/images/extension-manager-installed.svg"/><br/>{{Strings.EXTENSIONS_INSTALLED_TITLE}}</a></li>
Expand Down
1 change: 1 addition & 0 deletions src/nls/root/strings.js
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ define({
"REGISTRY_SANITY_CHECK_WARNING" : "NOTE: These extensions may come from different authors than {APP_NAME} itself. Extensions are not reviewed and have full local privileges. Be cautious when installing extensions from an unknown source.",
"EXTENSIONS_INSTALLED_TITLE" : "Installed",
"EXTENSIONS_AVAILABLE_TITLE" : "Available",
"EXTENSIONS_THEMES_TITLE" : "Themes",
"EXTENSIONS_UPDATES_TITLE" : "Updates",

"INLINE_EDITOR_NO_MATCHES" : "No matches available.",
Expand Down
8 changes: 8 additions & 0 deletions src/styles/images/themes-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading