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

Commit

Permalink
Merge pull request #8759 from MiguelCastillo/themes-tab
Browse files Browse the repository at this point in the history
Themes tab
  • Loading branch information
ingorichter committed Aug 20, 2014
2 parents 98b8ea7 + a03a2df commit 8712385
Show file tree
Hide file tree
Showing 9 changed files with 354 additions and 9 deletions.
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 @@ -520,6 +520,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

0 comments on commit 8712385

Please sign in to comment.