Best JavaScript code snippet using storybook-root
ReplyEditor.jsx
Source:ReplyEditor.jsx
1import React from 'react';2import PropTypes from 'prop-types';3import reactForm from 'app/utils/ReactForm';4import * as transactionActions from 'app/redux/TransactionReducer';5import * as userActions from 'app/redux/UserReducer';6import MarkdownViewer from 'app/components/cards/MarkdownViewer';7import CategorySelector from 'app/components/cards/CategorySelector';8import { validateCategory } from 'app/components/cards/CategorySelector';9import LoadingIndicator from 'app/components/elements/LoadingIndicator';10import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';11import Tooltip from 'app/components/elements/Tooltip';12import sanitizeConfig, { allowedTags } from 'app/utils/SanitizeConfig';13import sanitize from 'sanitize-html';14import HtmlReady from 'shared/HtmlReady';15import * as globalActions from 'app/redux/GlobalReducer';16import { Set } from 'immutable';17import Remarkable from 'remarkable';18import Dropzone from 'react-dropzone';19import tt from 'counterpart';20import axios from 'axios';21const remarkable = new Remarkable({ html: true, linkify: false, breaks: true });22const RTE_DEFAULT = false;23class ReplyEditor extends React.Component {24 static propTypes = {25 // html component attributes26 formId: PropTypes.string.isRequired, // unique form id for each editor27 type: PropTypes.oneOf(['submit_story', 'submit_comment', 'edit']),28 successCallback: PropTypes.func, // indicator that the editor is done and can be hidden29 onCancel: PropTypes.func, // hide editor when cancel button clicked30 author: PropTypes.string, // empty or string for top-level post31 permlink: PropTypes.string, // new or existing category (default calculated from title)32 parent_author: PropTypes.string, // empty or string for top-level post33 parent_permlink: PropTypes.string, // new or existing category34 jsonMetadata: PropTypes.object, // An existing comment has its own meta data35 category: PropTypes.string, // initial value36 title: PropTypes.string, // initial value37 body: PropTypes.string, // initial value38 richTextEditor: PropTypes.func,39 defaultPayoutType: PropTypes.string,40 payoutType: PropTypes.string,41 };42 static defaultProps = {43 isStory: false,44 author: '',45 parent_author: '',46 parent_permlink: '',47 type: 'submit_comment',48 };49 constructor(props) {50 super();51 this.state = { progress: {} };52 this.initForm(props);53 }54 componentWillMount() {55 const { setMetaData, formId, jsonMetadata } = this.props;56 setMetaData(formId, jsonMetadata);57 if (process.env.BROWSER) {58 // Check for rte editor preference59 let rte =60 this.props.isStory &&61 JSON.parse(62 localStorage.getItem('replyEditorData-rte') || RTE_DEFAULT63 );64 let raw = null;65 // Process initial body value (if this is an edit)66 const { body } = this.state;67 if (body.value) {68 raw = body.value;69 }70 // Check for draft data71 let draft = localStorage.getItem('replyEditorData-' + formId);72 if (draft) {73 draft = JSON.parse(draft);74 const { category, title } = this.state;75 if (category) category.props.onChange(draft.category);76 if (title) title.props.onChange(draft.title);77 if (draft.payoutType)78 this.props.setPayoutType(formId, draft.payoutType);79 raw = draft.body;80 }81 // If we have an initial body, check if it's html or markdown82 if (raw) {83 rte = isHtmlTest(raw);84 }85 // console.log("initial reply body:", raw || '(empty)')86 body.props.onChange(raw);87 this.setState({88 rte,89 rte_value: rte90 ? stateFromHtml(this.props.richTextEditor, raw)91 : null,92 });93 }94 }95 componentDidMount() {96 setTimeout(() => {97 if (this.props.isStory) this.refs.titleRef.focus();98 else if (this.refs.postRef) this.refs.postRef.focus();99 else if (this.refs.rte) this.refs.rte._focus();100 }, 300);101 }102 shouldComponentUpdate = shouldComponentUpdate(this, 'ReplyEditor');103 componentWillUpdate(nextProps, nextState) {104 if (process.env.BROWSER) {105 const ts = this.state;106 const ns = nextState;107 const tp = this.props;108 const np = nextProps;109 // Save curent draft to localStorage110 if (111 ts.body.value !== ns.body.value ||112 (ns.category && ts.category.value !== ns.category.value) ||113 (ns.title && ts.title.value !== ns.title.value) ||114 np.payoutType !== tp.payoutType115 ) {116 // also prevents saving after parent deletes this information117 const { formId, payoutType } = np;118 const { category, title, body } = ns;119 const data = {120 formId,121 title: title ? title.value : undefined,122 category: category ? category.value : undefined,123 body: body.value,124 payoutType,125 };126 clearTimeout(saveEditorTimeout);127 saveEditorTimeout = setTimeout(() => {128 // console.log('save formId', formId, body.value)129 localStorage.setItem(130 'replyEditorData-' + formId,131 JSON.stringify(data, null, 0)132 );133 this.showDraftSaved();134 }, 500);135 }136 }137 }138 componentWillUnmount() {139 const { clearMetaData, formId } = this.props;140 clearMetaData(formId);141 }142 initForm(props) {143 const { isStory, type, fields } = props;144 const isEdit = type === 'edit';145 const maxKb = isStory ? 65 : 16;146 reactForm({147 fields,148 instance: this,149 name: 'replyForm',150 initialValues: props.initialValues,151 validation: values => ({152 title:153 isStory &&154 (!values.title || values.title.trim() === ''155 ? tt('g.required')156 : values.title.length > 255157 ? tt('reply_editor.shorten_title')158 : null),159 category: isStory && validateCategory(values.category, !isEdit),160 body: !values.body161 ? tt('g.required')162 : values.body.length > maxKb * 1024163 ? tt('reply_editor.exceeds_maximum_length', { maxKb })164 : null,165 }),166 });167 }168 onTitleChange = e => {169 const value = e.target.value;170 // TODO block links in title (they do not make good permlinks)171 const hasMarkdown = /(?:\*[\w\s]*\*|\#[\w\s]*\#|_[\w\s]*_|~[\w\s]*~|\]\s*\(|\]\s*\[)/.test(172 value173 );174 this.setState({175 titleWarn: hasMarkdown176 ? tt('reply_editor.markdown_not_supported')177 : '',178 });179 const { title } = this.state;180 title.props.onChange(e);181 };182 onCancel = e => {183 if (e) e.preventDefault();184 const { formId, onCancel, defaultPayoutType } = this.props;185 const { replyForm, body } = this.state;186 if (187 !body.value ||188 confirm(tt('reply_editor.are_you_sure_you_want_to_clear_this_form'))189 ) {190 replyForm.resetForm();191 this.setState({192 rte_value: stateFromHtml(this.props.richTextEditor),193 });194 this.setState({ progress: {} });195 this.props.setPayoutType(formId, defaultPayoutType);196 if (onCancel) onCancel(e);197 }198 };199 // As rte_editor is updated, keep the (invisible) 'body' field in sync.200 onChange = rte_value => {201 this.setState({ rte_value });202 const html = stateToHtml(rte_value);203 const { body } = this.state;204 if (body.value !== html) body.props.onChange(html);205 };206 toggleRte = e => {207 e.preventDefault();208 const state = { rte: !this.state.rte };209 if (state.rte) {210 const { body } = this.state;211 state.rte_value = isHtmlTest(body.value)212 ? stateFromHtml(this.props.richTextEditor, body.value)213 : stateFromMarkdown(this.props.richTextEditor, body.value);214 }215 this.setState(state);216 localStorage.setItem('replyEditorData-rte', !this.state.rte);217 };218 showDraftSaved() {219 const { draft } = this.refs;220 draft.className = 'ReplyEditor__draft';221 void draft.offsetWidth; // reset animation222 draft.className = 'ReplyEditor__draft ReplyEditor__draft-saved';223 }224 showAdvancedSettings = e => {225 e.preventDefault();226 this.props.setPayoutType(this.props.formId, this.props.payoutType);227 this.props.showAdvancedSettings(this.props.formId);228 };229 onDrop = (acceptedFiles, rejectedFiles) => {230 if (!acceptedFiles.length) {231 if (rejectedFiles.length) {232 this.setState({233 progress: { error: 'Please insert only image files.' },234 });235 console.log('onDrop Rejected files: ', rejectedFiles);236 }237 return;238 }239 const file = acceptedFiles[0];240 this.upload(file, file.name);241 };242 onOpenClick = () => {243 this.dropzone.open();244 };245 onPasteCapture = e => {246 try {247 if (e.clipboardData) {248 for (const item of e.clipboardData.items) {249 if (item.kind === 'file' && /^image\//.test(item.type)) {250 const blob = item.getAsFile();251 this.upload(blob);252 }253 }254 } else {255 // http://joelb.me/blog/2011/code-snippet-accessing-clipboard-images-with-javascript/256 // contenteditable element that catches all pasted data257 this.setState({ noClipboardData: true });258 }259 } catch (error) {260 console.error('Error analyzing clipboard event', error);261 }262 };263 upload = (file, name = '') => {264 this.setState({265 progress: { message: tt('reply_editor.uploading') },266 });267 //bilal268 const formData = new FormData()269 let URIpost = "https://graphql.voilk.com/upload/files/"270 formData.append("photos", file)271 272 const config = {273 onUploadProgress: progressEvent => {274 this.setState({progress: progressEvent.loaded})275 }, // TO SHOW UPLOAD STATUS276 277 headers: {278 'content-type': 'multipart/form-data'279 }280 };281 axios.post(URIpost, formData, config, {282 }).then(res => {283 if(res.data.files[0]){284 let name = res.data.files[0].metadata.originalname;285 let url = res.data.files[0].metadata.fileurl;286 const image_md = `![${name}](${url})`;287 const { body } = this.state;288 const { selectionStart, selectionEnd } = this.refs.postRef;289 body.props.onChange(290 body.value.substring(0, selectionStart) +291 image_md +292 body.value.substring(selectionEnd, body.value.length)293 );294 295 }296 setTimeout(() => {297 this.setState({ progress: {} });298 }, 8000); // clear message299 })300 };301 render() {302 const originalPost = {303 category: this.props.category,304 body: this.props.body,305 };306 const { onCancel, onTitleChange } = this;307 const { title, category, body } = this.state;308 const {309 reply,310 username,311 isStory,312 formId,313 noImage,314 author,315 permlink,316 parent_author,317 parent_permlink,318 type,319 jsonMetadata,320 state,321 successCallback,322 defaultPayoutType,323 payoutType,324 } = this.props;325 const { submitting, valid, handleSubmit } = this.state.replyForm;326 const { postError, titleWarn, rte } = this.state;327 const { progress, noClipboardData } = this.state;328 const disabled = submitting || !valid;329 const loading = submitting || this.state.loading;330 const errorCallback = estr => {331 this.setState({ postError: estr, loading: false });332 };333 const successCallbackWrapper = (...args) => {334 this.setState({ loading: false });335 this.props.setPayoutType(formId, defaultPayoutType);336 if (successCallback) successCallback(args);337 };338 const isEdit = type === 'edit';339 const isHtml = rte || isHtmlTest(body.value);340 const replyParams = {341 author,342 permlink,343 parent_author,344 parent_permlink,345 type,346 state,347 originalPost,348 isHtml,349 isStory,350 jsonMetadata,351 payoutType,352 successCallback: successCallbackWrapper,353 errorCallback,354 };355 const postLabel = username ? (356 <Tooltip t={tt('g.post_as_user', { username })}>357 {tt('g.post')}358 </Tooltip>359 ) : (360 tt('g.post')361 );362 const hasTitleError = title && title.touched && title.error;363 let titleError = null;364 // The Required title error (triggered onBlur) can shift the form making it hard to click on things..365 if (366 (hasTitleError &&367 (title.error !== tt('g.required') || body.value !== '')) ||368 titleWarn369 ) {370 titleError = (371 <div className={hasTitleError ? 'error' : 'warning'}>372 {hasTitleError ? title.error : titleWarn} 373 </div>374 );375 }376 // TODO: remove all references to these vframe classes. Removed from css and no longer needed.377 const vframe_class = isStory ? 'vframe' : '';378 const vframe_section_class = isStory ? 'vframe__section' : '';379 const vframe_section_shrink_class = isStory380 ? 'vframe__section--shrink'381 : '';382 const RichTextEditor = this.props.richTextEditor;383 return (384 <div className="ReplyEditor row">385 <div className="column small-12">386 <div387 ref="draft"388 className="ReplyEditor__draft ReplyEditor__draft-hide"389 >390 {tt('reply_editor.draft_saved')}391 </div>392 <form393 className={vframe_class}394 onSubmit={handleSubmit(({ data }) => {395 const startLoadingIndicator = () =>396 this.setState({397 loading: true,398 postError: undefined,399 });400 reply({401 ...data,402 ...replyParams,403 startLoadingIndicator,404 });405 })}406 onChange={() => {407 this.setState({ postError: null });408 }}409 >410 <div className={vframe_section_shrink_class}>411 {isStory && (412 <span>413 <input414 type="text"415 className="ReplyEditor__title"416 onChange={onTitleChange}417 disabled={loading}418 placeholder={tt('reply_editor.title')}419 autoComplete="off"420 ref="titleRef"421 tabIndex={1}422 {...title.props}423 />424 <div425 className="float-right secondary"426 style={{ marginRight: '1rem' }}427 >428 {rte && (429 <a430 href="#"431 onClick={this.toggleRte}432 >433 {body.value434 ? 'Raw HTML'435 : 'Markdown'}436 </a>437 )}438 {!rte &&439 (isHtml || !body.value) && (440 <a441 href="#"442 onClick={this.toggleRte}443 >444 {tt('reply_editor.editor')}445 </a>446 )}447 </div>448 {titleError}449 </span>450 )}451 </div>452 <div453 className={454 'ReplyEditor__body ' +455 (rte456 ? `rte ${vframe_section_class}`457 : vframe_section_shrink_class)458 }459 >460 {process.env.BROWSER && rte ? (461 <RichTextEditor462 ref="rte"463 readOnly={loading}464 value={this.state.rte_value}465 onChange={this.onChange}466 onBlur={body.onBlur}467 tabIndex={2}468 />469 ) : (470 <span>471 <Dropzone472 onDrop={this.onDrop}473 className={474 type === 'submit_story'475 ? 'dropzone'476 : 'none'477 }478 disableClick479 multiple={false}480 accept="image/*"481 ref={node => {482 this.dropzone = node;483 }}484 >485 <textarea486 {...body.props}487 ref="postRef"488 onPasteCapture={this.onPasteCapture}489 className={490 type === 'submit_story'491 ? 'upload-enabled'492 : ''493 }494 disabled={loading}495 rows={isStory ? 10 : 3}496 placeholder={497 isStory498 ? tt('g.write_your_story')499 : tt('g.reply')500 }501 autoComplete="off"502 tabIndex={2}503 />504 </Dropzone>505 <p className="drag-and-drop">506 {tt(507 'reply_editor.insert_images_by_dragging_dropping'508 )}509 {noClipboardData510 ? ''511 : tt(512 'reply_editor.pasting_from_the_clipboard'513 )}514 {tt('reply_editor.or_by')}{' '}515 <a onClick={this.onOpenClick}>516 {tt('reply_editor.selecting_them')}517 </a>.518 </p>519 {progress.message && (520 <div className="info">521 {progress.message}522 </div>523 )}524 {progress.error && (525 <div className="error">526 {tt('reply_editor.image_upload')} :{' '}527 {progress.error}528 </div>529 )}530 </span>531 )}532 </div>533 <div className={vframe_section_shrink_class}>534 <div className="error">535 {body.touched &&536 body.error &&537 body.error !== 'Required' &&538 body.error}539 </div>540 </div>541 <div542 className={vframe_section_shrink_class}543 style={{ marginTop: '0.5rem' }}544 >545 {isStory && (546 <span>547 <CategorySelector548 {...category.props}549 disabled={loading}550 isEdit={isEdit}551 tabIndex={3}552 />553 <div className="error">554 {(category.touched || category.value) &&555 category.error} 556 </div>557 </span>558 )}559 </div>560 <div className={vframe_section_shrink_class}>561 {isStory &&562 !isEdit && (563 <div className="ReplyEditor__options">564 <div>565 <div>566 {tt('g.rewards')}567 {': '}568 {this.props.payoutType ==569 '0%' &&570 tt(571 'reply_editor.decline_payout'572 )}573 {this.props.payoutType ==574 '50%' &&575 tt(576 'reply_editor.default_50_50'577 )}578 {this.props.payoutType ==579 '100%' &&580 tt(581 'reply_editor.power_up_100'582 )}583 </div>584 <a585 href="#"586 onClick={587 this.showAdvancedSettings588 }589 >590 {tt(591 'reply_editor.advanced_settings'592 )}593 </a>{' '}594 <br />595 596 </div>597 </div>598 )}599 </div>600 <div className={vframe_section_shrink_class}>601 {postError && (602 <div className="error">{postError}</div>603 )}604 </div>605 <div className={vframe_section_shrink_class}>606 {!loading && (607 <button608 type="submit"609 className="button"610 disabled={disabled}611 tabIndex={4}612 >613 {isEdit614 ? tt('reply_editor.update_post')615 : postLabel}616 </button>617 )}618 {loading && (619 <span>620 <br />621 <LoadingIndicator type="circle" />622 </span>623 )}624 {' '}625 {!loading &&626 this.props.onCancel && (627 <button628 type="button"629 className="secondary hollow button no-border"630 tabIndex={5}631 onClick={onCancel}632 >633 {tt('g.cancel')}634 </button>635 )}636 {!loading &&637 !this.props.onCancel && (638 <button639 className="button hollow no-border"640 tabIndex={5}641 disabled={submitting}642 onClick={onCancel}643 >644 {tt('g.clear')}645 </button>646 )}647 {!isStory &&648 !isEdit &&649 this.props.payoutType != '50%' && (650 <div className="ReplyEditor__options float-right text-right">651 {tt('g.rewards')}652 {': '}653 {this.props.payoutType == '0%' &&654 tt('reply_editor.decline_payout')}655 {this.props.payoutType == '100%' &&656 tt('reply_editor.power_up_100')}657 {'. '}658 <a href={'/@' + username + '/settings'}>659 Update settings660 </a>661 </div>662 )}663 </div>664 {!loading &&665 !rte &&666 body.value && (667 <div668 className={669 'Preview ' + vframe_section_shrink_class670 }671 >672 {!isHtml && (673 <div className="float-right">674 <a675 target="_blank"676 href="https://guides.github.com/features/mastering-markdown/"677 rel="noopener noreferrer"678 >679 {tt(680 'reply_editor.markdown_styling_guide'681 )}682 </a>683 </div>684 )}685 <h6>{tt('g.preview')}</h6>686 <MarkdownViewer687 text={body.value}688 jsonMetadata={jsonMetadata}689 large={isStory}690 noImage={noImage}691 />692 </div>693 )}694 </form>695 </div>696 </div>697 );698 }699}700let saveEditorTimeout;701// removes <html></html> wrapper if exists702function stripHtmlWrapper(text) {703 const m = text.match(/<html>\n*([\S\s]+?)?\n*<\/html>/m);704 return m && m.length === 2 ? m[1] : text;705}706// See also MarkdownViewer render707const isHtmlTest = text => /^<html>/.test(text);708function stateToHtml(state) {709 let html = state.toString('html');710 if (html === '<p></p>') html = '';711 if (html === '<p><br></p>') html = '';712 if (html == '') return '';713 return `<html>\n${html}\n</html>`;714}715function stateFromHtml(RichTextEditor, html = null) {716 if (!RichTextEditor) return null;717 if (html) html = stripHtmlWrapper(html);718 if (html && html.trim() == '') html = null;719 return html720 ? RichTextEditor.createValueFromString(html, 'html')721 : RichTextEditor.createEmptyValue();722}723function stateFromMarkdown(RichTextEditor, markdown) {724 let html;725 if (markdown && markdown.trim() !== '') {726 html = remarkable.render(markdown);727 html = HtmlReady(html).html; // TODO: option to disable youtube conversion, @-links, img proxy728 //html = htmlclean(html) // normalize whitespace729 console.log('markdown converted to:', html);730 }731 return stateFromHtml(RichTextEditor, html);732}733import { connect } from 'react-redux';734const richTextEditor = process.env.BROWSER735 ? require('react-rte-image').default736 : null;737export default formId =>738 connect(739 // mapStateToProps740 (state, ownProps) => {741 const username = state.user.getIn(['current', 'username']);742 const fields = ['body'];743 const { type, parent_author, jsonMetadata } = ownProps;744 const isEdit = type === 'edit';745 const isStory =746 /submit_story/.test(type) || (isEdit && parent_author === '');747 if (isStory) fields.push('title');748 if (isStory) fields.push('category');749 let { category, title, body } = ownProps;750 if (/submit_/.test(type)) title = body = '';751 if (isStory && jsonMetadata && jsonMetadata.tags) {752 category = Set([category, ...jsonMetadata.tags]).join(' ');753 }754 const defaultPayoutType = state.app.getIn(755 [756 'user_preferences',757 isStory ? 'defaultBlogPayout' : 'defaultCommentPayout',758 ],759 '50%'760 );761 let payoutType = state.user.getIn([762 'current',763 'post',764 formId,765 'payoutType',766 ]);767 if (!payoutType) {768 payoutType = defaultPayoutType;769 }770 const ret = {771 ...ownProps,772 fields,773 isStory,774 username,775 defaultPayoutType,776 payoutType,777 initialValues: { title, body, category },778 state,779 formId,780 richTextEditor,781 };782 return ret;783 },784 // mapDispatchToProps785 dispatch => ({786 clearMetaData: id => {787 dispatch(globalActions.clearMeta({ id }));788 },789 setMetaData: (id, jsonMetadata) => {790 dispatch(791 globalActions.setMetaData({792 id,793 meta: jsonMetadata ? jsonMetadata.voilk : null,794 })795 );796 },797 uploadImage: (file, progress) =>798 dispatch(userActions.uploadImage({ file, progress })),799 showAdvancedSettings: formId =>800 dispatch(userActions.showPostAdvancedSettings({ formId })),801 setPayoutType: (formId, payoutType) =>802 dispatch(803 userActions.set({804 key: ['current', 'post', formId, 'payoutType'],805 value: payoutType,806 })807 ),808 reply: ({809 category,810 title,811 body,812 author,813 permlink,814 parent_author,815 parent_permlink,816 isHtml,817 isStory,818 type,819 originalPost,820 payoutType = '50%',821 state,822 jsonMetadata,823 successCallback,824 errorCallback,825 startLoadingIndicator,826 }) => {827 // const post = state.global.getIn(['content', author + '/' + permlink])828 const username = state.user.getIn(['current', 'username']);829 const isEdit = type === 'edit';830 const isNew = /^submit_/.test(type);831 // Wire up the current and parent props for either an Edit or a Submit (new post)832 //'submit_story', 'submit_comment', 'edit'833 const linkProps = isNew834 ? {835 // submit new836 parent_author: author,837 parent_permlink: permlink,838 author: username,839 // permlink, assigned in TransactionSaga840 }841 : // edit existing842 isEdit843 ? { author, permlink, parent_author, parent_permlink }844 : null;845 if (!linkProps) throw new Error('Unknown type: ' + type);846 // If this is an HTML post, it MUST begin and end with the tag847 if (isHtml && !body.match(/^<html>[\s\S]*<\/html>$/)) {848 errorCallback(849 'HTML posts must begin with <html> and end with </html>'850 );851 return;852 }853 let rtags;854 {855 const html = isHtml ? body : remarkable.render(body);856 rtags = HtmlReady(html, { mutate: false });857 }858 allowedTags.forEach(tag => {859 rtags.htmltags.delete(tag);860 });861 if (isHtml) rtags.htmltags.delete('html'); // html tag allowed only in HTML mode862 if (rtags.htmltags.size) {863 errorCallback(864 'Please remove the following HTML elements from your post: ' +865 Array(...rtags.htmltags)866 .map(tag => `<${tag}>`)867 .join(', ')868 );869 return;870 }871 const formCategories = Set(872 category873 ? category874 .trim()875 .replace(/#/g, '')876 .split(/ +/)877 : []878 );879 const rootCategory =880 originalPost && originalPost.category881 ? originalPost.category882 : formCategories.first();883 let allCategories = Set([...formCategories.toJS()]);884 if (/^[-a-z\d]+$/.test(rootCategory))885 allCategories = allCategories.add(rootCategory);886 let postHashtags = [...rtags.hashtags];887 while (allCategories.size < 5 && postHashtags.length > 0) {888 allCategories = allCategories.add(postHashtags.shift());889 }890 // merge891 const meta = isEdit ? jsonMetadata : {};892 if (allCategories.size) meta.tags = allCategories.toJS();893 else delete meta.tags;894 if (rtags.usertags.size) meta.users = rtags.usertags;895 else delete meta.users;896 if (rtags.images.size) meta.image = rtags.images;897 else delete meta.image;898 if (rtags.links.size) meta.links = rtags.links;899 else delete meta.links;900 meta.app = 'voilknetwork/0.1';901 if (isStory) {902 meta.format = isHtml ? 'html' : 'markdown';903 }904 // if(Object.keys(json_metadata.voilk).length === 0) json_metadata = {}// keep json_metadata minimal905 const sanitizeErrors = [];906 sanitize(body, sanitizeConfig({ sanitizeErrors }));907 if (sanitizeErrors.length) {908 errorCallback(sanitizeErrors.join('. '));909 return;910 }911 if (meta.tags.length > 5) {912 const includingCategory = isEdit913 ? tt('reply_editor.including_the_category', {914 rootCategory,915 })916 : '';917 errorCallback(918 tt('reply_editor.use_limited_amount_of_tags', {919 tagsLength: meta.tags.length,920 includingCategory,921 })922 );923 return;924 }925 startLoadingIndicator();926 const originalBody = isEdit ? originalPost.body : null;927 const __config = { originalBody };928 // Avoid changing payout option during edits #735929 if (!isEdit) {930 switch (payoutType) {931 case '0%': // decline payout932 __config.comment_options = {933 max_accepted_payout: '0.000 VSD',934 };935 break;936 case '100%': // 100% voilk power payout937 __config.comment_options = {938 percent_voilk_dollars: 0, // 10000 === 100% (of 50%)939 };940 break;941 default: // 50% voilk power, 50% sd+voilk942 }943 }944 const operation = {945 ...linkProps,946 category: rootCategory,947 title,948 body,949 json_metadata: meta,950 __config,951 };952 dispatch(953 transactionActions.broadcastOperation({954 type: 'comment',955 operation,956 errorCallback,957 successCallback,958 })959 );960 },961 })...
me.js
Source:me.js
1import { faker } from '@faker-js/faker';2export default function me() { 3 let isStory = faker.datatype.boolean();4 let stories = [];5 if (isStory) { 6 for (let i = 0; i < faker.random.numeric(2); i++) {7 stories.push(faker.image.image());8 }9 }10 return {11 firstname: faker.name.firstName(),12 lastname: faker.name.lastName(),13 avatar: faker.image.avatar(),14 city: faker.address.city(),15 relationship:faker.helpers.arrayElement(['Single', 'Married', 'Divorced', 'Widowed', 'Cohabiting']),16 gender:faker.name.gender(true),17 job_title: faker.name.jobTitle(),18 job_area:faker.name.jobArea(),19 story: isStory,20 status: faker.lorem.words(),21 stories: stories22 };...
people.js
Source:people.js
1import { faker } from '@faker-js/faker';2import {rdn_boolean } from '../common/index.js'3export function people() {4 let reply = [];5 for (let i = 0; i < faker.random.numeric(2); i++) {6 let isStory = faker.datatype.boolean();7 let stories = [];8 if (isStory) { 9 for (let i = 0; i < faker.random.numeric(2); i++) {10 stories.push(faker.image.image());11 }12 }13 reply.push({14 firstName: faker.name.firstName(),15 lastName:faker.name.lastName(),16 msg: faker.lorem.sentence(3),17 date: faker.date.month(),18 count: faker.random.numeric(),19 story: isStory,20 image: faker.image.image(),21 avatar: faker.image.avatar(),22 status: faker.lorem.words(),23 stories:stories24 });25 }26 return reply;...
Using AI Code Generation
1import { isStory } from 'storybook-root';2import { isStory } from 'storybook-root';3import { isStory } from 'storybook-root';4import { isStory } from 'storybook-root';5import { isStory } from 'storybook-root';6import { isStory } from 'storybook-root';7import { isStory } from 'storybook-root';8import { isStory } from 'storybook-root';9import { isStory } from 'storybook-root';10import { isStory } from 'storybook-root';11import { isStory } from 'storybook-root';12import { isStory } from 'storybook-root';13import { isStory } from 'storybook-root';14import { isStory } from 'storybook-root';15import { isStory } from 'storybook-root';16import { isStory } from 'storybook-root';17import { isStory } from 'storybook-root';18import { isStory } from 'storybook-root';19import { isStory } from 'storybook-root';20import { isStory } from 'storybook-root';
Using AI Code Generation
1import { isStory } from 'storybook-root-provider';2import { isStory } from 'storybook-root-provider';3import { isStory } from 'storybook-root-provider';4import { isStory } from 'storybook-root-provider';5import { isStory } from 'storybook-root-provider';6import { isStory } from 'storybook-root-provider';7import { isStory } from 'storybook-root-provider';8import { isStory } from 'storybook-root-provider';9import { isStory } from 'storybook-root-provider';10import { isStory } from 'storybook-root-provider';11import { isStory } from 'storybook-root-provider';12import { isStory } from 'storybook-root-provider';
Using AI Code Generation
1import { useStorybookRootProvider } from 'storybook-root-provider';2const App = () => {3 const { isStory } = useStorybookRootProvider();4 return (5 {isStory ? 'Story' : 'App'}6 );7};8export default App;9import React from 'react';10import App from '../../test';11export default {12};13export const AppStory = () => <App />;14import React from 'react';15import App from '../../test';16export default {17};18export const StoryStory = () => <App />;19import React from 'react';20import App from '../../test';21export default {22};23export const PreviewStory = () => <App />;24import React from 'react';25import App from '../../test';26export default {27};28export const DocsStory = () => <App />;
Using AI Code Generation
1import { isStory } from 'storybook-root';2if (isStory()) {3}4import { isStory } from 'storybook-root';5if (isStory()) {6}7import { isStory } from 'storybook-root';8jest.mock('storybook-root', () => ({9 isStory: () => true,10}));11if (isStory()) {12}13MIT © [Kenny Robinson](
Using AI Code Generation
1import { isStory } from 'storybook-root';2export default function test() {3 if (isStory()) {4 }5}6import test from 'test';7export default {8};9export const Test = () => test();
Using AI Code Generation
1import { isStory } from 'storybook-root'2const isStorybook = isStory()3export default function test() {4 if (isStorybook) {5 }6}7export function isStory() {8}9export function isStory() {10}11"scripts": {12}13if (process.env.NODE_ENV === 'development') {14}
Using AI Code Generation
1import {isStory} from 'storybook-root';2import {render, html} from 'lit-html';3import {MyComponent} from './my-component';4if (isStory()) {5 const story = () => html`6 `;7 render(story(), document.getElementById('root'));8} else {9 render(html`<my-component></my-component>`, document.getElementById('root'));10}11import {LitElement, html} from 'lit-element';12import {withA11y} from '@storybook/addon-a11y';13export class MyComponent extends LitElement {14 static get properties() {15 return {16 name: {type: String}17 };18 }19 constructor() {20 super();21 this.name = 'World';22 }23 render() {24 return html`<p>Hello, ${this.name}!</p>`;25 }26}27customElements.define('my-component', MyComponent);28export default {29};30export const story1 = () => {31 const el = document.createElement('my-component');32 el.name = 'Storybook';33 return el;34};35story1.story = {36};
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!