commit 4e4f795309ccd2ebf1e58e15fa59037caf1245d3 Author: cetra3 <peter@parashift.com.au> Date: Tue Aug 30 16:30:30 2016 +0930 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c53162 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.amp diff --git a/README.md b/README.md new file mode 100644 index 0000000..6119d1d --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# Markdown Preview for Alfresco Share + +This module adds a markdown preview to Alfresco Share: + + + +## Compiling + +You will need: + +* Java 7 SDK or above +* Gradle +* Parashift's alfresco amp plugin from here: https://bitbucket.org/parashift/alfresco-amp-plugin +* Run `gradle amp` from the `share` and `repo` directories + +### Installing to Alfresco + +* Deploy the amp to both the repo and share end using alfresco-mmt or other methods + +### Usage + +The usage is automatic. + +Any documents with the mime type `text/x-markdown` will display within the document details view. diff --git a/markdown-preview.png b/markdown-preview.png new file mode 100644 index 0000000..5478b39 Binary files /dev/null and b/markdown-preview.png differ diff --git a/repo/.gitignore b/repo/.gitignore new file mode 100644 index 0000000..247a14b --- /dev/null +++ b/repo/.gitignore @@ -0,0 +1,30 @@ +*.iml + +.idea/ + +*.ipr +*.iws + +/out/ + +.idea_modules/ + +.gradle +build/ + +gradle-app.setting + +gradle-wrapper.jar + +.gradletasknamecache + +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath diff --git a/repo/build.gradle b/repo/build.gradle new file mode 100644 index 0000000..581307a --- /dev/null +++ b/repo/build.gradle @@ -0,0 +1,64 @@ +buildscript { + repositories { + jcenter() + mavenLocal() + } + + dependencies { + classpath group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.3.6' + classpath group: 'com.parashift.amp', name: 'amp-plugin', version: '1.0-SNAPSHOT' + } +} + +apply plugin: 'alfresco-amp' + +allprojects { + gradle.projectsEvaluated { + tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" + } + } +} + +version = "1.0.0" + +ext { + alfresco = [:] + alfresco.version = "5.0.1" +} + +repositories { + mavenCentral() + maven { url "https://maven.alfresco.com/nexus/content/groups/public/" } + + maven { + credentials { + username project['alfresco.repo.private.username'] + password project['alfresco.repo.private.password'] + } + + url "https://maven.alfresco.com/nexus/content/groups/private/" + } + mavenLocal() + flatDir name: 'localRepository', dirs: 'lib' +} + +configurations { + all*.exclude group: 'maven-plugins' + all*.exclude group: 'org.jvnet.staxex' +} + +dependencies { + compile (group: "org.alfresco", name: "alfresco", version: "${alfresco.version}", classifier: "classes") + compile 'org.slf4j:slf4j-api:1.7.5' +} + +amp { + id = "com.parashift." + project.name + baseName = project.name + alias = project.name + version = project.version + title = project.title + description = project.description + addLibDir("ampLib") +} diff --git a/repo/gradle.properties b/repo/gradle.properties new file mode 100644 index 0000000..ffa9ae3 --- /dev/null +++ b/repo/gradle.properties @@ -0,0 +1,2 @@ +title=Markdown Preview Repo +description=Allows Markdown files to be Previewed in Share diff --git a/repo/settings.gradle b/repo/settings.gradle new file mode 100644 index 0000000..e7637e5 --- /dev/null +++ b/repo/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "parashift-mdpreview-repo" diff --git a/repo/src/main/java/com/parashift/mdpreview/debug/Debug.java b/repo/src/main/java/com/parashift/mdpreview/debug/Debug.java new file mode 100644 index 0000000..45ddfa4 --- /dev/null +++ b/repo/src/main/java/com/parashift/mdpreview/debug/Debug.java @@ -0,0 +1,25 @@ +package com.parashift.mdpreview.debug; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.PostConstruct; +import org.springframework.stereotype.Component; + +import java.util.Date; + +@Component +public class Debug { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @PostConstruct + void init() { + + logger.debug("\n**************************************************\n" + + "* Markdown Preview has been activated on {}\n" + + "**************************************************\n", new Date()); + + } + +} diff --git a/repo/src/main/java/com/parashift/mdpreview/webscript/ContentGet.java b/repo/src/main/java/com/parashift/mdpreview/webscript/ContentGet.java new file mode 100644 index 0000000..58e7ecd --- /dev/null +++ b/repo/src/main/java/com/parashift/mdpreview/webscript/ContentGet.java @@ -0,0 +1,73 @@ +package com.parashift.mdpreview.webscript; + +import org.alfresco.model.ContentModel; +import org.alfresco.repo.model.Repository; +import org.alfresco.service.cmr.repository.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.extensions.webscripts.AbstractWebScript; +import org.springframework.extensions.webscripts.WebScriptRequest; +import org.springframework.extensions.webscripts.WebScriptResponse; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Serializable; +import java.util.Map; + +/** + * Created by cetra on 30/08/2016. + */ + +@Component(value = "webscript.mdpreview.path.get") +public class ContentGet extends AbstractWebScript { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + protected Repository repository; + + @Autowired + ContentService contentService; + + + @Override + public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException { + + + // create map of template vars + Map<String, String> templateVars = req.getServiceMatch().getTemplateVars(); + + //nodepath is like: /Sites/md-test/documentLibrary/giraffe + String nodePath = "workspace/SpacesStore/Company Home/" + templateVars.get("nodepath").replaceFirst("^/",""); + + logger.debug("node path is:{}", nodePath); + + NodeRef nodeRef = repository.findNodeRef("path", nodePath.split("/")); + + logger.debug("node ref is:{}", nodeRef); + + if(nodeRef != null) { + + ContentReader reader = contentService.getReader(nodeRef, ContentModel.PROP_CONTENT); + + if(reader != null) { + + logger.debug("found reader for nodeRef:{}, streaming content of type:{}", nodeRef, reader.getMimetype()); + res.setContentType(reader.getMimetype()); + + try(OutputStream outputStream = res.getOutputStream()) { + reader.getContent(outputStream); + } + } else { + throw new IOException("Could not read content property for node: " + nodeRef); + } + + } else { + throw new IOException("Could not find node at path: " + nodePath); + } + + + } +} diff --git a/repo/src/main/resources/alfresco/extension/mdpreview-context.xml b/repo/src/main/resources/alfresco/extension/mdpreview-context.xml new file mode 100644 index 0000000..c948467 --- /dev/null +++ b/repo/src/main/resources/alfresco/extension/mdpreview-context.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans-3.0.xsd + http://www.springframework.org/schema/context + http://www.springframework.org/schema/context/spring-context-3.0.xsd"> + + <context:component-scan base-package="com.parashift.mdpreview" /> + +</beans> diff --git a/repo/src/main/resources/alfresco/templates/webscripts/mdpreview/path.get.desc.xml b/repo/src/main/resources/alfresco/templates/webscripts/mdpreview/path.get.desc.xml new file mode 100644 index 0000000..74cfbaf --- /dev/null +++ b/repo/src/main/resources/alfresco/templates/webscripts/mdpreview/path.get.desc.xml @@ -0,0 +1,7 @@ +<webscript> + <shortname>ONLYOFFICE Prepare URL</shortname> + <description>Sends information to Share to prepare the ONLYOFFICE Edit Page</description> + <url>/markdown/{nodepath}</url> + <format default="">argument</format> + <authentication>user</authentication> +</webscript> \ No newline at end of file diff --git a/share/.gitignore b/share/.gitignore new file mode 100644 index 0000000..247a14b --- /dev/null +++ b/share/.gitignore @@ -0,0 +1,30 @@ +*.iml + +.idea/ + +*.ipr +*.iws + +/out/ + +.idea_modules/ + +.gradle +build/ + +gradle-app.setting + +gradle-wrapper.jar + +.gradletasknamecache + +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath diff --git a/share/build.gradle b/share/build.gradle new file mode 100644 index 0000000..79f98e4 --- /dev/null +++ b/share/build.gradle @@ -0,0 +1,61 @@ +buildscript { + repositories{ + mavenCentral() + mavenLocal() + } + dependencies { + classpath group: 'com.parashift.amp', name: 'amp-plugin', version: '1.0-SNAPSHOT' + } +} + +apply plugin: "alfresco-amp" + +repositories { + mavenCentral() + maven { url "https://maven.alfresco.com/nexus/content/groups/public/" } + + maven { + credentials { + username project['alfresco.repo.private.username'] + password project['alfresco.repo.private.password'] + } + + url "https://maven.alfresco.com/nexus/content/groups/private/" + } + mavenLocal() + flatDir name: 'localRepository', dirs: 'lib' +} + +configurations { + all*.exclude group: 'maven-plugins' +} + +version = "1.0.0" + +ext { + alfresco = [:] + alfresco.version = "5.0.1" +} + +dependencies { + + compile (group: "org.alfresco", name: "share", version: "${alfresco.version}", classifier: "classes") + +} + +jar { + manifest { + attributes 'Implementation-Title': project.name, 'Implementation-Version': version + } +} + +amp { + id = "com.parashift." + project.name + baseName = project.name + alias = project.name + version = project.version + title = project.title + description = project.description + + addLibDir("extraLibs") +} diff --git a/share/gradle.properties b/share/gradle.properties new file mode 100644 index 0000000..171dcb9 --- /dev/null +++ b/share/gradle.properties @@ -0,0 +1,2 @@ +title=Markdown Preview Share +description=Allows Markdown files to be Previewed in Share diff --git a/share/settings.gradle b/share/settings.gradle new file mode 100644 index 0000000..62fa744 --- /dev/null +++ b/share/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "parashift-mdpreview-share" diff --git a/share/src/main/resources/META-INF/components/preview/MarkDown.css b/share/src/main/resources/META-INF/components/preview/MarkDown.css new file mode 100644 index 0000000..adfde97 --- /dev/null +++ b/share/src/main/resources/META-INF/components/preview/MarkDown.css @@ -0,0 +1,709 @@ +@font-face { + font-family: octicons-link; + src: url(data:font/woff !important;charset=utf-8 !important;base64,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) format('woff'); +} + +.markdown-body { + -ms-text-size-adjust: 100% !important; + -webkit-text-size-adjust: 100% !important; + line-height: 1.5 !important; + color: #333 !important; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important; + font-size: 16px !important; + line-height: 1.5 !important; + word-wrap: break-word !important; + + background-color: #fefefe; + border-top: 3px solid #ccc; + border-bottom: 1px solid #ccc; + border-left: 1px solid #ccc; + border-right: 1px solid #ccc; + padding: 10px; + margin-left: 3px; + +} + +.markdown-body .pl-c { + color: #969896 !important; +} + +.markdown-body .pl-c1, +.markdown-body .pl-s .pl-v { + color: #0086b3 !important; +} + +.markdown-body .pl-e, +.markdown-body .pl-en { + color: #795da3 !important; +} + +.markdown-body .pl-smi, +.markdown-body .pl-s .pl-s1 { + color: #333 !important; +} + +.markdown-body .pl-ent { + color: #63a35c !important; +} + +.markdown-body .pl-k { + color: #a71d5d !important; +} + +.markdown-body .pl-s, +.markdown-body .pl-pds, +.markdown-body .pl-s .pl-pse .pl-s1, +.markdown-body .pl-sr, +.markdown-body .pl-sr .pl-cce, +.markdown-body .pl-sr .pl-sre, +.markdown-body .pl-sr .pl-sra { + color: #183691 !important; +} + +.markdown-body .pl-v { + color: #ed6a43 !important; +} + +.markdown-body .pl-id { + color: #b52a1d !important; +} + +.markdown-body .pl-ii { + color: #f8f8f8 !important; + background-color: #b52a1d !important; +} + +.markdown-body .pl-sr .pl-cce { + font-weight: bold !important; + color: #63a35c !important; +} + +.markdown-body .pl-ml { + color: #693a17 !important; +} + +.markdown-body .pl-mh, +.markdown-body .pl-mh .pl-en, +.markdown-body .pl-ms { + font-weight: bold !important; + color: #1d3e81 !important; +} + +.markdown-body .pl-mq { + color: #008080 !important; +} + +.markdown-body .pl-mi { + font-style: italic !important; + color: #333 !important; +} + +.markdown-body .pl-mb { + font-weight: bold !important; + color: #333 !important; +} + +.markdown-body .pl-md { + color: #bd2c00 !important; + background-color: #ffecec !important; +} + +.markdown-body .pl-mi1 { + color: #55a532 !important; + background-color: #eaffea !important; +} + +.markdown-body .pl-mdr { + font-weight: bold !important; + color: #795da3 !important; +} + +.markdown-body .pl-mo { + color: #1d3e81 !important; +} + +.markdown-body .octicon { + display: inline-block !important; + vertical-align: text-top !important; + fill: currentColor !important; +} + +.markdown-body a { + background-color: transparent !important; + -webkit-text-decoration-skip: objects !important; +} + +.markdown-body a:active, +.markdown-body a:hover { + outline-width: 0 !important; +} + +.markdown-body strong { + font-weight: inherit !important; +} + +.markdown-body strong { + font-weight: bolder !important; +} + +.markdown-body h1 { + font-size: 2em !important; + margin: 0.67em 0 !important; +} + +.markdown-body img { + border-style: none !important; +} + +.markdown-body svg:not(:root) { + overflow: hidden !important; +} + +.markdown-body code, +.markdown-body kbd, +.markdown-body pre { + font-family: monospace; + font-size: 1em !important; +} + +.markdown-body hr { + box-sizing: content-box !important; + height: 0 !important; + overflow: visible !important; +} + +.markdown-body input { + font: inherit !important; + margin: 0 !important; +} + +.markdown-body input { + overflow: visible !important; +} + +.markdown-body button:-moz-focusring, +.markdown-body [type="button"]:-moz-focusring, +.markdown-body [type="reset"]:-moz-focusring, +.markdown-body [type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText !important; +} + +.markdown-body [type="checkbox"] { + box-sizing: border-box !important; + padding: 0 !important; +} + +.markdown-body * { + box-sizing: border-box !important; +} + +.markdown-body input { + font-family: inherit !important; + font-size: inherit !important; + line-height: inherit !important; +} + +.markdown-body a { + color: #4078c0 !important; + text-decoration: none !important; +} + +.markdown-body a:hover, +.markdown-body a:active { + text-decoration: underline !important; +} + +.markdown-body strong { + font-weight: 600 !important; +} + +.markdown-body hr { + height: 0 !important; + margin: 15px 0 !important; + overflow: hidden !important; + background: transparent !important; + border: 0 !important; + border-bottom: 1px solid #ddd !important; +} + +.markdown-body hr::before { + display: table !important; + content: "" !important; +} + +.markdown-body hr::after { + display: table !important; + clear: both !important; + content: "" !important; +} + +.markdown-body table { + border-spacing: 0 !important; + border-collapse: collapse !important; +} + +.markdown-body td, +.markdown-body th { + padding: 0 !important; +} + +.markdown-body h1, +.markdown-body h2, +.markdown-body h3, +.markdown-body h4, +.markdown-body h5, +.markdown-body h6 { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important; + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.markdown-body h1 { + font-size: 32px !important; + font-weight: 600 !important; +} + +.markdown-body h2 { + font-size: 24px !important; + font-weight: 600 !important; +} + +.markdown-body h3 { + font-size: 20px !important; + font-weight: 600 !important; +} + +.markdown-body h4 { + font-size: 16px !important; + font-weight: 600 !important; +} + +.markdown-body h5 { + font-size: 14px !important; + font-weight: 600 !important; +} + +.markdown-body h6 { + font-size: 12px !important; + font-weight: 600 !important; +} + +.markdown-body p { + margin-top: 0 !important; + margin-bottom: 10px !important; +} + +.markdown-body blockquote { + margin: 0 !important; +} + + +.markdown-body li { + list-style: inside !important; +} + +.markdown-body ul, +.markdown-body ol { + padding-left: 0 !important; + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.markdown-body ol ol, +.markdown-body ul ol { + list-style: lower-roman inside !important; +} + +.markdown-body ul ul ol, +.markdown-body ul ol ol, +.markdown-body ol ul ol, +.markdown-body ol ol ol { + list-style: lower-alpha inside !important; +} + +.markdown-body dd { + margin-left: 0 !important; +} + +.markdown-body code { + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; + font-size: 12px !important; +} + +.markdown-body pre { + margin-top: 0 !important; + margin-bottom: 0 !important; + font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace; +} + +.markdown-body .octicon { + vertical-align: text-bottom !important; +} + +.markdown-body input { + -webkit-font-feature-settings: "liga" 0 !important; + font-feature-settings: "liga" 0 !important; +} + +.markdown-body .form-select::-ms-expand { + opacity: 0 !important; +} + +.markdown-body::before { + display: table !important; + content: "" !important; +} + +.markdown-body::after { + display: table !important; + clear: both !important; + content: "" !important; +} + +.markdown-body>*:first-child { + margin-top: 0 !important; +} + +.markdown-body>*:last-child { + margin-bottom: 0 !important; +} + +.markdown-body a:not([href]) { + color: inherit !important; + text-decoration: none !important; +} + +.markdown-body .anchor { + float: left !important; + padding-right: 4px !important; + margin-left: -20px !important; + line-height: 1 !important; +} + +.markdown-body .anchor:focus { + outline: none !important; +} + +.markdown-body p, +.markdown-body blockquote, +.markdown-body ul, +.markdown-body ol, +.markdown-body dl, +.markdown-body table, +.markdown-body pre { + margin-top: 0 !important; + margin-bottom: 16px !important; +} + +.markdown-body hr { + height: 0.25em !important; + padding: 0 !important; + margin: 24px 0 !important; + background-color: #e7e7e7 !important; + border: 0 !important; +} + +.markdown-body blockquote { + padding: 0 1em !important; + color: #777 !important; + border-left: 0.25em solid #ddd !important; +} + +.markdown-body blockquote>:first-child { + margin-top: 0 !important; +} + +.markdown-body blockquote>:last-child { + margin-bottom: 0 !important; +} + +.markdown-body kbd { + display: inline-block !important; + padding: 3px 5px !important; + font-size: 11px !important; + line-height: 10px !important; + color: #555 !important; + vertical-align: middle !important; + background-color: #fcfcfc !important; + border: solid 1px #ccc !important; + border-bottom-color: #bbb !important; + border-radius: 3px !important; + box-shadow: inset 0 -1px 0 #bbb !important; +} + +.markdown-body h1, +.markdown-body h2, +.markdown-body h3, +.markdown-body h4, +.markdown-body h5, +.markdown-body h6 { + margin-top: 24px !important; + margin-bottom: 16px !important; + font-weight: 600 !important; + line-height: 1.25 !important; +} + +.markdown-body h1 .octicon-link, +.markdown-body h2 .octicon-link, +.markdown-body h3 .octicon-link, +.markdown-body h4 .octicon-link, +.markdown-body h5 .octicon-link, +.markdown-body h6 .octicon-link { + color: #000 !important; + vertical-align: middle !important; + visibility: hidden !important; +} + +.markdown-body h1:hover .anchor, +.markdown-body h2:hover .anchor, +.markdown-body h3:hover .anchor, +.markdown-body h4:hover .anchor, +.markdown-body h5:hover .anchor, +.markdown-body h6:hover .anchor { + text-decoration: none !important; +} + +.markdown-body h1:hover .anchor .octicon-link, +.markdown-body h2:hover .anchor .octicon-link, +.markdown-body h3:hover .anchor .octicon-link, +.markdown-body h4:hover .anchor .octicon-link, +.markdown-body h5:hover .anchor .octicon-link, +.markdown-body h6:hover .anchor .octicon-link { + visibility: visible !important; +} + +.markdown-body h1 { + padding-bottom: 0.3em !important; + font-size: 2em !important; + border-bottom: 1px solid #eee !important; +} + +.markdown-body h2 { + padding-bottom: 0.3em !important; + font-size: 1.5em !important; + border-bottom: 1px solid #eee !important; +} + +.markdown-body h3 { + font-size: 1.25em !important; +} + +.markdown-body h4 { + font-size: 1em !important; +} + +.markdown-body h5 { + font-size: 0.875em !important; +} + +.markdown-body h6 { + font-size: 0.85em !important; + color: #777 !important; +} + +.markdown-body ul, +.markdown-body ol { + padding-left: 2em !important; +} + +.markdown-body ul ul, +.markdown-body ul ol, +.markdown-body ol ol, +.markdown-body ol ul { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.markdown-body li>p { + margin-top: 16px !important; +} + +.markdown-body li+li { + margin-top: 0.25em !important; +} + +.markdown-body dl { + padding: 0 !important; +} + +.markdown-body dl dt { + padding: 0 !important; + margin-top: 16px !important; + font-size: 1em !important; + font-style: italic !important; + font-weight: bold !important; +} + +.markdown-body dl dd { + padding: 0 16px !important; + margin-bottom: 16px !important; +} + +.markdown-body table { + display: block !important; + width: 100% !important; + overflow: auto !important; + word-break: normal !important; + word-break: keep-all !important; +} + +.markdown-body table th { + font-weight: bold !important; +} + +.markdown-body table th, +.markdown-body table td { + padding: 6px 13px !important; + border: 1px solid #ddd !important; +} + +.markdown-body table tr { + background-color: #fff !important; + border-top: 1px solid #ccc !important; +} + +.markdown-body table tr:nth-child(2n) { + background-color: #f8f8f8 !important; +} + +.markdown-body img { + max-width: 100% !important; + box-sizing: content-box !important; + background-color: #fff !important; +} + +.markdown-body code { + padding: 0 !important; + padding-top: 0.2em !important; + padding-bottom: 0.2em !important; + margin: 0 !important; + font-size: 85% !important; + background-color: rgba(0,0,0,0.04) !important; + border-radius: 3px !important; +} + +.markdown-body code::before, +.markdown-body code::after { + letter-spacing: -0.2em !important; + content: "\00a0" !important; +} + +.markdown-body pre { + word-wrap: normal !important; +} + +.markdown-body pre>code { + padding: 0 !important; + margin: 0 !important; + font-size: 100% !important; + word-break: normal !important; + white-space: pre !important; + background: transparent !important; + border: 0 !important; +} + +.markdown-body .highlight { + margin-bottom: 16px !important; +} + +.markdown-body .highlight pre { + margin-bottom: 0 !important; + word-break: normal !important; +} + +.markdown-body .highlight pre, +.markdown-body pre { + padding: 16px !important; + overflow: auto !important; + font-size: 85% !important; + line-height: 1.45 !important; + background-color: #f7f7f7 !important; + border-radius: 3px !important; +} + +.markdown-body pre code { + display: inline !important; + max-width: auto !important; + padding: 0 !important; + margin: 0 !important; + overflow: visible !important; + line-height: inherit !important; + word-wrap: normal !important; + background-color: transparent !important; + border: 0 !important; +} + +.markdown-body pre code::before, +.markdown-body pre code::after { + content: normal !important; +} + +.markdown-body .pl-0 { + padding-left: 0 !important; +} + +.markdown-body .pl-1 { + padding-left: 3px !important; +} + +.markdown-body .pl-2 { + padding-left: 6px !important; +} + +.markdown-body .pl-3 { + padding-left: 12px !important; +} + +.markdown-body .pl-4 { + padding-left: 24px !important; +} + +.markdown-body .pl-5 { + padding-left: 36px !important; +} + +.markdown-body .pl-6 { + padding-left: 48px !important; +} + +.markdown-body .full-commit .btn-outline:not(:disabled):hover { + color: #4078c0 !important; + border: 1px solid #4078c0 !important; +} + +.markdown-body kbd { + display: inline-block !important; + padding: 3px 5px !important; + font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace; + line-height: 10px !important; + color: #555 !important; + vertical-align: middle !important; + background-color: #fcfcfc !important; + border: solid 1px #ccc !important; + border-bottom-color: #bbb !important; + border-radius: 3px !important; + box-shadow: inset 0 -1px 0 #bbb !important; +} + +.markdown-body :checked+.radio-label { + position: relative !important; + z-index: 1 !important; + border-color: #4078c0 !important; +} + +.markdown-body .task-list-item { + list-style-type: none !important; +} + +.markdown-body .task-list-item+.task-list-item { + margin-top: 3px !important; +} + +.markdown-body .task-list-item input { + margin: 0 0.2em 0.25em -1.6em !important; + vertical-align: middle !important; +} + +.markdown-body hr { + border-bottom-color: #eee !important; +} diff --git a/share/src/main/resources/META-INF/components/preview/MarkDown.js b/share/src/main/resources/META-INF/components/preview/MarkDown.js new file mode 100644 index 0000000..f56d3b7 --- /dev/null +++ b/share/src/main/resources/META-INF/components/preview/MarkDown.js @@ -0,0 +1,81 @@ +(function() { + + Alfresco.WebPreview.prototype.Plugins.MarkDown = function(wp, attributes) + { + this.wp = wp; + this.attributes = YAHOO.lang.merge(Alfresco.util.deepCopy(this.attributes), attributes); + return this; + }; + + Alfresco.WebPreview.prototype.Plugins.MarkDown.prototype = + { + attributes: {}, + + report: function() { + return null; + }, + + display: function() { + + var node = this.attributes.node; + + //get the default relative path of the node + var locationPath = Alfresco.constants.PROXY_URI_RELATIVE + "/markdown" + this.attributes.location.repoPath + "/"; + + //get the Div Element we'll be putting the Markdown + var divElem = document.getElementById(this.wp.id + "-body") + + + + //Execute Ajax request for content + require(["dojo/request", "showdown"], function(request, showdown){ + + + //Once we have the content, let's create a converter and add the html to the div element + converter = new showdown.Converter({ + extensions: [ + function() { + return [{ + type: 'output', + filter: function(source) { + return source.replace(/<img src="([^"]*)"/, function(match, src) { + + if(src.startsWith("http")) { + //if this includes external links, then don't change it. + return match; + } else { + //if it's a relative link, we need to use our webscript + return "<img src=\"" + locationPath + src + "\""; + } + }); + } + }] + } + ] + + }); + + + request.get(Alfresco.constants.PROXY_URI_RELATIVE + node.contentURL).then(function(mdData) { + + + newHtml = converter.makeHtml(mdData); + + console.log(newHtml); + console.log(divElem); + + divElem.className = "markdown-body"; + divElem.innerHTML = converter.makeHtml(mdData); + + + }); + + }); + + console.log(this.wp); + console.log(this.attributes); + + } + } + +})(); diff --git a/share/src/main/resources/alfresco/mdpreview-config.xml b/share/src/main/resources/alfresco/mdpreview-config.xml new file mode 100644 index 0000000..6eb3a8e --- /dev/null +++ b/share/src/main/resources/alfresco/mdpreview-config.xml @@ -0,0 +1,3 @@ +<alfresco-config> + <!-- Insert configuration here --> +</alfresco-config> diff --git a/share/src/main/resources/alfresco/site-data/extensions/markdown-preview-extension.xml b/share/src/main/resources/alfresco/site-data/extensions/markdown-preview-extension.xml new file mode 100644 index 0000000..b98674c --- /dev/null +++ b/share/src/main/resources/alfresco/site-data/extensions/markdown-preview-extension.xml @@ -0,0 +1,19 @@ +<extension> + <modules> + <module> + <id>Parashift Markdown Preview</id> + <version>1.0</version> + <auto-deploy>true</auto-deploy> + <customizations> + <customization> + <targetPackageRoot>org.alfresco.components.preview</targetPackageRoot> + <sourcePackageRoot>com.parashift.markdown.preview-config</sourcePackageRoot> + <dependencies> + <js>/res/components/preview/MarkDown.js</js> + <css>/res/components/preview/MarkDown.css</css> + </dependencies> + </customization> + </customizations> + </module> + </modules> +</extension> diff --git a/share/src/main/resources/alfresco/site-webscripts/com/parashift/markdown/preview-config/web-preview.get.js b/share/src/main/resources/alfresco/site-webscripts/com/parashift/markdown/preview-config/web-preview.get.js new file mode 100644 index 0000000..17e61c1 --- /dev/null +++ b/share/src/main/resources/alfresco/site-webscripts/com/parashift/markdown/preview-config/web-preview.get.js @@ -0,0 +1,33 @@ +if (model.widgets) +{ + for (var i = 0; i < model.widgets.length; i++) + { + var widget = model.widgets[i]; + if (widget.id == "WebPreview") + { + + //We need to know some extra bits about the node, such as the repoPath to display images + pObj = eval('(' + remote.call("/slingshot/doclib2/node/" + url.args.nodeRef.replace(":/","")) + ')'); + + //We check to see if the mime type is markdown, and if so, overwrite the conditions object. + if(pObj.item && pObj.item.node && pObj.item.node.mimetype == "text/x-markdown") { + + var conditions = [{ + attributes: { + mimeType: "text/x-markdown" + }, + plugins: [{ + name: "MarkDown", + attributes: pObj.item + }] + }]; + + // Override the original conditions + model.pluginConditions = jsonUtils.toJSONString(conditions); + widget.options.pluginConditions = model.pluginConditions; + + } + + } + } +} diff --git a/share/src/main/resources/alfresco/web-extension/mdpreview-context.xml b/share/src/main/resources/alfresco/web-extension/mdpreview-context.xml new file mode 100644 index 0000000..2cdcd50 --- /dev/null +++ b/share/src/main/resources/alfresco/web-extension/mdpreview-context.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans-2.5.xsd + http://www.springframework.org/schema/context + http://www.springframework.org/schema/context/spring-context-2.5.xsd"> + + <bean id="mdpreview.config" + class="org.springframework.extensions.config.ConfigBootstrap" + init-method="register"> + + <property name="configService" ref="web.config" /> + <property name="configs"> + <list> + <value>classpath:alfresco/mdpreview-config.xml</value> + </list> + </property> + </bean> + +</beans>