mirror of
https://github.com/chinchang/web-maker.git
synced 2025-04-26 13:47:12 +02:00
complete functionality for header
This commit is contained in:
parent
4642571658
commit
959fef487f
webmaker/src/components
@ -25,17 +25,29 @@ export default class ContentWrap extends Component {
|
||||
|
||||
onHtmlCodeChange(editor, change) {
|
||||
this.cmCodes.html = editor.getValue();
|
||||
this.props.onCodeChange('html', this.cmCodes.html);
|
||||
this.props.onCodeChange(
|
||||
'html',
|
||||
this.cmCodes.html,
|
||||
change.origin !== 'setValue'
|
||||
);
|
||||
this.onCodeChange(editor, change);
|
||||
}
|
||||
onCssCodeChange(editor, change) {
|
||||
this.cmCodes.css = editor.getValue();
|
||||
this.props.onCodeChange('css', this.cmCodes.css);
|
||||
this.props.onCodeChange(
|
||||
'css',
|
||||
this.cmCodes.css,
|
||||
change.origin !== 'setValue'
|
||||
);
|
||||
this.onCodeChange(editor, change);
|
||||
}
|
||||
onJsCodeChange(editor, change) {
|
||||
this.cmCodes.js = editor.getValue();
|
||||
this.props.onCodeChange('js', this.cmCodes.js);
|
||||
this.props.onCodeChange(
|
||||
'js',
|
||||
this.cmCodes.js,
|
||||
change.origin !== 'setValue'
|
||||
);
|
||||
this.onCodeChange(editor, change);
|
||||
}
|
||||
onCodeChange(editor, change) {
|
||||
@ -51,25 +63,11 @@ export default class ContentWrap extends Component {
|
||||
this.setPreviewContent();
|
||||
}
|
||||
|
||||
/* saveBtn.classList.add('is-marked');
|
||||
this.unsavedEditCount += 1;
|
||||
if (
|
||||
this.unsavedEditCount % this.unsavedEditWarningCount === 0 &&
|
||||
this.unsavedEditCount >= this.unsavedEditWarningCount
|
||||
) {
|
||||
saveBtn.classList.add('animated');
|
||||
saveBtn.classList.add('wobble');
|
||||
saveBtn.addEventListener('animationend', () => {
|
||||
saveBtn.classList.remove('animated');
|
||||
saveBtn.classList.remove('wobble');
|
||||
});
|
||||
} */
|
||||
|
||||
// Track when people actually are working.
|
||||
// trackEvent.previewCount = (trackEvent.previewCount || 0) + 1;
|
||||
// if (trackEvent.previewCount === 4) {
|
||||
// trackEvent('fn', 'usingPreview');
|
||||
// }
|
||||
trackEvent.previewCount = (trackEvent.previewCount || 0) + 1;
|
||||
if (trackEvent.previewCount === 4) {
|
||||
trackEvent('fn', 'usingPreview');
|
||||
}
|
||||
}
|
||||
}, this.updateDelay);
|
||||
}
|
||||
@ -292,17 +290,26 @@ export default class ContentWrap extends Component {
|
||||
this.codeInPreview.js = currentCode.js;
|
||||
}
|
||||
componentDidUpdate() {
|
||||
this.refreshEditor();
|
||||
// this.setPreviewContent(true);
|
||||
// console.log('componentdidupdate', this.props.currentItem);
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.onRef(this);
|
||||
}
|
||||
refreshEditor() {
|
||||
console.log('ContentWrap refresh editor');
|
||||
this.cmCodes.html = this.props.currentItem.html;
|
||||
this.cmCodes.css = this.props.currentItem.css;
|
||||
this.cmCodes.js = this.props.currentItem.js;
|
||||
this.cm.html.setValue(this.cmCodes.html || '');
|
||||
this.cm.css.setValue(this.cmCodes.css || '');
|
||||
this.cm.js.setValue(this.cmCodes.js || '');
|
||||
// this.setPreviewContent(true);
|
||||
// console.log('componentdidupdate', this.props.currentItem);
|
||||
}
|
||||
componentDidMount() {
|
||||
this.props.onRef(this);
|
||||
this.cm.html.refresh();
|
||||
this.cm.css.refresh();
|
||||
this.cm.js.refresh();
|
||||
|
||||
this.setPreviewContent(true);
|
||||
}
|
||||
applyCodemirrorSettings(prefs) {
|
||||
if (!this.cm) {
|
||||
|
@ -9,18 +9,6 @@ export default class Login extends Component {
|
||||
trackEvent('ui', 'loginProviderClick', provider);
|
||||
auth.login(provider);
|
||||
}
|
||||
logout(e) {
|
||||
if (this.unsavedEditCount) {
|
||||
var shouldDiscard = confirm(
|
||||
'You have unsaved changes. Do you still want to logout?'
|
||||
);
|
||||
if (!shouldDiscard) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
trackEvent('fn', 'loggedOut');
|
||||
auth.logout();
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
|
@ -9,7 +9,7 @@ export default class Header extends Component {
|
||||
id="titleInput"
|
||||
title="Click to edit"
|
||||
class="item-title-input"
|
||||
value="Untitled Work"
|
||||
value={this.props.title}
|
||||
onBlur={this.props.titleInputBlurHandler}
|
||||
/>
|
||||
<div class="main-header__btn-wrap flex flex-v-center">
|
||||
@ -46,7 +46,7 @@ export default class Header extends Component {
|
||||
<a
|
||||
class="flex flex-v-center hint--rounded hint--bottom-left"
|
||||
aria-label="Start a new creation"
|
||||
d-click="onNewBtnClick"
|
||||
onClick={this.props.newBtnHandler}
|
||||
>
|
||||
<svg
|
||||
style="vertical-align:middle;width:14px;height:14px"
|
||||
@ -59,7 +59,7 @@ export default class Header extends Component {
|
||||
id="saveBtn"
|
||||
class={`flex flex-v-center hint--rounded hint--bottom-left ${
|
||||
this.props.isSaving ? 'is-loading' : ''
|
||||
}`}
|
||||
} ${this.props.unsavedEditCount ? 'is-marked' : 0}`}
|
||||
aria-label="Save current creation (Ctrl/⌘ + S)"
|
||||
onClick={this.props.saveBtnHandler}
|
||||
>
|
||||
|
@ -5,6 +5,17 @@ export default class SavedItemPane extends Component {
|
||||
onCloseIntent() {
|
||||
this.props.closeHandler();
|
||||
}
|
||||
itemClickHandler(item) {
|
||||
this.props.itemClickHandler(item);
|
||||
}
|
||||
itemRemoveBtnClickHandler(item, e) {
|
||||
e.stopPropagation();
|
||||
this.props.itemRemoveBtnClickHandler(item);
|
||||
}
|
||||
itemForkBtnClickHandler(item, e) {
|
||||
e.stopPropagation();
|
||||
this.props.itemForkBtnClickHandler(item);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
@ -60,17 +71,20 @@ export default class SavedItemPane extends Component {
|
||||
<div
|
||||
class="js-saved-item-tile saved-item-tile"
|
||||
data-item-id={item.id}
|
||||
onClick={this.itemClickHandler.bind(this, item)}
|
||||
>
|
||||
<div class="saved-item-tile__btns">
|
||||
<a
|
||||
class="js-saved-item-tile__fork-btn saved-item-tile__btn hint--left hint--medium"
|
||||
aria-label="Creates a duplicate of this creation (Ctrl/⌘ + F)"
|
||||
onClick={this.itemForkBtnClickHandler.bind(this, item)}
|
||||
>
|
||||
Fork<span class="show-when-selected">(Ctrl/⌘ + F)</span>
|
||||
</a>
|
||||
<a
|
||||
class="js-saved-item-tile__remove-btn saved-item-tile__btn hint--left"
|
||||
aria-label="Remove"
|
||||
onClick={this.itemRemoveBtnClickHandler.bind(this, item)}
|
||||
>
|
||||
X
|
||||
</a>
|
||||
|
@ -21,6 +21,7 @@ import { alertsService } from '../notifications';
|
||||
import firebase from 'firebase/app';
|
||||
import 'firebase/auth';
|
||||
import Profile from './Profile';
|
||||
import { auth } from '../auth';
|
||||
|
||||
if (module.hot) {
|
||||
require('preact/debug');
|
||||
@ -30,6 +31,7 @@ const LocalStorageKeys = {
|
||||
LOGIN_AND_SAVE_MESSAGE_SEEN: 'loginAndsaveMessageSeen',
|
||||
ASKED_TO_IMPORT_CREATIONS: 'askedToImportCreations'
|
||||
};
|
||||
const UNSAVED_WARNING_COUNT = 15;
|
||||
|
||||
export default class App extends Component {
|
||||
constructor() {
|
||||
@ -71,7 +73,8 @@ export default class App extends Component {
|
||||
preserveConsoleLogs: true,
|
||||
lightVersion: false,
|
||||
lineWrap: true,
|
||||
infiniteLoopTimeout: 1000
|
||||
infiniteLoopTimeout: 1000,
|
||||
layoutMode: 2
|
||||
};
|
||||
this.prefs = {};
|
||||
|
||||
@ -131,7 +134,7 @@ export default class App extends Component {
|
||||
},
|
||||
result => {
|
||||
// this.toggleLayout(result.layoutMode);
|
||||
this.prefs.layoutMode = result.layoutMode;
|
||||
this.state.prefs.layoutMode = result.layoutMode;
|
||||
if (result.code) {
|
||||
lastCode = result.code;
|
||||
}
|
||||
@ -174,7 +177,31 @@ export default class App extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
refreshEditor() {}
|
||||
refreshEditor() {
|
||||
this.toggleLayout(
|
||||
this.state.currentItem.layoutMode || this.state.prefs.layoutMode
|
||||
);
|
||||
// this.contentWrap.refreshEditor();
|
||||
}
|
||||
// Creates a new item with passed item's contents
|
||||
forkItem(sourceItem) {
|
||||
if (this.state.unsavedEditCount) {
|
||||
var shouldDiscard = confirm(
|
||||
'You have unsaved changes in your current work. Do you want to discard unsaved changes and continue?'
|
||||
);
|
||||
if (!shouldDiscard) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const fork = JSON.parse(JSON.stringify(sourceItem));
|
||||
delete fork.id;
|
||||
fork.title = '(Forked) ' + sourceItem.title;
|
||||
fork.updatedOn = Date.now();
|
||||
this.setCurrentItem(fork);
|
||||
this.refreshEditor();
|
||||
alertsService.add(`"${sourceItem.title}" was forked`);
|
||||
trackEvent('fn', 'itemForked');
|
||||
}
|
||||
createNewItem() {
|
||||
var d = new Date();
|
||||
this.setCurrentItem({
|
||||
@ -196,8 +223,43 @@ export default class App extends Component {
|
||||
this.refreshEditor();
|
||||
alertsService.add('New item created');
|
||||
}
|
||||
openItem(item) {
|
||||
// console.log(itemId, this.state.savedItems)
|
||||
|
||||
this.setCurrentItem(item);
|
||||
this.refreshEditor();
|
||||
alertsService.add('Saved item loaded');
|
||||
}
|
||||
removeItem(itemId) {
|
||||
var answer = confirm(
|
||||
`Are you sure you want to delete "${savedItems[itemId].title}"?`
|
||||
);
|
||||
if (!answer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove from items list
|
||||
itemService.unsetItemForUser(itemId);
|
||||
|
||||
// Remove individual item too.
|
||||
itemService.removeItem(itemId).then(() => {
|
||||
alertsService.add('Item removed.');
|
||||
// This item is open in the editor. Lets open a new one.
|
||||
if (this.state.currentItem.id === itemId) {
|
||||
this.createNewItem();
|
||||
}
|
||||
});
|
||||
|
||||
// Remove from cached list
|
||||
delete this.state.savedItems[itemId];
|
||||
this.setState({
|
||||
savedItems: { ...this.state.savedItems }
|
||||
});
|
||||
|
||||
trackEvent('fn', 'itemRemoved');
|
||||
}
|
||||
setCurrentItem(item) {
|
||||
this.state.currentItem = item;
|
||||
this.setState({ currentItem: item });
|
||||
log('Current Item set', item);
|
||||
|
||||
// Reset auto-saving flag
|
||||
@ -373,8 +435,8 @@ export default class App extends Component {
|
||||
d.getSeconds()
|
||||
].join('-');
|
||||
|
||||
if (currentItem.title) {
|
||||
fileName = currentItem.title;
|
||||
if (this.state.currentItem.title) {
|
||||
fileName = this.state.currentItem.title;
|
||||
}
|
||||
fileName += '.html';
|
||||
|
||||
@ -440,8 +502,8 @@ export default class App extends Component {
|
||||
}
|
||||
|
||||
layoutBtnClickHandler(layoutId) {
|
||||
// saveSetting('layoutMode', mode);
|
||||
trackEvent('ui', 'toggleLayoutClick', mode);
|
||||
this.saveSetting('layoutMode', layoutId);
|
||||
trackEvent('ui', 'toggleLayoutClick', layoutId);
|
||||
this.toggleLayout(layoutId);
|
||||
}
|
||||
saveSetting(setting, value) {
|
||||
@ -454,8 +516,6 @@ export default class App extends Component {
|
||||
}
|
||||
|
||||
saveCode(key) {
|
||||
this.state.currentItem.title = window.titleInput.value;
|
||||
|
||||
// currentItem.htmlMode = htmlMode;
|
||||
// currentItem.cssMode = cssMode;
|
||||
// currentItem.jsMode = jsMode;
|
||||
@ -466,10 +526,6 @@ export default class App extends Component {
|
||||
}
|
||||
this.state.currentItem.updatedOn = Date.now();
|
||||
this.state.currentItem.layoutMode = this.state.currentLayoutMode;
|
||||
// this.state.currentItem.externalLibs = {
|
||||
// js: externalJsTextarea.value,
|
||||
// css: externalCssTextarea.value
|
||||
// };
|
||||
|
||||
// currentItem.sizes = getCodePaneSizes();
|
||||
// currentItem.mainSizes = getMainPaneSizes();
|
||||
@ -537,11 +593,28 @@ export default class App extends Component {
|
||||
itemService.setItemForUser(this.state.currentItem.id);
|
||||
}
|
||||
}
|
||||
onCodeChange(type, code) {
|
||||
onCodeChange(type, code, isUserChange) {
|
||||
this.state.currentItem[type] = code;
|
||||
if (isUserChange) {
|
||||
this.setState({ unsavedEditCount: this.state.unsavedEditCount + 1 });
|
||||
|
||||
if (
|
||||
this.state.unsavedEditCount % UNSAVED_WARNING_COUNT === 0 &&
|
||||
this.state.unsavedEditCount >= UNSAVED_WARNING_COUNT
|
||||
) {
|
||||
window.saveBtn.classList.add('animated');
|
||||
window.saveBtn.classList.add('wobble');
|
||||
window.saveBtn.addEventListener('animationend', () => {
|
||||
window.saveBtn.classList.remove('animated');
|
||||
window.saveBtn.classList.remove('wobble');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
titleInputBlurHandler() {
|
||||
titleInputBlurHandler(e) {
|
||||
this.state.currentItem.title = e.target.value;
|
||||
|
||||
if (this.state.currentItem.id) {
|
||||
this.saveItem();
|
||||
trackEvent('ui', 'titleChanged');
|
||||
@ -622,9 +695,8 @@ export default class App extends Component {
|
||||
this.setState({ isProfileModalOpen: true });
|
||||
}
|
||||
|
||||
logout(e) {
|
||||
e.preventDefault();
|
||||
if (unsavedEditCount) {
|
||||
logout() {
|
||||
if (this.state.unsavedEditCount) {
|
||||
var shouldDiscard = confirm(
|
||||
'You have unsaved changes. Do you still want to logout?'
|
||||
);
|
||||
@ -633,7 +705,36 @@ export default class App extends Component {
|
||||
}
|
||||
}
|
||||
trackEvent('fn', 'loggedOut');
|
||||
window.logout();
|
||||
auth.logout();
|
||||
}
|
||||
|
||||
itemClickHandler(item) {
|
||||
setTimeout(() => {
|
||||
this.openItem(item);
|
||||
}, 350);
|
||||
this.toggleSavedItemsPane();
|
||||
}
|
||||
itemRemoveBtnClickHandler(itemId) {
|
||||
this.removeItem(itemId);
|
||||
}
|
||||
itemForkBtnClickHandler(item) {
|
||||
this.toggleSavedItemsPane();
|
||||
setTimeout(() => {
|
||||
this.forkItem(item);
|
||||
}, 350);
|
||||
}
|
||||
newBtnClickHandler() {
|
||||
trackEvent('ui', 'newBtnClick');
|
||||
if (this.state.unsavedEditCount) {
|
||||
var shouldDiscard = confirm(
|
||||
'You have unsaved changes. Do you still want to create something new?'
|
||||
);
|
||||
if (shouldDiscard) {
|
||||
this.createNewItem();
|
||||
}
|
||||
} else {
|
||||
this.createNewItem();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -643,19 +744,24 @@ export default class App extends Component {
|
||||
<MainHeader
|
||||
externalLibCount={this.state.externalLibCount}
|
||||
openBtnHandler={this.openSavedItemsPane.bind(this)}
|
||||
newBtnHandler={this.newBtnClickHandler.bind(this)}
|
||||
saveBtnHandler={this.saveBtnClickHandler.bind(this)}
|
||||
loginBtnHandler={this.loginBtnClickHandler.bind(this)}
|
||||
profileBtnHandler={this.profileBtnClickHandler.bind(this)}
|
||||
addLibraryBtnHandler={this.openAddLibrary.bind(this)}
|
||||
isFetchingItems={this.state.isFetchingItems}
|
||||
isSaving={this.state.isSaving}
|
||||
title={this.state.currentItem.title}
|
||||
titleInputBlurHandler={this.titleInputBlurHandler.bind(this)}
|
||||
user={this.state.user}
|
||||
unsavedEditCount={this.state.unsavedEditCount}
|
||||
/>
|
||||
<ContentWrap
|
||||
currentLayoutMode={this.state.currentLayoutMode}
|
||||
currentItem={this.state.currentItem}
|
||||
onCodeChange={this.onCodeChange.bind(this)}
|
||||
onRef={comp => (this.contentWrap = comp)}
|
||||
prefs={this.state.prefs}
|
||||
/>
|
||||
<div class="global-console-container" id="globalConsoleContainerEl" />
|
||||
<Footer
|
||||
@ -674,6 +780,9 @@ export default class App extends Component {
|
||||
items={this.state.savedItems}
|
||||
isOpen={this.state.isSavedItemPaneOpen}
|
||||
closeHandler={this.closeSavedItemsPane.bind(this)}
|
||||
itemClickHandler={this.itemClickHandler.bind(this)}
|
||||
itemRemoveBtnClickHandler={this.itemRemoveBtnClickHandler.bind(this)}
|
||||
itemForkBtnClickHandler={this.itemForkBtnClickHandler.bind(this)}
|
||||
/>
|
||||
<div class="alerts-container" id="js-alerts-container" />
|
||||
<form
|
||||
@ -735,7 +844,10 @@ export default class App extends Component {
|
||||
show={this.state.isProfileModalOpen}
|
||||
closeHandler={() => this.setState({ isProfileModalOpen: false })}
|
||||
>
|
||||
<Profile user={this.state.user} />
|
||||
<Profile
|
||||
user={this.state.user}
|
||||
logoutBtnHandler={this.logout.bind(this)}
|
||||
/>
|
||||
</Modal>
|
||||
<HelpModal
|
||||
show={this.state.isHelpModalOpen}
|
||||
|
Loading…
x
Reference in New Issue
Block a user