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();
}
};
}