UNPKG

ingenta-lens

Version:
364 lines (297 loc) 8.17 kB
"use strict"; var _ = require("underscore"); var util = require("../substance/util"); var Document = require("../substance/document"); // Lens.Article // ----------------- var Article = function(options) { options = Article.prepareOptions(options); Document.call(this, options); // Index for easy mapping from NLM sourceIds to generated nodeIds // Needed for resolving figrefs / citationrefs etc. this.bySourceId = this.addIndex("by_source_id", { property: "source_id" }); this.nodeTypes = options.nodeTypes; // Seed the doc // -------- if (options.seed === undefined) { this.create({ id: "document", type: "document", guid: options.id, // external global document id creator: options.creator, created_at: options.created_at, views: Article.views, // is views really needed on the instance level title: "", abstract: "", authors: [] }); // Create views on the doc _.each(Article.views, function(view) { this.create({ id: view, "type": "view", nodes: [] }); }, this); } }; Article.Prototype = function() { this.fromSnapshot = function(data, options) { return Article.fromSnapshot(data, options); }; // For a given NLM source id, returns the corresponding node in the document graph // -------- this.getNodeBySourceId = function(sourceId) { var nodes = this.bySourceId.get(sourceId); var nodeId = Object.keys(nodes)[0]; var node = nodes[nodeId]; return node; }; // Get all headings of the content view // -------- this.getHeadings = function() { var headings = _.filter(this.get('content').getNodes(), function(node) { return node.type === "heading"; }); return headings; }; this.getTocNodes = function() { var nodes = _.filter(this.get('content').getNodes(), function(node) { return node.includeInToc(); }); return nodes; }; }; Article.prepareOptions = function(options) { // prepare configuration for options = options || {}; options.nodeTypes = _.extend(Article.nodeTypes, options.nodeTypes); options.schema = Article.getSchema(options.nodeTypes); return options; }; Article.getSchema = function(nodeTypes) { var schema = util.deepclone(Document.schema); schema.id = "lens-article"; schema.version = "2.0.0"; _.each(nodeTypes, function(nodeSpec, key) { schema.types[key] = nodeSpec.Model.type; }); return schema; }; // Factory method // -------- // // TODO: Ensure the snapshot doesn't get chronicled Article.fromSnapshot = function(data, options) { options = options || {}; options.seed = data; return new Article(options); }; // Define available views // -------- Article.views = ["content", "figures", "citations", "definitions", "info"]; // Register node types // -------- Article.nodeTypes = require("./nodes"); Article.ViewFactory = require('./view_factory'); // HACK: ResourceView is only used as a mixin for resource view implementations // There is no specific model for it, thus can not be registered in nodeTypes Article.ResourceView = require('./resource_view'); // From article definitions generate a nice reference document // -------- // var ARTICLE_DOC_SEED = { "id": "lens_article", "nodes": { "document": { "type": "document", "id": "document", "views": [ "content" ], "title": "The Anatomy of a Lens Article", "authors": ["contributor_1", "contributor_2", "contributor_3"], "guid": "lens_article" }, "content": { "type": "view", "id": "content", "nodes": [ "cover", ] }, "cover": { "id": "cover", "type": "cover" }, "contributor_1": { "id": "contributor_1", "type": "contributor", "name": "Michael Aufreiter" }, "contributor_2": { "id": "contributor_2", "type": "contributor", "name": "Ivan Grubisic" }, "contributor_3": { "id": "contributor_3", "type": "contributor", "name": "Rebecca Close" } } }; Article.describe = function() { var doc = new Article({seed: ARTICLE_DOC_SEED}); var id = 0; _.each(Article.nodeTypes, function(nodeType) { nodeType = nodeType.Model; // Create a heading for each node type var headingId = "heading_"+nodeType.type.id; doc.create({ id: headingId, type: "heading", content: nodeType.description.name, level: 1 }); // Turn remarks and description into an introduction paragraph var introText = nodeType.description.remarks.join(' '); var introId = "text_"+nodeType.type.id+"_intro"; doc.create({ id: introId, type: "text", content: introText, }); // Show it in the content view doc.show("content", [headingId, introId], -1); // Include property description // -------- // doc.create({ id: headingId+"_properties", type: "text", content: nodeType.description.name+ " uses the following properties:" }); doc.show("content", [headingId+"_properties"], -1); var items = []; _.each(nodeType.description.properties, function(propertyDescr, key) { var listItemId = "text_" + (++id); doc.create({ id: listItemId, type: "text", content: key +": " + propertyDescr }); // Create code annotation for the propertyName doc.create({ "id": id+"_annotation", "type": "code", "path": [listItemId, "content"], "range":[0, key.length] }); items.push(listItemId); }); // Create list doc.create({ id: headingId+"_property_list", type: "list", items: items, ordered: false }); // And show it doc.show("content", [headingId+"_property_list"], -1); // Include example // -------- // doc.create({ id: headingId+"_example", type: "text", content: "Here's an example:" }); doc.create({ id: headingId+"_example_codeblock", type: "codeblock", content: JSON.stringify(nodeType.example, null, ' '), }); doc.show("content", [headingId+"_example", headingId+"_example_codeblock"], -1); }); return doc; }; Article.Prototype.prototype = Document.prototype; Article.prototype = new Article.Prototype(); Article.prototype.constructor = Article; // Add convenience accessors for builtin document attributes Object.defineProperties(Article.prototype, { id: { get: function () { return this.get("document").guid; }, set: function(id) { this.get("document").guid = id; } }, creator: { get: function () { return this.get("document").creator; }, set: function(creator) { this.get("document").creator = creator; } }, created_at: { get: function () { return this.get("document").created_at; }, set: function(created_at) { this.get("document").created_at = created_at; } }, title: { get: function () { return this.get("document").title; }, set: function(title) { this.get("document").title = title; } }, abstract: { get: function () { return this.get("document").abstract; }, set: function(abstract) { this.get("document").abstract = abstract; } }, on_behalf_of: { get: function () { return this.get("document").on_behalf_of; }, set: function(on_behalf_of) { this.get("document").on_behalf_of = on_behalf_of; } }, authors: { get: function () { var docNode = this.get("document"); if (docNode.authors) { return _.map(docNode.authors, function(contributorId) { return this.get(contributorId); }, this); } else { return ""; } }, set: function(val) { var docNode = this.get("document"); docNode.authors = _.clone(val); } }, views: { get: function () { // Note: returing a copy to avoid inadvertent changes return this.get("document").views.slice(0); } }, }); module.exports = Article;