Permalink
Browse files

initial import of JS microformat parser.

git-svn-id: http://svn.danwebb.net/external/microformat@176 a686c101-5f17-0410-80e1-b267258107f6
  • Loading branch information...
0 parents commit 0d661c84a2e3d7ed03831ddf1d919650a95ed253 danwebb committed Feb 7, 2007
Showing with 276 additions and 0 deletions.
  1. +5 −0 hcalendar.js
  2. +34 −0 hcard.js
  3. +179 −0 microformat.js
  4. +58 −0 test/test.html
@@ -0,0 +1,5 @@
+HCalendar = Microformat.define('vevent', {
+ one : ['class', 'description', 'dtend', 'dtstamp', 'dtstart', 'duration',
+ 'location', 'status', 'summary', 'uid', 'last-modified', { 'url' : 'url' }],
+ many : ['category']
+});
@@ -0,0 +1,34 @@
+var HCard = Microformat.define('vcard', {
+ one : ['fn', 'bday', 'tz', 'sort-string', 'uid', 'class', {
+ 'n' : {
+ one : ['family-name', 'given-name', 'additional-name'],
+ many : ['honorific-prefix', 'honorific-suffix']
+ },
+ 'geo' : {
+ one : ['latitude', 'longitude']
+ }
+ }],
+ many : ['label', 'sound', 'title', 'role', 'key', 'mailer', 'rev', 'nickname', 'category', 'note', {
+ 'url' : 'url', 'logo' : 'url', 'photo' : 'url'
+ }, {
+ 'email' : {
+ many : ['type', { 'value' : 'url' }]
+ },
+ 'tel' : {
+ many : ['type', 'value']
+ },
+ 'adr' : {
+ one : ['post-office-box', 'extended-address', 'street-address', 'locality', 'region',
+ 'postal-code', 'country-name', 'value'],
+ many : ['type']
+ },
+ 'org' : {
+ one : ['organization-name', 'organization-unit']
+ }
+ }]
+});
+
+// Implied n processor
+HCard.addHandler('fn', function(value, data) {
+ // TODO
+})
@@ -0,0 +1,179 @@
+if (!Array.prototype.forEach) {
+ Array.prototype.forEach = function(func, scope) {
+ scope = scope || this;
+ for (var i = 0, l = this.length; i < l; i++)
+ func.call(scope, this[i], i, this);
+ }
+}
+
+if (!Array.prototype.map) {
+ Array.prototype.map = function(func, scope) {
+ scope = scope || this;
+ var list = [];
+ for (var i = 0, l = this.length; i < l; i++)
+ list.push(func.call(scope, this[i], i, this));
+ return list;
+ }
+}
+
+if (!Array.prototype.filter) {
+ Array.prototype.filter = function(func, scope) {
+ scope = scope || this;
+ var list = [];
+ for (var i = 0, l = this.length; i < l; i++)
+ if (func.call(scope, this[i], i, this)) list.push(this[i]);
+ return list;
+ }
+}
+
+['forEach', 'map', 'filter', 'slice', 'concat'].forEach(function(func) {
+ if (!Array[func]) Array[func] = function(object) {
+ return this.prototype[func].apply(object, Array.prototype.slice.call(arguments, 1));
+ }
+});
+
+Microformat = {
+ define : function(name, spec) {
+ var mf = function(node, data) {
+ this.parentElement = node;
+ Microformat.extend(this, data);
+ };
+
+ mf.container = name;
+ mf.format = spec;
+ mf.handlers = {};
+ mf.prototype = Microformat.Base;
+ return Microformat.extend(mf, Microformat.SingletonMethods);
+ },
+ SingletonMethods : {
+ discover : function(context) {
+ return Microformat.$$(this.container, context).map(function(node) {
+ return new this(node, this._parse(this.format, node));
+ }, this);
+ },
+ addHandler : function(prop, callback) {
+ this.handlers[prop] = callback;
+ },
+ _parse : function(format, node) {
+ var data = {};
+ Microformat.extend(data, this._parseOne(format, node));
+ Microformat.extend(data, this._parseMany(format, node));
+ return data;
+ },
+ _parseOne : function(format, context) {
+ var ones = {}, node;
+ format.one.forEach(function(item) {
+ if (typeof item == 'string') {
+ if (node = Microformat.$$(item, context)[0])
+ ones[this._propFor(item)] = this._extractData(node, 'simple');
+ } else {
+ for (var cls in item)
+ if (node = Microformat.$$(cls, context)[0]) {
+ ones[this._propFor(cls)] = this._extractData(node, item[cls]);
+ }
+ }
+ }, this);
+ return ones;
+ },
+ _parseMany : function(format, context) {
+ var manies = {}, nodes;
+ format.many.forEach(function(item) {
+ if (typeof item == 'string') {
+ nodes = Microformat.$$(item, context);
+ if (nodes.length > 0) manies[this._propFor(item) + 'List'] = nodes.map(function(node) {
+ return this._extractData(node, 'simple');
+ }, this);
+ } else {
+ nodes = Microformat.$$(cls, context);
+ for (var cls in item) {
+ nodes = Microformat.$$(item[cls], context);
+ if (nodes.length > 0) manies[this._propFor(cls + 'List')] = nodes.map(function(node) {
+ return this._extractData(node, item[cls]);
+ }, this);
+ }
+ }
+ }, this);
+ return manies;
+ },
+ _extractData : function(node, dataType) {
+ switch (dataType) {
+ case 'simple': return this._extractSimple(node);
+ case 'url': return this._extractURL(node);
+ }
+ return this._parse(dataType, node);
+ },
+ _extractURL : function(node) {
+ var href;
+ switch (node.nodeName.toLowerCase()) {
+ case 'img': href = node.src;
+ break;
+ case 'a': href = node.href;
+ break;
+ case 'object': href = node.data;
+ }
+ if (href) {
+ if (href.indexOf('mailto:') == 1)
+ href = href.replace(/^mailto:/, '').replace(/\?.*$/, '');
+ return href;
+ }
+
+ return this._coerce(this._getText(node));
+ },
+ _extractSimple : function(node) {
+ switch (node.nodeName.toLowerCase()) {
+ case 'abbr': return this._coerce(node.title);
+ case 'img': return this._coerce(node.alt);
+ }
+ return this._coerce(this._getText(node));
+ },
+ _getText : function(node) {
+ if (node.innerText) return node.innerText;
+ return Array.map(node.childNodes, function(node) {
+ if (node.nodeType == 3) return node.nodeValue;
+ else return this._getText(node);
+ }, this).join('');
+ },
+ _coerce : function(value) {
+ var date, number;
+ if (value == 'true') return true;
+ if (value == 'false') return false;
+ if (date = Date.parse(value.replace(/-/g, '/'))) return new Date(date);
+ if (number = parseFloat(value)) return number;
+ return String(value);
+ },
+ _propFor : function(name) {
+ this.__propCache = this.__propCache || {};
+ if (prop = this.__propCache[name]) return prop;
+ return this.__propCache[name] = name.replace(/(-(.))/g, function() {
+ // this isn't going to work on old safari without the fix....hmmm
+ return arguments[2].toUpperCase();
+ });
+ },
+ _handle : function(prop, item, data) {
+ if (this.handlers[prop]) this.handlers[prop].call(this, item, data);
+ }
+ },
+ $$ : function(className, context) {
+ context = context || document;
+ var nodeList;
+
+ if (context == document || context.nodeType == 1) {
+ if (typeof document.evaluate == 'function') {
+ var xpath = document.evaluate(".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]",
+ context, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+ var els = [];
+ for (var i = 0, l = xpath.snapshotLength; i < l; i++)
+ els.push(xpath.snapshotItem(i));
+ return els;
+ } else nodeList = context.getElementsByTagName('*');
+ } else nodeList = context;
+
+ var re = new RegExp('(^|\\s)' + className + '(\\s|$)');
+ return Array.filter(nodeList, function(node) { return node.className.match(re) });
+ },
+ extend : function(dest, source) {
+ for (var prop in source) dest[prop] = source[prop];
+ return dest;
+ },
+ Base : {}
+};
@@ -0,0 +1,58 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+
+ <title>test</title>
+ <script src="../microformat.js"></script>
+ <script src="../hcard.js"></script>
+ <script src="../hcalendar.js"></script>
+</head>
+
+<body>
+<h1>Thing</h1>
+<div id="bung">
+ <div class="vcard">
+ <h2><a href="http://danwebb.net" class="fn n url"><span class="given-name">Dan</span> <span class="family-name">Webb</span></a> <em class="role">Developer</em> <em class="role">Director</em></h2>
+ </div>
+
+ <div class="vcard">
+ <h2><a href="http://bob.net" class="fn url">Bob Fucker</a> <em class="role">Underling</em></h2>
+ </div>
+
+ <ul class="ll">
+
+ <li class="vevent"><a href="http://upcoming.org/event/144326" class="url summary">London Ruby User Group (LRUG) February Meeting</a>, <span class="location">London</span> <abbr title="2007-02-12" class="dtstart">12 FEB</abbr> - <abbr title="2007-02-06" class="dtend">06 FEB</abbr>.</li>
+
+
+ <li class="vevent"><a href="http://upcoming.org/event/138806" class="url summary">BarCampLondon2</a>, <span class="location"></span> <abbr title="2007-02-17" class="dtstart">17 FEB</abbr> - <abbr title="2007-02-18" class="dtend">18 FEB</abbr>.</li>
+
+ <li class="vevent"><a href="http://upcoming.org/event/90305" class="url summary">SXSW Interactive Festival</a>, <span class="location">Austin</span> <abbr title="2007-03-09" class="dtstart">09 MAR</abbr> - <abbr title="2007-03-14" class="dtend">14 MAR</abbr>.</li>
+
+
+ <li class="vevent"><a href="http://upcoming.org/event/122872" class="url summary">South by Northwest</a>, <span class="location">Austin</span> <abbr title="2007-03-12" class="dtstart">12 MAR</abbr> - <abbr title="2007-03-13" class="dtend">13 MAR</abbr>.</li>
+
+ <li class="vevent"><a href="http://upcoming.org/event/144002" class="url summary">The Great British Booze-up</a>, <span class="location">Austin</span> <abbr title="2007-03-12" class="dtstart">12 MAR</abbr> - <abbr title="2007-02-06" class="dtend">06 FEB</abbr>.</li>
+
+
+ <li class="vevent"><a href="http://upcoming.org/event/122605" class="url summary">AJAX2007</a>, <span class="location">Kensington</span> <abbr title="2007-04-17" class="dtstart">17 APR</abbr> - <abbr title="2007-04-18" class="dtend">18 APR</abbr>.</li>
+
+ <li class="vevent"><a href="http://upcoming.org/event/147703" class="url summary">RailsConf 2007</a>, <span class="location">Portland</span> <abbr title="2007-05-17" class="dtstart">17 MAY</abbr> - <abbr title="2007-05-20" class="dtend">20 MAY</abbr>.</li>
+
+
+ <li class="vevent"><a href="http://upcoming.org/event/110085" class="url summary">@media 2007 America</a>, <span class="location">San Francisco</span> <abbr title="2007-05-24" class="dtstart">24 MAY</abbr> - <abbr title="2007-05-25" class="dtend">25 MAY</abbr>.</li>
+
+ <li class="vevent"><a href="http://upcoming.org/event/110090" class="url summary">@media 2007 Asia</a>, <span class="location">Hong Kong</span> <abbr title="2007-05-31" class="dtstart">31 MAY</abbr> - <abbr title="2007-06-01" class="dtend">01 JUN</abbr>.</li>
+
+
+ <li class="vevent"><a href="http://upcoming.org/event/110091" class="url summary">@media 2007 Europe</a>, <span class="location">London</span> <abbr title="2007-06-07" class="dtstart">07 JUN</abbr> - <abbr title="2007-06-08" class="dtend">08 JUN</abbr>.</li>
+
+ <li class="vevent"><a href="http://upcoming.org/event/148676" class="url summary">Pub Standards 100</a>, <span class="location">London</span> <abbr title="2014-03-13" class="dtstart">13 MAR</abbr> - <abbr title="2007-02-06" class="dtend">06 FEB</abbr>.</li>
+
+
+ </ul>
+</div>
+</body>
+</html>

0 comments on commit 0d661c8

Please sign in to comment.