index.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. (function toggleColorModes(){
  2. const light = 'lit';
  3. const dark = 'dim';
  4. const storageKey = 'colorMode';
  5. const key = '--color-mode';
  6. const data = 'data-mode';
  7. const bank = window.localStorage;
  8. function currentMode() {
  9. let acceptableChars = light + dark;
  10. acceptableChars = [...acceptableChars];
  11. let mode = getComputedStyle(doc).getPropertyValue(key).replace(/\"/g, '').trim();
  12. mode = [...mode].filter(function(letter){
  13. return acceptableChars.includes(letter);
  14. });
  15. return mode.join('');
  16. }
  17. function changeMode(isDarkMode) {
  18. if(isDarkMode) {
  19. bank.setItem(storageKey, light)
  20. elemAttribute(doc, data, light);
  21. } else {
  22. bank.setItem(storageKey, dark);
  23. elemAttribute(doc, data, dark);
  24. }
  25. }
  26. function setUserColorMode(mode = false) {
  27. const isDarkMode = currentMode() == dark;
  28. const storedMode = bank.getItem(storageKey);
  29. if(storedMode) {
  30. if(mode) {
  31. changeMode(isDarkMode);
  32. } else {
  33. elemAttribute(doc, data, storedMode);
  34. }
  35. } else {
  36. if(mode === true) {
  37. changeMode(isDarkMode)
  38. }
  39. }
  40. }
  41. setUserColorMode();
  42. doc.addEventListener('click', function(event) {
  43. let target = event.target;
  44. let modeClass = 'color_choice';
  45. let animateClass = 'color_animate';
  46. let isModeToggle = containsClass(target, modeClass);
  47. if(isModeToggle) {
  48. pushClass(target, animateClass);
  49. setUserColorMode(true);
  50. }
  51. });
  52. })();
  53. function fileClosure(){
  54. (function updateDate() {
  55. const date = new Date();
  56. const year = date.getFullYear();
  57. const yearEl = elem('.year');
  58. yearEl ? yearEl.innerHTML = year : false;
  59. })();
  60. (function makeExternalLinks(){
  61. let links = elems('a');
  62. if(links) {
  63. Array.from(links).forEach(function(link){
  64. let target, rel, blank, noopener, attr1, attr2, url, isExternal;
  65. url = elemAttribute(link, 'href');
  66. isExternal = (url && typeof url == 'string' && url.startsWith('http')) && !url.startsWith(parentURL) ? true : false;
  67. if(isExternal) {
  68. target = 'target';
  69. rel = 'rel';
  70. blank = '_blank';
  71. noopener = 'noopener';
  72. attr1 = elemAttribute(link, target);
  73. attr2 = elemAttribute(link, noopener);
  74. attr1 ? false : elemAttribute(link, target, blank);
  75. attr2 ? false : elemAttribute(link, rel, noopener);
  76. }
  77. });
  78. }
  79. })();
  80. let headingNodes = [], results, link, icon, current, id,
  81. tags = ['h2', 'h3', 'h4', 'h5', 'h6'];
  82. current = document.URL;
  83. tags.forEach(function(tag){
  84. const article = elem('.post_content');
  85. if (article) {
  86. results = article.getElementsByTagName(tag);
  87. Array.prototype.push.apply(headingNodes, results);
  88. }
  89. });
  90. headingNodes.forEach(function(node){
  91. link = createEl('a');
  92. loadSvg('link', link);
  93. link.className = 'link icon';
  94. id = node.getAttribute('id');
  95. if(id) {
  96. link.href = `${current}#${id}`;
  97. node.appendChild(link);
  98. pushClass(node, 'link_owner');
  99. }
  100. });
  101. let inlineListItems = elems('ol li');
  102. if(inlineListItems) {
  103. inlineListItems.forEach(function(listItem){
  104. let firstChild = listItem.children[0]
  105. let containsHeading = isMatch(firstChild, tags);
  106. containsHeading ? pushClass(listItem, 'align') : false;
  107. })
  108. }
  109. function copyFeedback(parent) {
  110. const copyText = document.createElement('div');
  111. const yanked = 'link_yanked';
  112. copyText.classList.add(yanked);
  113. copyText.innerText = 'Link Copied';
  114. if(!elem(`.${yanked}`, parent)) {
  115. parent.appendChild(copyText);
  116. setTimeout(function() {
  117. parent.removeChild(copyText)
  118. }, 3000);
  119. }
  120. }
  121. (function copyHeadingLink() {
  122. let deeplink, deeplinks, newLink, parent, target;
  123. deeplink = 'link';
  124. deeplinks = elems(`.${deeplink}`);
  125. if(deeplinks) {
  126. document.addEventListener('click', function(event)
  127. {
  128. target = event.target;
  129. parent = target.parentNode;
  130. if (target && containsClass(target, deeplink) || containsClass(parent, deeplink)) {
  131. event.preventDefault();
  132. newLink = target.href != undefined ? target.href : target.parentNode.href;
  133. copyToClipboard(newLink);
  134. target.href != undefined ? copyFeedback(target) : copyFeedback(target.parentNode);
  135. }
  136. });
  137. }
  138. })();
  139. (function copyLinkToShare() {
  140. let copy, copied, excerpt, isCopyIcon, isInExcerpt, link, postCopy, postLink, target;
  141. copy = 'copy';
  142. copied = 'copy_done';
  143. excerpt = 'excerpt';
  144. postCopy = 'post_copy';
  145. postLink = 'post_card';
  146. doc.addEventListener('click', function(event) {
  147. target = event.target;
  148. isCopyIcon = containsClass(target, copy);
  149. let isWithinCopyIcon = target.closest(`.${copy}`);
  150. if (isCopyIcon || isWithinCopyIcon) {
  151. let icon = isCopyIcon ? isCopyIcon : isWithinCopyIcon;
  152. isInExcerpt = containsClass(icon, postCopy);
  153. if (isInExcerpt) {
  154. link = target.closest(`.${excerpt}`).previousElementSibling;
  155. link = containsClass(link, postLink)? elemAttribute(link, 'href') : false;
  156. } else {
  157. link = window.location.href;
  158. }
  159. if(link) {
  160. copyToClipboard(link);
  161. pushClass(icon, copied);
  162. }
  163. }
  164. const yankLink = '.link_yank';
  165. const isCopyLink = target.matches(yankLink);
  166. const isCopyLinkIcon = target.closest(yankLink);
  167. if(isCopyLink || isCopyLinkIcon) {
  168. event.preventDefault();
  169. const yankContent = isCopyLinkIcon ? elemAttribute(target.closest(yankLink), 'href') : elemAttribute(target, 'href');
  170. copyToClipboard(yankContent);
  171. isCopyLink ? copyFeedback(target) : copyFeedback(target.parentNode);
  172. }
  173. });
  174. })();
  175. (function hideAside(){
  176. let aside, title, posts;
  177. aside = elem('.aside');
  178. title = aside ? aside.previousElementSibling : null;
  179. if(aside && title.nodeName.toLowerCase() === 'h3') {
  180. posts = Array.from(aside.children);
  181. posts.length < 1 ? title.remove() : false;
  182. }
  183. })();
  184. (function goBack() {
  185. let backBtn = elem('.btn_back');
  186. let history = window.history;
  187. if (backBtn) {
  188. backBtn.addEventListener('click', function(){
  189. history.back();
  190. });
  191. }
  192. })();
  193. function showingImagePosition(){
  194. // whether or not to track image position for non-linear images within the article body element.
  195. const thisPage = document.documentElement;
  196. let showImagePositionOnPage = thisPage.dataset.figures;
  197. if(showImagePositionOnPage) {
  198. showImagePosition = showImagePositionOnPage;
  199. }
  200. return showImagePosition === "true" ? true : false;
  201. }
  202. function largeImages(baseParent, images = []) {
  203. if(images) {
  204. images.forEach(function(image) {
  205. image.addEventListener('load', function(){
  206. let actualWidth = image.naturalWidth;
  207. let parentWidth = baseParent.offsetWidth;
  208. let actionableRatio = actualWidth / parentWidth;
  209. if (actionableRatio > 1) {
  210. pushClass(image, "image-scalable");
  211. image.dataset.scale = actionableRatio;
  212. let figure = createEl('figure');
  213. wrapEl(image, figure)
  214. }
  215. });
  216. })
  217. }
  218. }
  219. doc.addEventListener('click', function(event) {
  220. let target = event.target;
  221. isClickableImage = target.matches('.image-scalable');
  222. let isFigure = target.matches('figure');
  223. if(isFigure) {
  224. let hasClickableImage = containsClass(target.children[0], 'image-scalable');
  225. if(hasClickableImage) {
  226. modifyClass(target, 'image-scale');
  227. }
  228. }
  229. if(isClickableImage) {
  230. let figure = target.parentNode;
  231. modifyClass(figure, 'image-scale');
  232. }
  233. });
  234. const tables = elems('table');
  235. if (tables) {
  236. const scrollable = 'scrollable';
  237. tables.forEach(function(table) {
  238. const wrapper = createEl();
  239. wrapper.className = scrollable;
  240. wrapEl(table, wrapper);
  241. });
  242. }
  243. function toggleTags(target = null) {
  244. const tagsButtonClass = 'post_tags_toggle';
  245. const tagsButtonClass2 = 'tags_hide';
  246. const tagsShowClass = 'jswidgetopen';
  247. const postTagsWrapper = elem(`.${tagsShowClass}`);
  248. target = target === null ? postTagsWrapper : target;
  249. const showingAllTags = target.matches(`.${tagsShowClass}`);
  250. const isExandButton = target.matches(`.${tagsButtonClass}`);
  251. const isCloseButton = target.matches(`.${tagsButtonClass2}`) || target.closest(`.${tagsButtonClass2}`);
  252. const isButton = isExandButton || isCloseButton;
  253. const isActionable = isButton || showingAllTags;
  254. if(isActionable) {
  255. if(isButton) {
  256. if(isExandButton) {
  257. let allTagsWrapper = target.nextElementSibling
  258. pushClass(allTagsWrapper, tagsShowClass);
  259. } else {
  260. deleteClass(postTagsWrapper, tagsShowClass);
  261. }
  262. } else {
  263. isActionable ? deleteClass(target, tagsShowClass) : false;
  264. }
  265. }
  266. }
  267. (function showAllPostTags(){
  268. doc.addEventListener('click', function(event){
  269. const target = event.target;
  270. toggleTags(target)
  271. });
  272. horizontalSwipe(doc, toggleTags, 'left');
  273. })();
  274. (function navToggle() {
  275. doc.addEventListener('click', function(event){
  276. const target = event.target;
  277. const open = 'jsopen';
  278. const navCloseIconClass = '.nav_close';
  279. const navClose = elem(navCloseIconClass);
  280. const isNavToggle = target.matches(navCloseIconClass) || target.closest(navCloseIconClass);
  281. const harmburgerIcon = navClose.firstElementChild.firstElementChild;
  282. if(isNavToggle) {
  283. event.preventDefault();
  284. modifyClass(doc, open);
  285. modifyClass(harmburgerIcon, 'isopen');
  286. }
  287. if(!target.closest('.nav') && elem(`.${open}`)) {
  288. modifyClass(doc, open);
  289. let navIsOpen = containsClass(doc, open);
  290. !navIsOpen ? modifyClass(harmburgerIcon, 'isopen') : false;
  291. }
  292. const navItem = 'nav_item';
  293. const navSub = 'nav_sub';
  294. const showSub = 'nav_open';
  295. const isNavItem = target.matches(`.${navItem}`);
  296. const isNavItemIcon = target.closest(`.${navItem}`)
  297. if(isNavItem || isNavItemIcon) {
  298. const thisItem = isNavItem ? target : isNavItemIcon;
  299. const hasNext = thisItem.nextElementSibling
  300. const hasSubNav = hasNext ? hasNext.matches(`.${navSub}`) : null;
  301. if (hasSubNav) {
  302. event.preventDefault();
  303. Array.from(thisItem.parentNode.parentNode.children).forEach(function(item){
  304. const targetItem = item.firstElementChild;
  305. targetItem != thisItem ? deleteClass(targetItem, showSub) : false;
  306. });
  307. modifyClass(thisItem, showSub);
  308. }
  309. }
  310. });
  311. })();
  312. function isMobileDevice() {
  313. const agent = navigator.userAgent.toLowerCase();
  314. const isMobile = agent.includes('android') || agent.includes('iphone');
  315. return isMobile;
  316. };
  317. (function ifiOS(){
  318. // modify backto top button
  319. const backToTopButton = elem('.to_top');
  320. const thisOS = getMobileOperatingSystem();
  321. const ios = 'ios';
  322. if(backToTopButton && thisOS === 'iOS') {
  323. pushClass(backToTopButton, ios);
  324. }
  325. if(!isMobileDevice()){
  326. backToTopButton.style.right = `100px`;
  327. }
  328. })();
  329. (function sortTags() {
  330. doc.addEventListener('click', function(event){
  331. const active = 'active';
  332. const target = event.target;
  333. const isSortButton = target.matches('.tags_sort') || target.matches('.tags_sort span');
  334. if(isSortButton) {
  335. const tagsList = target.closest('.tags_list');
  336. const sortButton = elem('.tags_sort', tagsList);
  337. modifyClass(sortButton, 'sorted');
  338. const tags = elems('.post_tag', tagsList);
  339. Array.from(tags).forEach(function(tag){
  340. const order = tag.dataset.position;
  341. const reverseSorting = containsClass(tag, active);
  342. tag.style.order = reverseSorting ? 0 : -order;
  343. modifyClass(tag, active);
  344. })
  345. }
  346. })
  347. })();
  348. (function shareViaLinkedin() {
  349. doc.addEventListener('click', function(event){
  350. const linkedin = '.linkedin';
  351. const target = event.target;
  352. if(target.matches(linkedin) || target.closest(linkedin)) {
  353. window.open('http://www.linkedin.com/shareArticle?mini=true&url='+encodeURIComponent(window.location.href), '', 'left=0,top=0,width=650,height=420,personalbar=0,toolbar=0,scrollbars=0,resizable=0');
  354. }
  355. });
  356. })();
  357. // add new code above this line
  358. }
  359. window.addEventListener('load', fileClosure());