crowi.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /* eslint-disable react/jsx-filename-extension */
  2. require('jquery.cookie');
  3. require('./thirdparty-js/waves');
  4. const Crowi = {};
  5. if (!window) {
  6. window = {};
  7. }
  8. window.Crowi = Crowi;
  9. /**
  10. * set 'data-caret-line' attribute that will be processed when 'shown.bs.tab' event fired
  11. * @param {number} line
  12. */
  13. Crowi.setCaretLineData = function(line) {
  14. const { appContainer } = window;
  15. const navigationContainer = appContainer.getContainer('NavigationContainer');
  16. navigationContainer.setEditorMode('edit');
  17. const pageEditorDom = document.querySelector('#page-editor');
  18. pageEditorDom.setAttribute('data-caret-line', line);
  19. };
  20. /**
  21. * invoked when;
  22. *
  23. * 1. 'shown.bs.tab' event fired
  24. */
  25. Crowi.setCaretLineAndFocusToEditor = function() {
  26. // get 'data-caret-line' attributes
  27. const pageEditorDom = document.querySelector('#page-editor');
  28. if (pageEditorDom == null) {
  29. return;
  30. }
  31. const { appContainer } = window;
  32. const editorContainer = appContainer.getContainer('EditorContainer');
  33. const line = pageEditorDom.getAttribute('data-caret-line') || 0;
  34. editorContainer.setCaretLine(+line);
  35. // reset data-caret-line attribute
  36. pageEditorDom.removeAttribute('data-caret-line');
  37. // focus
  38. editorContainer.focusToEditor();
  39. };
  40. // original: middleware.swigFilter
  41. Crowi.userPicture = function(user) {
  42. if (!user) {
  43. return '/images/icons/user.svg';
  44. }
  45. return user.image || '/images/icons/user.svg';
  46. };
  47. Crowi.modifyScrollTop = function() {
  48. const offset = 10;
  49. const hash = window.location.hash;
  50. if (hash === '') {
  51. return;
  52. }
  53. const pageHeader = document.querySelector('#page-header');
  54. if (!pageHeader) {
  55. return;
  56. }
  57. const pageHeaderRect = pageHeader.getBoundingClientRect();
  58. const sectionHeader = Crowi.findSectionHeader(hash);
  59. if (sectionHeader === null) {
  60. return;
  61. }
  62. let timeout = 0;
  63. if (window.scrollY === 0) {
  64. timeout = 200;
  65. }
  66. setTimeout(() => {
  67. const sectionHeaderRect = sectionHeader.getBoundingClientRect();
  68. if (sectionHeaderRect.top >= pageHeaderRect.bottom) {
  69. return;
  70. }
  71. window.scrollTo(0, (window.scrollY - pageHeaderRect.height - offset));
  72. }, timeout);
  73. };
  74. Crowi.initClassesByOS = function() {
  75. // add classes to cmd-key by OS
  76. const platform = navigator.platform.toLowerCase();
  77. const isMac = (platform.indexOf('mac') > -1);
  78. document.querySelectorAll('.system-version .cmd-key').forEach((element) => {
  79. if (isMac) {
  80. element.classList.add('mac');
  81. }
  82. else {
  83. element.classList.add('win');
  84. }
  85. });
  86. document.querySelectorAll('#shortcuts-modal .cmd-key').forEach((element) => {
  87. if (isMac) {
  88. element.classList.add('mac');
  89. }
  90. else {
  91. element.classList.add('win', 'key-longer');
  92. }
  93. });
  94. };
  95. Crowi.findHashFromUrl = function(url) {
  96. let match;
  97. /* eslint-disable no-cond-assign */
  98. if (match = url.match(/#(.+)$/)) {
  99. return `#${match[1]}`;
  100. }
  101. /* eslint-enable no-cond-assign */
  102. return '';
  103. };
  104. Crowi.findSectionHeader = function(hash) {
  105. if (hash.length === 0) {
  106. return;
  107. }
  108. // omit '#'
  109. const id = hash.replace('#', '');
  110. // don't use jQuery and document.querySelector
  111. // because hash may containe Base64 encoded strings
  112. const elem = document.getElementById(id);
  113. if (elem != null && elem.tagName.match(/h\d+/i)) { // match h1, h2, h3...
  114. return elem;
  115. }
  116. return null;
  117. };
  118. Crowi.unhighlightSelectedSection = function(hash) {
  119. const elem = Crowi.findSectionHeader(hash);
  120. if (elem != null) {
  121. elem.classList.remove('highlighted');
  122. }
  123. };
  124. Crowi.highlightSelectedSection = function(hash) {
  125. const elem = Crowi.findSectionHeader(hash);
  126. if (elem != null) {
  127. elem.classList.add('highlighted');
  128. }
  129. };
  130. window.addEventListener('load', (e) => {
  131. const { appContainer } = window;
  132. const pageContainer = appContainer.getContainer('PageContainer');
  133. const { isAbleToOpenPageEditor } = pageContainer;
  134. // hash on page
  135. if (window.location.hash) {
  136. const navigationContainer = appContainer.getContainer('NavigationContainer');
  137. if (window.location.hash === '#edit' && isAbleToOpenPageEditor) {
  138. navigationContainer.setEditorMode('edit');
  139. // focus
  140. Crowi.setCaretLineAndFocusToEditor();
  141. }
  142. else if (window.location.hash === '#hackmd') {
  143. navigationContainer.setEditorMode('hackmd');
  144. }
  145. }
  146. });
  147. window.addEventListener('load', (e) => {
  148. const crowi = window.crowi;
  149. if (crowi && crowi.users && crowi.users.length !== 0) {
  150. const totalUsers = crowi.users.length;
  151. const $listLiker = $('.page-list-liker');
  152. $listLiker.each((i, liker) => {
  153. const count = $(liker).data('count') || 0;
  154. if (count / totalUsers > 0.05) {
  155. $(liker).addClass('popular-page-high');
  156. // 5%
  157. }
  158. else if (count / totalUsers > 0.02) {
  159. $(liker).addClass('popular-page-mid');
  160. // 2%
  161. }
  162. else if (count / totalUsers > 0.005) {
  163. $(liker).addClass('popular-page-low');
  164. // 0.5%
  165. }
  166. });
  167. const $listSeer = $('.page-list-seer');
  168. $listSeer.each((i, seer) => {
  169. const count = $(seer).data('count') || 0;
  170. if (count / totalUsers > 0.10) {
  171. // 10%
  172. $(seer).addClass('popular-page-high');
  173. }
  174. else if (count / totalUsers > 0.05) {
  175. // 5%
  176. $(seer).addClass('popular-page-mid');
  177. }
  178. else if (count / totalUsers > 0.02) {
  179. // 2%
  180. $(seer).addClass('popular-page-low');
  181. }
  182. });
  183. }
  184. Crowi.highlightSelectedSection(window.location.hash);
  185. Crowi.modifyScrollTop();
  186. Crowi.initClassesByOS();
  187. });
  188. window.addEventListener('hashchange', (e) => {
  189. Crowi.unhighlightSelectedSection(Crowi.findHashFromUrl(e.oldURL));
  190. Crowi.highlightSelectedSection(Crowi.findHashFromUrl(e.newURL));
  191. Crowi.modifyScrollTop();
  192. const { appContainer } = window;
  193. const navigationContainer = appContainer.getContainer('NavigationContainer');
  194. // hash on page
  195. if (window.location.hash) {
  196. if (window.location.hash === '#edit') {
  197. navigationContainer.setEditorMode('edit');
  198. Crowi.setCaretLineAndFocusToEditor();
  199. }
  200. else if (window.location.hash === '#hackmd') {
  201. navigationContainer.setEditorMode('hackmd');
  202. }
  203. }
  204. });
  205. // adjust min-height of page for print temporarily
  206. window.onbeforeprint = function() {
  207. $('#page-wrapper').css('min-height', '0px');
  208. };