import 'preact/devtools'; import { h, Component } from 'preact'; import linkState from 'linkstate'; import { submitArticle, previewArticle } from './actions'; import BodyMarkdown from './elements/bodyMarkdown'; import BodyPreview from './elements/bodyPreview'; import Description from './elements/description'; import PublishToggle from './elements/publishToggle'; import Notice from './elements/notice'; import Tags from './elements/tags'; import Title from './elements/title'; import MainImage from './elements/mainImage'; import ImageManagement from './elements/imageManagement'; import OrgSettings from './elements/orgSettings'; import Errors from './elements/errors'; import ImageUploadIcon from 'images/image-upload.svg'; import CodeMirror from 'codemirror'; import 'codemirror/mode/markdown/markdown'; const algoliaId = document.querySelector("meta[name='algolia-public-id']").content const algoliaKey = document.querySelector("meta[name='algolia-public-key']").content const env = document.querySelector("meta[name='environment']").content const client = algoliasearch(algoliaId, algoliaKey); const index = client.initIndex('Tag_'+env); export default class ArticleForm extends Component { constructor(props) { super(props); const article = JSON.parse(this.props.article); const organization = this.props.organization ? JSON.parse(this.props.organization) : null; this.state = { id: article.id || null, title: article.title || '', tagList: article.cached_tag_list || '', description: '', bodyMarkdown: article.body_markdown || '', published: article.published || false, tagOptions: [], selectedTags: [], tagInputListIndex: -1, previewShowing: false, helpShowing: false, previewHTML: '', helpHTML: document.getElementById('editor-help-guide').innerHTML, submitting: false, editing: article.id != null, imageManagementShowing: false, mainImageUrl: article.main_image || null, organization: organization, postUnderOrg: false, errors: null, }; } componentDidMount() { initEditorResize(); console.log('codemirror-ify') const editor = document.getElementById("article_body_markdown"); const myCodeMirror = CodeMirror(editor, { mode: "markdown", theme: "material", highlightFormatting: true, }); myCodeMirror.setSize("100%", "100%"); } handleTagKeyUp = e => { const component = this; const inputArray = e.target.value.split(',') component.setState({ tagList: e.target.value, }) const query = inputArray[inputArray.length -1].replace(/ /g,'') if (query === '' && e.target.value != '') { component.setState({ tagOptions: [], }) return } else if (e.target.value === '') { component.setState({ tagOptions: [], tagList: '', selectedTags: [] }) return } index.search(query, { hitsPerPage: 10, filters: 'supported:true', }) .then(function(content) { component.setState({ tagOptions: content.hits.filter(hit => !component.state.selectedTags.includes(hit.name)), }) }); } handleTagKeyDown = e => { const component = this; let keyCode = e.keyCode; if (component.state.selectedTags.length === 4 && e.keyCode === 188) { e.preventDefault() return } if((e.keyCode === 40 || e.keyCode === 9) && (component.state.tagInputListIndex < component.state.tagOptions.length -1) && (component.state.tagList != '')) { // down key or tab key e.preventDefault() this.setState({tagInputListIndex: component.state.tagInputListIndex + 1}) } else if (e.keyCode === 38 && component.state.tagInputListIndex > -1) { // up key e.preventDefault() this.setState({tagInputListIndex: component.state.tagInputListIndex - 1}) } else if (e.keyCode === 13 && component.state.tagInputListIndex > -1 ) { // return key e.preventDefault(); const newInput = component.state.selectedTags + component.state.tagOptions[component.state.tagInputListIndex].name + ','; document.getElementById('tag-input').value = newInput; component.setState({ tagOptions: [], tagList: newInput, tagInputListIndex: -1, selectedTags: newInput.split(',') }) setTimeout(function(){ document.getElementById('tag-input').focus(); }, 10) } else if (e.keyCode === 188 && component.state.tagInputListIndex === -1){ // comma key e.preventDefault(); const newInput = component.state.tagList + ','; document.getElementById('tag-input').value = newInput; component.setState({ tagOptions: [], tagList: newInput, tagInputListIndex: -1, selectedTags: newInput.split(',') }) } else if (e.keyCode === 8 ) { // Delete key if (component.state.tagList[component.state.tagList.length -1] === ',') { let selectedTags = component.state.selectedTags component.setState({ tagInputListIndex: -1, selectedTags: selectedTags.slice(0, selectedTags.length -2) }) } } else if ((e.keyCode < 65 || e.keyCode > 90) && e.keyCode != 188 && e.keyCode != 8 && e.keyCode != 37 && e.keyCode != 39 && e.keyCode != 9) { // not letter or comma or delete e.preventDefault() } } handleTagClick = e => { document.getElementById('tag-input').focus(); const newInput = this.state.selectedTags + e.target.dataset.content + ','; document.getElementById('tag-input').value = newInput; console.log('CLICK') this.setState({ tagOptions: [], tagList: newInput, tagInputListIndex: -1, selectedTags: newInput.split(',') }) } handleFocusChange = e => { const component = this; setTimeout(function(){ if (document.activeElement.id === 'tag-input'){ return } component.forceUpdate(); }, 100) } toggleHelp = e => { e.preventDefault(); window.scrollTo(0, 0); this.setState({ helpShowing: !this.state.helpShowing, previewShowing: false, }) } fetchPreview = e => { e.preventDefault(); if (this.state.previewShowing) { this.setState({ previewShowing: false, helpShowing: false, }) } else { previewArticle(this.state.bodyMarkdown, this.showPreview, this.failedPreview) } } toggleImageManagement = e => { e.preventDefault(); this.setState({imageManagementShowing: !this.state.imageManagementShowing}) } showPreview = response => { this.setState({ previewShowing: true, helpShowing: false, previewHTML: response.processed_html }) } toggleOrgPosting = e => { e.preventDefault(); this.setState({postUnderOrg: !this.state.postUnderOrg}) } failedPreview = response => { console.log(response) } handleMainImageUrlChange = payload => { this.setState({mainImageUrl: payload.link, imageManagementShowing: false}) } onPublish = e => { e.preventDefault(); this.setState({submitting: true, published: true}) let state = this.state; state['published'] = true; submitArticle(state, this.handleArticleError); }; onSaveDraft = e => { e.preventDefault(); this.setState({submitting: true, published: false}) let state = this.state; state['published'] = false; submitArticle(state, this.handleArticleError); } handleArticleError = response => { window.scrollTo(0, 0); this.setState({ errors: response, submitting: false, }) } render() { // cover image url should asking for url OR providing option to upload an image const { title, tagList, description, bodyMarkdown, published, tagOptions, tagInputListIndex, previewShowing, helpShowing, previewHTML, helpHTML, submitting, imageManagementShowing, organization, postUnderOrg, mainImageUrl, errors, } = this.state; // let tagOptionsHTML = '' const component = this; const tagOptionRows = tagOptions.map((tag, index) => { return