Skip to content

API Documentation

Jason Kao edited this page Dec 24, 2020 · 17 revisions

This page contains detailed API reference documentation.

Table of contents

Spectate config

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.

Run time

Article hoisting

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.

image

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 commands

spectate create

$ 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.

spectate init

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

$ 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.

spectate open-doc

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.

spectate publish

AWS setup

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 and Spectate

ArchieML

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.

Docs Configuration

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; },
};

Glossary

Slug

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.