Feature #27758 » 0002-replace-preview-link-with-write-priview-tabs.patch
app/controllers/messages_controller.rb | ||
---|---|---|
118 | 118 | |
119 | 119 |
def preview |
120 | 120 |
message = @board.messages.find_by_id(params[:id]) |
121 |
@text = (params[:message] || params[:reply])[:content]
|
|
121 |
@text = params[:text] ? params[:text] : nil
|
|
122 | 122 |
@previewed = message |
123 | 123 |
render :partial => 'common/preview' |
124 | 124 |
end |
app/controllers/previews_controller.rb | ||
---|---|---|
16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 | |
18 | 18 |
class PreviewsController < ApplicationController |
19 |
before_action :find_project, :find_attachments |
|
19 |
before_action :find_project, :except => :text |
|
20 |
before_action :find_attachments |
|
20 | 21 | |
21 | 22 |
def issue |
22 |
@issue = Issue.visible.find_by_id(params[:id]) unless params[:id].blank?
|
|
23 |
@issue = Issue.visible.find_by_id(params[:issue_id]) unless params[:issue_id].blank?
|
|
23 | 24 |
if @issue |
24 |
@description = params[:issue] && params[:issue][:description] |
|
25 |
if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n") |
|
26 |
@description = nil |
|
27 |
end |
|
28 |
@notes = params[:journal] ? params[:journal][:notes] : nil |
|
29 |
@notes ||= params[:issue] ? params[:issue][:notes] : nil |
|
30 |
else |
|
31 |
@description = (params[:issue] ? params[:issue][:description] : nil) |
|
25 |
@previewed = @issue |
|
32 | 26 |
end |
33 |
render :layout => false |
|
27 |
@text = params[:text] ? params[:text] : nil |
|
28 |
render :partial => 'common/preview' |
|
34 | 29 |
end |
35 | 30 | |
36 | 31 |
def news |
37 | 32 |
if params[:id].present? && news = News.visible.find_by_id(params[:id]) |
38 | 33 |
@previewed = news |
39 | 34 |
end |
40 |
@text = (params[:news] ? params[:news][:description] : nil)
|
|
35 |
@text = params[:text] ? params[:text] : nil
|
|
41 | 36 |
render :partial => 'common/preview' |
42 | 37 |
end |
43 | 38 | |
39 |
def text |
|
40 |
@text = params[:text] ? params[:text] : nil |
|
41 |
render :partial => 'common/preview' |
|
42 |
end |
|
44 | 43 |
private |
45 | 44 | |
46 | 45 |
def find_project |
app/controllers/wiki_controller.rb | ||
---|---|---|
321 | 321 |
@attachments += page.attachments |
322 | 322 |
@previewed = page.content |
323 | 323 |
end |
324 |
@text = params[:content][:text] |
|
324 |
@text = params[:content].present? ? params[:content][:text] : params[:text]
|
|
325 | 325 |
render :partial => 'common/preview' |
326 | 326 |
end |
327 | 327 |
app/views/boards/show.html.erb | ||
---|---|---|
14 | 14 |
<%= form_for @message, :url => new_board_message_path(@board), :html => {:multipart => true, :id => 'message-form'} do |f| %> |
15 | 15 |
<%= render :partial => 'messages/form', :locals => {:f => f} %> |
16 | 16 |
<p><%= submit_tag l(:button_create) %> |
17 |
<%= preview_link(preview_board_message_path(@board), 'message-form') %> | |
|
18 | 17 |
<%= link_to l(:button_cancel), "#", :onclick => '$("#add-message").hide(); return false;' %></p> |
19 | 18 |
<% end %> |
20 |
<div id="preview" class="wiki"></div> |
|
21 | 19 |
<% end %> |
22 | 20 |
</div> |
23 | 21 | |
... | ... | |
60 | 58 |
<% end %> |
61 | 59 | |
62 | 60 |
<% html_title @board.name %> |
63 | ||
64 | 61 |
<% content_for :header_tags do %> |
65 | 62 |
<%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@project}: #{@board}") %> |
66 | 63 |
<% end %> |
app/views/common/_preview.html.erb | ||
---|---|---|
1 |
<fieldset class="preview"><legend><%= l(:label_preview) %></legend> |
|
2 |
<%= textilizable @text, :attachments => @attachments, :object => @previewed %> |
|
3 |
</fieldset> |
|
1 |
<% unless @text.blank? %> |
|
2 |
<%= textilizable @text, :attachments => @attachments, :object => @previewed %> |
|
3 |
<% else %> |
|
4 |
<p><%= l(:label_nothing_to_preview) %></p> |
|
5 |
<% end %> |
app/views/issues/_edit.html.erb | ||
---|---|---|
30 | 30 |
<% if @issue.notes_addable? %> |
31 | 31 |
<fieldset><legend><%= l(:field_notes) %></legend> |
32 | 32 |
<%= f.text_area :notes, :cols => 60, :rows => 10, :class => 'wiki-edit', :no_label => true %> |
33 |
<%= wikitoolbar_for 'issue_notes' %> |
|
33 |
<%= wikitoolbar_for 'issue_notes', preview_issue_path(:project_id => @project, :issue_id => @issue) %>
|
|
34 | 34 | |
35 | 35 |
<% if @issue.safe_attribute? 'private_notes' %> |
36 | 36 |
<%= f.check_box :private_notes, :no_label => true %> <label for="issue_private_notes"><%= l(:field_private_notes) %></label> |
... | ... | |
68 | 68 |
<%= f.hidden_field :lock_version %> |
69 | 69 |
<%= hidden_field_tag 'last_journal_id', params[:last_journal_id] || @issue.last_journal_id %> |
70 | 70 |
<%= submit_tag l(:button_submit) %> |
71 |
<%= preview_link preview_edit_issue_path(:project_id => @project, :id => @issue), 'issue-form' %> |
|
72 |
| <%= link_to l(:button_cancel), issue_path(id: @issue.id), :onclick => params[:action] == 'show' ? "$('#update').hide(); return false;" : '' %> |
|
71 |
<%= link_to l(:button_cancel), issue_path(id: @issue.id), :onclick => params[:action] == 'show' ? "$('#update').hide(); return false;" : '' %> |
|
73 | 72 | |
74 | 73 |
<%= hidden_field_tag 'prev_issue_id', @prev_issue_id if @prev_issue_id %> |
75 | 74 |
<%= hidden_field_tag 'next_issue_id', @next_issue_id if @next_issue_id %> |
76 | 75 |
<%= hidden_field_tag 'issue_position', @issue_position if @issue_position %> |
77 | 76 |
<%= hidden_field_tag 'issue_count', @issue_count if @issue_count %> |
77 | ||
78 | 78 |
<% end %> |
79 | 79 | |
80 |
<div id="preview" class="wiki"></div> |
app/views/issues/_form.html.erb | ||
---|---|---|
37 | 37 |
:no_label => true %> |
38 | 38 |
<% end %> |
39 | 39 |
</p> |
40 |
<%= wikitoolbar_for 'issue_description' %> |
|
40 |
<%= wikitoolbar_for 'issue_description', preview_issue_path(:project_id => @issue.project, :issue_id => @issue.id) %>
|
|
41 | 41 |
<% end %> |
42 | 42 | |
43 | 43 |
<div id="attributes" class="attributes"> |
app/views/issues/new.html.erb | ||
---|---|---|
39 | 39 | |
40 | 40 |
<%= submit_tag l(:button_create) %> |
41 | 41 |
<%= submit_tag l(:button_create_and_continue), :name => 'continue' %> |
42 |
<%= preview_link preview_new_issue_path(:project_id => @issue.project), 'issue-form' %> |
|
43 | 42 |
<% end %> |
44 | 43 | |
45 |
<div id="preview" class="wiki"></div> |
|
46 | ||
47 | 44 |
<% content_for :header_tags do %> |
48 | 45 |
<%= robot_exclusion_tag %> |
49 | 46 |
<% end %> |
app/views/journals/_notes_form.html.erb | ||
---|---|---|
14 | 14 |
<% end %> |
15 | 15 |
<%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %> |
16 | 16 |
<p><%= submit_tag l(:button_save) %> |
17 |
<%= preview_link preview_edit_issue_path(:project_id => @project, :id => @journal.issue), |
|
18 |
"journal-#{@journal.id}-form", |
|
19 |
"journal_#{@journal.id}_preview" %> | |
|
20 | 17 |
<%= link_to l(:button_cancel), '#', :onclick => "$('#journal-#{@journal.id}-form').remove(); $('#journal-#{@journal.id}-notes').show(); return false;" %></p> |
21 | ||
22 |
<div id="journal_<%= @journal.id %>_preview" class="wiki"></div> |
|
23 | 18 |
<% end %> |
24 |
<%= wikitoolbar_for "journal_#{@journal.id}_notes" %> |
|
19 |
<%= wikitoolbar_for "journal_#{@journal.id}_notes", preview_issue_path(:project_id => @project, :issue_id => @journal.issue) %> |
app/views/messages/_form.html.erb | ||
---|---|---|
24 | 24 |
<p> |
25 | 25 |
<%= label_tag "message_content", l(:description_message_content), :class => "hidden-for-sighted" %> |
26 | 26 |
<%= f.text_area :content, :cols => 80, :rows => 15, :class => 'wiki-edit', :id => 'message_content' %></p> |
27 |
<%= wikitoolbar_for 'message_content' %> |
|
27 |
<%= wikitoolbar_for 'message_content', preview_board_message_path(:board_id => @board, :id => @message) %>
|
|
28 | 28 |
<!--[eoform:message]--> |
29 | 29 | |
30 | 30 |
<p><%= l(:label_attachment_plural) %><br /> |
app/views/messages/edit.html.erb | ||
---|---|---|
12 | 12 |
<%= render :partial => 'form', |
13 | 13 |
:locals => {:f => f, :replying => !@message.parent.nil?} %> |
14 | 14 |
<%= submit_tag l(:button_save) %> |
15 |
<%= preview_link({:controller => 'messages', :action => 'preview', :board_id => @board, :id => @message}, 'message-form') %> |
|
16 | 15 |
<% end %> |
17 |
<div id="preview" class="wiki"></div> |
app/views/messages/new.html.erb | ||
---|---|---|
3 | 3 |
<%= form_for @message, :url => {:action => 'new'}, :html => {:multipart => true, :id => 'message-form'} do |f| %> |
4 | 4 |
<%= render :partial => 'form', :locals => {:f => f} %> |
5 | 5 |
<%= submit_tag l(:button_create) %> |
6 |
<%= preview_link({:controller => 'messages', :action => 'preview', :board_id => @board}, 'message-form') %> |
|
7 | 6 |
<% end %> |
8 | ||
9 |
<div id="preview" class="wiki"></div> |
app/views/messages/show.html.erb | ||
---|---|---|
85 | 85 |
<%= form_for @reply, :as => :reply, :url => {:action => 'reply', :id => @topic}, :html => {:multipart => true, :id => 'message-form'} do |f| %> |
86 | 86 |
<%= render :partial => 'form', :locals => {:f => f, :replying => true} %> |
87 | 87 |
<%= submit_tag l(:button_submit) %> |
88 |
<%= preview_link({:controller => 'messages', :action => 'preview', :board_id => @board}, 'message-form') %> |
|
89 | 88 |
<% end %> |
90 |
<div id="preview" class="wiki"></div> |
|
91 | 89 |
</div> |
92 | 90 |
<% end %> |
93 | 91 |
app/views/news/_form.html.erb | ||
---|---|---|
7 | 7 |
<p id="attachments_form"><label><%= l(:label_attachment_plural) %></label><%= render :partial => 'attachments/form', :locals => {:container => @news} %></p> |
8 | 8 |
</div> |
9 | 9 | |
10 |
<%= wikitoolbar_for 'news_description' %> |
|
10 |
<%= wikitoolbar_for 'news_description', preview_news_path(:project_id => @project, :id => @news) %>
|
app/views/news/edit.html.erb | ||
---|---|---|
3 | 3 |
<%= labelled_form_for @news, :html => { :id => 'news-form', :multipart => true, :method => :put } do |f| %> |
4 | 4 |
<%= render :partial => 'form', :locals => { :f => f } %> |
5 | 5 |
<%= submit_tag l(:button_save) %> |
6 |
<%= preview_link preview_news_path(:project_id => @project, :id => @news), 'news-form' %> |
|
7 | 6 |
<% end %> |
8 |
<div id="preview" class="wiki"></div> |
|
9 | 7 | |
10 | 8 |
<% content_for :header_tags do %> |
11 | 9 |
<%= stylesheet_link_tag 'scm' %> |
app/views/news/index.html.erb | ||
---|---|---|
12 | 12 |
:html => { :id => 'news-form', :multipart => true } do |f| %> |
13 | 13 |
<%= render :partial => 'news/form', :locals => { :f => f } %> |
14 | 14 |
<%= submit_tag l(:button_create) %> |
15 |
<%= preview_link preview_news_path(:project_id => @project), 'news-form' %> | |
|
16 | 15 |
<%= link_to l(:button_cancel), "#", :onclick => '$("#add-news").hide()' %> |
17 | 16 |
<% end if @project %> |
18 |
<div id="preview" class="wiki"></div> |
|
19 | 17 |
</div> |
20 | 18 | |
21 | 19 |
<h2><%=l(:label_news_plural)%></h2> |
app/views/news/new.html.erb | ||
---|---|---|
4 | 4 |
:html => { :id => 'news-form', :multipart => true } do |f| %> |
5 | 5 |
<%= render :partial => 'news/form', :locals => { :f => f } %> |
6 | 6 |
<%= submit_tag l(:button_create) %> |
7 |
<%= preview_link preview_news_path(:project_id => @project), 'news-form' %> |
|
8 | 7 |
<% end %> |
9 |
<div id="preview" class="wiki"></div> |
app/views/news/show.html.erb | ||
---|---|---|
16 | 16 |
:html => { :id => 'news-form', :multipart => true, :method => :put } do |f| %> |
17 | 17 |
<%= render :partial => 'form', :locals => { :f => f } %> |
18 | 18 |
<%= submit_tag l(:button_save) %> |
19 |
<%= preview_link preview_news_path(:project_id => @project, :id => @news), 'news-form' %> | |
|
20 | 19 |
<%= link_to l(:button_cancel), "#", :onclick => '$("#edit-news").hide(); return false;' %> |
21 | 20 |
<% end %> |
22 |
<div id="preview" class="wiki"></div> |
|
23 | 21 |
</div> |
24 | 22 |
<% end %> |
25 | 23 | |
... | ... | |
56 | 54 |
<%= form_tag({:controller => 'comments', :action => 'create', :id => @news}, :id => "add_comment_form", :style => "display:none;") do %> |
57 | 55 |
<div class="box"> |
58 | 56 |
<%= text_area 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit' %> |
59 |
<%= wikitoolbar_for 'comment_comments' %> |
|
57 |
<%= wikitoolbar_for 'comment_comments', preview_news_path(:project_id => @project, :id => @news) %>
|
|
60 | 58 |
</div> |
61 | 59 |
<p><%= submit_tag l(:button_add) %></p> |
62 | 60 |
<% end %> |
app/views/previews/issue.html.erb | ||
---|---|---|
1 |
<% if @notes %> |
|
2 |
<fieldset class="preview"><legend><%= l(:field_notes) %></legend> |
|
3 |
<%= textilizable @notes, :attachments => @attachments, :object => @issue %> |
|
4 |
</fieldset> |
|
5 |
<% end %> |
|
6 | ||
7 |
<% if @description %> |
|
8 |
<fieldset class="preview"><legend><%= l(:field_description) %></legend> |
|
9 |
<%= textilizable @description, :attachments => @attachments, :object => @issue %> |
|
10 |
</fieldset> |
|
11 |
<% end %> |
app/views/wiki/edit.html.erb | ||
---|---|---|
57 | 57 | |
58 | 58 |
<p> |
59 | 59 |
<%= submit_tag l(:button_save) %> |
60 |
<%= preview_link({:controller => 'wiki', :action => 'preview', :project_id => @project, :id => @page.title }, 'wiki_form') %> |
|
61 |
| <%= link_to l(:button_cancel), wiki_page_edit_cancel_path(@page) %> |
|
60 |
<%= link_to l(:button_cancel), wiki_page_edit_cancel_path(@page) %> |
|
62 | 61 |
</p> |
63 |
<%= wikitoolbar_for 'content_text' %> |
|
62 |
<%= wikitoolbar_for 'content_text', preview_project_wiki_page_path(:project_id => @project, :id => @page.title) %>
|
|
64 | 63 |
<% end %> |
65 | 64 | |
66 |
<div id="preview" class="wiki"></div> |
|
67 | ||
68 | 65 |
<% content_for :header_tags do %> |
69 | 66 |
<%= robot_exclusion_tag %> |
70 | 67 |
<% end %> |
config/locales/en.yml | ||
---|---|---|
1026 | 1026 |
label_font_monospace: Monospaced font |
1027 | 1027 |
label_font_proportional: Proportional font |
1028 | 1028 |
label_last_notes: Last notes |
1029 |
label_nothing_to_preview: Nothing to preview |
|
1029 | 1030 | |
1030 | 1031 |
button_login: Login |
1031 | 1032 |
button_submit: Submit |
config/routes.rb | ||
---|---|---|
26 | 26 |
get 'account/activation_email', :to => 'account#activation_email', :as => 'activation_email' |
27 | 27 | |
28 | 28 |
match '/news/preview', :controller => 'previews', :action => 'news', :as => 'preview_news', :via => [:get, :post, :put, :patch] |
29 |
match '/issues/preview/new/:project_id', :to => 'previews#issue', :as => 'preview_new_issue', :via => [:get, :post, :put, :patch] |
|
30 |
match '/issues/preview/edit/:id', :to => 'previews#issue', :as => 'preview_edit_issue', :via => [:get, :post, :put, :patch] |
|
31 | 29 |
match '/issues/preview', :to => 'previews#issue', :as => 'preview_issue', :via => [:get, :post, :put, :patch] |
30 |
match '/preview/text', :to => 'previews#text', :as => 'preview_text', :via => [:get, :post, :put, :patch] |
|
32 | 31 | |
33 | 32 |
match 'projects/:id/wiki/destroy', :to => 'wikis#destroy', :via => [:get, :post] |
34 | 33 | |
... | ... | |
156 | 155 |
end |
157 | 156 |
end |
158 | 157 |
end |
159 |
|
|
158 | ||
160 | 159 |
match 'wiki/index', :controller => 'wiki', :action => 'index', :via => :get |
161 | 160 |
resources :wiki, :except => [:index, :create], :as => 'wiki_page' do |
162 | 161 |
member do |
lib/redmine/wiki_formatting.rb | ||
---|---|---|
214 | 214 |
end |
215 | 215 | |
216 | 216 |
module Helper |
217 |
def wikitoolbar_for(field_id) |
|
217 |
def wikitoolbar_for(field_id, preview_url = preview_text_path)
|
|
218 | 218 |
end |
219 | 219 | |
220 | 220 |
def heads_for_wiki_formatter |
lib/redmine/wiki_formatting/markdown/helper.rb | ||
---|---|---|
19 | 19 |
module WikiFormatting |
20 | 20 |
module Markdown |
21 | 21 |
module Helper |
22 |
def wikitoolbar_for(field_id) |
|
22 |
def wikitoolbar_for(field_id, preview_url = preview_text_path)
|
|
23 | 23 |
heads_for_wiki_formatter |
24 | 24 |
url = "#{Redmine::Utils.relative_url_root}/help/#{current_language.to_s.downcase}/wiki_syntax_markdown.html" |
25 |
javascript_tag("var wikiToolbar = new jsToolBar(document.getElementById('#{field_id}')); wikiToolbar.setHelpLink('#{escape_javascript url}'); wikiToolbar.draw();") |
|
25 |
javascript_tag("var wikiToolbar = new jsToolBar(document.getElementById('#{field_id}')); wikiToolbar.setHelpLink('#{escape_javascript url}'); wikiToolbar.setPreviewUrl('#{preview_url}'); wikiToolbar.draw();")
|
|
26 | 26 |
end |
27 | 27 | |
28 | 28 |
def initial_page_content(page) |
lib/redmine/wiki_formatting/textile/helper.rb | ||
---|---|---|
19 | 19 |
module WikiFormatting |
20 | 20 |
module Textile |
21 | 21 |
module Helper |
22 |
def wikitoolbar_for(field_id) |
|
22 |
def wikitoolbar_for(field_id, preview_url = preview_text_path)
|
|
23 | 23 |
heads_for_wiki_formatter |
24 | 24 |
# Is there a simple way to link to a public resource? |
25 | 25 |
url = "#{Redmine::Utils.relative_url_root}/help/#{current_language.to_s.downcase}/wiki_syntax_textile.html" |
26 |
javascript_tag("var wikiToolbar = new jsToolBar(document.getElementById('#{field_id}')); wikiToolbar.setHelpLink('#{escape_javascript url}'); wikiToolbar.draw();") |
|
26 |
javascript_tag("var wikiToolbar = new jsToolBar(document.getElementById('#{field_id}')); wikiToolbar.setHelpLink('#{escape_javascript url}'); wikiToolbar.setPreviewUrl('#{preview_url}'); wikiToolbar.draw();")
|
|
27 | 27 |
end |
28 | 28 | |
29 | 29 |
def initial_page_content(page) |
public/javascripts/application.js | ||
---|---|---|
449 | 449 |
modal.dialog("close"); |
450 | 450 |
} |
451 | 451 | |
452 |
function submitPreview(url, form, target) { |
|
453 |
$.ajax({ |
|
454 |
url: url, |
|
455 |
type: 'post', |
|
456 |
data: $('#'+form).serialize(), |
|
457 |
success: function(data){ |
|
458 |
$('#'+target).html(data); |
|
459 |
} |
|
460 |
}); |
|
461 |
} |
|
462 | ||
463 | 452 |
function collapseScmEntry(id) { |
464 | 453 |
$('.'+id).each(function() { |
465 | 454 |
if ($(this).hasClass('open')) { |
... | ... | |
846 | 835 |
toggleDisabledInit(); |
847 | 836 |
}); |
848 | 837 | |
838 |
$(document).ready(function(){ |
|
839 |
$('#content').on('click', 'div.jstTabs a.tab-preview', function(event){ |
|
840 |
var tab = $(event.target); |
|
841 | ||
842 |
var url = tab.data('url'); |
|
843 |
var form = tab.parents('form'); |
|
844 |
var jstBlock = tab.parents('.jstBlock'); |
|
845 | ||
846 |
var element = encodeURIComponent(jstBlock.find('.wiki-edit').val()); |
|
847 |
var attachments = form.find('.attachments_fields input').serialize(); |
|
848 | ||
849 |
$.ajax({ |
|
850 |
url: url, |
|
851 |
type: 'post', |
|
852 |
data: "text=" + element + '&' + attachments, |
|
853 |
success: function(data){ |
|
854 |
jstBlock.find('.wiki-preview').html(data); |
|
855 |
} |
|
856 |
}); |
|
857 |
}); |
|
858 |
}); |
|
859 | ||
849 | 860 |
function keepAnchorOnSignIn(form){ |
850 | 861 |
var hash = decodeURIComponent(self.document.location.hash); |
851 | 862 |
if (hash) { |
public/javascripts/attachments.js | ||
---|---|---|
237 | 237 |
'selectionStart': cursorPosition + newLineBefore, |
238 | 238 |
'selectionEnd': cursorPosition + inlineFilename.length + newLineBefore |
239 | 239 |
}); |
240 |
$textarea.closest('.jstEditor') |
|
241 |
.siblings('.jstElements') |
|
240 |
$textarea.parents('.jstBlock') |
|
242 | 241 |
.find('.jstb_img').click(); |
243 | 242 | |
244 | 243 |
// move cursor into next line |
public/javascripts/jstoolbar/jstoolbar.js | ||
---|---|---|
7 | 7 |
* it under the terms of the GNU General Public License as published by |
8 | 8 |
* the Free Software Foundation; either version 2 of the License, or |
9 | 9 |
* (at your option) any later version. |
10 |
*
|
|
10 |
* |
|
11 | 11 |
* DotClear is distributed in the hope that it will be useful, |
12 | 12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | 13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | 14 |
* GNU General Public License for more details. |
15 |
*
|
|
15 |
* |
|
16 | 16 |
* You should have received a copy of the GNU General Public License |
17 | 17 |
* along with DotClear; if not, write to the Free Software |
18 | 18 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
... | ... | |
34 | 34 | |
35 | 35 |
this.textarea = textarea; |
36 | 36 | |
37 |
this.toolbarBlock = document.createElement('div'); |
|
38 |
this.toolbarBlock.className = 'jstBlock'; |
|
39 |
this.textarea.parentNode.insertBefore(this.toolbarBlock, this.textarea); |
|
40 | ||
37 | 41 |
this.editor = document.createElement('div'); |
38 | 42 |
this.editor.className = 'jstEditor'; |
39 | 43 | |
40 |
this.textarea.parentNode.insertBefore(this.editor,this.textarea); |
|
44 |
this.preview = document.createElement('div'); |
|
45 |
this.preview.className = 'wiki wiki-preview hidden'; |
|
46 |
this.preview.setAttribute('id', 'preview_' + textarea.getAttribute('id')); |
|
47 | ||
41 | 48 |
this.editor.appendChild(this.textarea); |
49 |
this.editor.appendChild(this.preview); |
|
50 | ||
51 |
this.tabsBlock = document.createElement('div'); |
|
52 |
this.tabsBlock.className = 'jstTabs tabs'; |
|
53 | ||
54 |
var This = this; |
|
55 |
this.writeTab = new jsTab('Write', true); |
|
56 |
this.writeTab.onclick = function(event) { This.hidePreview.call(This, event); return false; }; |
|
57 | ||
58 |
this.previewTab = new jsTab('Preview'); |
|
59 |
this.previewTab.onclick = function(event) { This.showPreview.call(This, event); return false; }; |
|
60 | ||
61 |
var elementsTab = document.createElement('li'); |
|
62 |
elementsTab.classList = 'tab-elements'; |
|
63 | ||
64 |
var tabs = document.createElement('ul'); |
|
65 |
tabs.appendChild(this.writeTab); |
|
66 |
tabs.appendChild(this.previewTab); |
|
67 |
tabs.appendChild(elementsTab); |
|
68 |
this.tabsBlock.appendChild(tabs); |
|
42 | 69 | |
43 | 70 |
this.toolbar = document.createElement("div"); |
44 | 71 |
this.toolbar.className = 'jstElements'; |
45 |
this.editor.parentNode.insertBefore(this.toolbar,this.editor); |
|
72 |
elementsTab.appendChild(this.toolbar); |
|
73 | ||
74 |
this.toolbarBlock.appendChild(this.tabsBlock); |
|
75 |
this.toolbarBlock.appendChild(this.editor); |
|
46 | 76 | |
47 | 77 |
// Dragable resizing |
48 | 78 |
if (this.editor.addEventListener && navigator.appVersion.match(/\bMSIE\b/)) |
... | ... | |
53 | 83 |
var This = this; |
54 | 84 |
this.handle.addEventListener('mousedown',function(event) { dragStart.call(This,event); },false); |
55 | 85 |
// fix memory leak in Firefox (bug #241518) |
56 |
window.addEventListener('unload',function() {
|
|
86 |
window.addEventListener('unload',function() { |
|
57 | 87 |
var del = This.handle.parentNode.removeChild(This.handle); |
58 | 88 |
delete(This.handle); |
59 | 89 |
},false); |
60 |
|
|
90 | ||
61 | 91 |
this.editor.parentNode.insertBefore(this.handle,this.editor.nextSibling); |
62 | 92 |
} |
63 |
|
|
93 | ||
64 | 94 |
this.context = null; |
65 |
this.toolNodes = {}; // lorsque la toolbar est dessinée , cet objet est garni
|
|
95 |
this.toolNodes = {}; // lorsque la toolbar est dessinée , cet objet est garni |
|
66 | 96 |
// de raccourcis vers les éléments DOM correspondants aux outils. |
67 | 97 |
} |
68 | 98 | |
99 |
function jsTab(name, selected) { |
|
100 |
selected = selected || false; |
|
101 |
if(typeof jsToolBar.strings == 'undefined') { |
|
102 |
var tabName = name || null; |
|
103 |
} else { |
|
104 |
var tabName = jsToolBar.strings[name] || name || null; |
|
105 |
} |
|
106 | ||
107 |
var tab = document.createElement('li'); |
|
108 |
var link = document.createElement('a'); |
|
109 |
link.setAttribute('href', '#'); |
|
110 |
link.innerText = tabName; |
|
111 |
link.className = 'tab-' + name.toLowerCase(); |
|
112 | ||
113 |
if (selected == true) { |
|
114 |
link.classList.add('selected'); |
|
115 |
} |
|
116 |
tab.appendChild(link) |
|
117 | ||
118 |
return tab; |
|
119 |
} |
|
69 | 120 |
function jsButton(title, fn, scope, className) { |
70 | 121 |
if(typeof jsToolBar.strings == 'undefined') { |
71 | 122 |
this.title = title || null; |
... | ... | |
91 | 142 |
if (this.icon != undefined) { |
92 | 143 |
button.style.backgroundImage = 'url('+this.icon+')'; |
93 | 144 |
} |
145 | ||
94 | 146 |
if (typeof(this.fn) == 'function') { |
95 | 147 |
var This = this; |
96 | 148 |
button.onclick = function() { try { This.fn.apply(This.scope, arguments) } catch (e) {} return false; }; |
... | ... | |
110 | 162 |
if (this.width) span.style.marginRight = this.width+'px'; |
111 | 163 | |
112 | 164 |
return span; |
113 |
}
|
|
165 |
} |
|
114 | 166 | |
115 | 167 |
function jsCombo(title, options, scope, fn, className) { |
116 | 168 |
this.title = title || null; |
... | ... | |
136 | 188 | |
137 | 189 |
var This = this; |
138 | 190 |
select.onchange = function() { |
139 |
try {
|
|
191 |
try { |
|
140 | 192 |
This.fn.call(This.scope, this.value); |
141 | 193 |
} catch (e) { alert(e); } |
142 | 194 | |
... | ... | |
152 | 204 |
mode: 'wiki', |
153 | 205 |
elements: {}, |
154 | 206 |
help_link: '', |
155 |
|
|
207 | ||
156 | 208 |
getMode: function() { |
157 | 209 |
return this.mode; |
158 | 210 |
}, |
... | ... | |
170 | 222 |
this.help_link = link; |
171 | 223 |
}, |
172 | 224 | |
225 |
setPreviewUrl: function(url) { |
|
226 |
this.previewTab.firstChild.setAttribute('data-url', url); |
|
227 |
}, |
|
228 | ||
173 | 229 |
button: function(toolName) { |
174 | 230 |
var tool = this.elements[toolName]; |
175 | 231 |
if (typeof tool.fn[this.mode] != 'function') return null; |
... | ... | |
292 | 348 | |
293 | 349 |
encloseSelection: function(prefix, suffix, fn) { |
294 | 350 |
this.textarea.focus(); |
295 | ||
296 | 351 |
prefix = prefix || ''; |
297 | 352 |
suffix = suffix || ''; |
298 | 353 | |
... | ... | |
343 | 398 |
this.textarea.scrollTop = scrollPos; |
344 | 399 |
} |
345 | 400 |
}, |
401 |
showPreview: function(event) { |
|
402 |
if (event.target.classList.contains('selected')) { return; } |
|
403 |
this.preview.setAttribute('style', 'min-height: ' + this.textarea.clientHeight + 'px;') |
|
404 |
this.toolbar.classList.add('hidden'); |
|
405 |
this.textarea.classList.add('hidden'); |
|
406 |
this.preview.classList.remove('hidden'); |
|
407 |
this.tabsBlock.getElementsByClassName('tab-write')[0].classList.remove('selected'); |
|
408 |
event.target.classList.add('selected'); |
|
346 | 409 | |
410 |
}, |
|
411 |
hidePreview: function(event) { |
|
412 |
if (event.target.classList.contains('selected')) { return; } |
|
413 |
this.toolbar.classList.remove('hidden'); |
|
414 |
this.textarea.classList.remove('hidden'); |
|
415 |
this.preview.classList.add('hidden'); |
|
416 |
this.tabsBlock.getElementsByClassName('tab-preview')[0].classList.remove('selected'); |
|
417 |
event.target.classList.add('selected'); |
|
418 |
}, |
|
347 | 419 |
stripBaseURL: function(url) { |
348 | 420 |
if (this.base_url != '') { |
349 | 421 |
var pos = url.indexOf(this.base_url); |
public/javascripts/jstoolbar/lang/jstoolbar-en.js | ||
---|---|---|
15 | 15 |
jsToolBar.strings['Preformatted text'] = 'Preformatted text'; |
16 | 16 |
jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; |
17 | 17 |
jsToolBar.strings['Image'] = 'Image'; |
18 |
jsToolBar.strings['Write'] = 'Write'; |
|
19 |
jsToolBar.strings['Preview'] = 'Preview'; |
public/stylesheets/application.css | ||
---|---|---|
273 | 273 |
tr.issue.idnt-9 td.subject {padding-left: 152px; background-position: 136px 50%;} |
274 | 274 | |
275 | 275 |
table.issue-report {table-layout:fixed;} |
276 |
table.issue-report th {white-space: normal;} |
|
277 | 276 | |
278 | 277 |
tr.entry { border: 1px solid #f8f8f8; } |
279 | 278 |
tr.entry td { white-space: nowrap; } |
... | ... | |
679 | 678 |
min-height: 2em; |
680 | 679 |
clear:left; |
681 | 680 |
} |
682 | ||
683 | 681 |
html>body .tabular p {overflow:hidden;} |
684 | 682 | |
685 | 683 |
.tabular input, .tabular select {max-width:95%} |
... | ... | |
731 | 729 |
input#time_entry_comments { width: 90%;} |
732 | 730 |
input#months { width: 30px; } |
733 | 731 | |
734 |
fieldset.preview {margin-top: 1em; min-width: inherit; background: url(../images/draft.png)} |
|
732 |
.jstBlock .jstTabs, .jstBlock .wiki-preview { width: 99%; } |
|
733 | ||
734 |
.jstBlock .jstTabs { padding-right: 6px; } |
|
735 |
.jstBlock .wiki-preview { padding: 2px; } |
|
736 |
.jstBlock .wiki-preview p:first-child { padding-top: 0 !important;} |
|
737 |
.jstBlock .wiki-preview p:last-child { padding-bottom: 0 !important;} |
|
738 |
#content .box .jstBlock .jstTabs li { background-color: #f6f6f6; } |
|
739 | ||
740 |
.tabular .wiki-preview, .tabular .jstTabs {width: 95%;} |
|
741 |
.tabular.settings .wiki-preview, .tabular.settings .jstTabs { width: 99%; } |
|
742 |
.tabular .wiki-preview p { |
|
743 |
min-height: initial; |
|
744 |
padding: 1em 0 1em 0 !important; |
|
745 |
overflow: initial; |
|
746 |
} |
|
735 | 747 | |
736 | 748 |
.tabular.settings p{ padding-left: 300px; } |
737 | 749 |
.tabular.settings label{ margin-left: -300px; width: 295px; } |
738 |
.tabular.settings textarea { width: 99%; } |
|
750 |
.tabular.settings textarea, .tabular.settings .wiki-preview, .tabular.settings .jstTabs { width: 99%; }
|
|
739 | 751 | |
740 | 752 |
.settings.enabled_scm table {width:100%} |
741 | 753 |
.settings.enabled_scm td.scm_name{ font-weight: bold; } |
public/stylesheets/jstoolbar.css | ||
---|---|---|
1 |
.jstBlock .hidden { |
|
2 |
display: none; |
|
3 |
} |
|
1 | 4 |
.jstEditor { |
2 | 5 |
padding-left: 0px; |
3 | 6 |
} |
4 | 7 |
.jstEditor textarea, .jstEditor iframe { |
5 | 8 |
margin: 0; |
6 | 9 |
} |
7 | ||
8 | 10 |
.jstHandle { |
9 | 11 |
height: 10px; |
10 | 12 |
font-size: 0.1em; |
11 | 13 |
cursor: s-resize; |
12 | 14 |
/*background: transparent url(img/resizer.png) no-repeat 45% 50%;*/ |
13 | 15 |
} |
14 | ||
16 |
#content .jstTabs.tabs { |
|
17 |
margin-bottom: 10px; |
|
18 |
} |
|
19 |
#content .jstTabs.tabs li { |
|
20 |
height: 42px; |
|
21 |
} |
|
22 |
#content .jstTabs.tabs li:before{ |
|
23 |
content: ''; |
|
24 |
display: inline-block; |
|
25 |
vertical-align: middle; |
|
26 |
height: 100%; |
|
27 |
} |
|
28 |
#content .jstTabs.tabs li a { |
|
29 |
display: inline-block; |
|
30 |
vertical-align: bottom; |
|
31 |
line-height: 19px; |
|
32 |
} |
|
15 | 33 |
.jstElements { |
16 |
padding: 3px 3px 3px 0; |
|
34 |
display: inline-block; |
|
35 |
vertical-align: bottom; |
|
36 |
border-bottom: 1px solid #bbbbbb; |
|
37 |
padding-left: 6px; |
|
38 |
height: 26px; |
|
39 |
} |
|
40 |
.wiki-preview { |
|
41 |
background-color: #ffffff; |
|
42 |
border: 1px solid #bbbbbb; |
|
17 | 43 |
} |
18 | 44 | |
19 | 45 |
.jstElements button { |
test/functional/messages_controller_test.rb | ||
---|---|---|
33 | 33 | |
34 | 34 |
assert_select 'h2', :text => 'First post' |
35 | 35 |
end |
36 |
|
|
36 | ||
37 | 37 |
def test_show_should_contain_reply_field_tags_for_quoting |
38 | 38 |
@request.session[:user_id] = 2 |
39 | 39 |
get :show, :params => { |
... | ... | |
214 | 214 |
:id => 1, |
215 | 215 |
:reply => { |
216 | 216 |
:content => 'This is a test reply', |
217 |
:subject => 'Test reply'
|
|
217 |
:subject => 'Test reply' |
|
218 | 218 |
} |
219 | 219 |
} |
220 | 220 |
reply = Message.order('id DESC').first |
... | ... | |
265 | 265 |
post :preview, :params => { |
266 | 266 |
:board_id => 1, |
267 | 267 |
:message => { |
268 |
:subject => "",
|
|
269 |
:content => "Previewed text"
|
|
270 |
}
|
|
268 |
:subject => "" |
|
269 |
},
|
|
270 |
:text => "Previewed text"
|
|
271 | 271 |
} |
272 | 272 |
assert_response :success |
273 | 273 |
assert_include 'Previewed text', response.body |
... | ... | |
280 | 280 |
:board_id => 1, |
281 | 281 |
:message => { |
282 | 282 |
:subject => "", |
283 |
:content => "Previewed text"
|
|
284 |
}
|
|
283 |
},
|
|
284 |
:text => "Previewed text"
|
|
285 | 285 |
} |
286 | 286 |
assert_response :success |
287 | 287 |
assert_include 'Previewed text', response.body |
test/functional/previews_controller_test.rb | ||
---|---|---|
28 | 28 |
:journals, :journal_details, |
29 | 29 |
:news |
30 | 30 | |
31 |
def test_preview_new_issue |
|
31 |
def test_preview_new_issue_description
|
|
32 | 32 |
@request.session[:user_id] = 2 |
33 | 33 |
post :issue, :params => { |
34 | 34 |
:project_id => '1', |
35 |
:issue => { |
|
36 |
:description => 'Foo' |
|
37 |
} |
|
35 |
:text => 'Foo' |
|
38 | 36 |
} |
39 | 37 |
assert_response :success |
40 |
assert_select 'fieldset' do |
|
41 |
assert_select 'legend', :text => 'Description' |
|
42 |
assert_select 'p', :text => 'Foo' |
|
43 |
end |
|
38 |
assert_select 'p', :text => 'Foo' |
|
44 | 39 |
end |
45 | 40 | |
46 |
def test_preview_issue_notes_with_no_change_to_description
|
|
41 |
def test_preview_issue_description |
|
47 | 42 |
@request.session[:user_id] = 2 |
48 | 43 |
post :issue, :params => { |
49 | 44 |
:project_id => '1', |
50 |
:id => 1, |
|
51 |
:issue => { |
|
52 |
:description => Issue.find(1).description, |
|
53 |
:notes => 'Foo' |
|
54 |
} |
|
45 |
:issue_id => 1, |
|
46 |
:text => 'Unable to print recipes' |
|
55 | 47 |
} |
56 | 48 |
assert_response :success |
57 |
assert_select 'legend', :text => 'Description', :count => 0 |
|
58 |
assert_select 'legend', :text => 'Notes' |
|
59 |
end |
|
60 | 49 | |
61 |
def test_preview_issue_notes_with_change_to_description |
|
62 |
@request.session[:user_id] = 2 |
|
63 |
post :issue, :params => { |
|
64 |
:project_id => '1', |
|
65 |
:id => 1, |
|
66 |
:issue => { |
|
67 |
:description => 'Changed description', |
|
68 |
:notes => 'Foo' |
|
69 |
} |
|
70 |
} |
|
71 |
assert_response :success |
|
72 |
assert_select 'legend', :text => 'Description' |
|
73 |
assert_select 'legend', :text => 'Notes' |
|
50 |
assert_select 'p', :text => 'Unable to print recipes' |
|
74 | 51 |
end |
75 | 52 | |
76 |
def test_preview_journal_notes_for_update
|
|
53 |
def test_preview_issue_notes
|
|
77 | 54 |
@request.session[:user_id] = 2 |
78 | 55 |
post :issue, :params => { |
79 | 56 |
:project_id => '1', |
80 | 57 |
:id => 1, |
81 |
:journal => { |
|
82 |
:notes => 'Foo' |
|
83 |
} |
|
58 |
:text => 'Foo' |
|
84 | 59 |
} |
85 | 60 |
assert_response :success |
86 |
assert_select 'legend', :text => 'Notes' |
|
87 | 61 |
assert_select 'p', :text => 'Foo' |
88 | 62 |
end |
89 | 63 | |
... | ... | |
92 | 66 |
@request.session[:user_id] = 2 |
93 | 67 |
post :issue, :params => { |
94 | 68 |
:project_id => '1', |
95 |
:id => 1, |
|
96 |
:issue => { |
|
97 |
:notes => 'attachment:foo.bar' |
|
98 |
} |
|
69 |
:issue_id => 1, |
|
70 |
:field => 'notes', |
|
71 |
:text => 'attachment:foo.bar' |
|
99 | 72 |
} |
100 | 73 |
assert_response :success |
101 | 74 |
assert_select 'a.attachment', :text => 'foo.bar' |
102 | 75 |
end |
103 | 76 | |
104 |
def test_preview_issue_with_project_changed |
|
105 |
@request.session[:user_id] = 2 |
|
106 |
post :issue, :params => { |
|
107 |
:project_id => '1', |
|
108 |
:id => 1, |
|
109 |
:issue => { |
|
110 |
:notes => 'notes', |
|
111 |
:project_id => 2 |
|
112 |
} |
|
113 |
} |
|
114 |
assert_response :success |
|
115 |
assert_select 'legend', :text => 'Notes' |
|
116 |
end |
|
117 | ||
118 | 77 |
def test_preview_new_news |
119 | 78 |
get :news, :params => { |
120 | 79 |
:project_id => 1, |
121 |
:news => { |
|
122 |
:title => '', |
|
123 |
:description => 'News description', |
|
124 |
:summary => '' |
|
125 |
} |
|
80 |
:text => 'News description', |
|
126 | 81 |
} |
127 | 82 |
assert_response :success |
128 |
assert_select 'fieldset.preview', :text => /News description/
|
|
83 |
assert_select 'p', :text => /News description/
|
|
129 | 84 |
end |
130 | 85 | |
131 | 86 |
def test_preview_existing_news |
132 | 87 |
get :news, :params => { |
133 | 88 |
:project_id => 1, |
134 | 89 |
:id => 2, |
135 |
:news => { |
|
136 |
:title => '', |
|
137 |
:description => 'News description', |
|
138 |
:summary => '' |
|
139 |
} |
|
90 |
:text => 'News description' |
|
140 | 91 |
} |
141 | 92 |
assert_response :success |
142 |
assert_select 'fieldset.preview', :text => /News description/
|
|
93 |
assert_select 'p', :text => /News description/
|
|
143 | 94 |
end |
144 | 95 |
end |
test/integration/attachments_test.rb | ||
---|---|---|
77 | 77 | |
78 | 78 |
token = ajax_upload('myupload.jpg', 'JPEG content') |
79 | 79 | |
80 |
post '/issues/preview/new/ecookbook', :params => { |
|
81 |
:issue => {:tracker_id => 1, :description => 'Inline upload: !myupload.jpg!'}, |
|
80 |
post '/issues/preview', :params => { |
|
81 |
:issue => {:tracker_id => 1, :project_id => 'ecookbook'}, |
|
82 |
:text => 'Inline upload: !myupload.jpg!', |
|
82 | 83 |
:attachments => {'1' => {:filename => 'myupload.jpg', :description => 'My uploaded file', :token => token}} |
83 | 84 |
} |
84 | 85 |
assert_response :success |
test/integration/layout_test.rb | ||
---|---|---|
63 | 63 |
Role.anonymous.add_permission! :add_issues |
64 | 64 | |
65 | 65 |
get '/projects/ecookbook/issues/new' |
66 |
assert_select 'head script[src^=?]', '/javascripts/jstoolbar/jstoolbar-textile.min.js?'
|
|
66 |
assert_select 'head script[src^=?]', '/javascripts/jstoolbar/jstoolbar.js?' |
|
67 | 67 |
end |
68 | 68 | |
69 | 69 |
def test_calendar_header_tags |
test/integration/routing/previews_test.rb | ||
---|---|---|
19 | 19 | |
20 | 20 |
class RoutingPreviewsTest < Redmine::RoutingTest |
21 | 21 |
def test_previews |
22 |
should_route 'GET /issues/preview/new/foo' => 'previews#issue', :project_id => 'foo' |
|
23 |
should_route 'PUT /issues/preview/new/foo' => 'previews#issue', :project_id => 'foo' |
|
24 |
should_route 'POST /issues/preview/new/foo' => 'previews#issue', :project_id => 'foo' |
|
25 | ||
26 |
should_route 'GET /issues/preview/edit/321' => 'previews#issue', :id => '321' |
|
27 |
should_route 'PUT /issues/preview/edit/321' => 'previews#issue', :id => '321' |
|
28 |
should_route 'POST /issues/preview/edit/321' => 'previews#issue', :id => '321' |
|
22 |
should_route 'GET /issues/preview' => 'previews#issue' |
|
23 |
should_route 'PUT /issues/preview' => 'previews#issue' |
|
24 |
should_route 'POST /issues/preview' => 'previews#issue' |
|
29 | 25 | |
30 | 26 |
should_route 'GET /news/preview' => 'previews#news' |
27 | ||
28 |
should_route 'GET /preview/text' => 'previews#text' |
|
29 |
should_route 'PUT /preview/text' => 'previews#text' |
|
30 |
should_route 'POST /preview/text' => 'previews#text' |
|
31 | 31 |
end |
32 | 32 |
end |
test/system/issues_test.rb | ||
---|---|---|
179 | 179 |
fill_in 'Subject', :with => 'new issue subject' |
180 | 180 |
fill_in 'Description', :with => 'new issue description' |
181 | 181 |
click_link 'Preview' |
182 |
find 'div.wiki-preview', :visible => true, :text => 'new issue description' |
|
182 | 183 |
end |
183 |
find 'div#preview fieldset', :visible => true, :text => 'new issue description' |
|
184 | 184 |
assert_difference 'Issue.count' do |
185 |
find('input[name=commit]').click
|
|
185 |
click_button('Create')
|
|
186 | 186 |
end |
187 | 187 | |
188 | 188 |
issue = Issue.order('id desc').first |
... | ... | |
314 | 314 |
# Update the notes |
315 | 315 |
fill_in 'Notes', :with => 'Updated notes' |
316 | 316 |
# Preview the change |
317 |
click_on 'Preview'
|
|
318 |
assert page.has_css?('#journal_2_preview')
|
|
319 |
assert page.first('#journal_2_preview').has_content?('Updated notes')
|
|
317 |
page.first('#change-2 a.tab-preview').click
|
|
318 |
assert page.has_css?('#preview_journal_2_notes')
|
|
319 |
assert page.first('#preview_journal_2_notes').has_content?('Updated notes')
|
|
320 | 320 |
# Save |
321 | 321 |
click_on 'Save' |
322 | 322 |