Browse Source

new site

master
Michael Murtaugh 4 years ago
commit
7563356d13
12 changed files with 1895 additions and 0 deletions
  1. 13
    0
      .gitignore
  2. 11
    0
      about.txt
  3. 436
    0
      index.html
  4. 27
    0
      makefile
  5. 166
    0
      scripts/html5tidy
  6. 63
    0
      scripts/imagetile2.py
  7. 28
    0
      scripts/includenodes.py
  8. 711
    0
      scripts/leaflet.py
  9. 318
    0
      scripts/mediawiki.py
  10. 32
    0
      scripts/texthierarchy.py
  11. 76
    0
      styles.css
  12. 14
    0
      xpub.top.json

+ 13
- 0
.gitignore View File

@@ -0,0 +1,13 @@
1
+*.pyc
2
+*~
3
+drop/
4
+drop.json
5
+tiles/
6
+lib/
7
+venv/
8
+fonts/
9
+xpub.node.json
10
+drop.node.json
11
+archive.json
12
+about.json
13
+index.json

+ 11
- 0
about.txt View File

@@ -0,0 +1,11 @@
1
+The new study path experimental publishing is the merging of two stories: a singular one, and a slightly more general one.
2
+	The singular story is the one of the Media Design and Communication Master, which for a decade has established a critical approach to the ambiguous notion of media.
3
+		In the past years we have welcomed a wide range of practitioners from the culture field, visual and digital artists, graphic designers, musicians, performances artists, architects, fine press book makers, and computer programmers, to help them develop a practice that explore the social, technical, cultural and political dimensions of their work, and ultimately as we took the habit to say, to encourage them to <em>design their own media</em>.
4
+		<p>Such an approach has resulted in a rich variety of projects and writings, from <a href="http://fffff.at/pirates/">browser plugins to connect Amazon purchase button to Pirate Bay torrent links</a>, <a href="http://joak.nospace.at/rrtrn">chat system and audio feedback loops working with networks of tape reels</a>, <a href="http://www.birgitbachler.com/portfolio/portfolio/the-discrete-dialogue-network/">autonomous phone</a> and <a href="http://oyoana.com/leaveamessage">computer based voice mail networks</a>, <a href="http://epicpedia.org/">theatre scripts based on Wikipedia page histories</a>, <a href="http://p2pdesignstrategies.parcodiyellowstone.it/">peer-to-peer workflows for graphic designers</a>, <a href="http://stdin.fr/Works/BCC">generative artists book</a> and <a href="http://mhoogenboom.nl/?portfolio=epub-boem-paukeslag">concrete poetry epub</a>, <a href="">secret social networks</a> and file sharing hidden <a href="https://pzwiki.wdka.nl/mediadesign/Ddump:_recycling_in_the_digital_context">in the trash can</a> of your computer desktop, <a href="http://monoskop.org">wikis to publish precarious materials</a> and <a href="http://p-dpa.net/">weblogs of emerging forms of online artistic publishing</a> , and many other amazing things.</p>
5
+	The common point of these projects is they all look at particular issues, tensions, and conflicts relevant to the field of practice of their authors, and communicate concerns that are relevant to a much broader public. Why? Because they all offer a conversation about the cultural diversity, the systems, the networks, of humans and machines, that constitute our society.
6
+		This aspect of communication, sharing, informing, and thinking about how things are made public, and circulate in a public space is what link us today with this other, more general story, that is the one of publishing. Originally rooted in print media, the notion of publishing has in the last decades been both culturally diffused and appropriated well beyond its original domain of preference. It does not mean that publishing has lost its sharpness, in fact, this Cambrian explosion of new publishing potentials, has demonstrated how publishing has become central to a diversity of networked practices.
7
+	From app stores to art book fairs and zine shops, from darknets to sneakernets, from fansubs to on-demand services, and from tweeting to whistleblowing, the act of making things public, that is to say publishing, has became pivotal in an age infused with myriad media technologies.
8
+		What is more, the tension between the publishing heritage and novel forms of producing and sharing information has shown that old dichotomies such as analog versus digital, or local versus global, have grown increasingly irrelevant given their bond with hybrid media practices based on both old and new technologies, and their existence within mixed human and machine networks.
9
+	In sum, by experimental publishing we mean to engage with a broad set of intermingled and collaborative practices, both inherited and to be invented, so as to critically explore and actively engage with an ecosystem in which multi-layered interactions occur that are:
10
+		... social, technical, cultural and political;<br> involving actors both human and algorithmic;<br> and mediated by networks of distribution and communication of varying scales and visibility.
11
+		For this journey, we seek students motivated to challenge the protocols of publishing (in all its (im)possible forms) using play, fiction, and ambiguity as methods and strategies of production and presentation, in order to experiment on the threshold of what is possible, desirable, allowed, or disruptive, in this ever expanding field.

+ 436
- 0
index.html View File

@@ -0,0 +1,436 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+<head>
4
+    <title></title>
5
+    <meta charset="utf-8">
6
+    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
7
+    <script src="/lib/leaflet-1.0.1/leaflet.js"></script>
8
+    <link href="/lib/leaflet-1.0.1/leaflet.css" rel="stylesheet" type="text/css">
9
+    <link href="styles.css" rel="stylesheet" type="text/css">
10
+</head>
11
+<body>
12
+    <div id="frame" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px">
13
+        <div id="map" style="width: 100%; height: 100%; background: black"></div>
14
+        <div id="text" style="position: absolute; left: 50px; top: 10px; width: auto; color: white">
15
+        </div>
16
+    </div>
17
+
18
+<script>
19
+(function() {
20
+  // warning CHANGES TO THIS CODE NEED TO BE ROLLED BACK INTO leaflet.py
21
+  var cell_layout, expandzoom, fourup, layoutxyz, render, split4, tiler, tiles_wrapper, zoom;
22
+
23
+  window.tiler = tiler = {};
24
+
25
+  tiler.tiles_wrapper = tiles_wrapper = function(path, ext) {
26
+    if (ext == null) { ext = "jpg"; }
27
+    var ret = {};
28
+    ret.get_tile_path = function(z, y, x) {
29
+      return path + ("/z"+z+"y"+y+"x"+x+"."+ext);
30
+    };
31
+    return ret;
32
+  };
33
+
34
+  tiler.zoom = zoom = function(tiles, caption, url, x, y, z, maxzoom) {
35
+    var c, i, k, kids, len, len1, node, r, ref, ref1;
36
+    if (x == null) {
37
+      x = 0;
38
+    }
39
+    if (y == null) {
40
+      y = 0;
41
+    }
42
+    if (z == null) {
43
+      z = 0;
44
+    }
45
+    if (maxzoom == null) {
46
+      maxzoom = 3;
47
+    }
48
+    node = {};
49
+    if (caption && x === 0 && y === 0) {
50
+      node['text'] = caption;
51
+    }
52
+    var lastc = Math.pow(2, z) - 1;
53
+    if (url && x === 0 && y === lastc) {
54
+      node['url'] = url
55
+    }
56
+    node['image'] = tiles.get_tile_path(z, y, x);
57
+    if (z < maxzoom) {
58
+      kids = [];
59
+      ref = [0, 1];
60
+      for (i = 0, len = ref.length; i < len; i++) {
61
+        r = ref[i];
62
+        ref1 = [0, 1];
63
+        for (k = 0, len1 = ref1.length; k < len1; k++) {
64
+          c = ref1[k];
65
+          kids.push(zoom(tiles, caption, url, (x * 2) + c, (y * 2) + r, z + 1, maxzoom));
66
+        }
67
+      }
68
+      node['children'] = kids;
69
+    }
70
+    return node;
71
+  };
72
+
73
+  split4 = function(items) {
74
+    var c, el, i, l, len, p, ref, results, x;
75
+    l = items.length;
76
+    p = Math.ceil(Math.log(l) / Math.log(4));
77
+    c = Math.max(1, Math.pow(4, p) / 4);
78
+    el = function(x, c) {
79
+      while (x.length < c) {
80
+        x.push(null);
81
+      }
82
+      return x;
83
+    };
84
+    ref = [items.slice(0, c), items.slice(c, c * 2), items.slice(c * 2, c * 3), items.slice(c * 3)];
85
+    results = [];
86
+    for (i = 0, len = ref.length; i < len; i++) {
87
+      x = ref[i];
88
+      results.push(el(x, c));
89
+    }
90
+    return results;
91
+  };
92
+
93
+  cell_layout = function(items) {
94
+    return [
95
+      {
96
+        y: 0,
97
+        x: 0,
98
+        item: items[0]
99
+      }, {
100
+        y: 0,
101
+        x: 1,
102
+        item: items[1]
103
+      }, {
104
+        y: 1,
105
+        x: 0,
106
+        item: items[2]
107
+      }, {
108
+        y: 1,
109
+        x: 1,
110
+        item: items[3]
111
+      }
112
+    ];
113
+  };
114
+
115
+  tiler.render = render = function(items, tilewidth, tileheight, z, y, x) {
116
+    var g, i, j, kids, len, node, ref;
117
+    if (tilewidth == null) {
118
+      tilewidth = 256;
119
+    }
120
+    if (tileheight == null) {
121
+      tileheight = 256;
122
+    }
123
+    if (z == null) {
124
+      z = 0;
125
+    }
126
+    if (y == null) {
127
+      y = 0;
128
+    }
129
+    if (x == null) {
130
+      x = 0;
131
+    }
132
+    if (items.length === 1) {
133
+      x = items[0];
134
+      if (x === null) {
135
+        return null;
136
+      }
137
+      return zoom(x, '');
138
+    } else {
139
+      node = {};
140
+      node['text'] = '';
141
+      kids = [];
142
+      ref = cell_layout(split4(items));
143
+      for (i = 0, len = ref.length; i < len; i++) {
144
+        g = ref[i];
145
+        kids.push(render(g.item, tilewidth, tileheight, z + 1, (y * 2) + g.y, (x * 2) + g.x));
146
+      }
147
+      node.children = (function() {
148
+        var k, len1, results;
149
+        results = [];
150
+        for (k = 0, len1 = kids.length; k < len1; k++) {
151
+          j = kids[k];
152
+          if (j !== null) {
153
+            results.push(j);
154
+          }
155
+        }
156
+        return results;
157
+      })();
158
+      node.image = fourup((function() {
159
+        var k, len1, ref1, results;
160
+        ref1 = node.children;
161
+        results = [];
162
+        for (k = 0, len1 = ref1.length; k < len1; k++) {
163
+          j = ref1[k];
164
+          if (j !== null) {
165
+            results.push(j.image);
166
+          }
167
+        }
168
+        return results;
169
+      })(), tilewidth, tileheight);
170
+      return node;
171
+    }
172
+  };
173
+
174
+  tiler.layoutxyz = layoutxyz = function(n, x, y, z, outnode) {
175
+    var g, i, len, ref;
176
+    if (x == null) {
177
+      x = 0;
178
+    }
179
+    if (y == null) {
180
+      y = 0;
181
+    }
182
+    if (z == null) {
183
+      z = 0;
184
+    }
185
+    if (outnode == null) {
186
+      outnode = {};
187
+    }
188
+    outnode[x + "," + y + "," + z] = n;
189
+    if (n.children) {
190
+      ref = cell_layout(n.children);
191
+      for (i = 0, len = ref.length; i < len; i++) {
192
+        g = ref[i];
193
+        if (g.item) {
194
+          layoutxyz(g.item, (x * 2) + g.x, (y * 2) + g.y, z + 1, outnode);
195
+        }
196
+      }
197
+    }
198
+    return outnode;
199
+  };
200
+
201
+  tiler.fourup = fourup = function(images, tilewidth, tileheight) {
202
+    if (tilewidth == null) {
203
+      tilewidth = 256;
204
+    }
205
+    if (tileheight == null) {
206
+      tileheight = 256;
207
+    }
208
+    return function(done) {
209
+      var i, img, imgelts, len, loadcount, results, src, x;
210
+      loadcount = 0;
211
+      images = (function() {
212
+        var i, len, results;
213
+        results = [];
214
+        for (i = 0, len = images.length; i < len; i++) {
215
+          x = images[i];
216
+          if (x !== null) {
217
+            results.push(x);
218
+          }
219
+        }
220
+        return results;
221
+      })();
222
+      imgelts = [];
223
+      results = [];
224
+      for (i = 0, len = images.length; i < len; i++) {
225
+        src = images[i];
226
+        img = new Image;
227
+        imgelts.push(img);
228
+        img.addEventListener("load", function() {
229
+          var canvas, ctx, g, hh, hw, k, len1, ref;
230
+          if (++loadcount >= images.length) {
231
+            canvas = document.createElement("canvas");
232
+            canvas.width = tilewidth;
233
+            canvas.height = tileheight;
234
+            ctx = canvas.getContext("2d");
235
+            hw = tilewidth / 2;
236
+            hh = tileheight / 2;
237
+            ref = cell_layout(imgelts);
238
+            for (k = 0, len1 = ref.length; k < len1; k++) {
239
+              g = ref[k];
240
+              if (g.item) {
241
+                ctx.drawImage(g.item, g.x * hw, g.y * hh, hw, hh);
242
+              }
243
+            }
244
+            return done(null, canvas.toDataURL());
245
+          }
246
+        }, false);
247
+        if (typeof src === "function") {
248
+          console.log("inside 4up, deferring");
249
+          results.push(src(function(err, data) {
250
+            console.log("  inside 4up, GOT DATA");
251
+            return img.src = data;
252
+          }));
253
+        } else {
254
+          results.push(img.src = src);
255
+        }
256
+      }
257
+      return results;
258
+    };
259
+  };
260
+
261
+  tiler.expandzoom = expandzoom = function(node) {
262
+    var c, ret, tilespath;
263
+    if (node.zoomable) {
264
+      tilespath = node.image.replace(/\/[^\/]+$/, "");
265
+      var ext = node.image.match(/\.([^\.]+)$/);
266
+      if (ext != null) { ext = ext[1] };
267
+      ret = zoom(tiles_wrapper(tilespath, ext), node.text, node.url);
268
+      return ret;
269
+    }
270
+    if (node.children) {
271
+      node.children = (function() {
272
+        var i, len, ref, results;
273
+        ref = node.children;
274
+        results = [];
275
+        for (i = 0, len = ref.length; i < len; i++) {
276
+          c = ref[i];
277
+          if (c != null) {
278
+              results.push(expandzoom(c));
279
+          }
280
+        }
281
+        return results;
282
+      })();
283
+    }
284
+    return node;
285
+  };
286
+
287
+  /* DynamicTiles */
288
+  /*
289
+  A simple GridLayer extension that takes an external "nodes" object as option,
290
+  Nodes are keyed [x,y,z]
291
+  and expected to be of the form: 
292
+      {
293
+          text: "My text",
294
+          image" "imagepath.jpg"
295
+      }
296
+  */
297
+  L.GridLayer.DynamicTiles = L.GridLayer.extend({
298
+      createTile: function (coords, done) { // done = (err, tile)
299
+        // console.log("createTile", coords, this.options, this.options.nodes);
300
+          var tile = document.createElement('div'),
301
+            node = this.options.nodes[coords.x+","+coords.y+","+coords.z],
302
+            defer = false;
303
+
304
+          tile.classList.add("tile");
305
+          if (node != undefined) {
306
+            // console.log("NODE", node);
307
+            if (node.image) {
308
+              var img = document.createElement("img");
309
+              defer = true;
310
+              img.addEventListener("load", function () {
311
+                done(null, tile);
312
+              })
313
+              img.src = node.image;
314
+              tile.appendChild(img);
315
+              img.classList.add("imagetile");
316
+            }
317
+            if (node.text) {
318
+                  //console.log("text", node.text);
319
+                var textdiv = document.createElement("div");
320
+                textdiv.innerHTML = node.text;
321
+                tile.appendChild(textdiv);
322
+                textdiv.classList.add("text");
323
+            }
324
+            // if (node.url) {
325
+            //   console.log("NODE HAS URL!", node.url);
326
+            //     var urldiv = document.createElement("div"),
327
+            //       urllink = document.createElement("a"),
328
+            //       m = node.url.search(/\/([^\/]+)$/);
329
+            //     urllink.innerHTML = (m != null) ? m[1] : "LINK";
330
+            //     urldiv.appendChild(urllink);
331
+            //     urldiv.classList.add("url");
332
+            //     tile.appendChild(urldiv);
333
+            // }
334
+            if (node.background) {
335
+              tile.style.color = node.background;
336
+            }
337
+            if (node.class) {
338
+              tile.classList.add(node.class);
339
+            }
340
+            tile.classList.add("z"+coords.z);
341
+          } else {
342
+            tile.innerHTML = [coords.x, coords.y, coords.z].join(', ');
343
+            tile.classList.add("coords");
344
+          }
345
+          // tile.style.outline = '1px solid red';
346
+          if (!defer) {
347
+            window.setTimeout(function () {
348
+              done(null, tile);
349
+            }, 250);
350
+          }
351
+          return tile;
352
+      }
353
+  });""
354
+
355
+  L.gridLayer.dynamicTiles = function(opts) {
356
+      return new L.GridLayer.DynamicTiles(opts);
357
+  };
358
+
359
+}).call(this);
360
+
361
+(function () {
362
+
363
+
364
+function getjson (url, callback) {
365
+    var request = new XMLHttpRequest();
366
+    request.open('GET', url, true);
367
+    request.onload = function() {
368
+      if (request.readyState == XMLHttpRequest.DONE && request.status >= 200 && request.status < 400) {
369
+        callback(null, JSON.parse(request.responseText));
370
+      } else {
371
+        callback("server error");
372
+      }
373
+    };
374
+    request.onerror = function() {
375
+        callback("connection error");
376
+    };
377
+    request.send();
378
+}
379
+
380
+var map = L.map('map', {
381
+        editable: true,
382
+        maxZoom: 100,
383
+        minZoom: 0,
384
+        zoom: 0,
385
+        crs: L.CRS.Simple,
386
+        center: new L.LatLng(0,0),
387
+    });
388
+
389
+getjson("index.json", function (err, data) {
390
+    var nodes = (tiler.layoutxyz(tiler.expandzoom(data)));
391
+    map.addLayer( L.gridLayer.dynamicTiles({
392
+        minZoom: 0,
393
+        nodes: nodes
394
+    }) );
395
+
396
+})
397
+
398
+var yx = L.latLng,
399
+    xy = function(x, y) {
400
+        if (L.Util.isArray(x)) {    // When doing xy([x, y]);
401
+            return yx(x[1], x[0]);
402
+        }
403
+        return yx(y, x);  // When doing xy(x, y);
404
+    };
405
+
406
+function absolutize (coords, scale, x, y) {
407
+  // turns inkscape x,y relative path coords into absolute
408
+  // nb flips the direction of the y axis as well 
409
+  if (scale == null) { scale = 1.0 }
410
+  if (x == null) { x = 0.0 }
411
+  if (y == null) { y = 0.0 }
412
+  var c,
413
+    out = [];
414
+  for (var i=0, l=coords.length; i<l; i++) {
415
+    c = coords[i];
416
+    x += c[0]*scale; y -= c[1]*scale;
417
+    out.push([x, y]);
418
+  }
419
+  return out;
420
+}
421
+
422
+
423
+var xpath = [[0,0], [-7.89063,-10.6836], [7.40235,0], [4.47265,6.48438], [4.53125,-6.48438], [7.40235,0], [-7.89063,10.64453], [8.28125,11.23047], [-7.40234,0], [-4.92188,-6.91406], [-4.86328,6.91406], [-7.40234,0], [8.28125,-11.1914]];
424
+xpath = absolutize(xpath, 10.3, 87, -128.5);
425
+// flip it
426
+xpath = xpath.map(function (x) { return [x[1], x[0]] });
427
+// x = x.map(function (x) { return yx(x) });
428
+var polyline = L.polyline(xpath, {color: '#ed4e47'}).addTo(map);
429
+
430
+map.setView(xy(0.5 * 256, -0.5 * 256), 0);
431
+
432
+})();
433
+</script>
434
+</body>
435
+</html>
436
+

+ 27
- 0
makefile View File

@@ -0,0 +1,27 @@
1
+all: index.json
2
+
3
+archive.json:
4
+	python scripts/mediawiki.py gallery --name archive --recursive \
5
+		https://pzwiki.wdka.nl/mediadesign/Category:2016 \
6
+		https://pzwiki.wdka.nl/mediadesign/Category:2015 \
7
+		https://pzwiki.wdka.nl/mediadesign/Category:2014 \
8
+		https://pzwiki.wdka.nl/mediadesign/Category:2013 \
9
+		https://pzwiki.wdka.nl/mediadesign/Category:2012 \
10
+		https://pzwiki.wdka.nl/mediadesign/Category:2011 \
11
+		https://pzwiki.wdka.nl/mediadesign/Category:2010 \
12
+		https://pzwiki.wdka.nl/mediadesign/Category:2009 \
13
+		https://pzwiki.wdka.nl/mediadesign/Category:2008 \
14
+		https://pzwiki.wdka.nl/mediadesign/Category:2007 \
15
+		https://pzwiki.wdka.nl/mediadesign/Category:2006 \
16
+		https://pzwiki.wdka.nl/mediadesign/Category:2005 \
17
+		https://pzwiki.wdka.nl/mediadesign/Category:2004 > archive.json
18
+
19
+drop.node.json: drop.json
20
+	cat drop.json | python scripts/leaflet.py gallery --recursive --direction 2 > drop.node.json
21
+
22
+about.json:
23
+	python scripts/texthierarchy.py < about.txt > about.json
24
+
25
+index.json: archive.json about.json drop.node.json
26
+	python scripts/includenodes.py xpub.top.json > index.json
27
+

+ 166
- 0
scripts/html5tidy View File

@@ -0,0 +1,166 @@
1
+#!/usr/bin/python
2
+from __future__ import print_function
3
+from html5lib import parse
4
+import os, sys
5
+from argparse import ArgumentParser
6
+from xml.etree import ElementTree as ET 
7
+
8
+
9
+def etree_indent(elem, level=0):
10
+    i = "\n" + level*"  "
11
+    if len(elem):
12
+        if not elem.text or not elem.text.strip():
13
+            elem.text = i + "  "
14
+        if not elem.tail or not elem.tail.strip():
15
+            elem.tail = i
16
+        for elem in elem:
17
+            etree_indent(elem, level+1)
18
+        if not elem.tail or not elem.tail.strip():
19
+            elem.tail = i
20
+    else:
21
+        if level and (not elem.tail or not elem.tail.strip()):
22
+            elem.tail = i
23
+
24
+def get_link_type (url):
25
+    lurl = url.lower()
26
+    if lurl.endswith(".html") or lurl.endswith(".htm"):
27
+        return "text/html"
28
+    elif lurl.endswith(".txt"):
29
+        return "text/plain"
30
+    elif lurl.endswith(".rss"):
31
+        return "application/rss+xml"
32
+    elif lurl.endswith(".atom"):
33
+        return "application/atom+xml"
34
+    elif lurl.endswith(".json"):
35
+        return "application/json"
36
+    elif lurl.endswith(".js") or lurl.endswith(".jsonp"):
37
+        return "text/javascript"
38
+
39
+def pluralize (x):
40
+    if type(x) == list or type(x) == tuple:
41
+        return x
42
+    else:
43
+        return (x,)
44
+
45
+def html5tidy (doc, charset="utf-8", title=None, scripts=None, links=None, indent=False):
46
+    if scripts:
47
+        script_srcs = [x.attrib.get("src") for x in doc.findall(".//script")]
48
+        for src in pluralize(scripts):
49
+            if src not in script_srcs:
50
+                script = ET.SubElement(doc.find(".//head"), "script", src=src)
51
+                script_srcs.append(src)
52
+
53
+    if links:
54
+        existinglinks = {}
55
+        for elt in doc.findall(".//link"):
56
+            href = elt.attrib.get("href")
57
+            if href:
58
+                existinglinks[href] = elt  
59
+        for link in links:
60
+            linktype = link.get("type") or get_link_type(link["href"])
61
+            if link["href"] in existinglinks:
62
+                elt = existinglinks[link["href"]]
63
+                elt.attrib["rel"] = link["rel"]
64
+            else:
65
+                elt = ET.SubElement(doc.find(".//head"), "link", href=link["href"], rel=link["rel"])
66
+            if linktype:
67
+                elt.attrib["type"] = linktype            
68
+            if "title" in link:
69
+                elt.attrib["title"] = link["title"]
70
+
71
+    if charset:
72
+        meta_charsets = [x.attrib.get("charset") for x in doc.findall(".//meta") if x.attrib.get("charset") != None]
73
+        if not meta_charsets:
74
+            meta = ET.SubElement(doc.find(".//head"), "meta", charset=args.charset)
75
+
76
+    if title != None:
77
+        titleelt = doc.find(".//title")
78
+        if not titleelt:
79
+            titleelt = ET.SubElement(doc.find(".//head"), "title")
80
+        titleelt.text = title
81
+            
82
+    if indent:
83
+        etree_indent(doc)
84
+    return doc
85
+
86
+
87
+if __name__ == "__main__": 
88
+    p = ArgumentParser("")
89
+    p.add_argument("input", nargs="?", default=None)
90
+    p.add_argument("--indent", default=False, action="store_true")
91
+    p.add_argument("--mogrify", default=False, action="store_true", help="modify file in place")
92
+    p.add_argument("--method", default="html", help="method, default: html, values: html, xml, text")
93
+    p.add_argument("--output", default=None, help="")
94
+    p.add_argument("--title", default=None, help="ensure/add title tag in head")
95
+    p.add_argument("--charset", default="utf-8", help="ensure/add meta tag with charset")
96
+    p.add_argument("--script", action="append", default=[], help="ensure/add script tag")
97
+    # <link>s, see https://www.w3.org/TR/html5/links.html#links
98
+    p.add_argument("--stylesheet", action="append", default=[], help="ensure/add style link")
99
+    p.add_argument("--alternate", action="append", default=[], nargs="+", help="ensure/add alternate links (optionally followed by a title and type)")
100
+    p.add_argument("--next", action="append", default=[], nargs="+", help="ensure/add alternate link")
101
+    p.add_argument("--prev", action="append", default=[], nargs="+", help="ensure/add alternate link")
102
+    p.add_argument("--search", action="append", default=[], nargs="+", help="ensure/add search link")
103
+    p.add_argument("--rss", action="append", default=[], nargs="+", help="ensure/add alternate link of type application/rss+xml")
104
+    p.add_argument("--atom", action="append", default=[], nargs="+", help="ensure/add alternate link of type application/atom+xml")
105
+
106
+    args = p.parse_args()
107
+    links = []
108
+    def add_links (links, items, rel, _type=None):
109
+        for href in items:
110
+            d = {}
111
+            d["rel"] = rel
112
+            if _type:
113
+                d["type"] = _type
114
+
115
+            if type(href) == list:
116
+                if len(href) == 1:
117
+                    d["href"] = href[0]
118
+                elif len(href) == 2:
119
+                    d["href"] = href[0]
120
+                    d["title"] = href[1]
121
+                elif len(href) == 3:
122
+                    d["href"] = href[0]
123
+                    d["title"] = href[1]
124
+                    d["type"] = href[2]
125
+                else:
126
+                    continue
127
+            else:
128
+                d["href"] = href
129
+
130
+            links.append(d)
131
+    for rel in ("stylesheet", "alternate", "next", "prev", "search"):
132
+        add_links(links, getattr(args, rel), rel)
133
+    for item in args.rss:
134
+        add_links(links, item, rel="alternate", _type="application/rss+xml")
135
+    for item in args.atom:
136
+        add_links(links, item, rel="alternate", _type="application/atom+xml")
137
+
138
+    # INPUT
139
+    if args.input:
140
+        fin = open(args.input)
141
+    else:
142
+        fin = sys.stdin
143
+
144
+    doc = parse(fin, namespaceHTMLElements=False)
145
+    if fin != sys.stdin:
146
+        fin.close()
147
+    html5tidy(doc, scripts=args.script, links=links, title=args.title, indent=args.indent)
148
+
149
+    # OUTPUT
150
+    tmppath = None
151
+    if args.output:
152
+        fout = open(args.output, "w")
153
+    elif args.mogrify:
154
+        tmppath = args.input+".tmp"
155
+        fout = open(tmppath, "w")
156
+    else:
157
+        fout = sys.stdout
158
+
159
+    print (ET.tostring(doc, method=args.method), file=fout)
160
+
161
+    if fout != sys.stdout:
162
+        fout.close()
163
+
164
+    if tmppath:
165
+        os.rename(args.input, args.input+"~")
166
+        os.rename(tmppath, args.input)

+ 63
- 0
scripts/imagetile2.py View File

@@ -0,0 +1,63 @@
1
+#!/usr/bin/env python
2
+
3
+from PIL import Image
4
+import re
5
+
6
+def fitbox (boxw, boxh, w, h):
7
+    rw = boxw
8
+    rh = int(rw * (float(h) / w))
9
+    if (rh >= boxh):
10
+        rh = boxh
11
+        rw = int(rh * (float(w) / h))
12
+    return rw, rh
13
+
14
+
15
+def tile_image (im, maxz=0, tilew=256, tileh=256, base=".", template="z{0[z]}y{0[y]}x{0[x]}.jpg", bgcolor=(0,0,0)):
16
+    z = 0
17
+    boxw, boxh = tilew, tileh
18
+
19
+    alpha = bgcolor != None # not template.endswith("jpg")
20
+
21
+    while True:
22
+        rw, rh = fitbox(boxw, boxh, im.size[0], im.size[1])
23
+        rim = im.resize((rw, rh), Image.ANTIALIAS)
24
+        if bgcolor:
25
+            tim = Image.new("RGB", (boxw, boxh), bgcolor)
26
+            tim.paste(rim, (0, 0))
27
+        else:
28
+            tim = Image.new("RGBA", (boxw, boxh))
29
+            tim.paste(rim, (0, 0))
30
+
31
+        rows, cols = 2**z, 2**z
32
+        for r in range(rows):
33
+            for c in range(cols):
34
+                ix = c*tileh
35
+                iy = r*tilew
36
+                cim = tim.crop((ix, iy, ix+tilew, iy+tileh))
37
+                op = base + template.format({'z':z, 'x':c, 'y':r})
38
+                # if not alpha:
39
+                #     cim = cim.convert("RGB")
40
+                cim.save(op)
41
+
42
+        z += 1
43
+        if z>maxz:
44
+            break
45
+        boxw *= 2
46
+        boxh *= 2
47
+
48
+if __name__ == "__main__":
49
+    from argparse import ArgumentParser
50
+    p = ArgumentParser("tile an image")
51
+    p.add_argument("--tilewidth", type=int, default=256, help="default: 256")
52
+    p.add_argument("--tileheight", type=int, default=256, help="default: 256")
53
+    p.add_argument("input")
54
+    p.add_argument("--output", default="./tile", help="output path, default: ./tile")
55
+    p.add_argument("--tilename", default="Z{z}Y{y}X{x}.jpg", help="template for tiles, default: Z{z}Y{y}X{x}.jpg")
56
+    p.add_argument("--background", default="0,0,0", help="background color, default: 0,0,0")
57
+    p.add_argument("--zoom", type=int, default=0, help="default 0")
58
+    args = p.parse_args()
59
+    im = Image.open(args.input)
60
+    tilename = re.sub(r"\{(.+?)\}", r"{0[\1]}", args.tilename)
61
+    background = tuple([int(x) for x in args.background.split(",")])
62
+    tile_image (im, args.zoom, args.tilewidth, args.tileheight, args.output, tilename, background)
63
+

+ 28
- 0
scripts/includenodes.py View File

@@ -0,0 +1,28 @@
1
+from __future__ import print_function
2
+from argparse import ArgumentParser
3
+
4
+ap = ArgumentParser("")
5
+ap.add_argument("input")
6
+args = ap.parse_args()
7
+
8
+import json
9
+
10
+with open(args.input) as f:
11
+	node = json.load(f)
12
+
13
+def expand (node):
14
+	if node == None:
15
+		return node
16
+	retnode = node
17
+	if "@include" in node:
18
+		with open(node['@include']) as f:
19
+			retnode = json.load(f)
20
+		if "text" in node:
21
+			retnode['text'] = node['text']
22
+	if "children" in retnode:
23
+		retnode['children'] = [expand(c) for c in retnode['children']]
24
+
25
+	return retnode
26
+
27
+print (json.dumps(expand(node), indent=2))
28
+

+ 711
- 0
scripts/leaflet.py View File

@@ -0,0 +1,711 @@
1
+#!/usr/bin/env python
2
+
3
+
4
+from __future__ import print_function, division
5
+from argparse import ArgumentParser
6
+from imagetile2 import tile_image
7
+from PIL import Image
8
+import os, json, sys, re, datetime, urlparse
9
+from math import ceil, log
10
+
11
+
12
+"""
13
+Maybe a better name for this script is tiling or tiler as it's not particularly leaflet specific.
14
+
15
+"""
16
+
17
+def tiles_path_for (n):
18
+    return n + ".tiles"
19
+
20
+def autolink (text):
21
+    def sub (m):
22
+        return u'<a href="{0}">LINK</a>'.format(m.group(0))
23
+    return re.sub(r"https?://[\S]+", sub, text, re.I)
24
+
25
+def parse8601 (t, fmt=None):
26
+    """ simple 8601 parser that doesn't care about more than YMDHMS"""
27
+    # 2016-11-16T14:13:40.379857
28
+    m = re.search(r"(?P<year>\d\d\d\d)-(?P<month>\d\d)-(?P<day>\d\d)T(?P<hour>\d\d):(?P<minute>\d\d):(?P<second>\d\d)", t)
29
+    if m:
30
+        d = m.groupdict()
31
+        ret = datetime.datetime(int(d['year']), int(d['month']), int(d['day']), int(d['hour']), int(d['minute']), int(d['second']))
32
+        if fmt:
33
+            return ret.strftime(fmt)
34
+        else:
35
+            return ret
36
+
37
+class tiles_wrapper (object):
38
+    """ Image wrapper abstraction... include URL to original + caption
39
+    """
40
+    def __init__(self, path, url=None, text=None, tilename="z{0[z]}y{0[y]}x{0[x]}.png"):
41
+        self.path = path
42
+        # self.item = item
43
+        self.url = url
44
+        self.text = text
45
+        self.tilename = tilename
46
+
47
+    def get_tile_path (self, z, y, x):
48
+        return os.path.join(self.path, self.tilename.format({'z':z,'y':y,'x':x}))
49
+
50
+    def zoom (self):
51
+        """ return serialized version of self """
52
+        node = {}
53
+        node['zoomable'] = True
54
+        if self.text:
55
+            node['text'] = self.text
56
+        else:
57
+            # autotext is a link to the url showing the basename
58
+            _, basename = os.path.split(self.url)
59
+            node['text'] = u"<a href=\"{0}\">{1}</a>".format(self.url, basename)
60
+        node['url'] = self.url
61
+        node['image'] = self.get_tile_path(0, 0, 0)
62
+        return node
63
+
64
+    def zoom_recursive (self, caption, x=0, y=0, z=0, maxzoom=3):
65
+        """ old style zoom in place -- ie render self to child nodes """
66
+        node = {}
67
+        node['text'] = self.text
68
+        node['image'] = self.get_tile_path(z, y, x)
69
+        if z < maxzoom:
70
+            kids = []
71
+            for r in range(2):
72
+                for c in range(2):
73
+                    kids.append(self.zoom_recursive(caption, (x*2)+c, (y*2)+r, z+1, maxzoom))
74
+            node['children'] = kids
75
+        return node
76
+
77
+def cell_layout(items, w=2):
78
+    i = 0
79
+    for r in range(w):
80
+        for c in range(w):
81
+            if i<len(items):
82
+                yield items[i], c, r
83
+                i+=1
84
+
85
+def fourup (imgs, w, h):
86
+    print ("fourup", imgs, w, h, file=sys.stderr)
87
+    oi = Image.new("RGBA", (w, h))
88
+    cw = w//2
89
+    ch = h//2
90
+    i = 0
91
+    for impath, c, r in cell_layout(imgs):
92
+        if impath:
93
+          im = Image.open(impath)
94
+          im.thumbnail((cw, ch))
95
+          oi.paste(im, (c*cw, r*ch))
96
+    return oi
97
+
98
+def split4(items):
99
+    """ returns 4 lists where len(l) is a power of 4 """
100
+    l = len(items)
101
+    p = int(ceil(log(l, 4)))
102
+    # print ("{0} items {1} {2} {3}".format(l, p, 2**p, 4**p))
103
+    c = int((4**p)/ 4)
104
+
105
+    # c = int(ceil(len(items) / 4))
106
+    def el (x, c): # ensurelength
107
+        while len(x) < c:
108
+            x.append(None)
109
+        return x
110
+
111
+    ret = [items[0:c],items[c:c*2],items[c*2:c*3],items[c*3:]]
112
+    return tuple([el(x, c) for x in ret])
113
+
114
+def gridrender (items, basename, tilewidth=256, tileheight=256, z=0, y=0, x=0):
115
+    """ items are now nodes proper """
116
+    """ Takes a list of nodes and returns a new node where items are arranged in a cascade of nodes such that
117
+    all items appear at the same (z) level -- side by side
118
+    Uses fourup to (recursively) produce a composite image of the underlying tiles.
119
+
120
+    """
121
+    print ("gridrender {0} items".format(len(items)), file=sys.stderr)
122
+
123
+    if len(items) == 1:
124
+        x = items[0]
125
+        if x == None:
126
+            return None
127
+        return x # x.zoom()
128
+    else:
129
+        node = {}
130
+        node['text'] = ''
131
+        kids = []
132
+        for group, x2, y2 in cell_layout(split4(items)):
133
+            kids.append(gridrender(group, basename, tilewidth, tileheight, z+1, (y*2)+y2, (x*2)+x2))
134
+        node['children'] = [j for j in kids if j != None]
135
+        newim = fourup([j.get("image") for j in node['children'] if j != None and j.get("image")], tilewidth, tileheight)
136
+        node['image'] = newim
137
+        newimpath = "{0}.z{1}y{2}x{3}.png".format(basename, z, y, x)
138
+        newim.save(newimpath)
139
+        node['image'] = newimpath
140
+        print ("Created 4up image {0}".format(newimpath), file=sys.stderr)
141
+
142
+        return node
143
+
144
+def recursiverender (items, basename, tilewidth=256, tileheight=256, direction=3, z=0):
145
+    node = {}
146
+    node['text'] = ''
147
+    # if len(items) >=1 and 'date' in items[0].item:
148
+    #     node['text'] = items[0].item['date']
149
+    # else:
150
+    #     node['text'] = ''
151
+    # node['image'] = ''
152
+    node['children'] = cc = [None, None, None, None]
153
+    ai = 0
154
+    for x in items[:3]:
155
+        # cap = os.path.splitext(os.path.basename(x.path))[0]
156
+        # cc.append(x) # x.zoom()
157
+        if (ai == direction):
158
+            ai += 1
159
+        cc[ai] = x
160
+        ai += 1;
161
+
162
+    rest = items[3:]
163
+    if rest:
164
+        # recurse
165
+        # cc.append(recursiverender(rest, basename, tilewidth, tileheight, z+1))
166
+        cc[direction] = recursiverender(rest, basename, tilewidth, tileheight, direction, z+1)
167
+
168
+    newim = fourup([x.get("image") for x in node['children'] if x != None and x.get("image")], tilewidth, tileheight)
169
+    # simplified name works just because there's only one generated tile per level
170
+    newimpath = u"{0}.z{1}.png".format(basename, z)
171
+    newim.save(newimpath)
172
+    node['image'] = newimpath
173
+
174
+    return node
175
+
176
+def layoutxyz (n, x=0, y=0, z=0, outnode={}):
177
+    # print ("layout", n, x, y, z, file=sys.stderr)
178
+    outnode["{0},{1},{2}".format(x,y,z)] = {
179
+        "text": n['text'],
180
+        "image": n['image']
181
+    }
182
+    if 'children' in n:
183
+        for child, cx, cy in cell_layout(n['children']):
184
+            layout(child, (x*2)+cx, (y*2)+cy, z+1, outnode)
185
+    return outnode
186
+
187
+def html (node, title):
188
+    page = u"""<!DOCTYPE html>
189
+<html>
190
+<head>
191
+    <title>""" + title + u"""</title>
192
+    <meta charset="utf-8">
193
+    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
194
+    <script src="/lib/leaflet-1.0.1/leaflet.js"></script>
195
+    <link href="/lib/leaflet-1.0.1/leaflet.css" rel="stylesheet" type="text/css">
196
+    <link href="map.css" rel="stylesheet" type="text/css">
197
+</head>
198
+<body>
199
+    <div id="frame" style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px">
200
+        <div id="map" style="width: 100%; height: 100%; background: black"></div>
201
+        <div id="text" style="position: absolute; left: 50px; top: 10px; width: auto; color: white">
202
+        </div>
203
+    </div>
204
+<script>
205
+(function() {
206
+  // warning CHANGES TO THIS CODE NEED TO BE ROLLED BACK INTO leaflet.py
207
+  var cell_layout, expandzoom, fourup, layoutxyz, render, split4, tiler, tiles_wrapper, zoom;
208
+
209
+  window.tiler = tiler = {};
210
+
211
+  tiler.tiles_wrapper = tiles_wrapper = function(path, ext) {
212
+    if (ext == null) { ext = "jpg"; }
213
+    var ret = {};
214
+    ret.get_tile_path = function(z, y, x) {
215
+      return path + ("/z"+z+"y"+y+"x"+x+"."+ext);
216
+    };
217
+    return ret;
218
+  };
219
+
220
+  tiler.zoom = zoom = function(tiles, caption, url, x, y, z, maxzoom) {
221
+    var c, i, k, kids, len, len1, node, r, ref, ref1;
222
+    if (x == null) {
223
+      x = 0;
224
+    }
225
+    if (y == null) {
226
+      y = 0;
227
+    }
228
+    if (z == null) {
229
+      z = 0;
230
+    }
231
+    if (maxzoom == null) {
232
+      maxzoom = 3;
233
+    }
234
+    node = {};
235
+    if (caption && x === 0 && y === 0) {
236
+      node['text'] = caption;
237
+    }
238
+    var lastc = Math.pow(2, z) - 1;
239
+    if (url && x === 0 && y === lastc) {
240
+      node['url'] = url
241
+    }
242
+    node['image'] = tiles.get_tile_path(z, y, x);
243
+    if (z < maxzoom) {
244
+      kids = [];
245
+      ref = [0, 1];
246
+      for (i = 0, len = ref.length; i < len; i++) {
247
+        r = ref[i];
248
+        ref1 = [0, 1];
249
+        for (k = 0, len1 = ref1.length; k < len1; k++) {
250
+          c = ref1[k];
251
+          kids.push(zoom(tiles, caption, url, (x * 2) + c, (y * 2) + r, z + 1, maxzoom));
252
+        }
253
+      }
254
+      node['children'] = kids;
255
+    }
256
+    return node;
257
+  };
258
+
259
+  split4 = function(items) {
260
+    var c, el, i, l, len, p, ref, results, x;
261
+    l = items.length;
262
+    p = Math.ceil(Math.log(l) / Math.log(4));
263
+    c = Math.max(1, Math.pow(4, p) / 4);
264
+    el = function(x, c) {
265
+      while (x.length < c) {
266
+        x.push(null);
267
+      }
268
+      return x;
269
+    };
270
+    ref = [items.slice(0, c), items.slice(c, c * 2), items.slice(c * 2, c * 3), items.slice(c * 3)];
271
+    results = [];
272
+    for (i = 0, len = ref.length; i < len; i++) {
273
+      x = ref[i];
274
+      results.push(el(x, c));
275
+    }
276
+    return results;
277
+  };
278
+
279
+  cell_layout = function(items) {
280
+    return [
281
+      {
282
+        y: 0,
283
+        x: 0,
284
+        item: items[0]
285
+      }, {
286
+        y: 0,
287
+        x: 1,
288
+        item: items[1]
289
+      }, {
290
+        y: 1,
291
+        x: 0,
292
+        item: items[2]
293
+      }, {
294
+        y: 1,
295
+        x: 1,
296
+        item: items[3]
297
+      }
298
+    ];
299
+  };
300
+
301
+  tiler.render = render = function(items, tilewidth, tileheight, z, y, x) {
302
+    var g, i, j, kids, len, node, ref;
303
+    if (tilewidth == null) {
304
+      tilewidth = 256;
305
+    }
306
+    if (tileheight == null) {
307
+      tileheight = 256;
308
+    }
309
+    if (z == null) {
310
+      z = 0;
311
+    }
312
+    if (y == null) {
313
+      y = 0;
314
+    }
315
+    if (x == null) {
316
+      x = 0;
317
+    }
318
+    if (items.length === 1) {
319
+      x = items[0];
320
+      if (x === null) {
321
+        return null;
322
+      }
323
+      return zoom(x, '');
324
+    } else {
325
+      node = {};
326
+      node['text'] = '';
327
+      kids = [];
328
+      ref = cell_layout(split4(items));
329
+      for (i = 0, len = ref.length; i < len; i++) {
330
+        g = ref[i];
331
+        kids.push(render(g.item, tilewidth, tileheight, z + 1, (y * 2) + g.y, (x * 2) + g.x));
332
+      }
333
+      node.children = (function() {
334
+        var k, len1, results;
335
+        results = [];
336
+        for (k = 0, len1 = kids.length; k < len1; k++) {
337
+          j = kids[k];
338
+          if (j !== null) {
339
+            results.push(j);
340
+          }
341
+        }
342
+        return results;
343
+      })();
344
+      node.image = fourup((function() {
345
+        var k, len1, ref1, results;
346
+        ref1 = node.children;
347
+        results = [];
348
+        for (k = 0, len1 = ref1.length; k < len1; k++) {
349
+          j = ref1[k];
350
+          if (j !== null) {
351
+            results.push(j.image);
352
+          }
353
+        }
354
+        return results;
355
+      })(), tilewidth, tileheight);
356
+      return node;
357
+    }
358
+  };
359
+
360
+  tiler.layoutxyz = layoutxyz = function(n, x, y, z, outnode) {
361
+    var g, i, len, ref;
362
+    if (x == null) {
363
+      x = 0;
364
+    }
365
+    if (y == null) {
366
+      y = 0;
367
+    }
368
+    if (z == null) {
369
+      z = 0;
370
+    }
371
+    if (outnode == null) {
372
+      outnode = {};
373
+    }
374
+    outnode[x + "," + y + "," + z] = n;
375
+    if (n.children) {
376
+      ref = cell_layout(n.children);
377
+      for (i = 0, len = ref.length; i < len; i++) {
378
+        g = ref[i];
379
+        if (g.item) {
380
+          layoutxyz(g.item, (x * 2) + g.x, (y * 2) + g.y, z + 1, outnode);
381
+        }
382
+      }
383
+    }
384
+    return outnode;
385
+  };
386
+
387
+  tiler.fourup = fourup = function(images, tilewidth, tileheight) {
388
+    if (tilewidth == null) {
389
+      tilewidth = 256;
390
+    }
391
+    if (tileheight == null) {
392
+      tileheight = 256;
393
+    }
394
+    return function(done) {
395
+      var i, img, imgelts, len, loadcount, results, src, x;
396
+      loadcount = 0;
397
+      images = (function() {
398
+        var i, len, results;
399
+        results = [];
400
+        for (i = 0, len = images.length; i < len; i++) {
401
+          x = images[i];
402
+          if (x !== null) {
403
+            results.push(x);
404
+          }
405
+        }
406
+        return results;
407
+      })();
408
+      imgelts = [];
409
+      results = [];
410
+      for (i = 0, len = images.length; i < len; i++) {
411
+        src = images[i];
412
+        img = new Image;
413
+        imgelts.push(img);
414
+        img.addEventListener("load", function() {
415
+          var canvas, ctx, g, hh, hw, k, len1, ref;
416
+          if (++loadcount >= images.length) {
417
+            canvas = document.createElement("canvas");
418
+            canvas.width = tilewidth;
419
+            canvas.height = tileheight;
420
+            ctx = canvas.getContext("2d");
421
+            hw = tilewidth / 2;
422
+            hh = tileheight / 2;
423
+            ref = cell_layout(imgelts);
424
+            for (k = 0, len1 = ref.length; k < len1; k++) {
425
+              g = ref[k];
426
+              if (g.item) {
427
+                ctx.drawImage(g.item, g.x * hw, g.y * hh, hw, hh);
428
+              }
429
+            }
430
+            return done(null, canvas.toDataURL());
431
+          }
432
+        }, false);
433
+        if (typeof src === "function") {
434
+          console.log("inside 4up, deferring");
435
+          results.push(src(function(err, data) {
436
+            console.log("  inside 4up, GOT DATA");
437
+            return img.src = data;
438
+          }));
439
+        } else {
440
+          results.push(img.src = src);
441
+        }
442
+      }
443
+      return results;
444
+    };
445
+  };
446
+
447
+  tiler.expandzoom = expandzoom = function(node) {
448
+    var c, ret, tilespath;
449
+    if (node.zoomable) {
450
+      tilespath = node.image.replace(/\/[^\/]+$/, "");
451
+      var ext = node.image.match(/\.([^\.]+)$/);
452
+      if (ext != null) { ext = ext[1] };
453
+      ret = zoom(tiles_wrapper(tilespath, ext), node.text, node.url);
454
+      return ret;
455
+    }
456
+    if (node.children) {
457
+      node.children = (function() {
458
+        var i, len, ref, results;
459
+        ref = node.children;
460
+        results = [];
461
+        for (i = 0, len = ref.length; i < len; i++) {
462
+          c = ref[i];
463
+          if (c != null) {
464
+              results.push(expandzoom(c));
465
+          }
466
+        }
467
+        return results;
468
+      })();
469
+    }
470
+    return node;
471
+  };
472
+
473
+  /* DynamicTiles */
474
+  /*
475
+  A simple GridLayer extension that takes an external "nodes" object as option,
476
+  Nodes are keyed [x,y,z]
477
+  and expected to be of the form: 
478
+      {
479
+          text: "My text",
480
+          image" "imagepath.jpg"
481
+      }
482
+  */
483
+  L.GridLayer.DynamicTiles = L.GridLayer.extend({
484
+      createTile: function (coords, done) { // done = (err, tile)
485
+        // console.log("createTile", coords, this.options, this.options.nodes);
486
+          var tile = document.createElement('div'),
487
+            node = this.options.nodes[coords.x+","+coords.y+","+coords.z],
488
+            defer = false;
489
+
490
+          tile.classList.add("tile");
491
+          if (node != undefined) {
492
+            // console.log("NODE", node);
493
+            if (node.image) {
494
+              var img = document.createElement("img");
495
+              defer = true;
496
+              img.addEventListener("load", function () {
497
+                done(null, tile);
498
+              })
499
+              img.src = node.image;
500
+              tile.appendChild(img);
501
+              img.classList.add("imagetile");
502
+            }
503
+            if (node.text) {
504
+                  //console.log("text", node.text);
505
+                var textdiv = document.createElement("div");
506
+                textdiv.innerHTML = node.text;
507
+                tile.appendChild(textdiv);
508
+                textdiv.classList.add("text");
509
+            }
510
+            // if (node.url) {
511
+            //   console.log("NODE HAS URL!", node.url);
512
+            //     var urldiv = document.createElement("div"),
513
+            //       urllink = document.createElement("a"),
514
+            //       m = node.url.search(/\/([^\/]+)$/);
515
+            //     urllink.innerHTML = (m != null) ? m[1] : "LINK";
516
+            //     urldiv.appendChild(urllink);
517
+            //     urldiv.classList.add("url");
518
+            //     tile.appendChild(urldiv);
519
+            // }
520
+            if (node.background) {
521
+              tile.style.color = node.background;
522
+            }
523
+            if (node.class) {
524
+              tile.classList.add(node.class);
525
+            }
526
+            tile.classList.add("z"+coords.z);
527
+          } else {
528
+            tile.innerHTML = [coords.x, coords.y, coords.z].join(', ');
529
+            tile.classList.add("coords");
530
+          }
531
+          // tile.style.outline = '1px solid red';
532
+          if (!defer) {
533
+            window.setTimeout(function () {
534
+              done(null, tile);
535
+            }, 250);
536
+          }
537
+          return tile;
538
+      }
539
+  });""
540
+
541
+  L.gridLayer.dynamicTiles = function(opts) {
542
+      return new L.GridLayer.DynamicTiles(opts);
543
+  };
544
+
545
+}).call(this);
546
+
547
+(function () {
548
+
549
+
550
+function getjson (url, callback) {
551
+    var request = new XMLHttpRequest();
552
+    request.open('GET', url, true);
553
+    request.onload = function() {
554
+      if (request.readyState == XMLHttpRequest.DONE && request.status >= 200 && request.status < 400) {
555
+        callback(null, JSON.parse(request.responseText));
556
+      } else {
557
+        callback("server error");
558
+      }
559
+    };
560
+    request.onerror = function() {
561
+        callback("connection error");
562
+    };
563
+    request.send();
564
+}
565
+
566
+var map = L.map('map', {
567
+        editable: true,
568
+        maxZoom: 100,
569
+        minZoom: 0,
570
+        zoom: 0,
571
+        crs: L.CRS.Simple,
572
+        center: new L.LatLng(0,0),
573
+    });
574
+var data = """ + json.dumps(node) + """;
575
+
576
+var nodes = (tiler.layoutxyz(tiler.expandzoom(data)));
577
+map.addLayer( L.gridLayer.dynamicTiles({
578
+    minZoom: 0,
579
+    nodes: nodes
580
+}) );
581
+
582
+var yx = L.latLng,
583
+    xy = function(x, y) {
584
+        if (L.Util.isArray(x)) {    // When doing xy([x, y]);
585
+            return yx(x[1], x[0]);
586
+        }
587
+        return yx(y, x);  // When doing xy(x, y);
588
+    };
589
+// map.setView(xy(0.5 * 256, -0.5 * 256), 0);
590
+
591
+})();
592
+</script>
593
+</body>
594
+</html>
595
+"""
596
+    return page
597
+
598
+def make_gallery(args):
599
+    """
600
+    to do -- separate the actual tiling process...
601
+    make tiling a separate pass ON THE ACTUAL NODE jSON
602
+
603
+    NB: this command accepts two different kinds of input.
604
+    1. One or more images as (argv) arguments -or-
605
+    2. A JSON stream (one object per line) on stdin.
606
+    """
607
+
608
+    bgcolor = None # (0, 0, 0)
609
+
610
+    items = []
611
+    if args.input:
612
+        for x in args.input:
613
+            i = {'url': x}
614
+            items.append(i)
615
+    else:
616
+        for line in sys.stdin:
617
+            line = line.rstrip()
618
+            if line and not line.startswith("#"):
619
+                item = json.loads(line)
620
+                items.append(item)
621
+
622
+    # Ensure / Generate tiles per image
623
+    items.sort(key=lambda x: x['url'])
624
+    tiles = []
625
+    for item in items:
626
+        n = item['url']
627
+        # print (n, file=sys.stderr)
628
+        path = os.path.join(args.tilespath, n)
629
+        # TODO date format...
630
+        caption = ''
631
+        if 'text' or 'date' in item:
632
+            caption += u'<p class="caption">';
633
+        if 'text' in item:
634
+            caption += u'<span class="text">{0}</span>'.format(autolink(item['text']))
635
+        if 'date' in item:
636
+            dt = parse8601(item['date'], "%d %b %Y")
637
+            caption += u'<span class="date">{0}</span>'.format(dt)
638
+        if 'url' in item:
639
+            ext = os.path.splitext(urlparse.urlparse(item['url']).path)[1]
640
+            if ext:
641
+                ext = ext[1:].upper()
642
+            caption += u'<a class="url" href="{0}">{1}</a>'.format(item['url'], ext)
643
+        if 'text' or 'date' in item:
644
+            caption += u'</p>';
645
+
646
+        t = tiles_wrapper(path, item['url'], text=caption)
647
+        tiles.append(t)
648
+        tile0 = t.get_tile_path(0, 0, 0) # os.path.join(path, args.tilename.format({'x': 0, 'y': 0, 'z': 0}))
649
+        if not os.path.exists(tile0) or args.force:
650
+            print ("Tiling {0}".format(n), file=sys.stderr)
651
+            try:
652
+                im = Image.open(n)
653
+                try:
654
+                    os.makedirs(path)
655
+                except OSError:
656
+                    pass
657
+                tile_image(im, args.zoom, args.tilewidth, args.tileheight, path+"/", args.tilename, bgcolor)
658
+                # tiles.append(t)
659
+
660
+            except IOError as e:
661
+                print ("Missing {0}, skipping".format(n), file=sys.stderr)
662
+                tiles = tiles[:-1]
663
+
664
+    # DO THE LAYOUT, generating intermediate tiles (zoom outs)
665
+    if args.reverse:
666
+        tiles.reverse()
667
+    tiles = [t.zoom() for t in tiles]
668
+    basename = os.path.join(args.tilespath, args.name)
669
+    if args.recursive:
670
+        root_node = recursiverender(tiles, basename, args.tilewidth, args.tileheight, args.direction)
671
+    else:
672
+        root_node = gridrender(tiles, basename, args.tilewidth, args.tileheight)
673
+
674
+    # OUTPUT ROOT NODE
675
+    if args.html:
676
+        print (html(root_node, args.name))
677
+    else:
678
+        print (json.dumps(root_node, indent=args.indent))
679
+
680
+
681
+if __name__ == "__main__":
682
+
683
+    ap = ArgumentParser("")
684
+
685
+    ap.add_argument("--basepath", default=".")
686
+    ap.add_argument("--baseuri", default="")
687
+
688
+    ap.add_argument("--tilespath", default="tiles")
689
+
690
+    ap.add_argument("--tilewidth", type=int, default=256)
691
+    ap.add_argument("--tileheight", type=int, default=256)
692
+    ap.add_argument("--zoom", type=int, default=3)
693
+
694
+    ap.add_argument("--tilename", default="z{0[z]}y{0[y]}x{0[x]}.png")
695
+    ap.add_argument("--reverse", default=False, action="store_true")
696
+    ap.add_argument("--indent", default=2, type=int)
697
+    ap.add_argument("--recursive", default=False, action="store_true")
698
+
699
+    ap.add_argument("--force", default=False, action="store_true")
700
+
701
+    subparsers = ap.add_subparsers(help='sub-command help')
702
+    ap_gallery = subparsers.add_parser('gallery', help='Create a grid gallery of images')
703
+    ap_gallery.add_argument("input", nargs="*")
704
+    ap_gallery.add_argument("--html", default=False, action="store_true")
705
+    ap_gallery.add_argument("--recursive", default=False, action="store_true")
706
+    ap_gallery.add_argument("--direction", type=int, default=3, help="cell to recursively expand into, 0-3, default: 3 (bottom-right)")
707
+    ap_gallery.add_argument("--name", default="gallery")
708
+    ap_gallery.set_defaults(func=make_gallery)
709
+
710
+    args = ap.parse_args()
711
+    args.func(args)

+ 318
- 0
scripts/mediawiki.py View File

@@ -0,0 +1,318 @@
1
+from __future__ import print_function
2
+
3
+import os, sys, re, urllib, urlparse, html5lib, json
4
+from PIL import Image
5
+from math import log
6
+from argparse import ArgumentParser
7
+from urllib2 import urlopen
8
+
9
+from xml.etree import ElementTree as ET 
10
+
11
+# from wiki_get_html import page_html
12
+from mwclient import Site
13
+from mwclient.page import Page
14
+
15
+from leaflet import tiles_wrapper, recursiverender, gridrender, html
16
+from imagetile2 import tile_image
17
+
18
+
19
+def wiki_url_to_title (url):
20
+    return urllib.unquote(url.split("/")[-1])
21
+
22
+def parse_gallery(t):
23
+    """ returns [(imagepageurl, caption, articleurl), ...] """
24
+    galleryitems = t.findall(".//li[@class='gallerybox']")
25
+    items = []
26
+    for i in galleryitems:
27
+        image_link = i.find(".//a[@class='image']")
28
+        src = None
29
+        captiontext = None
30
+        article = None
31
+
32
+        if image_link != None:
33
+            src = image_link.attrib.get("href")
34
+            # src = src.split("/")[-1]
35
+
36
+        caption = i.find(".//*[@class='gallerytext']")
37
+        if caption:
38
+            captiontext = ET.tostring(caption, method="html")
39
+            articlelink = caption.find(".//a")
40
+            if articlelink != None:
41
+                article = articlelink.attrib.get("href")
42
+
43
+        # f = wiki.Pages[imgname]
44
+        # items.append((f.imageinfo['url'], captiontext))
45
+        items.append((src, captiontext, article))
46
+    return items
47
+
48
+def mwfilepage_to_url (wiki, url):
49
+    filename = urllib.unquote(url.split("/")[-1])
50
+    page = wiki.Pages[filename]
51
+    return page, page.imageinfo['url']
52
+
53
+def url_to_path (url):
54
+    """  https://pzwiki.wdka.nl/mediadesign/File:I-could-have-written-that_these-are-the-words_mb_300dpi.png """
55
+    path = urllib.unquote(urlparse.urlparse(url).path)
56
+    return "/".join(path.split("/")[3:])
57
+
58
+def wiki_absurl (wiki, url):
59
+    ret = ''
60
+    if type(wiki.host) == tuple:
61
+        ret = wiki.host[0]+"://"+wiki.host[1]
62
+    else:
63
+        ret = "http://"+wiki.host
64
+
65
+    return urlparse.urljoin(ret, url)
66
+
67
+def wiki_title_to_url (wiki, title):
68
+    """ relies on wiki.site['base'] being set to the public facing URL of the Main page """
69
+    ret = ''
70
+    parts = urlparse.urlparse(wiki.site['base'])
71
+    base, main_page = os.path.split(parts.path)
72
+    ret = parts.scheme+"://"+parts.netloc+base
73
+    p = wiki.pages[title]
74
+    ret += "/" + p.normalize_title(p.name)
75
+    return ret
76
+
77
+def ensure_wiki_image_tiles (wiki, imagepageurl, text='', basepath="tiles", force=False, bgcolor=None, tilewidth=256, tileheight=256, zoom=3):
78
+    print ("ensure_wiki_image_tiles", imagepageurl, file=sys.stderr)
79
+    page, imageurl = mwfilepage_to_url(wiki, imagepageurl)
80
+    path = os.path.join(basepath, url_to_path(imageurl))
81
+    print ("imageurl, path", imageurl, path, file=sys.stderr)
82
+    ret = tiles_wrapper(path, imagepageurl, text=text)
83
+    tp = ret.get_tile_path(0, 0, 0)
84
+    if os.path.exists(tp) and not force:
85
+        return ret
86
+
87
+    try:
88
+        os.makedirs(path)
89
+    except OSError:
90
+        pass
91
+    im = Image.open(urlopen(imageurl))
92
+    tile_image(im, zoom, tilewidth, tileheight, path+"/", ret.tilename, bgcolor)
93
+    return ret
94
+
95
+def textcell (paras):
96
+    node = {}
97
+    node['text'] = paras[:1]
98
+    moretext = paras[1:]
99
+    if moretext:
100
+        node['children'] = [textcell([x]) for x in moretext]
101
+    return node
102
+
103
+def name_to_path (name):
104
+    return name.replace("/", "_")
105
+
106
+
107
+def render_article (wiki, ref, basepath="tiles", depth=0, maxdepth=3):
108
+    print ("render_article", ref, file=sys.stderr)
109
+    if type(ref) == Page:
110
+        page = ref
111
+        title = page.name
112
+        ref = wiki_title_to_url(wiki, page.name)
113
+    elif ref.startswith("http"):
114
+        title = wiki_url_to_title(ref)
115
+        page = wiki.pages[title]
116
+    else:
117
+        title = ref
118
+        page = wiki.pages[title]
119
+        ref = wiki_title_to_url(wiki, page.name)
120
+    # pagetext = page.text()
121
+    # print ("WIKI PARSE", title, file=sys.stderr)
122
+    parse = wiki.parse(page=title)
123
+    html = parse['text']['*']
124
+    # print ("GOT HTML ", html, file=sys.stderr)
125
+    tree = html5lib.parse(html, treebuilder="etree", namespaceHTMLElements=False)
126
+    body = tree.find("./body")
127
+    paras = []
128
+    images = []
129
+    imgsrcs = {}
130
+
131
+    for c in body:
132
+        if c.tag == "p":
133
+            # filter out paras like <p><br></p> but checking text-only render length
134
+            ptext = ET.tostring(c, encoding="utf-8", method="text").strip()
135
+            if len(ptext) > 0:
136
+                ptext = ET.tostring(c, encoding="utf-8", method="html").strip()
137
+                paras.append(ptext)
138
+
139
+        elif c.tag == "ul" and c.attrib.get("class") != None and "gallery" in c.attrib.get("class"):
140
+            # print ("GALLERY")
141
+            gallery = parse_gallery(c)
142
+            # Ensure image is downloaded ... at least the 00 image...
143
+            for src, caption, article in gallery:
144
+                src = wiki_absurl(wiki, src)
145
+                if src in imgsrcs:
146
+                    continue
147
+                imgsrcs[src] = True
148
+                print ("GalleryImage", src, caption, article, file=sys.stderr)
149
+                # if article and depth < maxdepth:
150
+                #     article = wiki_absurl(wiki, article)
151
+                #     images.append(render_article(wiki, article, caption, basepath, depth+1, maxdepth))
152
+                # else:
153
+                images.append(ensure_wiki_image_tiles(wiki, src, caption, basepath).zoom())
154
+
155
+    for a in body.findall('.//a[@class="image"]'):
156
+        caption = a.attrib.get("title", '')
157
+        src = wiki_absurl(wiki, a.attrib.get("href"))
158
+        # OEI... skippin svg for the moment (can't go straight to PIL)
159
+        if src.endswith(".svg"):
160
+            continue
161
+        print (u"Image_link {0}:'{1}'".format(src, caption).encode("utf-8"), file=sys.stderr)
162
+        if src in imgsrcs:
163
+            continue
164
+        imgsrcs[src] = True
165
+        images.append(ensure_wiki_image_tiles(wiki, src, caption, basepath).zoom())
166
+
167
+    print ("{0} paras, {1} images".format(len(paras), len(images)), file=sys.stderr)
168
+
169
+
170
+    if title == None:
171
+        title = page.name
172
+
173
+    basename = "tiles/" + name_to_path(page.name)
174
+
175
+    # gallerynode = gridrender(images, basename)
176
+    # return gallerynode
177
+    cells = []
178
+    if len(paras) > 0:
179
+        cells.append(textcell(paras))
180
+    cells.extend(images)
181
+
182
+    ret = recursiverender(cells, basename)
183
+    ret['text'] = u"""<p class="caption"><span class="text">{0}</span><a class="url" href="{1}">WIKI</a></p>""".format(title, ref)
184
+    if images:
185
+        ret['image'] = images[0]['image']
186
+    return ret
187
+
188
+    # article = {}
189
+    # article['text'] = title
190
+    # article['children'] = children = []
191
+    # children.append(textcell(paras))
192
+    # for iz in images[:2]:
193
+    #     if 'image' not in article and 'image' in iz:
194
+    #         article['image'] = iz['image']
195
+    #     children.append(iz)
196
+    # restimages = images[2:]
197
+    # if len(restimages) == 1:
198
+    #     children.append(restimages[0])
199
+    # elif len(restimages) > 1:
200
+    #     children.append(gridrender(restimages, basename))        
201
+    # return article
202
+
203
+def render_category (wiki, cat, output="tiles"):
204
+    print ("Render Category", cat, file=sys.stderr)
205
+    # if type(cat) == Page:
206
+    #     page = ref
207
+    #     title = page.name
208
+    #     ref = wiki_title_to_url(wiki, page.name)
209
+    if cat.startswith("http"):
210
+        title = wiki_url_to_title(cat)
211
+        cat = wiki.pages[title]
212
+    else:
213
+        title = ref
214
+        cat = wiki.pages[cat]
215
+        # ref = wiki_title_to_url(wiki, cat.name)
216
+    print ("cat", cat, file=sys.stderr)
217
+    pages = []
218
+    for m in cat.members():
219
+        pages.append(m)
220
+    pages.sort(key=lambda x: x.name)
221
+    pagenodes = [render_article(wiki, x.name) for x in pages]
222
+    for page, node in zip(pages, pagenodes):
223
+        node['text'] = u"""<p class="caption"><span class="text">{0}</span><a class="url" href="{1}">WIKI</a></p>""".format(page.name, wiki_title_to_url(wiki, page.name))
224
+    ret = gridrender(pagenodes, output+"/"+cat.name.replace(":", "_"))
225
+    ret['text'] = u"""<p class="caption"><a class="url" href="{0}">{1}</a></p>""".format(wiki_title_to_url(wiki, cat.name), cat.name)
226
+    return ret
227
+    # for p in pages:
228
+    #     print (p.name, wiki_title_to_url(wiki, p.name))
229
+
230
+def make_category (args):
231
+    wiki = Site((args.wikiprotocol, args.wikihost), path=args.wikipath)
232
+    root_node = render_category(wiki, args.category)
233
+    if args.html:
234
+        print (html(root_node, ""))
235
+    else:
236
+        print (json.dumps(root_node, indent=2))
237
+
238
+
239
+def make_article (args):
240
+    wiki = Site((args.wikiprotocol, args.wikihost), path=args.wikipath)
241
+    root_node = render_article(wiki, args.wikipage)
242
+    if args.html:
243
+        print (html(root_node, ""))
244
+    else:
245
+        print (json.dumps(root_node, indent=2))
246
+
247
+def make_gallery(args):
248
+    wiki = Site((args.wikiprotocol, args.wikihost), path=args.wikipath)
249
+    # apiurl = args.wikiprotocol+"://"+args.wikihost+args.wikipath+"api.php"
250
+    if len(args.wikipage) == 1:
251
+        root_node = render_article(wiki, args.wikipage[0])
252
+    else:
253
+        children = []
254
+        for wikipage in args.wikipage:
255
+            print ("rendering", wikipage, file=sys.stderr)
256
+            if "Category:" in wikipage:
257
+                print ("rendering", wikipage, file=sys.stderr)
258
+                cnode = render_category(wiki, wikipage, args.output)
259
+            else:
260
+                cnode = render_article(wiki, wikipage)
261
+            children.append(cnode)
262
+        if args.recursive:
263
+            root_node = recursiverender(children, args.output+"/"+args.name, direction=1)
264
+        else:
265
+            root_node = gridrender(children, args.output+"/"+args.name, direction=1)
266
+
267
+    if args.html:
268
+        print (html(root_node, ""))
269
+    else:
270
+        print (json.dumps(root_node, indent=2))
271
+
272
+
273
+def testwiki (args):
274
+    return Site((args.wikiprotocol, args.wikihost), path=args.wikipath)
275
+
276
+if __name__ == "__main__":
277
+
278
+    ap = ArgumentParser("")
279
+    ap.add_argument("--wikiprotocol", default="https")
280
+    ap.add_argument("--wikihost", default="pzwiki.wdka.nl")
281
+    ap.add_argument("--wikipath", default="/mw-mediadesign/")
282
+    ap.add_argument("--wikishortpath", default="/mediadesign/")
283
+
284
+    ap.add_argument("--tilewidth", type=int, default=256)
285
+    ap.add_argument("--tileheight", type=int, default=256)
286
+    # ap.add_argument("--zoom", type=int, default=3)
287
+
288
+    ap.add_argument("--output", default="tiles")
289
+    # ap.add_argument("--title", default="TITLE")
290
+
291
+ 
292
+    subparsers = ap.add_subparsers(help='sub-command help')
293
+    ap_article = subparsers.add_parser('article', help='Render an article')
294
+    ap_article.add_argument("wikipage")
295
+    ap_article.add_argument("--html", default=False, action="store_true")
296
+    ap_article.set_defaults(func=make_article)
297
+
298
+    ap_gallery = subparsers.add_parser('gallery', help='Render a gallery of articles')
299
+    ap_gallery.add_argument("wikipage", nargs="+")
300
+    ap_gallery.add_argument("--html", default=False, action="store_true")
301
+    ap_gallery.add_argument("--recursive", default=False, action="store_true")
302
+    ap_gallery.add_argument("--direction", type=int, default=3, help="cell to recursively expand into, 0-3, default: 3 (bottom-right)")
303
+    ap_gallery.add_argument("--name", default=None)
304
+    ap_gallery.set_defaults(func=make_gallery)
305
+
306
+    ap_gallery = subparsers.add_parser('testwiki', help='Render a gallery of articles')
307
+    ap_gallery.set_defaults(func=testwiki)
308
+
309
+    ap_article = subparsers.add_parser('category', help='Render an article')
310
+    ap_article.add_argument("category")
311
+    ap_article.add_argument("--html", default=False, action="store_true")
312
+    ap_article.set_defaults(func=make_category)
313
+
314
+
315
+
316
+    args = ap.parse_args()
317
+    ret = args.func(args)
318
+

+ 32
- 0
scripts/texthierarchy.py View File

@@ -0,0 +1,32 @@
1
+from __future__ import print_function
2
+from html5lib import parse
3
+import sys, json
4
+from xml.etree import ElementTree as ET 
5
+
6
+
7
+def process (f):
8
+    stack = []
9
+    for line in f:
10
+        line = line.rstrip()
11
+        if line:
12
+            level = 0
13
+            while line.startswith("\t"):
14
+                line = line[1:]
15
+                level += 1
16
+            print (level, line, file=sys.stderr)
17
+            node = {
18
+                'text': line,
19
+                'level': level,
20
+                'children': []
21
+            }
22
+            while len(stack) > level:
23
+                stack.pop()
24
+            if len(stack):
25
+                stack[len(stack)-1]['children'].append(node)
26
+            stack.append(node)
27
+    return stack[0]
28
+
29
+if __name__ == "__main__":
30
+    n = process(sys.stdin)
31
+    import json
32
+    print (json.dumps(n, indent=2))

+ 76
- 0
styles.css View File

@@ -0,0 +1,76 @@
1
+@font-face {
2
+      font-family: "Libertinage x";
3
+      src: url("fonts/Libertinage-x.ttf");
4
+}
5
+@font-face {
6
+      font-family: "OSP-DIN";
7
+      src: url("fonts/OSP-DIN.ttf");
8
+}
9
+
10
+body {
11
+    margin: 5em;
12
+    font-family: "Libertinage x", serif;
13
+    font-size: 1.1em;
14
+    color: #2d2020;
15
+    background: #f2eee3;
16
+}
17
+#map {
18
+    background: #f2eee3 !important;
19
+}
20
+div.tile {
21
+    color: #2d2020;
22
+    position: absolute;
23
+    pointer-events: auto; /* this enables links */
24
+}
25
+div.tile img.imagetile {
26
+    position: absolute;
27
+    left: 0; top: 0;
28
+    z-index: 0; 
29
+}
30
+div.tile div.text {
31
+    position: absolute;
32
+    left: 0; top: 0;
33
+    z-index: 1;
34
+    font-family: sans-serif;
35
+    font-size: 15px;
36
+    line-height: 18px;
37
+    /*text-shadow: 1px 1px 2px black;*/
38
+    padding-right: 10px;
39
+    padding-left: 0px;
40
+    margin-top: 0px;
41
+}
42
+div.tile div.text p {
43
+    margin: 0;
44
+    hyphens: auto;
45
+}
46
+div.tile div.text a {
47
+    margin: 0;
48
+    text-decoration: none;
49
+    color: #f2eee3;
50
+    background: #ed4e47;
51
+}
52
+div.tile div.text a:hover {}
53
+div.coords {
54
+   pointer-events: none;
55
+   display: none;
56
+}
57
+.leaflet-overlay-pane {
58
+    z-index: 0 !important; /* hack to put the x underneath */
59
+}
60
+p.caption {}
61
+p.caption span.text {
62
+  /*background: #444;*/
63
+}
64
+p.caption span.date {
65
+  padding-left: 8px;
66
+  /*background: #444;*/
67
+  /*color: #AAA;*/
68
+}
69
+p.caption a.url {
70
+  padding-left: 8px;
71
+  /*color: #FF0;*/
72
+}
73
+p.caption a.url:hover {
74
+  /*background: #FF0;*/
75
+  /*color: black;*/
76
+}

+ 14
- 0
xpub.top.json View File

@@ -0,0 +1,14 @@
1
+{
2
+	"text": "",
3
+	"children": [
4
+		{ "@include": "about.json" },
5
+		{
6
+			"text": "<p class=\"caption\"><span class=\"text\">Here you find a frequently updated stream of images and posts reflecting current events in the course.</span></p>",
7
+			"@include": "drop.node.json"
8
+		},
9
+		{
10
+			"text": "<p class=\"caption\"><span class=\"text\">In the archive you find a vast collection of final projects from over 10 years of Media Design (including Networked Media and Lens based).</span></p>",
11
+			"@include": "archive.json"
12
+		}
13
+	]
14
+}

Loading…
Cancel
Save