Skip to content
Merged
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ node_modules
dist
coverage
**/*.d.ts
tests
tests
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module.exports = {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-namespace': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/no-control-regex': 'off',
'@typescript-eslint/quotes': [
'error',
'single',
Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^2.25.0",
"@typescript-eslint/parser": "^2.25.0",
"eslint": "^6.8.0",
"eslint": "^7.7.0",
"eslint-config-prettier": "^6.10.1",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-react": "^7.20.4",
Expand All @@ -90,7 +90,6 @@
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --cache --fix"
],
"*.js": "eslint --cache --fix"
]
}
}
91 changes: 88 additions & 3 deletions src/CodeSnippetEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Message } from '@lumino/messaging';
import { Button } from '@jupyterlab/ui-components';
import { CodeSnippetContentsService } from './CodeSnippetContentsService';
import { CodeSnippetWidget } from './CodeSnippetWidget';
import { SUPPORTED_LANGUAGES } from './index';

/**
* CSS style classes
Expand Down Expand Up @@ -300,7 +301,52 @@ export class CodeSnippetEditor extends ReactWidget {
}

saveChange(event: React.MouseEvent<HTMLElement, MouseEvent>): void {
this.updateSnippet();
const name = (document.querySelector(
`.${CODE_SNIPPET_EDITOR}-${this._codeSnippet.id} .${CODE_SNIPPET_EDITOR_NAME_INPUT}`
) as HTMLInputElement).value;
const description = (document.querySelector(
`.${CODE_SNIPPET_EDITOR}-${this._codeSnippet.id} .${CODE_SNIPPET_EDITOR_DESC_INPUT}`
) as HTMLInputElement).value;
const language = (document.querySelector(
`.${CODE_SNIPPET_EDITOR}-${this._codeSnippet.id} .${CODE_SNIPPET_EDITOR_LANG_INPUT}`
) as HTMLSelectElement).value;

const validity = this.validateInputs(name, description, language);
if (validity) {
this.updateSnippet();
}
}

private validateInputs(
name: string,
description: string,
language: string
): boolean {
let status = true;
let message = '';
if (name === '') {
message += 'Name must be filled out\n';
//alert("Description must be filled out");
status = false;
}
if (description === '') {
message += 'Description must be filled out\n';
//alert("");
status = false;
}
if (language === '') {
message += 'Language must be filled out';
//alert("Description ");
status = false;
}
if (!(language in SUPPORTED_LANGUAGES)) {
message += 'Language must be one of the options';
status = false;
}
if (status === false) {
alert(message);
}
return status;
}

async updateSnippet(): Promise<void> {
Expand Down Expand Up @@ -381,6 +427,29 @@ export class CodeSnippetEditor extends ReactWidget {
);
}

renderLanguages(): React.ReactElement {
SUPPORTED_LANGUAGES.sort();

return (
<div>
<input
className="jp-snippet-editor-language"
list="languages"
name="language"
defaultValue={this._codeSnippet.language}
required
/>
<datalist id="languages">
{SUPPORTED_LANGUAGES.map(lang => this.renderLanguageOptions(lang))}
</datalist>
</div>
);
}

renderLanguageOptions(option: string): JSX.Element {
return <option key={option} value={option} />;
}

render(): React.ReactElement {
return (
<div
Expand All @@ -399,27 +468,41 @@ export class CodeSnippetEditor extends ReactWidget {
className="jp-snippet-editor-name"
defaultValue={this._codeSnippet.name}
type="text"
required
pattern={'[a-zA-Z0-9_ ]+'}
onMouseDown={(
event: React.MouseEvent<HTMLInputElement, MouseEvent>
): void => this.activeFieldState(event)}
onChange={(event: React.ChangeEvent<HTMLInputElement>): void => {
this.handleInputFieldChange(event);
}}
></input>
<p className="jp-inputName-validity">
{
'Name of the code snippet MUST be alphanumeric or composed of underscore(_)'
}
</p>
<label className="jp-snippet-editor-description-label">
Description
</label>
<input
className="jp-snippet-editor-description"
defaultValue={this._codeSnippet.description}
type="text"
required
pattern={'[a-zA-Z0-9_ ]+'}
onMouseDown={(
event: React.MouseEvent<HTMLInputElement, MouseEvent>
): void => this.activeFieldState(event)}
onChange={(event: React.ChangeEvent<HTMLInputElement>): void => {
this.handleInputFieldChange(event);
}}
></input>
<p className="jp-inputDesc-validity">
{
'Description of the code snippet MUST be alphanumeric or composed of underscore(_)'
}
</p>
{/* <input
className="jp-snippet-editor-language"
type="text"
Expand All @@ -433,10 +516,12 @@ export class CodeSnippetEditor extends ReactWidget {
<option value="Scala"></option>
<option value="Other"></option>
</datalist> */}
<select
{this.renderLanguages()}
{/* <select
className="jp-snippet-editor-language"
defaultValue={this._codeSnippet.language}
name="languages"
required
>
<option className="jp-snippet-editor-options" value="python">
python
Expand All @@ -450,7 +535,7 @@ export class CodeSnippetEditor extends ReactWidget {
<option className="jp-snippet-editor-options" value="Other">
Other
</option>
</select>
</select> */}
</section>
<span className="jp-codeSnippetInputArea-editorTitle">Code</span>
{this.renderCodeInput()}
Expand Down
74 changes: 52 additions & 22 deletions src/CodeSnippetForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {

import { CodeSnippetWidget } from './CodeSnippetWidget';
import { CodeSnippetWidgetModel } from './CodeSnippetWidgetModel';
import { SUPPORTED_LANGUAGES } from './index';

/**
* The class name added to file dialogs.
Expand All @@ -24,7 +25,7 @@ const FILE_DIALOG_CLASS = 'jp-FileDialog';
/**
* The class name added for the new name label in the rename dialog
*/
const INPUT_NEWNAME_TITLE_CLASS = 'jp-new-name-title';
const INPUT_NEW_SNIPPET_CLASS = 'jp-newSnippet-input';

/**
* A stripped-down interface for a file container.
Expand Down Expand Up @@ -196,6 +197,10 @@ export function validateForm(input: Dialog.IResult<string[]>): boolean {
//alert("Description ");
status = false;
}
if (!(language in SUPPORTED_LANGUAGES)) {
message += 'Language must be one of the options';
status = false;
}
if (status === false) {
alert(message);
}
Expand All @@ -212,17 +217,14 @@ class InputHandler extends Widget {
constructor() {
super({ node: Private.createInputNode() });
this.addClass(FILE_DIALOG_CLASS);
console.log(
(this.node.getElementsByTagName('select')[0] as HTMLSelectElement).value
);
}

getValue(): string[] {
const inputs = [];
inputs.push(
(this.node.getElementsByTagName('input')[0] as HTMLInputElement).value,
(this.node.getElementsByTagName('input')[1] as HTMLInputElement).value,
(this.node.getElementsByTagName('select')[0] as HTMLSelectElement).value
(this.node.getElementsByTagName('datalist')[0] as HTMLSelectElement).value
);
return inputs;
}
Expand Down Expand Up @@ -262,30 +264,55 @@ class Private {
*/
static createInputNode(): HTMLElement {
const body = document.createElement('form');
const nameValidity = document.createElement('p');
nameValidity.textContent =
'Name of the code snippet MUST be alphanumeric or composed of underscore(_)';
nameValidity.className = 'jp-inputName-validity';

const descriptionValidity = document.createElement('p');
descriptionValidity.textContent =
'Description of the code snippet MUST be alphanumeric or composed of underscore(_)';
descriptionValidity.className = 'jp-inputDesc-validity';

const nameTitle = document.createElement('label');
nameTitle.textContent = 'Snippet Name*';
nameTitle.className = INPUT_NEWNAME_TITLE_CLASS;
const name = document.createElement('input');
name.className = INPUT_NEW_SNIPPET_CLASS;
name.required = true;
// prettier-ignore
name.pattern = '[a-zA-Z0-9_ ]+';

const descriptionTitle = document.createElement('label');
descriptionTitle.textContent = 'Description*';
descriptionTitle.className = INPUT_NEWNAME_TITLE_CLASS;
const description = document.createElement('input');
description.className = INPUT_NEW_SNIPPET_CLASS;
description.required = true;
// prettier-ignore
description.pattern = '[a-zA-Z0-9_ ]+';

const languageTitle = document.createElement('label');
languageTitle.textContent = 'Language*';
languageTitle.className = INPUT_NEWNAME_TITLE_CLASS;
const language = document.createElement('select');
const optionPython = document.createElement('option');
optionPython.textContent = 'python';
const optionR = document.createElement('option');
optionR.textContent = 'R';
const optionScala = document.createElement('option');
optionScala.textContent = 'Scala';
const optionOther = document.createElement('option');
optionOther.textContent = 'Other';
const languageInput = document.createElement('input');
languageInput.className = INPUT_NEW_SNIPPET_CLASS;
languageInput.setAttribute('list', 'languages');
languageInput.required = true;
const languageOption = document.createElement('datalist');
languageOption.id = 'languages';

SUPPORTED_LANGUAGES.sort();
for (const language of SUPPORTED_LANGUAGES) {
const option = document.createElement('option');
option.value = language;
languageOption.appendChild(option);
}
// const optionPython = document.createElement('option');
// optionPython.textContent = 'python';
// const optionR = document.createElement('option');
// optionR.textContent = 'R';
// const optionScala = document.createElement('option');
// optionScala.textContent = 'Scala';
// const optionOther = document.createElement('option');
// optionOther.textContent = 'Other';
// optionOther.onclick = (): void => {
// createLanguageInput(body);
// };
Expand All @@ -298,10 +325,10 @@ class Private {
// optionR.onclick = (): void => {
// removeLanguageInput(body);
// };
language.appendChild(optionPython);
language.appendChild(optionR);
language.appendChild(optionScala);
language.appendChild(optionOther);
// language.appendChild(optionPython);
// language.appendChild(optionR);
// language.appendChild(optionScala);
// language.appendChild(optionOther);

// if (language.value === 'Other') {
// createLanguageInput(body);
Expand All @@ -311,10 +338,13 @@ class Private {

body.appendChild(nameTitle);
body.appendChild(name);
body.appendChild(nameValidity);
body.appendChild(descriptionTitle);
body.appendChild(description);
body.appendChild(descriptionValidity);
body.appendChild(languageTitle);
body.appendChild(language);
body.appendChild(languageInput);
body.appendChild(languageOption);
return body;
}

Expand Down
Loading