/*eslint max-lines: ["warn", {"max": 350, "skipBlankLines": true, "skipComments": true}]*/ require('./snippetbar.less'); const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); const cx = require('classnames'); import { loadHistory } from '../../utils/versionHistory.js'; //Import all themes const ThemeSnippets = {}; ThemeSnippets['Legacy_5ePHB'] = require('themes/Legacy/5ePHB/snippets.js'); ThemeSnippets['V3_5ePHB'] = require('themes/V3/5ePHB/snippets.js'); ThemeSnippets['V3_5eDMG'] = require('themes/V3/5eDMG/snippets.js'); ThemeSnippets['V3_Journal'] = require('themes/V3/Journal/snippets.js'); ThemeSnippets['V3_Blank'] = require('themes/V3/Blank/snippets.js'); const EditorThemes = require('build/homebrew/codeMirror/editorThemes.json'); const execute = function(val, props){ if(_.isFunction(val)) return val(props); return val; }; const Snippetbar = createClass({ displayName : 'SnippetBar', getDefaultProps : function() { return { brew : {}, view : 'text', onViewChange : ()=>{}, onInject : ()=>{}, onToggle : ()=>{}, showEditButtons : true, renderer : 'legacy', undo : ()=>{}, redo : ()=>{}, historySize : ()=>{}, foldCode : ()=>{}, unfoldCode : ()=>{}, updateEditorTheme : ()=>{}, cursorPos : {}, snippetBundle : [], updateBrew : ()=>{} }; }, getInitialState : function() { return { renderer : this.props.renderer, themeSelector : false, snippets : [], showHistory : false, historyExists : false, historyItems : [] }; }, componentDidMount : async function(prevState) { const snippets = this.compileSnippets(); this.setState({ snippets : snippets }); }, componentDidUpdate : async function(prevProps, prevState) { if(prevProps.renderer != this.props.renderer || prevProps.theme != this.props.theme || prevProps.snippetBundle != this.props.snippetBundle) { this.setState({ snippets : this.compileSnippets() }); }; // Update history list if it has changed const checkHistoryItems = await loadHistory(this.props.brew); // If all items have the noData property, there is no saved data const checkHistoryExists = !checkHistoryItems.every((historyItem)=>{ return historyItem?.noData; }); if(prevState.historyExists != checkHistoryExists){ this.setState({ historyExists : checkHistoryExists }); } // If any history items have changed, update the list if(checkHistoryExists && checkHistoryItems.some((historyItem, index)=>{ return index >= prevState.historyItems.length || !_.isEqual(historyItem, prevState.historyItems[index]); })){ this.setState({ historyItems : checkHistoryItems }); } }, mergeCustomizer : function(oldValue, newValue, key) { if(key == 'snippets') { const result = _.reverse(_.unionBy(_.reverse(newValue), _.reverse(oldValue), 'name')); // Join snippets together, with preference for the child theme over the parent theme return result.filter((snip)=>snip.gen || snip.subsnippets); } }, compileSnippets : function() { let compiledSnippets = []; let oldSnippets = _.keyBy(compiledSnippets, 'groupName'); for (let snippets of this.props.snippetBundle) { if(typeof(snippets) == 'string') // load staticThemes as needed; they were sent as just a file name snippets = ThemeSnippets[snippets]; const newSnippets = _.keyBy(_.cloneDeep(snippets), 'groupName'); compiledSnippets = _.values(_.mergeWith(oldSnippets, newSnippets, this.mergeCustomizer)); oldSnippets = _.keyBy(compiledSnippets, 'groupName'); } return compiledSnippets; }, handleSnippetClick : function(injectedText){ this.props.onInject(injectedText); }, toggleThemeSelector : function(e){ if(e.target.tagName != 'SELECT'){ this.setState({ themeSelector : !this.state.themeSelector }); } }, changeTheme : function(e){ if(e.target.value == this.props.currentEditorTheme) return; this.props.updateEditorTheme(e.target.value); this.setState({ showThemeSelector : false, }); }, renderThemeSelector : function(){ return
; }, renderSnippetGroups : function(){ const snippets = this.state.snippets.filter((snippetGroup)=>snippetGroup.view === this.props.view); if(snippets.length === 0) return null; return
{_.map(snippets, (snippetGroup)=>{ return ; }) }
; }, replaceContent : function(item){ return this.props.updateBrew(item); }, toggleHistoryMenu : function(){ this.setState({ showHistory : !this.state.showHistory }); }, renderHistoryItems : function() { if(!this.state.historyExists) return; return
{_.map(this.state.historyItems, (item, index)=>{ if(item.noData || !item.savedAt) return; const saveTime = new Date(item.savedAt); const diffMs = new Date() - saveTime; const diffSecs = Math.floor(diffMs / 1000); let diffString = `about ${diffSecs} seconds ago`; if(diffSecs > 60) diffString = `about ${Math.floor(diffSecs / 60)} minutes ago`; if(diffSecs > (60 * 60)) diffString = `about ${Math.floor(diffSecs / (60 * 60))} hours ago`; if(diffSecs > (24 * 60 * 60)) diffString = `about ${Math.floor(diffSecs / (24 * 60 * 60))} days ago`; if(diffSecs > (7 * 24 * 60 * 60)) diffString = `about ${Math.floor(diffSecs / (7 * 24 * 60 * 60))} weeks ago`; return
{this.replaceContent(item);}} > v{item.version} : {diffString}
; })}
; }, renderEditorButtons : function(){ if(!this.props.showEditButtons) return; return (
{this.props.view !== 'meta' && <>
{ this.state.showHistory && this.renderHistoryItems() }
{this.state.themeSelector && this.renderThemeSelector()}
}
this.props.onViewChange('text')}>
this.props.onViewChange('style')}>
this.props.onViewChange('meta')}>
) }, render : function(){ return
{this.renderSnippetGroups()} {this.renderEditorButtons()}
; } }); module.exports = Snippetbar; const SnippetGroup = createClass({ displayName : 'SnippetGroup', getDefaultProps : function() { return { brew : {}, groupName : '', icon : 'fas fa-rocket', snippets : [], onSnippetClick : function(){}, }; }, handleSnippetClick : function(e, snippet){ e.stopPropagation(); this.props.onSnippetClick(execute(snippet.gen, this.props)); }, renderSnippets : function(snippets){ return _.map(snippets, (snippet)=>{ return
this.handleSnippetClick(e, snippet)}> {snippet.name} {snippet.experimental && beta} {snippet.disabled && disabled} {snippet.subsnippets && <>
{this.renderSnippets(snippet.subsnippets)}
}
; }); }, render : function(){ return
{this.props.groupName}
{this.renderSnippets(this.props.snippets)}
; }, });