Update MegaMenu Application Customizer: Version bump to 1.1.0, localization support added, and unnecessary files removed

- Deleted obsolete localization file for English (en-us).
- Updated version number from 1.0.4 to 1.1.0 in manifests.js and manifests.json.
- Added localization support for German (de-de) in a new localization file.
- Removed unnecessary dependencies from manifests.
- Added .gitignore to exclude build artifacts and temporary files.
This commit is contained in:
Torsten Brendgen
2026-07-16 22:43:31 +02:00
parent a2b8165262
commit 97d2b6b5d2
53 changed files with 1071 additions and 1065 deletions

View File

@@ -54,59 +54,67 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
}
};
import { override } from '@microsoft/decorators';
import { Log } from '@microsoft/sp-core-library';
import { BaseApplicationCustomizer, PlaceholderName } from '@microsoft/sp-application-base';
import * as strings from 'MegaMenuApplicationCustomizerStrings';
import { TaxonomyNavigationService } from '../../services/TaxonomyNavigationService';
import { MegaMenuRenderer } from './MegaMenuRenderer';
// Import SCSS module
import { debugError, debugLog, debugWarn } from '../../services/MegaMenuDebug';
import './MegaMenu.module.scss';
var LOG_SOURCE = 'MegaMenuApplicationCustomizer';
export var UserCustomActionMegaMenuId = 'abc3361f-bb2d-491f-aba3-cd51c19a299b';
/** A Custom Action which can be run during execution of a Client Side Application */
var MegaMenuApplicationCustomizer = (function (_super) {
__extends(MegaMenuApplicationCustomizer, _super);
function MegaMenuApplicationCustomizer() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this._updateCallback = function (data) {
_this._loadExternalCss(data.cssUrl);
_this._renderMegaMenu(data.termSetName);
_this._onDispose = function () {
_this.context.placeholderProvider.changedEvent.remove(_this, _this._renderPlaceHolders);
if (_this._renderer) {
_this._renderer.dispose();
_this._renderer = undefined;
}
var externalCssLink = document.getElementById('mega-menu-additional-css-34FAB720');
if (externalCssLink) {
externalCssLink.remove();
}
_this._menuContainer = undefined;
_this._topPlaceholder = undefined;
debugLog(_this._isDebugEnabled(), LOG_SOURCE, 'Disposed custom top placeholder.');
};
return _this;
}
MegaMenuApplicationCustomizer.prototype.onInit = function () {
Log.info(LOG_SOURCE, "Initialized " + strings.Title);
// Load external CSS if provided
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'Initialized ' + strings.Title);
if (this.properties.cssUrl) {
this._loadExternalCss(this.properties.cssUrl);
}
// Wait for the page to be ready
this.context.placeholderProvider.changedEvent.add(this, this._renderPlaceHolders);
// Initial render
this._renderPlaceHolders();
return Promise.resolve();
};
MegaMenuApplicationCustomizer.prototype._renderPlaceHolders = function () {
console.log('Available placeholders: ', this.context.placeholderProvider.placeholderNames.map(function (name) { return PlaceholderName[name]; }).join(', '));
// Handling the top placeholder
var availablePlaceholders = this.context.placeholderProvider.placeholderNames
.map(function (name) { return PlaceholderName[name]; })
.join(', ');
debugLog(this._isDebugEnabled(), LOG_SOURCE, 'Available placeholders:', availablePlaceholders);
if (!this._topPlaceholder) {
this._topPlaceholder = this.context.placeholderProvider.tryCreateContent(PlaceholderName.Top, { onDispose: this._onDispose });
// The extension should not assume that the expected placeholder is available.
if (!this._topPlaceholder) {
console.error('The expected placeholder (Top) was not found.');
debugError(this._isDebugEnabled(), LOG_SOURCE, 'The expected placeholder (Top) was not found.');
return;
}
if (!this.properties.termSetName) {
console.error('TermSetName property is required but not provided.');
1;
var termSetIdentifier = this._getTermSetIdentifier();
if (!termSetIdentifier) {
debugWarn(this._isDebugEnabled(), LOG_SOURCE, 'No termSetId or termSetName configured. Mega Menu rendering is skipped.');
this._renderStatus(strings.ConfigurationMissing);
return;
}
this._renderMegaMenu(this.properties.termSetName);
this._renderMegaMenu(termSetIdentifier);
}
};
MegaMenuApplicationCustomizer.prototype._renderMegaMenu = function (termSetName) {
MegaMenuApplicationCustomizer.prototype._renderMegaMenu = function (termSetIdentifier, debug) {
if (debug === void 0) { debug = this._isDebugEnabled(); }
return __awaiter(this, void 0, void 0, function () {
var taxonomyService, menuItems, renderer, container, error_1;
var taxonomyService, menuItems, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
@@ -116,23 +124,27 @@ var MegaMenuApplicationCustomizer = (function (_super) {
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
taxonomyService = new TaxonomyNavigationService(this.context, termSetName);
taxonomyService = new TaxonomyNavigationService(this.context, termSetIdentifier, debug, this._getCacheMinutes());
return [4 /*yield*/, taxonomyService.getMenuItems()];
case 2:
menuItems = _a.sent();
renderer = new MegaMenuRenderer(this.context, menuItems, this._updateCallback);
container = this._getOrCreateContainer('CustomHeader', this._topPlaceholder);
if (container) {
renderer.render(container);
if (this._renderer) {
this._renderer.dispose();
}
this._renderer = new MegaMenuRenderer(menuItems, debug);
this._menuContainer = this._getOrCreateContainer('CustomHeader', this._topPlaceholder);
if (this._menuContainer) {
this._renderer.render(this._menuContainer);
}
else {
renderer.render(this._topPlaceholder.domElement);
this._renderer.render(this._topPlaceholder.domElement);
}
Log.info(LOG_SOURCE, "MegaMenu rendered successfully with " + menuItems.length + " top-level items");
debugLog(debug, LOG_SOURCE, 'MegaMenu rendered successfully with ' + menuItems.length + ' top-level items.');
return [3 /*break*/, 4];
case 3:
error_1 = _a.sent();
console.error('Error rendering MegaMenu:', error_1);
debugError(debug, LOG_SOURCE, 'Error rendering MegaMenu.', error_1);
this._renderStatus(strings.LoadError);
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
@@ -142,19 +154,29 @@ var MegaMenuApplicationCustomizer = (function (_super) {
MegaMenuApplicationCustomizer.prototype._getOrCreateContainer = function (id, placeholder) {
var container = document.getElementById(id);
if (container) {
var div = document.createElement('div');
container.appendChild(div);
return div;
}
else {
return placeholder.domElement;
var host = document.getElementById('MegaMenuHost');
if (!host) {
host = document.createElement('div');
host.id = 'MegaMenuHost';
container.appendChild(host);
}
return host;
}
return placeholder.domElement;
};
MegaMenuApplicationCustomizer.prototype._loadExternalCss = function (cssUrl) {
MegaMenuApplicationCustomizer.prototype._loadExternalCss = function (cssUrl, debug) {
if (debug === void 0) { debug = this._isDebugEnabled(); }
var externalCssLinkId = 'mega-menu-additional-css-34FAB720';
var link = document.getElementById(externalCssLinkId);
if (cssUrl && cssUrl.trim() !== '') {
// update previous link, if present
var validatedUrl = this._validateCssUrl(cssUrl);
if (!validatedUrl) {
debugWarn(debug, LOG_SOURCE, 'Rejected unsafe external CSS URL:', cssUrl);
if (link) {
link.remove();
}
return;
}
if (!link) {
var head = document.getElementsByTagName('head')[0];
link = document.createElement('link');
@@ -162,21 +184,69 @@ var MegaMenuApplicationCustomizer = (function (_super) {
link.type = 'text/css';
link.id = externalCssLinkId;
link.onload = function () {
Log.info(LOG_SOURCE, "External CSS loaded successfully from: " + cssUrl);
debugLog(debug, LOG_SOURCE, 'External CSS loaded successfully from:', cssUrl);
};
link.onerror = function () {
console.warn("Failed to load external CSS from: " + cssUrl);
debugWarn(debug, LOG_SOURCE, 'Failed to load external CSS from:', cssUrl);
};
head.appendChild(link);
}
link.href = cssUrl;
link.href = validatedUrl;
}
else if (link) {
link.remove();
}
};
MegaMenuApplicationCustomizer.prototype._onDispose = function () {
console.log('[MegaMenuApplicationCustomizer._onDispose] Disposed custom top placeholder.');
MegaMenuApplicationCustomizer.prototype._getTermSetIdentifier = function () {
var termSetId = this.properties && this.properties.termSetId
? this.properties.termSetId.trim()
: '';
if (termSetId && this._isGuid(termSetId)) {
return termSetId;
}
return this.properties && this.properties.termSetName
? this.properties.termSetName.trim()
: '';
};
MegaMenuApplicationCustomizer.prototype._getCacheMinutes = function () {
var value = this.properties ? Number(this.properties.cacheMinutes) : 15;
return isFinite(value) ? Math.min(Math.max(Math.floor(value), 1), 1440) : 15;
};
MegaMenuApplicationCustomizer.prototype._validateCssUrl = function (cssUrl) {
try {
var parsed = new URL(cssUrl.trim(), window.location.origin);
var isHttp = parsed.protocol === 'http:' || parsed.protocol === 'https:';
var isSameOrigin = parsed.origin === window.location.origin;
if (!isHttp || (!isSameOrigin && parsed.protocol !== 'https:')) {
return undefined;
}
return parsed.href;
}
catch (error) {
return undefined;
}
};
MegaMenuApplicationCustomizer.prototype._renderStatus = function (message) {
if (!this._topPlaceholder) {
return;
}
this._menuContainer = this._getOrCreateContainer('CustomHeader', this._topPlaceholder);
var container = this._menuContainer || this._topPlaceholder.domElement;
container.innerHTML = '';
var status = document.createElement('div');
status.className = 'mega-menu-status';
status.setAttribute('role', 'status');
status.textContent = message;
container.appendChild(status);
};
MegaMenuApplicationCustomizer.prototype._isGuid = function (value) {
return /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(value);
};
MegaMenuApplicationCustomizer.prototype._isDebugEnabled = function (debugOverride) {
if (typeof debugOverride === 'boolean') {
return debugOverride;
}
return !!(this.properties && this.properties.debug === true);
};
__decorate([
override