-
Notifications
You must be signed in to change notification settings - Fork 2
API Documentation
This page contains detailed API reference documentation.
A Spectate project can be configured through the spectate
field in its package.json
. Currently, there are 3 configuration settings for the page UI:
-
USE_NEWS_NAV
: Show a News navbar (a navbar with just the CDS logo) -
USE_EYE_NAV
: Show an Eye navbar (a navbar with the Eye logo and standard links) -
USE_COVER_HED
: Sort of a legacy Spectate feature. Puts the headline on a cover (example.)
Two other configuration keys, IS_EMBED
and DOC_URL
, are explained in the spectate create
and spectate init
sections, respectively.
Even though we can directly put HTML and text into our content management system Ellipsis, all of it is pushed deep into various nested container and grid elements. Below is a screenshot of the element structure of a general story on columbiaspectator.com. The story doesn't start until the <article>
node at the bottom.
Spectate HTML gets pushed into those containers too, and it seriously messes up the styling and layout of a story.
As seen in the screenshot, the uppermost structure of a columbiaspectator.com story looks like this:
<div id="pb-root">
<section id="top"> ... </section>
<section id="main">
...
<article> ... </article>
...
</section>
<section id="bottom"> ... </section>
</div>
div#pb-root
doesn't impose any styling constraints. section#main
is where it starts getting annoying. Thus, every Spectate project contains a few lines of code that implements "article hoisting": when the page loads, the uppermost container section#main
is directly replaced with the inner article
node. The structure becomes:
<div id="pb-root">
<section id="top"> ... </section>
<article> ... </article>
<section id="bottom"> ... </section>
This almost completely reduces style and layout conflicts that used to result from Spectate projects being stored in deeply nested containers. The hoisting function, hoistArticle()
, is run only when section#main
exists, which is detected using requestAnimationFrame()
.
$ spectate create [template-option]
There is one template option, embed
. All it does is set IS_EMBED
to true in the Spectate config, which prevents article hoisting. Embeds are projects that are not standalone pages, projects that should just be left as embedded HTML in the Arc story (example). When publishing embeds, just copy the HTML build into an HTML block an Arc. The contents of <head>
will get server-side-rendered into a heightless <p>
, and, for some reason, the non-text-element-having <p>
will have ineffectual margins.
It first asks for a slug which must be the name of an existing graphicsdesk
repository.
It then asks for a Google Docs link. If the link is valid, sets it to DOC_URL
in the Spectate config.
$ spectate download
Runs /process/download-doc.js
, which lives in your project, with keys stored in the Spectate directory. The script downloads the Google Doc and processes its contents with ArchieML.
The ArchieML output is prettified and written to /data/doc.json
. Sometimes you may want to import variables stored in the Google Doc to the script, but this may be a bad idea if your doc is large because it would be put into the JavaScript build. I basically just have this file to debug formatting errors from the doc download.
The ArchieML output is also stored in the PostHTML config (.posthtmlrc
) as the locals
object for the Expressions plugin. (When changing locals for posthtml-expressions, live reload seems to only invalidate the cache of .posthtmlrc
and not JavaScript configs.)
The PostHTML Expressions plugin isn't meant to be very smart. Consider this code block, which should only render multiple paragraphs if the local text
exists (which is determined by whether the text
variable exists in the Google Doc).
<if condition="typeof text !== 'undefined'">
<each loop="item in text.split('\n')">
<p>{{ item }}</p>
</each>
</if>
The expressions
plugin will throw TypeError: Cannot read property 'split' of undefined
. The if
block only considers whether some HTML should be included, not whether it should be processed, so expressions
will still try to split the undefined value.
To conditionally include a variable based on its existence in the Google Doc, you have to manually add a default value for the download-doc.js
script (see Docs Configuration).
Note that setting the default value of text
to null
in the previous example will still lead to the error TypeError: Cannot read property 'split' of null
for the same reason as above. The default value of a local should be set considering the operations that it must go through (e.g. empty string if splitting, empty array if looping).
<!-- text default was set to '' -->
<if condition="text.length > 0">
<each loop="item in text.split('\n')">
<p>{{ item }}</p>
</each>
</if>
You could also account for the operation in an expression, but you might risk repeating code.
<!-- text was left undefined -->
<each loop="item in (typeof text === 'undefined' ? [] : text).split('\n')">
<p>{{ item }}</p>
</each>
<!-- text was left undefined -->
<!-- but we want a container to always exist, so we must repeat some logic -->
<if condition="typeof text !== 'undefined'">
<div class="paragraphs">
<each loop="item in (typeof text === 'undefined' ? [] : text).split('\n')">
<p>{{ item }}</p>
</each>
</div>
</if>
Keep in mind that this only works for surface-level locals, not nested ones, because I am shallow cloning default locals with the ArchieML output and the config.
Make sure you have run spectate update
and you are in the directory of a Spectate project.
Running spectate open-doc
will open the Google Doc that powers the Spectate project you're in.
Part of publishing is uploading static assets (like stylesheets, scripts, and sometimes images) to Amazon Web Services' Simle Storage Service (S3). For that to work, write a new file at ~/.aws/credentials
with the contents below:
[spectate] aws_access_key_id = YOUR_ACCESS_KEY_ID aws_secret_access_key = YOUR_SECRET_ACCESS_KEY
See this doc for your access key (a dep can share you on this).
Run cat ~/.aws/credentials
. If the output is the contents of the file you just made, you should now be able to run any publish command.
Google Docs are written in a markup language called ArchieML. You should check out their syntax and reason for existence.
Docs are downloaded. Their text is then parsed and formatted. The output data is written as locals in the PostHTML config.
It is possible to configure defaults for the locals object, as well as the formatter for doc-to-archieml
. This can be done though a docs.config.js
file.
module.exports = {
defaultLocals: { ... }, // top: [] and body: [] are always defaults
formatter: function(textRun) { ... return content; },
};
A slug is a really short (1 – 4 words) label for an article. It consists of lowercase words connected by hyphens. Examples: property-acquisition, cd7-election-contributions, nypd-complaints-data.