Compare commits

...

7 Commits

Author SHA1 Message Date
rob phillips b79f8a0a50 Bump pod to v0.2 2016-06-02 08:31:05 -07:00
rob phillips 31d0ead0d7 Update readme for DownView usage 2016-06-02 08:29:36 -07:00
rob phillips bb22b86c8f DownView implementation 2016-06-02 08:29:36 -07:00
rob phillips a8186a3d82 Merge pull request #4 from iwasrobbed/attributed_string
Adds attributed string rendering
2016-06-01 17:29:02 -07:00
rob phillips 01858a2277 Adds attributed string render for #2 2016-06-01 17:18:02 -07:00
rob phillips 9c28de3237 iOS 8+ 2016-06-01 16:17:12 -07:00
rob phillips afbcee0ac4 Merge pull request #1 from iwasrobbed/cocoapods
Add CocoaPods support & cmark license
2016-06-01 15:32:54 -07:00
17 changed files with 316 additions and 12 deletions
+3 -2
View File
@@ -1,16 +1,17 @@
Pod::Spec.new do |spec|
spec.name = "Down"
spec.summary = "Blazing fast Markdown rendering in Swift, built upon cmark."
spec.version = "0.1"
spec.version = "0.2"
spec.homepage = "https://github.com/iwasrobbed/Down"
spec.license = { :type => "MIT", :file => "LICENSE" }
spec.authors = { "Rob Phillips" => "rob@desideratalabs.co" }
spec.source = { :git => "https://github.com/iwasrobbed/Down.git", :tag => "v" + spec.version.to_s }
spec.source_files = "Source/**/*"
spec.public_header_files = "Source/*.h"
spec.platform = :ios, "9.0"
spec.platform = :ios, "8.0"
spec.requires_arc = true
spec.module_name = "Down"
spec.preserve_path = 'Source/cmark/module.modulemap'
spec.pod_target_xcconfig = { 'SWIFT_INCLUDE_PATHS' => '$(SRCROOT)/Down/Source/cmark/**' }
spec.resource = 'Resources/DownView.bundle'
end
+50 -2
View File
@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
D41689B31CFFE28200E5802B /* DownViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41689B21CFFE28200E5802B /* DownViewTests.swift */; };
D41689B61CFFE6BB00E5802B /* DownView.bundle in Resources */ = {isa = PBXBuildFile; fileRef = D41689B51CFFE6BB00E5802B /* DownView.bundle */; };
D4201E8B1CFA5151008EEC6E /* Down.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4201E801CFA5151008EEC6E /* Down.framework */; };
D4201EEF1CFA59AD008EEC6E /* BindingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4201EC51CFA59A5008EEC6E /* BindingTests.swift */; };
D4201EF11CFA59F2008EEC6E /* Down.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4201EF01CFA59F2008EEC6E /* Down.swift */; };
@@ -47,6 +49,9 @@
D4201F431CFA5D63008EEC6E /* utf8.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F1C1CFA5D63008EEC6E /* utf8.c */; settings = {COMPILER_FLAGS = "-w"; }; };
D4201F441CFA5D63008EEC6E /* utf8.h in Headers */ = {isa = PBXBuildFile; fileRef = D4201F1D1CFA5D63008EEC6E /* utf8.h */; };
D4201F451CFA5D63008EEC6E /* xml.c in Sources */ = {isa = PBXBuildFile; fileRef = D4201F1E1CFA5D63008EEC6E /* xml.c */; settings = {COMPILER_FLAGS = "-w"; }; };
D43AE5CA1CFFAE4D006E1522 /* NSAttributedString+HTML.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43AE5C91CFFAE4D006E1522 /* NSAttributedString+HTML.swift */; };
D43AE5DA1CFFD0D0006E1522 /* DownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43AE5D91CFFD0D0006E1522 /* DownView.swift */; };
D43AE5DC1CFFD473006E1522 /* String+ToHTML.swift in Sources */ = {isa = PBXBuildFile; fileRef = D43AE5DB1CFFD473006E1522 /* String+ToHTML.swift */; };
D44875E41CFA6B200037A624 /* DownRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44875E31CFA6B200037A624 /* DownRenderable.swift */; };
D44875E61CFA6B660037A624 /* DownHTMLRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44875E51CFA6B660037A624 /* DownHTMLRenderable.swift */; };
D44875EA1CFA6CF30037A624 /* DownErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44875E81CFA6CF30037A624 /* DownErrors.swift */; };
@@ -55,6 +60,7 @@
D486E9961CFDD4860059FD7C /* DownASTRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D486E9951CFDD4860059FD7C /* DownASTRenderable.swift */; };
D486E9981CFDE2730059FD7C /* DownLaTeXRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D486E9971CFDE2730059FD7C /* DownLaTeXRenderable.swift */; };
D486E99A1CFDE28B0059FD7C /* DownGroffRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D486E9991CFDE28B0059FD7C /* DownGroffRenderable.swift */; };
D4CF88981CFFAC2C00F07FD1 /* DownAttributedStringRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4CF88971CFFAC2C00F07FD1 /* DownAttributedStringRenderable.swift */; };
D4DC91141CFDED4B0091CE09 /* DownCommonMarkRenderable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4DC91131CFDED4B0091CE09 /* DownCommonMarkRenderable.swift */; };
/* End PBXBuildFile section */
@@ -69,6 +75,8 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
D41689B21CFFE28200E5802B /* DownViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownViewTests.swift; sourceTree = "<group>"; };
D41689B51CFFE6BB00E5802B /* DownView.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = DownView.bundle; sourceTree = "<group>"; };
D4201E801CFA5151008EEC6E /* Down.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Down.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D4201E8A1CFA5151008EEC6E /* DownTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DownTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
D4201E9A1CFA59A5008EEC6E /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -112,6 +120,9 @@
D4201F1D1CFA5D63008EEC6E /* utf8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utf8.h; sourceTree = "<group>"; };
D4201F1E1CFA5D63008EEC6E /* xml.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xml.c; sourceTree = "<group>"; };
D42869501CFF501200FACB4C /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
D43AE5C91CFFAE4D006E1522 /* NSAttributedString+HTML.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+HTML.swift"; sourceTree = "<group>"; };
D43AE5D91CFFD0D0006E1522 /* DownView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownView.swift; sourceTree = "<group>"; };
D43AE5DB1CFFD473006E1522 /* String+ToHTML.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+ToHTML.swift"; sourceTree = "<group>"; };
D44875E31CFA6B200037A624 /* DownRenderable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownRenderable.swift; sourceTree = "<group>"; };
D44875E51CFA6B660037A624 /* DownHTMLRenderable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownHTMLRenderable.swift; sourceTree = "<group>"; };
D44875E81CFA6CF30037A624 /* DownErrors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownErrors.swift; sourceTree = "<group>"; };
@@ -121,6 +132,7 @@
D486E9971CFDE2730059FD7C /* DownLaTeXRenderable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownLaTeXRenderable.swift; sourceTree = "<group>"; };
D486E9991CFDE28B0059FD7C /* DownGroffRenderable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownGroffRenderable.swift; sourceTree = "<group>"; };
D4CF88961CFF94B300F07FD1 /* Down.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Down.h; sourceTree = "<group>"; };
D4CF88971CFFAC2C00F07FD1 /* DownAttributedStringRenderable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownAttributedStringRenderable.swift; sourceTree = "<group>"; };
D4DC91131CFDED4B0091CE09 /* DownCommonMarkRenderable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownCommonMarkRenderable.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -143,11 +155,20 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
D41689B41CFFE6BB00E5802B /* Resources */ = {
isa = PBXGroup;
children = (
D41689B51CFFE6BB00E5802B /* DownView.bundle */,
);
path = Resources;
sourceTree = "<group>";
};
D4201E761CFA5151008EEC6E = {
isa = PBXGroup;
children = (
D4201E9A1CFA59A5008EEC6E /* Info.plist */,
D4201E9B1CFA59A5008EEC6E /* Source */,
D41689B41CFFE6BB00E5802B /* Resources */,
D4201EC41CFA59A5008EEC6E /* Tests */,
D4201E811CFA5151008EEC6E /* Products */,
);
@@ -168,7 +189,9 @@
D4CF88961CFF94B300F07FD1 /* Down.h */,
D4201EF01CFA59F2008EEC6E /* Down.swift */,
D44875E71CFA6CF30037A624 /* Enums & Options */,
D43AE5C81CFFAE39006E1522 /* Extensions */,
D44875E21CFA6B120037A624 /* Renderers */,
D43AE5CB1CFFD068006E1522 /* Views */,
D4201EF61CFA5D63008EEC6E /* cmark */,
);
path = Source;
@@ -178,6 +201,7 @@
isa = PBXGroup;
children = (
D4201EC51CFA59A5008EEC6E /* BindingTests.swift */,
D41689B21CFFE28200E5802B /* DownViewTests.swift */,
);
path = Tests;
sourceTree = "<group>";
@@ -227,10 +251,28 @@
path = cmark;
sourceTree = "<group>";
};
D43AE5C81CFFAE39006E1522 /* Extensions */ = {
isa = PBXGroup;
children = (
D43AE5C91CFFAE4D006E1522 /* NSAttributedString+HTML.swift */,
D43AE5DB1CFFD473006E1522 /* String+ToHTML.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
D43AE5CB1CFFD068006E1522 /* Views */ = {
isa = PBXGroup;
children = (
D43AE5D91CFFD0D0006E1522 /* DownView.swift */,
);
path = Views;
sourceTree = "<group>";
};
D44875E21CFA6B120037A624 /* Renderers */ = {
isa = PBXGroup;
children = (
D486E9951CFDD4860059FD7C /* DownASTRenderable.swift */,
D4CF88971CFFAC2C00F07FD1 /* DownAttributedStringRenderable.swift */,
D4DC91131CFDED4B0091CE09 /* DownCommonMarkRenderable.swift */,
D486E9991CFDE28B0059FD7C /* DownGroffRenderable.swift */,
D44875E51CFA6B660037A624 /* DownHTMLRenderable.swift */,
@@ -358,6 +400,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D41689B61CFFE6BB00E5802B /* DownView.bundle in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -379,11 +422,14 @@
D486E9941CFDD33C0059FD7C /* DownXMLRenderable.swift in Sources */,
D4201F361CFA5D63008EEC6E /* iterator.c in Sources */,
D4201F391CFA5D63008EEC6E /* man.c in Sources */,
D4CF88981CFFAC2C00F07FD1 /* DownAttributedStringRenderable.swift in Sources */,
D4201F3D1CFA5D63008EEC6E /* references.c in Sources */,
D43AE5DC1CFFD473006E1522 /* String+ToHTML.swift in Sources */,
D4201F301CFA5D63008EEC6E /* houdini_html_e.c in Sources */,
D4201F3F1CFA5D63008EEC6E /* render.c in Sources */,
D486E9981CFDE2730059FD7C /* DownLaTeXRenderable.swift in Sources */,
D4201F2A1CFA5D63008EEC6E /* commonmark.c in Sources */,
D43AE5CA1CFFAE4D006E1522 /* NSAttributedString+HTML.swift in Sources */,
D4201EF11CFA59F2008EEC6E /* Down.swift in Sources */,
D4201F2F1CFA5D63008EEC6E /* houdini_href_e.c in Sources */,
D4201F451CFA5D63008EEC6E /* xml.c in Sources */,
@@ -393,6 +439,7 @@
D4201F201CFA5D63008EEC6E /* buffer.c in Sources */,
D4201F431CFA5D63008EEC6E /* utf8.c in Sources */,
D4DC91141CFDED4B0091CE09 /* DownCommonMarkRenderable.swift in Sources */,
D43AE5DA1CFFD0D0006E1522 /* DownView.swift in Sources */,
D4201F411CFA5D63008EEC6E /* scanners.c in Sources */,
D4201F381CFA5D63008EEC6E /* latex.c in Sources */,
D4201F321CFA5D63008EEC6E /* html.c in Sources */,
@@ -411,6 +458,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D41689B31CFFE28200E5802B /* DownViewTests.swift in Sources */,
D4201EEF1CFA59AD008EEC6E /* BindingTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -465,7 +513,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -509,7 +557,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

+22 -2
View File
@@ -24,16 +24,31 @@ pod 'Down'
> The library has been extensively fuzz-tested using [american fuzzy lop](http://lcamtuf.coredump.cx/afl). The test suite includes pathological cases that bring many other Markdown parsers to a crawl (for example, thousands-deep nested bracketed text or block quotes).
### Output Formats
* Web View (see DownView class)
* HTML
* XML
* LaTeX
* groff man
* CommonMark Markdown
* NSAttributedString
* AST (abstract syntax tree)
### API
### View Rendering
The `Down` struct has everything you need if you just want out-of-the-box setup.
The `DownView` class offers a very simple way to parse a UTF-8 encoded string with Markdown and convert it to a web view that can be added to any view:
```swift
let downView = try? DownView(frame: self.view.bounds, markdownString: "**Oh Hai**")
// Now add to view or constrain w/ Autolayout
```
Meta example of rendering this README:
![Example gif](Images/ohhai.gif)
### Parsing API
The `Down` struct has everything you need if you just want out-of-the-box setup for parsing and conversion.
```swift
let down = Down(markdownString: "## [Down](https://github.com/iwasrobbed/Down)")
@@ -58,6 +73,10 @@ let latex = try? down.toLaTeX()
let commonMark = try? down.toCommonMark()
// "## [Down](https://github.com/iwasrobbed/Down)\n"
// Convert to an attributed string
let attributedString = try? down.toAttributedString()
// NSAttributedString representation of the rendered HTML
// Convert to abstract syntax tree
let ast = try? down.toAST()
// Returns pointer to AST that you can manipulate
@@ -74,6 +93,7 @@ If you'd like more granularity for the output types you want to support, you can
* DownGroffRenderable
* DownCommonMarkRenderable
* DownASTRenderable
* DownAttributedStringRenderable
Example:
+8
View File
@@ -0,0 +1,8 @@
/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */progress,sub,sup{vertical-align:baseline}button,hr,input{overflow:visible}[type=checkbox],[type=radio],legend{box-sizing:border-box;padding:0}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}button,input,select,textarea{font:inherit;margin:0}optgroup{font-weight:700}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{color:inherit;display:table;max-width:100%;white-space:normal}textarea{overflow:auto}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}
/* Modified version of github.com/sindresorhus/github-markdown-css | MIT License */
/* Unminify it @ unminify.com */
hr,img{box-sizing:content-box}body:after,body:before,hr::after,hr::before{display:table;content:""}a,a:not([href]){text-decoration:none}blockquote,h6{color:#777}hr,svg:not(:root){overflow:hidden}dl,dl dt,hr,td,th{padding:0}img,table tr{background-color:#fff}pre,pre code{word-wrap:normal}body{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;color:#333;font-family:"Helvetica Neue",Helvetica,"Segoe UI",Arial,freesans,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1.5em;line-height:1.6;word-wrap:break-word;padding:2rem}a{background-color:transparent;-webkit-text-decoration-skip:objects;color:#4078c0}a:active,a:hover{outline-width:0;text-decoration:underline}strong{font-weight:bolder}h1{margin:.67em 0}img{border-style:none;max-width:100%}h1,h2{padding-bottom:.3em;border-bottom:1px solid #eee}input{margin:0;overflow:visible;font:13px/1.4 Helvetica,arial,nimbussansl,liberationsans,freesans,clean,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}[type=checkbox]{box-sizing:border-box;padding:0}table{border-spacing:0;border-collapse:collapse;display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}*{box-sizing:border-box}body:after,hr::after{clear:both}blockquote{margin:0;padding:0 15px;border-left:4px solid #ddd}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}dd{margin-left:0}code,pre{font:.9em Consolas,"Liberation Mono",Menlo,Courier,monospace}dl dt,table th{font-weight:700}body>:first-child{margin-top:0!important}dl dt,li>p{margin-top:16px}body>:last-child{margin-bottom:0!important}a:not([href]){color:inherit}h1,h2,h3,h4,h5,h6{margin-top:1em;margin-bottom:16px;font-weight:700;line-height:1.4}h1{font-size:2.25em;line-height:1.2}h2{font-size:1.75em;line-height:1.225}h3{font-size:1.5em;line-height:1.43}h4{font-size:1.25em}dl dt,h5,h6{font-size:1em}blockquote,dl,ol,p,pre,table,ul{margin-top:0;margin-bottom:16px}hr{background:#e7e7e7;height:4px;margin:16px 0;border:0}ol,ul{padding-left:2em}ol ol,ol ul,ul ol,ul ul{margin-top:0;margin-bottom:0}dl dt{font-style:italic}dl dd{padding:0 16px;margin-bottom:16px}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}table td,table th{padding:6px 13px;border:1px solid #ddd}table tr{border-top:1px solid #ccc}table tr:nth-child(2n){background-color:#f8f8f8}code{padding:.2em 0;margin:0;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px}pre code,pre>code{padding:0;margin:0;border:0}code:after,code:before{letter-spacing:-.2em;content:"\00a0"}pre>code{font-size:100%;word-break:normal;white-space:pre;background:0 0}pre code{display:inline;max-width:initial;overflow:initial;line-height:inherit;background-color:transparent}pre code:after,pre code:before{content:normal}kbd{display:inline-block;padding:3px 5px;font:11px Consolas,"Liberation Mono",Menlo,Courier,monospace;line-height:10px;color:#555;vertical-align:middle;background-color:#fcfcfc;border:1px solid #ccc;border-bottom-color:#bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb}:checked+.radio-label{position:relative;z-index:1;border-color:#4078c0}hr{border-bottom-color:#eee}
/*! highlightjs */
.hljs{display:block;overflow-x:auto;padding:.5em;background:#1d1f21;color:#c5c8c6}.hljs span::selection,.hljs::selection{background:#373b41}.hljs span::-moz-selection,.hljs::-moz-selection{background:#373b41}.hljs-name,.hljs-title{color:#f0c674}.hljs-comment,.hljs-meta,.hljs-meta .hljs-keyword{color:#707880}.hljs-deletion,.hljs-link,.hljs-literal,.hljs-number,.hljs-symbol{color:#c66}.hljs-addition,.hljs-doctag,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-string{color:#b5bd68}.hljs-attribute,.hljs-code,.hljs-selector-id{color:#b294bb}.hljs-bullet,.hljs-keyword,.hljs-selector-tag,.hljs-tag{color:#81a2be}.hljs-subst,.hljs-template-tag,.hljs-template-variable,.hljs-variable{color:#8abeb7}.hljs-built_in,.hljs-builtin-name,.hljs-quote,.hljs-section,.hljs-selector-class,.hljs-type{color:#de935f}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
+14
View File
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=640"/>
<link charset="utf-8" href="css/down.min.css" rel="stylesheet">
<script charset="utf-8" src="js/highlight.min.js" type="text/javascript"></script>
<script charset="utf-8" src="js/down.js" type="text/javascript"></script>
<title></title>
</head>
<body>
DOWN_HTML
</body>
</html>
+1
View File
@@ -0,0 +1 @@
hljs.initHighlightingOnLoad();
File diff suppressed because one or more lines are too long
+2 -1
View File
@@ -9,7 +9,8 @@
import Foundation
public struct Down: DownASTRenderable, DownHTMLRenderable, DownXMLRenderable,
DownLaTeXRenderable, DownGroffRenderable, DownCommonMarkRenderable {
DownLaTeXRenderable, DownGroffRenderable, DownCommonMarkRenderable,
DownAttributedStringRenderable {
/**
A string containing CommonMark Markdown
*/
+5
View File
@@ -18,4 +18,9 @@ public enum DownErrors: ErrorType {
Thrown when the abstract syntax tree could not be rendered into another format
*/
case ASTRenderingError
/**
Thrown when an HTML string cannot be converted into an `NSData` representation
*/
case HTMLDataConversionError
}
@@ -0,0 +1,32 @@
//
// NSAttributedString+HTML.swift
// Down
//
// Created by Rob Phillips on 6/1/16.
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
//
import UIKit
extension NSAttributedString {
/**
Instantiates an attributed string with the given HTML string
- parameter htmlString: An HTML string
- throws: `HTMLDataConversionError` or an instantiation error
- returns: An attributed string
*/
convenience init(htmlString: String) throws {
guard let data = htmlString.dataUsingEncoding(NSUTF8StringEncoding) else {
throw DownErrors.HTMLDataConversionError
}
let options = [NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: NSNumber(unsignedInteger:NSUTF8StringEncoding)]
try self.init(data: data, options: options, documentAttributes: nil)
}
}
+30
View File
@@ -0,0 +1,30 @@
//
// String+ToHTML.swift
// Down
//
// Created by Rob Phillips on 6/1/16.
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
//
import Foundation
import libcmark
extension String {
/**
Generates an HTML string from the contents of the string (self), which should contain CommonMark Markdown
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.Default`
- throws: `DownErrors` depending on the scenario
- returns: HTML string
*/
public func toHTML(options: DownOptions = .Default) throws -> String {
let ast = try DownASTRenderer.stringToAST(self, options: options)
let html = try DownHTMLRenderer.astToHTML(ast, options: options)
cmark_node_free(ast)
return html
}
}
@@ -0,0 +1,41 @@
//
// DownAttributedStringRenderable.swift
// Down
//
// Created by Rob Phillips on 6/1/16.
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
//
import Foundation
import libcmark
public protocol DownAttributedStringRenderable: DownHTMLRenderable {
/**
Generates an `NSAttributedString` from the `markdownString` property
- parameter options: `DownOptions` to modify parsing or rendering
- throws: `DownErrors` depending on the scenario
- returns: An `NSAttributedString`
*/
@warn_unused_result
func toAttributedString(options: DownOptions) throws -> NSAttributedString
}
public extension DownAttributedStringRenderable {
/**
Generates an `NSAttributedString` from the `markdownString` property
- parameter options: `DownOptions` to modify parsing or rendering, defaulting to `.Default`
- throws: `DownErrors` depending on the scenario
- returns: An `NSAttributedString`
*/
@warn_unused_result
public func toAttributedString(options: DownOptions = .Default) throws -> NSAttributedString {
let html = try self.toHTML(options)
return try NSAttributedString(htmlString: html)
}
}
+1 -4
View File
@@ -35,10 +35,7 @@ public extension DownHTMLRenderable {
*/
@warn_unused_result
public func toHTML(options: DownOptions = .Default) throws -> String {
let ast = try DownASTRenderer.stringToAST(markdownString, options: options)
let html = try DownHTMLRenderer.astToHTML(ast, options: options)
cmark_node_free(ast)
return html
return try markdownString.toHTML(options)
}
}
+78
View File
@@ -0,0 +1,78 @@
//
// DownView.swift
// Down
//
// Created by Rob Phillips on 6/1/16.
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
//
import WebKit
// MARK: - Public API
public class DownView: WKWebView {
/**
Initializes a web view with the results of rendering a CommonMark Markdown string
- parameter frame: The frame size of the web view
- parameter markdownString: A string containing CommonMark Markdown
- parameter openLinksInBrowser: Whether or not to open links using an external browser
- returns: An instance of Self
*/
@warn_unused_result
public init(frame: CGRect, markdownString: String, openLinksInBrowser: Bool = true) throws {
super.init(frame: frame, configuration: WKWebViewConfiguration())
if openLinksInBrowser { navigationDelegate = self }
try loadHTMLView(markdownString)
}
// MARK: - Private Properties
private let bundle: NSBundle = {
let bundle = NSBundle(forClass: DownView.self)
let url = bundle.URLForResource("DownView", withExtension: "bundle")!
return NSBundle(URL: url)!
}()
private lazy var baseURL: NSURL = {
return self.bundle.URLForResource("index", withExtension: "html")!
}()
}
// MARK: - Private API
private extension DownView {
func loadHTMLView(markdownString: String) throws {
let htmlString = try markdownString.toHTML()
let pageHTMLString = try htmlFromTemplate(htmlString)
loadHTMLString(pageHTMLString, baseURL: baseURL)
}
func htmlFromTemplate(htmlString: String) throws -> String {
let template = try NSString(contentsOfURL: baseURL, encoding: NSUTF8StringEncoding)
return template.stringByReplacingOccurrencesOfString("DOWN_HTML", withString: htmlString)
}
}
// MARK: - WKNavigationDelegate
extension DownView: WKNavigationDelegate {
public func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.URL else { return }
switch navigationAction.navigationType {
case .LinkActivated:
decisionHandler(.Cancel)
UIApplication.sharedApplication().openURL(url)
default:
decisionHandler(.Allow)
}
}
}
+7 -1
View File
@@ -9,7 +9,7 @@
import XCTest
@testable import Down
class RenderableTests: XCTestCase {
class BindingTests: XCTestCase {
let down = Down(markdownString: "## [Down](https://github.com/iwasrobbed/Down)")
@@ -47,5 +47,11 @@ class RenderableTests: XCTestCase {
XCTAssertNotNil(commonMark)
XCTAssertTrue(commonMark == "## [Down](https://github.com/iwasrobbed/Down)\n")
}
func testAttributedStringBindingsWork() {
let attributedString = try? down.toAttributedString()
XCTAssertNotNil(attributedString)
XCTAssertTrue(attributedString!.string == "Down\n")
}
}
+20
View File
@@ -0,0 +1,20 @@
//
// DownViewTests.swift
// Down
//
// Created by Rob Phillips on 6/1/16.
// Copyright © 2016 Glazed Donut, LLC. All rights reserved.
//
import XCTest
@testable import Down
class DownViewTests: XCTestCase {
func testInstantiation() {
let string = "## [Down](https://github.com/iwasrobbed/Down)"
let downView = try? DownView(frame: CGRectZero, markdownString: string)
XCTAssertNotNil(downView)
}
}