Add preview functionality to rich text controls
This commit is contained in:
parent
b6163f0fc2
commit
561f2f694a
15 changed files with 191 additions and 8 deletions
|
@ -205,3 +205,51 @@ function makeShortCode(lat, lon, zoom) {
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Click handler to switch a rich text control to preview mode
|
||||||
|
*/
|
||||||
|
function previewRichtext(event) {
|
||||||
|
var editor = $(this).parents(".richtext_container").find("textarea");
|
||||||
|
var preview = $(this).parents(".richtext_container").find(".richtext_preview");
|
||||||
|
var width = editor.outerWidth() - preview.outerWidth() + preview.innerWidth();
|
||||||
|
var minHeight = editor.outerHeight() - preview.outerHeight() + preview.innerHeight();
|
||||||
|
|
||||||
|
editor.hide();
|
||||||
|
preview.load(editor.attr("data-preview-url"), { text: editor.val() });
|
||||||
|
preview.width(width);
|
||||||
|
preview.css("min-height", minHeight + "px");
|
||||||
|
preview.show();
|
||||||
|
|
||||||
|
$(this).siblings(".richtext_doedit").prop("disabled", false);
|
||||||
|
$(this).prop("disabled", true);
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Click handler to switch a rich text control to edit mode
|
||||||
|
*/
|
||||||
|
function editRichtext(event) {
|
||||||
|
var editor = $(this).parents(".richtext_container").find("textarea");
|
||||||
|
var preview = $(this).parents(".richtext_container").find(".richtext_preview");
|
||||||
|
|
||||||
|
preview.hide();
|
||||||
|
editor.show();
|
||||||
|
|
||||||
|
$(this).siblings(".richtext_dopreview").prop("disabled", false);
|
||||||
|
$(this).prop("disabled", true);
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup any rich text controls
|
||||||
|
*/
|
||||||
|
$(document).ready(function () {
|
||||||
|
$(".richtext_preview").hide();
|
||||||
|
$(".richtext_doedit").prop("disabled", true);
|
||||||
|
$(".richtext_dopreview").prop("disabled", false);
|
||||||
|
$(".richtext_doedit").click(editRichtext);
|
||||||
|
$(".richtext_dopreview").click(previewRichtext);
|
||||||
|
});
|
||||||
|
|
|
@ -1040,3 +1040,61 @@ abbr.geo {
|
||||||
vertical-align: text-bottom;
|
vertical-align: text-bottom;
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Rules for rich text editors */
|
||||||
|
|
||||||
|
.richtext_container {
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
.richtext_content {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
|
||||||
|
.richtext_preview {
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 1px;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
border: 4px solid #eee;
|
||||||
|
background-color: #eee;
|
||||||
|
white-space: normal;
|
||||||
|
|
||||||
|
> :first-child {
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.richtext_help {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
background-color: #ddd;
|
||||||
|
margin-left: 15px;
|
||||||
|
padding: 5px 10px 10px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
vertical-align: top;
|
||||||
|
padding: 0px 15px 0px 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
font-family: fixed;
|
||||||
|
line-height: 16px;
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.richtext_doedit {
|
||||||
|
margin-top: 5px !important;
|
||||||
|
margin-right: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.richtext_dopreview {
|
||||||
|
margin-top: 5px !important;
|
||||||
|
margin-left: 10px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -85,4 +85,8 @@ class SiteController < ApplicationController
|
||||||
def copyright
|
def copyright
|
||||||
@locale = params[:copyright_locale] || I18n.locale
|
@locale = params[:copyright_locale] || I18n.locale
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def preview
|
||||||
|
render :text => RichText.new(params[:format], params[:text]).to_html
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -121,6 +121,24 @@ module ApplicationHelper
|
||||||
Math.log(360.0 / (scale.to_f * 512.0)) / Math.log(2.0)
|
Math.log(360.0 / (scale.to_f * 512.0)) / Math.log(2.0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def richtext_area(object_name, method, options = {})
|
||||||
|
id = "#{object_name.to_s}_#{method.to_s}"
|
||||||
|
format = options.delete(:format) || "markdown"
|
||||||
|
|
||||||
|
content_tag(:div, :id => "#{id}_container", :class => "richtext_container") do
|
||||||
|
output_buffer << content_tag(:div, :id => "#{id}_content", :class => "richtext_content") do
|
||||||
|
output_buffer << text_area(object_name, method, options.merge("data-preview-url" => preview_url(:format => format)))
|
||||||
|
output_buffer << content_tag(:div, "", :id => "#{id}_preview", :class => "richtext_preview")
|
||||||
|
end
|
||||||
|
|
||||||
|
output_buffer << content_tag(:div, :id => "#{id}_help", :class => "richtext_help") do
|
||||||
|
output_buffer << render("site/#{format}_help")
|
||||||
|
output_buffer << submit_tag(I18n.t("site.richtext_area.edit"), :id => "#{id}_doedit", :class => "richtext_doedit", :disabled => true)
|
||||||
|
output_buffer << submit_tag(I18n.t("site.richtext_area.preview"), :id => "#{id}_dopreview", :class => "richtext_dopreview")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def javascript_strings_for_key(key)
|
def javascript_strings_for_key(key)
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
<td class="fieldName"><%= t 'diary_entry.edit.body' -%></td>
|
<td class="fieldName"><%= t 'diary_entry.edit.body' -%></td>
|
||||||
<td><%= f.text_area :body, :cols => 80 %></td>
|
<td><%= richtext_area :diary_entry, :body, :cols => 80 %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
<td class="fieldName"><%= t 'diary_entry.edit.language' -%></td>
|
<td class="fieldName"><%= t 'diary_entry.edit.language' -%></td>
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
|
|
||||||
<%= error_messages_for 'diary_comment' %>
|
<%= error_messages_for 'diary_comment' %>
|
||||||
|
|
||||||
<%= form_for DiaryComment.new, :url => { :action => 'comment' } do |f| %>
|
<%= form_for :diary_comment, :url => { :action => 'comment' } do |f| %>
|
||||||
<%= f.text_area :body, :cols => 80, :rows => 5 %>
|
<%= richtext_area :diary_comment, :body, :cols => 80, :rows => 15 %>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<%= submit_tag t('diary_entry.view.save_button') %>
|
<%= submit_tag t('diary_entry.view.save_button') %>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr valign="top">
|
<tr valign="top">
|
||||||
<td class="fieldName"><%= t'message.new.body' %></td>
|
<td class="fieldName"><%= t'message.new.body' %></td>
|
||||||
<td><%= f.text_area :body, :cols => 80, :value => @body %></td>
|
<td><%= richtext_area :message, :body, :cols => 80, :value => @body %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
|
|
29
app/views/site/_markdown_help.html.erb
Normal file
29
app/views/site/_markdown_help.html.erb
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th colspan="2"><%= t "site.markdown_help.title" %></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th><%= t "site.markdown_help.headings" %></th>
|
||||||
|
<td># <%= t "site.markdown_help.heading" %><br />## <%= t "site.markdown_help.subheading" %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><%= t "site.markdown_help.unordered" %></th>
|
||||||
|
<td>* <%= t "site.markdown_help.first" %><br />* <%= t "site.markdown_help.second" %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><%= t "site.markdown_help.ordered" %></th>
|
||||||
|
<td>1. <%= t "site.markdown_help.first" %><br />2. <%= t "site.markdown_help.second" %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><%= t "site.markdown_help.link" %></th>
|
||||||
|
<td>[<%= t "site.markdown_help.text" %>](<%= t "site.markdown_help.url" %>)</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><%= t "site.markdown_help.image" %></th>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
|
@ -63,7 +63,7 @@
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td class="fieldName"><%= t 'user.account.profile description' %></td>
|
<td class="fieldName"><%= t 'user.account.profile description' %></td>
|
||||||
<td><%= f.text_area :description, :rows => '5', :cols => '60' %></td>
|
<td><%= richtext_area :user, :description, :rows => '15', :cols => '80' %></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<%= f.label :reason, t('user_block.new.reason', :name => @this_user.display_name) %><br />
|
<%= f.label :reason, t('user_block.new.reason', :name => @this_user.display_name) %><br />
|
||||||
<%= f.text_area :reason, :cols => 80, :rows => 5 %>
|
<%= richtext_area :user_block, :reason, :cols => 80, :rows => 20 %>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<%= label_tag 'user_block_period', t('user_block.new.period') %><br />
|
<%= label_tag 'user_block_period', t('user_block.new.period') %><br />
|
||||||
|
|
|
@ -1404,6 +1404,23 @@ en:
|
||||||
permissive: "Permissive access"
|
permissive: "Permissive access"
|
||||||
destination: "Destination access"
|
destination: "Destination access"
|
||||||
construction: "Roads under construction"
|
construction: "Roads under construction"
|
||||||
|
richtext_area:
|
||||||
|
edit: Edit
|
||||||
|
preview: Preview
|
||||||
|
markdown_help:
|
||||||
|
title: Parsed with Markdown
|
||||||
|
headings: Headings
|
||||||
|
heading: Heading
|
||||||
|
subheading: Subheading
|
||||||
|
unordered: Unordered list
|
||||||
|
ordered: Ordered list
|
||||||
|
first: First item
|
||||||
|
second: Second item
|
||||||
|
link: Link
|
||||||
|
text: Text
|
||||||
|
image: Image
|
||||||
|
alt: Alt text
|
||||||
|
url: url
|
||||||
trace:
|
trace:
|
||||||
visibility:
|
visibility:
|
||||||
private: "Private (only shared as anonymous, unordered points)"
|
private: "Private (only shared as anonymous, unordered points)"
|
||||||
|
|
|
@ -122,6 +122,9 @@ OpenStreetMap::Application.routes.draw do
|
||||||
# permalink
|
# permalink
|
||||||
match '/go/:code' => 'site#permalink', :via => :get, :code => /[a-zA-Z0-9_@~]+[=-]*/
|
match '/go/:code' => 'site#permalink', :via => :get, :code => /[a-zA-Z0-9_@~]+[=-]*/
|
||||||
|
|
||||||
|
# rich text preview
|
||||||
|
match '/preview/:format' => 'site#preview', :as => :preview
|
||||||
|
|
||||||
# traces
|
# traces
|
||||||
match '/user/:display_name/traces/tag/:tag/page/:page' => 'trace#list', :via => :get
|
match '/user/:display_name/traces/tag/:tag/page/:page' => 'trace#list', :via => :get
|
||||||
match '/user/:display_name/traces/tag/:tag' => 'trace#list', :via => :get
|
match '/user/:display_name/traces/tag/:tag' => 'trace#list', :via => :get
|
||||||
|
|
|
@ -159,7 +159,9 @@ class DiaryEntryControllerTest < ActionController::TestCase
|
||||||
assert_select "input#latitude[name='diary_entry[latitude]']", :count => 1
|
assert_select "input#latitude[name='diary_entry[latitude]']", :count => 1
|
||||||
assert_select "input#longitude[name='diary_entry[longitude]']", :count => 1
|
assert_select "input#longitude[name='diary_entry[longitude]']", :count => 1
|
||||||
assert_select "input[name=commit][type=submit][value=Save]", :count => 1
|
assert_select "input[name=commit][type=submit][value=Save]", :count => 1
|
||||||
assert_select "input", :count => 5
|
assert_select "input[name=commit][type=submit][value=Edit]", :count => 1
|
||||||
|
assert_select "input[name=commit][type=submit][value=Preview]", :count => 1
|
||||||
|
assert_select "input", :count => 7
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -54,6 +54,10 @@ class SiteControllerTest < ActionController::TestCase
|
||||||
{ :path => "/go/shortcode", :method => :get },
|
{ :path => "/go/shortcode", :method => :get },
|
||||||
{ :controller => "site", :action => "permalink", :code => "shortcode" }
|
{ :controller => "site", :action => "permalink", :code => "shortcode" }
|
||||||
)
|
)
|
||||||
|
assert_routing(
|
||||||
|
{ :path => "/preview/formatname", :method => :get },
|
||||||
|
{ :controller => "site", :action => "preview", :format => "formatname" }
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
## Lets check that we can get all the pages without any errors
|
## Lets check that we can get all the pages without any errors
|
||||||
|
|
|
@ -367,7 +367,7 @@ class UserControllerTest < ActionController::TestCase
|
||||||
assert_template :account
|
assert_template :account
|
||||||
assert_select "div#errorExplanation", false
|
assert_select "div#errorExplanation", false
|
||||||
assert_select "div#notice", /^User information updated successfully/
|
assert_select "div#notice", /^User information updated successfully/
|
||||||
assert_select "table#accountForm > tr > td > textarea#user_description", user.description
|
assert_select "table#accountForm > tr > td > div#user_description_container > div#user_description_content > textarea#user_description", user.description
|
||||||
|
|
||||||
# Changing name to one that exists should fail
|
# Changing name to one that exists should fail
|
||||||
user.display_name = users(:public_user).display_name
|
user.display_name = users(:public_user).display_name
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue