You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

518 lines
16 KiB

  1. // Generated by CoffeeScript 1.6.3
  2. var CSON, DocumentModel, FileModel, TaskGroup, YAML, eachr, extendr, extractOptsAndCallback, mime, pathUtil, _ref,
  3. __hasProp = {}.hasOwnProperty,
  4. __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  5. __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
  6. pathUtil = require('path');
  7. extendr = require('extendr');
  8. eachr = require('eachr');
  9. TaskGroup = require('taskgroup').TaskGroup;
  10. mime = require('mime');
  11. extractOptsAndCallback = require('extract-opts').extractOptsAndCallback;
  12. CSON = null;
  13. YAML = null;
  14. FileModel = require('./file');
  15. DocumentModel = (function(_super) {
  16. __extends(DocumentModel, _super);
  17. function DocumentModel() {
  18. _ref = DocumentModel.__super__.constructor.apply(this, arguments);
  19. return _ref;
  20. }
  21. DocumentModel.prototype.klass = DocumentModel;
  22. DocumentModel.prototype.type = 'document';
  23. DocumentModel.prototype.defaults = {
  24. referencesOthers: false,
  25. header: null,
  26. parser: null,
  27. body: null,
  28. rendered: false,
  29. contentRendered: null,
  30. contentRenderedWithoutLayouts: null,
  31. dynamic: false,
  32. tags: null,
  33. renderSingleExtensions: false
  34. };
  35. DocumentModel.prototype.getOutContent = function() {
  36. var content;
  37. content = this.get('contentRendered') || this.getContent();
  38. return content;
  39. };
  40. DocumentModel.prototype.referencesOthers = function(flag) {
  41. if (flag == null) {
  42. flag = true;
  43. }
  44. this.set({
  45. referencesOthers: flag
  46. });
  47. return this;
  48. };
  49. DocumentModel.prototype.parse = function(opts, next) {
  50. var buffer, key, meta, reset, value, _ref1, _ref2,
  51. _this = this;
  52. if (opts == null) {
  53. opts = {};
  54. }
  55. _ref1 = extractOptsAndCallback(opts, next), opts = _ref1[0], next = _ref1[1];
  56. buffer = this.getBuffer();
  57. meta = this.getMeta();
  58. reset = {};
  59. _ref2 = meta.attributes;
  60. for (key in _ref2) {
  61. if (!__hasProp.call(_ref2, key)) continue;
  62. value = _ref2[key];
  63. reset[key] = this.defaults[key];
  64. }
  65. reset = extendr.dereference(reset);
  66. this.set(reset);
  67. meta.clear();
  68. DocumentModel.__super__.parse.call(this, opts, function() {
  69. var body, content, err, header, ignored, match, metaData, metaDate, metaUrl, metaUrls, parser, regex, seperator;
  70. content = _this.get('content').replace(/\r\n?/gm, '\n');
  71. regex = /^\s*(([^\s\d\w])\2{2,})(?:\x20*([a-z]+))?([\s\S]*?)\1/;
  72. match = regex.exec(content);
  73. metaData = {};
  74. if (match) {
  75. seperator = match[1];
  76. parser = match[3] || 'yaml';
  77. header = match[4].trim();
  78. body = content.substring(match[0].length).trim();
  79. try {
  80. switch (parser) {
  81. case 'cson':
  82. case 'coffee':
  83. case 'coffeescript':
  84. case 'coffee-script':
  85. if (!CSON) {
  86. CSON = require('cson');
  87. }
  88. metaData = CSON.parseSync(header);
  89. meta.set(metaData);
  90. break;
  91. case 'yaml':
  92. if (!YAML) {
  93. YAML = require('yamljs');
  94. }
  95. metaData = YAML.parse(header.replace(/\t/g, ' '));
  96. meta.set(metaData);
  97. break;
  98. default:
  99. err = new Error("Unknown meta parser: " + parser);
  100. return next(err);
  101. }
  102. } catch (_error) {
  103. err = _error;
  104. return next(err);
  105. }
  106. } else {
  107. body = content;
  108. }
  109. if (metaData.encoding && metaData.encoding !== _this.get('encoding')) {
  110. _this.setMeta({
  111. encoding: metaData.encoding
  112. });
  113. opts.reencode = true;
  114. return _this.parse(opts, next);
  115. }
  116. body = body.replace(/^\n+/, '');
  117. _this.set({
  118. source: content,
  119. content: body,
  120. header: header,
  121. body: body,
  122. parser: parser,
  123. name: _this.get('name') || _this.get('title') || _this.get('basename')
  124. });
  125. metaDate = meta.get('date');
  126. if (metaDate) {
  127. metaDate = new Date(metaDate);
  128. meta.set({
  129. date: metaDate
  130. });
  131. }
  132. ignored = meta.get('ignored') || meta.get('ignore') || meta.get('skip') || meta.get('draft') || (meta.get('published') === false);
  133. if (ignored) {
  134. meta.set({
  135. ignored: true
  136. });
  137. }
  138. metaUrls = meta.get('urls');
  139. metaUrl = meta.get('url');
  140. if (metaUrls) {
  141. _this.addUrl(metaUrls);
  142. }
  143. if (metaUrl) {
  144. _this.addUrl(metaUrl);
  145. }
  146. _this.set(meta.toJSON());
  147. return next();
  148. });
  149. return this;
  150. };
  151. DocumentModel.prototype.normalize = function(opts, next) {
  152. var changes, extensions, filename, meta, outExtension, _ref1;
  153. if (opts == null) {
  154. opts = {};
  155. }
  156. _ref1 = extractOptsAndCallback(opts, next), opts = _ref1[0], next = _ref1[1];
  157. changes = {};
  158. meta = this.getMeta();
  159. outExtension = opts.outExtension || meta.get('outExtension') || null;
  160. filename = opts.filename || this.get('filename') || null;
  161. extensions = this.getExtensions({
  162. filename: filename
  163. }) || null;
  164. if (!outExtension) {
  165. changes.outExtension = outExtension = extensions[0] || null;
  166. }
  167. DocumentModel.__super__.normalize.call(this, extendr.extend(opts, changes), next);
  168. return this;
  169. };
  170. DocumentModel.prototype.contextualize = function(opts, next) {
  171. var _ref1,
  172. _this = this;
  173. if (opts == null) {
  174. opts = {};
  175. }
  176. _ref1 = extractOptsAndCallback(opts, next), opts = _ref1[0], next = _ref1[1];
  177. this.getEve(function(err, eve) {
  178. var changes, extensions, meta, outExtension, outFilename, outPath;
  179. if (err) {
  180. return next(err);
  181. }
  182. changes = {};
  183. meta = _this.getMeta();
  184. outFilename = opts.outFilename || meta.get('outFilename') || null;
  185. outPath = opts.outPath || meta.get('outPath') || null;
  186. outExtension = opts.outExtension || meta.get('outExtension') || null;
  187. extensions = _this.getExtensions({
  188. filename: outFilename
  189. }) || null;
  190. if (!outExtension) {
  191. if (!outFilename && !outPath) {
  192. if (eve != null) {
  193. changes.outExtension = outExtension = eve.get('outExtension') || extensions[0] || null;
  194. } else {
  195. changes.outExtension = extensions[0] || null;
  196. }
  197. }
  198. }
  199. return _this.normalize(extendr.extend(opts, changes), next);
  200. });
  201. return this;
  202. };
  203. DocumentModel.prototype.hasLayout = function() {
  204. return this.get('layout') != null;
  205. };
  206. DocumentModel.prototype.getLayout = function(next) {
  207. var file, layoutSelector;
  208. file = this;
  209. layoutSelector = this.get('layout');
  210. if (!layoutSelector) {
  211. return next(null, null);
  212. }
  213. this.emit('getLayout', {
  214. selector: layoutSelector
  215. }, function(err, opts) {
  216. var layout;
  217. layout = opts.layout;
  218. if (err) {
  219. file.set({
  220. 'layoutId': null
  221. });
  222. return next(err);
  223. } else if (!layout) {
  224. file.set({
  225. 'layoutId': null
  226. });
  227. err = new Error("Could not find the specified layout: " + layoutSelector);
  228. return next(err);
  229. } else {
  230. file.set({
  231. 'layoutId': layout.id
  232. });
  233. return next(null, layout);
  234. }
  235. });
  236. return this;
  237. };
  238. DocumentModel.prototype.getEve = function(next) {
  239. if (this.hasLayout()) {
  240. this.getLayout(function(err, layout) {
  241. if (err) {
  242. return next(err, null);
  243. } else {
  244. return layout.getEve(next);
  245. }
  246. });
  247. } else {
  248. next(null, this);
  249. }
  250. return this;
  251. };
  252. DocumentModel.prototype.renderExtensions = function(opts, next) {
  253. var content, extension, extensions, extensionsReversed, file, filename, renderSingleExtensions, result, tasks, templateData, _i, _len, _ref1;
  254. file = this;
  255. _ref1 = extractOptsAndCallback(opts, next), opts = _ref1[0], next = _ref1[1];
  256. content = opts.content, templateData = opts.templateData, renderSingleExtensions = opts.renderSingleExtensions;
  257. extensions = this.get('extensions');
  258. filename = this.get('filename');
  259. if (content == null) {
  260. content = this.get('body');
  261. }
  262. if (templateData == null) {
  263. templateData = {};
  264. }
  265. if (renderSingleExtensions == null) {
  266. renderSingleExtensions = this.get('renderSingleExtensions');
  267. }
  268. result = content;
  269. extensionsReversed = [];
  270. if (extensions.length === 0 && filename) {
  271. extensionsReversed.push(filename);
  272. }
  273. for (_i = 0, _len = extensions.length; _i < _len; _i++) {
  274. extension = extensions[_i];
  275. extensionsReversed.unshift(extension);
  276. }
  277. if (renderSingleExtensions && extensionsReversed.length === 1) {
  278. if (renderSingleExtensions !== 'auto' || filename.replace(/^\./, '') === extensionsReversed[0]) {
  279. extensionsReversed.push(null);
  280. }
  281. }
  282. if (extensionsReversed.length <= 1) {
  283. return next(null, result);
  284. }
  285. tasks = new TaskGroup().once('complete', function(err) {
  286. return next(err, result);
  287. });
  288. eachr(extensionsReversed.slice(1), function(extension, index) {
  289. return tasks.addTask(function(complete) {
  290. var eventData;
  291. eventData = {
  292. inExtension: extensionsReversed[index],
  293. outExtension: extension,
  294. templateData: templateData,
  295. file: file,
  296. content: result
  297. };
  298. return file.trigger('render', eventData, function(err) {
  299. var message;
  300. if (err) {
  301. return complete(err);
  302. }
  303. if (result && result === eventData.content) {
  304. message = "\n Rendering the extension \"" + eventData.inExtension + "\" to \"" + eventData.outExtension + "\" on \"" + file.attributes.relativePath + "\" didn't do anything.\n Explanation here: http://docpad.org/extension-not-rendering";
  305. file.log('warn', message);
  306. return complete();
  307. }
  308. result = eventData.content;
  309. return complete();
  310. });
  311. });
  312. });
  313. tasks.run();
  314. return this;
  315. };
  316. DocumentModel.prototype.renderDocument = function(opts, next) {
  317. var content, eventData, extension, file, templateData, _ref1;
  318. file = this;
  319. _ref1 = extractOptsAndCallback(opts, next), opts = _ref1[0], next = _ref1[1];
  320. content = opts.content, templateData = opts.templateData;
  321. extension = this.get('extensions')[0];
  322. if (content == null) {
  323. content = this.get('body');
  324. }
  325. if (templateData == null) {
  326. templateData = {};
  327. }
  328. eventData = {
  329. extension: extension,
  330. templateData: templateData,
  331. file: file,
  332. content: content
  333. };
  334. file.trigger('renderDocument', eventData, function(err) {
  335. return next(err, eventData.content);
  336. });
  337. return this;
  338. };
  339. DocumentModel.prototype.renderLayouts = function(opts, next) {
  340. var content, file, templateData, _ref1;
  341. file = this;
  342. _ref1 = extractOptsAndCallback(opts, next), opts = _ref1[0], next = _ref1[1];
  343. content = opts.content, templateData = opts.templateData;
  344. if (content == null) {
  345. content = this.get('body');
  346. }
  347. if (templateData == null) {
  348. templateData = {};
  349. }
  350. return file.getLayout(function(err, layout) {
  351. if (err) {
  352. return next(err, content);
  353. }
  354. if (layout) {
  355. templateData.content = content;
  356. return layout.render({
  357. templateData: templateData
  358. }, function(err, result) {
  359. return next(err, result);
  360. });
  361. } else {
  362. return next(null, content);
  363. }
  364. });
  365. };
  366. DocumentModel.prototype.render = function(opts, next) {
  367. var contentRenderedWithoutLayouts, file, relativePath, tasks, _base, _base1, _ref1;
  368. if (opts == null) {
  369. opts = {};
  370. }
  371. file = this;
  372. _ref1 = extractOptsAndCallback(opts, next), opts = _ref1[0], next = _ref1[1];
  373. opts = extendr.clone(opts || {});
  374. if (opts.actions == null) {
  375. opts.actions = ['renderExtensions', 'renderDocument', 'renderLayouts'];
  376. }
  377. contentRenderedWithoutLayouts = null;
  378. relativePath = this.get('relativePath');
  379. if (opts.content == null) {
  380. opts.content = this.get('body');
  381. }
  382. opts.templateData = extendr.clone(opts.templateData || {});
  383. if ((_base = opts.templateData).document == null) {
  384. _base.document = file.toJSON();
  385. }
  386. if ((_base1 = opts.templateData).documentModel == null) {
  387. _base1.documentModel = file;
  388. }
  389. file.log('debug', "Rendering the file: " + relativePath);
  390. tasks = new TaskGroup().once('complete', function(err) {
  391. var contentRendered, rendered;
  392. if (err) {
  393. file.log('warn', "Something went wrong while rendering: " + relativePath);
  394. return next(err, opts.content, file);
  395. }
  396. contentRendered = opts.content;
  397. if (contentRenderedWithoutLayouts == null) {
  398. contentRenderedWithoutLayouts = contentRendered;
  399. }
  400. rendered = true;
  401. file.set({
  402. contentRendered: contentRendered,
  403. contentRenderedWithoutLayouts: contentRenderedWithoutLayouts,
  404. rendered: rendered
  405. });
  406. file.log('debug', "Rendering completed for: " + relativePath);
  407. return next(null, opts.content, file);
  408. });
  409. if (__indexOf.call(opts.actions, 'renderExtensions') >= 0) {
  410. tasks.addTask(function(complete) {
  411. return file.renderExtensions(opts, function(err, result) {
  412. if (err) {
  413. return complete(err);
  414. }
  415. opts.content = result;
  416. return complete();
  417. });
  418. });
  419. }
  420. if (__indexOf.call(opts.actions, 'renderDocument') >= 0) {
  421. tasks.addTask(function(complete) {
  422. return file.renderDocument(opts, function(err, result) {
  423. if (err) {
  424. return complete(err);
  425. }
  426. opts.content = result;
  427. contentRenderedWithoutLayouts = result;
  428. return complete();
  429. });
  430. });
  431. }
  432. if (__indexOf.call(opts.actions, 'renderLayouts') >= 0) {
  433. tasks.addTask(function(complete) {
  434. return file.renderLayouts(opts, function(err, result) {
  435. if (err) {
  436. return complete(err);
  437. }
  438. opts.content = result;
  439. return complete();
  440. });
  441. });
  442. }
  443. tasks.run();
  444. return this;
  445. };
  446. DocumentModel.prototype.writeRendered = function(opts, next) {
  447. var file, _ref1;
  448. _ref1 = extractOptsAndCallback(opts, next), opts = _ref1[0], next = _ref1[1];
  449. file = this;
  450. opts.content || (opts.content = this.getOutContent());
  451. opts.type || (opts.type = 'rendered document');
  452. this.write(opts, next);
  453. return this;
  454. };
  455. DocumentModel.prototype.writeSource = function(opts, next) {
  456. var body, content, file, fullPath, header, meta, metaData, parser, seperator, source, _ref1;
  457. file = this;
  458. _ref1 = extractOptsAndCallback(opts, next), opts = _ref1[0], next = _ref1[1];
  459. meta = this.getMeta();
  460. if (!CSON) {
  461. CSON = require('cson');
  462. }
  463. fullPath = this.get('fullPath');
  464. content = (this.getContent() || '').toString();
  465. parser = 'cson';
  466. seperator = '---';
  467. file.log('debug', "Writing the source file: " + fullPath);
  468. metaData = meta.toJSON();
  469. header = CSON.stringifySync(metaData);
  470. content = body = content.replace(/^\s+/, '');
  471. source = "" + seperator + " " + parser + "\n" + header + "\n" + seperator + "\n\n" + body;
  472. this.set({
  473. parser: parser,
  474. header: header,
  475. body: body,
  476. content: content,
  477. source: source
  478. });
  479. opts.path || (opts.path = fullPath);
  480. opts.content || (opts.content = content);
  481. opts.type || (opts.type = 'source document');
  482. this.write(opts, next);
  483. return this;
  484. };
  485. return DocumentModel;
  486. })(FileModel);
  487. module.exports = DocumentModel;