Yuki Takei 7 лет назад
Родитель
Сommit
0e9bafe5e9
5 измененных файлов с 87 добавлено и 22 удалено
  1. 1 4
      lib/models/page.js
  2. 7 0
      lib/routes/hackmd.js
  3. 0 4
      lib/routes/page.js
  4. 11 4
      resource/js/app.js
  5. 68 10
      resource/js/components/PageStatusAlert.jsx

+ 1 - 4
lib/models/page.js

@@ -1348,10 +1348,7 @@ module.exports = function(crowi) {
     }
 
     pageData.hasDraftOnHackmd = newValue;
-    let savedPage = pageData.save();
-
-    pageEvent.emit('updateHasDraftOnHackmd', pageData);
-    return savedPage;
+    return pageData.save();
   };
 
   pageSchema.statics.getHistories = function() {

+ 7 - 0
lib/routes/hackmd.js

@@ -9,6 +9,7 @@ const ApiResponse = require('../util/apiResponse');
 module.exports = function(crowi, app) {
   const config = crowi.getConfig();
   const Page = crowi.models.Page;
+  const pageEvent = crowi.event('page');
 
   // load GROWI agent script for HackMD
   const manifest = require(path.join(crowi.publicDir, 'manifest.json'));
@@ -18,6 +19,10 @@ module.exports = function(crowi, app) {
   let agentScriptContentTpl = undefined;
   let stylesScriptContentTpl = undefined;
 
+  // init 'saveOnHackmd' event
+  pageEvent.on('saveOnHackmd', function(page) {
+    crowi.getIo().sockets.emit('page:editingWithHackmd', {page});
+  });
 
   /**
    * GET /_hackmd/load-agent
@@ -170,6 +175,8 @@ module.exports = function(crowi, app) {
   const saveOnHackmd = async function(req, res) {
     const page = req.page;
 
+    pageEvent.emit('saveOnHackmd', page);
+
     try {
       await Page.updateHasDraftOnHackmd(page, true);
       return res.json(ApiResponse.success());

+ 0 - 4
lib/routes/page.js

@@ -26,10 +26,6 @@ module.exports = function(crowi, app) {
   pageEvent.on('update', function(page, user) {
     crowi.getIo().sockets.emit('page:update', {page, user});
   });
-  pageEvent.on('updateHasDraftOnHackmd', function(page) {
-    crowi.getIo().sockets.emit('page:updateHasDraftOnHackmd', {page});
-  });
-
 
   function getPathFromRequest(req) {
     const path = '/' + (req.params[0] || '');

+ 11 - 4
resource/js/app.js

@@ -387,7 +387,7 @@ if (pageStatusAlertElem) {
               pageStatusAlert = elem.getWrappedInstance();
             }
           }}
-          revisionId={pageRevisionId} />
+          revisionId={pageRevisionId} hasDraftOnHackmd={hasDraftOnHackmd} />
     </I18nextProvider>,
     pageStatusAlertElem
   );
@@ -429,7 +429,10 @@ if (customHeaderEditorElem != null) {
 // notification from websocket
 const socket = io();
 socket.on('page:update', function(data) {
-  console.log(data);
+  // skip own trigger
+  if (data.user.username === crowi.me) {
+    return;
+  }
   if (data.page.path == pagePath) {
     // update PageStatusAlert
     const pageStatusAlert = componentInstances.pageStatusAlert;
@@ -444,9 +447,13 @@ socket.on('page:update', function(data) {
     }
   }
 });
-socket.on('page:updateHasDraftOnHackmd', function(data) {
-  console.log(data);
+socket.on('page:editingWithHackmd', function(data) {
   if (data.page.path == pagePath) {
+    // update PageStatusAlert
+    const pageStatusAlert = componentInstances.pageStatusAlert;
+    if (pageStatusAlert != null) {
+      pageStatusAlert.setHasDraftOnHackmd(data.page.hasDraftOnHackmd);
+    }
     // update PageEditorByHackmd
     const pageEditorByHackmd = componentInstances.pageEditorByHackmd;
     if (pageEditorByHackmd != null) {

+ 68 - 10
resource/js/components/PageStatusAlert.jsx

@@ -20,7 +20,13 @@ class PageStatusAlert extends React.Component {
       revisionId: this.props.revisionId,
       latestRevisionId: this.props.revisionId,
       lastUpdateUsername: undefined,
+      hasDraftOnHackmd: this.props.hasDraftOnHackmd,
+      isDraftUpdatingInRealtime: false,
     };
+
+    this.renderSomeoneEditingAlert = this.renderSomeoneEditingAlert.bind(this);
+    this.renderDraftExistsAlert = this.renderDraftExistsAlert.bind(this);
+    this.renderUpdatedAlert = this.renderUpdatedAlert.bind(this);
   }
 
   initRevisionId(revisionId) {
@@ -38,32 +44,84 @@ class PageStatusAlert extends React.Component {
     this.setState({lastUpdateUsername});
   }
 
-  render() {
+  setHasDraftOnHackmd(hasDraftOnHackmd) {
+    this.setState({
+      hasDraftOnHackmd,
+      isDraftUpdatingInRealtime: true,
+    });
+  }
+
+  renderSomeoneEditingAlert() {
+    return (
+      <div className="myadmin-alert alert-success myadmin-alert-bottom alertbottom2" style={{display: 'block'}}>
+        <i className="icon-fw icon-people"></i>
+        Someone editing this page on HackMD
+        &nbsp;
+        <i className="fa fa-angle-double-right"></i>
+        &nbsp;
+        <a href="">
+          Open HackMD Editor
+        </a>
+      </div>
+    );
+  }
+
+  renderDraftExistsAlert(isRealtime) {
+    return (
+      <div className="myadmin-alert alert-success myadmin-alert-bottom alertbottom2" style={{display: 'block'}}>
+        <i className="icon-fw icon-pencil"></i>
+        This page has a draft on HackMD
+        &nbsp;
+        <i className="fa fa-angle-double-right"></i>
+        &nbsp;
+        <a href="">
+          Open HackMD Editor
+        </a>
+      </div>
+    );
+  }
+
+  renderUpdatedAlert() {
     const { t } = this.props;
     const label1 = t('edited this page');
     const label2 = t('Load latest');
 
-    const isShown = this.state.revisionId !== this.state.latestRevisionId;
-    const style = {
-      display: isShown ? 'block' : 'none'
-    };
-
     return (
-      <div className="myadmin-alert alert-warning myadmin-alert-bottom alertbottom2" style={style}>
+      <div className="myadmin-alert alert-warning myadmin-alert-bottom alertbottom2" style={{display: 'block'}}>
         <i className="icon-fw icon-bulb"></i>
-        <span>{this.state.lastUpdateUsername}</span> {label1}&nbsp;
+        {this.state.lastUpdateUsername} {label1}
+        &nbsp;
+        <i className="fa fa-angle-double-right"></i>
+        &nbsp;
         <a href="javascript:location.reload();">
-          <i className="fa fa-angle-double-right"></i> {label2}
+          {label2}
         </a>
       </div>
     );
   }
+
+  render() {
+    let content = <React.Fragment></React.Fragment>;
+
+    if (this.state.isDraftUpdatingInRealtime) {
+      content = this.renderSomeoneEditingAlert();
+    }
+    else if (this.state.hasDraftOnHackmd) {
+      content = this.renderDraftExistsAlert();
+    }
+    else if (this.state.revisionId !== this.state.latestRevisionId) {
+      content = this.renderUpdatedAlert();
+    }
+
+    return content;
+  }
 }
 
 PageStatusAlert.propTypes = {
   t: PropTypes.func.isRequired,               // i18next
   crowi: PropTypes.object.isRequired,
-  revisionId: PropTypes.string,
+  revisionId: PropTypes.string.isRequired,
+  hasDraftOnHackmd: PropTypes.bool.isRequired,
   latestRevisionId: PropTypes.string,
 };