protected renderContents()

in src/vs/workbench/contrib/feedback/browser/feedback.ts [101:301]


	protected renderContents(container: HTMLElement): IDisposable {
		const disposables = new DisposableStore();

		dom.addClass(container, 'monaco-menu-container');

		// Form
		this.feedbackForm = dom.append<HTMLFormElement>(container, dom.$('form.feedback-form'));
		this.feedbackForm.setAttribute('action', 'javascript:void(0);');

		// Title
		dom.append(this.feedbackForm, dom.$('h2.title')).textContent = nls.localize("label.sendASmile", "Tweet us your feedback.");

		// Close Button (top right)
		const closeBtn = dom.append(this.feedbackForm, dom.$('div.cancel'));
		closeBtn.tabIndex = 0;
		closeBtn.setAttribute('role', 'button');
		closeBtn.title = nls.localize('close', "Close");

		disposables.add(dom.addDisposableListener(closeBtn, dom.EventType.MOUSE_OVER, () => {
			const theme = this.themeService.getTheme();
			let darkenFactor: number | undefined;
			switch (theme.type) {
				case 'light':
					darkenFactor = 0.1;
					break;
				case 'dark':
					darkenFactor = 0.2;
					break;
			}

			if (darkenFactor) {
				const backgroundBaseColor = theme.getColor(editorWidgetBackground);
				if (backgroundBaseColor) {
					const backgroundColor = darken(backgroundBaseColor, darkenFactor)(theme);
					if (backgroundColor) {
						closeBtn.style.backgroundColor = backgroundColor.toString();
					}
				}
			}
		}));

		disposables.add(dom.addDisposableListener(closeBtn, dom.EventType.MOUSE_OUT, () => {
			closeBtn.style.backgroundColor = null;
		}));

		this.invoke(closeBtn, disposables, () => this.hide());

		// Content
		const content = dom.append(this.feedbackForm, dom.$('div.content'));

		// Sentiment Buttons
		const sentimentContainer = dom.append(content, dom.$('div'));

		if (!this.isPure) {
			dom.append(sentimentContainer, dom.$('span')).textContent = nls.localize("patchedVersion1", "Your installation is corrupt.");
			sentimentContainer.appendChild(document.createElement('br'));
			dom.append(sentimentContainer, dom.$('span')).textContent = nls.localize("patchedVersion2", "Please specify this if you submit a bug.");
			sentimentContainer.appendChild(document.createElement('br'));
		}

		dom.append(sentimentContainer, dom.$('span')).textContent = nls.localize("sentiment", "How was your experience?");

		const feedbackSentiment = dom.append(sentimentContainer, dom.$('div.feedback-sentiment'));

		// Sentiment: Smiley
		this.smileyInput = dom.append(feedbackSentiment, dom.$('div.sentiment'));
		dom.addClass(this.smileyInput, 'smile');
		this.smileyInput.setAttribute('aria-checked', 'false');
		this.smileyInput.setAttribute('aria-label', nls.localize('smileCaption', "Happy Feedback Sentiment"));
		this.smileyInput.setAttribute('role', 'checkbox');
		this.smileyInput.title = nls.localize('smileCaption', "Happy Feedback Sentiment");
		this.smileyInput.tabIndex = 0;

		this.invoke(this.smileyInput, disposables, () => this.setSentiment(true));

		// Sentiment: Frowny
		this.frownyInput = dom.append(feedbackSentiment, dom.$('div.sentiment'));
		dom.addClass(this.frownyInput, 'frown');
		this.frownyInput.setAttribute('aria-checked', 'false');
		this.frownyInput.setAttribute('aria-label', nls.localize('frownCaption', "Sad Feedback Sentiment"));
		this.frownyInput.setAttribute('role', 'checkbox');
		this.frownyInput.title = nls.localize('frownCaption', "Sad Feedback Sentiment");
		this.frownyInput.tabIndex = 0;

		this.invoke(this.frownyInput, disposables, () => this.setSentiment(false));

		if (this.sentiment === 1) {
			dom.addClass(this.smileyInput, 'checked');
			this.smileyInput.setAttribute('aria-checked', 'true');
		} else {
			dom.addClass(this.frownyInput, 'checked');
			this.frownyInput.setAttribute('aria-checked', 'true');
		}

		// Contact Us Box
		const contactUsContainer = dom.append(content, dom.$('div.contactus'));

		dom.append(contactUsContainer, dom.$('span')).textContent = nls.localize("other ways to contact us", "Other ways to contact us");

		const channelsContainer = dom.append(contactUsContainer, dom.$('div.channels'));

		// Contact: Submit a Bug
		const submitBugLinkContainer = dom.append(channelsContainer, dom.$('div'));

		const submitBugLink = dom.append(submitBugLinkContainer, dom.$('a'));
		submitBugLink.setAttribute('target', '_blank');
		submitBugLink.setAttribute('href', '#');
		submitBugLink.textContent = nls.localize("submit a bug", "Submit a bug");
		submitBugLink.tabIndex = 0;

		disposables.add(dom.addDisposableListener(submitBugLink, 'click', e => {
			dom.EventHelper.stop(e);
			const actionId = 'workbench.action.openIssueReporter';
			this.commandService.executeCommand(actionId);
			this.hide();
			this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id: actionId, from: 'feedback' });
		}));

		// Contact: Request a Feature
		if (!!this.requestFeatureLink) {
			const requestFeatureLinkContainer = dom.append(channelsContainer, dom.$('div'));

			const requestFeatureLink = dom.append(requestFeatureLinkContainer, dom.$('a'));
			requestFeatureLink.setAttribute('target', '_blank');
			requestFeatureLink.setAttribute('href', this.requestFeatureLink);
			requestFeatureLink.textContent = nls.localize("request a missing feature", "Request a missing feature");
			requestFeatureLink.tabIndex = 0;

			disposables.add(dom.addDisposableListener(requestFeatureLink, 'click', e => this.hide()));
		}

		// Remaining Characters
		const remainingCharacterCountContainer = dom.append(this.feedbackForm, dom.$('h3'));
		remainingCharacterCountContainer.textContent = nls.localize("tell us why", "Tell us why?");

		this.remainingCharacterCount = dom.append(remainingCharacterCountContainer, dom.$('span.char-counter'));
		this.remainingCharacterCount.textContent = this.getCharCountText(0);

		// Feedback Input Form
		this.feedbackDescriptionInput = dom.append<HTMLTextAreaElement>(this.feedbackForm, dom.$('textarea.feedback-description'));
		this.feedbackDescriptionInput.rows = 3;
		this.feedbackDescriptionInput.maxLength = this.maxFeedbackCharacters;
		this.feedbackDescriptionInput.textContent = this.feedback;
		this.feedbackDescriptionInput.required = true;
		this.feedbackDescriptionInput.setAttribute('aria-label', nls.localize("feedbackTextInput", "Tell us your feedback"));
		this.feedbackDescriptionInput.focus();

		disposables.add(dom.addDisposableListener(this.feedbackDescriptionInput, 'keyup', () => this.updateCharCountText()));

		// Feedback Input Form Buttons Container
		const buttonsContainer = dom.append(this.feedbackForm, dom.$('div.form-buttons'));

		// Checkbox: Hide Feedback Smiley
		const hideButtonContainer = dom.append(buttonsContainer, dom.$('div.hide-button-container'));

		this.hideButton = dom.append(hideButtonContainer, dom.$('input.hide-button'));
		this.hideButton.type = 'checkbox';
		this.hideButton.checked = true;
		this.hideButton.id = 'hide-button';

		const hideButtonLabel = dom.append(hideButtonContainer, dom.$('label'));
		hideButtonLabel.setAttribute('for', 'hide-button');
		hideButtonLabel.textContent = nls.localize('showFeedback', "Show Feedback Smiley in Status Bar");

		// Button: Send Feedback
		this.sendButton = new Button(buttonsContainer);
		this.sendButton.enabled = false;
		this.sendButton.label = nls.localize('tweet', "Tweet");
		dom.addClass(this.sendButton.element, 'send');
		this.sendButton.element.title = nls.localize('tweetFeedback', "Tweet Feedback");
		disposables.add(attachButtonStyler(this.sendButton, this.themeService));

		this.sendButton.onDidClick(() => this.onSubmit());

		disposables.add(attachStylerCallback(this.themeService, { widgetShadow, editorWidgetBackground, editorWidgetForeground, inputBackground, inputForeground, inputBorder, editorBackground, contrastBorder }, colors => {
			if (this.feedbackForm) {
				this.feedbackForm.style.backgroundColor = colors.editorWidgetBackground ? colors.editorWidgetBackground.toString() : null;
				this.feedbackForm.style.color = colors.editorWidgetForeground ? colors.editorWidgetForeground.toString() : null;
				this.feedbackForm.style.boxShadow = colors.widgetShadow ? `0 0 8px ${colors.widgetShadow}` : null;
			}
			if (this.feedbackDescriptionInput) {
				this.feedbackDescriptionInput.style.backgroundColor = colors.inputBackground ? colors.inputBackground.toString() : null;
				this.feedbackDescriptionInput.style.color = colors.inputForeground ? colors.inputForeground.toString() : null;
				this.feedbackDescriptionInput.style.border = `1px solid ${colors.inputBorder || 'transparent'}`;
			}

			contactUsContainer.style.backgroundColor = colors.editorBackground ? colors.editorBackground.toString() : null;
			contactUsContainer.style.border = `1px solid ${colors.contrastBorder || 'transparent'}`;
		}));

		return {
			dispose: () => {
				this.feedbackForm = null;
				this.feedbackDescriptionInput = null;
				this.smileyInput = null;
				this.frownyInput = null;

				disposables.dispose();
			}
		};
	}