/
Search and Replace User Macro
Search and Replace User Macro
## @noparams #set ( $containerManagerClass = $content.class.forName('com.atlassian.spring.container.ContainerManager') ) #set ( $getInstanceMethod = $containerManagerClass.getDeclaredMethod('getInstance',null) ) #set ( $containerManager = $getInstanceMethod.invoke(null,null) ) #set ( $containerContext = $containerManager.containerContext ) #set ( $webResourceManager = $containerContext.getComponent('webResourceManager') ) $webResourceManager.requireResource('com.atlassian.auiplugin:aui-select2') #set ( $Integer = 0 ) #set ( $requestedSearch = "" ) #set ( $requestedSearch = $req.getParameter('requestedSearch') ) #set ( $requestedSpaces = "" ) #set ( $requestedSpaces = $req.getParameter('requestedSpaces') ) #set ( $replace = "" ) #set ( $replace = $req.getParameter('replace') ) #set ( $requestedReplace = "" ) #set ( $requestedReplace = $req.getParameter('requestedReplace') ) #set ( $escapedRequestedSearch = $generalUtil.escapeXml($requestedSearch) ) #set ( $escapedRequestedReplace = $generalUtil.escapeXml($requestedReplace) ) #set ( $requestCharacter = "?" ) #if ( $content.getUrlPath().contains("?") ) #set ( $requestCharacter = "&" ) #end <script> var qs = (function(a) { if (a == "") return {}; var b = {}; for (var i = 0; i < a.length; ++i) { var p=a[i].split('=', 2); if (p.length == 1) b[p[0]] = ""; else b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " ")); } return b; })(window.location.search.substr(1).split('&')); function htmlEncode (html) { return document.createElement('a').appendChild(document.createTextNode(html)).parentNode.innerHTML; } function htmlDecode (text) { return jQuery('<textarea/>').html(text).text(); } var formatXml = this.formatXml = function (xml) { var reg = /(>)\s*(<)(\/*)/g; var wsexp = / *(.*) +\n/g; var contexp = /(<.+>)(.+\n)/g; xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2'); var pad = 0; var formatted = ''; var lines = xml.split('\n'); var indent = 0; var lastType = 'other'; var transitions = { 'single->single': 0, 'single->closing': -1, 'single->opening': 0, 'single->other': 0, 'closing->single': 0, 'closing->closing': -1, 'closing->opening': 0, 'closing->other': 0, 'opening->single': 1, 'opening->closing': 0, 'opening->opening': 1, 'opening->other': 1, 'other->single': 0, 'other->closing': -1, 'other->opening': 0, 'other->other': 0 }; for (var i = 0; i < lines.length; i++) { var ln = lines[i]; var single = Boolean(ln.match(/<.+\/>/)); var closing = Boolean(ln.match(/<\/.+>/)); var opening = Boolean(ln.match(/<[^!].*>/)); var type = single ? 'single' : closing ? 'closing' : opening ? 'opening' : 'other'; var fromTo = lastType + '->' + type; lastType = type; var padding = ''; indent += transitions[fromTo]; for (var j = 0; j < indent; j++) { padding += ' '; } if (fromTo == 'opening->closing') formatted = formatted.substr(0, formatted.length - 1) + ln + '\n'; else formatted += padding + ln + '\n'; } return formatted; }; </script> #if ( $requestedSearch == "" ) <form class="aui top-label" onsubmit="return false;"> <div class="field-group top-label"> <label for="requested-search">Enter Search Terms:</label> <input id="requested-search" class="text long-field" type="text" name="requestedSearch"> </div> <div class="field-group"> <input id="replace" type="checkbox" onclick="jQuery('#requested-replace').val('');jQuery('#replace-fields').toggle();"> <span>Do Search/Replace</span> </div> <div class="field-group" id="replace-fields" style="display:none;"> <label for="requested-replace">Text to replace:</label> <input id="requested-replace" class="text long-field" type="text" name="requestedReplace"> </div> <script> jQuery(function() { if (document.getElementById('replace').checked) { jQuery('#replace-fields').show(); } }); </script> ## show replace field if user hits back button <div class="field-group"> <label for="requestedSpaces">Spaces to search:</label> <select class="select" id="requestedSpaces" name="requestedSpaces" multiple> #set ( $allSpaces = $spaceManager.getAllSpaces() ) #foreach ( $space in $allSpaces ) #if ( $space.isGlobal() ) <option value="$space.key">$space.name - $space.key</option> #end #end </div> <button class="button submit" onclick="window.location = '$content.getUrlPath()' + '${requestCharacter}requestedSearch=' + encodeURIComponent(document.getElementById('requested-search').value) + '&requestedSpaces=' + jQuery('#requestedSpaces').select2('val').join() + '&replace=' + jQuery('#replace').is(':checked') + '&requestedReplace=' + encodeURIComponent(document.getElementById('requested-replace').value);">Search</button> </form> <script> jQuery("#requestedSpaces").auiSelect2(); </script> #elseif ( $requestedSearch != "" && $replace == "false" ) #set ( $searchTerm = $requestedSearch ) #foreach ( $spaceKey in $requestedSpaces.split(",") ) #set ( $space = $spaceManager.getSpace($spaceKey) ) <p> Pages containing "${escapedRequestedSearch}" in $space.name </p> #set ( $spacePages = $pageManager.getPages($space, true) ) <table> <thead> <tr> <th> <p>Page</p> </th> <th> </th> </tr> </thead> <tbody> #foreach ($page in $spacePages) #set ( $pageId = $page.id ) #set ( $pageMarkup = $page.getBodyAsString() ) #if ( $permissionHelper.canView($action.remoteUser, $page) && $pageMarkup.contains($searchTerm) ) #set ( $quoteEscapedPageMarkup = $pageMarkup.replaceAll('"', '@@quot@@').replaceAll('"', '@@quot@@') ) <tr> <td style="vertical-align:middle"> <p><a href="$action.getGlobalSettings().getBaseUrl()$page.getUrlPath()" target="_blank">$page.title</a></p> <input style="display:none;" class="page-checkbox" type="checkbox" id="page-$pageId" pageid="$pageId" original="$quoteEscapedPageMarkup"> </td> <td> <button id="preview${pageId}" class="aui-button">Preview</button> <button class="aui-button" onclick="window.open(contextPath + '/pages/editpage.action?pageId=$pageId', '_blank');">Edit</button> </td> </tr> #end #end </tbody> </table> #end <p> </p> <button class="aui-button" onclick="window.location = '$content.getUrlPath()'">New Search</button> #elseif ( $requestedSearch != "" && $replace == "true" ) <button class="aui-button" onclick="jQuery('.page-checkbox').prop('checked', true);">Select All</button> <button class="aui-button" onclick="jQuery('.page-checkbox').prop('checked', false);">Select None</button> #set ( $searchResultCount = 0 ) #set ( $searchTerm = $requestedSearch ) #foreach ( $spaceKey in $requestedSpaces.split(",") ) #set ( $space = $spaceManager.getSpace($spaceKey) ) <p> Pages containing "${escapedRequestedSearch}" in $space.name </p> #set ( $spacePages = $pageManager.getPages($space, true) ) <table> <thead> <colgroup> ## To prevent table from being sortable </colgroup> <tr> <th> <p>Page</p> </th> <th> <button class="aui-button" onclick="jQuery('.page-checkbox[space=\'$space.key\']').click();">X</button> </th> <th> </th> </tr> </thead> <tbody> #foreach ($page in $spacePages) #set ( $pageId = $page.id ) #set ( $pageMarkup = $page.getBodyAsString() ) #if ( $permissionHelper.canView($action.remoteUser, $page) && $pageMarkup.contains($searchTerm) ) #set ( $searchResultCount = $searchResultCount + 1 ) <tr> <td style="vertical-align:middle"> <p><a href="$action.getGlobalSettings().getBaseUrl()$page.getUrlPath()" target="_blank">$page.title</a></p> </td> <td style="vertical-align:middle"> #if ( $permissionHelper.canEdit($action.remoteUser, $page) ) #set ( $replacedPageMarkup = $pageMarkup.replaceAll($requestedSearch, $requestedReplace) ) #set ( $newPageMarkup = $replacedPageMarkup.replaceAll('"', '@@quot@@').replaceAll('"', '@@quot@@') ) #set ( $newPageMarkup = $newPageMarkup.replaceAll(" ", " ") ) ## because of some sort of bug where is replaced with  #set ( $quoteEscapedPageMarkup = $pageMarkup.replaceAll('"', '@@quot@@').replaceAll('"', '@@quot@@') ) <input class="page-checkbox unchanged" type="checkbox" id="page-$pageId" pageid="$pageId" version="$page.version" title="$page.title" parent="$page.parent.id" space="$space.key" content="$newPageMarkup" original="$quoteEscapedPageMarkup" checked="checked"> <span class="aui-lozenge">unchanged</span> #else <span class="aui-lozenge aui-lozenge-current">cannot edit</span> #end </td> <td> <button id="preview${pageId}" class="aui-button">Preview</button> <button class="aui-button" onclick="window.open(contextPath + '/pages/editpage.action?pageId=$pageId', '_blank');">Edit</button> <button style="display:none;" id="undo-${pageId}" class="aui-button" onclick="window.open(contextPath + '/pages/revertpagebacktoversion.action?pageId=${pageId}&version=$page.version', '_blank');">Undo</button> </td> </tr> #end #end </tbody> </table> #end <p> Found $searchResultCount results. You are about to replace "${escapedRequestedSearch}" with "${escapedRequestedReplace}" on all selected pages. Continue? </p> <p> </p> <button class="aui-button" onclick="replaceText()">Continue</button> <button class="aui-button" onclick="window.location = '$content.getUrlPath()'">New Search</button> <script> function replaceText() { searchReplace(jQuery(".page-checkbox.unchanged:checked").first()) } function searchReplace(nextCheckbox) { var pageId = jQuery(nextCheckbox).attr("pageid"); var pageObj = { "id": pageId, "type": "page", "title": jQuery(nextCheckbox).attr("title"), "space": { "key": jQuery(nextCheckbox).attr("space") }, "body": { "storage": { "value": jQuery(nextCheckbox).attr("content").split('@@quot@@').join('"'), "representation": "storage" } }, "version": { "number": parseInt(jQuery(nextCheckbox).attr("version")) + 1 } } jQuery.ajax({ dataType: "json", contentType: "application/json", type: "PUT", url: contextPath + "/rest/api/content/" + pageId, data: JSON.stringify(pageObj), success: function (response) { jQuery(nextCheckbox) .removeClass("unchanged") .addClass("changed"); jQuery(nextCheckbox) .next() .removeClass("aui-lozenge-current") .removeClass("aui-lozenge-error") .addClass("aui-lozenge-complete") .html("updated"); jQuery("#undo-" + pageObj.id).show(); nextCheckbox = jQuery(".page-checkbox.unchanged:checked").first(); if (nextCheckbox.length) { searchReplace(nextCheckbox); } }, error: function() { jQuery(nextCheckbox).removeClass("unchanged").addClass("error"); jQuery(nextCheckbox) .next() .removeClass("aui-lozenge-complete") .removeClass("aui-lozenge-current") .addClass("aui-lozenge-error") .html("error") console.log(response); nextCheckbox = jQuery(".page-checkbox.unchanged:checked").first(); if (nextCheckbox.length) { searchReplace(nextCheckbox); } } }); } </script> #end <script> var nextMatch; var dialogs = {}; var requestedSearch = qs["requestedSearch"]; var requestedReplace = qs["requestedReplace"]; var replace = qs["replace"]; if (replace !== 'true') { requestedReplace = requestedSearch; } if (requestedReplace === "") { requestedReplace = '[Blank]'; } if (requestedSearch) { jQuery(".page-checkbox").each(function() { var pageId = jQuery(this).attr("pageid"); dialogs[pageId] = new AJS.Dialog({ width: 840, height: 640, id: "dialog" + pageId, closeOnOutsideClick: true }); dialogs[pageId].addHeader("Preview"); var replacedMarkup = jQuery(this) .attr("original") .split('@@quot@@') .join('"') .split(htmlDecode(requestedSearch)) .join(' @@start@@ ' + htmlEncode(requestedReplace) + ' @@end@@ '); var formattedMarkup = formatXml(replacedMarkup); var previewMarkup = jQuery('<pre style="white-space: pre-wrap;white-space: -moz-pre-wrap;white-space: -pre-wrap;white-space: -o-pre-wrap;word-wrap: break-word;"><span>' + formattedMarkup .split('<') .join('<') .split('>') .join('>') .split(' @@start@@ ') .join('</span><span class="match" style="background-color: #ddfade;">') .split(' @@end@@ ') .join('</span><span>') + '</span></pre>'); dialogs[pageId].addPanel("SinglePanel", previewMarkup, "singlePanel"); dialogs[pageId].addButton("Next Match", function () { if (!nextMatch) { nextMatch = jQuery(".match:visible").first(); nextMatch.css("background-color", "yellow"); } else { nextMatch.css("background-color", "#ddfade"); nextMatch = nextMatch.next().next(".match").length ? nextMatch.next().next(".match") : jQuery(".match:visible").first(); nextMatch.css("background-color", "yellow"); } nextMatch.get(0).scrollIntoView(); }); dialogs[pageId].addButton("Close", function () { if (nextMatch) { nextMatch.css("background-color", "#ddfade"); nextMatch = undefined; } dialogs[pageId].hide(); }); jQuery("#preview" + pageId).click(function() { dialogs[pageId].gotoPage(0); dialogs[pageId].gotoPanel(0); dialogs[pageId].show(); }); }); } </script>
, multiple selections available,
Related content
Useful Macros Home
Useful Macros Home
More like this
DC - Unresolved Comments Search
DC - Unresolved Comments Search
More like this
Unresolved Comments Search
Unresolved Comments Search
More like this
Security Vulnerability Policy
Security Vulnerability Policy
Read with this
Page Creator
Page Creator
More like this
DC - Inline Comments Overview Report
DC - Inline Comments Overview Report
More like this