PageSourceSearch

https://bogost.com/assets/writing.js

js bogost.com collected 2026-10-02 03:09:56 UTC 5,489 bytes, 162 lines download raw bytes

1(function () {
2  const LOCAL_JSON = '/assets/writing-cache.json';   // optional static fallback (absolute path)
3  const BYPASS_LOCAL = window.WRITING_BYPASS_LOCAL === true; // set true to skip local cache entirely
4  const TARGET   = document.getElementById('writing-cards');
5  const FALLBACK = document.getElementById('writing-fallback');
6
7  // Determine desired item count (script var -> data-count -> default)
8  const ITEM_COUNT = Number((window.WRITING_ITEM_COUNT ?? TARGET?.dataset?.count ?? 7));
9  console.debug('[writing] ITEM_COUNT =', ITEM_COUNT);
10
11  // Use `count=` (matches writing.php) and add a cache buster
12  const FEED_URL = `/assets/writing.php?count=${ITEM_COUNT}&_=${Date.now()}`;
13  console.debug('[writing] FEED_URL =', FEED_URL);
14
15  function showFallback(msg) {
16    if (FALLBACK) {
17      FALLBACK.style.display = 'block';
18      if (msg) FALLBACK.textContent = 'Can’t load feed right now. ' + msg;
19    }
20  }
21
22  function formatDate(d) {
23    if (!d) return '';
24    // If already looks like a human date, return as-is
25    if (/[A-Za-z]+\s+\d{1,2},\s*\d{4}/.test(d)) return d;
26    const t = Date.parse(d);
27    if (isNaN(t)) return d; // fallback to raw string
28    try {
29      const date = new Date(t);
30      return date.toLocaleDateString('en-US', {
31        year: 'numeric',
32        month: 'long',
33        day: 'numeric'
34      });
35    } catch {
36      return d;
37    }
38  }
39
40  function renderFromJson(items) {
41    if (!Array.isArray(items) || !items.length) return false;
42
43    const frag = document.createDocumentFragment();
44    if (FALLBACK) FALLBACK.style.display = 'none';
45    console.debug('[writing] renderFromJson input length =', items.length);
46
47    // Prepend a static "Read all" card
48    const staticCard = document.createElement('article');
49    staticCard.className = 'card card-wrap featured-card';
50    staticCard.innerHTML = `
51      <a href="https://www.theatlantic.com/author/ian-bogost/" class="card-link" target="_blank" rel="noopener">
52        <img src="/images/atlantic-card.png" alt="The Atlantic" class="card-img" />
53        <p>Read all my stories at <em>The Atlantic</em></p>
54      </a>
55    `;
56    frag.appendChild(staticCard);
57
58    // Render feed items (limited to ITEM_COUNT)
59    let cCount = 0;
60    let cMAX = 5;
61    const list = items.slice(0, ITEM_COUNT);
62    console.debug('[writing] rendering', list.length, 'items');
63    list.forEach((it) => {
64      const title   = it.title || '';
65      const link    = it.link || '#';
66      const rawDate = it.date || it.pubDate || it.updated || it.published || '';
67      const when    = formatDate(rawDate) || '';
68      const excerpt = it.excerpt || it.summary || '';
69
70      const article = document.createElement('article');
71      article.className = 'card card-wrap';
72
73      let c = 0;
74      if (Math.random() > 0.5) {
75        c = Math.floor(Math.random() * 25);
76        if (c>0) cCount++;
77        if (cCount >= cMAX) c = 0; 
78      }
79
80      article.innerHTML = `
81        <a href="${link}" class="card-link" target="_blank" rel="noopener">
82          <h3 class="card-title">${title}</h3>
83          <p class="muted date">${when}</p>
84          <p class="muted excerpt line-clamp">${excerpt}</p>
85          <img src="/assets/creatures/${c}.png" alt="" class="mascot" />
86        </a>
87      `;
88      frag.appendChild(article);
89    });
90
91    TARGET.innerHTML = '';
92    TARGET.appendChild(frag);
93    return true;
94  }
95
96  async function getJSON(url) {
97    console.debug('[writing] fetch →', url);
98    const res = await fetch(url, {
99      cache: 'no-store',
100      credentials: 'same-origin',
101      headers: { 'Accept': 'application/json' }
102    });
103    console.debug('[writing] status', res.status, res.ok ? 'OK' : 'ERROR');
104    if (!res.ok) throw new Error(`HTTP ${res.status} for ${url}`);
105    const json = await res.json();
106    console.debug('[writing] json length =', Array.isArray(json) ? json.length : '(non-array)');
107    return json;
108  }
109
110  async function load() {
111    if (!TARGET) {
112      console.warn('[writing] No #writing-cards element found in DOM.');
113      return;
114    }
115
116    // 1) Try live PHP endpoint first
117    try {
118      const live = await getJSON(FEED_URL);
119      console.info('[writing] Loaded PHP JSON:', live);
120      if (Array.isArray(live)) {
121        if (renderFromJson(live)) {
122          console.debug('[writing] DONE (live)');
123          return;
124        }
125        showFallback('(empty live array)');
126        return;
127      } else if (live && live.error) {
128        console.warn('[writing] PHP returned error:', live);
129        // fall through to local cache
130      } else {
131        console.warn('[writing] Unexpected PHP payload shape:', live);
132        // fall through to local cache
133      }
134    } catch (e) {
135      console.warn('[writing] PHP proxy fetch failed:', e.message);
136      // fall through to local cache
137    }
138
139    // 2) Optional local JSON fallback (unless explicitly bypassed)
140    if (!BYPASS_LOCAL) {
141      try {
142        const local = await getJSON(LOCAL_JSON);
143        console.info('[writing] Loaded local JSON cache:', LOCAL_JSON, local);
144        if (renderFromJson(local)) {
145          console.debug('[writing] DONE (local cache)');
146          return;
147        }
148        showFallback('(empty local array)');
149        return;
150      } catch (e) {
151        console.info('[writing] No local cache JSON or failed to load:', e.message);
152      }
153    } else {
154      console.info('[writing] Local cache bypassed by flag.');
155    }
156
157    // 3) Give up gracefully
158    showFallback();
159  }
160
161  load();
162})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.