Yuki Takei 7 лет назад
Родитель
Сommit
fc6e435251
78 измененных файлов с 1044 добавлено и 1333 удалено
  1. 86 115
      src/client/js/app.js
  2. 7 6
      src/client/js/components/Admin/CustomCssEditor.js
  3. 7 6
      src/client/js/components/Admin/CustomHeaderEditor.js
  4. 7 6
      src/client/js/components/Admin/CustomScriptEditor.js
  5. 2 0
      src/client/js/components/Common/UserDate.js
  6. 7 14
      src/client/js/components/CopyButton.js
  7. 3 3
      src/client/js/components/Page/PagePath.js
  8. 5 5
      src/client/js/components/Page/RevisionBody.js
  9. 21 23
      src/client/js/components/Page/RevisionPath.js
  10. 5 9
      src/client/js/components/Page/RevisionUrl.js
  11. 11 11
      src/client/js/components/PageAttachment.js
  12. 6 12
      src/client/js/components/PageAttachment/Attachment.js
  13. 7 15
      src/client/js/components/PageAttachment/DeleteAttachmentModal.js
  14. 7 5
      src/client/js/components/PageAttachment/PageAttachmentList.js
  15. 22 23
      src/client/js/components/PageComment/Comment.js
  16. 5 6
      src/client/js/components/PageComment/CommentPreview.js
  17. 9 15
      src/client/js/components/PageComment/DeleteCommentModal.js
  18. 30 38
      src/client/js/components/PageComments.js
  19. 25 30
      src/client/js/components/PageEditor.js
  20. 2 0
      src/client/js/components/PageEditor/AbstractEditor.js
  21. 25 123
      src/client/js/components/PageEditor/Cheatsheet.js
  22. 110 171
      src/client/js/components/PageEditor/CodeMirrorEditor.js
  23. 14 10
      src/client/js/components/PageEditor/EmojiAutoCompleteHelper.js
  24. 4 1
      src/client/js/components/PageEditor/MarkdownListUtil.js
  25. 3 2
      src/client/js/components/PageEditor/MarkdownTableInterceptor.js
  26. 8 7
      src/client/js/components/PageEditor/MarkdownTableUtil.js
  27. 31 47
      src/client/js/components/PageEditor/OptionsSelector.js
  28. 1 1
      src/client/js/components/PageEditor/PasteHelper.js
  29. 3 2
      src/client/js/components/PageEditor/PreventMarkdownListInterceptor.js
  30. 6 7
      src/client/js/components/PageEditor/Preview.js
  31. 9 8
      src/client/js/components/PageEditor/ScrollSyncHelper.js
  32. 13 52
      src/client/js/components/PageEditor/SimpleCheatsheet.js
  33. 18 19
      src/client/js/components/PageEditor/TextAreaEditor.js
  34. 19 18
      src/client/js/components/PageHistory.js
  35. 7 9
      src/client/js/components/PageHistory/RevisionDiff.js
  36. 3 2
      src/client/js/components/PageList/ListView.js
  37. 4 2
      src/client/js/components/PageList/Page.js
  38. 4 12
      src/client/js/components/PageList/PageListMeta.js
  39. 6 8
      src/client/js/components/PageList/PagePath.js
  40. 8 5
      src/client/js/components/ReactUtils.js
  41. 8 22
      src/client/js/components/SearchForm.js
  42. 17 21
      src/client/js/components/SearchPage.js
  43. 7 8
      src/client/js/components/SearchPage/DeletePageListModal.js
  44. 20 22
      src/client/js/components/SearchPage/SearchPageForm.js
  45. 58 88
      src/client/js/components/SearchPage/SearchResult.js
  46. 3 2
      src/client/js/components/SearchPage/SearchResultList.js
  47. 17 14
      src/client/js/components/SearchTypeahead.js
  48. 6 16
      src/client/js/components/User/User.js
  49. 9 7
      src/client/js/components/User/UserPicture.js
  50. 9 7
      src/client/js/hackmd-agent.js
  51. 1 1
      src/client/js/hackmd-styles.js
  52. 2 2
      src/client/js/i18n.js
  53. 1 1
      src/client/js/installer.js
  54. 17 14
      src/client/js/legacy/crowi-admin.js
  55. 3 3
      src/client/js/legacy/crowi-presentation.js
  56. 13 12
      src/client/js/models/MarkdownTable.js
  57. 4 1
      src/client/js/plugin.js
  58. 21 18
      src/client/js/util/Crowi.js
  59. 11 10
      src/client/js/util/GrowiRenderer.js
  60. 1 0
      src/client/js/util/PreProcessor/CsvToTable.js
  61. 3 1
      src/client/js/util/PreProcessor/Linker.js
  62. 5 2
      src/client/js/util/PreProcessor/XssFilter.js
  63. 3 1
      src/client/js/util/codemirror/update-display-util.ext.js
  64. 10 8
      src/client/js/util/interceptor/detach-code-blocks.js
  65. 1 0
      src/client/js/util/markdown-it/blockdiag.js
  66. 4 2
      src/client/js/util/markdown-it/emoji.js
  67. 2 0
      src/client/js/util/markdown-it/footernote.js
  68. 4 2
      src/client/js/util/markdown-it/header-line-number.js
  69. 1 0
      src/client/js/util/markdown-it/header-with-edit-link.js
  70. 4 2
      src/client/js/util/markdown-it/header.js
  71. 3 1
      src/client/js/util/markdown-it/mathjax.js
  72. 1 0
      src/client/js/util/markdown-it/plantuml.js
  73. 2 1
      src/client/js/util/markdown-it/table-with-handsontable-button.js
  74. 2 0
      src/client/js/util/markdown-it/table.js
  75. 2 0
      src/client/js/util/markdown-it/task-lists.js
  76. 2 0
      src/client/js/util/markdown-it/toc-and-anchor.js
  77. 34 38
      src/client/js/util/reveal/plugins/growi-renderer.js
  78. 163 158
      src/client/js/util/reveal/plugins/markdown.js

+ 86 - 115
src/client/js/app.js

@@ -3,45 +3,43 @@ import ReactDOM from 'react-dom';
 import { I18nextProvider } from 'react-i18next';
 import * as toastr from 'toastr';
 
-import loggerFactory from '@alias/logger';
-import Xss from '@commons/service/xss';
-import * as entities from 'entities';
 import i18nFactory from './i18n';
 
+import loggerFactory from '@alias/logger';
+import Xss from '@commons/service/xss';
 
 import Crowi from './util/Crowi';
 // import CrowiRenderer from './util/CrowiRenderer';
 import GrowiRenderer from './util/GrowiRenderer';
 
-import HeaderSearchBox from './components/HeaderSearchBox';
-import SearchPage from './components/SearchPage';
-import PageEditor from './components/PageEditor';
-import OptionsSelector from './components/PageEditor/OptionsSelector'; // eslint-disable-line import/no-duplicates
-import { EditorOptions, PreviewOptions } from './components/PageEditor/OptionsSelector'; // eslint-disable-line import/no-duplicates
+import HeaderSearchBox  from './components/HeaderSearchBox';
+import SearchPage       from './components/SearchPage';
+import PageEditor       from './components/PageEditor';
+import OptionsSelector  from './components/PageEditor/OptionsSelector';
+import { EditorOptions, PreviewOptions } from './components/PageEditor/OptionsSelector';
 import SavePageControls from './components/SavePageControls';
 import PageEditorByHackmd from './components/PageEditorByHackmd';
-import Page from './components/Page';
-import PageHistory from './components/PageHistory';
-import PageComments from './components/PageComments';
+import Page             from './components/Page';
+import PageHistory      from './components/PageHistory';
+import PageComments     from './components/PageComments';
 import CommentForm from './components/PageComment/CommentForm';
-import PageAttachment from './components/PageAttachment';
-import PageStatusAlert from './components/PageStatusAlert';
-import RevisionPath from './components/Page/RevisionPath';
-// import PageTagForm from './components/PageTagForm';
-import RevisionUrl from './components/Page/RevisionUrl';
-import BookmarkButton from './components/BookmarkButton';
-import LikeButton from './components/LikeButton';
+import PageAttachment   from './components/PageAttachment';
+import PageStatusAlert  from './components/PageStatusAlert';
+import RevisionPath     from './components/Page/RevisionPath';
+import PageTagForm      from './components/PageTagForm';
+import RevisionUrl      from './components/Page/RevisionUrl';
+import BookmarkButton   from './components/BookmarkButton';
+import LikeButton       from './components/LikeButton';
 import PagePathAutoComplete from './components/PagePathAutoComplete';
 import RecentCreated from './components/RecentCreated/RecentCreated';
-import UserPictureList from './components/Common/UserPictureList';
+import UserPictureList  from './components/Common/UserPictureList';
 
-import CustomCssEditor from './components/Admin/CustomCssEditor';
+import CustomCssEditor  from './components/Admin/CustomCssEditor';
 import CustomScriptEditor from './components/Admin/CustomScriptEditor';
 import CustomHeaderEditor from './components/Admin/CustomHeaderEditor';
 import AdminRebuildSearch from './components/Admin/AdminRebuildSearch';
 
-/* global location */
-/* eslint no-restricted-globals: ['error', 'locaion'] */
+import * as entities from 'entities';
 
 const logger = loggerFactory('growi:app');
 
@@ -67,8 +65,8 @@ let pagePath;
 let pageContent = '';
 let markdown = '';
 let slackChannels;
-// const currentPageTags = '';
-const newPageTags = '';
+let currentPageTags = '';
+let newPageTags = '';
 if (mainContent !== null) {
   pageId = mainContent.getAttribute('data-page-id') || null;
   pageRevisionId = mainContent.getAttribute('data-page-revision-id');
@@ -102,8 +100,8 @@ const socketClientId = crowi.getSocketClientId();
 
 const crowiRenderer = new GrowiRenderer(crowi, null, {
   mode: 'page',
-  isAutoSetup: false, //                                      manually setup because plugins may configure it
-  renderToc: crowi.getCrowiForJquery().renderTocContent, //   function for rendering Table Of Contents
+  isAutoSetup: false,                                     // manually setup because plugins may configure it
+  renderToc: crowi.getCrowiForJquery().renderTocContent,  // function for rendering Table Of Contents
 });
 window.crowiRenderer = crowiRenderer;
 
@@ -118,14 +116,14 @@ if (isEnabledPlugins) {
  * get new tags from page tag form
  * @param {String} tags new tags [TODO] String -> Array
  */
-// const getNewPageTags = function(tags) {
-//   newPageTags = tags;
-// };
+const getNewPageTags = function(tags) {
+  newPageTags = tags;
+};
 
 /**
  * component store
  */
-const componentInstances = {};
+let componentInstances = {};
 
 /**
  * save success handler when reloading is not needed
@@ -209,7 +207,7 @@ const saveWithShortcut = function(markdown) {
     revisionId = componentInstances.pageEditorByHackmd.getRevisionIdHackmdSynced();
   }
 
-  let promise;
+  let promise = undefined;
   if (pageId == null) {
     promise = crowi.createPage(pagePath, markdown, options);
   }
@@ -243,7 +241,7 @@ const saveWithSubmitButton = function(submitOpts) {
   // set 'submitOpts.overwriteScopesOfDescendants' to options
   options.overwriteScopesOfDescendants = submitOpts ? !!submitOpts.overwriteScopesOfDescendants : false;
 
-  let promise;
+  let promise = undefined;
   if (editorMode === 'hackmd') {
     // get markdown
     promise = componentInstances.pageEditorByHackmd.getMarkdown();
@@ -258,12 +256,12 @@ const saveWithSubmitButton = function(submitOpts) {
   }
   // create or update
   if (pageId == null) {
-    promise = promise.then((markdown) => {
+    promise = promise.then(markdown => {
       return crowi.createPage(pagePath, markdown, options);
     });
   }
   else {
-    promise = promise.then((markdown) => {
+    promise = promise.then(markdown => {
       return crowi.updatePage(pageId, revisionId, markdown, options);
     });
   }
@@ -292,11 +290,11 @@ const componentMappings = {
   'search-sidebar': <HeaderSearchBox crowi={crowi} />,
   'search-page': <I18nextProvider i18n={i18n}><SearchPage crowi={crowi} crowiRenderer={crowiRenderer} /></I18nextProvider>,
 
-  // 'revision-history': <PageHistory pageId={pageId} />,
+  //'revision-history': <PageHistory pageId={pageId} />,
   'bookmark-button': <BookmarkButton pageId={pageId} crowi={crowi} />,
   'bookmark-button-lg': <BookmarkButton pageId={pageId} crowi={crowi} size="lg" />,
 
-  'create-page-name-input': <PagePathAutoComplete crowi={crowi} initializedPath={pagePath} addTrailingSlash />,
+  'create-page-name-input': <PagePathAutoComplete crowi={crowi} initializedPath={pagePath} addTrailingSlash={true} />,
   'rename-page-name-input': <PagePathAutoComplete crowi={crowi} initializedPath={pagePath} />,
   'duplicate-page-name-input': <PagePathAutoComplete crowi={crowi} initializedPath={pagePath} />,
 
@@ -307,7 +305,7 @@ if (pageId) {
   componentMappings['page-attachment'] = <PageAttachment pageId={pageId} markdown={markdown} crowi={crowi} />;
 }
 if (pagePath) {
-  componentMappings.page = <Page crowi={crowi} crowiRenderer={crowiRenderer} markdown={markdown} pagePath={pagePath} showHeadEditButton onSaveWithShortcut={saveWithShortcut} />;
+  componentMappings['page'] = <Page crowi={crowi} crowiRenderer={crowiRenderer} markdown={markdown} pagePath={pagePath} showHeadEditButton={true} onSaveWithShortcut={saveWithShortcut} />;
   componentMappings['revision-path'] = <RevisionPath pagePath={pagePath} crowi={crowi} />;
   // componentMappings['page-tag'] = <PageTagForm pageTags={currentPageTags} submitTags={getNewPageTags} />; [pagetag]
   componentMappings['revision-url'] = <RevisionUrl pageId={pageId} pagePath={pagePath} />;
@@ -321,8 +319,8 @@ Object.keys(componentMappings).forEach((key) => {
 });
 
 // set page if exists
-if (componentInstances.page != null) {
-  crowi.setPage(componentInstances.page);
+if (componentInstances['page'] != null) {
+  crowi.setPage(componentInstances['page']);
 }
 
 // render LikeButton
@@ -331,7 +329,7 @@ if (likeButtonElem) {
   const isLiked = likeButtonElem.dataset.liked === 'true';
   ReactDOM.render(
     <LikeButton crowi={crowi} pageId={pageId} isLiked={isLiked} />,
-    likeButtonElem,
+    likeButtonElem
   );
 }
 
@@ -342,7 +340,7 @@ if (seenUserListElem) {
   const userIds = userIdsStr.split(',');
   ReactDOM.render(
     <UserPictureList crowi={crowi} userIds={userIds} />,
-    seenUserListElem,
+    seenUserListElem
   );
 }
 // render UserPictureList for liker-list
@@ -352,7 +350,7 @@ if (likerListElem) {
   const userIds = userIdsStr.split(',');
   ReactDOM.render(
     <UserPictureList crowi={crowi} userIds={userIds} />,
-    likerListElem,
+    likerListElem
   );
 }
 
@@ -365,23 +363,16 @@ if (savePageControlsElem) {
   const grantGroupName = savePageControlsElem.dataset.grantGroupName;
   ReactDOM.render(
     <I18nextProvider i18n={i18n}>
-      <SavePageControls
-        crowi={crowi}
-        onSubmit={saveWithSubmitButton}
-        ref={(elem) => {
+      <SavePageControls crowi={crowi} onSubmit={saveWithSubmitButton}
+          ref={(elem) => {
             if (savePageControls == null) {
               savePageControls = elem.getWrappedInstance();
             }
           }}
-        pageId={pageId}
-        pagePath={pagePath}
-        slackChannels={slackChannels}
-        grant={grant}
-        grantGroupId={grantGroupId}
-        grantGroupName={grantGroupName}
-      />
+          pageId={pageId} pagePath={pagePath} slackChannels={slackChannels}
+          grant={grant} grantGroupId={grantGroupId} grantGroupName={grantGroupName} />
     </I18nextProvider>,
-    savePageControlsElem,
+    savePageControlsElem
   );
   componentInstances.savePageControls = savePageControls;
 }
@@ -389,11 +380,13 @@ if (savePageControlsElem) {
 const recentCreatedControlsElem = document.getElementById('user-created-list');
 if (recentCreatedControlsElem) {
   let limit = crowi.getConfig().recentCreatedLimit;
-  if (limit == null) {
+  if (null == limit) {
     limit = 10;
   }
   ReactDOM.render(
-    <RecentCreated crowi={crowi} pageId={pageId} limit={limit} />, document.getElementById('user-created-list'),
+    <RecentCreated  crowi={crowi} pageId={pageId} limit={limit} >
+
+    </RecentCreated>, document.getElementById('user-created-list')
   );
 }
 
@@ -405,17 +398,12 @@ let pageEditorByHackmd = null;
 const pageEditorWithHackmdElem = document.getElementById('page-editor-with-hackmd');
 if (pageEditorWithHackmdElem) {
   pageEditorByHackmd = ReactDOM.render(
-    <PageEditorByHackmd
-      crowi={crowi}
-      pageId={pageId}
-      revisionId={pageRevisionId}
-      pageIdOnHackmd={pageIdOnHackmd}
-      revisionIdHackmdSynced={pageRevisionIdHackmdSynced}
-      hasDraftOnHackmd={hasDraftOnHackmd}
-      markdown={markdown}
-      onSaveWithShortcut={saveWithShortcut}
-    />,
-    pageEditorWithHackmdElem,
+    <PageEditorByHackmd crowi={crowi}
+        pageId={pageId} revisionId={pageRevisionId}
+        pageIdOnHackmd={pageIdOnHackmd} revisionIdHackmdSynced={pageRevisionIdHackmdSynced} hasDraftOnHackmd={hasDraftOnHackmd}
+        markdown={markdown}
+        onSaveWithShortcut={saveWithShortcut} />,
+    pageEditorWithHackmdElem
   );
   componentInstances.pageEditorByHackmd = pageEditorByHackmd;
 }
@@ -431,18 +419,12 @@ const previewOptions = new PreviewOptions(crowi.previewOptions);
 const pageEditorElem = document.getElementById('page-editor');
 if (pageEditorElem) {
   pageEditor = ReactDOM.render(
-    <PageEditor
-      crowi={crowi}
-      crowiRenderer={crowiRenderer}
-      pageId={pageId}
-      revisionId={pageRevisionId}
-      pagePath={pagePath}
-      markdown={markdown}
-      editorOptions={editorOptions}
-      previewOptions={previewOptions}
-      onSaveWithShortcut={saveWithShortcut}
-    />,
-    pageEditorElem,
+    <PageEditor crowi={crowi} crowiRenderer={crowiRenderer}
+        pageId={pageId} revisionId={pageRevisionId} pagePath={pagePath}
+        markdown={markdown}
+        editorOptions={editorOptions} previewOptions={previewOptions}
+        onSaveWithShortcut={saveWithShortcut} />,
+    pageEditorElem
   );
   componentInstances.pageEditor = pageEditor;
   // set refs for setCaretLine/forceToFocus when tab is changed
@@ -459,18 +441,15 @@ if (writeCommentElem) {
     }
   };
   ReactDOM.render(
-    <CommentForm
-      crowi={crowi}
+    <CommentForm crowi={crowi}
       crowiOriginRenderer={crowiRenderer}
       pageId={pageId}
       pagePath={pagePath}
       revisionId={pageRevisionId}
       onPostComplete={postCompleteHandler}
       editorOptions={editorOptions}
-      slackChannels={slackChannels}
-    />,
-    writeCommentElem,
-  );
+      slackChannels = {slackChannels}/>,
+    writeCommentElem);
 }
 
 // render OptionsSelector
@@ -478,10 +457,8 @@ const pageEditorOptionsSelectorElem = document.getElementById('page-editor-optio
 if (pageEditorOptionsSelectorElem) {
   ReactDOM.render(
     <I18nextProvider i18n={i18n}>
-      <OptionsSelector
-        crowi={crowi}
-        editorOptions={editorOptions}
-        previewOptions={previewOptions}
+      <OptionsSelector crowi={crowi}
+        editorOptions={editorOptions} previewOptions={previewOptions}
         onChange={(newEditorOptions, newPreviewOptions) => { // set onChange event handler
           // set options
           pageEditor.setEditorOptions(newEditorOptions);
@@ -489,10 +466,9 @@ if (pageEditorOptionsSelectorElem) {
           // save
           crowi.saveEditorOptions(newEditorOptions);
           crowi.savePreviewOptions(newPreviewOptions);
-        }}
-      />
+        }} />
     </I18nextProvider>,
-    pageEditorOptionsSelectorElem,
+    pageEditorOptionsSelectorElem
   );
 }
 
@@ -502,19 +478,15 @@ const pageStatusAlertElem = document.getElementById('page-status-alert');
 if (pageStatusAlertElem) {
   ReactDOM.render(
     <I18nextProvider i18n={i18n}>
-      <PageStatusAlert
-        crowi={crowi}
-        ref={(elem) => {
+      <PageStatusAlert crowi={crowi}
+          ref={(elem) => {
             if (pageStatusAlert == null) {
               pageStatusAlert = elem.getWrappedInstance();
             }
           }}
-        revisionId={pageRevisionId}
-        revisionIdHackmdSynced={pageRevisionIdHackmdSynced}
-        hasDraftOnHackmd={hasDraftOnHackmd}
-      />
+          revisionId={pageRevisionId} revisionIdHackmdSynced={pageRevisionIdHackmdSynced} hasDraftOnHackmd={hasDraftOnHackmd} />
     </I18nextProvider>,
-    pageStatusAlertElem,
+    pageStatusAlertElem
   );
   componentInstances.pageStatusAlert = pageStatusAlert;
 }
@@ -527,7 +499,7 @@ if (customCssEditorElem != null) {
 
   ReactDOM.render(
     <CustomCssEditor inputElem={customCssInputElem} />,
-    customCssEditorElem,
+    customCssEditorElem
   );
 }
 const customScriptEditorElem = document.getElementById('custom-script-editor');
@@ -537,7 +509,7 @@ if (customScriptEditorElem != null) {
 
   ReactDOM.render(
     <CustomScriptEditor inputElem={customScriptInputElem} />,
-    customScriptEditorElem,
+    customScriptEditorElem
   );
 }
 const customHeaderEditorElem = document.getElementById('custom-header-editor');
@@ -547,14 +519,14 @@ if (customHeaderEditorElem != null) {
 
   ReactDOM.render(
     <CustomHeaderEditor inputElem={customHeaderInputElem} />,
-    customHeaderEditorElem,
+    customHeaderEditorElem
   );
 }
 const adminRebuildSearchElem = document.getElementById('admin-rebuild-search');
 if (adminRebuildSearchElem != null) {
   ReactDOM.render(
     <AdminRebuildSearch crowi={crowi} />,
-    adminRebuildSearchElem,
+    adminRebuildSearchElem
   );
 }
 
@@ -568,7 +540,7 @@ function updatePageStatusAlert(page, user) {
     pageStatusAlert.setLastUpdateUsername(user.name);
   }
 }
-socket.on('page:create', (data) => {
+socket.on('page:create', function(data) {
   // skip if triggered myself
   if (data.socketClientId != null && data.socketClientId === socketClientId) {
     return;
@@ -577,11 +549,11 @@ socket.on('page:create', (data) => {
   logger.debug({ obj: data }, `websocket on 'page:create'`); // eslint-disable-line quotes
 
   // update PageStatusAlert
-  if (data.page.path === pagePath) {
+  if (data.page.path == pagePath) {
     updatePageStatusAlert(data.page, data.user);
   }
 });
-socket.on('page:update', (data) => {
+socket.on('page:update', function(data) {
   // skip if triggered myself
   if (data.socketClientId != null && data.socketClientId === socketClientId) {
     return;
@@ -589,7 +561,7 @@ socket.on('page:update', (data) => {
 
   logger.debug({ obj: data }, `websocket on 'page:update'`); // eslint-disable-line quotes
 
-  if (data.page.path === pagePath) {
+  if (data.page.path == pagePath) {
     // update PageStatusAlert
     updatePageStatusAlert(data.page, data.user);
     // update PageEditorByHackmd
@@ -601,7 +573,7 @@ socket.on('page:update', (data) => {
     }
   }
 });
-socket.on('page:delete', (data) => {
+socket.on('page:delete', function(data) {
   // skip if triggered myself
   if (data.socketClientId != null && data.socketClientId === socketClientId) {
     return;
@@ -610,11 +582,11 @@ socket.on('page:delete', (data) => {
   logger.debug({ obj: data }, `websocket on 'page:delete'`); // eslint-disable-line quotes
 
   // update PageStatusAlert
-  if (data.page.path === pagePath) {
+  if (data.page.path == pagePath) {
     updatePageStatusAlert(data.page, data.user);
   }
 });
-socket.on('page:editingWithHackmd', (data) => {
+socket.on('page:editingWithHackmd', function(data) {
   // skip if triggered myself
   if (data.socketClientId != null && data.socketClientId === socketClientId) {
     return;
@@ -622,7 +594,7 @@ socket.on('page:editingWithHackmd', (data) => {
 
   logger.debug({ obj: data }, `websocket on 'page:editingWithHackmd'`); // eslint-disable-line quotes
 
-  if (data.page.path === pagePath) {
+  if (data.page.path == pagePath) {
     // update PageStatusAlert
     const pageStatusAlert = componentInstances.pageStatusAlert;
     if (pageStatusAlert != null) {
@@ -637,10 +609,9 @@ socket.on('page:editingWithHackmd', (data) => {
 });
 
 // うわーもうー (commented by Crowi team -- 2018.03.23 Yuki Takei)
-$('a[data-toggle="tab"][href="#revision-history"]').on('show.bs.tab', () => {
+$('a[data-toggle="tab"][href="#revision-history"]').on('show.bs.tab', function() {
   ReactDOM.render(
     <I18nextProvider i18n={i18n}>
       <PageHistory pageId={pageId} crowi={crowi} />
-    </I18nextProvider>, document.getElementById('revision-history'),
-  );
+    </I18nextProvider>, document.getElementById('revision-history'));
 });

+ 7 - 6
src/client/js/components/Admin/CustomCssEditor.js

@@ -2,7 +2,6 @@ import React from 'react';
 import PropTypes from 'prop-types';
 
 import { UnControlled as CodeMirror } from 'react-codemirror2';
-
 require('codemirror/addon/lint/css-lint');
 require('codemirror/addon/hint/css-hint');
 require('codemirror/addon/hint/show-hint');
@@ -14,6 +13,7 @@ require('../../util/codemirror/autorefresh.ext');
 require('jquery-ui/ui/widgets/resizable');
 
 export default class CustomCssEditor extends React.Component {
+
   constructor(props) {
     super(props);
   }
@@ -25,24 +25,24 @@ export default class CustomCssEditor extends React.Component {
     return (
       <CodeMirror
         value={value}
-        autoFocus
+        autoFocus={true}
         options={{
           mode: 'css',
           lineNumbers: true,
           tabSize: 2,
           indentUnit: 2,
           theme: 'eclipse',
-          autoRefresh: { force: true }, // force option is enabled by autorefresh.ext.js -- Yuki Takei
+          autoRefresh: {force: true},   // force option is enabled by autorefresh.ext.js -- Yuki Takei
           matchBrackets: true,
           autoCloseBrackets: true,
-          extraKeys: { 'Ctrl-Space': 'autocomplete' },
+          extraKeys: {'Ctrl-Space': 'autocomplete'},
         }}
         editorDidMount={(editor, next) => {
           // resizable with jquery.ui
           $(editor.getWrapperElement()).resizable({
-            resize() {
+            resize: function() {
               editor.setSize($(this).width(), $(this).height());
-            },
+            }
           });
         }}
         onChange={(editor, data, value) => {
@@ -51,6 +51,7 @@ export default class CustomCssEditor extends React.Component {
       />
     );
   }
+
 }
 
 CustomCssEditor.propTypes = {

+ 7 - 6
src/client/js/components/Admin/CustomHeaderEditor.js

@@ -2,7 +2,6 @@ import React from 'react';
 import PropTypes from 'prop-types';
 
 import { UnControlled as CodeMirror } from 'react-codemirror2';
-
 require('codemirror/addon/hint/show-hint');
 require('codemirror/addon/edit/matchbrackets');
 require('codemirror/addon/edit/closebrackets');
@@ -12,6 +11,7 @@ require('../../util/codemirror/autorefresh.ext');
 require('jquery-ui/ui/widgets/resizable');
 
 export default class CustomHeaderEditor extends React.Component {
+
   constructor(props) {
     super(props);
   }
@@ -23,24 +23,24 @@ export default class CustomHeaderEditor extends React.Component {
     return (
       <CodeMirror
         value={value}
-        autoFocus
+        autoFocus={true}
         options={{
           mode: 'htmlmixed',
           lineNumbers: true,
           tabSize: 2,
           indentUnit: 2,
           theme: 'eclipse',
-          autoRefresh: { force: true }, // force option is enabled by autorefresh.ext.js -- Yuki Takei
+          autoRefresh: {force: true},   // force option is enabled by autorefresh.ext.js -- Yuki Takei
           matchBrackets: true,
           autoCloseBrackets: true,
-          extraKeys: { 'Ctrl-Space': 'autocomplete' },
+          extraKeys: {'Ctrl-Space': 'autocomplete'},
         }}
         editorDidMount={(editor, next) => {
           // resizable with jquery.ui
           $(editor.getWrapperElement()).resizable({
-            resize() {
+            resize: function() {
               editor.setSize($(this).width(), $(this).height());
-            },
+            }
           });
         }}
         onChange={(editor, data, value) => {
@@ -49,6 +49,7 @@ export default class CustomHeaderEditor extends React.Component {
       />
     );
   }
+
 }
 
 CustomHeaderEditor.propTypes = {

+ 7 - 6
src/client/js/components/Admin/CustomScriptEditor.js

@@ -2,7 +2,6 @@ import React from 'react';
 import PropTypes from 'prop-types';
 
 import { UnControlled as CodeMirror } from 'react-codemirror2';
-
 require('codemirror/addon/lint/javascript-lint');
 require('codemirror/addon/hint/javascript-hint');
 require('codemirror/addon/hint/show-hint');
@@ -14,6 +13,7 @@ require('../../util/codemirror/autorefresh.ext');
 require('jquery-ui/ui/widgets/resizable');
 
 export default class CustomScriptEditor extends React.Component {
+
   constructor(props) {
     super(props);
   }
@@ -25,24 +25,24 @@ export default class CustomScriptEditor extends React.Component {
     return (
       <CodeMirror
         value={value}
-        autoFocus
+        autoFocus={true}
         options={{
           mode: 'javascript',
           lineNumbers: true,
           tabSize: 2,
           indentUnit: 2,
           theme: 'eclipse',
-          autoRefresh: { force: true }, // force option is enabled by autorefresh.ext.js -- Yuki Takei
+          autoRefresh: {force: true},   // force option is enabled by autorefresh.ext.js -- Yuki Takei
           matchBrackets: true,
           autoCloseBrackets: true,
-          extraKeys: { 'Ctrl-Space': 'autocomplete' },
+          extraKeys: {'Ctrl-Space': 'autocomplete'},
         }}
         editorDidMount={(editor, next) => {
           // resizable with jquery.ui
           $(editor.getWrapperElement()).resizable({
-            resize() {
+            resize: function() {
               editor.setSize($(this).width(), $(this).height());
-            },
+            }
           });
         }}
         onChange={(editor, data, value) => {
@@ -51,6 +51,7 @@ export default class CustomScriptEditor extends React.Component {
       />
     );
   }
+
 }
 
 CustomScriptEditor.propTypes = {

+ 2 - 0
src/client/js/components/Common/UserDate.js

@@ -9,6 +9,7 @@ import dateFnsFormat from 'date-fns/format';
  * display date depends on user timezone of user settings
  */
 export default class UserDate extends React.Component {
+
   render() {
     const dt = dateFnsFormat(this.props.dateTime, this.props.format);
 
@@ -31,3 +32,4 @@ UserDate.defaultProps = {
   format: 'YYYY/MM/DD HH:mm:ss',
   className: '',
 };
+

+ 7 - 14
src/client/js/components/CopyButton.js

@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
 import ClipboardButton from 'react-clipboard.js';
 
 export default class CopyButton extends React.Component {
+
   constructor(props) {
     super(props);
 
@@ -22,7 +23,7 @@ export default class CopyButton extends React.Component {
 
   render() {
     const containerStyle = {
-      lineHeight: 0,
+      lineHeight: 0
     };
     const style = Object.assign({
       padding: '0 2px',
@@ -33,20 +34,12 @@ export default class CopyButton extends React.Component {
 
     return (
       <span className="btn-copy-container" style={containerStyle}>
-        <ClipboardButton
-          className={this.props.buttonClassName}
-          button-id={this.props.buttonId}
-          button-data-toggle="tooltip"
-          button-data-container="body"
-          button-title="copied!"
-          button-data-placement="bottom"
-          button-data-trigger="manual"
-          button-style={style}
-          data-clipboard-text={text}
-          onSuccess={this.showToolTip}
-        >
+        <ClipboardButton className={this.props.buttonClassName}
+            button-id={this.props.buttonId} button-data-toggle="tooltip" button-data-container="body" button-title="copied!" button-data-placement="bottom" button-data-trigger="manual"
+            button-style={style}
+            data-clipboard-text={text} onSuccess={this.showToolTip}>
 
-          <i className={this.props.iconClassName} />
+          <i className={this.props.iconClassName}></i>
         </ClipboardButton>
       </span>
     );

+ 3 - 3
src/client/js/components/Page/PagePath.js

@@ -2,6 +2,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 
 export default class PagePath extends React.Component {
+
   linkPath(path) {
     return path;
   }
@@ -9,12 +10,11 @@ export default class PagePath extends React.Component {
   render() {
     const page = this.props.page;
     const shortPath = this.getShortPath(page.path);
-    const pathPrefix = page.path.replace(new RegExp(`${shortPath}(/)?$`), '');
+    const pathPrefix = page.path.replace(new RegExp(shortPath + '(/)?$'), '');
 
     return (
       <span className="page-path">
-        {pathPrefix}
-        <strong>{shortPath}</strong>
+        {pathPrefix}<strong>{shortPath}</strong>
       </span>
     );
   }

+ 5 - 5
src/client/js/components/Page/RevisionBody.js

@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
 import { debounce } from 'throttle-debounce';
 
 export default class RevisionBody extends React.Component {
+
   constructor(props) {
     super(props);
 
@@ -38,7 +39,7 @@ export default class RevisionBody extends React.Component {
   }
 
   generateInnerHtml(html) {
-    return { __html: html };
+    return {__html: html};
   }
 
   render() {
@@ -51,16 +52,15 @@ export default class RevisionBody extends React.Component {
             this.props.inputRef(elm);
           }
         }}
-        className={`wiki ${additionalClassName}`}
-        dangerouslySetInnerHTML={this.generateInnerHtml(this.props.html)}
-      />
+        className={`wiki ${additionalClassName}`} dangerouslySetInnerHTML={this.generateInnerHtml(this.props.html)}>
+      </div>
     );
   }
 }
 
 RevisionBody.propTypes = {
   html: PropTypes.string,
-  inputRef: PropTypes.func, // for getting div element
+  inputRef: PropTypes.func,  // for getting div element
   isMathJaxEnabled: PropTypes.bool,
   renderMathJaxOnInit: PropTypes.bool,
   renderMathJaxInRealtime: PropTypes.bool,

+ 21 - 23
src/client/js/components/Page/RevisionPath.js

@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
 import CopyButton from '../CopyButton';
 
 export default class RevisionPath extends React.Component {
+
   constructor(props) {
     super(props);
 
@@ -23,25 +24,25 @@ export default class RevisionPath extends React.Component {
     this.setState({ isListPage });
 
     // whether set link to '/'
-    const behaviorType = this.props.crowi.getConfig().behaviorType;
-    const isLinkToListPage = (!behaviorType || behaviorType === 'crowi');
+    const behaviorType = this.props.crowi.getConfig()['behaviorType'];
+    const isLinkToListPage = (!behaviorType || 'crowi' === behaviorType);
     this.setState({ isLinkToListPage });
 
     // generate pages obj
-    const splitted = this.props.pagePath.split(/\//);
-    splitted.shift(); // omit first element with shift()
-    if (splitted[splitted.length - 1] === '') {
-      splitted.pop(); // omit last element with unshift()
+    let splitted = this.props.pagePath.split(/\//);
+    splitted.shift();   // omit first element with shift()
+    if (splitted[splitted.length-1] === '') {
+      splitted.pop();   // omit last element with unshift()
     }
 
-    const pages = [];
+    let pages = [];
     let parentPath = '/';
     splitted.forEach((pageName) => {
       pages.push({
         pagePath: parentPath + encodeURIComponent(pageName),
         pageName: this.xss.process(pageName),
       });
-      parentPath += `${pageName}/`;
+      parentPath += pageName + '/';
     });
 
     this.setState({ pages });
@@ -56,13 +57,14 @@ export default class RevisionPath extends React.Component {
 
   generateLinkElementToListPage(pagePath, isLinkToListPage, isLastElement) {
     if (isLinkToListPage) {
-      return <a href={`${pagePath}/`} className={(isLastElement && !this.state.isListPage) ? 'last-path' : ''}>/</a>;
+      return <a href={pagePath+'/'} className={(isLastElement && !this.state.isListPage) ? 'last-path' : ''}>/</a>;
     }
-    if (!isLastElement) {
+    else if (!isLastElement) {
       return <span>/</span>;
     }
-
-    return <span />;
+    else {
+      return <span></span>;
+    }
   }
 
   render() {
@@ -83,20 +85,20 @@ export default class RevisionPath extends React.Component {
 
     const afterElements = [];
     this.state.pages.forEach((page, index) => {
-      const isLastElement = (index == pageLength - 1);
+      const isLastElement = (index == pageLength-1);
 
       // add elements for page
       afterElements.push(
         <span key={page.pagePath} className="path-segment">
           <a href={page.pagePath}>{page.pageName}</a>
-        </span>,
+        </span>
       );
 
       // add elements for '/'
       afterElements.push(
-        <span key={`${page.pagePath}/`} className="separator" style={separatorStyle}>
+        <span key={page.pagePath+'/'} className="separator" style={separatorStyle}>
           {this.generateLinkElementToListPage(page.pagePath, this.state.isLinkToListPage, isLastElement)}
-        </span>,
+        </span>
       );
     });
 
@@ -106,14 +108,10 @@ export default class RevisionPath extends React.Component {
           <a href="/">/</a>
         </span>
         {afterElements}
-        <CopyButton
-          buttonId="btnCopyRevisionPath"
-          text={this.props.pagePath}
-          buttonClassName="btn btn-default btn-copy"
-          iconClassName="ti-clipboard"
-        />
+        <CopyButton buttonId="btnCopyRevisionPath" text={this.props.pagePath}
+            buttonClassName="btn btn-default btn-copy" iconClassName="ti-clipboard" />
         <a href="#edit" className="btn btn-default btn-edit" style={editButtonStyle}>
-          <i className="icon-note" />
+          <i className="icon-note"></i>
         </a>
       </span>
     );

+ 5 - 9
src/client/js/components/Page/RevisionUrl.js

@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
 import CopyButton from '../CopyButton';
 
 export default class RevisionUrl extends React.Component {
+
   constructor(props) {
     super(props);
 
@@ -13,7 +14,7 @@ export default class RevisionUrl extends React.Component {
 
   render() {
     const buttonStyle = {
-      fontSize: '1em',
+      fontSize: '1em'
     };
 
     const pagePath = this.xss.process(this.props.pagePath);
@@ -21,18 +22,13 @@ export default class RevisionUrl extends React.Component {
     const url = (this.props.pageId == null)
       ? decodeURIComponent(location.href)
       : `${location.origin}/${this.props.pageId}`;
-    const copiedText = `${pagePath}\n${url}`;
+    const copiedText = pagePath + '\n' + url;
 
     return (
       <span>
         {url}
-        <CopyButton
-          buttonId="btnCopyRevisionUrl"
-          text={copiedText}
-          buttonClassName="btn btn-default btn-copy-link"
-          buttonStyle={buttonStyle}
-          iconClassName="ti-clipboard"
-        />
+        <CopyButton buttonId="btnCopyRevisionUrl" text={copiedText}
+            buttonClassName="btn btn-default btn-copy-link" buttonStyle={buttonStyle} iconClassName="ti-clipboard" />
       </span>
     );
   }

+ 11 - 11
src/client/js/components/PageAttachment.js

@@ -24,21 +24,21 @@ export default class PageAttachment extends React.Component {
     const pageId = this.props.pageId;
 
     if (!pageId) {
-      return;
+      return ;
     }
 
-    this.props.crowi.apiGet('/attachments.list', { page_id: pageId })
-      .then((res) => {
+    this.props.crowi.apiGet('/attachments.list', {page_id: pageId })
+      .then(res => {
         const attachments = res.attachments;
-        const inUse = {};
+        let inUse = {};
 
         for (const attachment of attachments) {
           inUse[attachment._id] = this.checkIfFileInUse(attachment);
         }
 
         this.setState({
-          attachments,
-          inUse,
+          attachments: attachments,
+          inUse: inUse,
         });
       });
   }
@@ -62,8 +62,8 @@ export default class PageAttachment extends React.Component {
       deleting: true,
     });
 
-    this.props.crowi.apiPost('/attachments.remove', { attachment_id: attachmentId })
-      .then((res) => {
+    this.props.crowi.apiPost('/attachments.remove', {attachment_id: attachmentId})
+      .then(res => {
         this.setState({
           attachments: this.state.attachments.filter((at) => {
             return at._id != attachmentId;
@@ -71,7 +71,7 @@ export default class PageAttachment extends React.Component {
           attachmentToDelete: null,
           deleting: false,
         });
-      }).catch((err) => {
+      }).catch(err => {
         this.setState({
           deleteError: 'Something went wrong.',
           deleting: false,
@@ -87,10 +87,10 @@ export default class PageAttachment extends React.Component {
     let deleteAttachmentModal = '';
     if (this.isUserLoggedIn()) {
       const attachmentToDelete = this.state.attachmentToDelete;
-      const deleteModalClose = () => {
+      let deleteModalClose = () => {
         this.setState({ attachmentToDelete: null, deleteError: '' });
       };
-      const showModal = attachmentToDelete !== null;
+      let showModal = attachmentToDelete !== null;
 
       let deleteInUse = null;
       if (attachmentToDelete !== null) {

+ 6 - 12
src/client/js/components/PageAttachment/Attachment.js

@@ -36,28 +36,22 @@ export default class Attachment extends React.Component {
     const btnDownload = (this.props.isUserLoggedIn)
       ? (
         <a className="attachment-download" href={attachment.downloadPathProxied}>
-          <i className="icon-cloud-download" />
-        </a>
-      )
+          <i className="icon-cloud-download"></i>
+        </a>)
       : '';
 
     const btnTrash = (this.props.isUserLoggedIn)
       ? (
         <a className="text-danger attachment-delete" onClick={this._onAttachmentDeleteClicked}>
-          <i className="icon-trash" />
-        </a>
-      )
+          <i className="icon-trash"></i>
+        </a>)
       : '';
 
     return (
-      <li className="attachment">
+      <li className='attachment'>
         <User user={attachment.creator} />
 
-        <a href={attachment.filePathProxied}>
-          <i className={formatIcon} />
-          {' '}
-          {attachment.originalName}
-        </a>
+        <a href={attachment.filePathProxied}><i className={formatIcon}></i> {attachment.originalName}</a>
 
         {fileType}
 

+ 7 - 15
src/client/js/components/PageAttachment/DeleteAttachmentModal.js

@@ -32,14 +32,10 @@ export default class DeleteAttachmentModal extends React.Component {
     return (
       <div className="attachment-delete-image">
         <p>
-          <i className={this.iconNameByFormat(attachment.fileFormat)} />
-          {' '}
-          {attachment.originalName}
+          <i className={this.iconNameByFormat(attachment.fileFormat)}></i> {attachment.originalName}
         </p>
         <p>
-          uploaded by
-          {' '}
-          <User user={attachment.creator} username />
+          uploaded by <User user={attachment.creator} username />
         </p>
         {content}
       </div>
@@ -61,13 +57,13 @@ export default class DeleteAttachmentModal extends React.Component {
 
     let deletingIndicator = '';
     if (this.props.deleting) {
-      deletingIndicator = <div className="speeding-wheel-sm" />;
+      deletingIndicator = <div className="speeding-wheel-sm"></div>;
     }
     if (this.props.deleteError) {
       deletingIndicator = <span>{this.props.deleteError}</span>;
     }
 
-    const renderAttachment = this.renderByFileFormat(attachment);
+    let renderAttachment = this.renderByFileFormat(attachment);
 
     return (
       <Modal {...props} className="attachment-delete-modal" bsSize="large" aria-labelledby="contained-modal-title-lg">
@@ -81,15 +77,11 @@ export default class DeleteAttachmentModal extends React.Component {
           <div className="mr-3 d-inline-block">
             {deletingIndicator}
           </div>
-          <Button
-            onClick={this._onDeleteConfirm}
-            bsStyle="danger"
-            disabled={this.props.deleting}
-          >
-Delete!
-          </Button>
+          <Button onClick={this._onDeleteConfirm} bsStyle="danger"
+            disabled={this.props.deleting}>Delete!</Button>
         </Modal.Footer>
       </Modal>
     );
   }
 }
+

+ 7 - 5
src/client/js/components/PageAttachment/PageAttachmentList.js

@@ -3,6 +3,7 @@ import React from 'react';
 import Attachment from './Attachment';
 
 export default class PageAttachmentList extends React.Component {
+
   render() {
     if (this.props.attachments <= 0) {
       return null;
@@ -11,24 +12,25 @@ export default class PageAttachmentList extends React.Component {
     const attachmentList = this.props.attachments.map((attachment, idx) => {
       return (
         <Attachment
-          key={`page:attachment:${attachment._id}`}
+          key={'page:attachment:' + attachment._id}
           attachment={attachment}
           inUse={this.props.inUse[attachment._id] || false}
           onAttachmentDeleteClicked={this.props.onAttachmentDeleteClicked}
           isUserLoggedIn={this.props.isUserLoggedIn}
-        />
+         />
       );
     });
 
     return (
       <div>
-        {(attachmentList.length != 0)
-          && <h5><strong>Attachments</strong></h5>
+        {(attachmentList.length != 0) &&
+          <h5><strong>Attachments</strong></h5>
         }
-        <ul className="pl-2">
+        <ul className='pl-2'>
           {attachmentList}
         </ul>
       </div>
     );
   }
 }
+

+ 22 - 23
src/client/js/components/PageComment/Comment.js

@@ -17,6 +17,7 @@ import UserPicture from '../User/UserPicture';
  * @extends {React.Component}
  */
 export default class Comment extends React.Component {
+
   constructor(props) {
     super(props);
 
@@ -40,7 +41,7 @@ export default class Comment extends React.Component {
     this.renderHtml(nextProps.comment.comment);
   }
 
-  // not used
+  //not used
   setMarkdown(markdown) {
     this.setState({ markdown });
     this.renderHtml(markdown);
@@ -55,13 +56,13 @@ export default class Comment extends React.Component {
   }
 
   getRootClassName() {
-    return `page-comment ${
-      this.isCurrentUserEqualsToAuthor() ? 'page-comment-me ' : ''}`;
+    return 'page-comment '
+        + (this.isCurrentUserEqualsToAuthor() ? 'page-comment-me ' : '');
   }
 
   getRevisionLabelClassName() {
-    return `page-comment-revision label ${
-      this.isCurrentRevision() ? 'label-primary' : 'label-default'}`;
+    return 'page-comment-revision label '
+        + (this.isCurrentRevision() ? 'label-primary' : 'label-default');
   }
 
   deleteBtnClickedHandler() {
@@ -72,12 +73,10 @@ export default class Comment extends React.Component {
     const config = this.props.crowi.getConfig();
     const isMathJaxEnabled = !!config.env.MATHJAX;
     return (
-      <RevisionBody
-        html={this.state.html}
-        isMathJaxEnabled={isMathJaxEnabled}
-        renderMathJaxOnInit
-        additionalClassName="comment"
-      />
+      <RevisionBody html={this.state.html}
+          isMathJaxEnabled={isMathJaxEnabled}
+          renderMathJaxOnInit={true}
+          additionalClassName="comment" />
     );
   }
 
@@ -89,26 +88,27 @@ export default class Comment extends React.Component {
     const crowiRenderer = this.props.crowiRenderer;
     const interceptorManager = this.props.crowi.interceptorManager;
     interceptorManager.process('preRenderComment', context)
-      .then(() => { return interceptorManager.process('prePreProcess', context) })
+      .then(() => interceptorManager.process('prePreProcess', context))
       .then(() => {
         context.markdown = crowiRenderer.preProcess(context.markdown);
       })
-      .then(() => { return interceptorManager.process('postPreProcess', context) })
+      .then(() => interceptorManager.process('postPreProcess', context))
       .then(() => {
-        const parsedHTML = crowiRenderer.process(context.markdown);
-        context.parsedHTML = parsedHTML;
+        var parsedHTML = crowiRenderer.process(context.markdown);
+        context['parsedHTML'] = parsedHTML;
       })
-      .then(() => { return interceptorManager.process('prePostProcess', context) })
+      .then(() => interceptorManager.process('prePostProcess', context))
       .then(() => {
         context.parsedHTML = crowiRenderer.postProcess(context.parsedHTML);
       })
-      .then(() => { return interceptorManager.process('postPostProcess', context) })
-      .then(() => { return interceptorManager.process('preRenderCommentHtml', context) })
+      .then(() => interceptorManager.process('postPostProcess', context))
+      .then(() => interceptorManager.process('preRenderCommentHtml', context))
       .then(() => {
         this.setState({ html: context.parsedHTML });
       })
       // process interceptors for post rendering
-      .then(() => { return interceptorManager.process('postRenderCommentHtml', context) });
+      .then(() => interceptorManager.process('postRenderCommentHtml', context));
+
   }
 
   render() {
@@ -118,7 +118,7 @@ export default class Comment extends React.Component {
 
     const rootClassName = this.getRootClassName();
     const commentDate = dateFnsFormat(comment.createdAt, 'YYYY/MM/DD HH:mm');
-    const commentBody = isMarkdown ? this.renderRevisionBody() : ReactUtils.nl2br(comment.comment);
+    const commentBody = isMarkdown ? this.renderRevisionBody(): ReactUtils.nl2br(comment.comment);
     const creatorsPage = `/user/${creator.username}`;
     const revHref = `?revision=${comment.revision}`;
     const revFirst8Letters = comment.revision.substr(-8);
@@ -135,13 +135,12 @@ export default class Comment extends React.Component {
           </div>
           <div className="page-comment-body">{commentBody}</div>
           <div className="page-comment-meta">
-            {commentDate}
-&nbsp;
+            {commentDate}&nbsp;
             <a className={revisionLavelClassName} href={revHref}>{revFirst8Letters}</a>
           </div>
           <div className="page-comment-control">
             <button className="btn btn-link" onClick={this.deleteBtnClickedHandler}>
-              <i className="ti-close" />
+              <i className="ti-close"></i>
             </button>
           </div>
         </div>

+ 5 - 6
src/client/js/components/PageComment/CommentPreview.js

@@ -7,19 +7,18 @@ import RevisionBody from '../Page/RevisionBody';
  * Wrapper component for Page/RevisionBody
  */
 export default class CommentPreview extends React.Component {
+
   constructor(props) {
     super(props);
   }
 
   render() {
     return (
-      <div
-        className="page-comment-preview-body"
-        ref={(elm) => {
+      <div className="page-comment-preview-body"
+          ref={(elm) => {
             this.previewElement = elm;
             this.props.inputRef(elm);
-          }}
-      >
+          }}>
 
         <RevisionBody
           {...this.props}
@@ -32,5 +31,5 @@ export default class CommentPreview extends React.Component {
 
 CommentPreview.propTypes = {
   html: PropTypes.string,
-  inputRef: PropTypes.func.isRequired, // for getting div element
+  inputRef: PropTypes.func.isRequired,  // for getting div element
 };

+ 9 - 15
src/client/js/components/PageComment/DeleteCommentModal.js

@@ -10,6 +10,7 @@ import ReactUtils from '../ReactUtils';
 import UserPicture from '../User/UserPicture';
 
 export default class DeleteCommentModal extends React.Component {
+
   /*
    * the threshold for omitting body
    */
@@ -24,7 +25,7 @@ export default class DeleteCommentModal extends React.Component {
 
   render() {
     if (this.props.comment === undefined) {
-      return <div />;
+      return <div></div>;
     }
 
     const comment = this.props.comment;
@@ -33,7 +34,7 @@ export default class DeleteCommentModal extends React.Component {
     // generate body
     let commentBody = comment.comment;
     if (commentBody.length > DeleteCommentModal.OMIT_BODY_THRES) { // omit
-      commentBody = `${commentBody.substr(0, DeleteCommentModal.OMIT_BODY_THRES)}...`;
+      commentBody = commentBody.substr(0, DeleteCommentModal.OMIT_BODY_THRES) + '...';
     }
     commentBody = ReactUtils.nl2br(commentBody);
 
@@ -41,39 +42,32 @@ export default class DeleteCommentModal extends React.Component {
       <Modal show={this.props.isShown} onHide={this.props.cancel} className="page-comment-delete-modal">
         <Modal.Header closeButton>
           <Modal.Title>
-            <i className="icon-fw icon-fire text-danger" />
+            <i className="icon-fw icon-fire text-danger"></i>
             Delete comment?
           </Modal.Title>
         </Modal.Header>
         <Modal.Body>
-          <UserPicture user={comment.creator} size="xs" />
-          {' '}
-          <strong>{comment.creator.username}</strong>
-          {' '}
-wrote on
-          {' '}
-          {commentDate}
-:
+          <UserPicture user={comment.creator} size="xs" /> <strong>{comment.creator.username}</strong> wrote on {commentDate}:
           <p className="well well-sm comment-body m-t-5">{commentBody}</p>
         </Modal.Body>
         <Modal.Footer>
-          <span className="text-danger">{this.props.errorMessage}</span>
-&nbsp;
+          <span className="text-danger">{this.props.errorMessage}</span>&nbsp;
           <Button onClick={this.props.cancel} bsClass="btn btn-sm">Cancel</Button>
           <Button onClick={this.props.confirmedToDelete} bsClass="btn btn-sm btn-danger">
-            <i className="icon icon-fire" />
+            <i className="icon icon-fire"></i>
             Delete
           </Button>
         </Modal.Footer>
       </Modal>
     );
   }
+
 }
 
 DeleteCommentModal.propTypes = {
   isShown: PropTypes.bool.isRequired,
   comment: PropTypes.object,
   errorMessage: PropTypes.string,
-  cancel: PropTypes.func.isRequired, // for cancel evnet handling
+  cancel: PropTypes.func.isRequired,            // for cancel evnet handling
   confirmedToDelete: PropTypes.func.isRequired, // for confirmed event handling
 };

+ 30 - 38
src/client/js/components/PageComments.js

@@ -16,6 +16,7 @@ import DeleteCommentModal from './PageComment/DeleteCommentModal';
  * @extends {React.Component}
  */
 export default class PageComments extends React.Component {
+
   constructor(props) {
     super(props);
 
@@ -31,7 +32,7 @@ export default class PageComments extends React.Component {
       errorMessageForDeleting: undefined,
     };
 
-    this.growiRenderer = new GrowiRenderer(this.props.crowi, this.props.crowiOriginRenderer, { mode: 'comment' });
+    this.growiRenderer = new GrowiRenderer(this.props.crowi, this.props.crowiOriginRenderer, {mode: 'comment'});
 
     this.init = this.init.bind(this);
     this.confirmToDeleteComment = this.confirmToDeleteComment.bind(this);
@@ -50,8 +51,8 @@ export default class PageComments extends React.Component {
       return;
     }
 
-    const layoutType = this.props.crowi.getConfig().layoutType;
-    this.setState({ isLayoutTypeGrowi: layoutType === 'crowi-plus' || layoutType === 'growi' });
+    const layoutType = this.props.crowi.getConfig()['layoutType'];
+    this.setState({isLayoutTypeGrowi: 'crowi-plus' === layoutType || 'growi' === layoutType});
 
     this.retrieveData();
   }
@@ -61,35 +62,35 @@ export default class PageComments extends React.Component {
    */
   retrieveData() {
     // get data (desc order array)
-    this.props.crowi.apiGet('/comments.get', { page_id: this.props.pageId })
-      .then((res) => {
+    this.props.crowi.apiGet('/comments.get', {page_id: this.props.pageId})
+      .then(res => {
         if (res.ok) {
-          this.setState({ comments: res.comments });
+          this.setState({comments: res.comments});
         }
       });
   }
 
   confirmToDeleteComment(comment) {
-    this.setState({ commentToDelete: comment });
+    this.setState({commentToDelete: comment});
     this.showDeleteConfirmModal();
   }
 
   deleteComment() {
     const comment = this.state.commentToDelete;
 
-    this.props.crowi.apiPost('/comments.remove', { comment_id: comment._id })
-    .then((res) => {
+    this.props.crowi.apiPost('/comments.remove', {comment_id: comment._id})
+    .then(res => {
       if (res.ok) {
         this.findAndSplice(comment);
       }
       this.closeDeleteConfirmModal();
-    }).catch((err) => {
-      this.setState({ errorMessageForDeleting: err.message });
+    }).catch(err => {
+      this.setState({errorMessageForDeleting: err.message});
     });
   }
 
   findAndSplice(comment) {
-    const comments = this.state.comments;
+    let comments = this.state.comments;
 
     const index = comments.indexOf(comment);
     if (index < 0) {
@@ -97,11 +98,11 @@ export default class PageComments extends React.Component {
     }
     comments.splice(index, 1);
 
-    this.setState({ comments });
+    this.setState({comments});
   }
 
   showDeleteConfirmModal() {
-    this.setState({ isDeleteConfirmModalShown: true });
+    this.setState({isDeleteConfirmModalShown: true});
   }
 
   closeDeleteConfirmModal() {
@@ -122,28 +123,25 @@ export default class PageComments extends React.Component {
   generateCommentElements(comments) {
     return comments.map((comment) => {
       return (
-        <Comment
-          key={comment._id}
-          comment={comment}
+        <Comment key={comment._id} comment={comment}
           currentUserId={this.props.crowi.me}
           currentRevisionId={this.props.revisionId}
           deleteBtnClicked={this.confirmToDeleteComment}
           crowi={this.props.crowi}
-          crowiRenderer={this.growiRenderer}
-        />
+          crowiRenderer={this.growiRenderer} />
       );
     });
   }
 
   render() {
-    const currentComments = [];
-    const newerComments = [];
-    const olderComments = [];
+    let currentComments = [];
+    let newerComments = [];
+    let olderComments = [];
 
     let comments = this.state.comments;
     if (this.state.isLayoutTypeGrowi) {
       // replace with asc order array
-      comments = comments.slice().reverse(); // non-destructive reverse
+      comments = comments.slice().reverse();  // non-destructive reverse
     }
 
     // divide by revisionId and createdAt
@@ -153,7 +151,7 @@ export default class PageComments extends React.Component {
       if (comment.revision == revisionId) {
         currentComments.push(comment);
       }
-      else if (Date.parse(comment.createdAt) / 1000 > revisionCreatedAt) {
+      else if (Date.parse(comment.createdAt)/1000 > revisionCreatedAt) {
         newerComments.push(comment);
       }
       else {
@@ -184,29 +182,23 @@ export default class PageComments extends React.Component {
 
     // generate toggle elements
     const iconForNewer = (this.state.isLayoutTypeGrowi)
-      ? <i className="fa fa-angle-double-down" />
-      : <i className="fa fa-angle-double-up" />;
+      ? <i className="fa fa-angle-double-down"></i>
+      : <i className="fa fa-angle-double-up"></i>;
     const toggleNewer = (newerElements.length === 0)
-      ? <div />
+      ? <div></div>
       : (
         <a className="page-comments-list-toggle-newer text-center" data-toggle="collapse" href="#page-comments-list-newer">
-          {iconForNewer}
-          {' '}
-Comments for Newer Revision
-          {iconForNewer}
+          {iconForNewer} Comments for Newer Revision {iconForNewer}
         </a>
       );
     const iconForOlder = (this.state.isLayoutTypeGrowi)
-      ? <i className="fa fa-angle-double-up" />
-      : <i className="fa fa-angle-double-down" />;
+      ? <i className="fa fa-angle-double-up"></i>
+      : <i className="fa fa-angle-double-down"></i>;
     const toggleOlder = (olderElements.length === 0)
-      ? <div />
+      ? <div></div>
       : (
         <a className="page-comments-list-toggle-older text-center" data-toggle="collapse" href="#page-comments-list-older">
-          {iconForOlder}
-          {' '}
-Comments for Older Revision
-          {iconForOlder}
+          {iconForOlder} Comments for Older Revision {iconForOlder}
         </a>
       );
 

+ 25 - 30
src/client/js/components/PageEditor.js

@@ -3,18 +3,17 @@ import PropTypes from 'prop-types';
 
 import { throttle, debounce } from 'throttle-debounce';
 
-import * as toastr from 'toastr';
 import GrowiRenderer from '../util/GrowiRenderer';
 
 import { EditorOptions, PreviewOptions } from './PageEditor/OptionsSelector';
 import Editor from './PageEditor/Editor';
 import Preview from './PageEditor/Preview';
 import scrollSyncHelper from './PageEditor/ScrollSyncHelper';
+import * as toastr from 'toastr';
 
-/* global location */
-/* eslint no-restricted-globals: ['error', 'locaion'] */
 
 export default class PageEditor extends React.Component {
+
   constructor(props) {
     super(props);
 
@@ -34,7 +33,7 @@ export default class PageEditor extends React.Component {
       previewOptions: this.props.previewOptions,
     };
 
-    this.growiRenderer = new GrowiRenderer(this.props.crowi, this.props.crowiRenderer, { mode: 'editor' });
+    this.growiRenderer = new GrowiRenderer(this.props.crowi, this.props.crowiRenderer, {mode: 'editor'});
 
     this.setCaretLine = this.setCaretLine.bind(this);
     this.focusToEditor = this.focusToEditor.bind(this);
@@ -72,12 +71,12 @@ export default class PageEditor extends React.Component {
   setMarkdown(markdown, updateEditorValue = true) {
     this.setState({ markdown });
     if (updateEditorValue) {
-      this.editor.setValue(markdown);
+      this.refs.editor.setValue(markdown);
     }
   }
 
   focusToEditor() {
-    this.editor.forceToFocus();
+    this.refs.editor.forceToFocus();
   }
 
   /**
@@ -85,7 +84,7 @@ export default class PageEditor extends React.Component {
    * @param {number} line
    */
   setCaretLine(line) {
-    this.editor.setCaretLine(line);
+    this.refs.editor.setCaretLine(line);
     scrollSyncHelper.scrollPreview(this.previewElement, line);
   }
 
@@ -120,7 +119,7 @@ export default class PageEditor extends React.Component {
    */
   async onUpload(file) {
     try {
-      let res = await this.props.crowi.apiGet('/attachments.limit', { _csrf: this.props.crowi.csrfToken, fileSize: file.size });
+      let res  = await this.props.crowi.apiGet('/attachments.limit', {_csrf: this.props.crowi.csrfToken, fileSize: file.size});
       if (!res.isUploadable) {
         toastr.error(undefined, 'MongoDB for uploading files reaches limit', {
           closeButton: true,
@@ -150,9 +149,9 @@ export default class PageEditor extends React.Component {
       // when image
       if (attachment.fileFormat.startsWith('image/')) {
         // modify to "![fileName](url)" syntax
-        insertText = `!${insertText}`;
+        insertText = '!' + insertText;
       }
-      this.editor.insertText(insertText);
+      this.refs.editor.insertText(insertText);
 
       // when if created newly
       if (res.pageCreated) {
@@ -163,14 +162,13 @@ export default class PageEditor extends React.Component {
       this.apiErrorHandler(e);
     }
     finally {
-      this.editor.terminateUploadingState();
+      this.refs.editor.terminateUploadingState();
     }
   }
 
   /**
    * the scroll event handler from codemirror
-   * @param {any} data {left, top, width, height, clientWidth, clientHeight} object that represents the current scroll position,
-   *                    the size of the scrollable area, and the size of the visible area (minus scrollbars).
+   * @param {any} data {left, top, width, height, clientWidth, clientHeight} object that represents the current scroll position, the size of the scrollable area, and the size of the visible area (minus scrollbars).
    *                    And data.line is also available that is added by Editor component
    * @see https://codemirror.net/doc/manual.html#events
    */
@@ -255,13 +253,13 @@ export default class PageEditor extends React.Component {
 
     // prevent circular invocation
     if (this.isOriginOfScrollSyncEditor) {
-      this.isOriginOfScrollSyncEditor = false; // turn off the flag
+      this.isOriginOfScrollSyncEditor = false;  // turn off the flag
       return;
     }
 
     // turn on the flag
     this.isOriginOfScrollSyncPreview = true;
-    scrollSyncHelper.scrollEditor(this.editor, this.previewElement, offset);
+    scrollSyncHelper.scrollEditor(this.refs.editor, this.previewElement, offset);
   }
 
   saveDraft() {
@@ -270,7 +268,6 @@ export default class PageEditor extends React.Component {
       this.props.crowi.saveDraft(this.props.pagePath, this.state.markdown);
     }
   }
-
   clearDraft() {
     this.props.crowi.clearDraft(this.props.pagePath);
   }
@@ -281,32 +278,33 @@ export default class PageEditor extends React.Component {
     // render html
     const context = {
       markdown: this.state.markdown,
-      currentPagePath: decodeURIComponent(location.pathname),
+      currentPagePath: decodeURIComponent(location.pathname)
     };
 
     const growiRenderer = this.growiRenderer;
     const interceptorManager = this.props.crowi.interceptorManager;
     interceptorManager.process('preRenderPreview', context)
-      .then(() => { return interceptorManager.process('prePreProcess', context) })
+      .then(() => interceptorManager.process('prePreProcess', context))
       .then(() => {
         context.markdown = growiRenderer.preProcess(context.markdown);
       })
-      .then(() => { return interceptorManager.process('postPreProcess', context) })
+      .then(() => interceptorManager.process('postPreProcess', context))
       .then(() => {
         const parsedHTML = growiRenderer.process(context.markdown);
-        context.parsedHTML = parsedHTML;
+        context['parsedHTML'] = parsedHTML;
       })
-      .then(() => { return interceptorManager.process('prePostProcess', context) })
+      .then(() => interceptorManager.process('prePostProcess', context))
       .then(() => {
         context.parsedHTML = growiRenderer.postProcess(context.parsedHTML);
       })
-      .then(() => { return interceptorManager.process('postPostProcess', context) })
-      .then(() => { return interceptorManager.process('preRenderPreviewHtml', context) })
+      .then(() => interceptorManager.process('postPostProcess', context))
+      .then(() => interceptorManager.process('preRenderPreviewHtml', context))
       .then(() => {
         this.setState({ html: context.parsedHTML });
       })
       // process interceptors for post rendering
-      .then(() => { return interceptorManager.process('postRenderPreviewHtml', context) });
+      .then(() => interceptorManager.process('postRenderPreviewHtml', context));
+
   }
 
   apiErrorHandler(error) {
@@ -328,9 +326,7 @@ export default class PageEditor extends React.Component {
     return (
       <div className="row">
         <div className="col-md-6 col-sm-12 page-editor-editor-container">
-          <Editor
-            ref={(c) => { this.editor = c }}
-            value={this.state.markdown}
+          <Editor ref="editor" value={this.state.markdown}
             editorOptions={this.state.editorOptions}
             noCdn={noCdn}
             isMobile={this.props.crowi.isMobile}
@@ -347,9 +343,8 @@ export default class PageEditor extends React.Component {
           />
         </div>
         <div className="col-md-6 hidden-sm hidden-xs page-editor-preview-container">
-          <Preview
-            html={this.state.html}
-            inputRef={(el) => { return this.previewElement = el }}
+          <Preview html={this.state.html}
+            inputRef={el => this.previewElement = el}
             isMathJaxEnabled={this.state.isMathJaxEnabled}
             renderMathJaxOnInit={false}
             previewOptions={this.state.previewOptions}

+ 2 - 0
src/client/js/components/PageEditor/AbstractEditor.js

@@ -2,6 +2,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 
 export default class AbstractEditor extends React.Component {
+
   constructor(props) {
     super(props);
 
@@ -132,3 +133,4 @@ AbstractEditor.propTypes = {
 AbstractEditor.defaultProps = {
   isGfmMode: true,
 };
+

+ 25 - 123
src/client/js/components/PageEditor/Cheatsheet.js

@@ -11,74 +11,29 @@ class Cheatsheet extends React.Component {
         <div className="col-sm-6">
           <h4>{t('sandbox.header')}</h4>
           <ul className="hljs">
-            <li>
-              <code># </code>
-              {t('sandbox.header_x', { index: '1' })}
-            </li>
-            <li>
-              <code>## </code>
-              {t('sandbox.header_x', { index: '2' })}
-            </li>
-            <li>
-              <code>### </code>
-              {t('sandbox.header_x', { index: '3' })}
-            </li>
+            <li><code># </code>{t('sandbox.header_x', {index: '1'})}</li>
+            <li><code>## </code>{t('sandbox.header_x', {index: '2'})}</li>
+            <li><code>### </code>{t('sandbox.header_x', {index: '3'})}</li>
           </ul>
           <h4>{t('sandbox.block')}</h4>
-          <p className="mb-1">
-            <code>
-[
-              {t('sandbox.empty_line')}
-]
-            </code>
-            {t('sandbox.block_detail')}
-          </p>
+          <p className="mb-1"><code>[{t('sandbox.empty_line')}]</code>{t('sandbox.block_detail')}</p>
           <ul className="hljs">
             <li>text</li>
-            <li />
+            <li></li>
             <li>text</li>
           </ul>
           <h4>{t('sandbox.line_break')}</h4>
-          <p className="mb-1">
-            <code>[ ][ ]</code>
-            {' '}
-            {t('sandbox.line_break_detail')}
-          </p>
+          <p className="mb-1"><code>[ ][ ]</code> {t('sandbox.line_break_detail')}</p>
           <ul className="hljs">
             <li>text</li>
             <li>text</li>
           </ul>
           <h4>{t('sandbox.typography')}</h4>
           <ul className="hljs">
-            <li>
-              <i>
-*
-                {t('sandbox.italics')}
-*
-              </i>
-            </li>
-            <li>
-              <b>
-**
-                {t('sandbox.bold')}
-**
-              </b>
-            </li>
-            <li>
-              <i>
-                <b>
-***
-                  {t('sandbox.italic_bold')}
-***
-                </b>
-              </i>
-            </li>
-            <li>
-~~
-              {t('sandbox.strikethrough')}
-~~ =>
-              <s>{t('sandbox.strikethrough')}</s>
-            </li>
+            <li><i>*{t('sandbox.italics')}*</i></li>
+            <li><b>**{t('sandbox.bold')}**</b></li>
+            <li><i><b>***{t('sandbox.italic_bold')}***</b></i></li>
+            <li>~~{t('sandbox.strikethrough')}~~ => <s>{t('sandbox.strikethrough')}</s></li>
           </ul>
           <h4>{t('sandbox.link')}</h4>
           <ul className="hljs">
@@ -95,69 +50,27 @@ class Cheatsheet extends React.Component {
         <div className="col-sm-6">
           <h4>{t('sandbox.list')}</h4>
           <ul className="hljs">
-            <li>
--
-              {t('sandbox.unordered_list_x', { index: '1' })}
-            </li>
-            <li>
-&nbsp;&nbsp;-
-              {t('sandbox.unordered_list_x', { index: '1.1' })}
-            </li>
-            <li>
--
-              {t('sandbox.unordered_list_x', { index: '2' })}
-            </li>
+            <li>- {t('sandbox.unordered_list_x', {index: '1'})}</li>
+            <li>&nbsp;&nbsp;- {t('sandbox.unordered_list_x', {index: '1.1'})}</li>
+            <li>- {t('sandbox.unordered_list_x', {index: '2'})}</li>
           </ul>
           <ul className="hljs">
-            <li>
-1.
-              {t('sandbox.ordered_list_x', { index: '1' })}
-            </li>
-            <li>
-1.
-              {t('sandbox.ordered_list_x', { index: '2' })}
-            </li>
+            <li>1. {t('sandbox.ordered_list_x', {index: '1'})}</li>
+            <li>1. {t('sandbox.ordered_list_x', {index: '2'})}</li>
           </ul>
           <ul className="hljs">
-            <li>
-- [ ]
-              {t('sandbox.task')}
-(
-              {t('sandbox.task_unchecked')}
-)
-            </li>
-            <li>
-- [x]
-              {t('sandbox.task')}
-(
-              {t('sandbox.task_checked')}
-)
-            </li>
+            <li>- [ ] {t('sandbox.task')}({t('sandbox.task_unchecked')})</li>
+            <li>- [x] {t('sandbox.task')}({t('sandbox.task_checked')})</li>
           </ul>
           <h4>{t('sandbox.quote')}</h4>
           <ul className="hljs">
-            <li>
->
-              {t('sandbox.quote1')}
-            </li>
-            <li>
->
-              {t('sandbox.quote2')}
-            </li>
+            <li>> {t('sandbox.quote1')}</li>
+            <li>> {t('sandbox.quote2')}</li>
           </ul>
           <ul className="hljs">
-            <li>
->>
-              {t('sandbox.quote_nested')}
-            </li>
-            <li>
->>>
-              {t('sandbox.quote_nested')}
-            </li>
-            <li>
->>>>
-              {t('sandbox.quote_nested')}
-            </li>
+            <li>>> {t('sandbox.quote_nested')}</li>
+            <li>>>> {t('sandbox.quote_nested')}</li>
+            <li>>>>> {t('sandbox.quote_nested')}</li>
           </ul>
           <h4>{t('sandbox.table')}</h4>
           <ul className="hljs text-center">
@@ -167,25 +80,14 @@ class Cheatsheet extends React.Component {
             <li>|col 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;col 2&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;col 3|</li>
           </ul>
           <h4>{t('sandbox.image')}</h4>
-          <p className="mb-1">
-            <code>
-              {' '}
-![
-              {t('sandbox.alt_text')}
-](URL)
-            </code>
-            {' '}
-            {t('sandbox.insert_image')}
-          </p>
+          <p className="mb-1"><code> ![{t('sandbox.alt_text')}](URL)</code> {t('sandbox.insert_image')}</p>
           <ul className="hljs">
             <li>![ex](https://example.com/image.png)</li>
           </ul>
 
           <hr />
           <a href="/Sandbox" className="btn btn-info btn-block" target="_blank">
-            <i className="icon-share-alt" />
-            {' '}
-            {t('sandbox.open_sandbox')}
+            <i className="icon-share-alt"/> {t('sandbox.open_sandbox')}
           </a>
         </div>
       </div>
@@ -194,7 +96,7 @@ class Cheatsheet extends React.Component {
 }
 
 Cheatsheet.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
+  t: PropTypes.func.isRequired,               // i18next
 };
 
 export default translate()(Cheatsheet);

+ 110 - 171
src/client/js/components/PageEditor/CodeMirrorEditor.js

@@ -7,27 +7,10 @@ import Button from 'react-bootstrap/es/Button';
 import InterceptorManager from '@commons/service/interceptor-manager';
 
 import urljoin from 'url-join';
-
-import * as codemirror from 'codemirror';
-
-
-import { UnControlled as ReactCodeMirror } from 'react-codemirror2';
-
-import AbstractEditor from './AbstractEditor';
-
-import SimpleCheatsheet from './SimpleCheatsheet';
-import Cheatsheet from './Cheatsheet';
-
-import pasteHelper from './PasteHelper';
-import EmojiAutoCompleteHelper from './EmojiAutoCompleteHelper';
-
-import PreventMarkdownListInterceptor from './PreventMarkdownListInterceptor';
-import MarkdownTableInterceptor from './MarkdownTableInterceptor';
-import mtu from './MarkdownTableUtil';
-import HandsontableModal from './HandsontableModal';
-
 const loadScript = require('simple-load-script');
 const loadCssSync = require('load-css-file');
+
+import * as codemirror from 'codemirror';
 // set save handler
 codemirror.commands.save = (instance) => {
   if (instance.codeMirrorEditor != null) {
@@ -36,6 +19,9 @@ codemirror.commands.save = (instance) => {
 };
 // set CodeMirror instance as 'CodeMirror' so that CDN addons can reference
 window.CodeMirror = require('codemirror');
+
+
+import { UnControlled as ReactCodeMirror } from 'react-codemirror2';
 require('codemirror/addon/display/placeholder');
 require('codemirror/addon/edit/matchbrackets');
 require('codemirror/addon/edit/matchtags');
@@ -56,7 +42,21 @@ require('codemirror/addon/display/placeholder');
 require('codemirror/mode/gfm/gfm');
 require('../../util/codemirror/autorefresh.ext');
 
+import AbstractEditor from './AbstractEditor';
+
+import SimpleCheatsheet from './SimpleCheatsheet';
+import Cheatsheet from './Cheatsheet';
+
+import pasteHelper from './PasteHelper';
+import EmojiAutoCompleteHelper from './EmojiAutoCompleteHelper';
+
+import PreventMarkdownListInterceptor from './PreventMarkdownListInterceptor';
+import MarkdownTableInterceptor from './MarkdownTableInterceptor';
+import mtu from './MarkdownTableUtil';
+import HandsontableModal from './HandsontableModal';
+
 export default class CodeMirrorEditor extends AbstractEditor {
+
   constructor(props) {
     super(props);
     this.logger = require('@alias/logger')('growi:PageEditor:CodeMirrorEditor');
@@ -110,14 +110,14 @@ export default class CodeMirrorEditor extends AbstractEditor {
       new MarkdownTableInterceptor(),
     ]);
 
-    this.loadedThemeSet = new Set(['eclipse', 'elegant']); // themes imported in _vendor.scss
+    this.loadedThemeSet = new Set(['eclipse', 'elegant']);   // themes imported in _vendor.scss
     this.loadedKeymapSet = new Set();
   }
 
   componentWillMount() {
     if (this.props.emojiStrategy != null) {
       this.emojiAutoCompleteHelper = new EmojiAutoCompleteHelper(this.props.emojiStrategy);
-      this.setState({ isEnabledEmojiAutoComplete: true });
+      this.setState({isEnabledEmojiAutoComplete: true});
     }
   }
 
@@ -192,7 +192,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
     const editor = this.getCodeMirror();
     const linePosition = Math.max(0, line);
 
-    editor.setCursor({ line: linePosition }); // leave 'ch' field as null/undefined to indicate the end of line
+    editor.setCursor({line: linePosition});   // leave 'ch' field as null/undefined to indicate the end of line
     this.setScrollTopByLine(linePosition);
   }
 
@@ -206,7 +206,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
 
     const editor = this.getCodeMirror();
     // get top position of the line
-    const top = editor.charCoords({ line, ch: 0 }, 'local').top;
+    const top = editor.charCoords({line, ch: 0}, 'local').top;
     editor.scrollTo(null, top);
   }
 
@@ -331,8 +331,8 @@ export default class CodeMirrorEditor extends AbstractEditor {
    */
   loadKeymapMode(keymapMode) {
     const loadCss = this.loadCss;
-    const scriptList = [];
-    const cssList = [];
+    let scriptList = [];
+    let cssList = [];
 
     // add dependencies
     if (this.loadedKeymapSet.size == 0) {
@@ -394,7 +394,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
     }
 
     const context = {
-      handlers: [], // list of handlers which process enter key
+      handlers: [],  // list of handlers which process enter key
       editor: this,
     };
 
@@ -432,12 +432,14 @@ export default class CodeMirrorEditor extends AbstractEditor {
     if (mtu.isEndOfLine(editor) && mtu.linePartOfTableRE.test(strFromBol)) {
       if (!hasCustomClass) {
         additionalClassSet.add(autoformatTableClass);
-        this.setState({ additionalClassSet });
+        this.setState({additionalClassSet});
       }
     }
-    else if (hasCustomClass) {
-      additionalClassSet.delete(autoformatTableClass);
-      this.setState({ additionalClassSet });
+    else {
+      if (hasCustomClass) {
+        additionalClassSet.delete(autoformatTableClass);
+        this.setState({additionalClassSet});
+      }
     }
   }
 
@@ -472,6 +474,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
     else if (types.includes('text/plain')) {
       pasteHelper.pasteText(this, event);
     }
+
   }
 
   /**
@@ -502,15 +505,11 @@ export default class CodeMirrorEditor extends AbstractEditor {
     };
 
     return this.state.isLoadingKeymap
-      ? (
-        <div className="overlay overlay-loading-keymap">
+      ? <div className="overlay overlay-loading-keymap">
           <span style={style} className="overlay-content">
-            <div className="speeding-wheel d-inline-block" />
-            {' '}
-Loading Keymap ...
+            <div className="speeding-wheel d-inline-block"></div> Loading Keymap ...
           </span>
         </div>
-      )
       : '';
   }
 
@@ -524,21 +523,18 @@ Loading Keymap ...
 
   renderCheatsheetModalButton() {
     const showCheatsheetModal = () => {
-      this.setState({ isCheatsheetModalShown: true });
+      this.setState({isCheatsheetModalShown: true});
     };
 
     const hideCheatsheetModal = () => {
-      this.setState({ isCheatsheetModalShown: false });
+      this.setState({isCheatsheetModalShown: false});
     };
 
     return (
       <React.Fragment>
         <Modal className="modal-gfm-cheatsheet" show={this.state.isCheatsheetModalShown} onHide={() => { hideCheatsheetModal() }}>
           <Modal.Header closeButton>
-            <Modal.Title>
-              <i className="icon-fw icon-question" />
-Markdown Help
-            </Modal.Title>
+            <Modal.Title><i className="icon-fw icon-question"/>Markdown Help</Modal.Title>
           </Modal.Header>
           <Modal.Body className="pt-1">
             { this.renderCheatsheetModalBody() }
@@ -546,9 +542,7 @@ Markdown Help
         </Modal>
 
         <a className="gfm-cheatsheet-modal-link text-muted small" onClick={() => { showCheatsheetModal() }}>
-          <i className="icon-question" />
-          {' '}
-Markdown
+          <i className="icon-question" /> Markdown
         </a>
       </React.Fragment>
     );
@@ -596,8 +590,8 @@ Markdown
       for (let i = startLineNum; i <= endLineNum; i++) {
         lines.push(prefix + cm.getDoc().getLine(i));
       }
-      const replacement = `${lines.join('\n')}\n`;
-      cm.getDoc().replaceRange(replacement, { line: startLineNum, ch: 0 }, { line: endLineNum + 1, ch: 0 });
+      const replacement = lines.join('\n') + '\n';
+      cm.getDoc().replaceRange(replacement, {line: startLineNum, ch: 0}, {line: endLineNum + 1, ch: 0});
 
       cm.setCursor(endLineNum, cm.getDoc().getLine(endLineNum).length);
       cm.focus();
@@ -617,7 +611,7 @@ Markdown
     if (!line.startsWith('#')) {
       prefix += ' ';
     }
-    cm.getDoc().replaceRange(prefix, { line: lineNum, ch: 0 }, { line: lineNum, ch: 0 });
+    cm.getDoc().replaceRange(prefix, {line: lineNum, ch: 0}, {line: lineNum, ch: 0});
     cm.focus();
   }
 
@@ -627,113 +621,59 @@ Markdown
 
   getNavbarItems() {
     // The following styles will be removed after creating icons for the editor navigation bar.
-    const paddingTopBottom54 = { paddingTop: '6px', paddingBottom: '5px' };
-    const paddingBottom6 = { paddingBottom: '7px' };
-    const fontSize18 = { fontSize: '18px' };
+    const paddingTopBottom54 = {'paddingTop': '6px', 'paddingBottom': '5px'};
+    const paddingBottom6 = {'paddingBottom': '7px'};
+    const fontSize18 = {'fontSize': '18px'};
 
     return [
-      <Button
-        key="nav-item-bold"
-        bsSize="small"
-        title="Bold"
-        onClick={this.createReplaceSelectionHandler('**', '**')}
-      >
-        <i className="fa fa-bold" />
+      <Button key='nav-item-bold' bsSize="small" title={'Bold'}
+              onClick={ this.createReplaceSelectionHandler('**', '**') }>
+        <i className={'fa fa-bold'}></i>
       </Button>,
-      <Button
-        key="nav-item-italic"
-        bsSize="small"
-        title="Italic"
-        onClick={this.createReplaceSelectionHandler('*', '*')}
-      >
-        <i className="fa fa-italic" />
+      <Button key='nav-item-italic' bsSize="small" title={'Italic'}
+              onClick={ this.createReplaceSelectionHandler('*', '*') }>
+        <i className={'fa fa-italic'}></i>
       </Button>,
-      <Button
-        key="nav-item-strikethough"
-        bsSize="small"
-        title="Strikethrough"
-        onClick={this.createReplaceSelectionHandler('~~', '~~')}
-      >
-        <i className="fa fa-strikethrough" />
+      <Button key='nav-item-strikethough' bsSize="small" title={'Strikethrough'}
+              onClick={ this.createReplaceSelectionHandler('~~', '~~') }>
+        <i className={'fa fa-strikethrough'}></i>
       </Button>,
-      <Button
-        key="nav-item-header"
-        bsSize="small"
-        title="Heading"
-        onClick={this.makeHeaderHandler}
-      >
-        <i className="fa fa-header" />
+      <Button key='nav-item-header' bsSize="small" title={'Heading'}
+              onClick={ this.makeHeaderHandler }>
+        <i className={'fa fa-header'}></i>
       </Button>,
-      <Button
-        key="nav-item-code"
-        bsSize="small"
-        title="Inline Code"
-        onClick={this.createReplaceSelectionHandler('`', '`')}
-      >
-        <i className="fa fa-code" />
+      <Button key='nav-item-code' bsSize="small" title={'Inline Code'}
+              onClick={ this.createReplaceSelectionHandler('`', '`') }>
+        <i className={'fa fa-code'}></i>
       </Button>,
-      <Button
-        key="nav-item-quote"
-        bsSize="small"
-        title="Quote"
-        onClick={this.createAddPrefixToEachLinesHandler('> ')}
-        style={paddingBottom6}
-      >
-        <i className="ti-quote-right" />
+      <Button key='nav-item-quote' bsSize="small" title={'Quote'}
+              onClick={ this.createAddPrefixToEachLinesHandler('> ') } style={paddingBottom6}>
+        <i className={'ti-quote-right'}></i>
       </Button>,
-      <Button
-        key="nav-item-ul"
-        bsSize="small"
-        title="List"
-        onClick={this.createAddPrefixToEachLinesHandler('- ')}
-        style={paddingTopBottom54}
-      >
-        <i className="ti-list" style={fontSize18} />
+      <Button key='nav-item-ul' bsSize="small" title={'List'}
+              onClick={ this.createAddPrefixToEachLinesHandler('- ') } style={paddingTopBottom54}>
+        <i className={'ti-list'} style={fontSize18}></i>
       </Button>,
-      <Button
-        key="nav-item-ol"
-        bsSize="small"
-        title="Numbered List"
-        onClick={this.createAddPrefixToEachLinesHandler('1. ')}
-        style={paddingTopBottom54}
-      >
-        <i className="ti-list-ol" style={fontSize18} />
+      <Button key='nav-item-ol' bsSize="small" title={'Numbered List'}
+              onClick={ this.createAddPrefixToEachLinesHandler('1. ') } style={paddingTopBottom54}>
+        <i className={'ti-list-ol'} style={fontSize18}></i>
       </Button>,
-      <Button
-        key="nav-item-checkbox"
-        bsSize="small"
-        title="Check List"
-        onClick={this.createAddPrefixToEachLinesHandler('- [ ] ')}
-        style={paddingBottom6}
-      >
-        <i className="ti-check-box" />
+      <Button key='nav-item-checkbox' bsSize="small" title={'Check List'}
+              onClick={ this.createAddPrefixToEachLinesHandler('- [ ] ') } style={paddingBottom6}>
+        <i className={'ti-check-box'}></i>
       </Button>,
-      <Button
-        key="nav-item-link"
-        bsSize="small"
-        title="Link"
-        onClick={this.createReplaceSelectionHandler('[', ']()')}
-        style={paddingBottom6}
-      >
-        <i className="icon-link" />
+      <Button key='nav-item-link' bsSize="small" title={'Link'}
+              onClick={ this.createReplaceSelectionHandler('[', ']()') } style={paddingBottom6}>
+        <i className={'icon-link'}></i>
       </Button>,
-      <Button
-        key="nav-item-image"
-        bsSize="small"
-        title="Image"
-        onClick={this.createReplaceSelectionHandler('![', ']()')}
-        style={paddingBottom6}
-      >
-        <i className="icon-picture" />
+      <Button key='nav-item-image' bsSize="small" title={'Image'}
+              onClick={ this.createReplaceSelectionHandler('![', ']()') } style={paddingBottom6}>
+        <i className={'icon-picture'}></i>
       </Button>,
-      <Button
-        key="nav-item-table"
-        bsSize="small"
-        title="Table"
-        onClick={this.showHandsonTableHandler}
-      >
+      <Button key='nav-item-table' bsSize="small" title={'Table'}
+              onClick={ this.showHandsonTableHandler }>
         <img src="/images/icons/editor/table.svg" width="14" height="14" />
-      </Button>,
+      </Button>
     ];
   }
 
@@ -748,51 +688,50 @@ Markdown
 
     const placeholder = this.state.isGfmMode ? 'Input with Markdown..' : 'Input with Plane Text..';
 
-    return (
-      <React.Fragment>
+    return <React.Fragment>
 
-        <ReactCodeMirror
-          ref="cm"
-          className={additionalClasses}
-          placeholder="search"
-          editorDidMount={(editor) => {
+      <ReactCodeMirror
+        ref="cm"
+        className={additionalClasses}
+        placeholder="search"
+        editorDidMount={(editor) => {
           // add event handlers
           editor.on('paste', this.pasteHandler);
           editor.on('scrollCursorIntoView', this.scrollCursorIntoViewHandler);
         }}
-          value={this.state.value}
-          options={{
-          mode,
+        value={this.state.value}
+        options={{
+          mode: mode,
           theme: editorOptions.theme,
           styleActiveLine: editorOptions.styleActiveLine,
           lineNumbers: this.props.lineNumbers,
           tabSize: 4,
           indentUnit: 4,
           lineWrapping: true,
-          autoRefresh: { force: true }, // force option is enabled by autorefresh.ext.js -- Yuki Takei
+          autoRefresh: {force: true},   // force option is enabled by autorefresh.ext.js -- Yuki Takei
           autoCloseTags: true,
-          placeholder,
+          placeholder: placeholder,
           matchBrackets: true,
-          matchTags: { bothTags: true },
+          matchTags: {bothTags: true},
           // folding
           foldGutter: this.props.lineNumbers,
           gutters: this.props.lineNumbers ? ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'] : [],
           // match-highlighter, matchesonscrollbar, annotatescrollbar options
-          highlightSelectionMatches: { annotateScrollbar: true },
+          highlightSelectionMatches: {annotateScrollbar: true},
           // markdown mode options
           highlightFormatting: true,
           // continuelist, indentlist
           extraKeys: {
-            Enter: this.handleEnterKey,
+            'Enter': this.handleEnterKey,
             'Ctrl-Enter': this.handleCtrlEnterKey,
             'Cmd-Enter': this.handleCtrlEnterKey,
-            Tab: 'indentMore',
+            'Tab': 'indentMore',
             'Shift-Tab': 'indentLess',
             'Ctrl-Q': (cm) => { cm.foldCode(cm.getCursor()) },
-          },
+          }
         }}
-          onCursor={this.cursorHandler}
-          onScroll={(editor, data) => {
+        onCursor={this.cursorHandler}
+        onScroll={(editor, data) => {
           if (this.props.onScroll != null) {
             // add line data
             const line = editor.lineAtHeight(data.top, 'local');
@@ -800,25 +739,25 @@ Markdown
             this.props.onScroll(data);
           }
         }}
-          onChange={this.changeHandler}
-          onDragEnter={(editor, event) => {
+        onChange={this.changeHandler}
+        onDragEnter={(editor, event) => {
           if (this.props.onDragEnter != null) {
             this.props.onDragEnter(event);
           }
         }}
-        />
+      />
 
-        { this.renderLoadingKeymapOverlay() }
+      { this.renderLoadingKeymapOverlay() }
 
-        <div className="overlay overlay-gfm-cheatsheet mt-1 p-3 pt-3">
-          { this.state.isSimpleCheatsheetShown && this.renderSimpleCheatsheet() }
-          { this.state.isCheatsheetModalButtonShown && this.renderCheatsheetModalButton() }
-        </div>
+      <div className="overlay overlay-gfm-cheatsheet mt-1 p-3 pt-3">
+        { this.state.isSimpleCheatsheetShown && this.renderSimpleCheatsheet() }
+        { this.state.isCheatsheetModalButtonShown && this.renderCheatsheetModalButton() }
+      </div>
 
-        <HandsontableModal ref="handsontableModal" onSave={(table) => { return mtu.replaceFocusedMarkdownTableWithEditor(this.getCodeMirror(), table) }} />
-      </React.Fragment>
-    );
+      <HandsontableModal ref='handsontableModal' onSave={ table => mtu.replaceFocusedMarkdownTableWithEditor(this.getCodeMirror(), table) }/>
+    </React.Fragment>;
   }
+
 }
 
 CodeMirrorEditor.propTypes = Object.assign({

+ 14 - 10
src/client/js/components/PageEditor/EmojiAutoCompleteHelper.js

@@ -1,6 +1,7 @@
 import UpdateDisplayUtil from '../../util/codemirror/update-display-util.ext';
 
 class EmojiAutoCompleteHelper {
+
   constructor(emojiStrategy) {
     this.emojiStrategy = emojiStrategy;
 
@@ -13,7 +14,7 @@ class EmojiAutoCompleteHelper {
   }
 
   initEmojiImageMap() {
-    for (const unicode in this.emojiStrategy) {
+    for (let unicode in this.emojiStrategy) {
       const data = this.emojiStrategy[unicode];
       const shortname = data.shortname;
       // add image tag
@@ -61,7 +62,7 @@ class EmojiAutoCompleteHelper {
       // closeOnUnfocus: false,  // for debug
       hint: () => {
         const matched = editor.getDoc().getRange(sc.from(), sc.to());
-        const term = matched.replace(':', ''); // remove ':' in the head
+        const term = matched.replace(':', '');  // remove ':' in the head
 
         // get a list of shortnames
         const shortnames = this.searchEmojiShortnames(term);
@@ -86,9 +87,10 @@ class EmojiAutoCompleteHelper {
         text: shortname,
         className: 'crowi-emoji-autocomplete',
         render: (element) => {
-          element.innerHTML = `<div class="img-container">${this.emojiShortnameImageMap[shortname]}</div>`
-            + `<span class="shortname-container">${shortname}</span>`;
-        },
+          element.innerHTML =
+            `<div class="img-container">${this.emojiShortnameImageMap[shortname]}</div>` +
+            `<span class="shortname-container">${shortname}</span>`;
+        }
       };
     });
   }
@@ -101,15 +103,16 @@ class EmojiAutoCompleteHelper {
   searchEmojiShortnames(term) {
     const maxLength = 12;
 
-    const results1 = []; const results2 = []; const results3 = []; const
-      results4 = [];
+    let results1 = [], results2 = [], results3 = [], results4 = [];
     const countLen1 = () => { results1.length };
     const countLen2 = () => { countLen1() + results2.length };
     const countLen3 = () => { countLen2() + results3.length };
     const countLen4 = () => { countLen3() + results4.length };
     // TODO performance tune
     // when total length of all results is less than `maxLength`
-    for (const data of this.emojiStrategy) {
+    for (let unicode in this.emojiStrategy) {
+      const data = this.emojiStrategy[unicode];
+
       if (maxLength <= countLen1()) { break }
       // prefix match to shortname
       else if (data.shortname.indexOf(`:${term}`) > -1) {
@@ -124,13 +127,13 @@ class EmojiAutoCompleteHelper {
       }
       else if (maxLength <= countLen3()) { continue }
       // partial match to elements of aliases
-      else if ((data.aliases != null) && data.aliases.find((elem) => { return elem.indexOf(term) > -1 })) {
+      else if ((data.aliases != null) && data.aliases.find(elem => elem.indexOf(term) > -1)) {
         results3.push(data.shortname);
         continue;
       }
       else if (maxLength <= countLen4()) { continue }
       // partial match to elements of keywords
-      else if ((data.keywords != null) && data.keywords.find((elem) => { return elem.indexOf(term) > -1 })) {
+      else if ((data.keywords != null) && data.keywords.find(elem => elem.indexOf(term) > -1)) {
         results4.push(data.shortname);
       }
     }
@@ -140,6 +143,7 @@ class EmojiAutoCompleteHelper {
 
     return results;
   }
+
 }
 
 export default EmojiAutoCompleteHelper;

+ 4 - 1
src/client/js/components/PageEditor/MarkdownListUtil.js

@@ -2,6 +2,7 @@
  * Utility for markdown list
  */
 class MarkdownListUtil {
+
   constructor() {
     // https://github.com/codemirror/CodeMirror/blob/c7853a989c77bb9f520c9c530cbe1497856e96fc/addon/edit/continuelist.js#L14
     // https://regex101.com/r/7BN2fR/5
@@ -87,7 +88,7 @@ class MarkdownListUtil {
     // not listful data
     else {
       // append `indentAndMark` at the beginning of all lines (except the first line)
-      const replacedText = text.replace(/(\r\n|\r|\n)/g, `$1${indentAndMark}`);
+      const replacedText = text.replace(/(\r\n|\r|\n)/g, '$1' + indentAndMark);
       // append `indentAndMark` to the first line
       adjusted = indentAndMark + replacedText;
     }
@@ -117,11 +118,13 @@ class MarkdownListUtil {
       // ensure to be true if it is 50% or more
       if (count >= lines.length / 2) {
         isListful = true;
+        return;
       }
     });
 
     return isListful;
   }
+
 }
 
 // singleton pattern

+ 3 - 2
src/client/js/components/PageEditor/MarkdownTableInterceptor.js

@@ -7,6 +7,7 @@ import MarkdownTable from '../../models/MarkdownTable';
  * Interceptor for markdown table
  */
 export default class MarkdownTableInterceptor extends BasicInterceptor {
+
   constructor() {
     super();
   }
@@ -31,8 +32,8 @@ export default class MarkdownTableInterceptor extends BasicInterceptor {
    * @inheritdoc
    */
   process(contextName, ...args) {
-    const context = Object.assign(args[0]); // clone
-    const editor = context.editor; // AbstractEditor instance
+    const context = Object.assign(args[0]);   // clone
+    const editor = context.editor;            // AbstractEditor instance
 
     // do nothing if editor is not a CodeMirrorEditor
     if (editor == null || editor.getCodeMirror() == null) {

+ 8 - 7
src/client/js/components/PageEditor/MarkdownTableUtil.js

@@ -4,11 +4,12 @@ import MarkdownTable from '../../models/MarkdownTable';
  * Utility for markdown table
  */
 class MarkdownTableUtil {
+
   constructor() {
     // https://github.com/markdown-it/markdown-it/blob/d29f421927e93e88daf75f22089a3e732e195bd2/lib/rules_block/table.js#L83
     // https://regex101.com/r/7BN2fR/7
     this.tableAlignmentLineRE = /^[-:|][-:|\s]*$/;
-    this.tableAlignmentLineNegRE = /^[^-:]*$/; // it is need to check to ignore empty row which is matched above RE
+    this.tableAlignmentLineNegRE = /^[^-:]*$/;  // it is need to check to ignore empty row which is matched above RE
     this.linePartOfTableRE = /^\|[^\r\n]*|[^\r\n]*\|$|([^|\r\n]+\|[^|\r\n]*)+/; // own idea
 
     this.getBot = this.getBot.bind(this);
@@ -28,7 +29,7 @@ class MarkdownTableUtil {
   getBot(editor) {
     const curPos = editor.getCursor();
     if (!this.isInTable(editor)) {
-      return { line: curPos.line, ch: curPos.ch };
+      return { line: curPos.line, ch: curPos.ch};
     }
 
     const firstLine = editor.getDoc().firstLine();
@@ -50,7 +51,7 @@ class MarkdownTableUtil {
   getEot(editor) {
     const curPos = editor.getCursor();
     if (!this.isInTable(editor)) {
-      return { line: curPos.line, ch: curPos.ch };
+      return { line: curPos.line, ch: curPos.ch};
     }
 
     const lastLine = editor.getDoc().lastLine();
@@ -126,8 +127,8 @@ class MarkdownTableUtil {
    */
   addRowToMarkdownTable(mdtable) {
     const numCol = mdtable.table.length > 0 ? mdtable.table[0].length : 1;
-    const newRow = [];
-    (new Array(numCol)).forEach(() => { return newRow.push('') }); // create cols
+    let newRow = [];
+    (new Array(numCol)).forEach(() => newRow.push('')); // create cols
     mdtable.table.push(newRow);
   }
 
@@ -175,11 +176,11 @@ class MarkdownTableUtil {
 
     let newMarkdown = '';
     if (markdownBeforeTable.length > 0) {
-      newMarkdown += `${markdownBeforeTable.join('\n')}\n`;
+      newMarkdown += markdownBeforeTable.join('\n') + '\n';
     }
     newMarkdown += table;
     if (markdownAfterTable.length > 0) {
-      newMarkdown += `\n${markdownAfterTable.join('\n')}`;
+      newMarkdown += '\n' + markdownAfterTable.join('\n');
     }
 
     return newMarkdown;

+ 31 - 47
src/client/js/components/PageEditor/OptionsSelector.js

@@ -10,6 +10,7 @@ import Dropdown from 'react-bootstrap/es/Dropdown';
 import MenuItem from 'react-bootstrap/es/MenuItem';
 
 class OptionsSelector extends React.Component {
+
   constructor(props) {
     super(props);
 
@@ -24,7 +25,7 @@ class OptionsSelector extends React.Component {
     };
 
     this.availableThemes = [
-      'eclipse', 'elegant', 'neo', 'mdn-like', 'material', 'dracula', 'monokai', 'twilight',
+      'eclipse', 'elegant', 'neo', 'mdn-like', 'material', 'dracula', 'monokai', 'twilight'
     ];
     this.keymapModes = {
       default: 'Default',
@@ -51,8 +52,8 @@ class OptionsSelector extends React.Component {
 
   onChangeTheme() {
     const newValue = this.themeSelectorInputEl.value;
-    const newOpts = Object.assign(this.state.editorOptions, { theme: newValue });
-    this.setState({ editorOptions: newOpts });
+    const newOpts = Object.assign(this.state.editorOptions, {theme: newValue});
+    this.setState({editorOptions: newOpts});
 
     // dispatch event
     this.dispatchOnChange();
@@ -60,8 +61,8 @@ class OptionsSelector extends React.Component {
 
   onChangeKeymapMode() {
     const newValue = this.keymapModeSelectorInputEl.value;
-    const newOpts = Object.assign(this.state.editorOptions, { keymapMode: newValue });
-    this.setState({ editorOptions: newOpts });
+    const newOpts = Object.assign(this.state.editorOptions, {keymapMode: newValue});
+    this.setState({editorOptions: newOpts});
 
     // dispatch event
     this.dispatchOnChange();
@@ -72,8 +73,8 @@ class OptionsSelector extends React.Component {
     this._cddForceOpen = true;
 
     const newValue = !this.state.editorOptions.styleActiveLine;
-    const newOpts = Object.assign(this.state.editorOptions, { styleActiveLine: newValue });
-    this.setState({ editorOptions: newOpts });
+    const newOpts = Object.assign(this.state.editorOptions, {styleActiveLine: newValue});
+    this.setState({editorOptions: newOpts});
 
     // dispatch event
     this.dispatchOnChange();
@@ -84,8 +85,8 @@ class OptionsSelector extends React.Component {
     this._cddForceOpen = true;
 
     const newValue = !this.state.previewOptions.renderMathJaxInRealtime;
-    const newOpts = Object.assign(this.state.previewOptions, { renderMathJaxInRealtime: newValue });
-    this.setState({ previewOptions: newOpts });
+    const newOpts = Object.assign(this.state.previewOptions, {renderMathJaxInRealtime: newValue});
+    this.setState({previewOptions: newOpts});
 
     // dispatch event
     this.dispatchOnChange();
@@ -121,14 +122,9 @@ class OptionsSelector extends React.Component {
     return (
       <FormGroup controlId="formControlsSelect" className="my-0">
         <ControlLabel>Theme:</ControlLabel>
-        <FormControl
-          componentClass="select"
-          placeholder="select"
-          bsClass={bsClassName}
-          className="btn-group-sm selectpicker"
-          onChange={this.onChangeTheme}
-          inputRef={(el) => { return this.themeSelectorInputEl = el }}
-        >
+        <FormControl componentClass="select" placeholder="select" bsClass={bsClassName} className="btn-group-sm selectpicker"
+            onChange={this.onChangeTheme}
+            inputRef={ el => this.themeSelectorInputEl=el }>
 
           {optionElems}
 
@@ -139,13 +135,13 @@ class OptionsSelector extends React.Component {
 
   renderKeymapModeSelector() {
     const optionElems = [];
-    for (const mode in this.keymapModes) {
+    for (let mode in this.keymapModes) {
       const label = this.keymapModes[mode];
       const dataContent = (mode === 'default')
         ? label
         : `<img src='/images/icons/${mode}.png' width='16px' class='m-r-5'></img> ${label}`;
       optionElems.push(
-        <option key={mode} value={mode} data-content={dataContent}>{label}</option>,
+        <option key={mode} value={mode} data-content={dataContent}>{label}</option>
       );
     }
 
@@ -154,14 +150,9 @@ class OptionsSelector extends React.Component {
     return (
       <FormGroup controlId="formControlsSelect" className="my-0">
         <ControlLabel>Keymap:</ControlLabel>
-        <FormControl
-          componentClass="select"
-          placeholder="select"
-          bsClass={bsClassName}
-          className="btn-group-sm selectpicker"
-          onChange={this.onChangeKeymapMode}
-          inputRef={(el) => { return this.keymapModeSelectorInputEl = el }}
-        >
+        <FormControl componentClass="select" placeholder="select" bsClass={bsClassName} className="btn-group-sm selectpicker"
+            onChange={this.onChangeKeymapMode}
+            inputRef={ el => this.keymapModeSelectorInputEl=el }>
 
           {optionElems}
 
@@ -174,16 +165,11 @@ class OptionsSelector extends React.Component {
     return (
       <FormGroup controlId="formControlsSelect" className="my-0">
 
-        <Dropdown
-          dropup
-          id="configurationDropdown"
-          className="configuration-dropdown"
-          open={this.state.isCddMenuOpened}
-          onToggle={this.onToggleConfigurationDropdown}
-        >
+        <Dropdown dropup id="configurationDropdown" className="configuration-dropdown"
+            open={this.state.isCddMenuOpened} onToggle={this.onToggleConfigurationDropdown}>
 
           <Dropdown.Toggle bsSize="sm">
-            <i className="icon-settings" />
+            <i className="icon-settings"></i>
           </Dropdown.Toggle>
 
           <Dropdown.Menu>
@@ -210,9 +196,9 @@ class OptionsSelector extends React.Component {
 
     return (
       <MenuItem onClick={this.onClickStyleActiveLine}>
-        <span className="icon-container" />
+        <span className="icon-container"></span>
         <span className="menuitem-label">{ t('page_edit.Show active line') }</span>
-        <span className="icon-container"><i className={iconClassName} /></span>
+        <span className="icon-container"><i className={iconClassName}></i></span>
       </MenuItem>
     );
   }
@@ -233,21 +219,19 @@ class OptionsSelector extends React.Component {
 
     return (
       <MenuItem onClick={this.onClickRenderMathJaxInRealtime}>
-        <span className="icon-container"><img src="/images/icons/fx.svg" width="14px" /></span>
+        <span className="icon-container"><img src="/images/icons/fx.svg" width="14px"></img></span>
         <span className="menuitem-label">MathJax Rendering</span>
-        <i className={iconClassName} />
+        <i className={iconClassName}></i>
       </MenuItem>
     );
   }
 
   render() {
-    return (
-      <div className="d-flex flex-row">
-        <span className="m-l-5">{this.renderThemeSelector()}</span>
-        <span className="m-l-5">{this.renderKeymapModeSelector()}</span>
-        <span className="m-l-5">{this.renderConfigurationDropdown()}</span>
-      </div>
-    );
+    return <div className="d-flex flex-row">
+      <span className="m-l-5">{this.renderThemeSelector()}</span>
+      <span className="m-l-5">{this.renderKeymapModeSelector()}</span>
+      <span className="m-l-5">{this.renderConfigurationDropdown()}</span>
+    </div>;
   }
 }
 
@@ -270,7 +254,7 @@ export class PreviewOptions {
 }
 
 OptionsSelector.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
+  t: PropTypes.func.isRequired,               // i18next
   crowi: PropTypes.object.isRequired,
   editorOptions: PropTypes.instanceOf(EditorOptions).isRequired,
   previewOptions: PropTypes.instanceOf(PreviewOptions).isRequired,

+ 1 - 1
src/client/js/components/PageEditor/PasteHelper.js

@@ -3,6 +3,7 @@ import accepts from 'attr-accept';
 import markdownListUtil from './MarkdownListUtil';
 
 class PasteHelper {
+
   constructor() {
     this.pasteText = this.pasteText.bind(this);
   }
@@ -34,7 +35,6 @@ class PasteHelper {
   fileAccepted(file, accept) {
     return file.type === 'application/x-moz-file' || accepts(file, accept);
   }
-
   /**
    * transplanted from react-dropzone
    * @see https://github.com/react-dropzone/react-dropzone/blob/master/src/utils/index.js

+ 3 - 2
src/client/js/components/PageEditor/PreventMarkdownListInterceptor.js

@@ -2,6 +2,7 @@ import { BasicInterceptor } from 'growi-pluginkit';
 import mlu from './MarkdownListUtil';
 
 export default class PreventMarkdownListInterceptor extends BasicInterceptor {
+
   constructor() {
     super();
   }
@@ -26,8 +27,8 @@ export default class PreventMarkdownListInterceptor extends BasicInterceptor {
    * @inheritdoc
    */
   process(contextName, ...args) {
-    const context = Object.assign(args[0]); // clone
-    const editor = context.editor; // AbstractEditor instance
+    const context = Object.assign(args[0]);   // clone
+    const editor = context.editor;            // AbstractEditor instance
 
     // get strings from current position to EOL(end of line) before break the line
     const strToEol = editor.getStrToEol();

+ 6 - 7
src/client/js/components/PageEditor/Preview.js

@@ -9,6 +9,7 @@ import { PreviewOptions } from './OptionsSelector';
  * Wrapper component for Page/RevisionBody
  */
 export default class Preview extends React.Component {
+
   constructor(props) {
     super(props);
   }
@@ -17,18 +18,16 @@ export default class Preview extends React.Component {
     const renderMathJaxInRealtime = this.props.previewOptions.renderMathJaxInRealtime;
 
     return (
-      <div
-        className="page-editor-preview-body"
-        ref={(elm) => {
+      <div className="page-editor-preview-body"
+          ref={(elm) => {
             this.previewElement = elm;
             this.props.inputRef(elm);
           }}
-        onScroll={(event) => {
+          onScroll={(event) => {
             if (this.props.onScroll != null) {
               this.props.onScroll(event.target.scrollTop);
             }
-          }}
-      >
+          }}>
 
         <RevisionBody
           {...this.props}
@@ -41,7 +40,7 @@ export default class Preview extends React.Component {
 
 Preview.propTypes = {
   html: PropTypes.string,
-  inputRef: PropTypes.func.isRequired, // for getting div element
+  inputRef: PropTypes.func.isRequired,  // for getting div element
   isMathJaxEnabled: PropTypes.bool,
   renderMathJaxOnInit: PropTypes.bool,
   previewOptions: PropTypes.instanceOf(PreviewOptions),

+ 9 - 8
src/client/js/components/PageEditor/ScrollSyncHelper.js

@@ -3,6 +3,7 @@
  * @see https://github.com/Microsoft/vscode/blob/0532a3429a18688a0c086a4212e7e5b4888b2a48/extensions/markdown/media/main.js
  */
 class ScrollSyncHelper {
+
   /**
 	 * @typedef {{ element: Element, line: number }} CodeLineElement
 	 */
@@ -16,12 +17,11 @@ class ScrollSyncHelper {
     if (!elements) {
       elements = Array.prototype.map.call(
         parentElement.getElementsByClassName('code-line'),
-        (element) => {
+        element => {
           const line = +element.getAttribute('data-line');
           return { element, line };
-        },
-      )
-        .filter((x) => { return !isNaN(x.line) });
+        })
+        .filter(x => !isNaN(x.line));
     }
     return elements;
   }
@@ -44,7 +44,7 @@ class ScrollSyncHelper {
       if (entry.line === targetLine) {
         return { previous: entry, next: null };
       }
-      if (entry.line > targetLine) {
+      else if (entry.line > targetLine) {
         return { previous, next: entry };
       }
       previous = entry;
@@ -82,7 +82,7 @@ class ScrollSyncHelper {
     if (hi >= 1 && hiElement.element.getBoundingClientRect().top > position) {
       const loElement = lines[lo];
       const bounds = loElement.element.getBoundingClientRect();
-      const previous = { element: loElement.element, line: loElement.line };
+      let previous = { element: loElement.element, line: loElement.line };
       if (bounds.height > 0) {
         previous.line += (position - bounds.top) / (bounds.height);
       }
@@ -102,8 +102,9 @@ class ScrollSyncHelper {
         const betweenProgress = (offset - parentElement.scrollTop - previous.element.getBoundingClientRect().top) / (next.element.getBoundingClientRect().top - previous.element.getBoundingClientRect().top);
         return previous.line + betweenProgress * (next.line - previous.line);
       }
-
-      return previous.line;
+      else {
+        return previous.line;
+      }
     }
     return null;
   }

+ 13 - 52
src/client/js/components/PageEditor/SimpleCheatsheet.js

@@ -12,69 +12,30 @@ class SimpleCheatsheet extends React.Component {
           <div className="row">
             <div className="col-xs-6">
               <p>
-                #
-                {' '}
-                {t('sandbox.header_x', { index: '1' })}
-                <br />
-                ##
-                {' '}
-                {t('sandbox.header_x', { index: '2' })}
+                # {t('sandbox.header_x', {index: '1'})}<br />
+                ## {t('sandbox.header_x', {index: '2'})}
               </p>
+              <p><i>*{t('sandbox.italics')}*</i>&nbsp;&nbsp;<b>**{t('sandbox.bold')}**</b></p>
               <p>
-                <i>
-*
-                  {t('sandbox.italics')}
-*
-                </i>
-&nbsp;&nbsp;
-                <b>
-**
-                  {t('sandbox.bold')}
-**
-                </b>
-              </p>
-              <p>
-                [
-                {t('sandbox.link')}
-](http://..)
-                <br />
+                [{t('sandbox.link')}](http://..)<br />
                 [/Page1/ChildPage1]
               </p>
               <p>
-                ```javascript:index.js
-                <br />
-                writeCode();
-                <br />
+                ```javascript:index.js<br />
+                writeCode();<br />
                 ```
               </p>
             </div>
             <div className="col-xs-6">
               <p>
-                -
-                {' '}
-                {t('sandbox.unordered_list_x', { index: '1' })}
-                <br />
-                &nbsp;&nbsp;&nbsp;-
-                {' '}
-                {t('sandbox.unordered_list_x', { index: '1.1' })}
-                <br />
-                -
-                {' '}
-                {t('sandbox.unordered_list_x', { index: '2' })}
-                <br />
-                1.
-                {' '}
-                {t('sandbox.ordered_list_x', { index: '1' })}
-                <br />
-                1.
-                {' '}
-                {t('sandbox.ordered_list_x', { index: '2' })}
+                - {t('sandbox.unordered_list_x', {index: '1'})}<br />
+                &nbsp;&nbsp;&nbsp;- {t('sandbox.unordered_list_x', {index: '1.1'})}<br />
+                - {t('sandbox.unordered_list_x', {index: '2'})}<br />
+                1. {t('sandbox.ordered_list_x', {index: '1'})}<br />
+                1. {t('sandbox.ordered_list_x', {index: '2'})}
               </p>
               <hr />
-              <p>
-[ ][ ]
-                {t('sandbox.block_detail')}
-              </p>
+              <p>[ ][ ] {t('sandbox.block_detail')}</p>
             </div>
           </div>
         </div>
@@ -84,7 +45,7 @@ class SimpleCheatsheet extends React.Component {
 }
 
 SimpleCheatsheet.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
+  t: PropTypes.func.isRequired,               // i18next
 };
 
 export default translate()(SimpleCheatsheet);

+ 18 - 19
src/client/js/components/PageEditor/TextAreaEditor.js

@@ -13,6 +13,7 @@ import mlu from './MarkdownListUtil';
 import PreventMarkdownListInterceptor from './PreventMarkdownListInterceptor';
 
 export default class TextAreaEditor extends AbstractEditor {
+
   constructor(props) {
     super(props);
     this.logger = require('@alias/logger')('growi:PageEditor:TextAreaEditor');
@@ -85,11 +86,11 @@ export default class TextAreaEditor extends AbstractEditor {
     // scroll to bottom
     this.textarea.scrollTop = this.textarea.scrollHeight;
 
-    const lines = this.textarea.value.split('\n').slice(0, line + 1);
+    const lines = this.textarea.value.split('\n').slice(0, line+1);
     const pos = lines
-        .map((lineStr) => { return lineStr.length + 1 }) // correct length+1 of each lines
-        .reduce((a, x) => { return a += x }, 0) // sum
-        - 1; // -1
+        .map(lineStr => lineStr.length + 1) // correct length+1 of each lines
+        .reduce((a, x) => a += x, 0)        // sum
+        - 1;                                // -1
 
     this.textarea.setSelectionRange(pos, pos);
   }
@@ -148,13 +149,13 @@ export default class TextAreaEditor extends AbstractEditor {
 
   getBolPos() {
     const currentPos = this.textarea.selectionStart;
-    return this.textarea.value.lastIndexOf('\n', currentPos - 1) + 1;
+    return this.textarea.value.lastIndexOf('\n', currentPos-1) + 1;
   }
 
   getEolPos() {
     const currentPos = this.textarea.selectionStart;
     const pos = this.textarea.value.indexOf('\n', currentPos);
-    if (pos < 0) { // not found but EOF
+    if (pos < 0) {  // not found but EOF
       return this.textarea.value.length;
     }
     return pos;
@@ -196,7 +197,7 @@ export default class TextAreaEditor extends AbstractEditor {
     }
 
     const context = {
-      handlers: [], // list of handlers which process enter key
+      handlers: [],  // list of handlers which process enter key
       editor: this,
     };
 
@@ -239,23 +240,21 @@ export default class TextAreaEditor extends AbstractEditor {
   }
 
   render() {
-    return (
-      <React.Fragment>
-        <FormControl
-          componentClass="textarea"
-          className="textarea-editor"
-          inputRef={(ref) => { this.textarea = ref }}
-          defaultValue={this.state.value}
-          onChange={(e) => {
+    return <React.Fragment>
+      <FormControl
+        componentClass="textarea" className="textarea-editor"
+        inputRef={ref => { this.textarea = ref }}
+        defaultValue={this.state.value}
+        onChange={(e) => {
           if (this.props.onChange != null) {
             this.props.onChange(e.target.value);
           }
-        }}
-        />
-      </React.Fragment>
-    );
+        }} />
+    </React.Fragment>;
   }
+
 }
 
 TextAreaEditor.propTypes = Object.assign({
 }, AbstractEditor.propTypes);
+

+ 19 - 18
src/client/js/components/PageHistory.js

@@ -5,6 +5,7 @@ import { translate } from 'react-i18next';
 import PageRevisionList from './PageHistory/PageRevisionList';
 
 class PageHistory extends React.Component {
+
   constructor(props) {
     super(props);
 
@@ -21,13 +22,14 @@ class PageHistory extends React.Component {
     const pageId = this.props.pageId;
 
     if (!pageId) {
-      return;
+      return ;
     }
 
-    this.props.crowi.apiGet('/revisions.ids', { page_id: pageId })
-    .then((res) => {
+    this.props.crowi.apiGet('/revisions.ids', {page_id: pageId})
+    .then(res => {
+
       const rev = res.revisions;
-      const diffOpened = {};
+      let diffOpened = {};
       const lastId = rev.length - 1;
       res.revisions.map((revision, i) => {
         const user = this.props.crowi.findUserById(revision.author);
@@ -45,7 +47,7 @@ class PageHistory extends React.Component {
 
       this.setState({
         revisions: rev,
-        diffOpened,
+        diffOpened: diffOpened,
       });
 
       // load 0, and last default
@@ -58,14 +60,14 @@ class PageHistory extends React.Component {
       if (lastId !== 0 && lastId !== 1 && rev[lastId]) {
         this.fetchPageRevisionBody(rev[lastId]);
       }
-    }).catch((err) => {
+    }).catch(err => {
       // do nothing
     });
   }
 
   getPreviousRevision(currentRevision) {
     let cursor = null;
-    for (const revision of this.state.revisions) {
+    for (let revision of this.state.revisions) {
       if (cursor && cursor._id == currentRevision._id) {
         cursor = revision;
         break;
@@ -78,14 +80,12 @@ class PageHistory extends React.Component {
   }
 
   onDiffOpenClicked(revision) {
-    const diffOpened = this.state.diffOpened;
-
-
-    const revisionId = revision._id;
+    const diffOpened = this.state.diffOpened,
+      revisionId = revision._id;
 
     diffOpened[revisionId] = !(diffOpened[revisionId]);
     this.setState({
-      diffOpened,
+      diffOpened
     });
 
     this.fetchPageRevisionBody(revision);
@@ -94,12 +94,13 @@ class PageHistory extends React.Component {
 
   fetchPageRevisionBody(revision) {
     if (revision.body) {
-      return;
+      return ;
     }
 
     this.props.crowi.apiGet('/revisions.get',
-      { page_id: this.props.pageId, revision_id: revision._id })
-    .then((res) => {
+      { page_id: this.props.pageId, revision_id: revision._id}
+    )
+    .then(res => {
       if (res.ok) {
         this.setState({
           revisions: this.state.revisions.map((rev) => {
@@ -108,11 +109,11 @@ class PageHistory extends React.Component {
             }
 
             return rev;
-          }),
+          })
         });
       }
     })
-    .catch((err) => {
+    .catch(err => {
 
     });
   }
@@ -133,7 +134,7 @@ class PageHistory extends React.Component {
 }
 
 PageHistory.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
+  t: PropTypes.func.isRequired,               // i18next
   pageId: PropTypes.string,
   crowi: PropTypes.object.isRequired,
 };

+ 7 - 9
src/client/js/components/PageHistory/RevisionDiff.js

@@ -5,20 +5,18 @@ import { createPatch } from 'diff';
 import { Diff2Html } from 'diff2html';
 
 export default class RevisionDiff extends React.Component {
-  render() {
-    const currentRevision = this.props.currentRevision;
-
-
-    const previousRevision = this.props.previousRevision;
 
-
-    const revisionDiffOpened = this.props.revisionDiffOpened;
+  render() {
+    const currentRevision = this.props.currentRevision,
+      previousRevision = this.props.previousRevision,
+      revisionDiffOpened = this.props.revisionDiffOpened;
 
 
     let diffViewHTML = '';
     if (currentRevision.body
       && previousRevision.body
       && revisionDiffOpened) {
+
       let previousText = previousRevision.body;
       if (currentRevision._id == previousRevision._id) {
         previousText = '';
@@ -27,13 +25,13 @@ export default class RevisionDiff extends React.Component {
       const patch = createPatch(
         currentRevision.path,
         previousText,
-        currentRevision.body,
+        currentRevision.body
       );
 
       diffViewHTML = Diff2Html.getPrettyHtml(patch);
     }
 
-    const diffView = { __html: diffViewHTML };
+    const diffView = {__html: diffViewHTML};
     return <div className="revision-history-diff" dangerouslySetInnerHTML={diffView} />;
   }
 }

+ 3 - 2
src/client/js/components/PageList/ListView.js

@@ -4,15 +4,16 @@ import PropTypes from 'prop-types';
 import Page from './Page';
 
 export default class ListView extends React.Component {
+
   render() {
     const listView = this.props.pages.map((page) => {
-      return <Page page={page} key={`page-list:list-view:${page._id}`} />;
+      return <Page page={page} key={'page-list:list-view:' + page._id} />;
     });
 
     return (
       <div className="page-list">
         <ul className="page-list-ul page-list-ul-flat">
-          {listView}
+        {listView}
         </ul>
       </div>
     );

+ 4 - 2
src/client/js/components/PageList/Page.js

@@ -6,6 +6,7 @@ import PageListMeta from './PageListMeta';
 import PagePath from './PagePath';
 
 export default class Page extends React.Component {
+
   render() {
     const page = this.props.page;
     let link = this.props.linkTo;
@@ -14,7 +15,7 @@ export default class Page extends React.Component {
     }
 
     const styleFlex = {
-      flex: 1,
+      flex: 1
     };
 
     return (
@@ -24,7 +25,7 @@ export default class Page extends React.Component {
           <PagePath page={page} excludePathString={this.props.excludePathString} />
         </a>
         <PageListMeta page={page} />
-        <div style={styleFlex} />
+        <div style={styleFlex}></div>
         {this.props.children}
       </li>
     );
@@ -41,3 +42,4 @@ Page.defaultProps = {
   linkTo: '',
   excludePathString: '',
 };
+

+ 4 - 12
src/client/js/components/PageList/PageListMeta.js

@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
 import templateChecker from '@commons/util/template-checker';
 
 export default class PageListMeta extends React.Component {
+
   isPortalPath(path) {
     if (path.match(/.*\/$/)) {
       return true;
@@ -29,22 +30,12 @@ export default class PageListMeta extends React.Component {
 
     let commentCount;
     if (page.commentCount > 0) {
-      commentCount = (
-        <span>
-          <i className="icon-bubble" />
-          {page.commentCount}
-        </span>
-      );
+      commentCount = <span><i className="icon-bubble" />{page.commentCount}</span>;
     }
 
     let likerCount;
     if (page.liker.length > 0) {
-      likerCount = (
-        <span>
-          <i className="icon-like" />
-          {page.liker.length}
-        </span>
-      );
+      likerCount = <span><i className="icon-like" />{page.liker.length}</span>;
     }
 
     let locked;
@@ -71,3 +62,4 @@ PageListMeta.propTypes = {
 PageListMeta.defaultProps = {
   page: {},
 };
+

+ 6 - 8
src/client/js/components/PageList/PagePath.js

@@ -4,8 +4,9 @@ import PropTypes from 'prop-types';
 import escapeStringRegexp from 'escape-string-regexp';
 
 export default class PagePath extends React.Component {
+
   getShortPath(path) {
-    const name = path.replace(/(\/)$/, '');
+    let name = path.replace(/(\/)$/, '');
 
     // /.../hoge/YYYY/MM/DD 形式のページ
     if (name.match(/.+\/([^/]+\/\d{4}\/\d{2}\/\d{2})$/)) {
@@ -33,7 +34,7 @@ export default class PagePath extends React.Component {
     const shortPath = this.getShortPath(pagePath);
 
     const shortPathEscaped = escapeStringRegexp(shortPath);
-    const pathPrefix = pagePath.replace(new RegExp(`${shortPathEscaped}(/)?$`), '');
+    const pathPrefix = pagePath.replace(new RegExp(shortPathEscaped + '(/)?$'), '');
 
     let classNames = ['page-path'];
     classNames = classNames.concat(this.props.additionalClassNames);
@@ -41,13 +42,10 @@ export default class PagePath extends React.Component {
     if (isShortPathOnly) {
       return <span className={classNames.join(' ')}>{shortPath}</span>;
     }
+    else {
+      return <span className={classNames.join(' ')}>{pathPrefix}<strong>{shortPath}</strong></span>;
+    }
 
-    return (
-      <span className={classNames.join(' ')}>
-        {pathPrefix}
-        <strong>{shortPath}</strong>
-      </span>
-    );
   }
 }
 

+ 8 - 5
src/client/js/components/ReactUtils.js

@@ -1,6 +1,7 @@
 import React from 'react';
 
 export default class ReactUtils {
+
   /**
    * show '\n' as '<br>'
    *
@@ -13,13 +14,15 @@ export default class ReactUtils {
    * @memberOf ReactUtils
    */
   static nl2br(text) {
-    const regex = /(\n)/g;
-    return text.split(regex).map((line) => {
+    var regex = /(\n)/g;
+    return text.split(regex).map(function(line) {
       if (line.match(regex)) {
-        return React.createElement('br', { key: Math.random().toString(10).substr(2, 10) });
+        return React.createElement('br', {key: Math.random().toString(10).substr(2, 10)});
+      }
+      else {
+        return line;
       }
-
-      return line;
     });
   }
+
 }

+ 8 - 22
src/client/js/components/SearchForm.js

@@ -4,6 +4,7 @@ import SearchTypeahead from './SearchTypeahead';
 
 // SearchTypeahead wrapper
 export default class SearchForm extends React.Component {
+
   constructor(props) {
     super(props);
 
@@ -28,7 +29,7 @@ export default class SearchForm extends React.Component {
   }
 
   onChange(selected) {
-    const page = selected[0]; // should be single page selected
+    const page = selected[0];  // should be single page selected
 
     // navigate to page
     if (page != null) {
@@ -42,35 +43,20 @@ export default class SearchForm extends React.Component {
     return (
       <table className="table m-1 search-help">
         <caption className="text-left text-primary p-2 mb-2">
-          <h5 className="m-1">
-            <i className="icon-magnifier pr-2 mb-2" />
-            { t('search_help.title') }
-          </h5>
+          <h5 className="m-1"><i className="icon-magnifier pr-2 mb-2"/>{ t('search_help.title') }</h5>
         </caption>
         <tbody>
           <tr>
             <th className="text-right pt-2">
-              <code>word1</code>
-              {' '}
-              <code>word2</code>
-              <br />
-              <small>
-(
-                { t('search_help.and.syntax help') }
-)
-              </small>
+              <code>word1</code> <code>word2</code><br></br>
+              <small>({ t('search_help.and.syntax help') })</small>
             </th>
             <td><h6 className="m-0 pt-1">{ t('search_help.and.desc', { word1: 'word1', word2: 'word2' }) }</h6></td>
           </tr>
           <tr>
             <th className="text-right pt-2">
-              <code>"This is GROWI"</code>
-              <br />
-              <small>
-(
-                { t('search_help.phrase.syntax help') }
-)
-              </small>
+              <code>"This is GROWI"</code><br></br>
+              <small>({ t('search_help.phrase.syntax help') })</small>
             </th>
             <td><h6 className="m-0 pt-1">{ t('search_help.phrase.desc', { phrase: 'This is GROWI' }) }</h6></td>
           </tr>
@@ -114,7 +100,7 @@ export default class SearchForm extends React.Component {
 }
 
 SearchForm.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
+  t: PropTypes.func.isRequired,               // i18next
   crowi: PropTypes.object.isRequired,
   keyword: PropTypes.string,
   onSubmit: PropTypes.func.isRequired,

+ 17 - 21
src/client/js/components/SearchPage.js

@@ -7,15 +7,13 @@ import { translate } from 'react-i18next';
 import SearchPageForm from './SearchPage/SearchPageForm';
 import SearchResult from './SearchPage/SearchResult';
 
-/* global location */
-/* eslint no-restricted-globals: ['error', 'locaion'] */
-
 class SearchPage extends React.Component {
+
   constructor(props) {
     super(props);
 
     this.state = {
-      location,
+      location: location,
       searchingKeyword: this.props.query.q || '',
       searchedKeyword: '',
       searchedPages: [],
@@ -29,17 +27,17 @@ class SearchPage extends React.Component {
 
   componentDidMount() {
     const keyword = this.state.searchingKeyword;
-    if (keyword !== '') {
-      this.search({ keyword });
+    if (keyword !== '')  {
+      this.search({keyword});
     }
   }
 
   static getQueryByLocation(location) {
-    const search = location.search || '';
-    const query = {};
+    let search = location.search || '';
+    let query = {};
 
-    search.replace(/^\?/, '').split('&').forEach((element) => {
-      const queryParts = element.split('=');
+    search.replace(/^\?/, '').split('&').forEach(function(element) {
+      let queryParts = element.split('=');
       query[queryParts[0]] = decodeURIComponent(queryParts[1]).replace(/\+/g, ' ');
     });
 
@@ -74,8 +72,8 @@ class SearchPage extends React.Component {
       searchingKeyword: keyword,
     });
 
-    this.props.crowi.apiGet('/search', { q: keyword })
-    .then((res) => {
+    this.props.crowi.apiGet('/search', {q: keyword})
+    .then(res => {
       this.changeURL(keyword);
 
       this.setState({
@@ -83,7 +81,7 @@ class SearchPage extends React.Component {
         searchedPages: res.data,
         searchResultMeta: res.meta,
       });
-    }).catch((err) => {
+    }).catch(err => {
       // TODO error
       this.setState({
         searchError: err,
@@ -95,33 +93,31 @@ class SearchPage extends React.Component {
     return (
       <div>
         <div className="search-page-input">
-          <SearchPageForm
-            t={this.props.t}
+          <SearchPageForm t={this.props.t}
             crowi={this.props.crowi}
             onSearchFormChanged={this.search}
             keyword={this.state.searchingKeyword}
-          />
+            />
         </div>
         <SearchResult
-          crowi={this.props.crowi}
-          crowiRenderer={this.props.crowiRenderer}
+          crowi={this.props.crowi} crowiRenderer={this.props.crowiRenderer}
           pages={this.state.searchedPages}
           searchingKeyword={this.state.searchingKeyword}
           searchResultMeta={this.state.searchResultMeta}
-        />
+          />
       </div>
     );
   }
 }
 
 SearchPage.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
+  t: PropTypes.func.isRequired,               // i18next
   crowi: PropTypes.object.isRequired,
   crowiRenderer: PropTypes.object.isRequired,
   query: PropTypes.object,
 };
 SearchPage.defaultProps = {
-  // pollInterval: 1000,
+  //pollInterval: 1000,
   query: SearchPage.getQueryByLocation(location || {}),
   searchError: null,
 };

+ 7 - 8
src/client/js/components/SearchPage/DeletePageListModal.js

@@ -6,6 +6,7 @@ import Modal from 'react-bootstrap/es/Modal';
 import Checkbox from 'react-bootstrap/es/Checkbox';
 
 export default class DeletePageListModal extends React.Component {
+
   /*
    * the threshold for omitting body
    */
@@ -20,7 +21,7 @@ export default class DeletePageListModal extends React.Component {
 
   render() {
     if (this.props.pages === undefined || this.props.pages.length == 0) {
-      return <div />;
+      return <div></div>;
     }
 
     const listView = this.props.pages.map((page) => {
@@ -43,12 +44,9 @@ export default class DeletePageListModal extends React.Component {
           <div className="d-flex justify-content-between">
             <span className="text-danger">{this.props.errorMessage}</span>
             <span className="d-flex align-items-center">
-              <Checkbox className="text-danger" onClick={this.props.toggleDeleteCompletely} inline>Delete completely</Checkbox>
+              <Checkbox className="text-danger" onClick={this.props.toggleDeleteCompletely} inline={true}>Delete completely</Checkbox>
               <span className="m-l-10">
-                <Button onClick={this.props.confirmedToDelete}>
-                  <i className="icon-trash" />
-Delete
-                </Button>
+                <Button onClick={this.props.confirmedToDelete}><i className="icon-trash"></i>Delete</Button>
               </span>
             </span>
           </div>
@@ -56,13 +54,14 @@ Delete
       </Modal>
     );
   }
+
 }
 
 DeletePageListModal.propTypes = {
   isShown: PropTypes.bool.isRequired,
   pages: PropTypes.array,
   errorMessage: PropTypes.string,
-  cancel: PropTypes.func.isRequired, // for cancel evnet handling
-  confirmedToDelete: PropTypes.func.isRequired, // for confirmed event handling
+  cancel: PropTypes.func.isRequired,                 // for cancel evnet handling
+  confirmedToDelete: PropTypes.func.isRequired,      // for confirmed event handling
   toggleDeleteCompletely: PropTypes.func.isRequired, // for delete completely check event handling
 };

+ 20 - 22
src/client/js/components/SearchPage/SearchPageForm.js

@@ -9,6 +9,7 @@ import SearchForm from '../SearchForm';
 
 // Search.SearchForm
 export default class SearchPageForm extends React.Component {
+
   constructor(props) {
     super(props);
 
@@ -23,38 +24,35 @@ export default class SearchPageForm extends React.Component {
 
   search() {
     const keyword = this.state.keyword;
-    this.props.onSearchFormChanged({ keyword });
-    this.setState({ searchedKeyword: keyword });
+    this.props.onSearchFormChanged({keyword: keyword});
+    this.setState({searchedKeyword: keyword});
   }
 
   onInputChange(input) { // for only submitting with button
-    this.setState({ keyword: input });
+    this.setState({keyword: input});
   }
 
   render() {
-    return (
-      <FormGroup>
-        <InputGroup>
-          <SearchForm
-            t={this.props.t}
-            crowi={this.props.crowi}
-            onSubmit={this.search}
-            keyword={this.state.searchedKeyword}
-            onInputChange={this.onInputChange}
-          />
-          <InputGroup.Button className="">
-            <Button onClick={this.search}>
-              <i className="icon-magnifier" />
-            </Button>
-          </InputGroup.Button>
-        </InputGroup>
-      </FormGroup>
-    );
+    return <FormGroup>
+      <InputGroup>
+        <SearchForm t={this.props.t}
+          crowi={this.props.crowi}
+          onSubmit={this.search}
+          keyword={this.state.searchedKeyword}
+          onInputChange={this.onInputChange}
+        />
+        <InputGroup.Button className="">
+          <Button onClick={this.search}>
+            <i className="icon-magnifier"></i>
+          </Button >
+        </InputGroup.Button>
+      </InputGroup>
+    </FormGroup>;
   }
 }
 
 SearchPageForm.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
+  t: PropTypes.func.isRequired,               // i18next
   crowi: PropTypes.object.isRequired,
   keyword: PropTypes.string,
   onSearchFormChanged: PropTypes.func.isRequired,

+ 58 - 88
src/client/js/components/SearchPage/SearchResult.js

@@ -50,8 +50,8 @@ export default class SearchResult extends React.Component {
     else {
       this.state.selectedPages.add(page);
     }
-    this.setState({ isDeleteConfirmModalShown: false });
-    this.setState({ selectedPages: this.state.selectedPages });
+    this.setState({isDeleteConfirmModalShown: false});
+    this.setState({selectedPages: this.state.selectedPages});
   }
 
   /**
@@ -79,9 +79,8 @@ export default class SearchResult extends React.Component {
         this.state.selectedPages.add(page);
       });
     }
-    this.setState({ selectedPages: this.state.selectedPages });
+    this.setState({selectedPages: this.state.selectedPages});
   }
-
   /**
    * change deletion mode
    *
@@ -89,7 +88,7 @@ export default class SearchResult extends React.Component {
    */
   handleDeletionModeChange() {
     this.state.selectedPages.clear();
-    this.setState({ deletionMode: !this.state.deletionMode });
+    this.setState({deletionMode: !this.state.deletionMode});
   }
 
   /**
@@ -99,7 +98,7 @@ export default class SearchResult extends React.Component {
    */
   toggleDeleteCompletely() {
     // request で completely が undefined でないと指定アリと見なされるため
-    this.setState({ isDeleteCompletely: this.state.isDeleteCompletely ? undefined : true });
+    this.setState({isDeleteCompletely: this.state.isDeleteCompletely? undefined : true});
   }
 
   /**
@@ -108,23 +107,24 @@ export default class SearchResult extends React.Component {
    * @memberof SearchResult
    */
   deleteSelectedPages() {
-    const deleteCompletely = this.state.isDeleteCompletely;
+    let deleteCompletely = this.state.isDeleteCompletely;
     Promise.all(Array.from(this.state.selectedPages).map((page) => {
       return new Promise((resolve, reject) => {
         const pageId = page._id;
         const revisionId = page.revision._id;
-        this.props.crowi.apiPost('/pages.remove', { page_id: pageId, revision_id: revisionId, completely: deleteCompletely })
-          .then((res) => {
+        this.props.crowi.apiPost('/pages.remove', {page_id: pageId, revision_id: revisionId, completely: deleteCompletely})
+          .then(res => {
             if (res.ok) {
               this.state.selectedPages.delete(page);
               return resolve();
             }
-
-            return reject();
+            else {
+              return reject();
+            }
           })
-          .catch((err) => {
-            console.log(err.message); // eslint-disable-line no-console
-            this.setState({ errorMessageForDeleting: err.message });
+          .catch(err => {
+            console.log(err.message);   // eslint-disable-line no-console
+            this.setState({errorMessageForDeleting: err.message});
             return reject();
           });
       });
@@ -132,7 +132,7 @@ export default class SearchResult extends React.Component {
     .then(() => {
       window.location.reload();
     })
-    .catch((err) => {
+    .catch(err => {
       toastr.error(err, 'Error occured', {
         closeButton: true,
         progressBar: true,
@@ -150,7 +150,7 @@ export default class SearchResult extends React.Component {
    * @memberof SearchResult
    */
   showDeleteConfirmModal() {
-    this.setState({ isDeleteConfirmModalShown: true });
+    this.setState({isDeleteConfirmModalShown: true});
   }
 
   /**
@@ -168,14 +168,12 @@ export default class SearchResult extends React.Component {
   render() {
     const excludePathString = this.props.tree;
 
-    // console.log(this.props.searchError);
-    // console.log(this.isError());
+    //console.log(this.props.searchError);
+    //console.log(this.isError());
     if (this.isError()) {
       return (
         <div className="content-main">
-          <i className="searcing fa fa-warning" />
-          {' '}
-Error on searching.
+          <i className="searcing fa fa-warning"></i> Error on searching.
         </div>
       );
     }
@@ -191,78 +189,58 @@ Error on searching.
       }
       return (
         <div className="content-main">
-          <i className="icon-fw icon-info" />
-          {' '}
-No page found with &quot;
-          {this.props.searchingKeyword}
-&quot;
-          {under}
+            <i className="icon-fw icon-info" /> No page found with &quot;{this.props.searchingKeyword}&quot;{under}
         </div>
       );
+
     }
 
     let deletionModeButtons = '';
     let allSelectCheck = '';
 
     if (this.state.deletionMode) {
-      deletionModeButtons = (
-        <div className="btn-group">
-          <button type="button" className="btn btn-rounded btn-default btn-xs" onClick={() => { return this.handleDeletionModeChange() }}>
-            <i className="icon-ban" />
-            {' '}
-Cancel
-          </button>
-          <button type="button" className="btn btn-rounded btn-danger btn-xs" onClick={() => { return this.showDeleteConfirmModal() }} disabled={this.state.selectedPages.size == 0}>
-            <i className="icon-trash" />
-            {' '}
-Delete
-          </button>
-        </div>
-      );
-      allSelectCheck = (
-        <div>
-          <label>
-            <input
-              type="checkbox"
-              onClick={() => { return this.handleAllSelect() }}
-              checked={this.isAllSelected()}
-            />
+      deletionModeButtons =
+      <div className="btn-group">
+        <button type="button" className="btn btn-rounded btn-default btn-xs" onClick={() => this.handleDeletionModeChange()}>
+          <i className="icon-ban"/> Cancel
+        </button>
+        <button type="button" className="btn btn-rounded btn-danger btn-xs" onClick={() => this.showDeleteConfirmModal()} disabled={this.state.selectedPages.size == 0}>
+          <i className="icon-trash"/> Delete
+        </button>
+      </div>;
+      allSelectCheck =
+      <div>
+        <label>
+          <input
+            type="checkbox"
+            onClick={() => this.handleAllSelect()}
+            checked={this.isAllSelected()} />
             &nbsp;Check All
-          </label>
-        </div>
-      );
+        </label>
+      </div>;
     }
     else {
-      deletionModeButtons = (
-        <div className="btn-group">
-          <button type="button" className="btn btn-default btn-rounded btn-xs" onClick={() => { return this.handleDeletionModeChange() }}>
-            <i className="ti-check-box" />
-            {' '}
-DeletionMode
-          </button>
-        </div>
-      );
+      deletionModeButtons =
+      <div className="btn-group">
+        <button type="button" className="btn btn-default btn-rounded btn-xs" onClick={() => this.handleDeletionModeChange()}>
+          <i className="ti-check-box"/> DeletionMode
+        </button>
+      </div>;
     }
 
     const listView = this.props.pages.map((page) => {
-      const pageId = `#${page._id}`;
+      const pageId = '#' + page._id;
       return (
-        <Page
-          page={page}
+        <Page page={page}
           linkTo={pageId}
           key={page._id}
           excludePathString={excludePathString}
-        >
-          { this.state.deletionMode
-            && (
-            <input
-              type="checkbox"
-              className="search-result-list-delete-checkbox"
+          >
+          { this.state.deletionMode &&
+            <input type="checkbox" className="search-result-list-delete-checkbox"
               value={pageId}
               checked={this.state.selectedPages.has(page)}
-              onClick={() => { return this.toggleCheckbox(page) }}
-            />
-)
+              onClick={() => this.toggleCheckbox(page)} />
             }
           <div className="page-list-option">
             <a href={page.path}><i className="icon-login" /></a>
@@ -273,7 +251,7 @@ DeletionMode
 
     // TODO あとでなんとかする
     setTimeout(() => {
-      $('#search-result-list > nav').affix({ offset: { top: 50 } });
+      $('#search-result-list > nav').affix({ offset: { top: 50 }});
     }, 1200);
 
     /*
@@ -290,16 +268,9 @@ DeletionMode
                 {allSelectCheck}
               </div>
               <div className="search-result-meta">
-                <i className="icon-magnifier" />
-                {' '}
-Found
-                {this.props.searchResultMeta.total}
-                {' '}
-pages with &quot;
-                {this.props.searchingKeyword}
-&quot;
+                <i className="icon-magnifier" /> Found {this.props.searchResultMeta.total} pages with &quot;{this.props.searchingKeyword}&quot;
               </div>
-              <div className="clearfix" />
+              <div className="clearfix"></div>
               <div className="page-list">
                 <ul className="page-list-ul page-list-ul-flat nav">
                   {listView}
@@ -309,11 +280,10 @@ pages with &quot;
           </div>
           <div className="col-md-8 search-result-content" id="search-result-content">
             <SearchResultList
-              crowi={this.props.crowi}
-              crowiRenderer={this.props.crowiRenderer}
+              crowi={this.props.crowi} crowiRenderer={this.props.crowiRenderer}
               pages={this.props.pages}
               searchingKeyword={this.props.searchingKeyword}
-            />
+              />
           </div>
         </div>
         <DeletePageListModal
@@ -325,7 +295,7 @@ pages with &quot;
           toggleDeleteCompletely={this.toggleDeleteCompletely}
         />
 
-      </div>// content-main
+      </div>//content-main
     );
   }
 }
@@ -337,7 +307,7 @@ SearchResult.propTypes = {
   pages: PropTypes.array.isRequired,
   searchingKeyword: PropTypes.string.isRequired,
   searchResultMeta: PropTypes.object.isRequired,
-  searchError: PropTypes.object,
+  searchError: PropTypes.object
 };
 SearchResult.defaultProps = {
   tree: '',

+ 3 - 2
src/client/js/components/SearchPage/SearchResultList.js

@@ -6,10 +6,11 @@ import GrowiRenderer from '../../util/GrowiRenderer';
 import RevisionLoader from '../Page/RevisionLoader';
 
 export default class SearchResultList extends React.Component {
+
   constructor(props) {
     super(props);
 
-    this.growiRenderer = new GrowiRenderer(this.props.crowi, this.props.crowiRenderer, { mode: 'searchresult' });
+    this.growiRenderer = new GrowiRenderer(this.props.crowi, this.props.crowiRenderer, {mode: 'searchresult'});
   }
 
   render() {
@@ -31,7 +32,7 @@ export default class SearchResultList extends React.Component {
 
     return (
       <div>
-        {resultList}
+      {resultList}
       </div>
     );
   }

+ 17 - 14
src/client/js/components/SearchTypeahead.js

@@ -9,7 +9,9 @@ import PageListMeta from './PageList/PageListMeta';
 import PagePath from './PageList/PagePath';
 
 export default class SearchTypeahead extends React.Component {
+
   constructor(props) {
+
     super(props);
 
     this.state = {
@@ -58,6 +60,7 @@ export default class SearchTypeahead extends React.Component {
   }
 
   search(keyword) {
+
     if (keyword === '') {
       this.setState({
         keyword: '',
@@ -66,11 +69,11 @@ export default class SearchTypeahead extends React.Component {
       return;
     }
 
-    this.setState({ isLoading: true });
+    this.setState({isLoading: true});
 
-    this.crowi.apiGet('/search', { q: keyword })
-      .then((res) => { this.onSearchSuccess(res) })
-      .catch((err) => { this.onSearchError(err) });
+    this.crowi.apiGet('/search', {q: keyword})
+      .then(res => { this.onSearchSuccess(res) })
+      .catch(err => { this.onSearchError(err) });
   }
 
   /**
@@ -99,10 +102,10 @@ export default class SearchTypeahead extends React.Component {
   }
 
   onInputChange(text) {
-    this.setState({ input: text });
+    this.setState({input: text});
     this.props.onInputChange(text);
     if (text === '') {
-      this.setState({ pages: [] });
+      this.setState({pages: []});
     }
   }
 
@@ -138,9 +141,9 @@ export default class SearchTypeahead extends React.Component {
    * Get restore form button to initialize button
    */
   getRestoreFormButton() {
-    const isHidden = (this.state.input === this.props.keywordOnInit);
+    let isHidden = (this.state.input === this.props.keywordOnInit);
 
-    return isHidden ? <span /> : (
+    return isHidden ? <span></span> : (
       <button type="button" className="btn btn-link search-clear" onMouseDown={this.restoreInitialData}>
         <i className="icon-close" />
       </button>
@@ -151,16 +154,16 @@ export default class SearchTypeahead extends React.Component {
     const page = option;
     return (
       <span>
-        <UserPicture user={page.lastUpdateUser} size="sm" />
-        <PagePath page={page} />
-        <PageListMeta page={page} />
+      <UserPicture user={page.lastUpdateUser} size="sm" />
+      <PagePath page={page} />
+      <PageListMeta page={page} />
       </span>
     );
   }
 
   render() {
     const defaultSelected = (this.props.keywordOnInit != '')
-      ? [{ path: this.props.keywordOnInit }]
+      ? [{path: this.props.keywordOnInit}]
       : [];
     const inputProps = { autoComplete: 'off' };
     if (this.props.inputName != null) {
@@ -184,8 +187,8 @@ export default class SearchTypeahead extends React.Component {
               // DIRTY HACK
               //  note: The default searchText string has been shown wrongly even if isLoading is false
               //        since upgrade react-bootstrap-typeahead to v3.3.2 -- 2019.02.05 Yuki Takei
-          align="left"
-          submitFormOnEnter
+          align='left'
+          submitFormOnEnter={true}
           onSearch={this.search}
           onInputChange={this.onInputChange}
           onKeyDown={this.onKeyDown}

+ 6 - 16
src/client/js/components/User/User.js

@@ -4,9 +4,10 @@ import PropTypes from 'prop-types';
 import UserPicture from './UserPicture';
 
 export default class User extends React.Component {
+
   render() {
     const user = this.props.user;
-    const userLink = `/user/${user.username}`;
+    const userLink = '/user/' + user.username;
 
     const username = this.props.username;
     const name = this.props.name;
@@ -16,22 +17,11 @@ export default class User extends React.Component {
         <a href={userLink}>
           <UserPicture user={user} />
 
-          {username
-              && (
-              <span className="user-component-username">
-@
-                {user.username}
-              </span>
-)
+          {username &&
+              <span className="user-component-username">@{user.username}</span>
           }
-          {name
-              && (
-              <span className="user-component-name">
-(
-                {user.name}
-)
-              </span>
-)
+          {name &&
+              <span className="user-component-name">({user.name})</span>
           }
         </a>
       </span>

+ 9 - 7
src/client/js/components/User/UserPicture.js

@@ -4,20 +4,22 @@ import PropTypes from 'prop-types';
 
 // TODO UserComponent?
 export default class UserPicture extends React.Component {
+
   getUserPicture(user) {
     // gravatar
     if (user.isGravatarEnabled === true) {
       return this.generateGravatarSrc(user);
     }
     // uploaded image
-    if (user.image != null) {
+    else if (user.image != null) {
       return user.image;
     }
-    if (user.imageAttachment != null) {
+    else if (user.imageAttachment != null) {
       return user.imageAttachment.filePathProxied;
     }
-
-    return '/images/icons/user.svg';
+    else {
+      return '/images/icons/user.svg';
+    }
   }
 
   generateGravatarSrc(user) {
@@ -27,10 +29,10 @@ export default class UserPicture extends React.Component {
   }
 
   getClassName() {
-    const className = ['img-circle', 'picture'];
+    let className = ['img-circle', 'picture'];
     // size
     if (this.props.size) {
-      className.push(`picture-${this.props.size}`);
+      className.push('picture-' + this.props.size);
     }
 
     return className.join(' ');
@@ -44,7 +46,7 @@ export default class UserPicture extends React.Component {
         src={this.getUserPicture(user)}
         alt={user.username}
         className={this.getClassName()}
-      />
+        />
     );
   }
 }

+ 9 - 7
src/client/js/hackmd-agent.js

@@ -16,7 +16,7 @@ import { debounce } from 'throttle-debounce';
 
 /* eslint-disable no-console  */
 
-const allowedOrigin = '{{origin}}'; // will be replaced by swig
+const allowedOrigin = '{{origin}}';         // will be replaced by swig
 
 
 /**
@@ -45,6 +45,7 @@ function setValueToCodemirror(value) {
 function setValueToCodemirrorOnInit(newValue) {
   if (window.cmClient != null) {
     setValueToCodemirror(newValue);
+    return;
   }
   else {
     const intervalId = setInterval(() => {
@@ -85,7 +86,7 @@ function addEventListenersToCodemirror() {
     return;
   }
 
-  // // change event
+  //// change event
   editor.on('change', (cm, change) => {
     if (change.origin === 'ignoreHistory') {
       // do nothing because this operation triggered by other user
@@ -94,7 +95,7 @@ function addEventListenersToCodemirror() {
     debouncedPostParentToNotifyBodyChanges(cm.doc.getValue());
   });
 
-  // // save event
+  //// save event
   // Reset save commands and Cmd-S/Ctrl-S shortcuts that initialized by HackMD
   codemirror.commands.save = function(cm) {
     postParentToSaveWithShortcut(cm.doc.getValue());
@@ -116,12 +117,12 @@ function connectToParentWithPenpal() {
       },
       setValueOnInit(newValue) {
         setValueToCodemirrorOnInit(newValue);
-      },
-    },
+      }
+    }
   });
-  connection.promise.then((parent) => {
+  connection.promise.then(parent => {
     window.growi = parent;
-  }).catch((err) => {
+  }).catch(err => {
     console.log(err);
   });
 }
@@ -147,3 +148,4 @@ function connectToParentWithPenpal() {
 
   console.log('[HackMD] GROWI agent for HackMD has successfully loaded.');
 }());
+

+ 1 - 1
src/client/js/hackmd-styles.js

@@ -12,7 +12,7 @@
 
 /* eslint-disable no-console  */
 
-const styles = '{{styles}}'; // will be replaced by swig
+const styles = '{{styles}}';         // will be replaced by swig
 
 /**
  * Insert link tag to load style file

+ 2 - 2
src/client/js/i18n.js

@@ -39,7 +39,7 @@ export default (userlang) => {
         withRef: true,
         bindI18n: 'languageChanged loaded',
         bindStore: 'added removed',
-        nsMode: 'default',
-      },
+        nsMode: 'default'
+      }
     });
 };

+ 1 - 1
src/client/js/installer.js

@@ -19,6 +19,6 @@ if (installerFormElem) {
     <I18nextProvider i18n={i18n}>
       <InstallerForm userName={userName} name={name} email={email} csrf={csrf} />
     </I18nextProvider>,
-    installerFormElem,
+    installerFormElem
   );
 }

+ 17 - 14
src/client/js/legacy/crowi-admin.js

@@ -5,9 +5,9 @@ require('./thirdparty-js/jQuery.style.switcher');
 require('./thirdparty-js/switchery/switchery');
 require('./thirdparty-js/switchery/switchery.css');
 
-$(() => {
+$(function() {
   $('#slackNotificationForm').on('submit', function(e) {
-    $.post('/_api/admin/notification.add', $(this).serialize(), (res) => {
+    $.post('/_api/admin/notification.add', $(this).serialize(), function(res) {
       if (res.ok) {
         // TODO Fix
         location.reload();
@@ -18,7 +18,7 @@ $(() => {
   });
 
   $('form.admin-remove-updatepost').on('submit', function(e) {
-    $.post('/_api/admin/notification.remove', $(this).serialize(), (res) => {
+    $.post('/_api/admin/notification.remove', $(this).serialize(), function(res) {
       if (res.ok) {
         // TODO Fix
         location.reload();
@@ -29,7 +29,7 @@ $(() => {
 
   $('#createdUserModal').modal('show');
 
-  $('#admin-password-reset-modal').on('show.bs.modal', (button) => {
+  $('#admin-password-reset-modal').on('show.bs.modal', function(button) {
     const data = $(button.relatedTarget);
     const userId = data.data('user-id');
     const email = data.data('user-email');
@@ -39,16 +39,16 @@ $(() => {
   });
 
   $('form#admin-users-reset-password').on('submit', function(e) {
-    $.post('/_api/admin/users.resetPassword', $(this).serialize(), (res) => {
+    $.post('/_api/admin/users.resetPassword', $(this).serialize(), function(res) {
       if (res.ok) {
         // TODO Fix
-        // location.reload();
+        //location.reload();
         $('#admin-password-reset-modal').modal('hide');
         $('#admin-password-reset-modal-done').modal('show');
 
         $('#admin-password-reset-done-user').text(res.user.email);
         $('#admin-password-reset-done-password').text(res.newPassword);
-        return;
+        return ;
       }
 
       // fixme
@@ -58,7 +58,7 @@ $(() => {
     return false;
   });
 
-  $('#admin-delete-user-group-modal').on('show.bs.modal', (button) => {
+  $('#admin-delete-user-group-modal').on('show.bs.modal', function(button) {
     const data = $(button.relatedTarget);
     const userGroupId = data.data('user-group-id');
     const userGroupName = data.data('user-group-name');
@@ -68,8 +68,9 @@ $(() => {
   });
 
   $('form#user-group-relation-create').on('submit', function(e) {
-    $.post('/admin/user-group-relation/create', $(this).serialize(), (res) => {
+    $.post('/admin/user-group-relation/create', $(this).serialize(), function(res) {
       $('#admin-add-user-group-relation-modal').modal('hide');
+      return;
     });
   });
 
@@ -88,9 +89,9 @@ $(() => {
       contentType: false,
       data: fd,
       dataType: 'json',
-      success(data) {
+      success: function(data) {
         if (data.status) {
-          $('#settingUserPicture').attr('src', `${data.url}?time=${new Date()}`);
+          $('#settingUserPicture').attr('src', data.url + '?time=' + (new Date()));
           $('#pictureUploadFormMessage')
             .addClass('alert alert-success')
             .html('変更しました');
@@ -101,7 +102,7 @@ $(() => {
             .html('変更中にエラーが発生しました。');
         }
         $('#pictureUploadFormProgress').html('');
-      },
+      }
     });
     return false;
   });
@@ -111,9 +112,11 @@ $(() => {
 
   // switchery
   const elems = Array.prototype.slice.call(document.querySelectorAll('.js-switch'));
-  elems.forEach((elem) => {
+  elems.forEach(function(elem) {
     const color = elem.dataset.color;
     const size = elem.dataset.size;
-    new Switchery(elem, { color, size }); // eslint-disable-line no-undef
+    new Switchery(elem, { color, size });   // eslint-disable-line no-undef
   });
 });
+
+

+ 3 - 3
src/client/js/legacy/crowi-presentation.js

@@ -15,8 +15,8 @@ Reveal.initialize({
   center: true,
   transition: 'slide',
 
-  // // This specification method can't be used
-  // //   sice deleting symlink prevented `src` from being resolved -- 2017.06.15 Yuki Takei
+  //// This specification method can't be used
+  ////   sice deleting symlink prevented `src` from being resolved -- 2017.06.15 Yuki Takei
   //
   // Optional libraries used to extend on reveal.js
   // dependencies: [
@@ -40,7 +40,7 @@ require.ensure([], () => {
   Reveal.sync();
 });
 
-Reveal.addEventListener('ready', (event) => {
+Reveal.addEventListener('ready', function(event) {
   // event.currentSlide, event.indexh, event.indexv
   $('.reveal section').each(function(e) {
     const $self = $(this);

+ 13 - 12
src/client/js/models/MarkdownTable.js

@@ -5,7 +5,7 @@ import csvToMarkdown from 'csv-to-markdown-table';
 // https://github.com/markdown-it/markdown-it/blob/d29f421927e93e88daf75f22089a3e732e195bd2/lib/rules_block/table.js#L83
 // https://regex101.com/r/7BN2fR/7
 const tableAlignmentLineRE = /^[-:|][-:|\s]*$/;
-const tableAlignmentLineNegRE = /^[^-:]*$/; // it is need to check to ignore empty row which is matched above RE
+const tableAlignmentLineNegRE = /^[^-:]*$/;  // it is need to check to ignore empty row which is matched above RE
 const linePartOfTableRE = /^\|[^\r\n]*|[^\r\n]*\|$|([^|\r\n]+\|[^|\r\n]*)+/; // own idea
 
 // set up DOMParser
@@ -16,6 +16,7 @@ const domParser = new (window.DOMParser)();
  *   ref. https://github.com/wooorm/markdown-table
  */
 export default class MarkdownTable {
+
   constructor(table, options) {
     this.table = table || [];
     this.options = options || {};
@@ -32,7 +33,7 @@ export default class MarkdownTable {
    * (This method clones only the table field.)
    */
   clone() {
-    const newTable = [];
+    let newTable = [];
     for (let i = 0; i < this.table.length; i++) {
       newTable.push([].concat(this.table[i]));
     }
@@ -74,11 +75,11 @@ export default class MarkdownTable {
     const tableElement = dom.querySelector('table');
     const trElements = tableElement.querySelectorAll('tr');
 
-    const table = [];
+    let table = [];
     let maxRowSize = 0;
     for (let i = 0; i < trElements.length; i++) {
-      const row = [];
-      const cellElements = trElements[i].querySelectorAll('th,td');
+      let row = [];
+      let cellElements = trElements[i].querySelectorAll('th,td');
       for (let j = 0; j < cellElements.length; j++) {
         row.push(cellElements[j].innerHTML);
       }
@@ -87,12 +88,12 @@ export default class MarkdownTable {
       if (maxRowSize < row.length) maxRowSize = row.length;
     }
 
-    const align = [];
+    let align = [];
     for (let i = 0; i < maxRowSize; i++) {
       align.push('');
     }
 
-    return new MarkdownTable(table, { align });
+    return new MarkdownTable(table, {align: align});
   }
 
   /**
@@ -109,7 +110,7 @@ export default class MarkdownTable {
    */
   static fromMarkdownString(str) {
     const arrMDTableLines = str.split(/(\r\n|\r|\n)/);
-    const contents = [];
+    let contents = [];
     let aligns = [];
     for (let n = 0; n < arrMDTableLines.length; n++) {
       const line = arrMDTableLines[n];
@@ -118,14 +119,14 @@ export default class MarkdownTable {
         // parse line which described alignment
         const alignRuleRE = [
           { align: 'c', regex: /^:-+:$/ },
-          { align: 'l', regex: /^:-+$/ },
-          { align: 'r', regex: /^-+:$/ },
+          { align: 'l', regex: /^:-+$/  },
+          { align: 'r', regex: /^-+:$/  },
         ];
         let lineText = '';
         lineText = line.replace(/^\||\|$/g, ''); // strip off pipe charactor which is placed head of line and last of line.
         lineText = lineText.replace(/\s*/g, '');
-        aligns = lineText.split(/\|/).map((col) => {
-          const rule = alignRuleRE.find((rule) => { return col.match(rule.regex) });
+        aligns = lineText.split(/\|/).map(col => {
+          const rule = alignRuleRE.find(rule => col.match(rule.regex));
           return (rule != undefined) ? rule.align : '';
         });
       }

+ 4 - 1
src/client/js/plugin.js

@@ -1,4 +1,5 @@
 export default class CrowiPlugin {
+
   /**
    * process plugin entry
    *
@@ -33,7 +34,9 @@ export default class CrowiPlugin {
           });
       }
     });
+
   }
+
 }
 
-window.crowiPlugin = new CrowiPlugin(); // FIXME
+window.crowiPlugin = new CrowiPlugin();     // FIXME

+ 21 - 18
src/client/js/util/Crowi.js

@@ -36,8 +36,8 @@ export default class Crowi {
     this.apiRequest = this.apiRequest.bind(this);
 
     this.interceptorManager = new InterceptorManager();
-    this.interceptorManager.addInterceptor(new DetachCodeBlockInterceptor(this), 10); // process as soon as possible
-    this.interceptorManager.addInterceptor(new RestoreCodeBlockInterceptor(this), 900); // process as late as possible
+    this.interceptorManager.addInterceptor(new DetachCodeBlockInterceptor(this), 10);       // process as soon as possible
+    this.interceptorManager.addInterceptor(new RestoreCodeBlockInterceptor(this), 900);     // process as late as possible
 
     // FIXME
     this.me = context.me;
@@ -46,7 +46,7 @@ export default class Crowi {
 
     this.users = [];
     this.userByName = {};
-    this.userById = {};
+    this.userById   = {};
     this.draft = {};
     this.editorOptions = {};
 
@@ -100,7 +100,7 @@ export default class Crowi {
       'previewOptions',
     ];
 
-    keys.forEach((key) => {
+    keys.forEach(key => {
       const keyContent = this.localStorage[key];
       if (keyContent) {
         try {
@@ -114,19 +114,19 @@ export default class Crowi {
   }
 
   fetchUsers() {
-    const interval = 1000 * 60 * 15; // 15min
+    const interval = 1000*60*15; // 15min
     const currentTime = new Date();
     if (this.localStorage.lastFetched && interval > currentTime - new Date(this.localStorage.lastFetched)) {
-      return;
+      return ;
     }
 
     this.apiGet('/users.list', {})
-    .then((data) => {
+    .then(data => {
       this.users = data.users;
       this.localStorage.users = JSON.stringify(data.users);
 
-      const userByName = {};
-      const userById = {};
+      let userByName = {};
+      let userById = {};
       for (let i = 0; i < data.users.length; i++) {
         const user = data.users[i];
         userByName[user.username] = user;
@@ -139,7 +139,7 @@ export default class Crowi {
       this.localStorage.userById = JSON.stringify(userById);
 
       this.localStorage.lastFetched = new Date();
-    }).catch((err) => {
+    }).catch(err => {
       this.localStorage.removeItem('lastFetched');
       // ignore errors
     });
@@ -192,9 +192,9 @@ export default class Crowi {
   }
 
   findUserByIds(userIds) {
-    const users = [];
-    for (const userId of userIds) {
-      const user = this.findUserById(userId);
+    let users = [];
+    for (let userId of userIds) {
+      let user = this.findUserById(userId);
       if (user) {
         users.push(user);
       }
@@ -217,7 +217,7 @@ export default class Crowi {
       body: markdown,
     });
     return this.apiPost('/pages.create', params)
-      .then((res) => {
+      .then(res => {
         if (!res.ok) {
           throw new Error(res.error);
         }
@@ -232,7 +232,7 @@ export default class Crowi {
       body: markdown,
     });
     return this.apiPost('/pages.update', params)
-      .then((res) => {
+      .then(res => {
         if (!res.ok) {
           throw new Error(res.error);
         }
@@ -251,7 +251,7 @@ export default class Crowi {
   }
 
   apiGet(path, params) {
-    return this.apiRequest('get', path, { params });
+    return this.apiRequest('get', path, {params: params});
   }
 
   apiPost(path, params) {
@@ -263,9 +263,10 @@ export default class Crowi {
   }
 
   apiRequest(method, path, params) {
+
     return new Promise((resolve, reject) => {
       axios[method](`/_api${path}`, params)
-      .then((res) => {
+      .then(res => {
         if (res.data.ok) {
           resolve(res.data);
         }
@@ -273,9 +274,11 @@ export default class Crowi {
           reject(new Error(res.data.error));
         }
       })
-      .catch((res) => {
+      .catch(res => {
         reject(res);
       });
     });
   }
+
 }
+

+ 11 - 10
src/client/js/util/GrowiRenderer.js

@@ -1,8 +1,8 @@
 import MarkdownIt from 'markdown-it';
 
-import Linker from './PreProcessor/Linker';
-import CsvToTable from './PreProcessor/CsvToTable';
-import XssFilter from './PreProcessor/XssFilter';
+import Linker        from './PreProcessor/Linker';
+import CsvToTable    from './PreProcessor/CsvToTable';
+import XssFilter     from './PreProcessor/XssFilter';
 import CrowiTemplate from './PostProcessor/CrowiTemplate';
 
 import EmojiConfigurer from './markdown-it/emoji';
@@ -22,6 +22,7 @@ const logger = require('@alias/logger')('growi:util:GrowiRenderer');
 
 
 export default class GrowiRenderer {
+
   /**
    *
    * @param {Crowi} crowi
@@ -32,9 +33,8 @@ export default class GrowiRenderer {
     this.crowi = crowi;
     this.originRenderer = originRenderer || {};
     this.options = Object.assign( // merge options
-      { isAutoSetup: true }, // default options
-      options || {},
-    ); // specified options
+      { isAutoSetup: true },      // default options
+      options || {});             // specified options
 
     // initialize processors
     //  that will be retrieved if originRenderer exists
@@ -89,21 +89,21 @@ export default class GrowiRenderer {
           new TocAndAnchorConfigurer(crowi, options.renderToc),
           new HeaderLineNumberConfigurer(crowi),
           new HeaderWithEditLinkConfigurer(crowi),
-          new TableWithHandsontableButtonConfigurer(crowi),
+          new TableWithHandsontableButtonConfigurer(crowi)
         ]);
         break;
       case 'editor':
         this.markdownItConfigurers = this.markdownItConfigurers.concat([
           new FooternoteConfigurer(crowi),
           new HeaderLineNumberConfigurer(crowi),
-          new TableConfigurer(crowi),
+          new TableConfigurer(crowi)
         ]);
         break;
       // case 'comment':
       //   break;
       default:
         this.markdownItConfigurers = this.markdownItConfigurers.concat([
-          new TableConfigurer(crowi),
+          new TableConfigurer(crowi)
         ]);
         break;
     }
@@ -115,7 +115,7 @@ export default class GrowiRenderer {
   setup() {
     const crowiConfig = this.crowi.config;
 
-    let isEnabledLinebreaks;
+    let isEnabledLinebreaks = undefined;
     switch (this.options.mode) {
       case 'comment':
         isEnabledLinebreaks = crowiConfig.isEnabledLinebreaksInComments;
@@ -204,4 +204,5 @@ export default class GrowiRenderer {
 
   highlightCode(code, lang) {
   }
+
 }

+ 1 - 0
src/client/js/util/PreProcessor/CsvToTable.js

@@ -2,6 +2,7 @@ import csvToMarkdownTable from 'csv-to-markdown-table';
 
 export default class CsvToTable {
   process(markdown) {
+
     // see: https://regex101.com/r/WR6IvX/3
     return markdown.replace(/:::\s*(\S+)[\r\n]((.|[\r\n])*?)[\r\n]:::/gm, (all, group1, group2) => {
       switch (group1) {

+ 3 - 1
src/client/js/util/PreProcessor/Linker.js

@@ -1,12 +1,14 @@
 
 export default class Linker {
   process(markdown) {
+
     return markdown
       // process angle branckets like '</Level1/Level2>'
       // see: https://regex101.com/r/rxAy4F/2
       .replace(/<((\/[^>\n]+?){2,})>/g, '<a href="$1">$1</a>') // ページ間リンク: <> でかこまれてて / から始まり、 / が2個以上
       // process square branckets like '[/Level1]'
       // see: https://regex101.com/r/QSt1yu/5
-      .replace(/\[(\/[^\]\n]+?)\](?!\()/g, '<a href="$1">$1</a>');
+      .replace(/\[(\/[^\]\n]+?)\](?!\()/g, '<a href="$1">$1</a>')
+    ;
   }
 }

+ 5 - 2
src/client/js/util/PreProcessor/XssFilter.js

@@ -2,6 +2,7 @@ import Xss from '@commons/service/xss';
 import xssOption from '@commons/service/xss/xssOption';
 
 export default class XssFilter {
+
   constructor(crowi) {
     this.crowi = crowi;
 
@@ -15,7 +16,9 @@ export default class XssFilter {
     if (this.crowi.config.isEnabledXssPrevention) {
       return this.xss.process(markdown);
     }
-
-    return markdown;
+    else {
+      return markdown;
+    }
   }
+
 }

+ 3 - 1
src/client/js/util/codemirror/update-display-util.ext.js

@@ -5,6 +5,7 @@ import { DisplayUpdate } from 'codemirror/src/display/update_display';
 import { adjustView } from 'codemirror/src/display/view_tracking';
 
 class UpdateDisplayUtil {
+
   /**
    * Transplant 'updateDisplayIfNeeded' method to fix weseek/growi#703
    *
@@ -20,7 +21,7 @@ class UpdateDisplayUtil {
     const update = new DisplayUpdate(cm, cm.getViewport());
 
     // Compute a suitable new viewport (from & to)
-    const end = doc.first + doc.size;
+    let end = doc.first + doc.size;
     let from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
     let to = Math.min(end, update.visible.to + cm.options.viewportMargin);
     if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
@@ -33,6 +34,7 @@ class UpdateDisplayUtil {
 
     display.viewOffset = heightAtLine(getLine(doc, display.viewFrom));
   }
+
 }
 
 

+ 10 - 8
src/client/js/util/interceptor/detach-code-blocks.js

@@ -11,6 +11,7 @@ class DetachCodeBlockUtil {
  * The interceptor that detach code blocks
  */
 export class DetachCodeBlockInterceptor extends BasicInterceptor {
+
   constructor(crowi) {
     super();
     this.logger = require('@alias/logger')('growi:DetachCodeBlockInterceptor');
@@ -30,7 +31,7 @@ export class DetachCodeBlockInterceptor extends BasicInterceptor {
     if (contextName === 'prePreProcess') {
       return 'markdown';
     }
-    if (contextName === 'prePostProcess') {
+    else if (contextName === 'prePostProcess') {
       return 'parsedHTML';
     }
   }
@@ -41,7 +42,7 @@ export class DetachCodeBlockInterceptor extends BasicInterceptor {
   process(contextName, ...args) {
     this.logger.debug(`processing: 'contextName'=${contextName}`);
 
-    const context = Object.assign(args[0]); // clone
+    const context = Object.assign(args[0]);   // clone
     const targetKey = this.getTargetKey(contextName);
     const currentPagePath = context.currentPagePath; // eslint-disable-line no-unused-vars
 
@@ -50,11 +51,11 @@ export class DetachCodeBlockInterceptor extends BasicInterceptor {
     // see: https://regex101.com/r/8PAEcC/5
     context[targetKey] = context[targetKey].replace(/(^(```|~~~)(.|[\r\n])*?(```|~~~)$)|(`[^\r\n]*?`)|(<pre>(.|[\r\n])*?<\/pre>)|(<pre\s[^>]*>(.|[\r\n])*?<\/pre>)/gm, (all) => {
       // create ID
-      const replaceId = `dcb-${this.createRandomStr(8)}`;
+      const replaceId = 'dcb-' + this.createRandomStr(8);
       this.logger.debug(`'replaceId'=${replaceId} : `, all);
 
       // register to context
-      const dcbContext = {};
+      let dcbContext = {};
       dcbContext.content = all;
       dcbContext.substituteContent = DetachCodeBlockUtil.createReplaceStr(replaceId);
       context.dcbContextMap[replaceId] = dcbContext;
@@ -76,7 +77,7 @@ export class DetachCodeBlockInterceptor extends BasicInterceptor {
   createRandomStr(length) {
     const bag = 'abcdefghijklmnopqrstuvwxyz0123456789';
     let generated = '';
-    for (let i = 0; i < length; i++) {
+    for (var i = 0; i < length; i++) {
       generated += bag[Math.floor(Math.random() * bag.length)];
     }
     return generated;
@@ -88,6 +89,7 @@ export class DetachCodeBlockInterceptor extends BasicInterceptor {
  * The interceptor that restore detached code blocks
  */
 export class RestoreCodeBlockInterceptor extends BasicInterceptor {
+
   constructor(crowi) {
     super();
     this.logger = require('@alias/logger')('growi:DetachCodeBlockInterceptor');
@@ -107,7 +109,7 @@ export class RestoreCodeBlockInterceptor extends BasicInterceptor {
     if (contextName === 'postPreProcess') {
       return 'markdown';
     }
-    if (contextName === 'preRenderHtml' || contextName === 'preRenderPreviewHtml'
+    else if (contextName === 'preRenderHtml' || contextName === 'preRenderPreviewHtml'
         || contextName === 'preRenderCommentHtml' || contextName === 'preRenderCommentPreviewHtml') {
       return 'parsedHTML';
     }
@@ -119,13 +121,13 @@ export class RestoreCodeBlockInterceptor extends BasicInterceptor {
   process(contextName, ...args) {
     this.logger.debug(`processing: 'contextName'=${contextName}`);
 
-    const context = Object.assign(args[0]); // clone
+    const context = Object.assign(args[0]);   // clone
     const targetKey = this.getTargetKey(contextName);
 
     // forEach keys of dcbContextMap
     Object.keys(context.dcbContextMap).forEach((replaceId) => {
       // get context object from context
-      const dcbContext = context.dcbContextMap[replaceId];
+      let dcbContext = context.dcbContextMap[replaceId];
 
       // replace it with content by using getter function so that the doller sign does not work
       // see: https://github.com/weseek/growi/issues/285

+ 1 - 0
src/client/js/util/markdown-it/blockdiag.js

@@ -1,4 +1,5 @@
 export default class BlockdiagConfigurer {
+
   constructor(crowi) {
     this.crowi = crowi;
     const config = crowi.getConfig();

+ 4 - 2
src/client/js/util/markdown-it/emoji.js

@@ -1,4 +1,5 @@
 export default class EmojiConfigurer {
+
   constructor(crowi) {
     this.crowi = crowi;
   }
@@ -8,13 +9,13 @@ export default class EmojiConfigurer {
 
     const emojiShortnameUnicodeMap = {};
 
-    for (const unicode in emojiStrategy) {
+    for (let unicode in emojiStrategy) {
       const data = emojiStrategy[unicode];
       const shortname = data.shortname.replace(/:/g, '');
       emojiShortnameUnicodeMap[shortname] = String.fromCharCode(unicode);
     }
 
-    md.use(require('markdown-it-emoji'), { defs: emojiShortnameUnicodeMap });
+    md.use(require('markdown-it-emoji'), {defs: emojiShortnameUnicodeMap});
 
     // integrate markdown-it-emoji and emojione
     md.renderer.rules.emoji = (token, idx) => {
@@ -22,4 +23,5 @@ export default class EmojiConfigurer {
       return emojione.shortnameToImage(shortname);
     };
   }
+
 }

+ 2 - 0
src/client/js/util/markdown-it/footernote.js

@@ -1,4 +1,5 @@
 export default class FooternoteConfigurer {
+
   constructor(crowi) {
     this.crowi = crowi;
   }
@@ -6,4 +7,5 @@ export default class FooternoteConfigurer {
   configure(md) {
     md.use(require('markdown-it-footnote'));
   }
+
 }

+ 4 - 2
src/client/js/util/markdown-it/header-line-number.js

@@ -1,4 +1,5 @@
 export default class HeaderLineNumberConfigurer {
+
   constructor(crowi) {
     this.crowi = crowi;
     this.firstLine = 0;
@@ -26,8 +27,9 @@ export default class HeaderLineNumberConfigurer {
       if (original) {
         return original(tokens, idx, options, env, self);
       }
-
-      return self.renderToken(tokens, idx, options, env, self);
+      else {
+        return self.renderToken(tokens, idx, options, env, self);
+      }
     };
   }
 }

+ 1 - 0
src/client/js/util/markdown-it/header-with-edit-link.js

@@ -1,4 +1,5 @@
 export default class HeaderWithEditLinkConfigurer {
+
   constructor(crowi) {
     this.crowi = crowi;
   }

+ 4 - 2
src/client/js/util/markdown-it/header.js

@@ -1,4 +1,5 @@
 export default class HeaderConfigurer {
+
   constructor(crowi) {
     this.crowi = crowi;
 
@@ -17,8 +18,9 @@ export default class HeaderConfigurer {
       if (original) {
         return original(tokens, idx, options, env, self);
       }
-
-      return self.renderToken(tokens, idx, options, env, self);
+      else {
+        return self.renderToken(tokens, idx, options, env, self);
+      }
     };
   }
 

+ 3 - 1
src/client/js/util/markdown-it/mathjax.js

@@ -1,9 +1,10 @@
 export default class MathJaxConfigurer {
+
   constructor(crowi) {
     this.crowi = crowi;
 
     const config = crowi.getConfig();
-    this.isEnabled = !!config.env.MATHJAX; // convert to boolean
+    this.isEnabled = !!config.env.MATHJAX;  // convert to boolean
   }
 
   configure(md) {
@@ -11,4 +12,5 @@ export default class MathJaxConfigurer {
       md.use(require('markdown-it-mathjax')());
     }
   }
+
 }

+ 1 - 0
src/client/js/util/markdown-it/plantuml.js

@@ -2,6 +2,7 @@ import plantumlEncoder from 'plantuml-encoder';
 import urljoin from 'url-join';
 
 export default class PlantUMLConfigurer {
+
   constructor(crowi) {
     this.crowi = crowi;
     const config = crowi.getConfig();

+ 2 - 1
src/client/js/util/markdown-it/table-with-handsontable-button.js

@@ -1,4 +1,5 @@
 export default class TableWithHandsontableButtonConfigurer {
+
   constructor(crowi) {
     this.crowi = crowi;
   }
@@ -6,7 +7,7 @@ export default class TableWithHandsontableButtonConfigurer {
   configure(md) {
     md.renderer.rules.table_open = (tokens, idx) => {
       const beginLine = tokens[idx].map[0] + 1;
-      const endLine = tokens[idx].map[1];
+      const endLine  = tokens[idx].map[1];
       return `<div class="editable-with-handsontable"><button class="handsontable-modal-trigger" onClick="crowi.launchHandsontableModal('page', ${beginLine}, ${endLine})"><i class="icon-note"></i></button><table class="table table-bordered">`;
     };
 

+ 2 - 0
src/client/js/util/markdown-it/table.js

@@ -1,4 +1,5 @@
 export default class TableConfigurer {
+
   constructor(crowi) {
     this.crowi = crowi;
   }
@@ -8,4 +9,5 @@ export default class TableConfigurer {
       return '<table class="table table-bordered">';
     };
   }
+
 }

+ 2 - 0
src/client/js/util/markdown-it/task-lists.js

@@ -1,4 +1,5 @@
 export default class TaskListsConfigurer {
+
   constructor(crowi) {
     this.crowi = crowi;
   }
@@ -13,4 +14,5 @@ export default class TaskListsConfigurer {
       liClass: 'task-list-item',
     });
   }
+
 }

+ 2 - 0
src/client/js/util/markdown-it/toc-and-anchor.js

@@ -1,4 +1,5 @@
 export default class TocAndAnchorConfigurer {
+
   constructor(crowi, renderToc) {
     this.crowi = crowi;
     this.renderToc = renderToc;
@@ -22,4 +23,5 @@ export default class TocAndAnchorConfigurer {
       });
     }
   }
+
 }

+ 34 - 38
src/client/js/util/reveal/plugins/growi-renderer.js

@@ -5,21 +5,17 @@ import GrowiRenderer from '../../GrowiRenderer';
  */
 (function(root, factory) {
   // parent window DOM (crowi.js) of presentation window.
-  const parentWindow = window.parent;
+  let parentWindow = window.parent;
 
   // create GrowiRenderer instance and setup.
-  const growiRenderer = new GrowiRenderer(parentWindow.crowi, parentWindow.crowiRenderer, { mode: 'editor' });
+  let growiRenderer = new GrowiRenderer(parentWindow.crowi, parentWindow.crowiRenderer, {mode: 'editor'});
 
-  const growiRendererPlugin = factory(growiRenderer);
+  let growiRendererPlugin = factory(growiRenderer);
   growiRendererPlugin.initialize();
-}(this, (growiRenderer) => {
-  const DEFAULT_SLIDE_SEPARATOR = '^\r?\n---\r?\n$';
-
-
-  const DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '\\\.element\\\s*?(.+?)$';
-
-
-  const DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR = '\\\.slide:\\\s*?(\\\S.+?)$';
+}(this, function(growiRenderer) {
+  const DEFAULT_SLIDE_SEPARATOR = '^\r?\n---\r?\n$',
+    DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '\\\.element\\\s*?(.+?)$',
+    DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR = '\\\.slide:\\\s*?(\\\S.+?)$';
   let marked;
 
   /**
@@ -27,16 +23,16 @@ import GrowiRenderer from '../../GrowiRenderer';
    * starting with '#' to markdown.
    */
   function divideSlides() {
-    const sections = document.querySelectorAll('[data-markdown]');
+    let sections = document.querySelectorAll('[data-markdown]');
     for (let i = 0, len = sections.length; i < len; i++) {
-      const section = sections[i];
-      const markdown = marked.getMarkdownFromSlide(section);
-      const context = { markdown };
+      let section = sections[i];
+      let markdown = marked.getMarkdownFromSlide(section);
+      let context = {markdown};
       const interceptorManager = growiRenderer.crowi.interceptorManager;
-      let dataSeparator = section.getAttribute('data-separator') || DEFAULT_SLIDE_SEPARATOR;
+      let dataSeparator = section.getAttribute( 'data-separator' ) || DEFAULT_SLIDE_SEPARATOR;
       // replace string '\n' to LF code.
       dataSeparator = dataSeparator.replace(/\\n/g, '\n');
-      const replaceValue = `${dataSeparator}#`;
+      const replaceValue = dataSeparator + '#';
       // detach code block.
       interceptorManager.process('prePreProcess', context);
       // if there is only '\n' in the first line, replace it.
@@ -53,50 +49,50 @@ import GrowiRenderer from '../../GrowiRenderer';
    * Converts data-markdown slides to HTML slides by GrowiRenderer.
    */
   function convertSlides() {
-    const sections = document.querySelectorAll('[data-markdown]');
+    let sections = document.querySelectorAll('[data-markdown]');
     let markdown;
     const interceptorManager = growiRenderer.crowi.interceptorManager;
 
     for (let i = 0, len = sections.length; i < len; i++) {
-      const section = sections[i];
+      let section = sections[i];
 
       // Only parse the same slide once
       if (!section.getAttribute('data-markdown-parsed')) {
         section.setAttribute('data-markdown-parsed', 'true');
-        const notes = section.querySelector('aside.notes');
+        let notes = section.querySelector( 'aside.notes' );
         markdown = marked.getMarkdownFromSlide(section);
-        const context = { markdown };
+        let context = { markdown };
 
         interceptorManager.process('preRender', context)
-          .then(() => { return interceptorManager.process('prePreProcess', context) })
+          .then(() => interceptorManager.process('prePreProcess', context))
           .then(() => {
             context.markdown = growiRenderer.preProcess(context.markdown);
           })
-          .then(() => { return interceptorManager.process('postPreProcess', context) })
+          .then(() => interceptorManager.process('postPreProcess', context))
           .then(() => {
-            context.parsedHTML = growiRenderer.process(context.markdown);
+            context['parsedHTML'] = growiRenderer.process(context.markdown);
           })
-          .then(() => { return interceptorManager.process('prePostProcess', context) })
+          .then(() => interceptorManager.process('prePostProcess', context))
           .then(() => {
             context.parsedHTML = growiRenderer.postProcess(context.parsedHTML);
           })
-          .then(() => { return interceptorManager.process('postPostProcess', context) })
-          .then(() => { return interceptorManager.process('preRenderHtml', context) })
-          .then(() => { return interceptorManager.process('postRenderHtml', context) })
+          .then(() => interceptorManager.process('postPostProcess', context))
+          .then(() => interceptorManager.process('preRenderHtml', context))
+          .then(() => interceptorManager.process('postRenderHtml', context))
           .then(() => {
             section.innerHTML = context.parsedHTML;
           });
-        marked.addAttributes(section, section, null, section.getAttribute('data-element-attributes')
-          || section.parentNode.getAttribute('data-element-attributes')
-          || DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR,
-        section.getAttribute('data-attributes')
-          || section.parentNode.getAttribute('data-attributes')
-          || DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR);
+        marked.addAttributes(   section, section, null, section.getAttribute( 'data-element-attributes' ) ||
+          section.parentNode.getAttribute( 'data-element-attributes' ) ||
+          DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR,
+        section.getAttribute( 'data-attributes' ) ||
+          section.parentNode.getAttribute( 'data-attributes' ) ||
+          DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR);
 
         // If there were notes, we need to re-add them after
         // having overwritten the section's HTML
-        if (notes) {
-          section.appendChild(notes);
+        if ( notes ) {
+          section.appendChild( notes );
         }
       }
     }
@@ -104,12 +100,12 @@ import GrowiRenderer from '../../GrowiRenderer';
 
   // API
   return {
-    async initialize() {
+    initialize: async function() {
       growiRenderer.setup();
       marked = require('./markdown').default(growiRenderer.process);
       divideSlides();
       marked.processSlides();
       convertSlides();
-    },
+    }
   };
 }));

+ 163 - 158
src/client/js/util/reveal/plugins/markdown.js

@@ -5,17 +5,12 @@
  * Referred from The reveal.js markdown plugin.
  * https://github.com/hakimel/reveal.js/blob/master/plugin/markdown/markdown.js
  */
-export default function(marked) {
-  const DEFAULT_SLIDE_SEPARATOR = '^\r?\n---\r?\n$';
+export default function( marked ) {
 
-
-  const DEFAULT_NOTES_SEPARATOR = 'notes?:';
-
-
-  const DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '\\\.element\\\s*?(.+?)$';
-
-
-  const DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR = '\\\.slide:\\\s*?(\\\S.+?)$';
+  const DEFAULT_SLIDE_SEPARATOR = '^\r?\n---\r?\n$',
+    DEFAULT_NOTES_SEPARATOR = 'notes?:',
+    DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR = '\\\.element\\\s*?(.+?)$',
+    DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR = '\\\.slide:\\\s*?(\\\S.+?)$';
 
   const SCRIPT_END_PLACEHOLDER = '__SCRIPT_END__';
 
@@ -24,29 +19,29 @@ export default function(marked) {
    * Retrieves the markdown contents of a slide section
    * element. Normalizes leading tabs/whitespace.
    */
-  function getMarkdownFromSlide(section) {
+  function getMarkdownFromSlide( section ) {
+
     // look for a <script> or <textarea data-template> wrapper
-    const template = section.querySelector('[data-template]') || section.querySelector('script');
+    let template = section.querySelector( '[data-template]' ) || section.querySelector( 'script' );
 
     // strip leading whitespace so it isn't evaluated as code
-    let text = (template || section).textContent;
+    let text = ( template || section ).textContent;
 
     // restore script end tags
-    text = text.replace(new RegExp(SCRIPT_END_PLACEHOLDER, 'g'), '</script>');
+    text = text.replace( new RegExp( SCRIPT_END_PLACEHOLDER, 'g' ), '</script>' );
 
-    const leadingWs = text.match(/^\n?(\s*)/)[1].length;
+    let leadingWs = text.match( /^\n?(\s*)/ )[1].length,
+      leadingTabs = text.match( /^\n?(\t*)/ )[1].length;
 
-
-    const leadingTabs = text.match(/^\n?(\t*)/)[1].length;
-
-    if (leadingTabs > 0) {
-      text = text.replace(new RegExp(`\\n?\\t{${leadingTabs}}`, 'g'), '\n');
+    if ( leadingTabs > 0 ) {
+      text = text.replace( new RegExp('\\n?\\t{' + leadingTabs + '}', 'g'), '\n' );
     }
-    else if (leadingWs > 1) {
-      text = text.replace(new RegExp(`\\n? {${leadingWs}}`, 'g'), '\n');
+    else if ( leadingWs > 1 ) {
+      text = text.replace( new RegExp('\\n? {' + leadingWs + '}', 'g'), '\n' );
     }
 
     return text;
+
   }
 
   /**
@@ -55,113 +50,106 @@ export default function(marked) {
    * parsing. Used to forward any other user-defined arguments
    * to the output markdown slide.
    */
-  function getForwardedAttributes(section) {
-    const attributes = section.attributes;
-    const result = [];
+  function getForwardedAttributes( section ) {
 
-    for (let i = 0, len = attributes.length; i < len; i++) {
-      const name = attributes[i].name;
+    let attributes = section.attributes;
+    let result = [];
 
-
-      const value = attributes[i].value;
+    for ( let i = 0, len = attributes.length; i < len; i++ ) {
+      let name = attributes[i].name,
+        value = attributes[i].value;
 
       // disregard attributes that are used for markdown loading/parsing
-      if (/data\-(markdown|separator|vertical|notes)/gi.test(name)) continue;
+      if ( /data\-(markdown|separator|vertical|notes)/gi.test( name ) ) continue;
 
-      if (value) {
-        result.push(`${name}="${value}"`);
+      if ( value ) {
+        result.push( name + '="' + value + '"' );
       }
       else {
-        result.push(name);
+        result.push( name );
       }
     }
 
-    return result.join(' ');
+    return result.join( ' ' );
+
   }
 
   /**
    * Inspects the given options and fills out default
    * values for what's not defined.
    */
-  function getSlidifyOptions(options) {
+  function getSlidifyOptions( options ) {
+
     options = options || {};
     options.separator = options.separator || DEFAULT_SLIDE_SEPARATOR;
     options.notesSeparator = options.notesSeparator || DEFAULT_NOTES_SEPARATOR;
     options.attributes = options.attributes || '';
 
     return options;
+
   }
 
   /**
    * Helper function for constructing a markdown slide.
    */
-  function createMarkdownSlide(content, options) {
-    options = getSlidifyOptions(options);
+  function createMarkdownSlide( content, options ) {
+
+    options = getSlidifyOptions( options );
 
-    const notesMatch = content.split(new RegExp(options.notesSeparator, 'mgi'));
+    let notesMatch = content.split( new RegExp( options.notesSeparator, 'mgi' ) );
 
-    if (notesMatch.length === 2) {
-      content = `${notesMatch[0]}<aside class="notes">${marked(notesMatch[1].trim())}</aside>`;
+    if ( notesMatch.length === 2 ) {
+      content = notesMatch[0] + '<aside class="notes">' + marked(notesMatch[1].trim()) + '</aside>';
     }
 
     // prevent script end tags in the content from interfering
     // with parsing
-    content = content.replace(/<\/script>/g, SCRIPT_END_PLACEHOLDER);
+    content = content.replace( /<\/script>/g, SCRIPT_END_PLACEHOLDER );
+
+    return '<script type="text/template">' + content + '</script>';
 
-    return `<script type="text/template">${content}</script>`;
   }
 
   /**
    * Parses a data string into multiple slides based
    * on the passed in separator arguments.
    */
-  function slidify(markdown, options) {
-    options = getSlidifyOptions(options);
-
-    const separatorRegex = new RegExp(options.separator + (options.verticalSeparator ? `|${options.verticalSeparator}` : ''), 'mg');
-
-
-    const horizontalSeparatorRegex = new RegExp(options.separator);
-
-    let matches;
-
-
-    let lastIndex = 0;
-
-
-    let isHorizontal;
+  function slidify( markdown, options ) {
 
+    options = getSlidifyOptions( options );
 
-    let wasHorizontal = true;
+    let separatorRegex = new RegExp( options.separator + ( options.verticalSeparator ? '|' + options.verticalSeparator : '' ), 'mg' ),
+      horizontalSeparatorRegex = new RegExp( options.separator );
 
-
-    let content;
-
-
-    const sectionStack = [];
+    let matches,
+      lastIndex = 0,
+      isHorizontal,
+      wasHorizontal = true,
+      content,
+      sectionStack = [];
 
     // iterate until all blocks between separators are stacked up
-    while ((matches = separatorRegex.exec(markdown)) != null) {
+    while ( (matches = separatorRegex.exec( markdown )) != null ) {
       // notes = null;
 
       // determine direction (horizontal by default)
-      isHorizontal = horizontalSeparatorRegex.test(matches[0]);
+      isHorizontal = horizontalSeparatorRegex.test( matches[0] );
 
-      if (!isHorizontal && wasHorizontal) {
+      if ( !isHorizontal && wasHorizontal ) {
         // create vertical stack
-        sectionStack.push([]);
+        sectionStack.push( [] );
       }
 
       // pluck slide content from markdown input
-      content = markdown.substring(lastIndex, matches.index);
+      content = markdown.substring( lastIndex, matches.index );
 
-      if (isHorizontal && wasHorizontal) {
+      if ( isHorizontal && wasHorizontal ) {
         // add to horizontal stack
-        sectionStack.push(content);
+        sectionStack.push( content );
       }
       else {
         // add to vertical stack
-        sectionStack[sectionStack.length - 1].push(content);
+        sectionStack[sectionStack.length-1].push( content );
       }
 
       lastIndex = separatorRegex.lastIndex;
@@ -169,28 +157,29 @@ export default function(marked) {
     }
 
     // add the remaining slide
-    (wasHorizontal ? sectionStack : sectionStack[sectionStack.length - 1]).push(markdown.substring(lastIndex));
+    ( wasHorizontal ? sectionStack : sectionStack[sectionStack.length-1] ).push( markdown.substring( lastIndex ) );
 
     let markdownSections = '';
 
     // flatten the hierarchical stack, and insert <section data-markdown> tags
-    for (let i = 0, len = sectionStack.length; i < len; i++) {
+    for ( let i = 0, len = sectionStack.length; i < len; i++ ) {
       // vertical
-      if (sectionStack[i] instanceof Array) {
-        markdownSections += `<section ${options.attributes}>`;
+      if ( sectionStack[i] instanceof Array ) {
+        markdownSections += '<section '+ options.attributes +'>';
 
-        sectionStack[i].forEach((child) => {
-          markdownSections += `<section data-markdown>${createMarkdownSlide(child, options)}</section>`;
-        });
+        sectionStack[i].forEach( function( child ) {
+          markdownSections += '<section data-markdown>' + createMarkdownSlide( child, options ) + '</section>';
+        } );
 
         markdownSections += '</section>';
       }
       else {
-        markdownSections += `<section ${options.attributes} data-markdown>${createMarkdownSlide(sectionStack[i], options)}</section>`;
+        markdownSections += '<section '+ options.attributes +' data-markdown>' + createMarkdownSlide( sectionStack[i], options ) + '</section>';
       }
     }
 
     return markdownSections;
+
   }
 
   /**
@@ -199,69 +188,76 @@ export default function(marked) {
    * handles loading of external markdown.
    */
   function processSlides() {
-    const sections = document.querySelectorAll('[data-markdown]');
 
+    let sections = document.querySelectorAll( '[data-markdown]'),
+      section;
 
-    let section;
+    for ( let i = 0, len = sections.length; i < len; i++ ) {
 
-    for (let i = 0, len = sections.length; i < len; i++) {
       section = sections[i];
 
-      if (section.getAttribute('data-markdown').length) {
-        const xhr = new XMLHttpRequest();
-
+      if ( section.getAttribute( 'data-markdown' ).length ) {
 
-        const url = section.getAttribute('data-markdown');
+        let xhr = new XMLHttpRequest(),
+          url = section.getAttribute( 'data-markdown' );
 
-        const datacharset = section.getAttribute('data-charset');
+        let datacharset = section.getAttribute( 'data-charset' );
 
         // see https://developer.mozilla.org/en-US/docs/Web/API/element.getAttribute#Notes
-        if (datacharset != null && datacharset != '') {
-          xhr.overrideMimeType(`text/html; charset=${datacharset}`);
+        if ( datacharset != null && datacharset != '' ) {
+          xhr.overrideMimeType( 'text/html; charset=' + datacharset );
         }
 
         xhr.onreadystatechange = function() {
-          if (xhr.readyState === 4) {
+          if ( xhr.readyState === 4 ) {
             // file protocol yields status code 0 (useful for local debug, mobile applications etc.)
-            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 0) {
-              section.outerHTML = slidify(xhr.responseText, {
-                separator: section.getAttribute('data-separator'),
-                verticalSeparator: section.getAttribute('data-separator-vertical'),
-                notesSeparator: section.getAttribute('data-separator-notes'),
-                attributes: getForwardedAttributes(section),
+            if ( ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status === 0 ) {
+
+              section.outerHTML = slidify( xhr.responseText, {
+                separator: section.getAttribute( 'data-separator' ),
+                verticalSeparator: section.getAttribute( 'data-separator-vertical' ),
+                notesSeparator: section.getAttribute( 'data-separator-notes' ),
+                attributes: getForwardedAttributes( section )
               });
+
             }
             else {
-              section.outerHTML = `${'<section data-state="alert">'
-                + 'ERROR: The attempt to fetch '}${url} failed with HTTP status ${xhr.status}.`
-                + 'Check your browser\'s JavaScript console for more details.'
-                + '<p>Remember that you need to serve the presentation HTML from a HTTP server.</p>'
-                + '</section>';
+
+              section.outerHTML = '<section data-state="alert">' +
+                'ERROR: The attempt to fetch ' + url + ' failed with HTTP status ' + xhr.status + '.' +
+                'Check your browser\'s JavaScript console for more details.' +
+                '<p>Remember that you need to serve the presentation HTML from a HTTP server.</p>' +
+                '</section>';
+
             }
           }
         };
 
-        xhr.open('GET', url, false);
+        xhr.open( 'GET', url, false );
 
         try {
           xhr.send();
         }
-        catch (e) {
-          alert(`Failed to get the Markdown file ${url}. Make sure that the presentation and the file are served by a HTTP server and the file can be found there. ${e}`);
+        catch ( e ) {
+          alert( 'Failed to get the Markdown file ' + url + '. Make sure that the presentation and the file are served by a HTTP server and the file can be found there. ' + e );
         }
+
       }
-      else if (section.getAttribute('data-separator') || section.getAttribute('data-separator-vertical') || section.getAttribute('data-separator-notes')) {
-        section.outerHTML = slidify(getMarkdownFromSlide(section), {
-          separator: section.getAttribute('data-separator'),
-          verticalSeparator: section.getAttribute('data-separator-vertical'),
-          notesSeparator: section.getAttribute('data-separator-notes'),
-          attributes: getForwardedAttributes(section),
+      else if ( section.getAttribute( 'data-separator' ) || section.getAttribute( 'data-separator-vertical' ) || section.getAttribute( 'data-separator-notes' ) ) {
+
+        section.outerHTML = slidify( getMarkdownFromSlide( section ), {
+          separator: section.getAttribute( 'data-separator' ),
+          verticalSeparator: section.getAttribute( 'data-separator-vertical' ),
+          notesSeparator: section.getAttribute( 'data-separator-notes' ),
+          attributes: getForwardedAttributes( section )
         });
+
       }
       else {
-        section.innerHTML = createMarkdownSlide(getMarkdownFromSlide(section));
+        section.innerHTML = createMarkdownSlide( getMarkdownFromSlide( section ) );
       }
     }
+
   }
 
   /**
@@ -273,18 +269,20 @@ export default function(marked) {
    * directly on refresh (F5)
    * http://stackoverflow.com/questions/5690269/disabling-chrome-cache-for-website-development/7000899#answer-11786277
    */
-  function addAttributeInElement(node, elementTarget, separator) {
-    const mardownClassesInElementsRegex = new RegExp(separator, 'mg');
-    const mardownClassRegex = new RegExp('([^"= ]+?)="([^"=]+?)"', 'mg');
+  function addAttributeInElement( node, elementTarget, separator ) {
+
+    let mardownClassesInElementsRegex = new RegExp( separator, 'mg' );
+    let mardownClassRegex = new RegExp( "([^\"= ]+?)=\"([^\"=]+?)\"", 'mg' );
     let nodeValue = node.nodeValue;
-    const matches = mardownClassesInElementsRegex.exec(nodeValue);
-    if (matches != null) {
-      const classes = matches[1];
-      nodeValue = nodeValue.substring(0, matches.index) + nodeValue.substring(mardownClassesInElementsRegex.lastIndex);
+    let matches = mardownClassesInElementsRegex.exec( nodeValue );
+    if ( matches != null ) {
+
+      let classes = matches[1];
+      nodeValue = nodeValue.substring( 0, matches.index ) + nodeValue.substring( mardownClassesInElementsRegex.lastIndex );
       node.nodeValue = nodeValue;
       let matchesClass;
-      while ((matchesClass = mardownClassRegex.exec(classes)) != null) {
-        elementTarget.setAttribute(matchesClass[1], matchesClass[2]);
+      while ( (matchesClass = mardownClassRegex.exec( classes )) != null ) {
+        elementTarget.setAttribute( matchesClass[1], matchesClass[2] );
       }
       return true;
     }
@@ -295,36 +293,37 @@ export default function(marked) {
    * Add attributes to the parent element of a text node,
    * or the element of an attribute node.
    */
-  function addAttributes(section, element, previousElement, separatorElementAttributes, separatorSectionAttributes) {
-    if (element != null && element.childNodes != undefined && element.childNodes.length > 0) {
+  function addAttributes( section, element, previousElement, separatorElementAttributes, separatorSectionAttributes ) {
+
+    if ( element != null && element.childNodes != undefined && element.childNodes.length > 0 ) {
       let previousParentElement = element;
-      for (let i = 0; i < element.childNodes.length; i++) {
-        const childElement = element.childNodes[i];
-        if (i > 0) {
+      for ( let i = 0; i < element.childNodes.length; i++ ) {
+        let childElement = element.childNodes[i];
+        if ( i > 0 ) {
           let j = i - 1;
-          while (j >= 0) {
-            const aPreviousChildElement = element.childNodes[j];
-            if (typeof aPreviousChildElement.setAttribute === 'function' && aPreviousChildElement.tagName != 'BR') {
+          while ( j >= 0 ) {
+            let aPreviousChildElement = element.childNodes[j];
+            if ( typeof aPreviousChildElement.setAttribute == 'function' && aPreviousChildElement.tagName != 'BR' ) {
               previousParentElement = aPreviousChildElement;
               break;
             }
-            j -= 1;
+            j = j - 1;
           }
         }
         let parentSection = section;
-        if (childElement.nodeName == 'section') {
-          parentSection = childElement;
-          previousParentElement = childElement;
+        if ( childElement.nodeName ==  'section' ) {
+          parentSection = childElement ;
+          previousParentElement = childElement ;
         }
-        if (typeof childElement.setAttribute === 'function' || childElement.nodeType == Node.COMMENT_NODE) {
-          addAttributes(parentSection, childElement, previousParentElement, separatorElementAttributes, separatorSectionAttributes);
+        if ( typeof childElement.setAttribute == 'function' || childElement.nodeType == Node.COMMENT_NODE ) {
+          addAttributes( parentSection, childElement, previousParentElement, separatorElementAttributes, separatorSectionAttributes );
         }
       }
     }
 
-    if (element.nodeType == Node.COMMENT_NODE) {
-      if (addAttributeInElement(element, previousElement, separatorElementAttributes) == false) {
-        addAttributeInElement(element, section, separatorSectionAttributes);
+    if ( element.nodeType == Node.COMMENT_NODE ) {
+      if ( addAttributeInElement( element, previousElement, separatorElementAttributes ) == false ) {
+        addAttributeInElement( element, section, separatorSectionAttributes );
       }
     }
   }
@@ -334,41 +333,47 @@ export default function(marked) {
    * DOM to HTML.
    */
   function convertSlides() {
-    const sections = document.querySelectorAll('[data-markdown]');
 
-    for (let i = 0, len = sections.length; i < len; i++) {
-      const section = sections[i];
+    let sections = document.querySelectorAll( '[data-markdown]');
+
+    for ( let i = 0, len = sections.length; i < len; i++ ) {
+
+      let section = sections[i];
 
       // Only parse the same slide once
-      if (!section.getAttribute('data-markdown-parsed')) {
-        section.setAttribute('data-markdown-parsed', true);
+      if ( !section.getAttribute( 'data-markdown-parsed' ) ) {
+
+        section.setAttribute( 'data-markdown-parsed', true );
 
-        const notes = section.querySelector('aside.notes');
-        const markdown = getMarkdownFromSlide(section);
+        let notes = section.querySelector( 'aside.notes' );
+        let markdown = getMarkdownFromSlide( section );
 
-        section.innerHTML = marked(markdown);
-        addAttributes(section, section, null, section.getAttribute('data-element-attributes')
-                || section.parentNode.getAttribute('data-element-attributes')
-                || DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR,
-        section.getAttribute('data-attributes')
-                || section.parentNode.getAttribute('data-attributes')
-                || DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR);
+        section.innerHTML = marked( markdown );
+        addAttributes(   section, section, null, section.getAttribute( 'data-element-attributes' ) ||
+                section.parentNode.getAttribute( 'data-element-attributes' ) ||
+                DEFAULT_ELEMENT_ATTRIBUTES_SEPARATOR,
+        section.getAttribute( 'data-attributes' ) ||
+                section.parentNode.getAttribute( 'data-attributes' ) ||
+                DEFAULT_SLIDE_ATTRIBUTES_SEPARATOR);
 
         // If there were notes, we need to re-add them after
         // having overwritten the section's HTML
-        if (notes) {
-          section.appendChild(notes);
+        if ( notes ) {
+          section.appendChild( notes );
         }
+
       }
+
     }
+
   }
 
   // API
   return {
-    getMarkdownFromSlide,
-    createMarkdownSlide,
-    processSlides,
-    addAttributes,
-    convertSlides,
+    getMarkdownFromSlide: getMarkdownFromSlide,
+    createMarkdownSlide: createMarkdownSlide,
+    processSlides: processSlides,
+    addAttributes: addAttributes,
+    convertSlides: convertSlides
   };
 }