RefsContext.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import * as url from 'url';
  2. import { customTagUtils, pathUtils } from 'growi-commons';
  3. const { TagContext, ArgsParser, OptionParser } = customTagUtils;
  4. /**
  5. * Context Object class for $refs() and $refsimg()
  6. */
  7. export default class RefsContext extends TagContext {
  8. /**
  9. * @param {object|TagContext|RefsContext} initArgs
  10. */
  11. constructor(initArgs, fromPagePath) {
  12. super(initArgs);
  13. this.fromPagePath = fromPagePath;
  14. // initialized after parse()
  15. this.pagePath = null;
  16. this.isParsed = null;
  17. this.options = {};
  18. }
  19. get isSingle() {
  20. return this.method.match(/^(ref|refimg)$/);
  21. }
  22. get isExtractImg() {
  23. return this.method.match(/^(refimg|refsimg)$/);
  24. }
  25. parse() {
  26. if (this.isParsed) {
  27. return;
  28. }
  29. const parsedArgs = ArgsParser.parse(this.args);
  30. this.options = parsedArgs.options;
  31. if (this.isSingle) {
  32. this.parseForSingle(parsedArgs);
  33. }
  34. else {
  35. this.parseForMulti(parsedArgs);
  36. }
  37. this.isParsed = true;
  38. }
  39. /**
  40. * parse method for 'ref' and 'refimg'
  41. */
  42. parseForSingle(parsedArgs) {
  43. // determine fileName
  44. // order:
  45. // 1: ref(file=..., ...)
  46. // 2: refs(firstArgs, ...)
  47. this.fileName = this.options.file
  48. || ((parsedArgs.firstArgsValue === true) ? parsedArgs.firstArgsKey : undefined);
  49. if (this.fileName == null) {
  50. throw new Error('fileName is not specified. set first argument or specify \'file\' option');
  51. }
  52. // determine pagePath
  53. // order:
  54. // 1: ref(page=..., ...)
  55. // 2: constructor argument
  56. const specifiedPath = this.options.page || this.fromPagePath;
  57. this.pagePath = this.getAbsolutePathFor(specifiedPath);
  58. }
  59. /**
  60. * parse method for 'refs' and 'refsimg'
  61. */
  62. parseForMulti(parsedArgs) {
  63. if (this.options.prefix) {
  64. this.prefix = this.resolvePath(this.options.prefix);
  65. }
  66. else {
  67. // determine pagePath
  68. // order:
  69. // 1: ref(page=..., ...)
  70. // 2: refs(firstArgs, ...)
  71. // 3: constructor argument
  72. const specifiedPath = this.options.page
  73. || ((parsedArgs.firstArgsValue === true) ? parsedArgs.firstArgsKey : undefined)
  74. || this.fromPagePath;
  75. this.pagePath = this.getAbsolutePathFor(specifiedPath);
  76. }
  77. }
  78. // resolve pagePath
  79. // when `fromPagePath`=/hoge and `specifiedPath`=./fuga,
  80. // `pagePath` to be /hoge/fuga
  81. // when `fromPagePath`=/hoge and `specifiedPath`=/fuga,
  82. // `pagePath` to be /fuga
  83. // when `fromPagePath`=/hoge and `specifiedPath`=undefined,
  84. // `pagePath` to be /hoge
  85. resolvePath(pagePath) {
  86. return decodeURIComponent(url.resolve(pathUtils.addTrailingSlash(this.fromPagePath), pagePath));
  87. }
  88. getOptDepth() {
  89. if (this.options.depth === undefined) {
  90. return undefined;
  91. }
  92. return OptionParser.parseRange(this.options.depth);
  93. }
  94. isOptGridColumnEnabled() {
  95. const { grid } = this.options;
  96. return (grid != null) && grid.startsWith('col-');
  97. }
  98. getOptGridWidth() {
  99. const { grid, width } = this.options;
  100. // when Grid column mode
  101. if (this.isOptGridColumnEnabled()) {
  102. // not specify and ignore width
  103. return undefined;
  104. }
  105. // when width is specified
  106. if (width != null) {
  107. return width;
  108. }
  109. // when Grid autofill mode
  110. let autofillMagnification = 1;
  111. switch (grid) {
  112. case 'autofill-4x':
  113. autofillMagnification = 4;
  114. break;
  115. case 'autofill-3x':
  116. autofillMagnification = 3;
  117. break;
  118. case 'autofill-2x':
  119. autofillMagnification = 2;
  120. break;
  121. case 'autofill':
  122. default:
  123. break;
  124. }
  125. return `${autofillMagnification * 100}px`;
  126. }
  127. getOptGridHeight() {
  128. const { height } = this.options;
  129. // when height is specified
  130. if (height != null) {
  131. return height;
  132. }
  133. // return the value which is same to width
  134. return this.getOptGridWidth();
  135. }
  136. getOptGridColumnsNum() {
  137. const { grid } = this.options;
  138. let columnsNum = null;
  139. if (grid != null) {
  140. switch (grid) {
  141. case 'col-2':
  142. columnsNum = 2;
  143. break;
  144. case 'col-3':
  145. columnsNum = 3;
  146. break;
  147. case 'col-4':
  148. columnsNum = 4;
  149. break;
  150. case 'col-5':
  151. columnsNum = 5;
  152. break;
  153. case 'col-6':
  154. columnsNum = 6;
  155. break;
  156. }
  157. }
  158. return columnsNum;
  159. }
  160. /**
  161. * return absolute path for the specified path
  162. *
  163. * @param {string} relativePath relative path from `this.fromPagePath`
  164. */
  165. getAbsolutePathFor(relativePath) {
  166. return decodeURIComponent(
  167. pathUtils.normalizePath( // normalize like /foo/bar
  168. url.resolve(pathUtils.addTrailingSlash(this.fromPagePath), relativePath)
  169. ),
  170. );
  171. }
  172. }