Add article menu item

This user script will add menu options to to each article in BuildWise.

  1. // ==UserScript==
  2. // @name Add article menu item
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0.4
  5. // @description This user script will add menu options to to each article in BuildWise.
  6. // @author saikiran.dannana@buildwise.ai
  7. // @match *://*.buildwise.ai/*
  8. // @icon https://images.buildwise.ai/BuildWise_logo_without_name.png
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function () {
  13. 'use strict';
  14.  
  15. // Add event listeners to article menu buttons
  16. function setupMenuButtonListeners() {
  17. const menuButtons = document.querySelectorAll('.article-menu-btn');
  18. menuButtons.forEach(button => {
  19. if (!button.dataset.listenerAdded) {
  20. button.addEventListener('click', onMenuButtonClick);
  21. button.dataset.listenerAdded = true;
  22. }
  23. });
  24. }
  25.  
  26. // Find element by class and text
  27. function getElementByText(className, textContent) {
  28. return Array.from(document.querySelectorAll(`.${className}`)).find(
  29. el => el.textContent.trim() === textContent
  30. );
  31. }
  32.  
  33. // Handle menu button click
  34. function onMenuButtonClick() {
  35. setTimeout(() => {
  36. const menuContainer = document.getElementById('menu-list-container');
  37. const menuItemTemplate = document.querySelector('.menu-list-item');
  38.  
  39. if (!menuContainer || !menuItemTemplate) return;
  40.  
  41. const newItems = [
  42. {
  43. icon: `
  44. <svg width="17" height="17" viewBox="0 0 25 25" fill="none" xmlns="http://www.w3.org/2000/svg">
  45. <path d="M5.44019 2.97528C4.7482 3.04007 4.12246 3.25208 3.58948 3.60544C3.37011 3.74973 3.22435 3.86898 3.03147 4.06186C2.5353 4.5595 2.18931 5.22352 2.03913 5.96998C1.9449 6.43524 1.95226 5.89784 1.94637 12.4261C1.94343 16.7297 1.94637 18.417 1.95815 18.5878C2.01263 19.3475 2.23495 20.0306 2.61039 20.5901C2.80768 20.8831 3.12718 21.2247 3.3863 21.4176C3.94873 21.8387 4.61569 22.0963 5.35921 22.1802C5.65368 22.2126 18.4953 22.2141 18.8015 22.1802C19.5347 22.1022 20.1884 21.8563 20.7243 21.4588C21.5003 20.8816 21.9861 20.0645 22.1569 19.0442C22.2143 18.7041 22.2173 18.5745 22.2173 16.7945V15.0616L19.8822 15.0645L17.5486 15.0689L16.5282 16.8136L15.5079 18.5583H12.0067H8.50556L6.75644 15.5695L5.00586 12.5822L5.04119 12.5218C5.07653 12.4614 7.8813 7.6661 8.28471 6.97852L8.50409 6.60308H12.0067H15.5094L16.5268 8.34778L17.5441 10.0925L19.8807 10.0969L22.2173 10.0998V8.40078C22.2173 6.65314 22.2129 6.48235 22.1569 6.14224C22.0185 5.2986 21.6799 4.61839 21.1204 4.05597C20.5948 3.5274 19.9543 3.19466 19.1681 3.04007C18.7352 2.95614 19.1048 2.95909 12.0583 2.96203C8.49084 2.96203 5.51381 2.96792 5.44019 2.97528Z" fill="black"/>
  46. <path d="M10.2356 9.27804C10.2194 9.30454 9.83067 9.99212 9.37131 10.8063C8.91195 11.6205 8.49675 12.3522 8.45111 12.4332L8.36719 12.5819L9.31094 14.1779L10.2547 15.7754H12.1525H14.0503L14.9764 14.2074C15.4859 13.3446 15.9099 12.6246 15.9187 12.6084C15.932 12.5805 15.8009 12.3419 14.9882 10.9035L14.043 9.23093H12.154H10.265L10.2356 9.27804Z" fill="#EC5F2A"/>
  47. </svg>
  48. `,
  49. label: 'Send to Procore'
  50. }
  51. ];
  52.  
  53. const targetItem = getElementByText('menu-list-item', 'Bookmark');
  54.  
  55. newItems.forEach(({ icon, label }) => {
  56. const newItem = menuItemTemplate.cloneNode(true);
  57.  
  58. const svgElement = newItem.querySelector('svg');
  59. if (svgElement) svgElement.outerHTML = icon;
  60.  
  61. const textElement = newItem.querySelector('.menu-item-title');
  62. if (textElement) textElement.textContent = label;
  63.  
  64. if (targetItem?.nextSibling) {
  65. menuContainer.insertBefore(newItem, targetItem.nextSibling);
  66. } else {
  67. menuContainer.appendChild(newItem);
  68. }
  69.  
  70. newItem.addEventListener('click', onNewMenuItemClick);
  71. });
  72. }, 0);
  73. }
  74.  
  75. // Show full-screen modal with image
  76. function showImageModal(imageUrl, onClose) {
  77. const modalOverlay = document.createElement('div');
  78. Object.assign(modalOverlay.style, {
  79. position: 'fixed',
  80. top: '0',
  81. left: '0',
  82. width: '100%',
  83. height: '100%',
  84. backgroundColor: 'rgba(0, 0, 0, 0.5)',
  85. display: 'flex',
  86. justifyContent: 'center',
  87. alignItems: 'center',
  88. zIndex: '99999999',
  89. padding: '64px 0'
  90. });
  91.  
  92. const modalImage = document.createElement('img');
  93. modalImage.src = imageUrl;
  94. Object.assign(modalImage.style, {
  95. maxWidth: '100%',
  96. maxHeight: '100%',
  97. objectFit: 'contain',
  98. borderRadius: '8px'
  99. });
  100.  
  101. modalOverlay.appendChild(modalImage);
  102.  
  103. modalOverlay.addEventListener('click', () => {
  104. document.body.removeChild(modalOverlay);
  105. if (onClose) onClose();
  106. });
  107.  
  108. document.body.appendChild(modalOverlay);
  109. }
  110.  
  111. // Handle new menu item click
  112. function onNewMenuItemClick(event) {
  113. event.preventDefault();
  114. showImageModal(
  115. 'https://d3bg16e6fimkd7.cloudfront.net/Screenshot+2024-12-16+at+12.27.36%E2%80%AFPM.png',
  116. createTaskInProcore
  117. );
  118. }
  119.  
  120. // Create task in Procore
  121. function createTaskInProcore() {
  122. const token = JSON.parse(localStorage.getItem('bwAuthStorage'));
  123. if (!token?.state?.accessToken) {
  124. console.error('Access token not found');
  125. return;
  126. }
  127.  
  128. fetch('https://app.buildwise.ai/v1/api/procore/company/29274/project/1039305/task', {
  129. method: 'GET',
  130. headers: {
  131. 'Content-Type': 'application/json',
  132. Authorization: `Bearer ${token.state.accessToken}`
  133. }
  134. })
  135. .then(response => response.ok ? response.json() : Promise.reject('API call failed'))
  136. .then(data => console.log('API response:', data))
  137. .catch(error => console.error('Error:', error));
  138. }
  139.  
  140. // Monitor DOM changes
  141. const observer = new MutationObserver(setupMenuButtonListeners);
  142. observer.observe(document.body, { childList: true, subtree: true });
  143.  
  144. // Initial setup
  145. setupMenuButtonListeners();
  146. })();