diff --git a/.codeclimate.yml b/.codeclimate.yml index 2fa53227b2..8b28d9b81d 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -62,4 +62,3 @@ exclude_paths: - "**/node_modules/" - spec/** - spec_legacy/**/* - - lib/redcloth3.rb diff --git a/.rubocop.yml b/.rubocop.yml index c375c81b96..60185ec6ed 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,5 +1,5 @@ AllCops: - TargetRubyVersion: 2.2 + TargetRubyVersion: 2.5 Exclude: - db/schema.rb diff --git a/app/assets/javascripts/application.js.erb b/app/assets/javascripts/application.js.erb index 1f9b171325..ac7d99ac4f 100644 --- a/app/assets/javascripts/application.js.erb +++ b/app/assets/javascripts/application.js.erb @@ -34,7 +34,6 @@ //= require action_menu //= require breadcrumb //= require findDomElement -//= require jstoolbar //= require settings //= require modal //= require tab_handling diff --git a/app/assets/javascripts/forums.js b/app/assets/javascripts/forums.js index ef5e3503c8..96ee527d2e 100644 --- a/app/assets/javascripts/forums.js +++ b/app/assets/javascripts/forums.js @@ -35,7 +35,12 @@ content = $("#reply_content"); subject.val(result.subject); - content.val(result.content); + + $('op-ckeditor-form') + .data('editor') + .then(function(editor) { + editor.setData(result.content); + }); reply.slideDown(); content.focus(); diff --git a/app/assets/javascripts/jstoolbar.js b/app/assets/javascripts/jstoolbar.js deleted file mode 100644 index 559575dd03..0000000000 --- a/app/assets/javascripts/jstoolbar.js +++ /dev/null @@ -1,30 +0,0 @@ -//-- copyright -// OpenProject is a project management system. -// Copyright (C) 2012-2018 the OpenProject Foundation (OPF) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License version 3. -// -// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -// Copyright (C) 2006-2017 Jean-Philippe Lang -// Copyright (C) 2010-2013 the ChiliProject Team -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// See docs/COPYRIGHT.rdoc for more details. -//++ - -//= require jstoolbar/jstoolbar -//= require jstoolbar/translations diff --git a/app/assets/javascripts/jstoolbar/jstoolbar.js b/app/assets/javascripts/jstoolbar/jstoolbar.js deleted file mode 100644 index f4c0d2d660..0000000000 --- a/app/assets/javascripts/jstoolbar/jstoolbar.js +++ /dev/null @@ -1,378 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * This file is part of DotClear. - * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All - * rights reserved. - * - * DotClear is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * DotClear is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with DotClear; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ***** END LICENSE BLOCK ***** -*/ - -/* Modified by JP LANG for textile formatting */ - -function jsToolBar(textarea) { - if (!document.createElement) { return; } - - if (!textarea) { return; } - - if ((typeof(document["selection"]) == "undefined") - && (typeof(textarea["setSelectionRange"]) == "undefined")) { - return; - } - - this.textarea = textarea; - - this.editor = document.createElement('div'); - this.editor.className = 'jstEditor'; - - this.textarea.parentNode.insertBefore(this.editor,this.textarea); - this.editor.appendChild(this.textarea); - - this.toolbar = document.createElement("div"); - this.toolbar.className = 'jstElements'; - this.editor.parentNode.insertBefore(this.toolbar,this.editor); - - // Dragable resizing (only for gecko) - if (this.editor.addEventListener) - { - this.handle = document.createElement('div'); - this.handle.className = 'jstHandle'; - var dragStart = this.resizeDragStart; - var This = this; - this.handle.addEventListener('mousedown',function(event) { dragStart.call(This,event); },false); - // fix memory leak in Firefox (bug #241518) - window.addEventListener('unload',function() { - var del = This.handle.parentNode.removeChild(This.handle); - delete(This.handle); - },false); - - this.editor.parentNode.insertBefore(this.handle,this.editor.nextSibling); - } - - this.context = null; - this.toolNodes = {}; // lorsque la toolbar est dessinée , cet objet est garni - // de raccourcis vers les éléments DOM correspondants aux outils. -} - -function jsButton(title, fn, scope, className) { - if(typeof jsToolBar.strings == 'undefined') { - this.title = title || null; - } else { - this.title = jsToolBar.strings[title] || title || null; - } - this.fn = fn || function(){}; - this.scope = scope || null; - this.className = className || null; -} -jsButton.prototype.draw = function() { - if (!this.scope) return null; - - var button = document.createElement('button'); - button.setAttribute('type','button'); - button.setAttribute('aria-label', this.title); - if (this.className) button.className = this.className; - button.title = this.title; - - if (this.icon != undefined) { - button.style.backgroundImage = 'url('+this.icon+')'; - } - if (typeof(this.fn) == 'function') { - var This = this; - button.onclick = function() { try { This.fn.apply(This.scope, arguments) } catch (e) {} return false; }; - } - return button; -}; - -function jsSpace(id) { - this.id = id || null; - this.width = null; -} -jsSpace.prototype.draw = function() { - var span = document.createElement('span'); - if (this.id) span.id = this.id; - span.appendChild(document.createTextNode(String.fromCharCode(160))); - span.className = 'jstSpacer'; - if (this.width) span.style.marginRight = this.width+'px'; - - return span; -}; - -function jsCombo(title, options, scope, fn, className) { - this.title = title || null; - this.options = options || null; - this.scope = scope || null; - this.fn = fn || function(){}; - this.className = className || null; -} -jsCombo.prototype.draw = function() { - if (!this.scope || !this.options) return null; - - var select = document.createElement('select'); - if (this.className) select.className = className; - select.title = this.title; - - for (var o in this.options) { - //var opt = this.options[o]; - var option = document.createElement('option'); - option.value = o; - option.appendChild(document.createTextNode(this.options[o])); - select.appendChild(option); - } - - var This = this; - select.onchange = function() { - try { - This.fn.call(This.scope, this.value); - } catch (e) { alert(e); } - - return false; - }; - - return select; -}; - - -jsToolBar.prototype = { - base_url: '', - mode: 'wiki', - elements: {}, - help_link: '', - - getMode: function() { - return this.mode; - }, - - setMode: function(mode) { - this.mode = mode || 'wiki'; - }, - - switchMode: function(mode) { - mode = mode || 'wiki'; - this.draw(mode); - }, - - setHelpLink: function(link) { - this.help_link = link; - }, - - button: function(toolName) { - var tool = this.elements[toolName]; - if (typeof tool.fn[this.mode] != 'function') return null; - var b = new jsButton(tool.title, tool.fn[this.mode], this, 'icon-small jstb_'+toolName); - if (tool.icon != undefined) b.icon = tool.icon; - return b; - }, - space: function(toolName) { - var tool = new jsSpace(toolName); - if (this.elements[toolName].width !== undefined) - tool.width = this.elements[toolName].width; - return tool; - }, - combo: function(toolName) { - var tool = this.elements[toolName]; - var length = tool[this.mode].list.length; - - if (typeof tool[this.mode].fn != 'function' || length == 0) { - return null; - } else { - var options = {}; - for (var i=0; i < length; i++) { - var opt = tool[this.mode].list[i]; - options[opt] = tool.options[opt]; - } - return new jsCombo(tool.title, options, this, tool[this.mode].fn); - } - }, - draw: function(mode) { - this.setMode(mode); - - // Empty toolbar - while (this.toolbar.hasChildNodes()) { - this.toolbar.removeChild(this.toolbar.firstChild) - } - this.toolNodes = {}; // vide les raccourcis DOM/**/ - - // Draw toolbar elements - var b, tool, newTool; - - for (var i in this.elements) { - b = this.elements[i]; - - var disabled = - b.type == undefined || b.type == '' - || (b.disabled != undefined && b.disabled) - || (b.context != undefined && b.context != null && b.context != this.context); - - if (!disabled && typeof this[b.type] == 'function') { - tool = this[b.type](i); - if (tool) newTool = tool.draw(); - if (newTool) { - this.toolNodes[i] = newTool; //mémorise l'accès DOM pour usage éventuel ultérieur - this.toolbar.appendChild(newTool); - } - } - } - - if (this.help_link !== '') { - this.toolbar.appendChild(this.help_link); - } - }, - - singleTag: function(stag,etag) { - stag = stag || null; - etag = etag || stag; - - if (!stag || !etag) { return; } - - this.encloseSelection(stag,etag); - }, - - encloseLineSelection: function (prefix, suffix, fn) { - this.textarea.focus(); - prefix = prefix || ''; - suffix = suffix || ''; - var start, end, sel, scrollPos, subst, res; - if (typeof(document["selection"]) != "undefined") { - // just makes it work in IE8 somehow - var helperRange = document.selection.createRange(); - var bookmark = helperRange.getBookmark(); - var origParent = helperRange.parentElement(); - var moveStart = 0; - // we move the starting point of the selection to the last newline - // and track the number of movements - try { - while (helperRange.text[0] != "\n" && helperRange.text[0] != "\r") { - helperRange.moveStart("character", -1); - if (origParent != helperRange.parentElement()) { - throw "Outside of Textarea"; - } - moveStart -= 1; - } - moveStart += 1; - } catch(err) { - if (err != "Outside of Textarea") - throw err; - } - var range = document.selection.createRange(); - range.moveStart("character", moveStart); - if (range.text.match(/ $/)) - range.moveEnd("character", -1); - sel = range.text; - } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") { - start = this.textarea.selectionStart; - end = this.textarea.selectionEnd; - scrollPos = this.textarea.scrollTop; - // go to the start of the line - start = this.textarea.value.substring(0, start).replace(/[^\r\n]*$/g,'').length; - // go to the end of the line - end = this.textarea.value.length - this.textarea.value.substring(end, this.textarea.value.length).replace(/^[^\r\n]*/, '').length; - sel = this.textarea.value.substring(start, end); - } - if (sel.match(/ $/)) { - sel = sel.substring(0, sel.length - 1); - suffix = suffix + " "; - } - if (typeof(fn) == 'function') { - res = (sel) ? fn.call(this, sel) : fn(''); - } else { - res = (sel) ? sel : ''; - } - subst = prefix + res + suffix; - if (typeof(document["selection"]) != "undefined") { - range.text = subst; - this.textarea.caretPos -= suffix.length; - } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") { - var cursorPosition = start; - this.textarea.value = this.textarea.value.substring(0, start) + subst + this.textarea.value.substring(end); - if (sel) { - cursorPosition += subst.length; - } else { - cursorPosition += prefix.length + res.length; - } - this.textarea.setSelectionRange(cursorPosition, cursorPosition); - this.textarea.scrollTop = scrollPos; - } - }, - - encloseSelection: function (prefix, suffix, fn) { - this.textarea.focus(); - prefix = prefix || ''; - suffix = suffix || ''; - var start, end, sel, scrollPos, subst, res; - if (typeof(document["selection"]) != "undefined") { - sel = document.selection.createRange().text; - } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") { - start = this.textarea.selectionStart; - end = this.textarea.selectionEnd; - scrollPos = this.textarea.scrollTop; - sel = this.textarea.value.substring(start, end); - } - if (sel.match(/ $/)) { - sel = sel.substring(0, sel.length - 1); - suffix = suffix + " "; - } - if (typeof(fn) == 'function') { - res = (sel) ? fn.call(this, sel) : fn(''); - } else { - res = (sel) ? sel : ''; - } - subst = prefix + res + suffix; - if (typeof(document["selection"]) != "undefined") { - var range = document.selection.createRange().text = subst; - this.textarea.caretPos -= suffix.length; - } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") { - this.textarea.value = this.textarea.value.substring(0, start) + subst + this.textarea.value.substring(end); - if (sel) { - this.textarea.setSelectionRange(start + subst.length, start + subst.length); - } else { - this.textarea.setSelectionRange(start + prefix.length, start + prefix.length); - } - this.textarea.scrollTop = scrollPos; - } - }, - - stripBaseURL: function(url) { - if (this.base_url != '') { - var pos = url.indexOf(this.base_url); - if (pos == 0) { - url = url.substr(this.base_url.length); - } - } - - return url; - } -}; - -/** Resizer --------------------------------------------------------- */ -jsToolBar.prototype.resizeSetStartH = function() { - this.dragStartH = this.textarea.offsetHeight + 0; -}; -jsToolBar.prototype.resizeDragStart = function(event) { - var This = this; - this.dragStartY = event.clientY; - this.resizeSetStartH(); - document.addEventListener('mousemove', this.dragMoveHdlr=function(event){This.resizeDragMove(event);}, false); - document.addEventListener('mouseup', this.dragStopHdlr=function(event){This.resizeDragStop(event);}, false); -}; - -jsToolBar.prototype.resizeDragMove = function(event) { - this.textarea.style.height = (this.dragStartH+event.clientY-this.dragStartY)+'px'; -}; - -jsToolBar.prototype.resizeDragStop = function(event) { - document.removeEventListener('mousemove', this.dragMoveHdlr, false); - document.removeEventListener('mouseup', this.dragStopHdlr, false); -}; diff --git a/app/assets/javascripts/jstoolbar/markdown.js b/app/assets/javascripts/jstoolbar/markdown.js deleted file mode 100644 index b15d201831..0000000000 --- a/app/assets/javascripts/jstoolbar/markdown.js +++ /dev/null @@ -1,193 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * This file is part of DotClear. - * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All - * rights reserved. - * - * DotClear is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * DotClear is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with DotClear; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ***** END LICENSE BLOCK ***** -*/ - -/* Modified by JP LANG for textile formatting */ - -// strong -jsToolBar.prototype.elements.strong = { - type: 'button', - title: 'Strong', - fn: { - wiki: function() { this.singleTag('**') } - } -}; - -// em -jsToolBar.prototype.elements.em = { - type: 'button', - title: 'Italic', - fn: { - wiki: function() { this.singleTag("_") } - } -}; - -// del -jsToolBar.prototype.elements.del = { - type: 'button', - title: 'Deleted', - fn: { - wiki: function() { this.singleTag('~~') } - } -}; - -// code -jsToolBar.prototype.elements.code = { - type: 'button', - title: 'Code', - fn: { - wiki: function() { this.singleTag('`') } - } -}; - -// spacer -jsToolBar.prototype.elements.space1 = {type: 'space'}; - -// headings -jsToolBar.prototype.elements.h1 = { - type: 'button', - title: 'Heading 1', - fn: { - wiki: function() { - this.encloseLineSelection('# ', '',function(str) { - str = str.replace(/^#+/, ''); - return str; - }); - } - } -}; -jsToolBar.prototype.elements.h2 = { - type: 'button', - title: 'Heading 2', - fn: { - wiki: function() { - this.encloseLineSelection('## ', '',function(str) { - str = str.replace(/^#+/, ''); - return str; - }); - } - } -}; -jsToolBar.prototype.elements.h3 = { - type: 'button', - title: 'Heading 3', - fn: { - wiki: function() { - this.encloseLineSelection('### ', '',function(str) { - str = str.replace(/^#+/, ''); - return str; - }); - } - } -}; - -// spacer -jsToolBar.prototype.elements.space2 = {type: 'space'}; - -// ul -jsToolBar.prototype.elements.ul = { - type: 'button', - title: 'Unordered list', - fn: { - wiki: function() { - this.encloseLineSelection('','',function(str) { - str = str.replace(/\r/g,''); - return str.replace(/(\n|^)[#-]?\s*/g,"$1- "); - }); - } - } -}; - -// ol -jsToolBar.prototype.elements.ol = { - type: 'button', - title: 'Ordered list', - fn: { - wiki: function() { - this.encloseLineSelection('','',function(str) { - str = str.replace(/\r/g,''); - return str.replace(/(\n|^)[*-]?\s*/g,"$11. "); - }); - } - } -}; - -// spacer -jsToolBar.prototype.elements.space3 = {type: 'space'}; - -// bq -jsToolBar.prototype.elements.bq = { - type: 'button', - title: 'Quote', - fn: { - wiki: function() { - this.encloseLineSelection('','',function(str) { - str = str.replace(/\r/g,''); - return str.replace(/(\n|^) *([^\n]*)/g,"$1> $2"); - }); - } - } -}; - -// unbq -jsToolBar.prototype.elements.unbq = { - type: 'button', - title: 'Unquote', - fn: { - wiki: function() { - this.encloseLineSelection('','',function(str) { - str = str.replace(/\r/g,''); - return str.replace(/(\n|^) *[>]? *([^\n]*)/g,"$1$2"); - }); - } - } -}; - -// pre -jsToolBar.prototype.elements.code = { - type: 'button', - title: 'Code fence', - fn: { - wiki: function() { this.encloseLineSelection('```\n', '\n```') } - } -}; - -// spacer -jsToolBar.prototype.elements.space4 = {type: 'space'}; - -// wiki page -jsToolBar.prototype.elements.link = { - type: 'button', - title: 'Link', - fn: { - wiki: function() { this.encloseSelection("[", "]()") } - } -}; -// image -jsToolBar.prototype.elements.img = { - type: 'button', - title: 'Image', - fn: { - wiki: function() { this.encloseSelection("![](", ")") } - } -}; - - diff --git a/app/assets/javascripts/jstoolbar/textile.js b/app/assets/javascripts/jstoolbar/textile.js deleted file mode 100644 index fef9112dd6..0000000000 --- a/app/assets/javascripts/jstoolbar/textile.js +++ /dev/null @@ -1,202 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * This file is part of DotClear. - * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All - * rights reserved. - * - * DotClear is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * DotClear is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with DotClear; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ***** END LICENSE BLOCK ***** -*/ - -/* Modified by JP LANG for textile formatting */ - -// strong -jsToolBar.prototype.elements.strong = { - type: 'button', - title: 'Strong', - fn: { - wiki: function() { this.singleTag('*') } - } -}; - -// em -jsToolBar.prototype.elements.em = { - type: 'button', - title: 'Italic', - fn: { - wiki: function() { this.singleTag("_") } - } -}; - -// ins -jsToolBar.prototype.elements.ins = { - type: 'button', - title: 'Underline', - fn: { - wiki: function() { this.singleTag('+') } - } -}; - -// del -jsToolBar.prototype.elements.del = { - type: 'button', - title: 'Deleted', - fn: { - wiki: function() { this.singleTag('-') } - } -}; - -// code -jsToolBar.prototype.elements.pre = { - type: 'button', - title: 'Code', - fn: { - wiki: function() { this.singleTag('@') } - } -}; - -// spacer -jsToolBar.prototype.elements.space1 = {type: 'space'}; - -// headings -jsToolBar.prototype.elements.h1 = { - type: 'button', - title: 'Heading 1', - fn: { - wiki: function() { - this.encloseLineSelection('h1. ', '',function(str) { - str = str.replace(/^h\d+\.\s+/, ''); - return str; - }); - } - } -}; -jsToolBar.prototype.elements.h2 = { - type: 'button', - title: 'Heading 2', - fn: { - wiki: function() { - this.encloseLineSelection('h2. ', '',function(str) { - str = str.replace(/^h\d+\.\s+/, ''); - return str; - }); - } - } -}; -jsToolBar.prototype.elements.h3 = { - type: 'button', - title: 'Heading 3', - fn: { - wiki: function() { - this.encloseLineSelection('h3. ', '',function(str) { - str = str.replace(/^h\d+\.\s+/, ''); - return str; - }); - } - } -}; - -// spacer -jsToolBar.prototype.elements.space2 = {type: 'space'}; - -// ul -jsToolBar.prototype.elements.ul = { - type: 'button', - title: 'Unordered list', - fn: { - wiki: function() { - this.encloseLineSelection('','',function(str) { - str = str.replace(/\r/g,''); - return str.replace(/(\n|^)[#-]?\s*/g,"$1* "); - }); - } - } -}; - -// ol -jsToolBar.prototype.elements.ol = { - type: 'button', - title: 'Ordered list', - fn: { - wiki: function() { - this.encloseLineSelection('','',function(str) { - str = str.replace(/\r/g,''); - return str.replace(/(\n|^)[*-]?\s*/g,"$1# "); - }); - } - } -}; - -// spacer -jsToolBar.prototype.elements.space3 = {type: 'space'}; - -// bq -jsToolBar.prototype.elements.bq = { - type: 'button', - title: 'Quote', - fn: { - wiki: function() { - this.encloseLineSelection('','',function(str) { - str = str.replace(/\r/g,''); - return str.replace(/(\n|^) *([^\n]*)/g,"$1> $2"); - }); - } - } -}; - -// unbq -jsToolBar.prototype.elements.unbq = { - type: 'button', - title: 'Unquote', - fn: { - wiki: function() { - this.encloseLineSelection('','',function(str) { - str = str.replace(/\r/g,''); - return str.replace(/(\n|^) *[>]? *([^\n]*)/g,"$1$2"); - }); - } - } -}; - -// pre -jsToolBar.prototype.elements.pre = { - type: 'button', - title: 'Preformatted text', - fn: { - wiki: function() { this.encloseLineSelection('
\n', '\n
') } - } -}; - -// spacer -jsToolBar.prototype.elements.space4 = {type: 'space'}; - -// wiki page -jsToolBar.prototype.elements.link = { - type: 'button', - title: 'Wiki link', - fn: { - wiki: function() { this.encloseSelection("[[", "]]") } - } -}; -// image -jsToolBar.prototype.elements.img = { - type: 'button', - title: 'Image', - fn: { - wiki: function() { this.encloseSelection("!", "!") } - } -}; - - diff --git a/app/assets/javascripts/jstoolbar/translations.js b/app/assets/javascripts/jstoolbar/translations.js deleted file mode 100644 index 1874dc71ef..0000000000 --- a/app/assets/javascripts/jstoolbar/translations.js +++ /dev/null @@ -1,20 +0,0 @@ -jQuery(function() { - jsToolBar.strings = { - 'Strong': I18n.t('js.wiki_formatting.strong'), - 'Italic': I18n.t('js.wiki_formatting.italic'), - 'Underline': I18n.t('js.wiki_formatting.underline'), - 'Deleted': I18n.t('js.wiki_formatting.deleted'), - 'Code': I18n.t('js.wiki_formatting.code'), - 'Heading 1': I18n.t('js.wiki_formatting.heading1'), - 'Heading 2': I18n.t('js.wiki_formatting.heading2'), - 'Heading 3': I18n.t('js.wiki_formatting.heading3'), - 'Unordered list': I18n.t('js.wiki_formatting.unordered_list'), - 'Ordered list': I18n.t('js.wiki_formatting.ordered_list'), - 'Quote': I18n.t('js.wiki_formatting.quote'), - 'Unquote': I18n.t('js.wiki_formatting.unquote'), - 'Preformatted text': I18n.t('js.wiki_formatting.preformatted_text'), - 'Wiki link': I18n.t('js.wiki_formatting.wiki_link'), - 'Image': I18n.t('js.wiki_formatting.image') - } -}); - diff --git a/app/assets/stylesheets/openproject/_index.sass b/app/assets/stylesheets/openproject/_index.sass index bd45845923..a10e93138d 100644 --- a/app/assets/stylesheets/openproject/_index.sass +++ b/app/assets/stylesheets/openproject/_index.sass @@ -2,7 +2,6 @@ @import openproject/announcements @import openproject/functions @import openproject/homescreen -@import openproject/jstoolbar // Legacy styles, remove if possible @import openproject/legacy diff --git a/app/assets/stylesheets/openproject/_jstoolbar.sass b/app/assets/stylesheets/openproject/_jstoolbar.sass deleted file mode 100644 index fe73bfb8fc..0000000000 --- a/app/assets/stylesheets/openproject/_jstoolbar.sass +++ /dev/null @@ -1,154 +0,0 @@ -//-- copyright -// OpenProject is a project management system. -// Copyright (C) 2012-2018 the OpenProject Foundation (OPF) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License version 3. -// -// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -// Copyright (C) 2006-2017 Jean-Philippe Lang -// Copyright (C) 2010-2013 the ChiliProject Team -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// See docs/COPYRIGHT.rdoc for more details. -//++ - -$jstoolbar--icon-background: #fff -$jstoolbar--icon-hover-border: #ccc -$jstoolbar--icon-border: #fff -$jstoolbar--icon-active-border: #bbb -$jstoolbar--icon-active-background: #eee - -.jstEditor - padding-left: 0 - clear: both - - textarea, iframe - margin: 0 - - textarea - min-height: 200px - - textarea.-small - min-height: 50px - -.jstHandle - height: 10px - font-size: 0.1em - cursor: s-resize - -.jstElements - background: #fff - float: right - line-height: 1.6rem - margin-bottom: 0.25rem - text-align: right - - button - @include icon-common - padding: 0.25rem - margin-left: 0.125rem - height: 1.625rem - width: 1.625rem - max-width: 1.625rem - border: 1px solid $jstoolbar--icon-border - background-color: $jstoolbar--icon-background - color: $body-font-color - border-radius: 2px - overflow: hidden - display: inline-block - - &:hover - border-color: $jstoolbar--icon-hover-border - cursor: pointer - - &:focus - border-color: $jstoolbar--icon-hover-border - - &.-active - border-color: $jstoolbar--icon-hover-border - box-shadow: inset 0px 0px 3px $jstoolbar--icon-active-border - background: $jstoolbar--icon-active-background - - &:before - display: block - - span - display: none - - .jstb_help - font-size: 0.8125rem - padding: 0.35rem - line-height: 1rem - @extend .icon-help1 - - &:before - color: $body-font-color - padding: 0 - - span - display: inline - - -.jstSpacer - width: 0 - font-size: 1px - margin-right: 4px - -.jstb_strong - @extend .icon-bold - -.jstb_em - @extend .icon-italic - -.jstb_ins - @extend .icon-underline - -.jstb_del - @extend .icon-strike-through - -.jstb_code - @extend .icon-code-tag - -.jstb_h1 - @extend .icon-headline1 - -.jstb_h2 - @extend .icon-headline2 - -.jstb_h3 - @extend .icon-headline3 - -.jstb_ul - @extend .icon-unordered-list - -.jstb_ol - @extend .icon-ordered-list - -.jstb_bq - @extend .icon-paragraph-right - -.jstb_unbq - @extend .icon-paragraph-left - -.jstb_pre - @extend .icon-pre - -.jstb_link - @extend .icon-link - -.jstb_img - @extend .icon-image1 diff --git a/app/controllers/boards_controller.rb b/app/controllers/boards_controller.rb index 67bdf7b0e5..c16528ad43 100644 --- a/app/controllers/boards_controller.rb +++ b/app/controllers/boards_controller.rb @@ -80,7 +80,9 @@ class BoardsController < ApplicationController render template: 'messages/index' end format.atom do - @messages = @board.messages.order(["#{Message.table_name}.sticked_on ASC", sort_clause].compact.join(', ')) + @messages = @board + .messages + .order(["#{Message.table_name}.sticked_on ASC", sort_clause].compact.join(', ')) .includes(:author, :board) .limit(Setting.feeds_limit.to_i) @@ -90,14 +92,15 @@ class BoardsController < ApplicationController end def set_topics - @topics = @board.topics.order(["#{Message.table_name}.sticked_on ASC", sort_clause].compact.join(', ')) - .includes(:author, last_reply: :author) + @topics = @board + .topics + .order(["#{Message.table_name}.sticked_on ASC", sort_clause].compact.join(', ')) + .includes(:author, last_reply: :author) .page(params[:page]) .per_page(per_page_param) end - def new - end + def new; end def create if @board.save @@ -108,8 +111,7 @@ class BoardsController < ApplicationController end end - def edit - end + def edit; end def update if @board.update_attributes(permitted_params.board) diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index bde22329e8..b7ca2efdd7 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -30,10 +30,6 @@ class HelpController < ApplicationController layout 'help' - def wiki_syntax; end - - def wiki_syntax_detailed; end - def keyboard_shortcuts; end def text_formatting diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 6e31a28471..43f0b0898e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -633,12 +633,6 @@ module ApplicationHelper end end - def wiki_helper - helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) - extend helper - self - end - def link_to_content_update(text, url_params = {}, html_options = {}) link_to(text, url_params, html_options) end diff --git a/app/helpers/text_formatting_helper.rb b/app/helpers/text_formatting_helper.rb index 22feffe840..954e9ec8ea 100644 --- a/app/helpers/text_formatting_helper.rb +++ b/app/helpers/text_formatting_helper.rb @@ -52,10 +52,9 @@ module TextFormattingHelper end end - private - + #TODO remove def current_formatting_helper - helper_class = OpenProject::TextFormatting::Formatters.helper_for(Setting.text_formatting) + helper_class = OpenProject::TextFormatting::Formats.rich_helper helper_class.new(self) end end diff --git a/app/views/attribute_help_texts/_form.html.erb b/app/views/attribute_help_texts/_form.html.erb index 192a5a7fd0..50653c1a09 100644 --- a/app/views/attribute_help_texts/_form.html.erb +++ b/app/views/attribute_help_texts/_form.html.erb @@ -41,7 +41,6 @@ See docs/COPYRIGHT.rdoc for more details. <% end %>
- <%= f.text_area :help_text, :cols => 100, :rows => 20, :class => 'wiki-edit' %> - <%= wikitoolbar_for("#{f.object_name}_help_text") %> + <%= f.text_area :help_text, cols: 100, rows: 20, class: 'wiki-edit', with_text_formatting: true %>
diff --git a/app/views/boards/index.html.erb b/app/views/boards/index.html.erb index aee679f795..937cad297c 100644 --- a/app/views/boards/index.html.erb +++ b/app/views/boards/index.html.erb @@ -88,8 +88,9 @@ See docs/COPYRIGHT.rdoc for more details. <%= board.messages_count %> <% if board.last_message %> + <% board.last_message %> <%= authoring board.last_message.created_on, board.last_message.author %>
- <%= link_to_message board.last_message %> + <%= link_to_message board.last_message, no_root: true %> <% end %> diff --git a/app/views/boards/show.html.erb b/app/views/boards/show.html.erb index f77cf3b0cd..76d01d410e 100644 --- a/app/views/boards/show.html.erb +++ b/app/views/boards/show.html.erb @@ -130,7 +130,7 @@ See docs/COPYRIGHT.rdoc for more details. <% if message.last_reply %> <%= authoring message.last_reply.created_on, message.last_reply.author %>

- <%= link_to message.subject, topic_path(message.last_reply) %> + <%= link_to_message message.last_reply, no_root: true %> <% end %> diff --git a/app/views/help/wiki_syntax.html.erb b/app/views/help/wiki_syntax.html.erb deleted file mode 100644 index 7cfa9d4404..0000000000 --- a/app/views/help/wiki_syntax.html.erb +++ /dev/null @@ -1,235 +0,0 @@ -<%#-- copyright -OpenProject is a project management system. -Copyright (C) 2012-2018 the OpenProject Foundation (OPF) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 3. - -OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -Copyright (C) 2006-2017 Jean-Philippe Lang -Copyright (C) 2010-2013 the ChiliProject Team - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -See docs/COPYRIGHT.rdoc for more details. - -++#%> -<% content_for :styles do %> - h1 { font-family: Verdana, sans-serif; font-size: 14px; text-align: center; color: #444; } - body { font-family: Verdana, sans-serif; font-size: 12px; color: #444; } - table th { padding-top: 1em; } - table td { vertical-align: top; background-color: #f5f5f5; height: 2em; vertical-align: middle;} - table td code { font-size: 1.2em; } - table td h1 { font-size: 1.8em; text-align: left; } - table td h2 { font-size: 1.4em; text-align: left; } - table td h3 { font-size: 1.2em; text-align: left; } -<% end %> - -<% html_title "Wiki Syntax Quick Reference" %> -

Wiki Syntax Quick Reference

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Font Styles
<%= image_tag 'jstoolbar/bt_strong.png', style: 'border: 1px solid #bbb', alt: 'Strong' %>*Strong*Strong
<%= image_tag 'jstoolbar/bt_em.png', style: 'border: 1px solid #bbb', alt: 'Italic' %>_Italic_Italic
<%= image_tag 'jstoolbar/bt_ins.png', style: 'border: 1px solid #bbb', alt: 'Underline' %>+Underline+Underline
<%= image_tag 'jstoolbar/bt_del.png', style: 'border: 1px solid #bbb', alt: 'Deleted' %>-Deleted-Deleted
??Quote??Quote
<%= image_tag 'jstoolbar/bt_code.png', style: 'border: 1px solid #bbb', alt: 'Inline Code' %>@Inline Code@Inline Code
<%= image_tag 'jstoolbar/bt_pre.png', style: 'border: 1px solid #bbb', alt: 'Preformatted text' %><pre>
-  lines
-  of code
- </pre>
-
- lines
- of code
-
-
Lists
<%= image_tag 'jstoolbar/bt_ul.png', style: 'border: 1px solid #bbb', alt: 'Unordered list' %>* Item 1
- * Item 2
-
    -
  • Item 1
  • -
  • Item 2
  • -
-
<%= image_tag 'jstoolbar/bt_ol.png', style: 'border: 1px solid #bbb', alt: 'Ordered list' %># Item 1
- # Item 2
-
    -
  1. Item 1
  2. -
  3. Item 2
  4. -
-
Headings
<%= image_tag 'jstoolbar/bt_h1.png', style: 'border: 1px solid #bbb', alt: 'Heading 1' %>h1. Title 1 -

Title 1

-
<%= image_tag 'jstoolbar/bt_h2.png', style: 'border: 1px solid #bbb', alt: 'Heading 2' %>h2. Title 2 -

Title 2

-
<%= image_tag 'jstoolbar/bt_h3.png', style: 'border: 1px solid #bbb', alt: 'Heading 3' %>h3. Title 3 -

Title 3

-
Links
http://foo.barhttp://foo.bar
"Foo":http://foo.barFoo
OpenProject links
<%= image_tag 'jstoolbar/bt_link.png', style: 'border: 1px solid #bbb', alt: 'Link to a Wiki page' %>[[Wiki page]]Wiki page
<%= image_tag 'jstoolbar/bt_link.png', style: 'border: 1px solid #bbb', alt: 'Link to a Wiki page' %>[[Sandbox:Wiki page]]Wiki page (On the Sandbox project)
WorkPackage #12WorkPackage #12
WorkPackage ##12WorkPackage Bug #12: WorkPackage Subject 2012-06-06 – 2013-06-06
WorkPackage ###12WorkPackage Bug #12: WorkPackage Subject 2012-06-06 – 2013-06-06 - -
- Responsible: John Doe
- Assigned to: John Doe -
-
- I am the description of this work package. -
-
Link user#4 via ID
(Using links in work package descriptions or comments will trigger a "you were mentioned" email notification. Type '@' to let an autocompleter suggest you project members to link to.)
Link John Doe via ID
Link user:"johndoe" via login name
(Using links in work package descriptions or comments will trigger a "you were mentioned" email notification.)
Link John Doe via login name
Revision r43Revision r43
commit:f30e13e43f30e13e4
source:some/filesource:some/file
Inline images
<%= image_tag 'jstoolbar/bt_img.png', style: 'border: 1px solid #bbb', alt: 'Image' %>!image_url!
!attached_image!
- -

- <%= link_to_function 'More Information', "window.open('wiki_syntax_detailed', '', '')" %> -

diff --git a/app/views/help/wiki_syntax_detailed.html.erb b/app/views/help/wiki_syntax_detailed.html.erb deleted file mode 100644 index a8c7fa316d..0000000000 --- a/app/views/help/wiki_syntax_detailed.html.erb +++ /dev/null @@ -1,297 +0,0 @@ -<%#-- copyright -OpenProject is a project management system. -Copyright (C) 2012-2018 the OpenProject Foundation (OPF) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License version 3. - -OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -Copyright (C) 2006-2017 Jean-Philippe Lang -Copyright (C) 2010-2013 the ChiliProject Team - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -See docs/COPYRIGHT.rdoc for more details. - -++#%> -<% content_for :styles do %> - body { font:80% Verdana,Tahoma,Arial,sans-serif; } - h1, h2, h3, h4 { font-family: Trebuchet MS,Georgia,"Times New Roman",serif; } - pre, code { font-size:120%; } - pre code { font-size:100%; } - pre { - margin: 1em 1em 1em 1.6em; - padding: 2px; - background-color: #fafafa; - border: 1px solid #dadada; - width:95%; - overflow-x: auto; - } - a.new { color: #b73535; } - - .CodeRay .c { color:#666; } - - .CodeRay .cl { color:#B06; font-weight:bold } - .CodeRay .dl { color:black } - .CodeRay .fu { color:#06B; font-weight:bold } - - .CodeRay .il { background: #eee } - .CodeRay .il .idl { font-weight: bold; color: #888 } - - .CodeRay .iv { color:#33B } - .CodeRay .r { color:#080; font-weight:bold } - - .CodeRay .s { background-color:#fff0f0 } - .CodeRay .s .dl { color:#710 } -<% end %> -<% html_title "Wiki Formatting" %> -

Wiki Formatting

-

Links

-

OpenProject links

-

OpenProject allows hyperlinking between work packages, changesets and wiki pages from anywhere wiki formatting is used.

- -

Wiki links:

- -

You can also link to pages of an other project wiki:

- -

Wiki links are displayed in red if the page doesn't exist yet, eg: Nonexistent page.

-

Links to other resources:

- - - - - -

Escaping:

- -

External links

-

HTTP URLs and email addresses are automatically turned into clickable links:

-
-https://www.openproject.org, someone@foo.bar
-
-

displays: https://www.openproject.org, someone@foo.bar

-

If you want to display a specific text instead of the URL, you can use the standard textile syntax:

-
-"OpenProject web site":https://www.openproject.org
-
-

displays: OpenProject web site

-

Text formatting

-

For things such as headlines, bold, tables, lists, OpenProject supports Textile syntax. See http://txstyle.org/ for information on using any of these features. A few samples are included below, but the engine is capable of much more of that.

-

Font style

-
-* *bold*
-* _italic_
-* _*bold italic*_
-* +underline+
-* -strike-through-
-
-

Display:

- -

Inline images

- -

Headings

-

Prefixing a line with h1., h2. etc. will create a heading:

-
-h1. Heading
-h2. Subheading
-h3. Subsubheading
-
-

OpenProject assigns an anchor to each of those headings thus you can link to them with "#Heading", "#Subheading" and so forth.

-

Numbered Headings

-

- You may also define numbered headings by prefixing lines with h1#., h2#. etc. The heading numbers are then automatically managed by OpenProject for you. -

- - - - - - - - - - - - - -
- Wiki format - - Resulting Text -
-
-h1#. Topic Foo
-h2#. Sub-Topic Foo Bar
-h1#. Topic Baz
-
-
- 1. Topic A
- 1.2. Sub-Topic 1
- 2. Topic B -
-

Paragraphs

-
-p>. right aligned
-p=. centered
-
-

This is a centered paragraph.

-

Blockquotes

-

Start the paragraph with bq.

-
-bq. Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
-To go live, all you need to add is a database and a web server.
-
-

Display:

-
-

Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
- To go live, all you need to add is a database and a web server.

-
-

Table of content

-
-{{toc}} => left aligned toc
-{{>toc}} => right aligned toc
-
-

Acronyms

-

Display tooltip for acronym by entering tooltip in parantheses after upper case -acronym.

-
-WHO(World Health Organisation) => Displays "World Health Organisation" as
-tooltip of "WHO"
-
-

- WHO -

-

Macros

-

OpenProject has the following builtin macros:

-

-

-
hello_world
-
-

Sample macro.

-
-
include
-
-

Include a wiki page. Example:

-
{{include(Foo)}}
-
-
child_pages
-
-

Displays a list of child pages. With no argument, it displays the child pages of the current wiki page. Examples:

-

-        {{child_pages}} -- can be used from a wiki page only
-        {{child_pages(Foo)}} -- lists all children of page Foo
-        {{child_pages(Foo, parent=1)}} -- same as above with a link to page Foo
-      
-
-
macro_list
-
-

Displays a list of all available macros, including description if available.

-
-
-

-

Code highlighting

-

Code highlighting relies on CodeRay, a fast syntax highlighting library written completely in Ruby. It currently supports c, cpp, css, delphi, groovy, html, java, javascript, json, php, python, rhtml, ruby, scheme, sql, xml and yaml languages.

-

You can highlight code in your wiki page using this syntax:

-
-<pre><code class="ruby">
-  Place you code here.
-</code></pre>
-
-

Example:

-
 1 # The Greeter class
- 2 class Greeter
- 3   def initialize(name)
- 4     @name = name.capitalize
- 5   end
- 6
- 7   def salute
- 8     puts "Hello #{@name}!"
- 9   end
-10 end
-
-
diff --git a/app/views/settings/_general.html.erb b/app/views/settings/_general.html.erb index 8e1eb40d67..59c8b7c644 100644 --- a/app/views/settings/_general.html.erb +++ b/app/views/settings/_general.html.erb @@ -49,13 +49,6 @@ See docs/COPYRIGHT.rdoc for more details.
<%= setting_select :protocol, [['HTTP', 'http'], ['HTTPS', 'https']], container_class: '-xslim' %>
-
<%= setting_select :text_formatting, OpenProject::TextFormatting::Formatters.format_names.collect{|name| [t("text_formatting.#{name}"), name]}, container_class: '-xslim' %>
-
- <%= setting_check_box :use_wysiwyg %> - - <%= t(:setting_use_wysiwyg_description) %> - -
<%= setting_check_box :cache_formatted_text %>
<%= setting_select :wiki_compression, [['Gzip', 'gzip']], blank: :label_none, container_class: '-xslim' %>
<%= setting_check_box :feeds_enabled, size: 6 %>
diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index d963767139..9b1b98c63b 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -13,8 +13,6 @@ OpenProject::Application.configure do copy_issue_actions.js date-de-DE.js date-en-US.js - jstoolbar/textile.js - jstoolbar/markdown.js locales/*.js members_form.js members_select_boxes.js diff --git a/config/initializers/redcloth_numbered_headings.rb b/config/initializers/redcloth_numbered_headings.rb deleted file mode 100644 index 2720832e64..0000000000 --- a/config/initializers/redcloth_numbered_headings.rb +++ /dev/null @@ -1,131 +0,0 @@ -#-- encoding: UTF-8 - -#-- copyright -# OpenProject is a project management system. -# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2017 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See docs/COPYRIGHT.rdoc for more details. -#++ - -require 'redcloth3' - -module RedCloth3Patch - private - - def block_textile_prefix(text) - text.replace(prepend_number_to_heading(text)) - - super(text) - end - - HEADING = /^h(\d)\.(.*)$/ unless defined? HEADING - NUMBERED_HEADING = /^h(\d)#\.(.*)$/ unless defined? NUMBERED_HEADING - - def prepend_number_to_heading(text) - if text =~ NUMBERED_HEADING - level = $1.to_i - - number = get_next_number_or_start_new_numbering level - - new_text = "h#{level}. #{number}#{$2}" - elsif text =~ HEADING - reset_numbering - end - - new_text.nil? ? text : new_text - end - - def get_next_number_or_start_new_numbering(level) - begin - number = get_number_for_level level - rescue ArgumentError - reset_numbering - number = get_number_for_level level - end - - number - end - - def get_number_for_level(level) - @numbering_provider ||= Redcloth3::NumberingStack.new level - - @numbering_provider.get_next_numbering_for_level level - end - - def reset_numbering - @numbering_provider = nil - end -end - -RedCloth3.send(:prepend, RedCloth3Patch) - -module Redcloth3 - class NumberingStack - def initialize(level) - @stack = [] - @init_level = level ? level.to_i : 1 - end - - def get_next_numbering_for_level(level) - internal_level = map_external_to_internal_level level - - increase_numbering_for_level internal_level - - current_numbering - end - - private - - def increase_numbering_for_level(level) - if @stack[level].nil? - @stack[level] = 1 - fill_nil_levels_with_zero - else - @stack[level] += 1 - reset_higher_levels_than level - end - - @stack[level] - end - - def reset_higher_levels_than(level) - @stack = @stack.slice! 0, level + 1 - end - - def current_numbering - @stack.join('.') + '.' - end - - def map_external_to_internal_level(level) - if level.to_i < @init_level - raise ArgumentError, 'Current level lower than initial level' - end - level.to_i - @init_level - end - - def fill_nil_levels_with_zero - @stack.map! { |e| e.nil? ? 0 : e } - end - end -end diff --git a/config/locales/en.yml b/config/locales/en.yml index 77032372ba..613e8dec91 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1999,7 +1999,6 @@ en: setting_brute_force_block_after_failed_logins: "Block user after this number of failed login attempts" setting_brute_force_block_minutes: "Time the user is blocked for" setting_cache_formatted_text: "Cache formatted text" - setting_use_wysiwyg: "WYSIWYG editor" setting_use_wysiwyg_description: "Select to enable CKEditor5 WYSIWYG editor for all users by default. CKEditor has limited functionality for GFM Markdown." setting_column_options: "Customize the appearance of the work package lists" setting_commit_fix_keywords: "Fixing keywords" @@ -2074,7 +2073,6 @@ en: setting_start_of_week: "Week starts on" setting_sys_api_enabled: "Enable repository management web service" setting_sys_api_description: "The repository management web service provides integration and user authorization for accessing repositories." - setting_text_formatting: "Text formatting" setting_time_format: "Time format" setting_accessibility_mode_for_anonymous: "Enable accessibility mode for anonymous users" setting_user_format: "Users display format" @@ -2099,7 +2097,6 @@ en: deletion: "Deletion" text_formatting: - textile: 'Textile' markdown: 'Markdown' plain: 'Plain text' diff --git a/config/routes.rb b/config/routes.rb index a3d9338dee..5d8966bacf 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -88,7 +88,6 @@ OpenProject::Application.routes.draw do mount API::Root => '/' get '/roles/workflow/:id/:role_id/:type_id' => 'roles#workflow' - get '/help/:ctrl/:page' => 'help#index' get '/types/:id/edit/:tab' => "types#edit", as: "edit_type_tab" @@ -493,8 +492,6 @@ OpenProject::Application.routes.draw do resource :help, controller: :help, only: [] do member do - get :wiki_syntax - get :wiki_syntax_detailed get :keyboard_shortcuts get :text_formatting end diff --git a/config/settings.yml b/config/settings.yml index fbeb171a07..deea499151 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -77,7 +77,7 @@ consent_time: consent_info: serialized: true default: - en: "h2. Consent\n\nYou need to agree to the privacy and security policy of this OpenProject instance." + en: "## Consent\n\nYou need to agree to the privacy and security policy of this OpenProject instance." # Indicates wether or not users need to consent to something such as privacy policy. consent_required: default: 0 @@ -144,10 +144,6 @@ bcc_recipients: default: 1 plain_text_mail: default: 0 -text_formatting: - default: textile -use_wysiwyg: - default: 1 cache_formatted_text: default: 0 wiki_compression: diff --git a/spec_legacy/functional/help_controller_spec.rb b/db/migrate/20180706150714_convert_to_markdown.rb similarity index 76% rename from spec_legacy/functional/help_controller_spec.rb rename to db/migrate/20180706150714_convert_to_markdown.rb index 9dbfdff55b..16de2880a3 100644 --- a/spec_legacy/functional/help_controller_spec.rb +++ b/db/migrate/20180706150714_convert_to_markdown.rb @@ -1,5 +1,3 @@ -#-- encoding: UTF-8 - #-- copyright # OpenProject is a project management system. # Copyright (C) 2012-2018 the OpenProject Foundation (OPF) @@ -28,20 +26,15 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require_relative '../legacy_spec_helper' - -describe HelpController, type: :controller do - render_views - - specify 'renders wiki_syntax properly' do - get 'wiki_syntax' - - assert_select 'h1', 'Wiki Syntax Quick Reference' - end +class ConvertToMarkdown < ActiveRecord::Migration[5.1] + def up + setting = Setting.where(name: 'text_formatting').pluck(:value) - specify 'renders wiki_syntax_detailed properly' do - get 'wiki_syntax_detailed' + if setting && setting[0] == 'textile' + converter = OpenProject::TextFormatting::Formatters::Markdown::TextileConverter.new + converter.run! + end - assert_select 'h1', 'Wiki Formatting' + Setting.where(name: %w(text_formatting use_wysiwyg)).delete_all end end diff --git a/docs/api/apiv3/basic-objects.apib b/docs/api/apiv3/basic-objects.apib index a2912d3dcd..1f71654412 100644 --- a/docs/api/apiv3/basic-objects.apib +++ b/docs/api/apiv3/basic-objects.apib @@ -143,24 +143,21 @@ embedded errors or simply state that multiple errors occured. # Formattable Text -OpenProject supports text formatting in Textile. Other text formats *may* be introduced in the future. -Properties that contain formattable text have a special representation in this API. In this specification their +OpenProject supports text formatting in Markdown. Properties that contain formattable text have a special representation in this API. In this specification their type is indicated as `Formattable`. Their representation contains the following properties: | Property | Description | Type | Example | Supported operations | |:--------:| -------------------------------------------------- | ------ | ---------------------------------- | -------------------- | -| format | Indicates the formatting language of the raw text | String | textile | READ | -| raw | The raw text, as entered by the user | String | `I *am* formatted!` | READ / WRITE | +| format | Indicates the formatting language of the raw text | String | markdown | READ | +| raw | The raw text, as entered by the user | String | `I **am** formatted!` | READ / WRITE | | html | The text converted to HTML according to the format | String | `I am formatted!` | READ | `format` can as of today have one of the following values: * `plain` - only basic formatting, e.g. inserting paragraphs and line breaks into HTML -* `textile` - formatting using Textile +* `markdown` - formatting using Markdown * `custom` - There is no apparent formatting rule that transforms the raw version to HTML (only used for read only properties) -More formats might be added in the future. - Note that `raw` is the only property supporting the **write** operation. A property of type *Formattable* that is marked as **read and write**, will only accept changes to the `raw` property. Changes to `format` and `html` will be **silently ignored**. It is thus sufficient to solely provide the `raw` property for changes. @@ -170,8 +167,8 @@ If the *Formattable* is marked as **read only**, the `raw` attribute also become #### Example { - "format": "textile", - "raw": "I *am* formatted!", + "format": "markdown", + "raw": "I **am** formatted!", "html": "I am formatted!" } diff --git a/docs/api/apiv3/endpoints/activities.apib b/docs/api/apiv3/endpoints/activities.apib index 482a3780e2..e76eb6e710 100644 --- a/docs/api/apiv3/endpoints/activities.apib +++ b/docs/api/apiv3/endpoints/activities.apib @@ -35,13 +35,13 @@ Activity can be either _type Activity or _type Activity::Comment. "id": 1, "details": [ { - "format": "textile", + "format": "markdown", "raw": "Lorem ipsum dolor sit amet.", "html": "

Lorem ipsum dolor sit amet.

" } ], "comment": { - "format": "textile", + "format": "markdown", "raw": "Lorem ipsum dolor sit amet.", "html": "

Lorem ipsum dolor sit amet.

" }, diff --git a/docs/api/apiv3/endpoints/forms.apib b/docs/api/apiv3/endpoints/forms.apib index dbc042a71b..6a4df00906 100644 --- a/docs/api/apiv3/endpoints/forms.apib +++ b/docs/api/apiv3/endpoints/forms.apib @@ -21,7 +21,7 @@ Subsequent calls to the form should contain a single JSON object as described by |:-------------------:| --------------------------------------------------------------------- | -------------------------------- | | validate | Validate changes, show errors and allowed values for changed resource | | | commit | Actually perform changes to the resource | form content is valid | -| previewMarkup | Post markup (e.g. textile) here to receive an HTML-rendered response | | +| previewMarkup | Post markup (e.g. markdown) here to receive an HTML-rendered response | | ## Linked Properties @@ -88,7 +88,7 @@ That is because the main purpose of a form is helping the client to sort out val "method": "POST" }, "previewMarkup": { - "href": "/api/v3/render/textile", + "href": "/api/v3/render/markdown", "method": "POST" }, "commit": { diff --git a/docs/api/apiv3/endpoints/help_texts.apib b/docs/api/apiv3/endpoints/help_texts.apib index 0076d0d231..5a2ccbbf67 100644 --- a/docs/api/apiv3/endpoints/help_texts.apib +++ b/docs/api/apiv3/endpoints/help_texts.apib @@ -45,7 +45,7 @@ "attributeCaption": 'ID', "scope": 'WorkPackage', "helpText": { - "format": "textile", + "format": "markdown", "raw": "Help text for id attribute.", "html": "

Help text for id attribute.

" } @@ -62,7 +62,7 @@ "attributeCaption": 'Status', "scope": 'WorkPackage', "helpText": { - "format": "textile", + "format": "markdown", "raw": "Help text for status attribute.", "html": "

Help text for status attribute.

" } @@ -99,7 +99,7 @@ "attributeCaption": 'ID', "scope": 'WorkPackage', "helpText": { - "format": "textile", + "format": "markdown", "raw": "Help text for id attribute.", "html": "

Help text for id attribute.

" } diff --git a/docs/api/apiv3/endpoints/render.apib b/docs/api/apiv3/endpoints/render.apib index 94805fc547..60e53be678 100644 --- a/docs/api/apiv3/endpoints/render.apib +++ b/docs/api/apiv3/endpoints/render.apib @@ -1,27 +1,28 @@ # Group Previewing -Throughout OpenProject user input for many properties can be formatted (e.g. using *Textile*). +Throughout OpenProject user input for many properties can be formatted using *Markdown*. Using the appropriate rendering endpoint it is possible to render custom formatted inputs into HTML and thus receive a preview of the rendered text. The request to a rendering endpoint must always have a MIME-Type of `text/plain`. The request body is the actual string that shall be rendered as HTML string. -## Textile [/api/v3/render/textile{?context}] +## Markdown [/api/v3/render/markdown{?context}] + Model + Body -

Hello world! This is textile!

+

Hello world! This is markdown!

-## Preview Textile document [POST] +## Preview Markdown document [POST] + Parameters + context (optional, string, `/api/v3/work_packages/42`) API-Link to the context in which the rendering occurs, for example a specific work package. If left out only context-agnostic rendering takes place. - Please note that OpenProject features textile-extensions that can only work given a context (e.g. display attached images). + Please note that OpenProject features markdown-extensions on top of the extensions GitHub Flavored Markdown (gfm) already + provides that can only work given a context (e.g. display attached images). **Supported contexts:** @@ -29,11 +30,11 @@ The request body is the actual string that shall be rendered as HTML string. + Request (text/plain) - Hello world! "This":http://example.com *is* textile! + Hello world! "This":http://example.com **is** markdown! + Response 200 (text/html) - [Textile][] + [Markdown][] + Response 400 (application/json) @@ -47,7 +48,7 @@ The request body is the actual string that shall be rendered as HTML string. { "_type": "Error", "errorIdentifier": "urn:openproject-org:api:v3:errors:InvalidRenderContext", - "message": "Could not render textile string in the given context." + "message": "Could not render markdown string in the given context." } + Response 415 (application/json) diff --git a/docs/api/apiv3/endpoints/work-packages.apib b/docs/api/apiv3/endpoints/work-packages.apib index 0ddc15ab80..05b0572124 100644 --- a/docs/api/apiv3/endpoints/work-packages.apib +++ b/docs/api/apiv3/endpoints/work-packages.apib @@ -9,7 +9,7 @@ | addRelation | Adds a relation to this work package. | **Permission**: manage wp relations | | addWatcher | Add any user to WP watchers | **Permission**: add watcher | | customActions | Collection of predefined changes that can be applied to the work package | | -| previewMarkup | Post markup (e.g. textile) here to receive an HTML-rendered response | | +| previewMarkup | Post markup (in markdown) here to receive an HTML-rendered response | | | removeWatcher | Remove any user from WP watchers | **Permission**: delete watcher | | unwatch | Remove current user from WP watchers | logged in; watching | | update | Form endpoint that aids in preparing and performing edits on a WP | **Permission**: edit work package | @@ -253,7 +253,7 @@ and [update](#work-packages-work-package-patch). The attachments the work packag "id": 1528, "subject": "Develop API", "description": { - "format": "textile", + "format": "markdown", "raw": "Develop super cool OpenProject API.", "html": "

Develop super cool OpenProject API.

" }, @@ -1962,7 +1962,7 @@ Only linked revisions from repositories are shown if the user has the view chang "id": 1, "details": [ ], "comment": { - "format": "textile", + "format": "markdown", "raw": "Lorem ipsum dolor sit amet.", "html": "

Lorem ipsum dolor sit amet.

" }, @@ -1985,7 +1985,7 @@ Only linked revisions from repositories are shown if the user has the view chang "id": 2, "details": [ ], "comment": { - "format": "textile", + "format": "markdown", "raw": "Lorem ipsum dolor sit amet.", "html": "

Lorem ipsum dolor sit amet.

" }, diff --git a/features/messages/message.feature b/features/messages/message.feature deleted file mode 100644 index c34c613c6e..0000000000 --- a/features/messages/message.feature +++ /dev/null @@ -1,104 +0,0 @@ -#-- copyright -# OpenProject is a project management system. -# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2017 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See docs/COPYRIGHT.rdoc for more details. -#++ - -Feature: Issue textile quickinfo links - - Background: - Given there is 1 project with the following: - | name | parent | - | identifier | parent | - And I am working in project "parent" - And there is a board "development discussion" for project "parent" - And there is a role "member" - And the role "member" may have the following rights: - | manage_boards | - | add_messages | - | edit_messages | - | edit_own_messages | - | delete_messages | - | delete_messages | - | delete_own_messages | - And there is 1 user with the following: - | login | bob | - And the user "bob" is a "member" in the project "parent" - And I am already logged in as "bob" - - Scenario: Adding a message to a forum - When I go to the boards page of the project called "parent" - And I follow "New message" - And I fill in "New relase" for "message_subject" - And I fill in "We have release a new version of our software." for "message_content" - When I click on the first button matching "Create" - Then I should see "New relase" within "#content" - Then I should see "We have release a new version of our software." within "#content" - - Scenario: Message's reply count is zero - Given the board "development discussion" has the following messages: - | message #1 | - When I go to the message page of message "message #1" - Then I should not see "Replies" - - Scenario: Message's reply count is two - Given the board "development discussion" has the following messages: - | message #1 | - And "message #1" has the following replies: - | reply #1 | - | reply #2 | - When I go to the message page of message "message #1" - Then I should see "Replies (2)" - - Scenario: Check field value after error message raise when title is empty - When I go to the boards page of the project called "parent" - And I follow "New message" - And I fill in "New relase FAQ" for "message_subject" - When I click on the first button matching "Create" - Then there should be an error message - Then the "message_subject" field should contain "New relase FAQ" - - Scenario: Check field value after error message raise when description is empty - When I go to the boards page of the project called "parent" - And I follow "New message" - And I fill in "Here you find the most frequently asked questions" for "message_content" - When I click on the first button matching "Create" - Then there should be an error message - Then the "message_content" field should contain "Here you find the most frequently asked questions" - - @javascript - Scenario: Sticky message on top of messages list - Given the board "development discussion" has the following messages: - | message #1 | - | message #2 | - | message #3 | - When I go to the boards page of the project called "parent" - And I follow "New message" - And I fill in "How to?" for "message_subject" - And I fill in "How to st-up project on local mashine." for "message_content" - And I check "Sticky" - When I click on the first button matching "Create" - And I go to the boards page of the project called "parent" - Then "How to?" should be the first row in table diff --git a/features/wiki/wiki_add_edit.feature b/features/wiki/wiki_add_edit.feature deleted file mode 100644 index 24b6ff132c..0000000000 --- a/features/wiki/wiki_add_edit.feature +++ /dev/null @@ -1,73 +0,0 @@ -#-- copyright -# OpenProject is a project management system. -# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2017 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See docs/COPYRIGHT.rdoc for more details. -#++ - -Feature: Adding and Editing Wiki Tabs - - Background: - Given there is 1 project with the following: - | Name | Wookies | - And the project "Wookies" uses the following modules: - | wiki | - And the project "Wookies" has 1 wiki page with the following: - | Title | wookietest | - - @javascript - Scenario: Adding simple wiki tab as admin - Given I am admin - And I am working in project "Wookies" - And I go to the wiki index page of the project called "Wookies" - - @javascript - Scenario: Editing of wiki pages as a member with proper rights - Given there is 1 user with the following: - | login | chewbacca| - And I am logged in as "chewbacca" - And there is a role "humanoid" - And the role "humanoid" may have the following rights: - | view_wiki_pages | - | edit_wiki_pages | - And the user "chewbacca" is a "humanoid" in the project "Wookies" - When I go to the wiki page "wookietest" for the project called "Wookies" - And I click "Edit" - And I fill in "content_text" with "testing wookie" - And I click "Save" - Then I should see "testing wookie" within "#content" - And I click "Edit" - - - @javascript - Scenario: Overview and see the history of a wiki page - Given I am already admin - Given the wiki page "wookietest" of the project "Wookies" has 3 versions - And I go to the wiki page "wookietest" for the project called "Wookies" - And I follow "More" within "#content" - When I click "History" - Then I should see "History" within "#content" - When I press "View differences" - Then I should see "Version 1/4" - Then I should see "Version 2/4" diff --git a/features/wiki/wiki_create_child.feature b/features/wiki/wiki_create_child.feature deleted file mode 100644 index 69741acaa4..0000000000 --- a/features/wiki/wiki_create_child.feature +++ /dev/null @@ -1,71 +0,0 @@ -#-- copyright -# OpenProject is a project management system. -# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2017 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See docs/COPYRIGHT.rdoc for more details. -#++ - -Feature: Creating a wiki child page - - Background: - Given there are no wiki menu items - And there is 1 user with the following: - | login | bob | - And there is a role "member" - And the role "member" may have the following rights: - | view_wiki_pages | - | edit_wiki_pages | - And there is 1 project with the following: - | name | project1 | - | identifier | project1 | - | name | project1 | - And the user "bob" is a "member" in the project "project1" - And I am already logged in as "bob" - - @javascript - Scenario: A user with proper rights can add a child wiki page - Given the project "project1" has 1 wiki page with the following: - | title | Wikiparentpage | - Given I go to the wiki index page of the project called "project1" - And I click "Wikiparentpage" - And I click "Wiki page" - And I fill in "content_page_title" with "Todd's wiki" - And I fill in "content_text" with "Great content" - And I press "Save" - When I go to the wiki index page of the project called "project1" - Then I should see "Todd's wiki" within "#content" - - @javascript - Scenario: Creating a wiki child page the title of which contains special characters - Given the project "project1" has 1 wiki page with the following: - | title | ParentWikiPage | - And the project "project1" has 1 wiki menu item with the following: - | title | ParentWikiPage | - | new_wiki_page | true | - When I go to the wiki page "ParentWikiPage" of the project called "project1" - And I click "Wiki page" - And I fill in "content_page_title" with "Child Page !@#{$%^&*()_},./<>?;':" - And I fill in "content_text" with "Great content" - And I click "Save" - Then I should see "Successful creation." diff --git a/features/wiki/wiki_initial.feature b/features/wiki/wiki_initial.feature deleted file mode 100644 index f39fe552a7..0000000000 --- a/features/wiki/wiki_initial.feature +++ /dev/null @@ -1,52 +0,0 @@ -#-- copyright -# OpenProject is a project management system. -# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2017 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See docs/COPYRIGHT.rdoc for more details. -#++ - -Feature: Activating and deactivating wiki menu as admin - -Background: - -Given I am admin -And there is 1 project with the following: - - | Name | Wookie | - -@javascript -Scenario: Activation of wiki module via aproject settings as admin -When I go to the settings page of the project called "Wookie" -And I click on "tab-modules" -And I check "Wiki" -And I press "Save" -Then I should see "Wiki" within "#menu-sidebar" - -@javascript -Scenario: Deactivation of wiki module via project settings -When I go to the settings page of the project called "Wookie" -And I click on "tab-modules" -And I uncheck "Wiki" -And I press "Save" -And I should not see "Wiki" within "#menu-sidebar" \ No newline at end of file diff --git a/features/wiki/wiki_new_child.feature b/features/wiki/wiki_new_child.feature deleted file mode 100644 index 87c433b4c3..0000000000 --- a/features/wiki/wiki_new_child.feature +++ /dev/null @@ -1,66 +0,0 @@ -#-- copyright -# OpenProject is a project management system. -# Copyright (C) 2012-2018 the OpenProject Foundation (OPF) -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2017 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See docs/COPYRIGHT.rdoc for more details. -#++ - -Feature: Viewing the wiki new child page - - Background: - Given there are no wiki menu items - And there is 1 user with the following: - | login | bob | - And there is a role "member" - And the role "member" may have the following rights: - | view_wiki_pages | - | edit_wiki_pages | - And there is 1 project with the following: - | name | project1 | - | identifier | project1 | - And the user "bob" is a "member" in the project "project1" - And I am already logged in as "bob" - - Scenario: Visiting the wiki new child page with a parent page that has the new child page option enabled on it's menu item should show the page and select the toc menu entry within the wiki menu item - Given the project "project1" has 1 wiki page with the following: - | title | ParentWikiPage | - And the project "project1" has 1 wiki menu item with the following: - | title | ParentWikiPage | - | new_wiki_page | true | - When I go to the wiki page "ParentWikiPage" of the project called "project1" - Then I should see "Wiki page" within "#content" - - Scenario: Visiting the wiki new child page with a related page that has the new child page option disabled on it's menu item should show the page and select no menu item - Given the project "project1" has 1 wiki page with the following: - | title | ParentWikiPage | - And the project "project1" has 1 wiki menu item with the following: - | title | ParentWikiPage | - When I go to the wiki new child page below the "ParentWikiPage" page of the project called "project1" - Then I should see "Wiki page" within "#content" - And there should be no child menu item selected - - Scenario: Visiting the wiki new child page with an invalid parent page - When I go to the wiki new child page below the "InvalidPage" page of the project called "project1" - Then I should see "404" within "#content" - Then I should see "The page you were trying to access doesn't exist or has been removed." diff --git a/frontend/legacy/app/components/help-texts/attribute-help-text.directive.ts b/frontend/legacy/app/components/help-texts/attribute-help-text.directive.ts index 143374f4da..dca3010808 100644 --- a/frontend/legacy/app/components/help-texts/attribute-help-text.directive.ts +++ b/frontend/legacy/app/components/help-texts/attribute-help-text.directive.ts @@ -71,7 +71,7 @@ export class AttributeHelpTextController { }); } - // HACK: without this, the tempalte is not displayed + // HACK: without this, the template is not displayed setTimeout(() => this.$scope.$apply()); }); } diff --git a/frontend/src/app/angular4-modules.ts b/frontend/src/app/angular4-modules.ts index 62493b63e9..9f69a028be 100644 --- a/frontend/src/app/angular4-modules.ts +++ b/frontend/src/app/angular4-modules.ts @@ -188,7 +188,6 @@ import {WorkPackageCommentComponent} from "core-components/work-packages/work-pa import {OpCkeditorFormComponent} from "core-components/ckeditor/op-ckeditor-form.component"; import {WorkPackageUploadComponent} from "core-components/wp-attachments/wp-attachments-upload/wp-attachments-upload.component"; import {OpDragScrollDirective} from "core-app/modules/common/ui/op-drag-scroll.directive"; -import {TextileService} from "core-app/modules/common/textile/textile-service"; import {UIRouterModule} from "@uirouter/angular"; import {initializeUiRouterConfiguration} from "core-components/routing/ui-router.config"; import {WorkPackagesBaseComponent} from "core-components/routing/main/work-packages-base.component"; @@ -250,7 +249,6 @@ import {WikiIncludePageMacroModal} from "core-components/modals/editor/macro-wik deps: [Injector], multi: true }, - TextileService, OpTitleService, TimezoneService, WorkPackageRelationsService, diff --git a/frontend/src/app/components/ckeditor/op-ckeditor-form.component.ts b/frontend/src/app/components/ckeditor/op-ckeditor-form.component.ts index 2c1fb8391b..4c05450dbe 100644 --- a/frontend/src/app/components/ckeditor/op-ckeditor-form.component.ts +++ b/frontend/src/app/components/ckeditor/op-ckeditor-form.component.ts @@ -88,7 +88,7 @@ export class OpCkeditorFormComponent implements OnInit { this.wrappedTextArea = this.formElement.find(this.textareaSelector); this.wrappedTextArea.hide(); const wrapper = this.$element.find(`.${ckEditorReplacementClass}`); - window.OPClassicEditor + let editorPromise = window.OPClassicEditor .create(wrapper[0], { openProject: { context: null, @@ -100,6 +100,8 @@ export class OpCkeditorFormComponent implements OnInit { .catch((error:any) => { console.error(error); }); + + this.$element.data('editor', editorPromise); } public $onDestroy() { @@ -123,6 +125,23 @@ export class OpCkeditorFormComponent implements OnInit { // Continue with submission return true; }); + + this.setLabel(); + + return editor; } -} + private setLabel() { + let textareaId = this.textareaSelector.substring(1); + let label = jQuery(`label[for=${textareaId}`); + + let ckContent = this.$element.find('.ck-content'); + + ckContent.attr('aria-label', null); + ckContent.attr('aria-labelledby', textareaId); + + label.click(() => { + ckContent.focus(); + }); + } +} diff --git a/frontend/src/app/components/wp-activity/user/user-activity.component.ts b/frontend/src/app/components/wp-activity/user/user-activity.component.ts index 52bac345eb..a8b212ce29 100644 --- a/frontend/src/app/components/wp-activity/user/user-activity.component.ts +++ b/frontend/src/app/components/wp-activity/user/user-activity.component.ts @@ -33,7 +33,6 @@ import {ConfigurationService} from 'core-app/modules/common/config/configuration import {WorkPackageCommentField} from 'core-components/work-packages/work-package-comment/wp-comment-field.module'; import {WorkPackageResource} from 'core-app/modules/hal/resources/work-package-resource'; import {WorkPackagesActivityService} from 'core-components/wp-single-view-tabs/activity-panel/wp-activity.service'; -import {TextileService} from "core-app/modules/common/textile/textile-service"; import {AfterViewInit, Component, ElementRef, Inject, Input, OnInit} from "@angular/core"; import {UserCacheService} from "core-components/user/user-cache.service"; import {IEditFieldHandler} from "core-app/modules/fields/edit/editing-portal/edit-field-handler.interface"; @@ -76,7 +75,7 @@ export class UserActivityComponent implements IEditFieldHandler, OnInit, AfterVi label_updated_on: this.I18n.t('js.label_updated_on'), quote_comment: this.I18n.t('js.label_quote_comment'), edit_comment: this.I18n.t('js.label_edit_comment'), - } + }; public accessibilityModeEnabled = this.ConfigurationService.accessibilityModeEnabled(); private $element:JQuery; @@ -88,8 +87,7 @@ export class UserActivityComponent implements IEditFieldHandler, OnInit, AfterVi readonly wpCacheService:WorkPackageCacheService, readonly ConfigurationService:ConfigurationService, readonly userCacheService:UserCacheService, - readonly I18n:I18nService, - readonly textileService:TextileService) { + readonly I18n:I18nService) { } public ngOnInit() { diff --git a/frontend/src/app/globals/augmenting/wiki-toolbar.augment.ts b/frontend/src/app/globals/augmenting/wiki-toolbar.augment.ts deleted file mode 100644 index e34dde6c9a..0000000000 --- a/frontend/src/app/globals/augmenting/wiki-toolbar.augment.ts +++ /dev/null @@ -1,42 +0,0 @@ -//-- copyright -// OpenProject is a project management system. -// Copyright (C) 2012-2018 the OpenProject Foundation (OPF) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License version 3. -// -// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -// Copyright (C) 2006-2017 Jean-Philippe Lang -// Copyright (C) 2010-2013 the ChiliProject Team -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// See docs/COPYRIGHT.rdoc for more details. -//++ - -import {WikiToolbar} from "core-app/globals/augmenting/wiki-toolbar"; - -(function($:JQueryStatic) { - - // Identify all uses - $(function () { - - // Wrap all static wiki-toolbars (rendered from backend) - $('.wiki-toolbar') - .each((i:number, el:HTMLElement) => { - new WikiToolbar(I18n, el); - }); - }); -}(jQuery)); diff --git a/frontend/src/app/globals/augmenting/wiki-toolbar.ts b/frontend/src/app/globals/augmenting/wiki-toolbar.ts deleted file mode 100644 index 25dd7f33eb..0000000000 --- a/frontend/src/app/globals/augmenting/wiki-toolbar.ts +++ /dev/null @@ -1,91 +0,0 @@ -//-- copyright -// OpenProject is a project management system. -// Copyright (C) 2012-2018 the OpenProject Foundation (OPF) -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License version 3. -// -// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -// Copyright (C) 2006-2017 Jean-Philippe Lang -// Copyright (C) 2010-2013 the ChiliProject Team -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of the GNU General Public License -// as published by the Free Software Foundation; either version 2 -// of the License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -// -// See docs/COPYRIGHT.rdoc for more details. -//++ - -import {GlobalI18n} from "core-app/modules/common/i18n/i18n.service"; - -export class WikiToolbar { - public isPreview = false; - - constructor(protected I18n:GlobalI18n, - protected element:HTMLElement, - public previewCallback?:(preview:boolean) => void) { - - this.onInit(); - } - - onInit() { - const element = jQuery(this.element); - const help_link_title = this.I18n.t('js.inplace.link_formatting_help'); - - const button = document.createElement('button'); - button.classList.add('jstb_help', 'formatting-help-link-button'); - button.setAttribute('type', 'button'); - button.setAttribute('aria-label', help_link_title); - button.setAttribute('title', help_link_title); - - const PREVIEW_ENABLE_TEXT = this.I18n.t('js.inplace.btn_preview_enable'); - const PREVIEW_DISABLE_TEXT = this.I18n.t('js.inplace.btn_preview_disable'); - const PREVIEW_BUTTON_CLASS = 'jstb_preview'; - let previewButtonAttributes:any = { - 'class': PREVIEW_BUTTON_CLASS + ' icon-preview icon-small', - 'type': 'button', - 'title': PREVIEW_ENABLE_TEXT, - 'aria-label': PREVIEW_ENABLE_TEXT, - 'text': '' - }; - - let textarea = this.element; - if (!element.is('textarea')) { - textarea = this.element.querySelector('textarea') as any; - } - - const wikiToolbar = new (window as any).jsToolBar(textarea); - wikiToolbar.setHelpLink(button); - wikiToolbar.draw(); - - previewButtonAttributes.click = () => { - this.isPreview = !this.isPreview; - !!this.previewCallback && this.previewCallback(this.isPreview); - - const title = this.isPreview ? PREVIEW_DISABLE_TEXT : PREVIEW_ENABLE_TEXT; - const toggledClasses = 'icon-preview icon-ticket-edit -active'; - - element.closest('.textarea-wrapper') - .find('.' + PREVIEW_BUTTON_CLASS).attr('title', title) - .attr('aria-label', title) - .toggleClass(toggledClasses); - }; - - if (!!this.previewCallback) { - element - .closest('.textarea-wrapper') - .find('.jstb_help') - .after(jQuery('