From 2a1f2658e92b2d8983cab2694a37fac595a76213 Mon Sep 17 00:00:00 2001 From: Christian Genco Date: Tue, 7 Apr 2015 03:01:42 -0500 Subject: [PATCH] apa header pages --- ...ionship Research by Christian R. Genco.pdf | Bin 0 -> 3112 bytes apa_paper.md | 44 +++ markdowntoapa.coffee | 274 ++++++++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 Varying Definitions of Online Communication and Their Effects on Relationship Research by Christian R. Genco.pdf create mode 100644 apa_paper.md create mode 100644 markdowntoapa.coffee diff --git a/Varying Definitions of Online Communication and Their Effects on Relationship Research by Christian R. Genco.pdf b/Varying Definitions of Online Communication and Their Effects on Relationship Research by Christian R. Genco.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3a1e6f0e238c9f9d4d4d3fe18955b918aad2e4f1 GIT binary patch literal 3112 zcmb_fX;>5I7IuT%Mtr1-3NARx;z}ly5E6EQ5M&8LKrlotV;D#%B#=yKz~zb$SWyrw zqU@Fk70_Z;D#)Tm5CKC4uUrwR2xvs4h!@Z+g4~%H3Zg%JZaY6R&-Z@ccg}gwHYY|N z45kT0q!5h8v4=nfNPuWpFu}@-0D4D;ApqzB2O$LPSBwZz0K&G}1dxRU2w;1W4B(P5 zzziY-G;{I}0_Y$TqS!GBKzVfD2-_ z0H8M_Ljlk^6w_<3emkh&&X^7+rUSsuW0C>038|BU&8G1ab`h+Sq0et;; z5dfJK0Kz@VCSXJ+xj?uZCzSjJGLSlKlWeevskN!;sDKGoe``RXX`v2~@(?kw77Mkj z09}XWj2MAY5r%}q;%@>(-wII?90misA^{#>ERdiASV#;)ghZZb;;=v@WWXo_tYuh` zNf4DpA<;;55=0{TVJEx=Xb86D1B)XC!XSWw1PX)#6uTk;M1jB-VTeG801l$iP^nPB zgYgXj76t&`d_*7y90LOp9+tis$VNg`yAr-23|mMLSj^*N^6jK3AGg+F!Z?6U1e_2d zZr)_%@Wh<(=KH|mX-fd@VF{v2V9d@?L}J1gg~CDt=q25Ss)`Li3lTs^Ok4nNKIkhD z+6g6s31Er}RlAsKWuq#EF9Nju3>^_4~}4B#y5?yr4RVw+1Oz zw-f^CDhQAOT)fY)0lZk*fGW+|JEn4*D#i^F2BCa_Ofki3UJ!y}*#k1M;2;bH^Adtz zlb~15*XE8y|MZb9{$Z4JjFt*y?blNOst28#0f|3o-|+f-Ekss%<8)N zA}>wjnu>p9J2>~G&Z8}@;(%JKTKJyVEIcAc*R6fd%6k-_G|qCZYe_Tv9sMzPMtVW2 zyuUPcx%o4C?-AGRedQ3LAzaw-+ziZifc2n}gs|@NEs%yr{fzh3-lj)(IIf0LFrc=2Mu8W}*&0t~)jhpFO z6FM;KfmJ!7`e)*ml2?45cWD5S<)1X@nqgDbremX@zkyL#;Fz2dlQ*{SwS|T!fu&Kt zBYWn>+m6e0fBBW%VM;eR6Zz13Q>$fcebh!5Zh@9(^}17*Mm?o+cZt4Rkz`3m*T2_9 z=P##_TFs8Ishs@R4f2?Ci6`xvUBN5e4FP90pXruy6YX}(h@$VRcdqVw$BiLpg;x-7 z=+aUL^xTYdbPt#4 zU3o9Ex4-+3xx2G<7OYtS%J%)ye_hn^qWJWkdv-}$?U!FiUX8FYxDA+Vi0k5R*&45| zm@fm#H+;PFzj(+xx&5&HF?h)B>5O91Md`VKWzKs!zLo%>(Gp_#K(O9^8DbGYOQv~(&J01UQwYw z-TBJr4~Wv0-&90LZ`JhF41k;YjSR)z!Qm^xA(g(ddoD4C*^MW5XTvL{TL=7afuyvE zp2PvSq~ia=d2)7>_04HmW2d8d7w(XJ6XFQTDUk zl)7Q}cJZ6pZAr@W#MHHx4^L5)LF~7duU2xyveI8&@olhnX(DrqmV>EQO_B(=`1@Vo zovWz5cD5qVd;YTA729L@gR_;5mU7j{_sl}!{LAoWW zxBp4|&xIv^Wjbf7v+iC?Q~dysB+k zMlF9t(~Z!1KX%5;;k!>azSvsmsqbDoZgHXh+{4j59m(hSf3;>MFRa$-a4N-i+n^#| zTqCqLLD(m08itJ+A7S)Q z$fKKK4Pe?`3O-j&!^k9TcASQpQ$MyDqJ4yssGqRU^b @[0] + +Array::last ?= -> @[@length - 1] + +process.chdir(__dirname) + +# style definitions for markdown +styles = + default: + font: 'Times-Roman' + fontSize: 12 + lineGap: 14 + align: 'left' + meta: + indent: 0 + title: + align: 'center' + para: + indent: 72/2 + blockquote: + indent: 0 + marginLeft: 72 + color: 'red' + font: 'Times-Italic' + em: + font: 'Times-Italic' + strong: + font: 'Times-Bold' + h1: + align: 'center' + # h2: + # font: 'Times-Italic' + # h3: + # font: 'Times-Bold' + # align: 'center' + # h4: + # font: 'Times-Italic' + # align: 'center' + # h5: + # underline: true + citationHeader: + align: 'center' + citation: + indent: -72/2 + marginLeft: 72/2 + +# This class represents a node in the markdown tree, and can render it to pdf +class Node + constructor: (tree) -> + # special case for text nodes + if typeof tree is 'string' + @type = 'text' + @text = tree + return + + @type = tree.shift() + @attrs = {} + + if typeof tree[0] is 'object' and not Array.isArray tree[0] + @attrs = tree.shift() + + switch @type + when 'header' + @type = 'h' + @attrs.level + when 'img' + # images are used to generate inline example output + # compiles the coffeescript to JS so it can be run + # in the render method + @type = 'example' + code = codeBlocks[@attrs.alt] + @code = coffee.compile code if code + @height = +@attrs.title or 0 + + @style = _.extend({}, styles.default, styles[@type]) + + # parse sub nodes + @content = while tree.length + child = new Node tree.shift() + # blockquotes have an embedded paragraph; make sure the inner paragraph doesn't re-define + # its indentation + child.style?.indent = @style.indent if @style.indent? + child + + # console.log "content =", @content + # console.log "type =", @type + + + # sets the styles on the document for this node + setStyle: (doc) -> + if @style.font + doc.font @style.font + + if @style.fontSize + doc.fontSize @style.fontSize + + if @style.color + doc.fillColor @style.color + else + doc.fillColor 'black' + + # renders this node and its subnodes to the document + render: (doc, continued = false) -> + # console.log "rendering node: ", @ + if @style.marginLeft + doc.x += @style.marginLeft + + switch @type + when 'hr' + doc.addPage() + else + # loop through subnodes and render them + for fragment, index in @content + if fragment.type is 'text' + @setStyle doc + + # remove newlines unless this is code + # unless @type is 'code' + # fragment.text = fragment.text.replace(/[\r\n]\s*/g, ' ') + + # console.log "rendering text. continued =", continued, 'attrs.continued =', @attrs.continued + doc.text fragment.text, _.extend({}, @style, {continued: continued or index < @content.length - 1}) + else + # console.log "rendering fragment #{fragment.type}" + fragment.render doc, index < @content.length - 1 and @type isnt 'bulletlist' + + if @style.marginBottom + doc.y += @style.marginBottom + if @style.marginLeft + doc.x -= @style.marginLeft + +addAPAHeader = (doc, runningHead) -> + range = doc.bufferedPageRange() # => { start: 0, count: 2 } + doc.font styles.default.font + for i in [range.start...range.start + range.count] + doc.switchToPage(i) + doc.y = 72/2 + doc.x = 72 + head = runningHead + head = "Running head: " + head if i == 0 + doc.text head, _.extend({}, styles.default, {}) + + doc.y = 72/2 + doc.x = 72 + doc.text "#{i + 1}", _.extend({}, styles.default, {align: 'right'}) + +# reads and renders a markdown/literate coffeescript file to the document +render = (doc, tree) -> + doc.font 'Times-Roman' + doc.fontSize 12 + + codeBlocks = [] + + onWorksCited = false + while tree.length + node = new Node(tree.shift()) + # console.log "node =", node + if node.type == "h1" && node.content?.first()?.text?.toLowerCase() == "works cited" + onWorksCited = true + node.style = _.extend({}, styles.default, styles.citationHeader) + + if onWorksCited && node.type == "para" + node.style = _.extend({}, styles.default, styles.citation) + + node.render(doc) + + doc + +# renders the title page of the guide +# renderTitlePage = (doc) -> +# title = 'PDFKit Guide' +# author = 'By Devon Govett' +# version = 'Version ' + require('./package.json').version + +# doc.font 'fonts/AlegreyaSans-Light.ttf', 60 +# doc.y = doc.page.height / 2 - doc.currentLineHeight() +# doc.text title, align: 'center' +# w = doc.widthOfString(title) + +# doc.fontSize 20 +# doc.y -= 10 +# doc.text author, +# align: 'center' +# indent: w - doc.widthOfString(author) + +# doc.font styles.para.font, 10 +# doc.text version, +# align: 'center' +# indent: w - doc.widthOfString(version) + +# doc.addPage() + +extractMetadata = (text) -> + body = "" + metadata = {} + + metadata_pattern = /// ^ + ([\w.-]+) # key + \:\ # colon + \s* # optional whitespace + (.+) # value + $/// + + for line in text.split("\n") + if meta = line.match(metadata_pattern) + key = meta[1] + value = meta[2].replace(/\\n/, "\n") + metadata[key] = value + else + body += line + "\n" + + {metadata: metadata, body: body} + +createAPADocument = (body, metadata, stream) -> + tree = md.parse body + tree.shift() # ignore 'markdown' first element + + metadata.lastName ||= metadata.author?.split(" ").last() + + doc = new PDFDocument + bufferPages: true + + doc.info.Title = metadata.title.replace("\n", " ") + doc.info.Author = metadata.author + doc.info.Creator = "markdowntoapa by christian.gen.co" + + # add header + doc.y = 72*3 + doc.font 'Times-Roman' + doc.fontSize 12 + doc.text(metadata.title, _.extend({}, styles.default, styles.title)) + doc.text(metadata.author, _.extend({}, styles.default, styles.title)) + doc.text(metadata.institution, _.extend({}, styles.default, styles.title)) + + doc.addPage() + + # add abstract page + doc.text("Abstract", _.extend({}, styles.default, styles.h1)) + doc.text(metadata.abstract, _.extend({}, styles.default, {})) + if metadata.keywords + # TODO: more generic text writing function + doc.font styles.em.font + doc.text("Keywords: ", _.extend({continued: true}, styles.default, styles.para)) + doc.font styles.default.font + doc.text(metadata.keywords, _.extend({}, styles.default, styles.para)) + + doc.addPage() + + doc.text(metadata.title, _.extend({}, styles.default, styles.title)) + + # doc.pipe(stream) + # render doc, tree + addAPAHeader(doc, metadata.runninghead) + doc.end() + doc + +exports.extractMetadata = extractMetadata +exports.createAPADocument = createAPADocument + +do -> + # command line + fs = require 'fs' + filename = "apa_paper.md" + content = fs.readFileSync(filename, 'utf8') + content = extractMetadata(content) + body = content.body + metadata = content.metadata + doc = createAPADocument(body, metadata) + stream = fs.createWriteStream("#{metadata.title.replace("\n", ' ')} by #{metadata.author}.pdf") + doc.pipe(stream) \ No newline at end of file