Nothing
nullFun = function(...) TRUE
setClassUnion("characterOrNULL", c("character","NULL"))
setOldClass("ggplot")
#I'm envisioning each ReportHandlers set representing a distinct target (eg internal DOM, write to pipe, etc)
#Currently args expects a named list of named lists, up to one for each function, eg list(finish = list(file = "myfile.html"))
#we might want to make this an S4 class later?
setClass("ReportHandlers",
representation = list(init = "function",
addElement = "function",
removeElement = "function",
finish = "function",
location = "ANY",
args = "ANY"),
prototype = list(init = nullFun,
addElement = nullFun,
removeElement = nullFun,
finish= nullFun,
location = NULL,
args = NULL)
)
baseReport <- setRefClass("BaseReportRef",
fields = list(
.shortName = "character",
shortName = function(val)
{
if(missing(val))
.shortName
else
.self$.shortName <- val
},
.title = "character",
title = function(val)
{
if(missing(val))
.title
else
{
.self$.title <- val
#if we have an HTML document, change/add the title node
if(is(.reportDOM, "XMLInternalDocument"))
{
tnode = getNodeSet(.reportDOM, "/html/head/title")
if(length(tnode))
xmlValue(tnode[[1]]) = val
else
{
head = getNodeSet(.reportDOM, "/html/head")[[1]]
addChildren(head, newXMLNode("title", val))}
}
.title
}
},
.reportDirectory = "character",
reportDirectory = function(val)
{
if(missing(val))
.reportDirectory
else
#.self$.reportDirectory <- val
.reportDirectory <<- val
},
.report = "list",
.reportDOM = "ANY",
.basePath = "characterOrNULL",
basePath = function(val)
{
if(missing(val))
.basePath
else
.self$.basePath <- val
},
.handlers = "list",
handlers = function(val)
{
if(missing(val))
.handlers
else
{
#stop("The addHandlers/removeHandlers methods must be used to manipulate event handlers.")
if(!is.list(val))
val = list(val)
.self$.handlers <- val
}
}),
methods = list(
addHandlers = function(handlers, init = nullFun, addElement = nullFun,
removeElement = nullFun, finalize = nullFun)
{
if(missing(handlers) | is.null(handlers))
handlers2 = new("ReportHandlers", init = init, addElement = addElement,
removeElement = removeElement, finalize = finalize)
else
handlers2 = handlers
.self$.handlers <- c(.handlers, handlers2)
},
removeHandlers = function(pos = 1)
{
if (!(pos %in% seq(along = .handlers)))
stop(sprintf("There is no set of handlers at position %d to remove.", pos))
.self$.handlers <- .handlers[-pos]
}
)
)
htmlReport <- setRefClass("HTMLReportRef", contains = "BaseReportRef",
fields = list(
.toHTML = "list",
.toDF = "list",
.modifyDF = "list"),
methods = list(
prepare = function(obj,.toHTML = NULL, .toDF = NULL, .modifyDF = NULL, ... )
{
#if the user has overridden the html conversion for this class, we use that
#we grab the first class if there are more than one (ie with XMLInternalNode)
klass = class(obj)[1]
f = if(missing(.toHTML) || is.null(.toHTML)) .self$.toHTML[[klass]] else .toHTML
if(is.function(f))
{
ret = f(obj, ...)
}
else
{
if(missing(.toDF) || is.null(.toDF))
.toDF2 = .self$.toDF[[klass]]
else
.toDF2 = .toDF
if(missing(.modifyDF) || is.null(.modifyDF))
.modifyDF2 = .self$.modifyDF[[klass]]
else
.modifyDF2 = .modifyDF
html = objectToHTML(obj, .self, ..., .toDF=.toDF2, .modifyDF = .modifyDF2 )
#prepping for conversion from text HTML nubuilding to XML construction Once the
#conversion is complete objectToHTML methods will be returning XMLInternalNode
#objects
#this is a bit hacky but oh well!! We may be getting a list with elements "html"
#and "object"
if(is(html, "XMLNodeSet"))
{
htmlcode <- html
} else if(is.list(html))
{
htmlcode = html$html
obj = html$object
}
else
{
htmlcode = html
obj = NULL
}
if(is.character(htmlcode))
{
htmlcode = htmlParse(htmlcode)
ret = getNodeSet(htmlcode, "//body/*")
} else {
ret = htmlcode
}
}
list(html = ret, object = obj)
},
finish = function()
{
sapply(.handlers, function(fs) fs@finish(.self, fs@args$finish))
# do we want to force a saveXML call here, or just assign one as a finalize
# event handler by default? For now we make people assign a handler,
# because sometimes we only want to send the content down a connection and
# not write a file.
},
addElement = function(name, value, .toHTML = NULL, .toDF = NULL,
.modifyDF = NULL, pos = NA, ... )
{
if(missing(name))
name = paste("id", length(getNodeSet(.self$.reportDOM,"//body/div")) + 1, sep="")
if(is.character(name))
nodes = getNodeSet(.self$.reportDOM, sprintf("//div[@id='%s']", name))
else if (is.numeric(name))
stop("positional insertion is not yet supported")
if(length(nodes))
{
if(!is.na(pos))
stop("Attempt to specify a position (pos) when replacing an existing element")
node = nodes[[1]]
#remove whatever was assigned to this name previously
removeChildren(node, kids = xmlChildren(node))
} else {
#create new div with the specified id and add it to the body of the HTML page
node = newXMLNode("div", attrs= list(id=name, class = "ReportingTools container"))
if(is.na(pos))
{
#No position means it gets added to the end of the document
body = getNodeSet(.self$.reportDOM, "//body")[[1]]
addChildren(body, node)
} else {
#If we are given a position n, find the nth report element in the current report and insert our new element directly ahead of it.
addSibling(.self$.report[[pos]], after=FALSE, node)
}
}
#turn value into html nodes to add to DOM
newcontent = .self$prepare(value, .toHTML = .toHTML, .toDF = .toDF,
.modifyDF = .modifyDF,... )
obj = newcontent$object
newcontent=newcontent$html
if(is.list(newcontent))
addChildren(node, kids = newcontent)
else
addChildren(node, newcontent)
# call all currently assigned addElement handlers with the node for the div
# containing the new content
sapply(.self$.handlers, function(fs, node, name)
fs@addElement(node, name, fs@args$addElement), node= node, name=name)
if(is.na(pos))
.self$.report[[name]] = node
else
{
#insert our new element in the right place and shift everything else around.
oldlist = .self$.report
oldnames = names(oldlist)
before = which(seq(along=oldlist) < pos)
after = which(seq(along=oldlist) >= pos)
newlist = vector("list", length(oldlist) + 1)
newlist[before] = oldlist[before]
newlist[[pos]] = node
newlist[after + 1] = oldlist[after]
names(newlist ) = c(oldnames[before], name, oldnames[after])
.self$.report = newlist
}
invisible(obj)
},
initialize = function(...)
{
args = list(...)
handlers2 = args$handlers
if(is.null(handlers))
handlers2 = list(toFileHandlers)
#if we only have one set of handler sometimes it won't come in the form of a list
if(!is.list(handlers2))
handlers2 = list(handlers2)
dom = startHTMLReport(...)
.self$.reportDOM = dom
sapply(handlers2, function(h) h@init(dom, h@args$init))
.self$initFields(shortName = args$shortName, title = args$title,
reportDirectory = args$reportDirectory, handlers = handlers2,
basePath = args$basePath)
}
)
)
HTMLReport <- function(shortName = "coolProject",
title = shortName,
reportDirectory = ".",
basePath = NULL,
handlers = list(fileHandlers(makeReportPath(basePath, reportDirectory, shortName))),
.toHTML = list(),
.toDF = list(),
.modifyDF= list(),
link.css = NULL,
link.javascript=NULL,
overwrite.js = TRUE,
...
)
{
shortName <- sub(".html$", "", shortName)
if(is.null(title))
title <- shortName
if(substr(reportDirectory,1,1) == "~"){
reportDirectory <- path.expand(reportDirectory)
}
if(!is.list(handlers))
handlers = list(handlers)
allargs = list(shortName = shortName, basePath = basePath, reportDirectory = reportDirectory, ...)
handlers = lapply(handlers, function(hnd)
{
if(is(hnd, "ReportHandlers"))
hnd
else if (is(hnd, "function"))
do.call(hnd, allargs)
else
stop("handlers must be a list containing only ReportHandler objects and/or functions which return such objects.")
})
if(substr(reportDirectory, 1, 1) == "/")
stop("Non-NULL baseDirectory in combination with absolute reportDirectory is not supported.")
if(sum(grepl("[A-Za-z]:", reportDirectory)) > 0 & .Platform$OS.type == "windows")
stop("Non-NULL baseDirectory in combination with absolute reportDirectory is not supported.")
htmlReport$new(title = title, shortName = shortName,
reportDirectory = reportDirectory, handlers = handlers,
basePath = basePath, .toHTML = .toHTML,
.toDF = .toDF, .modifyDF = .modifyDF, link.css= link.css,
link.javascript = link.javascript, ovewrite.js = overwrite.js)
}
### See AllOldClasses.R for old S4 based Report classes.
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.