Skip to content

Instantly share code, notes, and snippets.

@balupton
Created June 29, 2012 06:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save balupton/3016370 to your computer and use it in GitHub Desktop.
Save balupton/3016370 to your computer and use it in GitHub Desktop.
DocPad Text Plugin: Different HTML Implementations
# Export Plugin
module.exports = (BasePlugin) ->
# Define Plugin
class TextPlugin extends BasePlugin
# Plugin name
name: 'text'
# Get the text
getText: (opts) ->
# Prepare
{source,store} = opts
key = source or ''
key = 'store.'+key.replace(/[#\{\(\n]/g,'').trim()
# Fetch the value
try
result = eval(key) ? source
catch err
result = source
# Return
result
# Populate text
populateText: (opts,next) ->
# Prepare
{source,store,file} = opts
me = @
docpad = @docpad
cheerio = @cheerio or require('cheerio')
balUtil = @balUtil or require('bal-util')
# Render plugins
# next(err)
renderPlugins = (eventData,next) =>
# Render through plugins
file.trigger eventData.name, eventData, (err) ->
# Error?
if err
docpad.log 'warn', "Something went wrong while rendering: #{fullPath}"
return next(err)
# Forward
return next()
# DOMify our source
$ = cheerio.load(source)
$textElements = $('t,text')
# Prepare the parent tasks
parentTasks = new balUtil.Group (err) ->
console.log('done-1', parentTasks.total, source.split('\n')[0])
return next(err) if err
result = $.html()
return next(null,result)
console.log('start1', parentTasks.total, source.split('\n')[0])
# Render the elements
$textElements.each -> parentTasks.push @, (complete) ->
# Grab the value
$textElement = $(this)
key = $textElement.html()
value = me.getText({source:key,store})
console.log('start2', parentTasks.total, value.split('\n')[0])
# Prepare child tasks
childTasks = new balUtil.Group (err) ->
# Forward
console.log('done-2', parentTasks.total, value.split('\n')[0])
return complete(err)
# Facilate deep elements
if value isnt key
childTasks.push (complete) ->
# Populate the valuecd te
me.populateText {file,store,source:value}, (err,result) ->
return complete(err) if err
value = result
return complete()
# If we have a type attribute, render the value as well
extensions = $textElement.attr('type') or $textElement.attr('render') or ''
if extensions
# Fetch extensions and reverse them
extensions = extensions.split('.')
extensions.unshift(null) if extensions.length is 1
extensionsReversed = []
for extension in extensions
extensionsReversed.unshift(extension)
# Render it
for extension,index in extensionsReversed[1..]
# Render through the plugins
context =
inExtension: extensionsReversed[index]
outExtension: extension
console.log('CONTEXT:',context)
childTasks.push context, (complete) ->
# Prepare
eventData =
name: 'render'
inExtension: @inExtension
outExtension: @outExtension
templateData: store
file: file
content: value
# Render
blah = @
console.log('=========\n',"RENDER #{blah.inExtension}:\n",value,'\n========')
renderPlugins eventData, (err) ->
return complete(err) if err
console.log('=========\n',"RENDERED #{blah.inExtension}:\m",eventData.content,'\n--------\n',value,'\n========')
value = eventData.content
return complete()
# Replace the text element
childTasks.push ->
$textElement.replaceWith($('<div>').text(value))
childTasks.exit()
# Run child tasks
childTasks.sync()
# Run parent tasks
parentTasks.sync()
# Chain
@
# Render the document
renderDocument: (opts,next) ->
# Prepare
me = @
{templateData,file} = opts
# Only run on text content
if file.isText()
# Populate the file content
me.populateText {file,store:templateData,source:opts.content}, (err,result) ->
return next(err) if err
opts.content = result
return next()
else
return next()
# Export Plugin
module.exports = (BasePlugin) ->
# Define Plugin
class TextPlugin extends BasePlugin
# Plugin name
name: 'text'
# Get the text
getText: (opts) ->
# Prepare
{source,store} = opts
key = source or ''
key = 'store.'+key.replace(/[#\{\(\n]/g,'').trim()
# Fetch the value
try
result = eval(key) ? source
catch err
result = source
# Return
result
# Populate text
populateText: (opts,next) ->
# Prepare
{source,store,file} = opts
me = @
docpad = @docpad
jsdom = @jsdom or require('jsdom')
balUtil = @balUtil or require('bal-util')
# Render plugins
# next(err)
renderPlugins = (eventData,next) =>
# Render through plugins
file.trigger eventData.name, eventData, (err) ->
# Error?
if err
docpad.log 'warn', "Something went wrong while rendering: #{fullPath}"
return next(err)
# Forward
return next()
# Create DOM from the file content
jsdom.env(
html: "<html><body>#{source}</body></html>"
features:
QuerySelector: true
done: (err,window) ->
# Fetch elements
textElements = window.document.querySelectorAll('t,text')
# Prepare the parent tasks
parentTasks = new balUtil.Group (err) ->
console.log('done-1', parentTasks.total, source.split('\n')[0])
return next(err) if err
result = window.document.body.innerHTML or source
return next(null,result)
console.log('start1', parentTasks.total, source.split('\n')[0])
# Render the elements
textElements.forEach (textElement) -> parentTasks.push (complete) ->
# Grab the value
key = textElement.innerHTML
console.log('==========\n',key,'\n=========')
value = me.getText({source:key,store})
console.log('start2', parentTasks.total, value.split('\n')[0])
# Prepare child tasks
childTasks = new balUtil.Group (err) ->
# Forward
console.log('done-2', parentTasks.total, value.split('\n')[0])
return complete(err)
# Facilate deep elements
if value isnt key
childTasks.push (complete) ->
# Populate the valuecd te
me.populateText {file,store,source:value}, (err,result) ->
return complete(err) if err
value = result
return complete()
# If we have a type attribute, render the value as well
extensions = textElement.getAttribute('type') or textElement.getAttribute('render') or ''
if extensions
# Fetch extensions and reverse them
extensions = extensions.split('.')
extensions.unshift(null) if extensions.length is 1
extensionsReversed = []
for extension in extensions
extensionsReversed.unshift(extension)
# Render it
for extension,index in extensionsReversed[1..]
# Render through the plugins
context =
inExtension: extensionsReversed[index]
outExtension: extension
console.log('CONTEXT:',context)
childTasks.push context, (complete) ->
# Prepare
eventData =
name: 'render'
inExtension: @inExtension
outExtension: @outExtension
templateData: store
file: file
content: value
# Render
blah = @
console.log('=========\n',"RENDER #{blah.inExtension}:\n",value,'\n========')
renderPlugins eventData, (err) ->
return complete(err) if err
console.log('=========\n',"RENDERED #{blah.inExtension}:\m",eventData.content,'\n--------\n',value,'\n========')
value = eventData.content
return complete()
# Replace the text element
childTasks.push ->
try
resultElWrapper = window.document.createElement('span')
resultElWrapper.innerHTML = value
resultElInner = resultElWrapper.childNodes[0]
textElement.parentNode.replaceChild(resultElInner,textElement)
catch err
# don't care
childTasks.exit()
# Run child tasks
childTasks.sync()
# Run parent tasks
parentTasks.sync()
)
# Chain
@
# Render the document
renderDocument: (opts,next) ->
# Prepare
me = @
{templateData,file} = opts
# Only run on text content
if file.isText()
# Populate the file content
me.populateText {file,store:templateData,source:opts.content}, (err,result) ->
return next(err) if err
opts.content = result
return next()
else
return next()
# Export Plugin
module.exports = (BasePlugin) ->
# Define Plugin
class TextPlugin extends BasePlugin
# Plugin name
name: 'text'
# Get the text
getText: (opts) ->
# Prepare
{source,store} = opts
key = source or ''
key = 'store.'+key.replace(/[#\{\(\n]/g,'').trim()
# Fetch the value
try
result = eval(key) ? source
catch err
result = source
# Return
result
# Extract Argument
getAttribute: (attributes,attribute) ->
regex = new RegExp("""(#{attribute})\\s*=\\s*('[^']+'|\\"[^\\"]+\\"|[^'\\"\\s]\\S*)""",'ig')
value = null
while match = regex.exec(attributes)
value = match[2].trim().replace(/(^['"]\s*|\s*['"]$)/g, '')
return value
# Populate text
populateText: (opts,next) ->
# Prepare
{source,store,file} = opts
me = @
docpad = @docpad
balUtil = @balUtil or require('bal-util')
# Render plugins
# next(err)
renderPlugins = (eventData,next) =>
# Render through plugins
file.trigger eventData.name, eventData, (err) ->
# Error?
if err
docpad.log 'warn', "Something went wrong while rendering: #{fullPath}"
return next(err)
# Forward
return next()
# Prepare the parent tasks
parentTasks = new balUtil.Group (err) ->
return next(err) if err
return next(null,result)
# Render the elements
result = source.replace /\<(t(?:ext)?(?:\:[a-z0-9\:\-\_]+)?)([^\>]*)\>([\s\S]+?)\<\/\1\>/gi, (str, tagName, attributes, key) ->
# Generate a temporary random number to replace the text with in the meantime
random = Math.random()
# Push the render task
parentTasks.push (complete) ->
# Grab the value
value = me.getText({source:key,store})
# Prepare child tasks
childTasks = new balUtil.Group (err) ->
return complete(err) if err
#console.log({random,key,value})
result = result.replace(random,value)
return complete(err)
# Facilate deep elements
childTasks.push (complete) ->
# Populate the valuecd te
me.populateText {file,store,source:value}, (err,result) ->
return complete(err) if err
value = result
return complete()
# If we have a type attribute, render the value as well
extensions = me.getAttribute(attributes,'type') or me.getAttribute(attributes,'render') or ''
if extensions
# Fetch extensions and reverse them
extensions = extensions.split('.')
extensions.unshift(null) if extensions.length is 1
extensionsReversed = []
for extension in extensions
extensionsReversed.unshift(extension)
# Render it
for extension,index in extensionsReversed[1..]
# Render through the plugins
context =
inExtension: extensionsReversed[index]
outExtension: extension
childTasks.push context, (complete) ->
# Prepare
eventData =
name: 'render'
inExtension: @inExtension
outExtension: @outExtension
templateData: store
file: file
content: value
# Render
blah = @
renderPlugins eventData, (err) ->
return complete(err) if err
value = eventData.content
return complete()
# Replace the text element
childTasks.push -> childTasks.exit()
# Run child tasks
childTasks.sync()
# Return the random number to the replace
random
# Run parent tasks
parentTasks.sync()
# Chain
@
# Render the document
renderDocument: (opts,next) ->
# Prepare
me = @
{templateData,file} = opts
# Only run on text content
if file.isText()
# Populate the file content
me.populateText {file,store:templateData,source:opts.content}, (err,result) ->
return next(err) if err
opts.content = result
return next()
else
return next()
# Export Plugin
module.exports = (BasePlugin) ->
# Define Plugin
class TextPlugin extends BasePlugin
# Plugin name
name: 'text'
# Get the text
getText: (source,store) ->
# Prepare fetch
key = 'store.'+source.replace(/[#\{\(\n]/g,'').trim()
# Fetch the value
try
result = eval(key)
catch err
result = source
# Return
result
# Populate text
populateText: (source,store) ->
# Prepare
me = @
# Replace our text elements
result = source.replace /\<t(ext)?\>([^\<]+)\<\/t(ext)?\>/g, (str, group1, key, group3) ->
value = me.getText(key,store)
if value isnt key
# facilate deep elements
value = me.populateText(value,store)
return value
# Return
return result
# Render the document
renderDocument: (opts,next) ->
# Prepare
me = @
{templateData,file} = opts
# Only run on text content
if file.isText()
# Populate the text element
opts.content = me.populateText(opts.content,templateData)
# Done
return next()
else
return next()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment