showmd 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,9 @@
1
+ require_relative "showmd/preview_generator"
2
+
3
+ if ARGV.size != 1
4
+ puts "Argument error, showmd only accepts one argument. It must me a path to a markdown file."
5
+ else
6
+ file_path = File.join(Dir.pwd, ARGV[0])
7
+ puts "Generating Preview #{file_path}"
8
+ Showmd::PreviewGenerator.new(file_path).generate
9
+ end
@@ -0,0 +1,77 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>README.md - showmd preview</title>
5
+ <style type="text/css">
6
+ #preview{
7
+ width: 80%;
8
+ margin: auto;
9
+ background: white;
10
+ padding: 10px 30px;
11
+ box-shadow: 5px 5px 1px grey;
12
+ }
13
+ body{
14
+ background: #d3d3d3;
15
+ }
16
+ footer{
17
+ width: 80%;
18
+ margin:auto;
19
+ text-align: right;
20
+ padding-top: 15px;
21
+ }
22
+ img{
23
+ max-width: 100%;
24
+ }
25
+ </style>
26
+ <script type="text/javascript" src="../pagedown/Markdown.Converter.js"></script>
27
+ <script type="text/javascript" src="../pagedown/Markdown.Sanitizer.js"></script>
28
+ <script type="text/javascript" src="../pagedown/Markdown.Extra.js"></script>
29
+ </head>
30
+
31
+ <body>
32
+ <div id="markdown">## Showmd
33
+ ### An executable to preview markdown in your browser
34
+
35
+ Showmd lets you preview markdown files in your browser from the command line, it's a lightweight utility that will take the path to a markdown file and open up a preview in your browser. The markdown file is read and converted to HTML using [pagedown](https://code.google.com/p/pagedown/) and [pagedown-extra](https://github.com/jmcmanus/pagedown-extra) javascript libraries, a temporary file is created and previewed using [launchy](http://github.com), so as everything is done client side you don't even need a net connection.
36
+
37
+ ### Installation
38
+
39
+ ```
40
+ gem install showmd
41
+ ```
42
+
43
+ ### Usage
44
+
45
+ ```
46
+ showmd my_project/README.md
47
+ ```
48
+
49
+ ### Screenshot
50
+
51
+ ![](http://cih-static.s3.amazonaws.com/blog/showmd-screenshot.png)
52
+
53
+ ### Tests
54
+
55
+ ```
56
+ rake test
57
+ ```
58
+
59
+ ### Licence
60
+
61
+ See [Licence.txt](https://github.com/cih/showmd/blob/master/Licence.txt)
62
+ </div>
63
+ <div id="preview"></div>
64
+ <footer>Preview generated using <a href="http://github.com/cih/showmd">showmd</footer>
65
+
66
+ <script type="text/javascript">
67
+ (function () {
68
+ var converter = Markdown.getSanitizingConverter();
69
+ var markdown = document.getElementById("markdown");
70
+ var preview = document.getElementById("preview")
71
+ Markdown.Extra.init(converter);
72
+ preview.innerHTML = converter.makeHtml(markdown.innerHTML);
73
+ markdown.innerHTML = "";
74
+ })();
75
+ </script>
76
+ </body>
77
+ </html>
@@ -0,0 +1,41 @@
1
+ require 'launchy'
2
+
3
+ module Showmd
4
+ class InputError < StandardError;end;
5
+ class PreviewGenerator
6
+ # Pass in a md file path, read the file, build an html file and open in the default browser
7
+ attr_accessor :input_path, :output_path, :template_path, :markdown
8
+
9
+ def initialize(file)
10
+ @input_path = file
11
+ @output_path = File.expand_path(File.join(File.dirname(__FILE__), "markdown_preview.html"))
12
+ @template_path = File.expand_path(File.join(File.dirname(__FILE__), "template.html"))
13
+ end
14
+
15
+ def generate
16
+ read_md_file
17
+ build_html_file
18
+ open_in_browser
19
+ end
20
+
21
+ def read_md_file
22
+ begin
23
+ @markdown = File.read(input_path)
24
+ rescue => exception
25
+ raise InputError, "Sorry showmd was unable to read the file, please use a valid markdown file."
26
+ end
27
+ end
28
+
29
+ def build_html_file
30
+ template_text = File.read(template_path)
31
+ html_string = template_text.gsub(/<% markdown %>/, markdown)
32
+ html_string.gsub!(/<% page_title %>/, File.basename(input_path))
33
+
34
+ File.open(output_path, "w") {|file| file.puts html_string}
35
+ end
36
+
37
+ def open_in_browser
38
+ Launchy.open("file://localhost/#{output_path}")
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,47 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><% page_title %> - showmd preview</title>
5
+ <style type="text/css">
6
+ #preview{
7
+ width: 80%;
8
+ margin: auto;
9
+ background: white;
10
+ padding: 10px 30px;
11
+ box-shadow: 5px 5px 1px grey;
12
+ }
13
+ body{
14
+ background: #d3d3d3;
15
+ }
16
+ footer{
17
+ width: 80%;
18
+ margin:auto;
19
+ text-align: right;
20
+ padding-top: 15px;
21
+ }
22
+ img{
23
+ max-width: 100%;
24
+ }
25
+ </style>
26
+ <script type="text/javascript" src="../pagedown/Markdown.Converter.js"></script>
27
+ <script type="text/javascript" src="../pagedown/Markdown.Sanitizer.js"></script>
28
+ <script type="text/javascript" src="../pagedown/Markdown.Extra.js"></script>
29
+ </head>
30
+
31
+ <body>
32
+ <div id="markdown"><% markdown %></div>
33
+ <div id="preview"></div>
34
+ <footer>Preview generated using <a href="http://github.com/cih/showmd">showmd</footer>
35
+
36
+ <script type="text/javascript">
37
+ (function () {
38
+ var converter = Markdown.getSanitizingConverter();
39
+ var markdown = document.getElementById("markdown");
40
+ var preview = document.getElementById("preview")
41
+ Markdown.Extra.init(converter);
42
+ preview.innerHTML = converter.makeHtml(markdown.innerHTML);
43
+ markdown.innerHTML = "";
44
+ })();
45
+ </script>
46
+ </body>
47
+ </html>
@@ -0,0 +1,3 @@
1
+ module Showmd
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'showmd/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "showmd"
8
+ spec.version = Showmd::VERSION
9
+ spec.authors = ["Chris Holmes"]
10
+ spec.email = ["tochrisholmes@gmail.com"]
11
+ spec.description = %q{An executable to preview markdown in your browser}
12
+ spec.summary = %q{Showmd lets you preview markdown files in your browser from the command line, it's a lightweight utility that will take the path to a markdown file and open up a preview in your browser.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = ["showmd"]
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "minitest"
24
+
25
+ spec.add_dependency "launchy"
26
+ end
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>valid.md - showmd preview</title>
5
+ </head>
6
+
7
+ <body>
8
+ <% markdown %>
9
+ <h1>HTML Template!</h1>
10
+ </body>
11
+ </html>
@@ -0,0 +1,3 @@
1
+ ### showmd testfile
2
+
3
+ *Here we have some markdown!*
@@ -0,0 +1,61 @@
1
+ require_relative '../lib/showmd/preview_generator'
2
+ require 'minitest/autorun'
3
+ require 'minitest/spec'
4
+ require 'minitest/pride'
5
+
6
+ module Showmd
7
+ class PreviewGeneratorSpec < MiniTest::Test
8
+
9
+ INVALID_FILE = File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "doesnt_exist.html"))
10
+ TEST_OUTPUT_PATH = File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "preview.html"))
11
+ TEST_TEMPLATE_PATH = File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "template.html"))
12
+ VALID_MD_FILE = File.expand_path(File.join(File.dirname(__FILE__), "fixtures", "valid.md"))
13
+
14
+ describe "read_md_file" do
15
+ it "should read a valid file" do
16
+ preview_generator = Showmd::PreviewGenerator.new(VALID_MD_FILE)
17
+ preview_generator.read_md_file.must_match "*Here we have some markdown!*"
18
+ end
19
+
20
+ it "should raise if file is invalid" do
21
+ lambda do
22
+ Showmd::PreviewGenerator.new(INVALID_FILE).read_md_file
23
+ end.must_raise(Showmd::InputError)
24
+ end
25
+ end
26
+
27
+ describe "build_html_file" do
28
+ before do
29
+ @preview_generator = Showmd::PreviewGenerator.new(VALID_MD_FILE)
30
+ @preview_generator.read_md_file
31
+ @preview_generator.output_path = TEST_OUTPUT_PATH
32
+ @preview_generator.template_path = TEST_TEMPLATE_PATH
33
+ end
34
+ it "should read from the html template" do
35
+ @preview_generator.build_html_file
36
+
37
+ File.exist?(@preview_generator.output_path).must_be :==, true
38
+ File.delete(@preview_generator.output_path)
39
+ end
40
+
41
+ it "should contain the markdown string" do
42
+ @preview_generator.build_html_file
43
+
44
+ File.read(@preview_generator.output_path).must_match "*Here we have some markdown!*"
45
+ File.delete(@preview_generator.output_path)
46
+ end
47
+ end
48
+
49
+ describe "generate" do
50
+ it "should call methods to read, build and open" do
51
+ showmd = MiniTest::Mock.new
52
+ def Launchy.open(x);;end
53
+ preview_generator = Showmd::PreviewGenerator.new(VALID_MD_FILE).generate
54
+
55
+ showmd.expect :read_md_file, true
56
+ showmd.expect :build_html_file, true
57
+ showmd.expect :open_in_browser, true
58
+ end
59
+ end
60
+ end
61
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: showmd
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris Holmes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: launchy
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: An executable to preview markdown in your browser
70
+ email:
71
+ - tochrisholmes@gmail.com
72
+ executables:
73
+ - showmd
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .travis.yml
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - bin/showmd
83
+ - lib/.DS_Store
84
+ - lib/pagedown/Markdown.Converter.js
85
+ - lib/pagedown/Markdown.Editor.js
86
+ - lib/pagedown/Markdown.Extra.js
87
+ - lib/pagedown/Markdown.Sanitizer.js
88
+ - lib/showmd.rb
89
+ - lib/showmd/markdown_preview.html
90
+ - lib/showmd/preview_generator.rb
91
+ - lib/showmd/template.html
92
+ - lib/showmd/version.rb
93
+ - showmd.gemspec
94
+ - spec/fixtures/template.html
95
+ - spec/fixtures/valid.md
96
+ - spec/preview_generator_spec.rb
97
+ homepage: ''
98
+ licenses:
99
+ - MIT
100
+ metadata: {}
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 2.0.5
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: Showmd lets you preview markdown files in your browser from the command line,
121
+ it's a lightweight utility that will take the path to a markdown file and open up
122
+ a preview in your browser.
123
+ test_files:
124
+ - spec/fixtures/template.html
125
+ - spec/fixtures/valid.md
126
+ - spec/preview_generator_spec.rb