Merge pull request #273 from gopesht/implements_markdown

Implements markdown
This commit is contained in:
Gopesh Tulsyan 2014-07-03 21:01:46 +05:30
commit fbf52b1d69
23 changed files with 3140 additions and 21 deletions

View file

@ -81,6 +81,9 @@ gem 'active_model_serializers'
# Use FontAwesome for splash themes
gem 'font-awesome-rails'
#Use Redcarpet for Markdown in description
gem 'redcarpet'
# Use rspec and capybara as testing framework
group :development, :test do
gem 'rspec', '>= 3.0.0.beta'

View file

@ -273,6 +273,7 @@ GEM
loggability (~> 0.6)
rdoc (~> 4.0)
yajl-ruby (~> 1.1)
redcarpet (3.1.2)
referer-parser (0.2.1)
request_store (1.0.6)
rest-client (1.6.7)
@ -413,6 +414,7 @@ DEPENDENCIES
rails (~> 4.1)
rails-observers
rdoc-generator-fivefish
redcarpet
rspec (>= 3.0.0.beta)
rspec-rails (>= 3.0.0.beta)
rubocop

View file

@ -24,7 +24,9 @@
//= require dashboard
//= require ahoy
//= require smoothscroll
//= require bootstrap-markdown
//= require to-markdown
//= require markdown
$(document).ready(function() {
$('a[disabled=disabled]').click(function(event){
return false;

View file

@ -10,4 +10,5 @@
*= require osem-schedule
*= require osem-schedule-print
*= require font-awesome
*= require bootstrap-markdown.min
*/

View file

@ -0,0 +1 @@
.md-editor{display:block;border:1px solid #ddd}.md-editor>.md-header,.md-editor .md-footer{display:block;padding:6px 4px;background:#fff}.md-editor>.md-header{margin: 0;}.md-editor>.md-preview{background:#fff;border-top:1px dashed #ddd;border-bottom:1px dashed #ddd;min-height:10px;overflow:auto}.md-editor>textarea{font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:14px;outline:0;outline:thin dotted \9;margin:0;display:block;padding:0;width:100%;border:0;border-top:1px dashed #ddd;border-bottom:1px dashed #ddd;border-radius:0;box-shadow:none;background:#eee}.md-editor>textarea:focus{box-shadow:none;background:#fff}.md-editor.active{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,0.6)}

View file

@ -197,4 +197,18 @@ module ApplicationHelper
(short_title_brand(@conference) if @conference) ||
default_brand
end
def markdown(text)
options = {
autolink: true,
space_after_headers: true,
no_intra_emphasis: true
}
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, options)
markdown.render(text).html_safe
end
def markdown_hint(text="")
markdown("#{text} Please look at #{link_to '**Markdown Syntax**', 'https://daringfireball.net/projects/markdown/syntax', target: '_blank'} to format your text")
end
end

View file

@ -4,7 +4,7 @@
= f.input :include_cfp_in_splash, label: 'Include Call for Papers in Splash', hint: 'On setting this true you will enable the call for papers to be displayed on the splash page'
= f.input :start_date, :as => :string, :input_html => { :id => "conference-start-datepicker", :readonly => "readonly" }
= f.input :end_date, :as => :string, :input_html => { :id => "conference-end-datepicker", :readonly => "readonly" }
= f.input :description, :hint => "Welcome text for the Call for Papers"
= f.input :description, hint: markdown_hint("Welcome text for the Call for Papers."), input_html: { data: { provide: "markdown-editable" } }
= f.input :schedule_changes
= f.input :schedule_public
= f.input :rating, :hint => "Enter the number of different rating levels you want to have for voting on proposals. Enter 0 if you do not want to vote on proposals."

View file

@ -12,7 +12,7 @@
= f.inputs name: 'Banner for Splash' do
= f.input :include_banner_in_splash, hint: 'This enable the Banner Photo with description to be displayed on the splash'
= f.input :banner_photo, hint: 'This will be the top most component of the splash.This background cover will contain start_date and end_date of the conference and the description'
= f.input :description, hint: 'This description will be shown at the bottom of the banner photo of the Splash'
= f.input :description, hint: markdown_hint("This description will be shown at the bottom of the banner photo of the Splash."), input_html: { data: { provide: "markdown-editable" } }
= f.inputs :name => "Scheduling" do
= f.input :timezone, :as => :time_zone, :hint => "The conference time zone"
@ -22,11 +22,11 @@
= f.input :include_registrations_in_splash, hint: 'On setting this true you will enable the registrations to be displayed on the splash page'
= f.input :registration_start_date, :as => :string, :input_html => { :id => "conference-reg-start-datepicker", :readonly => "readonly" }
= f.input :registration_end_date, :as => :string, :input_html => { :id => "conference-reg-end-datepicker", :readonly => "readonly" }
= f.input :registration_description, hint: 'This description will appear in registration segment of the splash'
= f.input :ticket_description, hint: 'This will appear in the Tickets segment of the splash'
= f.input :sponsor_description, hint: 'This will appear in the sponsor segment of the splash'
= f.input :registration_description, hint: markdown_hint("This description will appear in registration segment of the splash."), input_html: { data: { provide: "markdown-editable" } }
= f.input :ticket_description, hint: markdown_hint("This will appear in the Tickets segment of the splash."), input_html: { data: { provide: "markdown-editable" } }
= f.input :sponsor_description, hint: markdown_hint("This will appear in the sponsor segment of the splash."), input_html: { data: { provide: "markdown-editable" } }
= f.input :sponsor_email, hint: 'This will appear in the sponsor segment of the splash for the sponsors to contact to the organizers'
= f.input :lodging_description, hint: 'This will appear in the lodging segment of the splash'
= f.input :lodging_description, hint: markdown_hint("This will appear in the lodging segment of the splash."), input_html: { data: { provide: "markdown-editable" } }
= dynamic_association :photos, "Photos", f

View file

@ -1,8 +1,7 @@
<div class="nested-fields">
<%= f.inputs do %>
<%= f.input :name %>
<%= f.input :description, :input_html => {:rows => 2 }, hint: 'Write about the hotel/place,
of what they are offering, about types of rooms, prices and address' %>
<%= f.input :description, :input_html => {:rows => 2, data: { provide: "markdown-editable" } }, hint: markdown_hint("Write about the hotel/place, of what they are offering, about types of rooms, prices and address.") %>
<%= image_tag f.object.photo(:thumb) if !f.object.photo.blank? %>
<%= f.input :photo %>
<%= f.input :website_link %>

View file

@ -2,7 +2,7 @@
<%= f.inputs do %>
<%= f.input :title%>
<%= f.input :url %>
<%= f.input :description %>
<%= f.input :description, hint: markdown_hint, input_html: { data: { provide: "markdown-editable" } } %>
<%= f.input :ticket_price, hint: 'Please enter price with currency symbol.
For example, $200,₹300' %>
<%= remove_association_link :supporter_level, f %>

View file

@ -2,7 +2,8 @@
<%= f.inputs do %>
<%= f.input :name %>
<%= f.input :color, :input_html => {:size => 6, :type => "color"}, :required=> true %>
<%= f.input :description, :input_html => {:rows => 2 } %>
<%= f.input :description, :input_html => {:rows => 2, data: { provide: "markdown-editable" } }, hint: markdown_hint %>
<%= remove_association_link :track, f %>
<% end %>
</div>
data: { provide: "markdown-editable" }

View file

@ -5,7 +5,7 @@
= f.input :name, :input_html => {:rows => 1}
= f.input :address, :input_html => {:rows => 1}
= f.input :website
= f.input :description, :input_html => { :rows => 10, :cols => 20 }
= f.input :description, :input_html => { :rows => 10, :cols => 20, data: { provide: "markdown-editable" } }, hint: markdown_hint
- unless @venue.photo.blank?
= image_tag @venue.photo(:thumb)
= f.input :photo

View file

@ -9,7 +9,7 @@
Call For Papers
- if !@conference.call_for_papers.description.blank?
%p
= @conference.call_for_papers.description
= markdown(@conference.call_for_papers.description)
- if !@conference.call_for_papers.start_date.blank? && !@conference.call_for_papers.end_date.blank?
%p.lead Proposals will be accepted between
#cfp-date

View file

@ -14,7 +14,7 @@
%strong #{ @conference.venue.address }
- unless @conference.venue.description.blank?
%p
= @conference.venue.description
= markdown(@conference.venue.description)
%ul.location-links
- unless @conference.venue.address.blank?
%li

View file

@ -2,7 +2,7 @@
%h2 Lodgings
-unless @conference.lodging_description.blank?
%p.lead
= @conference.lodging_description
= markdown(@conference.lodging_description)
%div.row.text-center
- @conference.venue.lodgings.each do |r|
@ -13,7 +13,7 @@
-unless r.name.blank?
%h4.text-center #{ r.name }
-unless r.description.blank?
%p.text-left #{ r.description }
%p.text-left #{ markdown(r.description) }
- unless r.website_link.blank?
.text-center
= link_to 'Go to Website', r.website_link

View file

@ -6,7 +6,7 @@
%h1 Registration
- if !@conference.registration_description.blank?
%p
= @conference.registration_description
= markdown(@conference.registration_description)
- if @conference.registration_dates_given?
-if @conference.registration_end_date >= Date.today
%h4 Registration period #{ date_string(@conference.registration_start_date, @conference.registration_end_date) }

View file

@ -6,7 +6,8 @@
%div.col-md-12
%h2 Sponsors
-if !@conference.sponsor_description.blank?
%p #{ @conference.sponsor_description }
%p
= markdown(@conference.sponsor_description)
-if !@conference.sponsor_email.blank?
%h3= mail_to "#{ @conference.sponsor_email }", 'Become a Sponsor'
- if !@conference.sponsorship_levels.blank?

View file

@ -1,7 +1,8 @@
%div.row
%h3 Tickets
-if !@conference.ticket_description.blank?
%p #{ @conference.ticket_description }
%p
= markdown(@conference.ticket_description)
- @conference.supporter_levels.each do |s|
%div.col-md-6
- if !s.title.blank?

View file

@ -6,4 +6,4 @@
%h4
= t.name
%p
= t.description
= markdown(t.description)

View file

@ -16,7 +16,8 @@
- unless @conference.description.blank?
.row-fluid
.col-md-12.lead
%p= @conference.description
%p
= markdown(@conference.description)
-unless @conference.photos.blank?
= link_to 'Gallery', gallery_photos_conference_path(@conference.short_title), class: 'btn btn-primary btn-lg', id: 'gallery-btn', remote: true
= render 'gallery'

File diff suppressed because it is too large Load diff

1616
vendor/assets/javascripts/markdown.js vendored Normal file

File diff suppressed because it is too large Load diff

184
vendor/assets/javascripts/to-markdown.js vendored Normal file
View file

@ -0,0 +1,184 @@
/*
* to-markdown - an HTML to Markdown converter
*
* Copyright 2011, Dom Christie
* Licenced under the MIT licence
*
*/
var toMarkdown = function(string) {
var ELEMENTS = [
{
patterns: 'p',
replacement: function(str, attrs, innerHTML) {
return innerHTML ? '\n\n' + innerHTML + '\n' : '';
}
},
{
patterns: 'br',
type: 'void',
replacement: '\n'
},
{
patterns: 'h([1-6])',
replacement: function(str, hLevel, attrs, innerHTML) {
var hPrefix = '';
for(var i = 0; i < hLevel; i++) {
hPrefix += '#';
}
return '\n\n' + hPrefix + ' ' + innerHTML + '\n';
}
},
{
patterns: 'hr',
type: 'void',
replacement: '\n\n* * *\n'
},
{
patterns: 'a',
replacement: function(str, attrs, innerHTML) {
var href = attrs.match(attrRegExp('href')),
title = attrs.match(attrRegExp('title'));
return href ? '[' + innerHTML + ']' + '(' + href[1] + (title && title[1] ? ' "' + title[1] + '"' : '') + ')' : str;
}
},
{
patterns: ['b', 'strong'],
replacement: function(str, attrs, innerHTML) {
return innerHTML ? '**' + innerHTML + '**' : '';
}
},
{
patterns: ['i', 'em'],
replacement: function(str, attrs, innerHTML) {
return innerHTML ? '_' + innerHTML + '_' : '';
}
},
{
patterns: 'code',
replacement: function(str, attrs, innerHTML) {
return innerHTML ? '`' + innerHTML + '`' : '';
}
},
{
patterns: 'img',
type: 'void',
replacement: function(str, attrs, innerHTML) {
var src = attrs.match(attrRegExp('src')),
alt = attrs.match(attrRegExp('alt')),
title = attrs.match(attrRegExp('title'));
return '![' + (alt && alt[1] ? alt[1] : '') + ']' + '(' + src[1] + (title && title[1] ? ' "' + title[1] + '"' : '') + ')';
}
}
];
for(var i = 0, len = ELEMENTS.length; i < len; i++) {
if(typeof ELEMENTS[i].patterns === 'string') {
string = replaceEls(string, { tag: ELEMENTS[i].patterns, replacement: ELEMENTS[i].replacement, type: ELEMENTS[i].type });
}
else {
for(var j = 0, pLen = ELEMENTS[i].patterns.length; j < pLen; j++) {
string = replaceEls(string, { tag: ELEMENTS[i].patterns[j], replacement: ELEMENTS[i].replacement, type: ELEMENTS[i].type });
}
}
}
function replaceEls(html, elProperties) {
var pattern = elProperties.type === 'void' ? '<' + elProperties.tag + '\\b([^>]*)\\/?>' : '<' + elProperties.tag + '\\b([^>]*)>([\\s\\S]*?)<\\/' + elProperties.tag + '>',
regex = new RegExp(pattern, 'gi'),
markdown = '';
if(typeof elProperties.replacement === 'string') {
markdown = html.replace(regex, elProperties.replacement);
}
else {
markdown = html.replace(regex, function(str, p1, p2, p3) {
return elProperties.replacement.call(this, str, p1, p2, p3);
});
}
return markdown;
}
function attrRegExp(attr) {
return new RegExp(attr + '\\s*=\\s*["\']?([^"\']*)["\']?', 'i');
}
// Pre code blocks
string = string.replace(/<pre\b[^>]*>`([\s\S]*)`<\/pre>/gi, function(str, innerHTML) {
innerHTML = innerHTML.replace(/^\t+/g, ' '); // convert tabs to spaces (you know it makes sense)
innerHTML = innerHTML.replace(/\n/g, '\n ');
return '\n\n ' + innerHTML + '\n';
});
// Lists
// Escape numbers that could trigger an ol
// If there are more than three spaces before the code, it would be in a pre tag
// Make sure we are escaping the period not matching any character
string = string.replace(/^(\s{0,3}\d+)\. /g, '$1\\. ');
// Converts lists that have no child lists (of same type) first, then works it's way up
var noChildrenRegex = /<(ul|ol)\b[^>]*>(?:(?!<ul|<ol)[\s\S])*?<\/\1>/gi;
while(string.match(noChildrenRegex)) {
string = string.replace(noChildrenRegex, function(str) {
return replaceLists(str);
});
}
function replaceLists(html) {
html = html.replace(/<(ul|ol)\b[^>]*>([\s\S]*?)<\/\1>/gi, function(str, listType, innerHTML) {
var lis = innerHTML.split('</li>');
lis.splice(lis.length - 1, 1);
for(i = 0, len = lis.length; i < len; i++) {
if(lis[i]) {
var prefix = (listType === 'ol') ? (i + 1) + ". " : "* ";
lis[i] = lis[i].replace(/\s*<li[^>]*>([\s\S]*)/i, function(str, innerHTML) {
innerHTML = innerHTML.replace(/^\s+/, '');
innerHTML = innerHTML.replace(/\n\n/g, '\n\n ');
// indent nested lists
innerHTML = innerHTML.replace(/\n([ ]*)+(\*|\d+\.) /g, '\n$1 $2 ');
return prefix + innerHTML;
});
}
}
return lis.join('\n');
});
return '\n\n' + html.replace(/[ \t]+\n|\s+$/g, '');
}
// Blockquotes
var deepest = /<blockquote\b[^>]*>((?:(?!<blockquote)[\s\S])*?)<\/blockquote>/gi;
while(string.match(deepest)) {
string = string.replace(deepest, function(str) {
return replaceBlockquotes(str);
});
}
function replaceBlockquotes(html) {
html = html.replace(/<blockquote\b[^>]*>([\s\S]*?)<\/blockquote>/gi, function(str, inner) {
inner = inner.replace(/^\s+|\s+$/g, '');
inner = cleanUp(inner);
inner = inner.replace(/^/gm, '> ');
inner = inner.replace(/^(>([ \t]{2,}>)+)/gm, '> >');
return inner;
});
return html;
}
function cleanUp(string) {
string = string.replace(/^[\t\r\n]+|[\t\r\n]+$/g, ''); // trim leading/trailing whitespace
string = string.replace(/\n\s+\n/g, '\n\n');
string = string.replace(/\n{3,}/g, '\n\n'); // limit consecutive linebreaks to 2
return string;
}
return cleanUp(string);
};
if (typeof exports === 'object') {
exports.toMarkdown = toMarkdown;
}