mirror of
				https://github.com/mickael-kerjean/filestash.git
				synced 2025-11-04 13:35:46 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			209 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			209 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* eslint-disable react/jsx-no-target-blank */
 | 
						|
import React from "react";
 | 
						|
import ReactCSSTransitionGroup from "react-addons-css-transition-group";
 | 
						|
import { withRouter } from "react-router";
 | 
						|
import { Subject } from "rxjs/Subject";
 | 
						|
 | 
						|
import {
 | 
						|
    NgIf, Fab, Icon, Dropdown, DropdownButton, DropdownList, DropdownItem,
 | 
						|
} from "../../components/";
 | 
						|
import { confirm, currentShare } from "../../helpers/";
 | 
						|
import { Editor } from "./editor";
 | 
						|
import { MenuBar } from "./menubar";
 | 
						|
import { OrgTodosViewer, OrgEventsViewer } from "./org_viewer";
 | 
						|
import { t } from "../../locales/";
 | 
						|
 | 
						|
import "./ide.scss";
 | 
						|
 | 
						|
class IDEComponent extends React.Component {
 | 
						|
    constructor(props) {
 | 
						|
        super(props);
 | 
						|
        this.state = {
 | 
						|
            event: new Subject(),
 | 
						|
            contentToSave: props.content,
 | 
						|
            appear_agenda: false,
 | 
						|
            appear_todo: false,
 | 
						|
            mode: null,
 | 
						|
            folding: null,
 | 
						|
        };
 | 
						|
    }
 | 
						|
 | 
						|
    componentDidMount() {
 | 
						|
        this.unblock = this.props.history.block((nextLocation)=> {
 | 
						|
            if (this.props.needSaving === false) return true;
 | 
						|
            confirm.now(
 | 
						|
                <div style={{ textAlign: "center", paddingBottom: "5px" }}>
 | 
						|
                    { t("Do you want to save the changes ?") }
 | 
						|
                </div>,
 | 
						|
                () =>{
 | 
						|
                    return this.save()
 | 
						|
                        .then(() => this.props.history.push(nextLocation));
 | 
						|
                },
 | 
						|
                () => {
 | 
						|
                    this.props.needSavingUpdate(false)
 | 
						|
                        .then(() => this.props.history.push(nextLocation));
 | 
						|
                },
 | 
						|
            );
 | 
						|
            return false;
 | 
						|
        });
 | 
						|
    }
 | 
						|
    componentWillUnmount() {
 | 
						|
        this.unblock();
 | 
						|
        window.clearInterval(this.state.id);
 | 
						|
    }
 | 
						|
 | 
						|
    save() {
 | 
						|
        if (this.props.needSaving === false) return;
 | 
						|
        // the ipad is the new IE, they don't support the file object so we got to fallback :(
 | 
						|
        return this.props.onSave(
 | 
						|
            new window.Blob(
 | 
						|
                [this.state.contentToSave],
 | 
						|
                { type: "text/plain" },
 | 
						|
            ),
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    onUpdate(property, refresh, value) {
 | 
						|
        this.setState({ [property]: value }, () => {
 | 
						|
            if (refresh) {
 | 
						|
                this.state.event.next(["refresh"]);
 | 
						|
            }
 | 
						|
            if (this.props.content === this.state.contentToSave) {
 | 
						|
                this.props.needSavingUpdate(false);
 | 
						|
            } else {
 | 
						|
                this.props.needSavingUpdate(true);
 | 
						|
            }
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    /* Org Viewer specific stuff */
 | 
						|
    toggleAgenda(force = null) {
 | 
						|
        this.setState({
 | 
						|
            appear_agenda: force === null ? !this.state.appear_agenda : !!force,
 | 
						|
        });
 | 
						|
    }
 | 
						|
    toggleTodo(force = null) {
 | 
						|
        this.setState({
 | 
						|
            appear_todo: force === null ? !this.state.appear_todo : !!force,
 | 
						|
        });
 | 
						|
    }
 | 
						|
    onModeChange() {
 | 
						|
        this.state.event.next(["fold"]);
 | 
						|
    }
 | 
						|
    goTo(lineNumber) {
 | 
						|
        this.state.event.next(["goTo", lineNumber]);
 | 
						|
    }
 | 
						|
 | 
						|
    download() {
 | 
						|
        document.cookie = "download=yes; path=/; max-age=120;";
 | 
						|
        this.setState({
 | 
						|
            refresh: Date.now(),
 | 
						|
            id: window.setInterval(() => {
 | 
						|
                if (/download=yes/.test(document.cookie) === false) {
 | 
						|
                    window.clearInterval(this.state.id);
 | 
						|
                    this.setState({ refresh: Date.now() });
 | 
						|
                }
 | 
						|
            }, 100),
 | 
						|
        });
 | 
						|
    }
 | 
						|
 | 
						|
    render() {
 | 
						|
        const changeExt = function(filename, ext) {
 | 
						|
            return filename.replace(/\.org$/, "."+ext);
 | 
						|
        };
 | 
						|
 | 
						|
        return (
 | 
						|
            <div className="component_ide">
 | 
						|
                <MenuBar
 | 
						|
                    title={this.props.filename}
 | 
						|
                    download={this.state.mode === "orgmode" ? null : this.props.url}>
 | 
						|
                    <NgIf type="inline" cond={this.state.mode === "orgmode"}>
 | 
						|
                        <span onClick={this.onModeChange.bind(this)}>
 | 
						|
                            <NgIf cond={this.state.folding === "SHOW_ALL"} type="inline">
 | 
						|
                                <Icon name="arrow_up_double"/>
 | 
						|
                            </NgIf>
 | 
						|
                            <NgIf cond={this.state.folding === "OVERVIEW"} type="inline">
 | 
						|
                                <Icon name="arrow_down"/>
 | 
						|
                            </NgIf>
 | 
						|
                            <NgIf cond={this.state.folding === "CONTENT"} type="inline">
 | 
						|
                                <Icon name="arrow_down_double"/>
 | 
						|
                            </NgIf>
 | 
						|
                        </span>
 | 
						|
                        <Dropdown
 | 
						|
                            className="view sort"
 | 
						|
                            onChange={() => this.download()}
 | 
						|
                            enable={/download=yes/.test(document.cookie) ? false : true}>
 | 
						|
                            <DropdownButton>
 | 
						|
                                <Icon name={/download=yes/.test(document.cookie) ? "loading_white" : "download_white"} />
 | 
						|
                            </DropdownButton>
 | 
						|
                            <DropdownList>
 | 
						|
                                <DropdownItem name="na"><a download={this.props.filename} href={this.props.url}>{ t("Save current file") }</a></DropdownItem>
 | 
						|
                                <DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/text/html"+this.props.path}>{ t("Export as {{VALUE}}", "HTML") }</a></DropdownItem>
 | 
						|
                                <DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/application/pdf"+this.props.path}>{ t("Export as {{VALUE}}", "PDF") }</a></DropdownItem>
 | 
						|
                                <DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/text/markdown"+this.props.path}>{ t("Export as {{VALUE}}", "Markdown") }</a></DropdownItem>
 | 
						|
                                <DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/text/plain"+this.props.path}>{ t("Export as {{VALUE}}", "TXT") }</a></DropdownItem>
 | 
						|
                                <DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "tex")} href={"/api/export/"+(currentShare() || "private")+"/text/x-latex"+this.props.path}>{ t("Export as {{VALUE}}", "Latex") }</a></DropdownItem>
 | 
						|
                                <DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "ics")} href={"/api/export/"+(currentShare() || "private")+"/text/calendar"+this.props.path}>{ t("Export as {{VALUE}}", "ical") }</a></DropdownItem>
 | 
						|
                                <DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "odt")} href={"/api/export/"+(currentShare() || "private")+"/application/vnd.oasis.opendocument.text"+this.props.path}>{ t("Export as {{VALUE}}", "Open office") }</a></DropdownItem>
 | 
						|
                                <DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "pdf")} href={"/api/export/"+(currentShare() || "private")+"/application/pdf"+this.props.path+"?mode=beamer"}>{ t("Export as {{VALUE}}", "Beamer") }</a></DropdownItem>
 | 
						|
                            </DropdownList>
 | 
						|
                        </Dropdown>
 | 
						|
 | 
						|
                        <span onClick={this.toggleAgenda.bind(this)}>
 | 
						|
                            <Icon name="calendar_white"/>
 | 
						|
                        </span>
 | 
						|
                        <span onClick={this.toggleTodo.bind(this)}>
 | 
						|
                            <Icon name="todo_white"/>
 | 
						|
                        </span>
 | 
						|
                    </NgIf>
 | 
						|
                </MenuBar>
 | 
						|
 | 
						|
                <ReactCSSTransitionGroup
 | 
						|
                    transitionName="editor" transitionAppear={true} transitionEnter={false}
 | 
						|
                    transitionLeave={false} transitionAppearTimeout={300}
 | 
						|
                    className="editor_container">
 | 
						|
                    <Editor
 | 
						|
                        onSave={this.save.bind(this)} filename={this.props.filename}
 | 
						|
                        content={this.state.contentToSave}
 | 
						|
                        readonly={/PUT/.test(this.props.acl)}
 | 
						|
                        event={this.state.event.asObservable()}
 | 
						|
                        onModeChange={this.onUpdate.bind(this, "mode", false)}
 | 
						|
                        onFoldChange={this.onUpdate.bind(this, "folding", false)}
 | 
						|
                        onChange={this.onUpdate.bind(this, "contentToSave", false)} />
 | 
						|
                </ReactCSSTransitionGroup>
 | 
						|
 | 
						|
                <ReactCSSTransitionGroup
 | 
						|
                    transitionName="fab" transitionLeave={true} transitionEnter={true}
 | 
						|
                    transitionAppear={true} transitionAppearTimeout={400}
 | 
						|
                    transitionEnterTimeout={400} transitionLeaveTimeout={200}>
 | 
						|
                    <NgIf cond={!!this.props.needSaving || !!this.props.isSaving}>
 | 
						|
                        <NgIf cond={!this.props.isSaving}>
 | 
						|
                            <Fab onClick={this.save.bind(this)}>
 | 
						|
                                <Icon name="save" style={{ height: "100%", width: "100%" }} />
 | 
						|
                            </Fab>
 | 
						|
                        </NgIf>
 | 
						|
                        <NgIf cond={this.props.isSaving}>
 | 
						|
                            <Fab>
 | 
						|
                                <Icon name="loading" style={{ height: "100%", width: "100%" }} />
 | 
						|
                            </Fab>
 | 
						|
                        </NgIf>
 | 
						|
                    </NgIf>
 | 
						|
                </ReactCSSTransitionGroup>
 | 
						|
 | 
						|
                <OrgEventsViewer
 | 
						|
                    isActive={this.state.appear_agenda} content={this.state.contentToSave}
 | 
						|
                    onUpdate={this.onUpdate.bind(this, "contentToSave", true)}
 | 
						|
                    goTo={this.goTo.bind(this)}
 | 
						|
                    onQuit={this.toggleAgenda.bind(this, false)} />
 | 
						|
                <OrgTodosViewer
 | 
						|
                    isActive={this.state.appear_todo} content={this.state.contentToSave}
 | 
						|
                    onUpdate={this.onUpdate.bind(this, "contentToSave", true)}
 | 
						|
                    goTo={this.goTo.bind(this)}
 | 
						|
                    onQuit={this.toggleTodo.bind(this, false)} />
 | 
						|
            </div>
 | 
						|
        );
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
export const IDE = withRouter(IDEComponent);
 |