More trip planner testing with colors
[busui.git] / labs / openlayers / lib / OpenLayers / Format / Atom.js
blob:a/labs/openlayers/lib/OpenLayers/Format/Atom.js -> blob:b/labs/openlayers/lib/OpenLayers/Format/Atom.js
  /* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the Clear BSD license.
  * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
   
  /**
  * @requires OpenLayers/Format/XML.js
  * @requires OpenLayers/Format/GML/v3.js
  * @requires OpenLayers/Feature/Vector.js
  */
   
  /**
  * Class: OpenLayers.Format.Atom
  * Read/write Atom feeds. Create a new instance with the
  * <OpenLayers.Format.AtomFeed> constructor.
  *
  * Inherits from:
  * - <OpenLayers.Format.XML>
  */
  OpenLayers.Format.Atom = OpenLayers.Class(OpenLayers.Format.XML, {
   
  /**
  * Property: namespaces
  * {Object} Mapping of namespace aliases to namespace URIs. Properties
  * of this object should not be set individually. Read-only. All
  * XML subclasses should have their own namespaces object. Use
  * <setNamespace> to add or set a namespace alias after construction.
  */
  namespaces: {
  atom: "http://www.w3.org/2005/Atom",
  georss: "http://www.georss.org/georss"
  },
   
  /**
  * APIProperty: feedTitle
  * {String} Atom feed elements require a title. Default is "untitled".
  */
  feedTitle: "untitled",
   
  /**
  * APIProperty: defaultEntryTitle
  * {String} Atom entry elements require a title. In cases where one is
  * not provided in the feature attributes, this will be used. Default
  * is "untitled".
  */
  defaultEntryTitle: "untitled",
   
  /**
  * Property: gmlParse
  * {Object} GML Format object for parsing features
  * Non-API and only created if necessary
  */
  gmlParser: null,
   
  /**
  * APIProperty: xy
  * {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x)
  * For GeoRSS the default is (y,x), therefore: false
  */
  xy: false,
   
  /**
  * Constructor: OpenLayers.Format.AtomEntry
  * Create a new parser for Atom.
  *
  * Parameters:
  * options - {Object} An optional object whose properties will be set on
  * this instance.
  */
  initialize: function(options) {
  OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
  },
   
  /**
  * APIMethod: read
  * Return a list of features from an Atom feed or entry document.
   
  * Parameters:
  * doc - {Element} or {String}
  *
  * Returns:
  * An Array of <OpenLayers.Feature.Vector>s
  */
  read: function(doc) {
  if (typeof doc == "string") {
  doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]);
  }
  return this.parseFeatures(doc);
  },
   
  /**
  * APIMethod: write
  * Serialize or more feature nodes to Atom documents.
  *
  * Parameters:
  * features - a single {<OpenLayers.Feature.Vector>} or an
  * Array({<OpenLayers.Feature.Vector>}).
  *
  * Returns:
  * {String} an Atom entry document if passed one feature node, or a feed
  * document if passed an array of feature nodes.
  */
  write: function(features) {
  var doc;
  if (features instanceof Array) {
  doc = this.createElementNSPlus("atom:feed");
  doc.appendChild(
  this.createElementNSPlus("atom:title", {
  value: this.feedTitle
  })
  );
  for (var i=0, ii=features.length; i<ii; i++) {
  doc.appendChild(this.buildEntryNode(features[i]));
  }
  }
  else {
  doc = this.buildEntryNode(features);
  }
  return OpenLayers.Format.XML.prototype.write.apply(this, [doc]);
  },
   
  /**
  * Method: buildContentNode
  *
  * Parameters:
  * content - {Object}
  *
  * Returns:
  * {DOMElement} an Atom content node.
  *
  * TODO: types other than text.
  */
  buildContentNode: function(content) {
  var node = this.createElementNSPlus("atom:content", {
  attributes: {
  type: content.type || null
  }
  });
  if (content.src) {
  node.setAttribute("src", content.src);
  } else {
  if (content.type == "text" || content.type == null) {
  node.appendChild(
  this.createTextNode(content.value)
  );
  } else if (content.type == "html") {
  if (typeof content.value != "string") {
  throw "HTML content must be in form of an escaped string";
  }
  node.appendChild(
  this.createTextNode(content.value)
  );
  } else if (content.type == "xhtml") {
  node.appendChild(content.value);
  } else if (content.type == "xhtml" ||
  content.type.match(/(\+|\/)xml$/)) {
  node.appendChild(content.value);
  }
  else { // MUST be a valid Base64 encoding
  node.appendChild(
  this.createTextNode(content.value)
  );
  }
  }
  return node;
  },
   
  /**
  * Method: buildEntryNode
  * Build an Atom entry node from a feature object.
  *
  * Parameters:
  * feature - {<OpenLayers.Feature.Vector>}
  *
  * Returns:
  * {DOMElement} an Atom entry node.
  *
  * These entries are geared for publication using AtomPub.
  *
  * TODO: support extension elements
  */
  buildEntryNode: function(feature) {
  var attrib = feature.attributes;
  var atomAttrib = attrib.atom || {};
  var entryNode = this.createElementNSPlus("atom:entry");
   
  // atom:author
  if (atomAttrib.authors) {
  var authors = atomAttrib.authors instanceof Array ?
  atomAttrib.authors : [atomAttrib.authors];
  for (var i=0, ii=authors.length; i<ii; i++) {
  entryNode.appendChild(
  this.buildPersonConstructNode(
  "author", authors[i]
  )
  );
  }
  }
   
  // atom:category
  if (atomAttrib.categories) {
  var categories = atomAttrib.categories instanceof Array ?
  atomAttrib.categories : [atomAttrib.categories];
  var category;
  for (var i=0, ii=categories.length; i<ii; i++) {
  category = categories[i];
  entryNode.appendChild(
  this.createElementNSPlus("atom:category", {
  attributes: {
  term: category.term,
  scheme: category.scheme || null,
  label: category.label || null
  }
  })
  );
  }
  }
   
  // atom:content
  if (atomAttrib.content) {
  entryNode.appendChild(this.buildContentNode(atomAttrib.content));
  }
   
  // atom:contributor
  if (atomAttrib.contributors) {
  var contributors = atomAttrib.contributors instanceof Array ?
  atomAttrib.contributors : [atomAttrib.contributors];
  for (var i=0, ii=contributors.length; i<ii; i++) {
  entryNode.appendChild(
  this.buildPersonConstructNode(
  "contributor",
  contributors[i]
  )
  );
  }
  }
   
  // atom:id
  if (feature.fid) {
  entryNode.appendChild(
  this.createElementNSPlus("atom:id", {
  value: feature.fid
  })
  );
  }
   
  // atom:link
  if (atomAttrib.links) {
  var links = atomAttrib.links instanceof Array ?
  atomAttrib.links : [atomAttrib.links];
  var link;
  for (var i=0, ii=links.length; i<ii; i++) {
  link = links[i];
  entryNode.appendChild(
  this.createElementNSPlus("atom:link", {
  attributes: {
  href: link.href,
  rel: link.rel || null,
  type: link.type || null,
  hreflang: link.hreflang || null,
  title: link.title || null,
  length: link.length || null
  }
  })
  );
  }
  }
   
  // atom:published
  if (atomAttrib.published) {
  entryNode.appendChild(
  this.createElementNSPlus("atom:published", {
  value: atomAttrib.published
  })
  );
  }
   
  // atom:rights
  if (atomAttrib.rights) {
  entryNode.appendChild(
  this.createElementNSPlus("atom:rights", {
  value: atomAttrib.rights
  })
  );
  }
   
  // atom:source not implemented
   
  // atom:summary
  if (atomAttrib.summary || attrib.description) {
  entryNode.appendChild(
  this.createElementNSPlus("atom:summary", {
  value: atomAttrib.summary || attrib.description
  })
  );
  }
   
  // atom:title
  entryNode.appendChild(
  this.createElementNSPlus("atom:title", {
  value: atomAttrib.title || attrib.title || this.defaultEntryTitle
  })
  );
   
  // atom:updated
  if (atomAttrib.updated) {
  entryNode.appendChild(
  this.createElementNSPlus("atom:updated", {
  value: atomAttrib.updated
  })
  );
  }
   
  // georss:where
  if (feature.geometry) {
  var whereNode = this.createElementNSPlus("georss:where");
  whereNode.appendChild(
  this.buildGeometryNode(feature.geometry)
  );
  entryNode.appendChild(whereNode);
  }
   
  return entryNode;
  },
   
  /**
  * Method: initGmlParser
  * Creates a GML parser.
  */
  initGmlParser: function() {
  this.gmlParser = new OpenLayers.Format.GML.v3({
  xy: this.xy,
  featureNS: "http://example.com#feature",
  internalProjection: this.internalProjection,
  externalProjection: this.externalProjection
  });
  },
   
  /**
  * Method: buildGeometryNode
  * builds a GeoRSS node with a given geometry
  *
  * Parameters:
  * geometry - {<OpenLayers.Geometry>}
  *
  * Returns:
  * {DOMElement} A gml node.
  */
  buildGeometryNode: function(geometry) {
  if (!this.gmlParser) {
  this.initGmlParser();
  }
  var node = this.gmlParser.writeNode("feature:_geometry", geometry);
  return node.firstChild;
  },
   
  /**
  * Method: buildPersonConstructNode
  *
  * Parameters:
  * name - {String}
  * value - {Object}
  *
  * Returns:
  * {DOMElement} an Atom person construct node.
  *
  * Example:
  * >>> buildPersonConstructNode("author", {name: "John Smith"})
  * {<author><name>John Smith</name></author>}
  *
  * TODO: how to specify extension elements? Add to the oNames array?
  */
  buildPersonConstructNode: function(name, value) {
  var oNames = ["uri", "email"];
  var personNode = this.createElementNSPlus("atom:" + name);
  personNode.appendChild(
  this.createElementNSPlus("atom:name", {
  value: value.name
  })
  );