diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index cdd95c25..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,2 +0,0 @@ -ko_fi: pegadevguy -patreon: pegadevguy diff --git a/.gitignore b/.gitignore index 709dad01..4444e30e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ resources/codemirror/htmlmixed.html resources/codemirror/javascript.html resources/codemirror/jsxjava.html clipboard.experimental.js +*.bak +devstudio/devstudio_notes.js diff --git a/.vscode/settings.json b/.vscode/settings.json index 0a156472..140a58b2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,56 @@ { "cSpell.ignoreWords": [ "filtertable", - "openlanding" + "openlanding", + "Recordkey" + ], + "cSpell.words": [ + "agilestudio", + "bgcolor", + "closetag", + "Cntr", + "codemirror", + "contextmenu", + "ctxmenu", + "datapage", + "datatransform", + "deploymentmanager", + "devstudio", + "endregion", + "foldcode", + "foldgutter", + "fullscreen", + "htmlmixed", + "Huebee", + "inanchor", + "logfile", + "Marcin", + "matchtags", + "OOTB", + "origprocess", + "pagesort", + "Pega", + "pegacloud", + "prweb", + "rightborder", + "ruleform", + "ruleset", + "rulesets", + "rulespecific", + "Subflow", + "TABANCHOR", + "TABSPAN", + "tabtitle", + "threadname", + "tracertop", + "uicolors", + "valign", + + "bsimplelayout", + "editaction", + "Leśniak", + + + "Tinycon" ] } \ No newline at end of file diff --git a/PegaDevTools.code-workspace b/PegaDevTools.code-workspace index 039756e1..8828d036 100644 --- a/PegaDevTools.code-workspace +++ b/PegaDevTools.code-workspace @@ -15,9 +15,11 @@ "codemirror", "contextmenu", "Copypz", + "copypzinskey", "datapage", "deploymentmanager", "devstudio", + "favico", "foldcode", "foldgutter", "fullscreen", @@ -29,16 +31,16 @@ "lesniak", "Leśniak", "marcin", + "Marcin", "matchtags", "nocopy", - "noopener", - "noreferrer", "ootb", + "OOTB", "pagesort", "Pega", "pegacloud", - "portalharnessinsname", "prweb", + "pzInskey", "PRXML", "Recordkey", "Ruleset", @@ -47,6 +49,7 @@ "t", "tabanchor", "threadname", + "tracertop", "Tinycon", "tooltiptext", "valign" diff --git a/README.md b/README.md index 1aeb3239..5d218b28 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,52 @@ -# **PegaDevTools (PDT)** +# **PegaDevTools** -PDT is a browser-based developer productivity tool for Pega 8, designed to enhance your development experience without the need for ruleset deployment. The extension primarily targets Chromium-based browsers (Chrome, Edge, Opera, etc.). +PDT is browser-only (i.e. no ruleset deployment is required) Pega 8 developer productivity tool. +**Check out available features in the [PDT Wiki](https://github.com/marcin-l/PegaDevTools/wiki)** -**[Explore the PDT Wiki](https://github.com/marcin-l/PegaDevTools/wiki)** to learn about the available features. +Extension development is mostly targeting chromium-based browsers, but it should for the most part work in Firefox. -## Installation -1. Download or clone the extension using the green *Code* button at the top of this page and selecting `Download ZIP` -
-1. Extract downloaded ZIP file - - -1. Load unpacked extension -- For Chrome and Edge: - - Navigate to the browser settings and click `Extensions` - - Enable `Developer mode` - - Click `Load Unpacked` and select the extracted ZIP file directory +## Issues and feature requests +Check the [Issues](https://github.com/marcin-l/PegaDevTools/issues) page to see things to be fixed and features to be implemented. -- For Firefox - - Open `about:debugging` URL - - Click the `This Firefox` button on the left - - Click the `Load Temporary Add-on...` button - - Navigate to the extracted ZIP file directory, select any file, and click *Open*. -
Please note that this method is not persistent. Extension needs to be loaded for each Firefox session. +If you found a bug or have a new idea/feature for the extension, [you can report them](https://github.com/marcin-l/PegaDevTools/issues/new). -## Post-Installation -- Go to PDT [Extension Options](https://github.com/marcin-l/PegaDevTools/wiki/Configuration). In the *Site config* section add your environment domain name (e.g. `client-dt1.pegacloud.net`, without `https://`) and click *Save site configuration*. -- Turn on features in the *Settings* section and click `Save settings`. +## How to use +- Download (or clone) the extension using green button on the top of this page +**Code -> Download ZIP** +- Unpack downloaded zip file + + + +### Chrome and Edge +- Go to Chrome/Edge settings +- Click **Extensions** +- Enable **Developer mode** +- Click on **Load Unpacked** and select your unpacked zip file directory + +### Firefox +- go to **about:debugging** URL +- click on **This Firefox** button on the left +- click on **Load Temporary Add-on...** button +- navigate your unpacked zip file directory +- select any file in the directory and click **Open** +- Please note that this method is not persistent. Extension needs to be loaded for each Firefox session. + +### Post-installation steps +- Go to [Extension Options](https://github.com/marcin-l/PegaDevTools/wiki/Configuration). In the **Site config** section add your environment by domain name (e.g. *client-dt1.pegacloud.net*, without *https://*) and click **Save site configuration**. Turn on features in the **Settings** section and click **Save settings**. - Reload your Pega tabs if needed -
Some features will not work if this step is skipped -## Updating to a New Version +### Updating - Overwrite extension with new download, your settings will be left intact - Go to Chrome/Edge settings -- Click `Extensions` +- Click **Extensions** - Reload PegaDevTools -- Check the PDT Extension Options to see if there are any new features to be enabled - -## Known Issues and Limitations -- System rules customizations in Dev Studio will stop working when a rule is refreshed (to be addressed in the future). Reopen the rule to restore customizations. -- Some features may not work when Dev Studio language is set to something other than English. Use the `ignore locale` option in user preferences as a workaround. -- Not all customizations will load if you open your application in App or Admin Studio. Set _Developer_ portal as the default for your Access Group to circumvent this issue. -- Firefox support is currently unavailable but coming soon. - -## Issue Reporting and Feature Requests -Visit the [Issues](https://github.com/marcin-l/PegaDevTools/issues) page to view pending fixes and upcoming features. +- Check the PDT Options to see if there are any new features to be enabled -If you find a bug or have a new idea/feature for the extension, feel free to [report them](https://github.com/marcin-l/PegaDevTools/issues/new). +## Known issues and limitations +- System rules customizations in Dev studio will stop working when a rule is refreshed (to be addressed in the future). Reopening the rule will restore customizations. +- Some features will not work when Dev Studio is language other than English. I recommend to use the "ignore locale" option in user preferences. +- Not all customizations will load if you open your application in App or Admin Studio. As a workaround set _Developer_ portal as default one for your Access Group. ## Credits Tracer feature to navigate to first Error and Message is based on Piotr Olejniczak's idea. @@ -57,8 +57,8 @@ Tracer feature to navigate to first Error and Message is based on Piotr Olejnicz ### Third-party libraries (MIT license) - [arrive.js](https://github.com/uzairfarooq/arrive) - [CodeMirror](https://codemirror.net/) -- [ContextmenuJS](https://github.com/m-thalmann/contextmenujs) +- [ctxmenu.js](https://github.com/nkappler/ctxmenu) - [Huebee](https://huebee.buzz) - [jQuery](https://jquery.com/) - [jQuery.FilterTable](https://github.com/sunnywalker/jQuery.FilterTable) -- [Tinycon](https://github.com/tommoor/tinycon) +- [Tinycon](https://github.com/tommoor/tinycon) \ No newline at end of file diff --git a/agilestudio/agilestudio.js b/agilestudio/agilestudio.js index ba3e0159..5814583f 100644 --- a/agilestudio/agilestudio.js +++ b/agilestudio/agilestudio.js @@ -1,5 +1,5 @@ if(window.location.href.includes("agilestudio")) { - + PDT.setScriptsApplied(); console.log("agilestudio.js"); if (PDT.isAgilestudioEnabled()) { diff --git a/background.html b/background.html new file mode 100644 index 00000000..d282da70 --- /dev/null +++ b/background.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/background.js b/background.js index eb9c5a6b..f205ba19 100644 --- a/background.js +++ b/background.js @@ -1,5 +1,12 @@ var browser = (browser) ? browser : chrome; +//TODO: modularize +// try { +// importScripts('/path/file.js', '/path2/file2.js' /*, and so on */); +// } catch (e) { +// console.error(e); +//} + function injectScript(injectedScript, tabId, frameId) { browser.scripting.executeScript({ files: [injectedScript], @@ -17,17 +24,45 @@ function appendScript(appendedScript, tabId, frameId) { } var tracerIsRunningAppended = false; + // handle content script messages -browser.runtime.onMessage.addListener(async (request, sender, sendResponse) => { +browser.runtime.onMessage.addListener(async (request, sender, sendResponse) => { console.debug(request); - if (request.purpose == "getFrameId") { + if (request.purpose == "getSettings") { + sendResponse(getSettings()); + } + else if (request.purpose == "reloadSettings") { + initSettings(); + } + else if (request.purpose == "getFrameId") sendResponse({ frameId: sender.frameId }); - } else if (request.purpose == "appendScript") { + else if (request.purpose == "appendScript") { appendScript(request.appendedScript, sender.tab.id, sender.frameId); - sendResponse("appending to tab " + sender.tab.id + " frame " + sender.frameId); + sendResponse("appending to tab " + sender.tab.id + " frame " + sender.frameId); + } else if (request.purpose == "reloadContentScripts") { + if(loadedFrames.has(sender.tab.id + "-" + sender.frameId)) { + reloadContentScripts(sender.tab.id, sender.frameId, loadedFrames.get(sender.tab.id + "-" + sender.frameId)); + sendResponse("reloading content scripts " + sender.tab.id + " frame " + sender.frameId); + } else { + console.log(sender.tab.id + "-" + sender.frameId + " not found in loadedFrames"); + } } else if (request.purpose == "injectScript") { injectScript(request.injectedScript, sender.tab.id, sender.frameId); sendResponse("injecting " + request.injectedScript + " to tab " + sender.tab.id + " frame " + sender.frameId); + } else if (request.purpose == "loaded") { + if(request.url != "about:blank" && !loadedFrames.has(sender.tab.id + "-" + sender.frameId)) { + loadedFrames.set(sender.tab.id + "-" + sender.frameId, request.url); + console.log("Registered " + sender.tab.id + "-" + sender.frameId + ": " + request.url); + } + // else { + // if(loadedFrames.has(sender.tab.id + "-" + sender.frameId) && (request.url.includes("DeleteCheckOut") || request.url.includes("ReloadHarness"))) { + // reloadContentScripts(sender.tab.id, sender.frameId, loadedFrames.get(sender.tab.id + "-" + sender.frameId)); + // sendResponse("Reloading content scripts tab " + sender.tab.id + " frame " + sender.frameId); + // } else { + // console.log(sender.tab.id + "-" + sender.frameId + " not found in loadedFrames"); + // } + // } + } else if (request.purpose == "tracerState" && arrDevTabs.get(sender.origin)) { //TODO: try Long-lived connections https://developer.chrome.com/docs/extensions/mv3/messaging/#connect @@ -69,7 +104,7 @@ function tracerIsRunning() { let tracerIndicator = document.querySelector("div#PDTTracerIndicator"); document.querySelector("button#PDTDevTracerPlayPause").addEventListener("click", function(event) { browser.runtime.sendMessage({ purpose: "tracerStop"}) }); - let titleTimerId = setInterval(function () { + let _titleTimerId = setInterval(function () { heartbeat = document.querySelector("input#PDTTracerHeartbeat").value; if (hasHeartbeat && (heartbeat === "off" || (Math.floor(Date.now() / 1000) - heartbeat) > 4)) { console.log("PDT Tracer heartbeat lost " + heartbeat + " " + Math.floor(Date.now() / 1000)); @@ -117,38 +152,142 @@ function tracerStop() { document.getElementById("Pause").click(); } -const injectScriptsToIframe = (tabId, frameId, scriptList) => { - browser.scripting.executeScript({ - files: scriptList, - target: { tabId: tabId, frameIds: [frameId] }, - world: "MAIN", +function matchToRegEx(match) { + let regEx = match.replace(/[{}()\[\]\\.+?^$|]/g, "\\$&").replace(/\*/g, '.*?'); + return regEx; +} + +function reloadContentScripts(tabId, frameId, url) { + let frameIndex = tabId + "-" + frameId; + // if(processedFrames.has(frameIndex)) { + // console.log("frameIndex " + frameIndex + " " + processedFrames.get(frameIndex) + " " + Date.now()); + // } + if(processedFrames.has(frameIndex) && (Math.floor(Date.now() - processedFrames.get(frameIndex))/1000) < 2 ) + return false; + processedFrames.set(frameIndex, Date.now()); + console.log("PDT reloadContentScripts tabId " + tabId + ", frameId" + frameId + ", URL " + url); + let manifest = browser.runtime.getManifest(); + let contentScripts = manifest.content_scripts; + if(contentScripts.length == 0) + return false; + + contentScripts.forEach(contentScript => { + let isAMatch = false; + + contentScript.matches.forEach(match => { + if(!isAMatch) { + let matchRegEx = matchToRegEx(match); + let regEx = new RegExp(matchRegEx); + isAMatch = regEx.test(url); + } + }); + + // contentScript.js = contentScript.js.filter(function(value){ + // return !value.includes("registerWithServiceWorker"); + // }); + + if(contentScript.js.includes("resources/shared.js") || contentScript.js.includes("resources/registerWithServiceWorker.js")) + isAMatch = false; + + if(isAMatch && contentScript.js.length>0) { + console.log(contentScript); + + browser.scripting.executeScript({ + files: contentScript.js, + target: { tabId: tabId, frameIds: [frameId] }, + world: "ISOLATED", + }); + + // if(contentScript.css) { + // contentScript.css.forEach(css => + // chrome.scripting.insertCSS(tabId, { + // file: css.value + // }) + // ) + // } + } + }) + +} + +function pingFrame(tabId, frameId) { + browser.tabs.sendMessage( + tabId, + { purpose: "PingContent" }, + { frameId: frameId } + ); + console.log("Pinging content tab " + tabId + " frameId " + frameId); +} + +function initSettings() { + browser.storage.sync.get(["settings", "siteConfig"], (data) => { + settings = data.settings; + if(typeof settings === "undefined") settings = {}; + if(typeof settings.tracer === "undefined") settings.tracer = {}; + if(typeof settings.clipboard === "undefined") settings.clipboard = {}; + if(typeof settings.devstudio === "undefined") settings.devstudio = {}; + settings.siteConfig = new Map(); + + if (data.siteConfig) { + for (let i = 0; i < data.siteConfig.length; i++) { + if(data.siteConfig[i].color) { + data.siteConfig[i].color = data.siteConfig[i].color.replace("#", ''); + if (data.siteConfig[i].color.length === 3) { + data.siteConfig[i].color = data.siteConfig[i].color.split('').map((hex) => { + return hex + hex; + }).join(''); + } + if(data.siteConfig[i].color[0] != "#") + data.siteConfig[i].color = "#" + data.siteConfig[i].color; + } + + siteConfig.set(data.siteConfig[i].site, data.siteConfig[i]); + } + } }); +} - // scriptList.forEach((script) => { - // console.log("PDT executeScript tabId: " + tabId + ", frameId: " + frameId + ": " + `${script}`); - // browser.scripting.executeScript({ - // files: [injectedScript], - // target: { tabId: tabId, frameIds: [frameId] }, - // world: "MAIN" - // }); - - // browser.tabs.executeScript(tabId, { - // file: `${script}`, - // runAt: 'document_end', - // frameId: frameId - // //If the script injection fails (without the tab permission and so on) and is not checked in the callback` runtime.lastError `, - // //It's a mistake. There is no other complicated logic in this example. You don't need to record the tab of successful injection. You can fool it like this. - // }, () => void browser.runtime.lastError); - // }); -}; +function getSettings(site) { + let settingsForSite = settings; + if(siteConfig.has(site)) + settingsForSite.siteConfig = siteConfig.get(site); + else + settingsForSite.siteConfig = {}; + return settingsForSite; +} -let arrDevTabs = new Map(), arrTracerTabs = new Map(); +let arrDevTabs = new Map(), arrTracerTabs = new Map(), loadedFrames = new Map(), processedFrames = new Map(), settings = {}, siteConfig = new Map(); async function setup() { browser.runtime.onInstalled.addListener(async () => { let url = browser.runtime.getURL("settings.html"); await browser.tabs.create({ url }); }); + + browser.webRequest.onCompleted.addListener( + function(details) { + console.debug(details); + if(details.frameType == "sub_frame" && details.frameId && loadedFrames.has(details.tabId + "-" + details.frameId)) + pingFrame(details.tabId, details.frameId); + }, + {urls: [""]}, + ["responseHeaders"] + ); + + initSettings(); + + // //FEATURE: toggle certain options from extension context menu + // browser.contextMenus.create({ + // title: "Toggle", + // id: "toggleMenu", + // "contexts": ["all"] + // }); + + // browser.contextMenus.create({ + // title: "Hide tab close button", + // "contexts": ["all"], + // parentId: "toggleMenu" + // }); } -setup(); \ No newline at end of file +setup(); diff --git a/clipboard/clipboard.js b/clipboard/clipboard.js index bc82d4af..41c2edab 100644 --- a/clipboard/clipboard.js +++ b/clipboard/clipboard.js @@ -12,7 +12,6 @@ function addpyWorkPageLink() { let clsNameFull = extractClassName(title, true); if (clsName) jQuery("header").append(' (' + clsName + ') '); - pyWorkPage.style.fontWeight = "bold"; console.log('PDT pyWorkPage found'); } @@ -26,7 +25,6 @@ function addpyWorkPageLink() { let clsNameFull = extractClassName(title, true); if (clsName) jQuery("header").append(' (' + clsName + ') '); - pyWorkPage.style.fontWeight = "bold"; console.log('PDT RH_1 found'); } // else { @@ -40,12 +38,11 @@ function addnewAssignPage() { let newAssignPage = jQuery("#gridNode li.gridRow ul li").has("span[title^='newAssignPage']")[0]; if (newAssignPage) { + jQuery("header").append(" newAssignPage"); + jQuery("#devToolsGoToAssignPage").click(function () { jQuery("#gridNode li.gridRow ul li").has("span[title^='newAssignPage']").first().trigger("click"); }); let clsName = extractClassName(jQuery("#gridNode li.gridRow ul li span[title^='newAssignPage']")[0].title); - if (clsName && clsName !== "Assign-") { - jQuery("header").append(" newAssignPage"); - jQuery("#devToolsGoToAssignPage").click(function () { jQuery("#gridNode li.gridRow ul li").has("span[title^='newAssignPage']").first().trigger("click"); }); + if (clsName) { jQuery("header").append(' (' + clsName + ')'); - newAssignPage.style.fontWeight = "bold"; } } } diff --git a/clipboard/inject_clipboard.js b/clipboard/inject_clipboard.js index 6fdc7ae9..1145b7c4 100644 --- a/clipboard/inject_clipboard.js +++ b/clipboard/inject_clipboard.js @@ -13,15 +13,13 @@ function handleRightPanelChange() { if(status) jQuery(".heading_2").append(" (" + status + ")"); } - } //handle newAssignPage else if(jQuery(".heading_2").length > 0 && jQuery(".heading_2")[0].textContent == 'newAssignPage') { - let addedText = "", cls = ""; + let addedText = ""; let napElem = jQuery('div#gridBody_right table.gridTable td.dataLabelRead.gridCell').filter(function(){return this.textContent.trim() === "pxObjClass"}); if(napElem.length > 0) { - - cls = napElem.next()[0].innerText; + let cls = napElem.next()[0].innerText; if(cls) { if(cls.includes("-")) cls = cls.split('-')[1]; @@ -56,38 +54,7 @@ function handleRightPanelChange() { let addedFilterInput = document.querySelector("p.filter-table input"); if(addedFilterInput) addedFilterInput.focus(); - } - - document.querySelectorAll("div#gridBody_right table.gridTable")[1].querySelectorAll("tr.cellCont").forEach( - (e) => { - if(e.querySelector("tr a")) { - let eTextProp = e.querySelector("tr a").innerText; - let eTextValue; - let eValue = e.querySelector("td div.oflowDivM span"); - if(eValue) { - eTextValue = eValue.innerText.replace(/\n/g, "\\n") - .replace(//g, "\\>") - .replace(/"/g, """) - .replace(/'/g, "\\'"); - } - - //FEATURE: copy property name to clipboard - if(eTextProp) - e.querySelector("tr a").insertAdjacentHTML('beforebegin', ' '); - - //FEATURE: copy property value to clipboard - if(eTextValue) - e.querySelector("td div.oflowDivM span").insertAdjacentHTML('beforebegin', ' ') - - //FEATURE: copy property name and value to clipboard - if(eTextProp && eTextValue) { - let eText = "." + eTextProp + " = "" + eTextValue + """; - e.querySelector("td div.oflowDivM").insertAdjacentHTML('beforeend', '
') - } - } - } - ); + } }); } @@ -95,39 +62,6 @@ function stripeTable(table) { jQuery(table).find('tr').removeClass('striped').filter(':visible:even').addClass('striped'); }; -//TODO: inject from shared file? -function copyToClipboard(textContent) { - // create hidden text element, if it doesn't already exist - let targetId = "_hiddenCopyText_"; - let target = document.createElement("textarea"); - target.style.position = "absolute"; - target.style.left = "-9999px"; - target.style.top = "0"; - target.id = targetId; - document.body.appendChild(target); - target.textContent = textContent; - - // select the content - let currentFocus = document.activeElement; - target.focus(); - target.setSelectionRange(0, target.value.length); - - // copy the selection - let succeed; - try { - succeed = document.execCommand("copy"); - } catch (e) { - succeed = false; - } - // restore original focus - if (currentFocus && typeof currentFocus.focus === "function") { - currentFocus.focus(); - } - - target.textContent = ""; - return succeed; -}; - if(pega && pega.ui && pega.ui.Doc) { let origprocessActionGridDetail_Success = pega.ui.Doc.prototype.processActionGridDetail_Success; pega.ui.Doc.prototype.processActionGridDetail_Success = function() { diff --git a/devstudio/datapage.js b/devstudio/datapage.js index f3dfee32..8c5f4f87 100644 --- a/devstudio/datapage.js +++ b/devstudio/datapage.js @@ -1,3 +1,4 @@ +PDT.setScriptsApplied(); console.log("PDT: devstudio/datapage.js"); document.arrive("div[node_name='pzRuleFormParameters'] h2", {onceOnly: true, existing: true}, () => { @@ -18,4 +19,4 @@ document.arrive("div[node_name='pzRuleFormParameters'] h2", {onceOnly: true, exi '
' + dpCallString + '
' ); -}); \ No newline at end of file +}); diff --git a/devstudio/devstudio.css b/devstudio/devstudio.css index 8d10da0c..468c91ec 100644 --- a/devstudio/devstudio.css +++ b/devstudio/devstudio.css @@ -2,14 +2,20 @@ padding-left: 7px !important; } - .header-layout.flex.content>.flex.content-item.system-search, .header-layout.flex.content>.flex.content-item.with-icon { border-right-width: 0 !important; margin: 0 !important; } - /* remove reserved space in recents explorer, giving more space for item description */ div[node_name='pzRecentExplorer'] div[node_name='pyFatListItems'] div.explorer-list-item > div { - padding-left: 0 !important; + padding-left: 2px !important; +} + +div[node_name='pzRecentExplorer'] div[node_name='pyFatListItems'] > div { + padding: 0 !important; +} + +div.workspace-app-name { + margin-right: 4px !important; } \ No newline at end of file diff --git a/devstudio/devstudio.js b/devstudio/devstudio.js index 77a67d4e..c70f170b 100644 --- a/devstudio/devstudio.js +++ b/devstudio/devstudio.js @@ -9,14 +9,14 @@ function applyPDTCustomization() { globalConfig.settings && globalConfig.settings.useSiteLabelForBrowserTitle ) { - var newTitle = siteConfig.label + " Pega"; + let newTitle = siteConfig.label + " Pega"; if (siteConfig.version) newTitle += " " + siteConfig.version.slice(0, 1) + "." + siteConfig.version.slice(1, 2); parent.document.title = newTitle; } //FEATURE: environment header - var productionEnvElement = document.querySelector( + let productionEnvElement = document.querySelector( "div[data-ui-meta*='D_pzGetCurrentSystemRecord.pyActiveProductionLevelName']" ); if (productionEnvElement) { @@ -43,9 +43,7 @@ function applyPDTCustomization() { ); } - if ( - globalConfig.settings && globalConfig.settings.hideEnvironmentHeader - ) { + if (globalConfig.settings && globalConfig.settings.hideEnvironmentHeader) { if (productionEnvElement) productionEnvElement.style.display = "none"; } @@ -57,7 +55,7 @@ function applyPDTCustomization() { siteConfig.color.replace("#", ''); } } - var settings; + let settings; if (globalConfig && globalConfig.settings) { settings = globalConfig.settings; } @@ -70,46 +68,11 @@ function applyPDTCustomization() { alterTracerOpenBehavior(settings.tracer.openBehavior); } - //FEATURE: hide close button - if (PDT.settings.devstudio.hideCloseButton) - injectStyles("div.tStrCntr ul #close {display: none}"); - - if (PDT.settings.devstudio.longerRuleNames) { - //inject script which will apply it for newly opened tabs - injectScript("/js/", "makeRuleNamesLonger.js"); - injectStyles( - ".Temporary_top_tabs .Temporary_top_tabsList LI span#TABANCHOR { padding-right: 4px !important; padding-left: 4px; !important}" - ); - } - - if (PDT.settings.devstudio.expandTabOnHover) { - //inject script which will apply it for newly opened tabs - injectScript("/js/", "expandTabOnHover.js"); - } - - if (PDT.settings.devstudio.checkoutIndicator) { - showCheckoutIndicator(); - } - addHeaderShortcuts(); customizeText(); injectSidebarToggle(); - - //FEATURE: close tab on middle click - if (PDT.settings.devstudio.closeTabMiddleClick) { - //inject script which will apply it for newly opened tabs - injectScript("/js/", "closeTabMiddleClick.js"); - - // apply for existing tabs - document.querySelectorAll("div.tStrCntr ul table#RULE_KEY span[data-stl='1'], div.tStrCntr ul table#RULE_KEY svg").forEach(function (elem) { - elem.addEventListener("mousedown", function (e) { - console.log(e); - if (e && (e.which == 2 || e.button == 4)) - this.parentNode.parentNode.querySelector('#close').click(); - }) - }) - } } + PDT.alterFavicon(); } @@ -150,20 +113,16 @@ function showCheckoutIndicator() { if (containerTabListIndicator) { const containerTabListCallbackIndicator = function ( mutationsList, - observer + _observer ) { mutationsList.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (DEBUG) console.log(node.nodeName); + let elem; document.querySelectorAll("iframe").forEach((iframe) => { - if ( - iframe.contentWindow.document.querySelectorAll( - "button[title^='Check in']" - ).length > 0 - ) - var elem = document.querySelector( - "div.tStrCntr ul li[aria-label='" + iframe.title + "'] td span" - ); + if (iframe.contentWindow.document.querySelectorAll("button[title^='Check in']").length > 0) { + elem = document.querySelector("div.tStrCntr ul li[aria-label='" + iframe.title + "'] td span"); + } if (elem && !elem.innerText.startsWith("*")) { elem.innerText = "*" + elem.innerText; if (DEBUG) console.log(iframe.title); @@ -208,8 +167,7 @@ function customizeText() { //document.querySelector("span#TABANCHOR span.textIn").eq(0).replaceWith('') //FEATURE: shorten Application label and make it bold - if (document.querySelector("div.current-application") && - document.querySelector("div.current-application label").innerText) { + if (document.querySelector("div.current-application label").innerText) { document.querySelector("div.current-application label").innerText = "App:"; document.querySelector("div.current-application div a").style.fontWeight = "bolder"; } @@ -225,7 +183,7 @@ function customizeText() { document.querySelector("div.alerts a").innerHTML = document.querySelector("div.alerts a").innerHTML.replace(document.querySelector("div.alerts a").textContent, ''); //FEATURE: shorten Live Data - var DataInspectorButton = document.querySelector( + let DataInspectorButton = document.querySelector( "div a[data-test-id='DataInspectorButton']" ); if (DataInspectorButton) { diff --git a/devstudio/devstudio_activity.js b/devstudio/devstudio_activity.js index 3f0935c5..94363720 100644 --- a/devstudio/devstudio_activity.js +++ b/devstudio/devstudio_activity.js @@ -1,3 +1,5 @@ // console.log("PDT: devstudio/devstudio_activity.js"); +//PDT.setScriptsApplied(); //document.querySelectorAll("table ul.gridNode li.gridRow[pl_index]") -// //injectRuleExport(); \ No newline at end of file +// //injectRuleExport(); + diff --git a/devstudio/devstudio_data.js b/devstudio/devstudio_data.js index ab09af56..4b78f9c6 100644 --- a/devstudio/devstudio_data.js +++ b/devstudio/devstudio_data.js @@ -1,6 +1,7 @@ console.log("PDT: devstudio/devstudio_data.js"); +PDT.setScriptsApplied(); //TODO: to be reviewed diff --git a/devstudio/devstudio_datatransform.js b/devstudio/devstudio_datatransform.js index a0f95bad..923648b1 100644 --- a/devstudio/devstudio_datatransform.js +++ b/devstudio/devstudio_datatransform.js @@ -1,3 +1,4 @@ +PDT.setScriptsApplied(); console.log("PDT: devstudio/devstudio_datatransform.js"); document.arrive("div[data-node-id='pzRuleFormRuleset'] div.primary-navigation-links", {onceOnly: true, existing: true}, (selection) => { diff --git a/devstudio/devstudio_flow.js b/devstudio/devstudio_flow.js index 086db379..1e67f1b5 100644 --- a/devstudio/devstudio_flow.js +++ b/devstudio/devstudio_flow.js @@ -1,8 +1,9 @@ console.log("PDT: devstudio/devstudio_flow.js"); +PDT.setScriptsApplied(); injectSidebarToggle(); injectCloseShortcut(); document.arrive("div.gfw-breadcrumbs ul li", {onceOnly: true, existing: true}, () => { injectScript("/js/", "injectFlowType.js"); -}); \ No newline at end of file +}); diff --git a/devstudio/devstudio_function.js b/devstudio/devstudio_function.js index 89f381fa..ae8e785c 100644 --- a/devstudio/devstudio_function.js +++ b/devstudio/devstudio_function.js @@ -1,8 +1,7 @@ +PDT.setScriptsApplied(); console.log("PDT: devstudio/devstudio_function.js"); - -var cms = document.querySelector("a.ce-expand"); -if(cms) { +document.arrive("a.ce-expand", {onceOnly: true, existing: true}, () => { injectScript("/js/", "formatJava.js"); cms.insertAdjacentHTML('beforebegin', ''); -} +}); diff --git a/devstudio/devstudio_paragraph.js b/devstudio/devstudio_paragraph.js index a91619e6..734ef3be 100644 --- a/devstudio/devstudio_paragraph.js +++ b/devstudio/devstudio_paragraph.js @@ -1,31 +1,42 @@ + +PDT.setScriptsApplied(); console.log("PDT: devstudio/devstudio_paragraph.js"); -var tries = 0; -var mainDiv; +/* //TODO: currently broken. does not work on reload +document.arrive("span.TextAreaContainer textarea", {onceOnly: true, existing: true}, () => { + applyCodeMirror(); +}); + +// var tries = 0; +// var mainDiv; -function addObserver() { - const paragraphSection = document.querySelector("div[node_name='pzViewParagraph']"); +// function addObserver() { +// const paragraphSection = document.querySelector("div[node_name='pzViewParagraph']"); - const paragraphCallback = function (mutationsList, observer) { - mutationsList.forEach((mutation) => { - applyCodeMirror(); - }); - }; +// const paragraphCallback = function (mutationsList, observer) { +// mutationsList.forEach((mutation) => { +// applyCodeMirror(); +// }); +// }; - const paragraphObserver = new MutationObserver(paragraphCallback); - paragraphObserver.observe(paragraphSection, { - childList: true, - }) -} +// const paragraphObserver = new MutationObserver(paragraphCallback); +// paragraphObserver.observe(paragraphSection, { +// childList: true, +// }) +// } +if(typeof myCodeMirror !== "undefined") + myCodeMirror.destroy(); -var myCodeMirror; +let myCodeMirror; function applyCodeMirror() { //injectStyles(".CodeMirror { height: auto;}"); - var tarea = document.querySelector("span.TextAreaContainer textarea"); - if (tarea) { + if(document.querySelector("divCodeMirror-wrap")) + document.querySelector("divCodeMirror-wrap").remove(); + let textArea = document.querySelector("span.TextAreaContainer textarea"); + if (textArea) { console.log("PDT: devstudio/devstudio_paragraph.js applying CodeMirror"); - myCodeMirror = CodeMirror.fromTextArea(tarea, { + myCodeMirror = CodeMirror.fromTextArea(textArea, { mode: "htmlmixed", lineNumbers: true, lineWrapping: true, @@ -56,32 +67,33 @@ function applyCodeMirror() { } -function waitUntilRenderRS() { - mainDiv = document.querySelector("div[node_name='pzViewParagraph']"); - if (mainDiv) { - applyCodeMirror(); - addObserver(); - } else { - tries = tries + 1; - console.log(tries); - if (tries > 10) return; - setTimeout(() => { - waitUntilRenderRS(); - }, 500); - } -} +// function waitUntilRenderRS() { +// mainDiv = document.querySelector("div[node_name='pzViewParagraph']"); +// if (mainDiv) { +// applyCodeMirror(); +// addObserver(); +// } else { +// tries = tries + 1; +// console.log(tries); +// if (tries > 10) return; +// setTimeout(() => { +// waitUntilRenderRS(); +// }, 500); +// } +// } -waitUntilRenderRS(); +// waitUntilRenderRS(); -var dom_observer = new MutationObserver(function(mutationsList) { - mutationsList.forEach((mutation) => { - console.log(mutation); - }); -}); -var container = document.documentElement || document.body; -console.log(container); -var config = { attributes: true, childList: true }; -dom_observer.observe(container, config); +// var dom_observer = new MutationObserver(function(mutationsList) { +// mutationsList.forEach((mutation) => { +// console.log(mutation); +// }); +// }); +// var container = document.documentElement || document.body; +// console.log(container); +// var config = { attributes: true, childList: true }; +// dom_observer.observe(container, config); +*/ \ No newline at end of file diff --git a/devstudio/devstudio_report.js b/devstudio/devstudio_report.js index 186d9023..a776a26d 100644 --- a/devstudio/devstudio_report.js +++ b/devstudio/devstudio_report.js @@ -1,3 +1,3 @@ console.log("PDT: devstudio/devstudio_report.js"); - +PDT.setScriptsApplied(); injectRuleExport(); \ No newline at end of file diff --git a/devstudio/devstudio_rule.js b/devstudio/devstudio_rule.js index 32703568..8e6f7368 100644 --- a/devstudio/devstudio_rule.js +++ b/devstudio/devstudio_rule.js @@ -1,5 +1,7 @@ console.log("PDT: devstudio/devstudio_rule.js"); +PDT.setScriptsApplied(); + //TODO: open rule class in app explorer // function openRuleClassInAppExplorer() { // showRuleInAppExplorer("Rule-HTML-Section", "RULE-OBJ-CLASS"); @@ -28,8 +30,8 @@ function siteConfigCallback(siteConfig, globalConfig) { }); //FEATURE: copy class name - document.arrive("a[name^='RuleFormHeader'], span[title='Class Name']", {onceOnly: true, existing: true}, function() { - this.insertAdjacentHTML('afterend', ''); + document.arrive("a[name^='RuleFormHeader'], span[tile='Class Name']", {onceOnly: true, existing: true}, function() { + this.insertAdjacentHTML('afterend', ''); //} else { //TODO: show class name //document.querySelector('div#PEGA_HARNESS').getAttribute('classname'); @@ -50,4 +52,5 @@ function siteConfigCallback(siteConfig, globalConfig) { siteConfig(siteConfigCallback); injectSidebarToggle(); -injectCloseShortcut(); \ No newline at end of file +injectCloseShortcut(); + diff --git a/devstudio/devstudio_ruleform_popup.js b/devstudio/devstudio_ruleform_popup.js index cbfb06d6..a24d7228 100644 --- a/devstudio/devstudio_ruleform_popup.js +++ b/devstudio/devstudio_ruleform_popup.js @@ -1,4 +1,5 @@ console.log("PDT: devstudio/devstudio_ruleform_popup.js"); +PDT.setScriptsApplied(); var tries = 0; var mainDiv; @@ -60,4 +61,5 @@ function waitUntilRender() { } } +//TODO: use arrive.js waitUntilRender(); diff --git a/devstudio/devstudio_ruleset.js b/devstudio/devstudio_ruleset.js index 0f0d31d0..b7b4af32 100644 --- a/devstudio/devstudio_ruleset.js +++ b/devstudio/devstudio_ruleset.js @@ -1,4 +1,5 @@ console.log("PDT: devstudio/devstudio_ruleset.js"); +PDT.setScriptsApplied(); var tries = 0, pagerDiv; var rsvListObserver; diff --git a/devstudio/devstudio_tabs.js b/devstudio/devstudio_tabs.js new file mode 100644 index 00000000..08bd9191 --- /dev/null +++ b/devstudio/devstudio_tabs.js @@ -0,0 +1,149 @@ +console.log("PDT: devstudio/devstudio_tabs.js"); + +function applyTabMenu() { + let tabClicked; + + let menuDefinition = [ + { + text: "⇐ Move left", + action: () => { + if(tabClicked.previousSibling && tabClicked.previousSibling.getAttribute("section_index") !="1") + tabClicked.parentElement.insertBefore(tabClicked, tabClicked.previousSibling) + } + }, + { + text: "⇒ Move right", + action: () => { + if(tabClicked.nextSibling && tabClicked.parentElement && !(tabClicked.nextSibling.classList.contains("rightborder"))) + tabClicked.parentElement.insertBefore(tabClicked.nextSibling, tabClicked) + } + }, + { isDivider: true }, + { + text: "⚐ Mark", + action: () => { + tabClicked.querySelectorAll("span#TABANCHOR, span#TABSPAN").forEach((s) => { + if(s.style.backgroundColor == "rgb(169, 7, 30)") + s.style.backgroundColor = null; + else + s.style.backgroundColor = "rgb(169, 7, 30)"; + }) + } + }, + { isDivider: true }, + { + text: "ŀ Move to split view", + action: () => { + let tabId = document.querySelector("div[data-node-id='pzStudioContainerTabs'] div.tStrCntr ul li[aria-selected='true']").id; + let tabDynamicContainer = document.querySelector(`div.dynamicContainer[aria-labelledby='${tabId}']`) + if(tabDynamicContainer) { + tabDynamicContainer.style.width = "50%"; + tabDynamicContainer.style.display = "block"; + } + + tabId = tabClicked.id; + tabDynamicContainer = document.querySelector(`div.dynamicContainer[aria-labelledby='${tabId}']`) + if(tabDynamicContainer) { + tabDynamicContainer.style.width = "50%"; + tabDynamicContainer.style.right = "0"; + tabDynamicContainer.style.display = "block"; + } + else { + alert('Oops, something went wrong'); + } + } + }, + { + text: "ŀ Exit split view", + action: () => { + let tabId = document.querySelector("div[data-node-id='pzStudioContainerTabs'] div.tStrCntr ul li[aria-selected='true']").id; + let tabDynamicContainer = document.querySelector(`div.dynamicContainer[aria-labelledby='${tabId}']`) + if(tabDynamicContainer) { + tabDynamicContainer.style.width = "100%"; + tabDynamicContainer.style.display = "block"; + } + + document.querySelector('div.dynamicContainer[style*="width: 50%"]').style = "display: hidden"; + } + }, + { isDivider: true }, + { + text: "⦻ Close tab", + action: () => { if(tabClicked.querySelector('#close')) tabClicked.querySelector('#close').click(); } + }, + { + text: "☓ Close this menu", + action: () => { /* empty action just closes menu */ } + } + ] + + //FEATURE: menus + $("div.dc-header div.pegaTabGrp div.tStrCntr ul").on( + "contextmenu", + "li", + function (evt) { + evt.preventDefault(); + tabClicked = this; + let menuDefinitionEditable = menuDefinition.slice();; + //let menuDefinitionEditable = structuredClone(menuDefinition); + //let menuDefinitionEditable = JSON.parse(JSON.stringify(menuDefinition)); + + if(evt.currentTarget.classList.contains("selected")) { + //remove split view + menuDefinitionEditable.splice(5, 1); + } else { + menuDefinitionEditable.splice(6, 1); + } + ctxmenu.show(menuDefinitionEditable, evt); + }); +} + +document.arrive("body[data-PDTSettings='loaded']", {onceOnly: true, existing: true}, () => { + if(PDT.settings.devstudio.useTabMenu) { + applyTabMenu(); + } + + //FEATURE: scroll tabs with mouse wheel + if (PDT.settings.devstudio.mouseScrollTabs) { + injectScript("/js/", "mouseScrollTabs.js"); + } + + //FEATURE: expand tabs on hover + if (PDT.settings.devstudio.expandTabOnHover) { + //inject script which will apply it for newly opened tabs + injectScript("/js/", "expandTabOnHover.js"); + } + + //FEATURE: checkout indicator + if (PDT.settings.devstudio.checkoutIndicator) { + showCheckoutIndicator(); + } + + //FEATURE: close tab on middle click + if (PDT.settings.devstudio.closeTabMiddleClick) { + //inject script which will apply it for newly opened tabs + injectScript("/js/", "closeTabMiddleClick.js"); + + // apply for existing tabs + document.querySelectorAll("div.tStrCntr ul table#RULE_KEY span[data-stl='1'], div.tStrCntr ul table#RULE_KEY svg").forEach(function (elem) { + elem.addEventListener("mousedown", function (e) { + console.log(e); + if (e && (e.which == 2 || e.button == 4)) + this.parentNode.parentNode.querySelector('#close').click(); + }) + }) + } + + //FEATURE: hide close button + if (PDT.settings.devstudio.hideCloseButton) + injectStyles("div.tStrCntr ul #close {display: none}"); + + if (PDT.settings.devstudio.longerRuleNames) { + //inject script which will apply it for newly opened tabs + injectScript("/js/", "makeRuleNamesLonger.js"); + + injectStyles( + ".Temporary_top_tabs .Temporary_top_tabsList LI span#TABANCHOR { padding-right: 4px !important; padding-left: 4px; !important}" + ); + } +}); diff --git a/devstudio/logfile.js b/devstudio/logfile.js index 852658d7..8cbe68d3 100644 --- a/devstudio/logfile.js +++ b/devstudio/logfile.js @@ -5,8 +5,8 @@ if(document.querySelector("div#LogContentDiv > div b.page").nextElementSibling = window.scrollTo(0, document.body.scrollHeight); } -var pager = document.querySelector("div#LogContentDiv > div").cloneNode(true); -var target = document.querySelector("div#LogContentDiv"); +let pager = document.querySelector("div#LogContentDiv > div").cloneNode(true); +let target = document.querySelector("div#LogContentDiv"); if(target) { target.insertBefore(pager, target.firstChild); } diff --git a/devstudio/refactorClass.js b/devstudio/refactorClass.js new file mode 100644 index 00000000..5474827d --- /dev/null +++ b/devstudio/refactorClass.js @@ -0,0 +1,6 @@ +console.log("PDT: devstudio/refactorClass.js"); + +document.querySelectorAll("div.repeatContainer").forEach((e) => { + e.insertAdjacentHTML('beforebegin', ''); + } +) \ No newline at end of file diff --git a/js/copyDPcall.js b/js/copyDPcall.js index e076eef6..5db4a6db 100644 --- a/js/copyDPcall.js +++ b/js/copyDPcall.js @@ -1,5 +1,5 @@ -function CopyDPCall(nocopy) { - let dpCallString = document.querySelector("span[title='Page Name']").innerText + "["; +function CopyDPCall(noCopy) { + dpCallString = document.querySelector("span[title='Page Name']").innerText + "["; document.querySelectorAll("div[node_name='pzRuleFormParameters'] div#gridBody_right table.gridTable tr.cellCont").forEach(function (row) { if (row.querySelector("input") && row.querySelector("input").value) { dpCallString += row.querySelector("input").value + ": \"" + "\", " @@ -7,7 +7,7 @@ function CopyDPCall(nocopy) { }); if (dpCallString.endsWith(", ")) dpCallString = dpCallString.substring(0, dpCallString.length - 2); dpCallString += "]"; - if(!nocopy) { + if(!noCopy) { copyToClipboard(dpCallString); //let user know diff --git a/js/copyNameClass.js b/js/copyNameClass.js index 917505e0..bc3625aa 100644 --- a/js/copyNameClass.js +++ b/js/copyNameClass.js @@ -17,10 +17,7 @@ function CopyClassName() { if(xml && xml.val()) { xml = xml.val().replace('', '').replace("", ""); $xml = $($.parseXML(xml)); - if($xml.find("pyClassName").length>0) - copyText = $xml.find("pyClassName")[0].textContent; - else - copyText = document.querySelector("span[title='Class Name'").innerText; + copyText = $xml.find("pyClassName")[0].textContent; } else if(document.querySelector("a[name^='pzDataTypeKeysAndDescription'")){ copyText = document.querySelector("a[name^='pzDataTypeKeysAndDescription'").innerText; } diff --git a/js/makeRuleNamesLonger.js b/js/makeRuleNamesLonger.js index 2538cdd1..7f4bc082 100644 --- a/js/makeRuleNamesLonger.js +++ b/js/makeRuleNamesLonger.js @@ -1,33 +1,30 @@ const containerTabListNames = document.querySelector("div.tStrCntr ul"); -const containerTabListCallbackNames = function (mutationsList, _observer) { - mutationsList.forEach((mutation) => { - if(mutation.attributeName == "aria-label"){ - if (mutation.target.nodeName == "LI") { - mutation.target.classList.add("PDTmakeRuleNamesLonger"); - let titleOriginal = mutation.target.querySelector("span[inanchor]").innerText; - if(titleOriginal.endsWith("...")) { - let title = mutation.target.getAttribute("aria-label").replace("Press Delete to close the current tab", "").trim(); - titleOriginal = titleOriginal.replace("...", ""); - if(!title.startsWith(titleOriginal)) { - title = mutation.target.getAttribute("title").trim(); - } - if (title && title.startsWith(titleOriginal)) { +if(containerTabListNames) { + + const containerTabListCallbackNames = function (mutationsList, _observer) { + mutationsList.forEach((mutation) => { + if(mutation.attributeName == "aria-label"){ + if (mutation.target.nodeName == "LI") { + mutation.target.classList.add("PDTmakeRuleNamesLonger"); + let title = mutation.target.getAttribute("aria-label"); + if (title) { title = title.length > 20 ? title.substring(0, 20) + "..." : title; mutation.target.querySelector("span[inanchor]").innerText = title; } } } - } - }); -}; + }); + }; -const containerTabListNamesObserver = new MutationObserver(containerTabListCallbackNames); -containerTabListNamesObserver.observe(containerTabListNames, - { - attributeFilter: [ "aria-label"], - subtree: true - } -); + const containerTabListNamesObserver = new MutationObserver(containerTabListCallbackNames); + + containerTabListNamesObserver.observe(containerTabListNames, + { + attributeFilter: [ "aria-label"], + subtree: true + } + ); +} -console.log("PDT: makeRuleNamesLonger.js loaded"); \ No newline at end of file +console.log("PDT: makeRuleNamesLonger.js loaded"); diff --git a/js/mouseScrollTabs.js b/js/mouseScrollTabs.js new file mode 100644 index 00000000..dcf0da09 --- /dev/null +++ b/js/mouseScrollTabs.js @@ -0,0 +1,11 @@ +function scrollHorizontally(e) { + e.currentTarget.scrollLeft -= e.wheelDelta; + e.preventDefault(); +} + +let tabListContainer = document.querySelector("div.dc-header div.pegaTabGrp div.tStrCntr"); +if (tabListContainer && tabListContainer.addEventListener) { + tabListContainer.addEventListener('wheel', scrollHorizontally, false); +} + +console.log("PDT: mouseScrollTabs.js loaded"); \ No newline at end of file diff --git a/js/tracerMarkNavigatedPage.js b/js/tracerMarkNavigatedPage.js index c819d3d1..1d4df66a 100644 --- a/js/tracerMarkNavigatedPage.js +++ b/js/tracerMarkNavigatedPage.js @@ -1,25 +1,8 @@ function markNavigatedPage(e) { - function animateCell(cell) { - cell.style.border = "solid black"; - cell.style.borderWidth = "6px 0 6px"; - let animate = function() { - let borderWidth = parseInt(cell.style.borderWidth); - if (borderWidth > 0) { - borderWidth--; - cell.style.borderWidth = borderWidth + "px 0 " + borderWidth + "px"; - setTimeout(animate, 64); - } - }; - animate(); - } - document .querySelectorAll("tr.eventTable") .forEach((el) => (el.style.backgroundColor = "#EFEFEF")); //revert highlight let eid = e.getAttribute("href"); eid = eid.replaceAll("(", "\\(").replaceAll(")", "\\)"); //escape chars which querySelector doesn't like - let elem = document.querySelector(eid); - animateCell(elem); - animateCell(elem.nextSibling); - elem.parentNode.style.backgroundColor = "LightYellow"; + document.querySelector(eid).parentNode.style.backgroundColor = "LightYellow"; } \ No newline at end of file diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 00000000..173db8ec --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,7 @@ +{ + "typeAcquisition": { + "include": [ + "chrome" + ] + } + } \ No newline at end of file diff --git a/manifest.json b/manifest.json index 829d5543..aac747f7 100644 --- a/manifest.json +++ b/manifest.json @@ -10,7 +10,8 @@ "contextMenus", "storage", "notifications", - "scripting" + "scripting", + "webRequest" ], "host_permissions": [""], "incognito":"spanning", @@ -21,7 +22,6 @@ "page": "settings.html", "open_in_tab": true }, - "icons": { "128": "icon.png" }, @@ -37,15 +37,29 @@ "resources/shared.css" ], "js": [ - "resources/jquery-3.4.1.min.js", - "resources/tinycon.min.js", + "resources/jquery-3.4.1.min.js", "resources/arrive.min.js", - "resources/shared.js" + "resources/shared.js", + "resources/tinycon.min.js" + ], "all_frames": true, "match_about_blank": true, "run_at": "document_end" }, + { + "matches": [ + "*://*/prweb/*" + ], + "exclude_globs": [ + "*blank.htm*" + ], + "js": [ + "resources/registerWithServiceWorker.js" + ], + "all_frames": true, + "run_at": "document_idle" + }, { "matches": [ "*://*/prweb/*!STANDARD*", @@ -56,7 +70,9 @@ "*agile*" ], "js": [ - "devstudio/devstudio.js" + "resources/ctxmenu.min.js", + "devstudio/devstudio.js", + "devstudio/devstudio_tabs.js" ], "css": [ "devstudio/devstudio.css" @@ -218,11 +234,10 @@ ], "js": [ "resources/jquery-3.4.1.min.js", - "resources/contextmenu.min.js", + "resources/ctxmenu.min.js", "tracer/tracer_event.js" ], "css": [ - "resources/contextmenu.min.css", "tracer/tracer_event.css" ], "all_frames": true, @@ -318,6 +333,14 @@ "match_about_blank": true, "run_at": "document_end" }, + { + "matches": [ + "*://*/prweb/*/*RefactorClass*PegaAccel-Management-Refactor-Class*" + ], + "js": [ + "devstudio/refactorClass.js" + ] + }, { "matches": [ "*://*.pegacloud.net/prweb/*/*" @@ -342,9 +365,10 @@ "clipboard/*", "tracer/*", "devstudio/*", - "js/*" + "js/*", + "/*" ], "matches": [""] } ] -} +} \ No newline at end of file diff --git a/popup.html b/popup.html new file mode 100644 index 00000000..5ce9402f --- /dev/null +++ b/popup.html @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/resources/contextmenu.min.css b/resources/contextmenu.min.css deleted file mode 100644 index 6d694713..00000000 --- a/resources/contextmenu.min.css +++ /dev/null @@ -1 +0,0 @@ -.cm_container{position:fixed;opacity:0;transform:scale(0);transition:transform 0.1s;transform-origin:top left;padding:0}.cm_container.display{opacity:1;transform:scale(1)}.cm_container,.cm_container *{box-sizing:border-box}.cm_container *{position:relative}.cm_container ul{list-style-type:none;padding:0;margin:0;background-color:#eee;box-shadow:0 0 5px #333}.cm_container li{padding:5px 10px;padding-right:1.7em;cursor:pointer;white-space:nowrap}.cm_container li:hover{background-color:#bbb}.cm_container li .cm_icon_span{width:1.5em;height:1.2em;vertical-align:bottom;display:inline-block;border-right:1px solid #aaa;margin-right:5px;padding-right:5px;text-align:center}.cm_container li .cm_sub_span{width:1em;display:inline-block;text-align:center;position:absolute;top:50%;right:.5em;transform:translateY(-50%)}.cm_container li>ul{position:absolute;top:0;left:100%;opacity:0;transition:opacity 0.2s;visibility:hidden}.cm_container li:hover>ul{opacity:1;visibility:visible}.cm_container li.cm_divider{border-bottom:1px solid #aaa;margin:5px;padding:0;cursor:default}.cm_container li.cm_divider:hover{background-color:inherit}.cm_container.cm_border_right>ul ul{left:unset;right:100%}.cm_container.cm_border_bottom>ul ul{top:unset;bottom:0}.cm_container li[disabled=""]{color:#777;cursor:default}.cm_container li[disabled=""]:hover{background-color:inherit} diff --git a/resources/contextmenu.min.js b/resources/contextmenu.min.js deleted file mode 100644 index fe15bb7f..00000000 --- a/resources/contextmenu.min.js +++ /dev/null @@ -1 +0,0 @@ -function ContextMenu(a,b){function c(h){var j=document.createElement("ul");return h.forEach(function(k){var l=document.createElement("li");if(l.menu=f,"undefined"==typeof k.type){var m=document.createElement("span");m.className="cm_icon_span",m.innerHTML=""==ContextUtil.getProperty(k,"icon","")?ContextUtil.getProperty(b,"default_icon",""):ContextUtil.getProperty(k,"icon","");var n=document.createElement("span");n.className="cm_text",n.innerHTML=""==ContextUtil.getProperty(k,"text","")?ContextUtil.getProperty(b,"default_text","item"):ContextUtil.getProperty(k,"text","");var o=document.createElement("span");if(o.className="cm_sub_span","undefined"!=typeof k.sub&&(""==ContextUtil.getProperty(b,"sub_icon","")?o.innerHTML="›":o.innerHTML=ContextUtil.getProperty(b,"sub_icon","")),l.appendChild(m),l.appendChild(n),l.appendChild(o),!ContextUtil.getProperty(k,"enabled",!0))l.setAttribute("disabled","");else{if("object"==typeof k.events)for(var p=Object.keys(k.events),q=0;qc&&(c=g.offsetWidth),g.offsetHeight>d&&(d=g.offsetHeight);for(var h=c,j=d,f=0;fh&&(h=c+l.width),d+l.height>j&&(j=d+l.height)}}return{width:h,height:j}}}; diff --git a/resources/favicon.png b/resources/favicon.png new file mode 100644 index 00000000..082a5b2c Binary files /dev/null and b/resources/favicon.png differ diff --git a/resources/registerWithServiceWorker.js b/resources/registerWithServiceWorker.js new file mode 100644 index 00000000..13592aaa --- /dev/null +++ b/resources/registerWithServiceWorker.js @@ -0,0 +1 @@ +browser.runtime.sendMessage({ purpose: "loaded", url: window.location.href }); diff --git a/resources/shared.css b/resources/shared.css index b958e289..49bc277a 100644 --- a/resources/shared.css +++ b/resources/shared.css @@ -1,4 +1,4 @@ -.PegaDevToolsButton { +/* .PegaDevToolsButton { border: 3px solid; border-radius: 5px; margin-right: 7px; @@ -14,6 +14,11 @@ background: orange; } +.PegaDevToolsButtonGrey { + border-color: darkgrey; + background: darkgrey; +} */ + .pz-pi.pi-clipboard, .pi.pi-clipboard, .pz-pi.pi-tracer, @@ -28,6 +33,11 @@ border: 1px solid red !important; } +.PegaDevToolsTextBlue { + color: blue; + border: 1px solid blue !important; +} + /*can be moved to tracer-event.css*/ .PegaDevToolsTracerCloseBottom { position: absolute; @@ -81,7 +91,6 @@ div[data-node-id="pzRuntimeToolsTopBar"] div.layout-content-pz-inline-middle { transform: rotate(135deg); } - .transformUp { -webkit-transform: rotate(-135deg); transform: rotate(-135deg); @@ -122,6 +131,10 @@ div[data-node-id="pzRuntimeToolsTopBar"] div.layout-content-pz-inline-middle { background-color: green; } +.greyPDT button { + background-color: darkgrey; +} + /*** 3-column layout ***/ .PDTcolumn { @@ -182,6 +195,32 @@ div#PDTTracerIndicator button { margin-bottom: 4px; } +.PDTdropdown { + display: none; + position: fixed; + z-index: 1; + background-color: whitesmoke; + overflow: auto; + min-width: 160px; + box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2); + overflow-y: scroll; + height: 400px; +} + +.PDTdropdown a { + color: black; + padding: 2px; + text-decoration: none; + display: block; +} + +.PDTdropdown a:hover { + background-color: #ddd; +} + +.initiallyHidden { + display: none; +} .PegaDevToolsTransparent, .PegaDevToolsTransparent a { color: transparent !important; diff --git a/resources/shared.js b/resources/shared.js index 9083e2f3..db9bbbc9 100644 --- a/resources/shared.js +++ b/resources/shared.js @@ -22,6 +22,7 @@ class PDT { if(typeof this.settings.tracer === "undefined") this.settings.tracer = {}; if(typeof this.settings.clipboard === "undefined") this.settings.clipboard = {}; if(typeof this.settings.devstudio === "undefined") this.settings.devstudio = {}; + PDT.debug("storage settings load"); //var siteConfigs = await getObjectFromLocalStorage("siteConfig"); @@ -45,6 +46,17 @@ class PDT { } } } + + document.arrive("body", { onceOnly: true, existing: true}, (elem) => { + let skip = PDT.shouldSkipContentForDocument(elem); + if(!skip) + elem.setAttribute("data-PDTSettings", "loaded"); + else + PDT.debug("skipped data-PDTSettings"); + }); + + PDT.debug("storage settings load"); + }); } @@ -125,6 +137,13 @@ class PDT { return (L > contrastThreshold) ? "#000000" : "#FFFFFF"; } + static tabColorCoding = new Map([ + ['RULE-HTML-SECTION', 'green'], + ['RULE-OBJ-ACTIVITY', 'red'], + ['RULE-OBJ-MODEL', 'blue'], + ]); + + static alterFavicon(forceSmall = false, forceLargeLabel = "", forceColor = "") { //favicon fallback let favicon = document.querySelector("link[rel~='icon']"); @@ -168,11 +187,25 @@ class PDT { } } - static makeFullscreen() { - window.resizeTo(screen.width, screen.height); + static setScriptsApplied() { + if(!document.querySelector("input#PDTContent")) + document.querySelector("div[data-node-id='RuleFormHeader'], body").insertAdjacentHTML("beforeend",''); } -} + //TODO: not really working, probably CKE starts with empty body + static shouldSkipContentForDocument(document){ + //CKE editor loads a body element which causes hidden input to be appended to paragraph source + let skip = false; + document.classList.forEach((className) => { if(className.includes("cke")) skip = true; }); + if(skip) { + if(document.querySelector("body")) + document.querySelector("body").setAttribute("data-PDTskipContent", true); + else + PDT.debug("could not set data-PDTskipContent"); + } + return skip; + } +} if(typeof PDT.settings === "undefined") PDT.init(); @@ -286,19 +319,14 @@ function appendScript(appendedScript) { ); } -function injectScript(basePath, scriptURL) { - injectScriptWithCallback(basePath, scriptURL, function (response) { - console.log(response); - }); -} - -function injectScriptWithCallback(basePath, scriptURL, callback) { - chrome.runtime.sendMessage( - { purpose: "injectScript", injectedScript: basePath+scriptURL }, - callback +function injectScript(aBasePath, aScriptURL) { + browser.runtime.sendMessage( + { purpose: "injectScript", injectedScript: aBasePath+aScriptURL }, + function (response) { + console.log(response); + } ); } - //inject script to toggle sidebar using keyboard shortcut function injectSidebarToggle() { injectScript("/js/", "sidebarToggle.js"); @@ -309,7 +337,7 @@ function injectCloseShortcut() { injectScript("/js/", "closeShortcut.js"); } -// deprecated? +//TODO: deprecated? function executeScript(injectedCode) { let scriptEl = document.createElement("script"); scriptEl.appendChild(document.createTextNode("(" + injectedCode + ")();")); @@ -382,8 +410,12 @@ function sleep(milliseconds) { function isInDevStudio() { //NOTE: ugly but works return ( - document.querySelector("div[data-portalharnessinsname") && - document.querySelector("div[data-portalharnessinsname").getAttribute("data-portalharnessinsname").includes("DesignerStudio") + document.querySelector( + "span#TABANCHOR span.textIn, span#TABANCHOR[tabtitle='Home']" + ) && + document.querySelector( + "span#TABANCHOR span.textIn, span#TABANCHOR[tabtitle='Home']" + ).innerText.startsWith("Home") ); //TODO: get Pega api object // if(pega.desktop.support.isInDesignerDesktop) @@ -393,7 +425,7 @@ function isInDevStudio() { function injectRuleExport() { let selection = document.querySelector("div[data-node-id='pzRuleFormRuleset'] div.primary-navigation-links"); if(selection) { - selection.insertAdjacentHTML("beforeend", "Export"); + selection.insertAdjacentHTML("beforeend", "Export"); injectScript("/js/", "copyRuleTableContent.js"); } } @@ -409,3 +441,18 @@ const getObjectFromStorage = async function (key) { } }); }; + +browser.runtime.onMessage.addListener(function(msg) { + if(msg.purpose == "PingContent") { + if (document.querySelector("input#PDTContent")) { + //messageServiceWorker('OK'); + } + else if(document.querySelector("body") && document.querySelector("body").hasAttribute("data-PDTskipContent")) { + //messageServiceWorker('OK'); + } + else { + console.log("PDT requesting content script reload"); + messageServiceWorker('reloadContentScripts'); + } + } +}) diff --git a/settings.html b/settings.html index 3cdf2810..4bb0c469 100644 --- a/settings.html +++ b/settings.html @@ -33,7 +33,6 @@ button { margin: 5px; cursor: pointer; - border-radius: 7px; } hr { @@ -87,12 +86,13 @@ h2, h3 { - margin-bottom: 3px; + margin-bottom: 0; } .actionButton { background-color: #1B8EC4; color: white; + border-radius: 7px; border: none; padding: 8px; font-size: 14px; @@ -100,7 +100,7 @@ } a { - color: #beeaff; + color: #0080BC; text-decoration: none; font-weight: bold; } @@ -116,14 +116,6 @@ .noCheckBox { margin-left: 20px; } - - span.feature a::after { - content: '\1F517'; /* Unicode for a link icon */ - } - - select { - margin-top: 2px; - } @@ -143,11 +135,11 @@

Settings

Dev Studio features + rel="noopener noreferrer">features

-