|
|
@@ -2,10 +2,15 @@
|
|
|
/* Author: Sotaro KARASAWA <sotarok@crocos.co.jp>
|
|
|
*/
|
|
|
|
|
|
+import React from 'react';
|
|
|
+import ReactDOM from 'react-dom';
|
|
|
+
|
|
|
+import GrowiRenderer from '../util/GrowiRenderer';
|
|
|
+import Page from '../components/Page';
|
|
|
+
|
|
|
const io = require('socket.io-client');
|
|
|
const entities = require("entities");
|
|
|
const escapeStringRegexp = require('escape-string-regexp');
|
|
|
-const getLineFromPos = require('get-line-from-pos');
|
|
|
require('bootstrap-sass');
|
|
|
require('jquery.cookie');
|
|
|
|
|
|
@@ -20,36 +25,20 @@ Crowi.createErrorView = function(msg) {
|
|
|
$('#main').prepend($('<p class="alert-message error">' + msg + '</p>'));
|
|
|
};
|
|
|
|
|
|
-Crowi.correctHeaders = function(contentId) {
|
|
|
- // h1 ~ h6 の id 名を補正する
|
|
|
- var $content = $(contentId || '#revision-body-content');
|
|
|
- var i = 0;
|
|
|
- $('h1,h2,h3,h4,h5,h6', $content).each(function(idx, elm) {
|
|
|
- var id = 'head' + i++;
|
|
|
- $(this).attr('id', id);
|
|
|
- $(this).addClass('revision-head');
|
|
|
- $(this).append('<span class="revision-head-link"><a href="#' + id +'"><i class="fa fa-link"></i></a></span>');
|
|
|
- });
|
|
|
-};
|
|
|
+/**
|
|
|
+ * render Table Of Contents
|
|
|
+ * @param {string} tocHtml
|
|
|
+ */
|
|
|
+Crowi.renderTocContent = (tocHtml) => {
|
|
|
+ $('#revision-toc-content').html(tocHtml);
|
|
|
+}
|
|
|
|
|
|
/**
|
|
|
* append buttons to section headers
|
|
|
*/
|
|
|
-Crowi.appendEditSectionButtons = function(contentId, markdown) {
|
|
|
- const $content = $(contentId || '#revision-body-content');
|
|
|
- $('h1,h2,h3,h4,h5,h6', $content).each(function(idx, elm) {
|
|
|
- // get header text string
|
|
|
- const text = $(this).text();
|
|
|
- const escapedText = escapeStringRegexp(text);
|
|
|
-
|
|
|
- // search pos for '# ...'
|
|
|
- // https://regex101.com/r/y5rpO5/1
|
|
|
- const regexp = new RegExp(`[^\r\n]*#+[^\r\n]*${escapedText}[^\r\n]*`);
|
|
|
- let position = markdown.search(regexp);
|
|
|
- if (position < 0) { // if not found, search with header text only
|
|
|
- position = markdown.search(text);
|
|
|
- }
|
|
|
- const line = getLineFromPos(markdown, position);
|
|
|
+Crowi.appendEditSectionButtons = function(parentElement) {
|
|
|
+ $('h1,h2,h3,h4,h5,h6', parentElement).each(function(idx, elm) {
|
|
|
+ const line = +elm.getAttribute('data-line');
|
|
|
|
|
|
// add button
|
|
|
$(this).append(`
|
|
|
@@ -98,52 +87,6 @@ Crowi.setCaretLineAndFocusToEditor = function() {
|
|
|
crowi.focusToEditor();
|
|
|
}
|
|
|
|
|
|
-Crowi.revisionToc = function(contentId, tocId) {
|
|
|
- var $content = $(contentId || '#revision-body-content');
|
|
|
- var $tocId = $(tocId || '#revision-toc');
|
|
|
-
|
|
|
- var $tocContent = $('<div id="revision-toc-content" class="revision-toc-content collapse in"></div>');
|
|
|
- $tocId.append($tocContent);
|
|
|
-
|
|
|
- $('h1', $content).each(function(idx, elm) {
|
|
|
- var id = $(this).attr('id');
|
|
|
- var title = $(this).text();
|
|
|
- var selector = '#' + id + ' ~ h2:not(#' + id + ' ~ h1 ~ h2)';
|
|
|
-
|
|
|
- var $toc = $('<ul></ul>');
|
|
|
- var $tocLi = $('<li><a href="#' + id +'">' + title + '</a></li>');
|
|
|
-
|
|
|
-
|
|
|
- $tocContent.append($toc);
|
|
|
- $toc.append($tocLi);
|
|
|
-
|
|
|
- $(selector).each(function()
|
|
|
- {
|
|
|
- var id2 = $(this).attr('id');
|
|
|
- var title2 = $(this).text();
|
|
|
- var selector2 = '#' + id2 + ' ~ h3:not(#' + id2 + ' ~ h2 ~ h3)';
|
|
|
-
|
|
|
- var $toc2 = $('<ul></ul>');
|
|
|
- var $tocLi2 = $('<li><a href="#' + id2 +'">' + title2 + '</a></li>');
|
|
|
-
|
|
|
- $tocLi.append($toc2);
|
|
|
- $toc2.append($tocLi2);
|
|
|
-
|
|
|
- $(selector2).each(function()
|
|
|
- {
|
|
|
- var id3 = $(this).attr('id');
|
|
|
- var title3 = $(this).text();
|
|
|
-
|
|
|
- var $toc3 = $('<ul></ul>');
|
|
|
- var $tocLi3 = $('<li><a href="#' + id3 +'">' + title3 + '</a></li>');
|
|
|
-
|
|
|
- $tocLi2.append($toc3);
|
|
|
- $toc3.append($tocLi3);
|
|
|
- });
|
|
|
- });
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
// original: middleware.swigFilter
|
|
|
Crowi.userPicture = function (user) {
|
|
|
if (!user) {
|
|
|
@@ -167,7 +110,7 @@ Crowi.modifyScrollTop = function() {
|
|
|
}
|
|
|
var pageHeaderRect = pageHeader.getBoundingClientRect();
|
|
|
|
|
|
- var sectionHeader = document.querySelector(hash);
|
|
|
+ var sectionHeader = Crowi.findSectionHeader(hash);
|
|
|
if (sectionHeader === null) {
|
|
|
return;
|
|
|
}
|
|
|
@@ -227,14 +170,6 @@ $(function() {
|
|
|
var pagePath= $('#content-main').data('path');
|
|
|
var isSavedStatesOfTabChanges = config['isSavedStatesOfTabChanges'];
|
|
|
|
|
|
- // generate options obj
|
|
|
- var rendererOptions = {
|
|
|
- // see: https://www.npmjs.com/package/marked
|
|
|
- marked: {
|
|
|
- breaks: config.isEnabledLineBreaks
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
$('[data-toggle="popover"]').popover();
|
|
|
$('[data-toggle="tooltip"]').tooltip();
|
|
|
$('[data-tooltip-stay]').tooltip('show');
|
|
|
@@ -486,29 +421,26 @@ $(function() {
|
|
|
});
|
|
|
|
|
|
// for list page
|
|
|
+ let growiRendererForTimeline = null;
|
|
|
$('a[data-toggle="tab"][href="#view-timeline"]').on('show.bs.tab', function() {
|
|
|
var isShown = $('#view-timeline').data('shown');
|
|
|
+
|
|
|
+ if (growiRendererForTimeline == null) {
|
|
|
+ growiRendererForTimeline = new GrowiRenderer(crowi, crowiRenderer, {mode: 'timeline'});
|
|
|
+ }
|
|
|
+
|
|
|
if (isShown == 0) {
|
|
|
$('#view-timeline .timeline-body').each(function()
|
|
|
{
|
|
|
var id = $(this).attr('id');
|
|
|
var contentId = '#' + id + ' > script';
|
|
|
var revisionBody = '#' + id + ' .revision-body';
|
|
|
- var $revisionBody = $(revisionBody);
|
|
|
+ var revisionBodyElem = document.querySelector(revisionBody);
|
|
|
var revisionPath = '#' + id + ' .revision-path';
|
|
|
-
|
|
|
+ var pagePath = document.getElementById(id).getAttribute('data-page-path');
|
|
|
var markdown = entities.decodeHTML($(contentId).html());
|
|
|
- var parsedHTML = crowiRenderer.render(markdown, $revisionBody.get(0), rendererOptions);
|
|
|
- $revisionBody.html(parsedHTML);
|
|
|
|
|
|
- $('.template-create-button', revisionBody).on('click', function() {
|
|
|
- var path = $(this).data('path');
|
|
|
- var templateId = $(this).data('template');
|
|
|
- var template = $('#' + templateId).html();
|
|
|
-
|
|
|
- crowi.saveDraft(path, template);
|
|
|
- top.location.href = path;
|
|
|
- });
|
|
|
+ ReactDOM.render(<Page crowi={crowi} crowiRenderer={growiRendererForTimeline} markdown={markdown} pagePath={pagePath} />, revisionBodyElem);
|
|
|
});
|
|
|
|
|
|
$('#view-timeline').data('shown', 1);
|
|
|
@@ -540,6 +472,10 @@ $(function() {
|
|
|
|
|
|
if (pageId) {
|
|
|
|
|
|
+ /*
|
|
|
+ * transplanted to React components -- 2018.02.04 Yuki Takei
|
|
|
+ *
|
|
|
+
|
|
|
// if page exists
|
|
|
var $rawTextOriginal = $('#raw-text-original');
|
|
|
if ($rawTextOriginal.length > 0) {
|
|
|
@@ -556,12 +492,12 @@ $(function() {
|
|
|
crowi.interceptorManager.process('preRender', context)
|
|
|
.then(() => crowi.interceptorManager.process('prePreProcess', context))
|
|
|
.then(() => {
|
|
|
- context.markdown = crowiRenderer.preProcess(context.markdown, context.dom);
|
|
|
+ context.markdown = crowiRenderer.preProcess(context.markdown);
|
|
|
})
|
|
|
.then(() => crowi.interceptorManager.process('postPreProcess', context))
|
|
|
.then(() => {
|
|
|
var revisionBody = $('#revision-body-content');
|
|
|
- var parsedHTML = crowiRenderer.render(context.markdown, context.dom, rendererOptions);
|
|
|
+ var parsedHTML = crowiRenderer.render(context.markdown, context.dom);
|
|
|
context.parsedHTML = parsedHTML;
|
|
|
Promise.resolve(context);
|
|
|
})
|
|
|
@@ -580,9 +516,7 @@ $(function() {
|
|
|
top.location.href = path;
|
|
|
});
|
|
|
|
|
|
- Crowi.correctHeaders('#revision-body-content');
|
|
|
Crowi.appendEditSectionButtons('#revision-body-content', markdown);
|
|
|
- Crowi.revisionToc('#revision-body-content', '#revision-toc');
|
|
|
|
|
|
Promise.resolve($('#revision-body-content'));
|
|
|
})
|
|
|
@@ -594,6 +528,7 @@ $(function() {
|
|
|
|
|
|
|
|
|
}
|
|
|
+ */
|
|
|
|
|
|
// header
|
|
|
var $header = $('#page-header');
|
|
|
@@ -883,28 +818,43 @@ Crowi.findHashFromUrl = function(url)
|
|
|
{
|
|
|
var match;
|
|
|
if (match = url.match(/#(.+)$/)) {
|
|
|
- return '#' + match[1];
|
|
|
+ return `#${match[1]}`;
|
|
|
}
|
|
|
|
|
|
return "";
|
|
|
}
|
|
|
|
|
|
+Crowi.findSectionHeader = function(hash) {
|
|
|
+ if (hash.length == 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // omit '#'
|
|
|
+ const id = hash.replace('#', '');
|
|
|
+ // don't use jQuery and document.querySelector
|
|
|
+ // because hash may containe Base64 encoded strings
|
|
|
+ const elem = document.getElementById(id);
|
|
|
+ if (elem != null && elem.tagName.match(/h\d+/i)) { // match h1, h2, h3...
|
|
|
+ return elem;
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+}
|
|
|
+
|
|
|
Crowi.unhighlightSelectedSection = function(hash)
|
|
|
{
|
|
|
- if (!hash || hash == "" || !hash.match(/^#head.+/)) {
|
|
|
- // とりあえず head* だけ (検索結果ページで副作用出た
|
|
|
- return true;
|
|
|
+ const elem = Crowi.findSectionHeader(hash);
|
|
|
+ if (elem != null) {
|
|
|
+ elem.classList.remove('highlighted');
|
|
|
}
|
|
|
- $(hash).removeClass('highlighted');
|
|
|
}
|
|
|
|
|
|
Crowi.highlightSelectedSection = function(hash)
|
|
|
{
|
|
|
- if (!hash || hash == "" || !hash.match(/^#head.+/)) {
|
|
|
- // とりあえず head* だけ (検索結果ページで副作用出た
|
|
|
- return true;
|
|
|
+ const elem = Crowi.findSectionHeader(hash);
|
|
|
+ if (elem != null) {
|
|
|
+ elem.classList.add('highlighted');
|
|
|
}
|
|
|
- $(hash).addClass('highlighted');
|
|
|
}
|
|
|
|
|
|
window.addEventListener('load', function(e) {
|
|
|
@@ -971,7 +921,7 @@ window.addEventListener('hashchange', function(e) {
|
|
|
$('a[data-toggle="tab"][href="#revision-history"]').tab('show');
|
|
|
}
|
|
|
}
|
|
|
- if (location.hash == '' || location.hash.match(/^#head.+/)) {
|
|
|
+ else {
|
|
|
$('a[data-toggle="tab"][href="#revision-body"]').tab('show');
|
|
|
}
|
|
|
});
|