activeadmin_pagedown 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +141 -0
- data/README.md +45 -0
- data/Rakefile +1 -0
- data/active_admin_pagedown.gemspec +22 -0
- data/app/assets/images/active_admin_pagedown/wmd-buttons.png +0 -0
- data/app/assets/javascripts/active_admin_pagedown/Markdown.Converter.js +1332 -0
- data/app/assets/javascripts/active_admin_pagedown/Markdown.Editor.js +2212 -0
- data/app/assets/javascripts/active_admin_pagedown/Markdown.Sanitizer.js +108 -0
- data/app/assets/javascripts/active_admin_pagedown/base.js +3 -0
- data/app/assets/javascripts/active_admin_pagedown/default.js +5 -0
- data/app/assets/stylesheets/active_admin_pagedown/base.css.scss +98 -0
- data/app/inputs/pagedown_text_input.rb +24 -0
- data/lib/active_admin_pagedown.rb +5 -0
- data/lib/active_admin_pagedown/version.rb +3 -0
- data/lib/activeadmin_pagedown.rb +1 -0
- data/pagedown.png +0 -0
- metadata +80 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
(function () {
|
2
|
+
var output, Converter;
|
3
|
+
if (typeof exports === "object" && typeof require === "function") { // we're in a CommonJS (e.g. Node.js) module
|
4
|
+
output = exports;
|
5
|
+
Converter = require("./Markdown.Converter").Converter;
|
6
|
+
} else {
|
7
|
+
output = window.Markdown;
|
8
|
+
Converter = output.Converter;
|
9
|
+
}
|
10
|
+
|
11
|
+
output.getSanitizingConverter = function () {
|
12
|
+
var converter = new Converter();
|
13
|
+
converter.hooks.chain("postConversion", sanitizeHtml);
|
14
|
+
converter.hooks.chain("postConversion", balanceTags);
|
15
|
+
return converter;
|
16
|
+
}
|
17
|
+
|
18
|
+
function sanitizeHtml(html) {
|
19
|
+
return html.replace(/<[^>]*>?/gi, sanitizeTag);
|
20
|
+
}
|
21
|
+
|
22
|
+
// (tags that can be opened/closed) | (tags that stand alone)
|
23
|
+
var basic_tag_whitelist = /^(<\/?(b|blockquote|code|del|dd|dl|dt|em|h1|h2|h3|i|kbd|li|ol|p|pre|s|sup|sub|strong|strike|ul)>|<(br|hr)\s?\/?>)$/i;
|
24
|
+
// <a href="url..." optional title>|</a>
|
25
|
+
var a_white = /^(<a\shref="((https?|ftp):\/\/|\/)[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+"(\stitle="[^"<>]+")?\s?>|<\/a>)$/i;
|
26
|
+
|
27
|
+
// <img src="url..." optional width optional height optional alt optional title
|
28
|
+
var img_white = /^(<img\ssrc="(https?:\/\/|\/)[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+"(\swidth="\d{1,3}")?(\sheight="\d{1,3}")?(\salt="[^"<>]*")?(\stitle="[^"<>]*")?\s?\/?>)$/i;
|
29
|
+
|
30
|
+
function sanitizeTag(tag) {
|
31
|
+
if (tag.match(basic_tag_whitelist) || tag.match(a_white) || tag.match(img_white))
|
32
|
+
return tag;
|
33
|
+
else
|
34
|
+
return "";
|
35
|
+
}
|
36
|
+
|
37
|
+
/// <summary>
|
38
|
+
/// attempt to balance HTML tags in the html string
|
39
|
+
/// by removing any unmatched opening or closing tags
|
40
|
+
/// IMPORTANT: we *assume* HTML has *already* been
|
41
|
+
/// sanitized and is safe/sane before balancing!
|
42
|
+
///
|
43
|
+
/// adapted from CODESNIPPET: A8591DBA-D1D3-11DE-947C-BA5556D89593
|
44
|
+
/// </summary>
|
45
|
+
function balanceTags(html) {
|
46
|
+
|
47
|
+
if (html == "")
|
48
|
+
return "";
|
49
|
+
|
50
|
+
var re = /<\/?\w+[^>]*(\s|$|>)/g;
|
51
|
+
// convert everything to lower case; this makes
|
52
|
+
// our case insensitive comparisons easier
|
53
|
+
var tags = html.toLowerCase().match(re);
|
54
|
+
|
55
|
+
// no HTML tags present? nothing to do; exit now
|
56
|
+
var tagcount = (tags || []).length;
|
57
|
+
if (tagcount == 0)
|
58
|
+
return html;
|
59
|
+
|
60
|
+
var tagname, tag;
|
61
|
+
var ignoredtags = "<p><img><br><li><hr>";
|
62
|
+
var match;
|
63
|
+
var tagpaired = [];
|
64
|
+
var tagremove = [];
|
65
|
+
var needsRemoval = false;
|
66
|
+
|
67
|
+
// loop through matched tags in forward order
|
68
|
+
for (var ctag = 0; ctag < tagcount; ctag++) {
|
69
|
+
tagname = tags[ctag].replace(/<\/?(\w+).*/, "$1");
|
70
|
+
// skip any already paired tags
|
71
|
+
// and skip tags in our ignore list; assume they're self-closed
|
72
|
+
if (tagpaired[ctag] || ignoredtags.search("<" + tagname + ">") > -1)
|
73
|
+
continue;
|
74
|
+
|
75
|
+
tag = tags[ctag];
|
76
|
+
match = -1;
|
77
|
+
|
78
|
+
if (!/^<\//.test(tag)) {
|
79
|
+
// this is an opening tag
|
80
|
+
// search forwards (next tags), look for closing tags
|
81
|
+
for (var ntag = ctag + 1; ntag < tagcount; ntag++) {
|
82
|
+
if (!tagpaired[ntag] && tags[ntag] == "</" + tagname + ">") {
|
83
|
+
match = ntag;
|
84
|
+
break;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
if (match == -1)
|
90
|
+
needsRemoval = tagremove[ctag] = true; // mark for removal
|
91
|
+
else
|
92
|
+
tagpaired[match] = true; // mark paired
|
93
|
+
}
|
94
|
+
|
95
|
+
if (!needsRemoval)
|
96
|
+
return html;
|
97
|
+
|
98
|
+
// delete all orphaned tags from the string
|
99
|
+
|
100
|
+
var ctag = 0;
|
101
|
+
html = html.replace(re, function (match) {
|
102
|
+
var res = tagremove[ctag] ? "" : match;
|
103
|
+
ctag++;
|
104
|
+
return res;
|
105
|
+
});
|
106
|
+
return html;
|
107
|
+
}
|
108
|
+
})();
|
@@ -0,0 +1,98 @@
|
|
1
|
+
|
2
|
+
.wmd-panel
|
3
|
+
{
|
4
|
+
margin-left: 25%;
|
5
|
+
margin-right: 25%;
|
6
|
+
width: 76%;
|
7
|
+
display: inline-block;
|
8
|
+
}
|
9
|
+
|
10
|
+
.wmd-button-bar
|
11
|
+
{
|
12
|
+
width: 100%;
|
13
|
+
background-color: Silver;
|
14
|
+
}
|
15
|
+
|
16
|
+
.wmd-input
|
17
|
+
{
|
18
|
+
height: 300px;
|
19
|
+
width: 100% !important;
|
20
|
+
}
|
21
|
+
|
22
|
+
.wmd-preview
|
23
|
+
{
|
24
|
+
background-color: #c0e0ff;
|
25
|
+
}
|
26
|
+
|
27
|
+
.wmd-button-row
|
28
|
+
{
|
29
|
+
position: relative;
|
30
|
+
margin-left: 5px;
|
31
|
+
margin-right: 5px;
|
32
|
+
margin-bottom: 5px;
|
33
|
+
margin-top: 10px;
|
34
|
+
padding: 0px;
|
35
|
+
height: 20px;
|
36
|
+
}
|
37
|
+
|
38
|
+
.wmd-spacer
|
39
|
+
{
|
40
|
+
width: 1px;
|
41
|
+
height: 20px;
|
42
|
+
margin-left: 14px;
|
43
|
+
|
44
|
+
position: absolute;
|
45
|
+
background-color: Silver;
|
46
|
+
display: inline-block;
|
47
|
+
list-style: none;
|
48
|
+
}
|
49
|
+
|
50
|
+
.wmd-button {
|
51
|
+
width: 20px;
|
52
|
+
height: 20px;
|
53
|
+
padding-left: 2px;
|
54
|
+
padding-right: 3px;
|
55
|
+
position: absolute;
|
56
|
+
display: inline-block;
|
57
|
+
list-style: none;
|
58
|
+
cursor: pointer;
|
59
|
+
}
|
60
|
+
|
61
|
+
.wmd-button > span {
|
62
|
+
background-image: url( image-path("active_admin_pagedown/wmd-buttons.png") );
|
63
|
+
background-repeat: no-repeat;
|
64
|
+
background-position: 0px 0px;
|
65
|
+
width: 20px;
|
66
|
+
height: 20px;
|
67
|
+
display: inline-block;
|
68
|
+
}
|
69
|
+
|
70
|
+
.wmd-spacer1 {
|
71
|
+
left: 50px;
|
72
|
+
}
|
73
|
+
.wmd-spacer2 {
|
74
|
+
left: 175px;
|
75
|
+
}
|
76
|
+
.wmd-spacer3 {
|
77
|
+
left: 300px;
|
78
|
+
}
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
.wmd-preview > ul, .wmd-preview > ol {
|
83
|
+
margin: 0 0 10px 25px !important;
|
84
|
+
}
|
85
|
+
|
86
|
+
.wmd-preview > p {
|
87
|
+
margin: 0 0 10px !important;
|
88
|
+
}
|
89
|
+
|
90
|
+
.wmd-preview > ul > li {
|
91
|
+
list-style: disc !important;
|
92
|
+
}
|
93
|
+
|
94
|
+
.wmd-prompt-dialog
|
95
|
+
{
|
96
|
+
border: 1px solid #999999;
|
97
|
+
background-color: #F5F5F5;
|
98
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class PagedownTextInput < Formtastic::Inputs::StringInput
|
2
|
+
|
3
|
+
|
4
|
+
def input_html_options
|
5
|
+
super.merge(:class => "wmd-input", :id => 'wmd-input')
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_html
|
9
|
+
input_wrapping do
|
10
|
+
|
11
|
+
label_html <<
|
12
|
+
|
13
|
+
template.content_tag(:div, :class => 'wmd-panel' ) do
|
14
|
+
template.content_tag(:div, "", :id => 'wmd-button-bar') <<
|
15
|
+
builder.text_area(method, input_html_options)
|
16
|
+
end <<
|
17
|
+
|
18
|
+
template.content_tag(:div, "", :style=> 'margin-top:20px' ) do
|
19
|
+
template.content_tag(:label, "Preview" ) <<
|
20
|
+
template.content_tag(:div, "", :id => "wmd-preview", :class => "wmd-panel wmd-preview" )
|
21
|
+
end
|
22
|
+
end.html_safe
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_admin_pagedown'
|
data/pagedown.png
ADDED
Binary file
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: activeadmin_pagedown
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michael Guymon
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activeadmin
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.5.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.5.0
|
30
|
+
description: Pagedown widget for ActiveAdmin.
|
31
|
+
email:
|
32
|
+
- mguymon@tobedevoured.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- Gemfile
|
39
|
+
- Gemfile.lock
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- active_admin_pagedown.gemspec
|
43
|
+
- app/assets/images/active_admin_pagedown/wmd-buttons.png
|
44
|
+
- app/assets/javascripts/active_admin_pagedown/Markdown.Converter.js
|
45
|
+
- app/assets/javascripts/active_admin_pagedown/Markdown.Editor.js
|
46
|
+
- app/assets/javascripts/active_admin_pagedown/Markdown.Sanitizer.js
|
47
|
+
- app/assets/javascripts/active_admin_pagedown/base.js
|
48
|
+
- app/assets/javascripts/active_admin_pagedown/default.js
|
49
|
+
- app/assets/stylesheets/active_admin_pagedown/base.css.scss
|
50
|
+
- app/inputs/pagedown_text_input.rb
|
51
|
+
- lib/active_admin_pagedown.rb
|
52
|
+
- lib/active_admin_pagedown/version.rb
|
53
|
+
- lib/activeadmin_pagedown.rb
|
54
|
+
- pagedown.png
|
55
|
+
homepage: https://github.com/mguymon/active_admin_pagedown
|
56
|
+
licenses:
|
57
|
+
- MIT
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 1.8.24
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: Pagedown widget for ActiveAdmin.
|
80
|
+
test_files: []
|