Просмотр исходного кода

Merge branch 'imprv/growi_renderer-in-reveal' into imprv/add-reveal-growi_renderer-plugin

Yuto Iwata 7 лет назад
Родитель
Сommit
f91fe6ece6

+ 7 - 1
CHANGES.md

@@ -1,7 +1,11 @@
 CHANGES
 ========
 
-## 3.3.5-RC
+## 3.3.7-RC
+
+* 
+
+## 3.3.6
 
 * Improvement: Site URL settings must be set
 * Improvement: Site URL settings can be set with environment variable
@@ -23,6 +27,8 @@ CHANGES
     * sinon
     * sinon-chai
 
+## 3.3.5 (Missing number)
+
 ## 3.3.4
 
 * Improvement: SAML configuration with environment variables

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "growi",
-  "version": "3.3.6-RC",
+  "version": "3.3.7-RC",
   "description": "Team collaboration software using markdown",
   "tags": [
     "wiki",

+ 123 - 1
src/client/js/components/PageEditor/CodeMirrorEditor.js

@@ -95,6 +95,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
     this.renderLoadingKeymapOverlay = this.renderLoadingKeymapOverlay.bind(this);
     this.renderCheatsheetModalButton = this.renderCheatsheetModalButton.bind(this);
 
+    this.makeHeaderHandler = this.makeHeaderHandler.bind(this);
     this.showHandsonTableHandler = this.showHandsonTableHandler.bind(this);
   }
 
@@ -547,12 +548,133 @@ export default class CodeMirrorEditor extends AbstractEditor {
     );
   }
 
+  /**
+   * return a function to replace a selected range with prefix + selection + suffix
+   *
+   * The cursor after replacing is inserted between the selection and the suffix.
+   */
+  createReplaceSelectionHandler(prefix, suffix) {
+    return () => {
+      const cm = this.getCodeMirror();
+      const selection = cm.getDoc().getSelection();
+      const curStartPos = cm.getCursor('from');
+      const curEndPos = cm.getCursor('to');
+
+      const curPosAfterReplacing = {};
+      curPosAfterReplacing.line = curEndPos.line;
+      if (curStartPos.line === curEndPos.line) {
+        curPosAfterReplacing.ch = curEndPos.ch + prefix.length;
+      }
+      else {
+        curPosAfterReplacing.ch = curEndPos.ch;
+      }
+
+      cm.getDoc().replaceSelection(prefix + selection + suffix);
+      cm.setCursor(curPosAfterReplacing);
+      cm.focus();
+    };
+  }
+
+  /**
+   * return a function to add prefix to selected each lines
+   *
+   * The cursor after editing is inserted between the end of the selection.
+   */
+  createAddPrefixToEachLinesHandler(prefix) {
+    return () => {
+      const cm = this.getCodeMirror();
+      const startLineNum = cm.getCursor('from').line;
+      const endLineNum = cm.getCursor('to').line;
+
+      const lines = [];
+      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});
+
+      cm.setCursor(endLineNum, cm.getDoc().getLine(endLineNum).length);
+      cm.focus();
+    };
+  }
+
+  /**
+   * make a selected line a header
+   *
+   * The cursor after editing is inserted between the end of the line.
+   */
+  makeHeaderHandler() {
+    const cm = this.getCodeMirror();
+    const lineNum = cm.getCursor('from').line;
+    const line = cm.getDoc().getLine(lineNum);
+    let prefix = '#';
+    if (!line.startsWith('#')) {
+      prefix += ' ';
+    }
+    cm.getDoc().replaceRange(prefix, {line: lineNum, ch: 0}, {line: lineNum, ch: 0});
+    cm.focus();
+  }
+
   showHandsonTableHandler() {
     this.refs.handsontableModal.show(mtu.getMarkdownTable(this.getCodeMirror()));
   }
 
   getNavbarItems() {
-    return <Button bsSize="small" onClick={ this.showHandsonTableHandler }><img src="/images/icons/editor/table.svg" width="14" /></Button>;
+    // 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'};
+
+    return [
+      <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'}></i>
+      </Button>,
+      <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'}></i>
+      </Button>,
+      <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'}></i>
+      </Button>,
+      <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}></i>
+      </Button>,
+      <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'}></i>
+      </Button>,
+      <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 }>
+        <img src="/images/icons/editor/table.svg" width="14" height="14" />
+      </Button>
+    ];
   }
 
   render() {

+ 1 - 1
src/client/js/components/PageEditor/Editor.jsx

@@ -210,7 +210,7 @@ export default class Editor extends AbstractEditor {
   renderNavbar() {
     return (
       <div className="m-0 navbar navbar-default navbar-editor" style={{ minHeight: 'unset' }}>
-        <ul className="pr-4 nav nav-navbar navbar-right">
+        <ul className="pl-2 nav nav-navbar">
           { this.getNavbarItems() != null && this.getNavbarItems().map((item, idx) => {
             return <li key={idx}>{item}</li>;
           }) }

+ 9 - 1
src/client/styles/scss/_mixins.scss

@@ -51,8 +51,16 @@
         }
 
         .navbar-editor {
+          li {
+            display: inline-block;
+          }
+
           button {
-            padding: 7px 8px;
+            margin: 0 2px;
+            padding: 8px;
+            border: none;
+            background-color: transparent;
+            font-size: 14px;
             line-height: 1;
           }
 

+ 2 - 2
src/server/util/middlewares.js

@@ -283,7 +283,7 @@ exports.applicationNotInstalled = function() {
   return function(req, res, next) {
     var config = req.config;
 
-    if (Object.keys(config.crowi).length !== 1) {
+    if (Object.keys(config.crowi).length !== 0) {
       req.flash('errorMessage', 'Application already installed.');
       return res.redirect('admin'); // admin以外はadminRequiredで'/'にリダイレクトされる
     }
@@ -323,7 +323,7 @@ exports.applicationInstalled = function() {
   return function(req, res, next) {
     var config = req.config;
 
-    if (Object.keys(config.crowi).length === 1) { // app:url is set by process
+    if (Object.keys(config.crowi).length === 0) {
       return res.redirect('/installer');
     }
 

+ 1 - 2
src/server/util/swigFunctions.js

@@ -136,8 +136,7 @@ module.exports = function(crowi, app, req, locals) {
   };
 
   locals.passportSamlLoginEnabled = function() {
-    let config = crowi.getConfig();
-    return locals.isEnabledPassport() && config.crowi['security:passport-saml:isEnabled'];
+    return locals.isEnabledPassport() && locals.getConfig('crowi', 'security:passport-saml:isEnabled');
   };
 
   locals.getSamlMissingMandatoryConfigKeys = function() {

+ 3 - 0
src/server/views/admin/app.html

@@ -2,6 +2,9 @@
 
 {% block html_title %}{{ customTitle(t('App settings')) }}{% endblock %}
 
+{% block head_warn %} {# remove including block for './widget/alert_siteurl_undefined.html' #}
+{% endblock %}
+
 {% block content_header %}
 <div class="header-wrap">
   <header id="page-header">

+ 4 - 0
src/server/views/layout-crowi/base/layout.html

@@ -7,6 +7,10 @@
   {{ cdnScriptTag('highlight-addons') }}
 {% endblock %}
 
+{% block head_warn %}
+  {% include '../../widget/alert_siteurl_undefined.html' %}
+{% endblock %}
+
 {% block layout_main %}
 <div class="container-fluid">
 

+ 4 - 0
src/server/views/layout-growi/base/layout.html

@@ -5,6 +5,10 @@
   {{ cdnScriptTag('highlight-addons') }}
 {% endblock %}
 
+{% block head_warn %}
+  {% include '../../widget/alert_siteurl_undefined.html' %}
+{% endblock %}
+
 {% block layout_main %}
 <div class="container-fluid">
 

+ 4 - 0
src/server/views/layout-kibela/base/layout.html

@@ -5,6 +5,10 @@
   {{ cdnScriptTag('highlight-addons') }}
 {% endblock %}
 
+{% block head_warn %}
+  {% include '../../widget/alert_siteurl_undefined.html' %}
+{% endblock %}
+
 {% block layout_main %}
 <div class="container-fluid">
 

+ 1 - 6
src/server/views/layout/layout.html

@@ -195,12 +195,7 @@
   {% include '../modal/create_page.html' %}
   {% endblock  %} {# layout_head_nav #}
 
-  {% if !getConfig('crowi', 'app:siteUrl') %}
-  <div class="alert alert-danger mb-0">
-    <i class="icon-exclamation"></i>
-    {{ t("security_setting.alert_siteUrl_is_not_set", '<a href="/admin/app">' + t('App settings') + '<i class="icon-login"></i></a>') }}
-  </div>
-  {% endif %}
+  {% block head_warn %}{% endblock %}
 
   {% block sidebar %}
   <!-- Left navbar-header -->

+ 3 - 0
src/server/views/search.html

@@ -10,6 +10,9 @@
   data-target="#search-result-list"
 {% endblock %}
 
+{% block head_warn %}
+  {% include './widget/alert_siteurl_undefined.html' %}
+{% endblock %}
 
 {% block layout_main %}
 <div class="container-fluid">

+ 6 - 0
src/server/views/widget/alert_siteurl_undefined.html

@@ -0,0 +1,6 @@
+{% if !getConfig('crowi', 'app:siteUrl') %}
+<div class="alert alert-danger mb-0">
+  <i class="icon-exclamation"></i>
+  {{ t("security_setting.alert_siteUrl_is_not_set", '<a href="/admin/app">' + t('App settings') + '<i class="icon-login"></i></a>') }}
+</div>
+{% endif %}