Actualizar plugin CKEditor a 1.2.3

This commit is contained in:
Manuel Cillero 2020-11-30 11:19:32 +01:00
parent fd78375294
commit dda045bde9
23 changed files with 513 additions and 240 deletions

3
plugins/redmine_ckeditor/.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "app/assets/javascripts/ckeditor-releases"]
path = app/assets/javascripts/ckeditor-releases
url = git://github.com/ckeditor/ckeditor-releases.git

View file

@ -1,7 +1,9 @@
gem 'rich', git: 'https://github.com/a-ono/rich.git' source 'https://rubygems.org'
gem 'rich', git: 'https://github.com/a-ono/rich.git', tag: '1.5.2'
gem 'kaminari' gem 'kaminari'
gem 'htmlentities' gem 'htmlentities'
gem 'paperclip', '~> 4.2.1' gem 'paperclip', '~> 6.1.0'
gem 'pandoc-ruby' gem 'pandoc-ruby'
# It is needed for upgrading CKEditor # It is needed for upgrading CKEditor

View file

@ -17,7 +17,9 @@ See {the official site}[http://ckeditor.com/] for more details.
# Mac OS X # Mac OS X
brew install imagemagick brew install imagemagick
* Redmine 3.0.x, (version {1.1.5}[https://github.com/a-ono/redmine_ckeditor/releases/tag/1.1.5]) * Redmine 4.x (version {1.2.3}[https://github.com/a-ono/redmine_ckeditor/releases/tag/1.2.3])
* Redmine 3.x, (version {1.1.7}[https://github.com/a-ono/redmine_ckeditor/releases/tag/1.1.7])
* Redmine 2.3.x, Ruby 1.9.2 or higher (version {1.0.20}[https://github.com/a-ono/redmine_ckeditor/releases/tag/1.0.20]) * Redmine 2.3.x, Ruby 1.9.2 or higher (version {1.0.20}[https://github.com/a-ono/redmine_ckeditor/releases/tag/1.0.20])
@ -33,7 +35,7 @@ See {the official site}[http://ckeditor.com/] for more details.
== Plugin installation and setup == Plugin installation and setup
1. Copy the plugin directory into the plugins directory (make sure the name is redmine_ckeditor) 1. Download the {zip package}[https://github.com/a-ono/redmine_ckeditor/archive/master.zip] and extract the directory that it contains into the plugins directory (make sure the name is redmine_ckeditor)
2. Install the required gems (in the Redmine root directory) 2. Install the required gems (in the Redmine root directory)
bundle install --without development test bundle install --without development test
3. Execute migration 3. Execute migration
@ -84,7 +86,9 @@ This plugin stores contents in HTML format and renders as is.
If you have old contents, these look weird. If you have old contents, these look weird.
You can use {redmine_per_project_formatting}[https://github.com/a-ono/redmine_per_project_formatting] plugin for backward compatibility or execute redmine_ckeditor:migrate task for migrating old text to HTML. You can use {redmine_per_project_formatting}[https://github.com/a-ono/redmine_per_project_formatting] plugin for backward compatibility or execute redmine_ckeditor:migrate task for migrating old text to HTML.
rake redmine_ckeditor:migrate RAILS_ENV=production [PROJECT=project_identifier1,project_identifier2] [FROM=textile] [TO=html] rake redmine_ckeditor:migrate RAILS_ENV=production FROM=textile TO=html
You can also use PROJECT parameter to migrate only specific projets
rake redmine_ckeditor:migrate RAILS_ENV=production PROJECT=project_identifier1,project_identifier2 FROM=textile TO=html
This task requires to {install Pandoc}[http://johnmacfarlane.net/pandoc/installing.html]. This task requires to {install Pandoc}[http://johnmacfarlane.net/pandoc/installing.html].
== Upgrading CKEditor (for development) == Upgrading CKEditor (for development)

View file

@ -0,0 +1,316 @@
/**
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
/*
skin.js
=========
In this file we interact with the CKEditor JavaScript API to register the skin
and enable additional skin related features.
The level of complexity of this file depends on the features available in the
skin. There is only one mandatory line of code to be included here, which is
setting CKEDITOR.skin.name. All the rest is optional, but recommended to be
implemented as they make higher quality skins.
For this skin, the following tasks are achieved in this file:
1. Register the skin.
2. Register browser specific skin files.
3. Define the "Chameleon" feature.
4. Register the skin icons, to have them used on the development version of
the skin.
*/
// 1. Register the skin
// ----------------------
// The CKEDITOR.skin.name property must be set to the skin name. This is a
// lower-cased name, which must match the skin folder name as well as the value
// used on config.skin to tell the editor to use the skin.
//
// This is the only mandatory property to be defined in this file.
CKEDITOR.skin.name = 'moono';
// 2. Register browser specific skin files
// -----------------------------------------
// (http://docs.cksource.com/CKEditor_4.x/Skin_SDK/Browser_Hacks)
//
// To help implementing browser specific "hacks" to the skin files and have it
// easy to maintain, it is possible to have dedicated files for such browsers,
// for both the main skin CSS files: editor.css and dialog.css.
//
// The browser files must be named after the main file names, appended by an
// underscore and the browser name (e.g. editor_ie.css, dialog_ie8.css).
//
// The accepted browser names must match the CKEDITOR.env properties. The most
// common names are: ie, webkit and gecko. Check the documentation for the complete
// list:
// http://docs.ckeditor.com/#!/api/CKEDITOR.env
//
// Internet explorer is an expection and the browser version is also accepted
// (ie7, ie8, ie9, ie10), as well as a special name for IE in Quirks mode (iequirks).
//
// The available browser specific files must be set separately for editor.css
// and dialog.css.
CKEDITOR.skin.ua_editor = 'ie,iequirks,ie7,ie8,gecko';
CKEDITOR.skin.ua_dialog = 'ie,iequirks,ie7,ie8';
// 3. Define the "Chameleon" feature
// -----------------------------------
// (http://docs.cksource.com/CKEditor_4.x/Skin_SDK/Chameleon)
//
// "Chameleon" is a unique feature available in CKEditor. It makes it possible
// to end users to specify which color to use as the basis for the editor UI.
// It is enough to set config.uiColor to any color value and voila, the UI is
// colored.
//
// The only detail here is that the skin itself must be compatible with the
// Chameleon feature. That's because the skin CSS files are the responsible to
// apply colors in the UI and each skin do that in different way and on
// different places.
//
// Implementing the Chameleon feature requires a bit of JavaScript programming.
// The CKEDITOR.skin.chameleon function must be defined. It must return the CSS
// "template" to be used to change the color of a specific CKEditor instance
// available in the page. When a color change is required, this template is
// appended to the page holding the editor, overriding styles defined in the
// skin files.
//
// The "$color" placeholder can be used in the returned string. It'll be
// replaced with the desired color.
CKEDITOR.skin.chameleon = ( function() {
// This method can be used to adjust colour brightness of various element.
// Colours are accepted in 7-byte hex format, for example: #00ff00.
// Brightness ratio must be a float number within [-1, 1],
// where -1 is black, 1 is white and 0 is the original colour.
var colorBrightness = ( function() {
function channelBrightness( channel, ratio ) {
var brighten = ratio < 0 ? (
0 | channel * ( 1 + ratio )
) : (
0 | channel + ( 255 - channel ) * ratio
);
return ( '0' + brighten.toString( 16 ) ).slice( -2 );
}
return function( hexColor, ratio ) {
var channels = hexColor.match( /[^#]./g );
for ( var i = 0 ; i < 3 ; i++ )
channels[ i ] = channelBrightness( parseInt( channels[ i ], 16 ), ratio );
return '#' + channels.join( '' );
};
} )(),
// Use this function just to avoid having to repeat all these rules on
// several places of our template.
verticalGradient = ( function() {
var template = new CKEDITOR.template( 'background:#{to};' +
'background-image:linear-gradient(to bottom,{from},{to});' +
'filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr=\'{from}\',endColorstr=\'{to}\');' );
return function( from, to ) {
return template.output( { from: from, to: to } );
};
} )(),
// Style templates for various user interface parts:
// * Default editor template.
// * Default panel template.
templates = {
editor: new CKEDITOR.template(
'{id}.cke_chrome [border-color:{defaultBorder};] ' +
'{id} .cke_top [ ' +
'{defaultGradient}' +
'border-bottom-color:{defaultBorder};' +
'] ' +
'{id} .cke_bottom [' +
'{defaultGradient}' +
'border-top-color:{defaultBorder};' +
'] ' +
'{id} .cke_resizer [border-right-color:{ckeResizer}] ' +
// Dialogs.
'{id} .cke_dialog_title [' +
'{defaultGradient}' +
'border-bottom-color:{defaultBorder};' +
'] ' +
'{id} .cke_dialog_footer [' +
'{defaultGradient}' +
'outline-color:{defaultBorder};' +
'border-top-color:{defaultBorder};' + // IE7 doesn't use outline.
'] ' +
'{id} .cke_dialog_tab [' +
'{lightGradient}' +
'border-color:{defaultBorder};' +
'] ' +
'{id} .cke_dialog_tab:hover [' +
'{mediumGradient}' +
'] ' +
'{id} .cke_dialog_contents [' +
'border-top-color:{defaultBorder};' +
'] ' +
'{id} .cke_dialog_tab_selected, {id} .cke_dialog_tab_selected:hover [' +
'background:{dialogTabSelected};' +
'border-bottom-color:{dialogTabSelectedBorder};' +
'] ' +
'{id} .cke_dialog_body [' +
'background:{dialogBody};' +
'border-color:{defaultBorder};' +
'] ' +
// Toolbars, buttons.
'{id} .cke_toolgroup [' +
'{lightGradient}' +
'border-color:{defaultBorder};' +
'] ' +
'{id} a.cke_button_off:hover, {id} a.cke_button_off:focus, {id} a.cke_button_off:active [' +
'{mediumGradient}' +
'] ' +
'{id} .cke_button_on [' +
'{ckeButtonOn}' +
'] ' +
'{id} .cke_toolbar_separator [' +
'background-color: {ckeToolbarSeparator};' +
'] ' +
// Combo buttons.
'{id} .cke_combo_button [' +
'border-color:{defaultBorder};' +
'{lightGradient}' +
'] ' +
'{id} a.cke_combo_button:hover, {id} a.cke_combo_button:focus, {id} .cke_combo_on a.cke_combo_button [' +
'border-color:{defaultBorder};' +
'{mediumGradient}' +
'] ' +
// Elementspath.
'{id} .cke_path_item [' +
'color:{elementsPathColor};' +
'] ' +
'{id} a.cke_path_item:hover, {id} a.cke_path_item:focus, {id} a.cke_path_item:active [' +
'background-color:{elementsPathBg};' +
'] ' +
'{id}.cke_panel [' +
'border-color:{defaultBorder};' +
'] '
),
panel: new CKEDITOR.template(
// Panel drop-downs.
'.cke_panel_grouptitle [' +
'{lightGradient}' +
'border-color:{defaultBorder};' +
'] ' +
// Context menus.
'.cke_menubutton_icon [' +
'background-color:{menubuttonIcon};' +
'] ' +
'.cke_menubutton:hover .cke_menubutton_icon, .cke_menubutton:focus .cke_menubutton_icon, .cke_menubutton:active .cke_menubutton_icon [' +
'background-color:{menubuttonIconHover};' +
'] ' +
'.cke_menuseparator [' +
'background-color:{menubuttonIcon};' +
'] ' +
// Color boxes.
'a:hover.cke_colorbox, a:focus.cke_colorbox, a:active.cke_colorbox [' +
'border-color:{defaultBorder};' +
'] ' +
'a:hover.cke_colorauto, a:hover.cke_colormore, a:focus.cke_colorauto, a:focus.cke_colormore, a:active.cke_colorauto, a:active.cke_colormore [' +
'background-color:{ckeColorauto};' +
'border-color:{defaultBorder};' +
'] '
)
};
return function( editor, part ) {
var uiColor = editor.uiColor,
// The following are CSS styles used in templates.
// Styles are generated according to current editor.uiColor.
templateStyles = {
// CKEditor instances have a unique ID, which is used as class name into
// the outer container of the editor UI (e.g. ".cke_1").
//
// The Chameleon feature is available for each CKEditor instance,
// independently. Because of this, we need to prefix all CSS selectors with
// the unique class name of the instance.
id: '.' + editor.id,
// These styles are used by various UI elements.
defaultBorder: colorBrightness( uiColor, -0.1 ),
defaultGradient: verticalGradient( colorBrightness( uiColor, 0.9 ), uiColor ),
lightGradient: verticalGradient( colorBrightness( uiColor, 1 ), colorBrightness( uiColor, 0.7 ) ),
mediumGradient: verticalGradient( colorBrightness( uiColor, 0.8 ), colorBrightness( uiColor, 0.5 ) ),
// These are for specific UI elements.
ckeButtonOn: verticalGradient( colorBrightness( uiColor, 0.6 ), colorBrightness( uiColor, 0.7 ) ),
ckeResizer: colorBrightness( uiColor, -0.4 ),
ckeToolbarSeparator: colorBrightness( uiColor, 0.5 ),
ckeColorauto: colorBrightness( uiColor, 0.8 ),
dialogBody: colorBrightness( uiColor, 0.7 ),
// Use gradient instead of simple hex to avoid further filter resetting in IE.
dialogTabSelected: verticalGradient( '#FFFFFF', '#FFFFFF' ),
dialogTabSelectedBorder: '#FFF',
elementsPathColor: colorBrightness( uiColor, -0.6 ),
elementsPathBg: uiColor,
menubuttonIcon: colorBrightness( uiColor, 0.5 ),
menubuttonIconHover: colorBrightness( uiColor, 0.3 )
};
return templates[ part ]
.output( templateStyles )
.replace( /\[/g, '{' ) // Replace brackets with braces.
.replace( /\]/g, '}' );
};
} )();
// %REMOVE_START%
// 4. Register the skin icons for development purposes only
// ----------------------------------------------------------
// (http://docs.cksource.com/CKEditor_4.x/Skin_SDK/Icons)
//
// This code is here just to make the skin work fully when using its "source"
// version. Without this, the skin will still work, but its icons will not be
// used (again, on source version only).
//
// This block of code is not necessary on the release version of the skin.
// Because of this it is very important to include it inside the REMOVE_START
// and REMOVE_END comment markers, so the skin builder will properly clean
// things up.
//
// If a required icon is not available here, the plugin defined icon will be
// used instead. This means that a skin is not required to provide all icons.
// Actually, it is not required to provide icons at all.
( function() {
// The available icons. This list must match the file names (without
// extension) available inside the "icons" folder.
var icons = ( 'about,anchor-rtl,anchor,bgcolor,bidiltr,bidirtl,blockquote,' +
'bold,bulletedlist-rtl,bulletedlist,button,checkbox,copy-rtl,copy,copyformatting,' +
'creatediv,cut-rtl,cut,docprops-rtl,docprops,find-rtl,find,flash,form,' +
'hiddenfield,horizontalrule,icons,iframe,image,imagebutton,indent-rtl,' +
'indent,italic,justifyblock,justifycenter,justifyleft,justifyright,' +
'link,maximize,newpage-rtl,newpage,numberedlist-rtl,numberedlist,' +
'outdent-rtl,outdent,pagebreak-rtl,pagebreak,paste-rtl,paste,' +
'pastefromword-rtl,pastefromword,pastetext-rtl,pastetext,preview-rtl,' +
'preview,print,radio,redo-rtl,redo,removeformat,replace,save,scayt,' +
'select-rtl,select,selectall,showblocks-rtl,showblocks,smiley,' +
'source-rtl,source,specialchar,spellchecker,strike,subscript,' +
'superscript,table,templates-rtl,templates,textarea-rtl,textarea,' +
'textcolor,textfield-rtl,textfield,uicolor,underline,undo-rtl,undo,unlink' ).split( ',' );
var iconsFolder = CKEDITOR.getUrl( CKEDITOR.skin.path() + 'icons/' + ( CKEDITOR.env.hidpi ? 'hidpi/' : '' ) );
for ( var i = 0; i < icons.length; i++ ) {
CKEDITOR.skin.addIcon( icons[ i ], iconsFolder + icons[ i ] + '.png' );
}
} )();
// %REMOVE_END%

View file

@ -0,0 +1,15 @@
pt:
ckeditor_skin: Skin
ckeditor_ui_color: Cor UI
ckeditor_enter_mode: Modo do ENTER
ckeditor_startup_show_blocks: Blocos de exibição de inicialização
ckeditor_toolbar_can_collapse: Barra de ferramentas pode minimizar
ckeditor_toolbar_location: Barra de ferramentas localização
ckeditor_toolbar_buttons: Barra de ferramentas botões
ckeditor_width: Largura
ckeditor_height: Altura
add: Adicionar
remove: Remover
separator: Separador
subgroup: Subgrupo
line_break: Quebra de linha

View file

@ -1,5 +1,5 @@
# This migration comes from rich (originally 20111002142937) # This migration comes from rich (originally 20111002142937)
class CreateRichRichImages < ActiveRecord::Migration class CreateRichRichImages < ActiveRecord::Migration[4.2]
def change def change
create_table :rich_rich_images do |t| create_table :rich_rich_images do |t|

View file

@ -1,5 +1,5 @@
# This migration comes from rich (originally 20111117202133) # This migration comes from rich (originally 20111117202133)
class AddUriCacheToRichImage < ActiveRecord::Migration class AddUriCacheToRichImage < ActiveRecord::Migration[4.2]
def change def change
add_column :rich_rich_images, :uri_cache, :text add_column :rich_rich_images, :uri_cache, :text
end end

View file

@ -1,5 +1,5 @@
# This migration comes from rich (originally 20111201095829) # This migration comes from rich (originally 20111201095829)
class RefactorImageToFile < ActiveRecord::Migration class RefactorImageToFile < ActiveRecord::Migration[4.2]
def change def change
rename_table :rich_rich_images, :rich_rich_files rename_table :rich_rich_images, :rich_rich_files

View file

@ -1,7 +1,7 @@
require 'redmine' require 'redmine'
require 'redmine_ckeditor' require 'redmine_ckeditor'
Rails.application.config.to_prepare do ActiveSupport::Reloader.to_prepare do
RedmineCkeditor.apply_patch RedmineCkeditor.apply_patch
end end
@ -9,8 +9,8 @@ Redmine::Plugin.register :redmine_ckeditor do
name 'Redmine CKEditor plugin' name 'Redmine CKEditor plugin'
author 'Akihiro Ono' author 'Akihiro Ono'
description 'This is a CKEditor plugin for Redmine' description 'This is a CKEditor plugin for Redmine'
version '1.1.5' version '1.2.3'
requires_redmine :version_or_higher => '3.0.0' requires_redmine :version_or_higher => '4.0.0'
url 'http://github.com/a-ono/redmine_ckeditor' url 'http://github.com/a-ono/redmine_ckeditor'
settings(:partial => 'settings/ckeditor') settings(:partial => 'settings/ckeditor')
@ -19,4 +19,4 @@ Redmine::Plugin.register :redmine_ckeditor do
RedmineCkeditor::WikiFormatting::Helper RedmineCkeditor::WikiFormatting::Helper
end end
Loofah::HTML5::WhiteList::ALLOWED_PROTOCOLS.replace RedmineCkeditor.allowed_protocols (Loofah::VERSION >= "2.3.0" ? Loofah::HTML5::SafeList : Loofah::HTML5::WhiteList)::ALLOWED_PROTOCOLS.replace RedmineCkeditor.allowed_protocols

View file

@ -1,4 +1,5 @@
require 'rake' require 'rake'
require 'rails/generators'
module RedmineCkeditor module RedmineCkeditor
class RichAssetsGenerator < Rails::Generators::Base class RichAssetsGenerator < Rails::Generators::Base

View file

@ -128,17 +128,22 @@ module RedmineCkeditor
end end
def apply_patch def apply_patch
require 'redmine_ckeditor/application_helper_patch' ::ApplicationController.send :helper, ApplicationHelperPatch
require 'redmine_ckeditor/queries_helper_patch' ::JournalsController.prepend JournalsControllerPatch
require 'redmine_ckeditor/rich_files_helper_patch' ::MailHandler.prepend MailHandlerPatch
require 'redmine_ckeditor/journals_controller_patch' ::MessagesController.prepend MessagesControllerPatch
require 'redmine_ckeditor/messages_controller_patch' ::QueriesController.send :helper, QueriesHelperPatch
require 'redmine_ckeditor/mail_handler_patch' ::Rich::FilesController.send :helper, RichFilesHelperPatch
end end
end end
end end
require 'redmine_ckeditor/hooks/views_layouts_hook' require 'redmine_ckeditor/helper'
require 'redmine_ckeditor/hooks/journal_listener' require 'redmine_ckeditor/application_helper_patch'
require 'redmine_ckeditor/queries_helper_patch'
require 'redmine_ckeditor/rich_files_helper_patch'
require 'redmine_ckeditor/journals_controller_patch'
require 'redmine_ckeditor/messages_controller_patch'
require 'redmine_ckeditor/mail_handler_patch'
require 'redmine_ckeditor/pdf_patch' require 'redmine_ckeditor/pdf_patch'
require 'redmine_ckeditor/tempfile_patch' require 'redmine_ckeditor/tempfile_patch'

View file

@ -1,22 +1,13 @@
require_dependency 'application_helper' module RedmineCkeditor
module ApplicationHelperPatch
include RedmineCkeditor::Helper
module ApplicationHelper def format_activity_description(text)
def ckeditor_javascripts if RedmineCkeditor.enabled?
root = RedmineCkeditor.assets_root simple_format(truncate(HTMLEntities.new.decode(strip_tags(text.to_s)), :length => 120))
javascript_tag("CKEDITOR_BASEPATH = '#{root}/ckeditor/';") + else
javascript_include_tag("application", :plugin => "redmine_ckeditor") + super
javascript_tag(RedmineCkeditor.plugins.map {|name| end
path = "#{root}/ckeditor-contrib/plugins/#{name}/"
"CKEDITOR.plugins.addExternal('#{name}', '#{path}/');"
}.join("\n"))
end
def format_activity_description_with_ckeditor(text)
if RedmineCkeditor.enabled?
simple_format(truncate(HTMLEntities.new.decode(strip_tags(text.to_s)), :length => 120))
else
format_activity_description_without_ckeditor(text)
end end
end end
alias_method_chain :format_activity_description, :ckeditor
end end

View file

@ -0,0 +1,37 @@
module RedmineCkeditor
module Helper
def ckeditor_javascripts
root = RedmineCkeditor.assets_root
plugin_script = RedmineCkeditor.plugins.map {|name|
"CKEDITOR.plugins.addExternal('#{name}', '#{root}/ckeditor-contrib/plugins/#{name}/');"
}.join
javascript_tag("CKEDITOR_BASEPATH = '#{root}/ckeditor/';") +
javascript_include_tag("application", :plugin => "redmine_ckeditor") +
javascript_tag(<<-EOT)
#{plugin_script}
CKEDITOR.on("instanceReady", function(event) {
var editor = event.editor;
var textarea = document.getElementById(editor.name);
editor.on("change", function() {
textarea.value = editor.getSnapshot();
});
});
$(window).on("beforeunload", function() {
for (var id in CKEDITOR.instances) {
if (CKEDITOR.instances[id].checkDirty()) {
return #{l(:text_warn_on_leaving_unsaved).inspect};
}
}
});
$(document).on("submit", "form", function() {
for (var id in CKEDITOR.instances) {
CKEDITOR.instances[id].resetDirty();
}
});
EOT
end
end
end

View file

@ -1,36 +0,0 @@
module RedmineCkeditor::Hooks
class JournalListener < Redmine::Hook::ViewListener
def view_journals_notes_form_after_notes(context)
return unless RedmineCkeditor.enabled?
project = context[:project]
journal = context[:journal]
javascript_tag <<-EOT
(function() {
var note_id = "journal_#{journal.id}_notes";
CKEDITOR.replace(note_id, #{RedmineCkeditor.options(project).to_json});
var note = $("#" + note_id);
var save_button = note.parent().find(":submit");
var preview_button = save_button.next();
var cancel_button = preview_button.next().get(0);
save_button.click(function() {
var editor = CKEDITOR.instances[note_id];
note.val(editor.getData());
editor.destroy();
});
preview_button.hide();
var cancel = cancel_button.onclick;
cancel_button.onclick = function() {
CKEDITOR.instances[note_id].destroy();
cancel();
return false;
};
})();
EOT
end
end
end

View file

@ -1,11 +0,0 @@
module RedmineCkeditor
module Hooks
class ViewsLayoutsHook < Redmine::Hook::ViewListener
def view_layouts_base_html_head(context={})
return stylesheet_link_tag('/plugin_assets/redmine_ckeditor/ckeditor-contrib/plugins/codesnippet/lib/highlight/styles/default.css', :media => 'all') +
javascript_include_tag('/plugin_assets/redmine_ckeditor/ckeditor-contrib/plugins/codesnippet/lib/highlight/highlight.pack.js') +
javascript_include_tag('inithighlight', :plugin => 'redmine_ckeditor')
end
end
end
end

View file

@ -1,40 +1,24 @@
require_dependency 'journals_controller'
module RedmineCkeditor module RedmineCkeditor
module JournalsControllerPatch module JournalsControllerPatch
def self.included(base) def new
base.send(:include, InstanceMethods) unless RedmineCkeditor.enabled?
return super
base.class_eval do
unloadable
alias_method_chain :new, :ckeditor
end end
end
module InstanceMethods @journal = Journal.visible.find(params[:journal_id]) if params[:journal_id]
def new_with_ckeditor if @journal
unless RedmineCkeditor.enabled? user = @journal.user
new_without_ckeditor text = @journal.notes
return else
end user = @issue.author
text = @issue.description
@journal = Journal.visible.find(params[:journal_id]) if params[:journal_id]
if @journal
user = @journal.user
text = @journal.notes
else
user = @issue.author
text = @issue.description
end
@content = "<p>#{ll(I18n.locale, :text_user_wrote, user)}</p>"
@content << "<blockquote>#{text}</blockquote><p/>"
render "new_with_ckeditor"
rescue ActiveRecord::RecordNotFound
render_404
end end
@content = "<p>#{ll(I18n.locale, :text_user_wrote, user)}</p>"
@content << "<blockquote>#{text}</blockquote><p/>"
render "new_with_ckeditor"
rescue ActiveRecord::RecordNotFound
render_404
end end
end end
JournalsController.send(:include, JournalsControllerPatch)
end end

View file

@ -1,29 +1,18 @@
require_dependency 'mail_handler'
module RedmineCkeditor module RedmineCkeditor
module MailHandlerPatch module MailHandlerPatch
extend ActiveSupport::Concern
include ActionView::Helpers::TextHelper include ActionView::Helpers::TextHelper
included do def cleaned_up_text_body(format = true)
unloadable if format
alias_method_chain :cleaned_up_text_body, :ckeditor simple_format(super())
alias_method_chain :extract_keyword!, :ckeditor
end
def cleaned_up_text_body_with_ckeditor
if RedmineCkeditor.enabled?
simple_format(cleaned_up_text_body_without_ckeditor)
else else
cleaned_up_text_body_without_ckeditor super()
end end
end end
def extract_keyword_with_ckeditor!(text, attr, format=nil) def extract_keyword!(text, attr, format=nil)
text = cleaned_up_text_body_without_ckeditor if RedmineCkeditor.enabled? text = cleaned_up_text_body(false) if RedmineCkeditor.enabled?
extract_keyword_without_ckeditor!(text, attr, format) super(text, attr, format)
end end
end end
MailHandler.send(:include, MailHandlerPatch)
end end

View file

@ -1,32 +1,16 @@
require_dependency 'messages_controller'
module RedmineCkeditor module RedmineCkeditor
module MessagesControllerPatch module MessagesControllerPatch
def self.included(base) def quote
base.send(:include, InstanceMethods) unless RedmineCkeditor.enabled?
return super
base.class_eval do
unloadable
alias_method_chain :quote, :ckeditor
end end
end
module InstanceMethods @subject = @message.subject
def quote_with_ckeditor @subject = "RE: #{@subject}" unless @subject.starts_with?('RE:')
unless RedmineCkeditor.enabled? @content = "<p>#{ll(I18n.locale, :text_user_wrote, @message.author)}</p>"
quote_without_ckeditor @content << "<blockquote>#{ActionView::Base.full_sanitizer.sanitize(@message.content.to_s)}</blockquote><p/>"
return
end
@subject = @message.subject render "quote_with_ckeditor"
@subject = "RE: #{@subject}" unless @subject.starts_with?('RE:')
@content = "<p>#{ll(I18n.locale, :text_user_wrote, @message.author)}</p>"
@content << "<blockquote>#{ActionView::Base.full_sanitizer.sanitize(@message.content.to_s)}</blockquote><p/>"
render "quote_with_ckeditor"
end
end end
end end
MessagesController.send(:include, MessagesControllerPatch)
end end

View file

@ -1,31 +1,21 @@
require_dependency 'redmine/export/pdf'
module RedmineCkeditor module RedmineCkeditor
module PDFPatch module PDFPatch
def self.included(base) def formatted_text(text)
base.class_eval do html = super
alias_method_chain :formatted_text, :ckeditor
alias_method_chain :get_image_filename, :ckeditor
alias_method_chain :RDMwriteHTMLCell, :ckeditor
end
end
def formatted_text_with_ckeditor(text)
html = formatted_text_without_ckeditor(text)
html = HTMLEntities.new.decode(html) if RedmineCkeditor.enabled? html = HTMLEntities.new.decode(html) if RedmineCkeditor.enabled?
html html
end end
def RDMwriteHTMLCell_with_ckeditor(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0) def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0)
@tmp_images = [] @tmp_images = []
RDMwriteHTMLCell_without_ckeditor(w, h, x, y, txt, attachments, border, ln, fill) super
@tmp_images.each do |item| @tmp_images.each do |item|
#logger.info item #logger.info item
File.delete(item) if File.file?(item) File.delete(item) if File.file?(item)
end end
end end
def get_image_filename_with_ckeditor(attrname) def get_image_filename(attrname)
img = nil img = nil
if attrname.sub!(/^data:([^\/]+)\/([^;]+);base64,/, '') if attrname.sub!(/^data:([^\/]+)\/([^;]+);base64,/, '')
@ -50,12 +40,12 @@ module RedmineCkeditor
img = if attrname.include?("/rich/rich_files/rich_files/") img = if attrname.include?("/rich/rich_files/rich_files/")
Rails.root.join("public#{URI.decode(attrname)}").to_s Rails.root.join("public#{URI.decode(attrname)}").to_s
else else
get_image_filename_without_ckeditor(attrname) super(attrname)
end end
end end
img img
end end
end end
Redmine::Export::PDF::ITCPDF.send(:include, PDFPatch)
end end
Redmine::Export::PDF::ITCPDF.prepend RedmineCkeditor::PDFPatch

View file

@ -1,13 +1,12 @@
require_dependency 'queries_helper' module RedmineCkeditor
module QueriesHelperPatch
module QueriesHelper def csv_value(column, issue, value)
def csv_value_with_ckeditor(column, issue, value) if RedmineCkeditor.enabled? && column.name == :description
if RedmineCkeditor.enabled? && column.name == :description text = Rails::Html::FullSanitizer.new.sanitize(value.to_s)
text = Rails::Html::FullSanitizer.new.sanitize(value.to_s) text.gsub(/(?:\r\n\t*)+/, "\r").gsub("&nbsp;", " ").strip
text.gsub(/(?:\r\n\t*)+/, "\r").gsub("&nbsp;", " ").strip else
else super
csv_value_without_ckeditor(column, issue, value) end
end end
end end
alias_method_chain :csv_value, :ckeditor
end end

View file

@ -1,24 +1,11 @@
require_dependency 'rich/files_helper'
module RedmineCkeditor module RedmineCkeditor
module RichFilesHelperPatch module RichFilesHelperPatch
def self.included(base) def thumb_for_file(file)
base.send(:include, InstanceMethods) Redmine::Utils.relative_url_root + if file.simplified_type == "image"
base.class_eval do file.rich_file.url(:rich_thumb)
alias_method_chain :thumb_for_file, :redmine else
end "/plugin_assets/redmine_ckeditor/images/document-thumb.png"
end
module InstanceMethods
def thumb_for_file_with_redmine(file)
Redmine::Utils.relative_url_root + if file.simplified_type == "image"
file.rich_file.url(:rich_thumb)
else
"/plugin_assets/redmine_ckeditor/images/document-thumb.png"
end
end end
end end
end end
Rich::FilesHelper.send(:include, RichFilesHelperPatch)
end end

View file

@ -1,9 +1,11 @@
class Tempfile module RedmineCkeditor
def initialize_with_binmode(basename, *rest) module TempfilePatch
initialize_without_binmode(basename, *rest).tap do |f| def initialize(basename, *rest)
f.binmode if basename == "raw-upload." super.tap do |f|
f.binmode if basename == "raw-upload."
end
end end
end end
alias_method_chain :initialize, :binmode
end end
Tempfile.prepend RedmineCkeditor::TempfilePatch

View file

@ -1,28 +1,20 @@
module RedmineCkeditor::WikiFormatting module RedmineCkeditor::WikiFormatting
module Helper module Helper
def replace_editor_tag(field_id) include RedmineCkeditor::Helper
javascript_tag <<-EOT
$(document).ready(function() {
#{replace_editor_script(field_id)}
});
EOT
end
def replace_editor_script(field_id) def replace_editor_script(field_id, preview_url)
<<-EOT <<-EOT
(function() { (function() {
var id = '#{field_id}'; var textarea = document.getElementById('#{field_id}');
var textarea = document.getElementById(id); if (!textarea) return;
if (!textarea) return; new jsToolBar(textarea).setPreviewUrl('#{preview_url}');
CKEDITOR.replace(textarea, #{RedmineCkeditor.options(@project).to_json});
var editor = CKEDITOR.replace(textarea, #{RedmineCkeditor.options(@project).to_json}); })();
editor.on("change", function() { textarea.value = editor.getSnapshot(); });
})();
EOT EOT
end end
def overwrite_functions def overwrite_functions
javascript_tag <<-EOT <<-EOT
function showAndScrollTo(id, focus) { function showAndScrollTo(id, focus) {
var elem = $("#" + id); var elem = $("#" + id);
elem.show(); elem.show();
@ -33,21 +25,30 @@ module RedmineCkeditor::WikiFormatting
function destroyEditor(id) { function destroyEditor(id) {
if (CKEDITOR.instances[id]) CKEDITOR.instances[id].destroy(); if (CKEDITOR.instances[id]) CKEDITOR.instances[id].destroy();
} }
if (!jsToolBar.prototype._showPreview) {
jsToolBar.prototype._showPreview = jsToolBar.prototype.showPreview
jsToolBar.prototype.showPreview = function(event) {
this._showPreview(event);
$(this.textarea).next().hide();
}
}
if (!jsToolBar.prototype._hidePreview) {
jsToolBar.prototype._hidePreview = jsToolBar.prototype.hidePreview
jsToolBar.prototype.hidePreview = function(event) {
this._hidePreview(event);
$(this.textarea).next().show();
}
}
EOT EOT
end end
def initial_setup def wikitoolbar_for(field_id, preview_url = preview_text_path)
overwrite_functions heads_for_wiki_formatter
end script = replace_editor_script(field_id, preview_url)
script += overwrite_functions if request.format.html?
def wikitoolbar_for(field_id) javascript_tag script
if params[:format] == "js"
javascript_tag(replace_editor_script(field_id))
else
ckeditor_javascripts +
stylesheet_link_tag('editor', :plugin => 'redmine_ckeditor') +
initial_setup + replace_editor_tag(field_id)
end
end end
def initial_page_content(page) def initial_page_content(page)
@ -55,6 +56,16 @@ module RedmineCkeditor::WikiFormatting
end end
def heads_for_wiki_formatter def heads_for_wiki_formatter
unless @heads_for_wiki_formatter_included
content_for :header_tags do
javascript_include_tag('jstoolbar/jstoolbar') +
javascript_include_tag("jstoolbar/lang/jstoolbar-#{current_language.to_s.downcase}") +
stylesheet_link_tag('jstoolbar') +
ckeditor_javascripts +
stylesheet_link_tag('editor', :plugin => 'redmine_ckeditor')
end
@heads_for_wiki_formatter_included = true
end
end end
end end
end end