mirror of
https://github.com/JuanCanham/HackMyResume.git
synced 2025-05-12 00:27:08 +01:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
7c0354046c | |||
43cd1c7e52 | |||
f80c333361 | |||
cdbb264093 | |||
87b3bbe785 | |||
b92cf7298a | |||
93456b5f40 | |||
72f29bf402 | |||
f6fc384466 | |||
c5ab3fdfae | |||
78c5081a29 |
54
README.md
54
README.md
@ -2,7 +2,8 @@ HackMyResume
|
||||
============
|
||||
*Create polished résumés and CVs in multiple formats from your command line or
|
||||
shell. Author in clean Markdown and JSON, export to Word, HTML, PDF, LaTeX,
|
||||
plain text, and other arbitrary formats.*
|
||||
plain text, and other arbitrary formats. Fight the power, save trees. Compatible
|
||||
with [FRESH][fresca] and [JRS][6] resumes.*
|
||||
|
||||

|
||||
|
||||
@ -24,8 +25,6 @@ or Windows.
|
||||
- Store your resume data as a durable, versionable JSON or YAML document.
|
||||
- Generate polished resumes in multiple formats without violating [DRY][dry].
|
||||
- Output to HTML, Markdown, LaTeX, PDF, MS Word, JSON, YAML, plain text, or XML.
|
||||
- Compatible with [FRESH][fresh], [JSON Resume][6], [FRESCA][fresca], and
|
||||
[FCV Desktop][7].
|
||||
- Validate resumes against the FRESH or JSON Resume schema.
|
||||
- Support for multiple input and output resumes.
|
||||
- Use from your command line or [desktop][7].
|
||||
@ -49,8 +48,9 @@ To use HackMyResume you'll need to create a valid resume in either
|
||||
[FRESH][fresca] or [JSON Resume][6] format. Then you can start using the command
|
||||
line tool. There are four basic commands you should be aware of:
|
||||
|
||||
- `build` generates resumes in HTML, Word, Markdown, PDF, and other formats. Use
|
||||
it when you need to submit, upload, print, or email resumes in specific formats.
|
||||
- `**build**` generates resumes in HTML, Word, Markdown, PDF, and other formats.
|
||||
Use it when you need to submit, upload, print, or email resumes in specific
|
||||
formats.
|
||||
|
||||
```bash
|
||||
# hackmyresume BUILD <INPUTS> TO <OUTPUTS> [-t THEME]
|
||||
@ -58,7 +58,7 @@ it when you need to submit, upload, print, or email resumes in specific formats.
|
||||
hackmyresume BUILD r1.json r2.json TO out/rez.html out/rez.md foo/rez.all
|
||||
```
|
||||
|
||||
- `new` creates a new resume in FRESH or JSON Resume format.
|
||||
- `**new**` creates a new resume in FRESH or JSON Resume format.
|
||||
|
||||
```bash
|
||||
# hackmyresume NEW <OUTPUTS> [-f <FORMAT>]
|
||||
@ -67,8 +67,10 @@ it when you need to submit, upload, print, or email resumes in specific formats.
|
||||
hackmyresume NEW r1.json r2.json -f jrs
|
||||
```
|
||||
|
||||
- `convert` converts your source resume between FRESH and JSON Resume formats.
|
||||
Use it to convert between the two formats to take advantage of tools and services.
|
||||
- `**convert**` converts your source resume between FRESH and JSON Resume
|
||||
formats.
|
||||
Use it to convert between the two formats to take advantage of tools and
|
||||
services.
|
||||
|
||||
```bash
|
||||
# hackmyresume CONVERT <INPUTS> TO <OUTPUTS>
|
||||
@ -76,7 +78,7 @@ Use it to convert between the two formats to take advantage of tools and service
|
||||
hackmyresume CONVERT 1.json 2.json 3.json TO out/1.json out/2.json out/3.json
|
||||
```
|
||||
|
||||
- `validate` validates the specified resume against either the FRESH or JSON
|
||||
- `**validate**` validates the specified resume against either the FRESH or JSON
|
||||
Resume schema. Use it to make sure your resume data is sufficient and complete.
|
||||
|
||||
```bash
|
||||
@ -161,25 +163,34 @@ Generating YAML resume: out/resume.yml
|
||||
|
||||
### Applying a theme
|
||||
|
||||
You can specify a predefined or custom theme via the optional `-t` parameter. For a predefined theme, include the theme name. For a custom theme, include the path to the custom theme's folder.
|
||||
You can specify a predefined or custom theme via the optional `-t` parameter.
|
||||
For a predefined theme, include the theme name. For a custom theme, include the
|
||||
path to the custom theme's folder.
|
||||
|
||||
```bash
|
||||
hackmyresume build resume.json -t modern
|
||||
hackmyresume build resume.json -t ~/foo/bar/my-custom-theme/
|
||||
```
|
||||
|
||||
As of v0.9.0, available predefined themes are `modern`, `minimist`, and `hello-world`, and `compact`.
|
||||
As of v1.0.0, available predefined themes are `positive`, `modern`, `compact`,
|
||||
`minimist`, and `hello-world`.
|
||||
|
||||
### Merging resumes
|
||||
|
||||
You can **merge multiple resumes together** by specifying them in order from most generic to most specific:
|
||||
You can **merge multiple resumes together** by specifying them in order from
|
||||
most generic to most specific:
|
||||
|
||||
```bash
|
||||
# Merge specific.json onto base.json and generate all formats
|
||||
hackmyresume build base.json specific.json -o resume.all
|
||||
```
|
||||
|
||||
This can be useful for overriding a base (generic) resume with information from a specific (targeted) resume. For example, you might override your generic catch-all "software developer" resume with specific details from your targeted "game developer" resume, or combine two partial resumes into a "complete" resume. Merging follows conventional [extend()][9]-style behavior and there's no arbitrary limit to how many resumes you can merge:
|
||||
This can be useful for overriding a base (generic) resume with information from
|
||||
a specific (targeted) resume. For example, you might override your generic
|
||||
catch-all "software developer" resume with specific details from your targeted
|
||||
"game developer" resume, or combine two partial resumes into a "complete"
|
||||
resume. Merging follows conventional [extend()][9]-style behavior and there's
|
||||
no arbitrary limit to how many resumes you can merge:
|
||||
|
||||
```bash
|
||||
hackmyresume build in1.json in2.json in3.json in4.json TO out.html out.doc
|
||||
@ -210,14 +221,17 @@ hackmyresume build resume.json
|
||||
|
||||
### Using .all
|
||||
|
||||
The special `.all` extension tells HackMyResume to generate all supported output formats for the given resume. For example, this...
|
||||
The special `.all` extension tells HackMyResume to generate all supported output
|
||||
formats for the given resume. For example, this...
|
||||
|
||||
```bash
|
||||
# Generate all resume formats (HTML, PDF, DOC, TXT, etc.)
|
||||
hackmyresume build me.json -o out/resume.all
|
||||
```
|
||||
|
||||
..tells HackMyResume to read `me.json` and generate `out/resume.md`, `out/resume.doc`, `out/resume.html`, `out/resume.txt`, `out/resume.pdf`, and `out/resume.json`.
|
||||
..tells HackMyResume to read `me.json` and generate `out/resume.md`,
|
||||
`out/resume.doc`, `out/resume.html`, `out/resume.txt`, `out/resume.pdf`, and
|
||||
`out/resume.json`.
|
||||
|
||||
### Validating
|
||||
|
||||
@ -240,17 +254,17 @@ Validating JSON resume: resumeB.json (VALID)
|
||||
|
||||
### Converting
|
||||
|
||||
HackMyResume can convert between the [FRESH][fresca] and [JSON Resume][6] formats.
|
||||
Just run:
|
||||
HackMyResume can convert between the [FRESH][fresca] and [JSON Resume][6]
|
||||
formats. Just run:
|
||||
|
||||
```bash
|
||||
hackmyresume CONVERT <INPUTS> <OUTPUTS>
|
||||
```
|
||||
|
||||
where <INPUTS> is one or more resumes in FRESH or JSON Resume format, and
|
||||
<OUTPUTS> is a corresponding list of output file names. HackMyResume will autodetect
|
||||
the format (FRESH or JRS) of each input resume and convert it to the other
|
||||
format (JRS or FRESH).
|
||||
<OUTPUTS> is a corresponding list of output file names. HackMyResume will
|
||||
autodetect the format (FRESH or JRS) of each input resume and convert it to the
|
||||
other format (JRS or FRESH).
|
||||
|
||||
### Prettifying
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hackmyresume",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"description": "Generate polished résumés and CVs in HTML, Markdown, LaTeX, MS Word, PDF, plain text, JSON, XML, YAML, smoke signal, and carrier pigeon.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -18,7 +18,11 @@
|
||||
"PDF",
|
||||
"YAML",
|
||||
"HTML",
|
||||
"CLI"
|
||||
"LaTeX",
|
||||
"CLI",
|
||||
"Handlebars",
|
||||
"Underscore",
|
||||
"template"
|
||||
],
|
||||
"author": "hacksalot <hacksalot@fluentdesk.com> (https://github.com/hacksalot)",
|
||||
"license": "MIT",
|
||||
|
169
src/eng/generic-helpers.js
Normal file
169
src/eng/generic-helpers.js
Normal file
@ -0,0 +1,169 @@
|
||||
/**
|
||||
Generic template helper definitions for FluentCV.
|
||||
@license MIT. Copyright (c) 2015 James Devlin / FluentDesk.
|
||||
@module generic-helpers.js
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
|
||||
var MD = require('marked')
|
||||
, H2W = require('../utils/html-to-wpml')
|
||||
, moment = require('moment')
|
||||
, _ = require('underscore');
|
||||
|
||||
/**
|
||||
Generic template helper function definitions.
|
||||
@class GenericHelpers
|
||||
*/
|
||||
var GenericHelpers = module.exports = {
|
||||
|
||||
/**
|
||||
Convert the input date to a specified format through Moment.js.
|
||||
@method formatDate
|
||||
*/
|
||||
formatDate: function(datetime, format) {
|
||||
return moment ? moment( datetime ).format( format ) : datetime;
|
||||
},
|
||||
|
||||
/**
|
||||
Convert inline Markdown to inline WordProcessingML.
|
||||
@method wpml
|
||||
*/
|
||||
wpml: function( txt, inline ) {
|
||||
if(!txt) return '';
|
||||
inline = (inline && !inline.hash) || false;
|
||||
txt = inline ?
|
||||
MD(txt.trim()).replace(/^\s*<p>|<\/p>\s*$/gi, '') :
|
||||
MD(txt.trim());
|
||||
txt = H2W( txt.trim() );
|
||||
return txt;
|
||||
},
|
||||
|
||||
/**
|
||||
Emit a conditional link.
|
||||
@method link
|
||||
*/
|
||||
link: function( text, url ) {
|
||||
return url && url.trim() ?
|
||||
('<a href="' + url + '">' + text + '</a>') : text;
|
||||
},
|
||||
|
||||
/**
|
||||
Return the last word of the specified text.
|
||||
@method lastWord
|
||||
*/
|
||||
lastWord: function( txt ) {
|
||||
return txt && txt.trim() ? _.last( txt.split(' ') ) : '';
|
||||
},
|
||||
|
||||
/**
|
||||
Convert a skill level to an RGB color triplet.
|
||||
@method skillColor
|
||||
@param lvl Input skill level. Skill level can be expressed as a string
|
||||
("beginner", "intermediate", etc.), as an integer (1,5,etc), as a string
|
||||
integer ("1", "5", etc.), or as an RRGGBB color triplet ('#C00000',
|
||||
'#FFFFAA').
|
||||
*/
|
||||
skillColor: function( lvl ) {
|
||||
var idx = skillLevelToIndex( lvl );
|
||||
var skillColors = (this.theme && this.theme.palette &&
|
||||
this.theme.palette.skillLevels) ||
|
||||
[ '#FFFFFF', '#5CB85C', '#F1C40F', '#428BCA', '#C00000' ];
|
||||
return skillColors[idx];
|
||||
},
|
||||
|
||||
/**
|
||||
Return an appropriate height.
|
||||
@method lastWord
|
||||
*/
|
||||
skillHeight: function( lvl ) {
|
||||
var idx = skillLevelToIndex( lvl );
|
||||
return ['38.25', '30', '16', '8', '0'][idx];
|
||||
},
|
||||
|
||||
/**
|
||||
Return all but the last word of the input text.
|
||||
@method initialWords
|
||||
*/
|
||||
initialWords: function( txt ) {
|
||||
return txt && txt.trim() ? _.initial( txt.split(' ') ).join(' ') : '';
|
||||
},
|
||||
|
||||
/**
|
||||
Trim the protocol (http or https) from a URL/
|
||||
@method trimURL
|
||||
*/
|
||||
trimURL: function( url ) {
|
||||
return url && url.trim() ? url.trim().replace(/^https?:\/\//i, '') : '';
|
||||
},
|
||||
|
||||
/**
|
||||
Convert text to lowercase.
|
||||
@method toLower
|
||||
*/
|
||||
toLower: function( txt ) {
|
||||
return txt && txt.trim() ? txt.toLowerCase() : '';
|
||||
},
|
||||
|
||||
/**
|
||||
Return true if either value is truthy.
|
||||
@method either
|
||||
*/
|
||||
either: function( lhs, rhs, options ) {
|
||||
if (lhs || rhs) return options.fn(this);
|
||||
},
|
||||
|
||||
/**
|
||||
Perform a generic comparison.
|
||||
See: http://doginthehat.com.au/2012/02/comparison-block-helper-for-handlebars-templates
|
||||
@method compare
|
||||
*/
|
||||
compare: function(lvalue, rvalue, options) {
|
||||
if (arguments.length < 3)
|
||||
throw new Error("Handlerbars Helper 'compare' needs 2 parameters");
|
||||
var operator = options.hash.operator || "==";
|
||||
var operators = {
|
||||
'==': function(l,r) { return l == r; },
|
||||
'===': function(l,r) { return l === r; },
|
||||
'!=': function(l,r) { return l != r; },
|
||||
'<': function(l,r) { return l < r; },
|
||||
'>': function(l,r) { return l > r; },
|
||||
'<=': function(l,r) { return l <= r; },
|
||||
'>=': function(l,r) { return l >= r; },
|
||||
'typeof': function(l,r) { return typeof l == r; }
|
||||
};
|
||||
if (!operators[operator])
|
||||
throw new Error("Handlerbars Helper 'compare' doesn't know the operator "+operator);
|
||||
var result = operators[operator](lvalue,rvalue);
|
||||
return result ? options.fn(this) : options.inverse(this);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function skillLevelToIndex( lvl ) {
|
||||
var idx = 0;
|
||||
if( String.is( lvl ) ) {
|
||||
lvl = lvl.trim().toLowerCase();
|
||||
var intVal = parseInt( lvl );
|
||||
if( isNaN( intVal ) ) {
|
||||
switch( lvl ) {
|
||||
case 'beginner': idx = 1; break;
|
||||
case 'intermediate': idx = 2; break;
|
||||
case 'advanced': idx = 3; break;
|
||||
case 'master': idx = 4; break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
idx = Math.min( intVal / 2, 4 );
|
||||
idx = Math.max( 0, idx );
|
||||
}
|
||||
}
|
||||
else {
|
||||
idx = Math.min( lvl / 2, 4 );
|
||||
idx = Math.max( 0, intVal );
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
}());
|
@ -31,7 +31,7 @@ Definition of the HandlebarsGenerator class.
|
||||
});
|
||||
|
||||
// Register necessary helpers.
|
||||
registerHelpers();
|
||||
registerHelpers( theme );
|
||||
|
||||
// Compile and run the Handlebars template.
|
||||
var template = HANDLEBARS.compile(jst);
|
||||
|
@ -8,116 +8,17 @@ Template helper definitions for Handlebars.
|
||||
(function() {
|
||||
|
||||
var HANDLEBARS = require('handlebars')
|
||||
, MD = require('marked')
|
||||
, H2W = require('../utils/html-to-wpml')
|
||||
, moment = require('moment')
|
||||
, _ = require('underscore');
|
||||
, _ = require('underscore')
|
||||
, helpers = require('./generic-helpers');
|
||||
|
||||
/**
|
||||
Register useful Handlebars helpers.
|
||||
@method registerHelpers
|
||||
*/
|
||||
module.exports = function() {
|
||||
module.exports = function( theme ) {
|
||||
|
||||
// Set up a date formatting helper so we can do:
|
||||
// {{formatDate val 'YYYY-MM'}}
|
||||
HANDLEBARS.registerHelper("formatDate", function(datetime, format) {
|
||||
return moment ? moment( datetime ).format( format ) : datetime;
|
||||
});
|
||||
|
||||
// Set up a Markdown-to-WordProcessingML helper so we can do:
|
||||
// {{wmpl val [true|false]}}
|
||||
HANDLEBARS.registerHelper("wpml", function( txt, inline ) {
|
||||
if(!txt) return '';
|
||||
inline = (inline && !inline.hash) || false;
|
||||
txt = inline ?
|
||||
MD(txt.trim()).replace(/^\s*<p>|<\/p>\s*$/gi, '') :
|
||||
MD(txt.trim());
|
||||
txt = H2W( txt.trim() );
|
||||
return txt;
|
||||
});
|
||||
|
||||
// Set up a last-word helper so we can do:
|
||||
// {{lastWord val [true|false]}}
|
||||
HANDLEBARS.registerHelper("link", function( text, url ) {
|
||||
return url && url.trim() ?
|
||||
('<a href="' + url + '">' + text + '</a>') : text;
|
||||
});
|
||||
|
||||
// Set up a last-word helper so we can do:
|
||||
// {{lastWord val [true|false]}}
|
||||
HANDLEBARS.registerHelper("lastWord", function( txt ) {
|
||||
return txt && txt.trim() ? _.last( txt.split(' ') ) : '';
|
||||
});
|
||||
|
||||
// Set up a skill colorizing helper:
|
||||
// {{skillColor val}}
|
||||
HANDLEBARS.registerHelper("skillColor", function( lvl ) {
|
||||
switch(lvl) {
|
||||
case 'beginner': return '#5CB85C';
|
||||
case 'intermediate': return '#F1C40F';
|
||||
case 'advanced': return '#428BCA';
|
||||
case 'master': return '#C00000';
|
||||
}
|
||||
});
|
||||
|
||||
// Set up a skill colorizing helper:
|
||||
// {{skillColor val}}
|
||||
HANDLEBARS.registerHelper("skillHeight", function( lvl ) {
|
||||
switch(lvl) {
|
||||
case 'beginner': return '30';
|
||||
case 'intermediate': return '16';
|
||||
case 'advanced': return '8';
|
||||
case 'master': return '0';
|
||||
}
|
||||
});
|
||||
|
||||
// Set up a Markdown-to-WordProcessingML helper so we can do:
|
||||
// {{initialWords val [true|false]}}
|
||||
HANDLEBARS.registerHelper("initialWords", function( txt ) {
|
||||
return txt && txt.trim() ? _.initial( txt.split(' ') ).join(' ') : '';
|
||||
});
|
||||
|
||||
// Set up a URL-trimming helper to drop the protocol so we can do:
|
||||
// {{trimURL url}}
|
||||
HANDLEBARS.registerHelper("trimURL", function( url ) {
|
||||
return url && url.trim() ? url.trim().replace(/^https?:\/\//i, '') : '';
|
||||
});
|
||||
|
||||
// Set up a URL-trimming helper to drop the protocol so we can do:
|
||||
// {{trimURL url}}
|
||||
HANDLEBARS.registerHelper("toLower", function( txt ) {
|
||||
return txt && txt.trim() ? txt.toLowerCase() : '';
|
||||
});
|
||||
|
||||
// Set up a Markdown-to-WordProcessingML helper so we can do:
|
||||
// {{either A B}}
|
||||
HANDLEBARS.registerHelper("either", function( lhs, rhs, options ) {
|
||||
if (lhs || rhs) return options.fn(this);
|
||||
});
|
||||
|
||||
// Set up a generic conditional helper so we can do:
|
||||
// {{compare val otherVal operator="<"}}
|
||||
// http://doginthehat.com.au/2012/02/comparison-block-helper-for-handlebars-templates/
|
||||
HANDLEBARS.registerHelper('compare', function(lvalue, rvalue, options) {
|
||||
if (arguments.length < 3)
|
||||
throw new Error("Handlerbars Helper 'compare' needs 2 parameters");
|
||||
var operator = options.hash.operator || "==";
|
||||
var operators = {
|
||||
'==': function(l,r) { return l == r; },
|
||||
'===': function(l,r) { return l === r; },
|
||||
'!=': function(l,r) { return l != r; },
|
||||
'<': function(l,r) { return l < r; },
|
||||
'>': function(l,r) { return l > r; },
|
||||
'<=': function(l,r) { return l <= r; },
|
||||
'>=': function(l,r) { return l >= r; },
|
||||
'typeof': function(l,r) { return typeof l == r; }
|
||||
};
|
||||
if (!operators[operator])
|
||||
throw new Error("Handlerbars Helper 'compare' doesn't know the operator "+operator);
|
||||
var result = operators[operator](lvalue,rvalue);
|
||||
return result ? options.fn(this) : options.inverse(this);
|
||||
});
|
||||
helpers.theme = theme;
|
||||
HANDLEBARS.registerHelper( helpers );
|
||||
|
||||
};
|
||||
|
||||
|
@ -47,7 +47,6 @@ function main() {
|
||||
opts = getOpts( a );
|
||||
logMsg( title );
|
||||
|
||||
|
||||
// Get the action to be performed
|
||||
var params = a._.map( function(p){ return p.toLowerCase().trim(); });
|
||||
var verb = params[0];
|
||||
@ -56,7 +55,7 @@ function main() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get source and dest params
|
||||
// Find the TO keyword, if any
|
||||
var splitAt = _.indexOf( params, 'to' );
|
||||
if( splitAt === a._.length - 1 ) {
|
||||
// 'TO' cannot be the last argument
|
||||
@ -66,8 +65,10 @@ function main() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Massage inputs and outputs
|
||||
var src = a._.slice(1, splitAt === -1 ? undefined : splitAt );
|
||||
var dst = splitAt === -1 ? [] : a._.slice( splitAt + 1 );
|
||||
( splitAt === -1 ) && dst.push( src.pop() ); // Allow omitting TO keyword
|
||||
var parms = [ src, dst, opts, logMsg ];
|
||||
|
||||
// Invoke the action
|
||||
|
@ -11,49 +11,49 @@ Definition of the Markdown to WordProcessingML conversion routine.
|
||||
|
||||
module.exports = function( html ) {
|
||||
|
||||
var final = '';
|
||||
var is_bold = false, is_italic = false, is_link = false;
|
||||
var depth = 0;
|
||||
|
||||
// Tokenize the HTML stream.
|
||||
var tokens = HTML5Tokenizer.tokenize( html );
|
||||
|
||||
var final = '', is_bold, is_italic, is_link, link_url;
|
||||
|
||||
// Process <em>, <strong>, and <a> elements in the HTML stream, producing
|
||||
// equivalent WordProcessingML that can be dumped into a <w:p> or other
|
||||
// text container element.
|
||||
_.each( tokens, function( tok ) {
|
||||
|
||||
switch( tok.type ) {
|
||||
|
||||
case 'StartTag':
|
||||
switch( tok.tagName ) {
|
||||
case 'p':
|
||||
final += '<w:p>';
|
||||
break;
|
||||
case 'strong':
|
||||
is_bold = true;
|
||||
break;
|
||||
case 'em':
|
||||
is_italic = true;
|
||||
break;
|
||||
case 'p': final += '<w:p>'; break;
|
||||
case 'strong': is_bold = true; break;
|
||||
case 'em': is_italic = true; break;
|
||||
case 'a':
|
||||
is_link = true;
|
||||
link_url = tok.attributes.filter(function(attr){
|
||||
return attr[0] === 'href'; }
|
||||
)[0][1];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'EndTag':
|
||||
switch( tok.tagName ) {
|
||||
case 'p':
|
||||
final += '</w:p>';
|
||||
break;
|
||||
case 'strong':
|
||||
is_bold = false;
|
||||
break;
|
||||
case 'em':
|
||||
is_italic = false;
|
||||
break;
|
||||
case 'a':
|
||||
is_link = false;
|
||||
break;
|
||||
case 'p': final += '</w:p>'; break;
|
||||
case 'strong': is_bold = false; break;
|
||||
case 'em': is_italic = false; break;
|
||||
case 'a': is_link = false; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Chars':
|
||||
var style = is_bold ? '<w:b/>' : '';
|
||||
style += is_italic ? '<w:i/>': '';
|
||||
final += '<w:r><w:rPr>' + style + '</w:rPr><w:t>' + tok.chars + '</w:t></w:r>';
|
||||
style += is_link ? '<w:rStyle w:val="Hyperlink"/>' : '';
|
||||
final +=
|
||||
(is_link ? ('<w:hlink w:dest="' + link_url + '">') : '') +
|
||||
'<w:r><w:rPr>' + style + '</w:rPr><w:t>' + tok.chars +
|
||||
'</w:t></w:r>' + (is_link ? '</w:hlink>' : '');
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
@ -17,3 +17,7 @@ String.isNullOrWhitespace = function( input ) {
|
||||
String.prototype.endsWith = function(suffix) {
|
||||
return this.indexOf(suffix, this.length - suffix.length) !== -1;
|
||||
};
|
||||
|
||||
String.is = function( val ) {
|
||||
return typeof val === 'string' || val instanceof String;
|
||||
};
|
||||
|
Reference in New Issue
Block a user