diff --git a/webmaker/src/components/AddLibrary.jsx b/webmaker/src/components/AddLibrary.jsx index 94df91f..1ee76a0 100644 --- a/webmaker/src/components/AddLibrary.jsx +++ b/webmaker/src/components/AddLibrary.jsx @@ -1,6 +1,7 @@ import { h, Component } from 'preact'; import { jsLibs, cssLibs } from '../libraryList'; import { trackEvent } from '../analytics'; +import { LibraryAutoSuggest } from './LibraryAutoSuggest'; export default class AddLibrary extends Component { constructor(props) { @@ -20,6 +21,10 @@ export default class AddLibrary extends Component { this.setState({ js: `${this.state.js}\n${target.value}` }); + } else { + this.setState({ + css: `${this.state.css}\n${target.value}` + }); } trackEvent('ui', 'addLibrarySelect', target.selectedOptions[0].label); @@ -27,17 +32,51 @@ export default class AddLibrary extends Component { // Reset the select to the default value target.value = ''; } + textareaBlurHandler(e, textarea) { + const target = e ? e.target : textarea; + const type = target.dataset.lang; + if (type === 'js') { + this.setState({ + js: target.value || '' + }); + } else { + this.setState({ + css: target.value || '' + }); + } + + // trackEvent('ui', 'addLibrarySelect', target.selectedOptions[0].label); + this.props.onChange({ js: this.state.js, css: this.state.css }); + } + suggestionSelectHandler(value) { + const textarea = value.match(/\.js$/) + ? window.externalJsTextarea + : window.externalCssTextarea; + textarea.value = `${textarea.value}\n${value}`; + window.externalLibrarySearchInput.value = ''; + this.textareaBlurHandler(null, textarea); + } render() { return (
Put each library in new line
+Note: You can load external scripts from following domains: localhost, https://ajax.googleapis.com, https://code.jquery.com, @@ -76,23 +117,27 @@ export default class AddLibrary extends Component {
-Put each library in new line
); diff --git a/webmaker/src/components/Footer.jsx b/webmaker/src/components/Footer.jsx index 8c494cd..df873f7 100644 --- a/webmaker/src/components/Footer.jsx +++ b/webmaker/src/components/Footer.jsx @@ -1,5 +1,4 @@ import { h, Component } from 'preact'; -import Modal from './Modal.jsx'; import { A } from './common'; export default class Footer extends Component { diff --git a/webmaker/src/components/LibraryAutoSuggest.jsx b/webmaker/src/components/LibraryAutoSuggest.jsx new file mode 100644 index 0000000..f051736 --- /dev/null +++ b/webmaker/src/components/LibraryAutoSuggest.jsx @@ -0,0 +1,164 @@ +import { h, Component } from 'preact'; +import { trackEvent } from '../analytics'; + +export class LibraryAutoSuggest extends Component { + componentDidMount() { + this.t = this.wrap.querySelector('input,textarea'); + this.filter = this.props.filter; + this.selectedCallback = this.props.onSelect; + + // after list is insrted into the DOM, we put it in the body + // fixed at same position + setTimeout(() => { + requestIdleCallback(() => { + document.body.appendChild(this.list); + this.list.style.position = 'fixed'; + }); + }, 100); + + this.t.addEventListener('input', e => this.onInput(e)); + this.t.addEventListener('keydown', e => this.onKeyDown(e)); + this.t.addEventListener('blur', e => this.closeSuggestions(e)); + this.list.addEventListener('mousedown', e => this.onListMouseDown(e)); + } + componentWillUnmount() { + this.t.removeEventListener('input', e => this.onInput(e)); + this.t.removeEventListener('keydown', e => this.onKeyDown(e)); + this.t.removeEventListener('blur', e => this.closeSuggestions(e)); + this.list.removeEventListener('mousedown', e => this.onListMouseDown(e)); + } + + get currentLineNumber() { + return this.t.value.substr(0, this.t.selectionStart).split('\n').length; + } + get currentLine() { + var line = this.currentLineNumber; + return this.t.value.split('\n')[line - 1]; + } + closeSuggestions() { + this.list.classList.remove('is-open'); + this.isShowingSuggestions = false; + } + getList(input) { + var url = 'https://api.cdnjs.com/libraries?search='; + return fetch(url + input).then(response => { + return response.json().then(json => json.results); + }); + } + replaceCurrentLine(val) { + var lines = this.t.value.split('\n'); + lines.splice(this.currentLineNumber - 1, 1, val); + this.t.value = lines.join('\n'); + } + onInput() { + var currentLine = this.currentLine; + if (currentLine) { + if (currentLine.indexOf('/') !== -1 || currentLine.match(/https*:\/\//)) { + return; + } + clearTimeout(this.timeout); + this.timeout = setTimeout(() => { + this.loader.style.display = 'block'; + this.getList(currentLine).then(arr => { + this.loader.style.display = 'none'; + if (!arr.length) { + this.closeSuggestions(); + return; + } + this.list.innerHTML = ''; + if (this.filter) { + /* eslint-disable no-param-reassign */ + arr = arr.filter(this.filter); + } + for (var i = 0; i < Math.min(arr.length, 10); i++) { + this.list.innerHTML += `