0

Is there a way to programmatically copy a wikipage from one location to another, with all of the content?

I've figured how to copy files within a sharepoint site using javascript, mainly following this guide:

http://www.techmikael.com/2013/07/how-to-copy-files-between-sites-using.html

However, if I copy a wikipage (by copying the .aspx file, e.g. wikipage.aspx) to a new location and open it, the page is blank.

Wiki pages can be copied via Site Content and Structure, but I need to do this programmatically, preferably in Javascript

Any help would be greatly appreciated.

Here's my javascript for copying a file in SharePoint:

<head>
    <script src="/sites/customwebconfig/cdn/js/jquery.js"></script> 
    <script type="text/javascript" src="/_layouts/15/SP.RequestExecutor.js"></script>
    <script type="text/javascript" src="/_layouts/15/SP.js"></script>
</head>


<br><br>Source File:
<br><input id="TheSourceFile" class="textarea" type="text" value="/sites/SharepointSandbox/WillsWikiLibSrc/Test.txt" style="width:80%;" >
<br> Destination Folder: 
<br><input id="TheDestFolder" class="textarea" type="text" value="/sites/SharepointSandbox/WillsWikiLib" style="width:80%;">
<br> New FileName: 
<br><input id="TheFileName" class="textarea" type="text" value="TestCopy.txt" style="width:80%;">
<br><br><br>
<input id="test" type="button" value="Copy File" onclick="myFunc()">

<script>

var hostweburl="https://xxxxxxxxx.com";


function myFunc()
{
    console.log("TESTING1!");
    initListName();
    //document.getElementById("test").value="potato1";
    copyFile();
}


function initListName() { 
    var scriptbase = hostweburl + "/_layouts/15/"; 
    $.getScript(scriptbase + "SP.RequestExecutor.js", function(){
        SP.RequestExecutorInternalSharedUtility.BinaryDecode = function SP_RequestExecutorInternalSharedUtility$BinaryDecode(data) {
           var ret = '';

           if (data) {
              var byteArray = new Uint8Array(data);

              for (var i = 0; i < data.byteLength; i++) {
                 ret = ret + String.fromCharCode(byteArray[i]);
              }
           }
           ;
           return ret;
        };

        SP.RequestExecutorUtility.IsDefined = function SP_RequestExecutorUtility$$1(data) {
           var nullValue = null;

           return data === nullValue || typeof data === 'undefined' || !data.length;
        };

        SP.RequestExecutor.ParseHeaders = function SP_RequestExecutor$ParseHeaders(headers) {
           if (SP.RequestExecutorUtility.IsDefined(headers)) {
              return null;
           }
           var result = {};
           var reSplit = new RegExp('\r?\n');
           var headerArray = headers.split(reSplit);

           for (var i = 0; i < headerArray.length; i++) {
              var currentHeader = headerArray[i];

              if (!SP.RequestExecutorUtility.IsDefined(currentHeader)) {
                 var splitPos = currentHeader.indexOf(':');

                 if (splitPos > 0) {
                    var key = currentHeader.substr(0, splitPos);
                    var value = currentHeader.substr(splitPos + 1);

                    key = SP.RequestExecutorNative.trim(key);
                    value = SP.RequestExecutorNative.trim(value);
                    result[key.toUpperCase()] = value;
                 }
              }
           }
           return result;
        };

        SP.RequestExecutor.internalProcessXMLHttpRequestOnreadystatechange = function SP_RequestExecutor$internalProcessXMLHttpRequestOnreadystatechange(xhr, requestInfo, timeoutId) {
           if (xhr.readyState === 4) {
              if (timeoutId) {
                 window.clearTimeout(timeoutId);
              }
              xhr.onreadystatechange = SP.RequestExecutorNative.emptyCallback;
              var responseInfo = new SP.ResponseInfo();

              responseInfo.state = requestInfo.state;
              responseInfo.responseAvailable = true;
              if (requestInfo.binaryStringResponseBody) {
                 responseInfo.body = SP.RequestExecutorInternalSharedUtility.BinaryDecode(xhr.response);
              }
              else {
                 responseInfo.body = xhr.responseText;
              }
              responseInfo.statusCode = xhr.status;
              responseInfo.statusText = xhr.statusText;
              responseInfo.contentType = xhr.getResponseHeader('content-type');
              responseInfo.allResponseHeaders = xhr.getAllResponseHeaders();
              responseInfo.headers = SP.RequestExecutor.ParseHeaders(responseInfo.allResponseHeaders);
              if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 1223) {
                 if (requestInfo.success) {
                    requestInfo.success(responseInfo);
                 }
              }
              else {
                 var error = SP.RequestExecutorErrors.httpError;
                 var statusText = xhr.statusText;

                 if (requestInfo.error) {
                    requestInfo.error(responseInfo, error, statusText);
                 }
              }
           }
        };
    }); 


}



function copyFile() { 
    var sourceUrl="https://xxxxxxxxxxxxx.com/sites/SharepointSandbox/";//provide source site url
    var destUrl="https://xxxxxxxxxxxxx.com/sites/SharepointSandbox/";//provide destination site url 
    //document.getElementById("test").value="potato";
    console.log("POTATO!");

    // Create a request executor.
    var sourceExecutor = new  SP.RequestExecutor(sourceUrl); 
    var targetExecutor = new SP.RequestExecutor(destUrl); 
    var fileName= document.getElementById("TheSourceFile").value;   //"/sites/SharepointSandbox/WillsWikiLibSrc/Test.txt";

    //provide file name with path 
    var fileContentUrl=sourceUrl+"_api/web/GetFileByServerRelativeUrl('"+fileName+"')/$value";

    var targetSiteUrl=destUrl;

    //var folderName='ProjectAttachments';

    var newFileName=document.getElementById("TheFileName").value;  //"TestCopy.txt";//New name of added file
    var folderName= document.getElementById("TheDestFolder").value; //"/sites/SharepointSandbox/WillsWikiLib";
//provide folder path to which file to be copied
    var restUrl=targetSiteUrl+"/_api/web/GetFolderByServerRelativeUrl('"+folderName+"')/Files/Add(url='"+newFileName+"',overwrite=true)";

    $.ajax({
        url: targetSiteUrl + "_api/contextinfo",
        type: "POST",
        headers: {
            "Accept": "application/json;odata=verbose"
        },
        success: function (data) {
            var digest = data.d.GetContextWebInformation.FormDigestValue;
            // Build executor action to retrieve the file data.
            var getFileAction = {
                url: fileContentUrl,
                method: "GET",
                binaryStringResponseBody: true,
                success: function (getFileData) {
                    // Get the binary data.
                    var result = data.body;
                    // Build executor action to copy the file data to the new location.
                    var copyFileAction = {
                        url: restUrl,
                        method: "POST",
                        headers: {
                            "Accept": "application/json; odata=verbose",
                            "X-RequestDigest": digest
                        },
                        contentType: "application/json;odata=verbose",
                        binaryStringRequestBody: true,
                        body: getFileData.body,
                        success: function(copyFileData) {
                        alert("successfully Copied");
                        },
                        error: function(ex) {
                        alert("Something went wrong, please try again later");
                            //show your 'failed' message
                        }
                    };

                    targetExecutor.executeAsync(copyFileAction);
                },
                error: function(ex) {
                    //fail
                    alert("Something went wrong, please try again later");
                }
            };
            sourceExecutor.executeAsync(getFileAction);
        },
        error: function(ex) {
            //fail
            alert("Something went wrong, please try again later");
        }
    });
}

$(document).ready(function() {

  $('.textarea').keydown(function(event){
    var position1 = $(':focus').prop("selectionStart");
    var position2 = $(':focus').prop("selectionEnd");

    //37 left. 39 right. 38 up. 40 down. 8 backspace. 13 enter. 9 tab. 46 delete. .
    switch(event.keyCode){
        case 37: //left arrow
            event.preventDefault();
            setCaretPosition(document.activeElement,position1-1)
            break;
        case 39: //right arrow
            event.preventDefault();
            setCaretPosition(document.activeElement,position1+1)
            break;  
        case 38: //up
        case 40: //down
        case 9:  //tab
            event.preventDefault();
            break;
        case 46: //delete
            event.preventDefault();
            var eqText = document.activeElement.value;
            if(position1 == position2){
                eqText = eqText.slice(0,position1) + eqText.slice(position1+1,eqText.length) 
                document.activeElement.value = eqText;
                setCaretPosition(document.activeElement,position1)
            }else{
                eqText = eqText.slice(0,position1) + eqText.slice(position2,eqText.length) 
                document.activeElement.value = eqText;
                setCaretPosition(document.activeElement,position1)          
            }
            break;
        case 8: //backspace
            event.preventDefault();
            var eqText = document.activeElement.value;
            if(position1 == position2 && position1 != 0){
                eqText = eqText.slice(0,position1-1) + eqText.slice(position1,eqText.length) 
                document.activeElement.value = eqText;
                setCaretPosition(document.activeElement,position1-1)
            }else{
                eqText = eqText.slice(0,position1) + eqText.slice(position2,eqText.length) 
                document.activeElement.value = eqText;
                setCaretPosition(document.activeElement,position1)          
            }
            break;
        default:
            break;
    } 
  }); 
});

//Sets the cursor position to a specified location in a textarea
function setCaretPosition(elem, caretPos) {
    if(elem != null) {
        if(elem.createTextRange) {
            var range = elem.createTextRange();
            range.move('character', caretPos);
            range.select();
        }
        else {
            if(elem.selectionStart) {
                elem.focus();
                elem.setSelectionRange(caretPos, caretPos);
            }
            else
                elem.focus();
        }
    }
}
</script>

Edit:

Getting an error when I try and create a page. Here's the code I have, I

function createPage() {
    // add blank wiki pagef
    // ServerRelativeUrl is /sites/technical/sp/Examples/_NewPage.aspx
    return $.ajax({
    url: "https://xxxxxxxx.com/sites/SharepointSandbox/_api/web/GetFolderByServerRelativeUrl('/sites/SharepointSandbox/FileDest')/Files/AddTemplateFile(urlOfFile='/sites/SharepointSandbox/FileDest/asdf_5_copy.aspx', templateFileType=1)",

    type: "POST",
    headers: {
        "accept": "application/json;odata=verbose",
        "content-type": "application/json;odata=verbose",
        "X-RequestDigest": digest,
    },
    success: function (data) {
        // call function do fill wiki with content
    //  alert('created, now update with template '  );
     },
    error: function (err) {
        // handle error
        alert('bummer create page ' + JSON.stringify(err));
    }
});

}
1
  • We can use spd workflow, to copy documents from one library to other, using copy document action Oct 6, 2017 at 12:03

1 Answer 1

0

I kind of got lost in your code - I've done this before but a bit differently. We seem to be doing something similar. In my case, I was copying a template page to a new page. Maybe this will give you a few hints?

You have to create a page first, which will be blank.

You then have to get that page ID, then go get your original page to get the info to update your new page.

Here are some of my pieces. My main function (the important functions are createPage, getPageID, updatePage:

function createAndUpdatePage() {
    getLibraryNameTitle();
    templatePage = $('#fmgTemplateName').val();
    newPageName = $('#fmgPageName').val();
    if(!newPageName) { newPageName = "_NewPage";}
    if(newPageName.length < 6 || newPageName.substr(newPageName.length-5,5) != '.aspx') { newPageName += '.aspx';}

    // create page, we will need the ID
    createPage().then(function(data) {
                        getPageID().then(function(pageData) {
                                    pageID = pageData.d.ID;
                                    getListItemType().then(function(data) {
                                                            updatePage(data);
                                                    });
                                  });
              }).fail(function(err) {
        alert('create page error: ' + JSON.stringify(err));
                    });
}

Here is how to create the blank wiki page (which will be updated by the template)

function createPage() {
        // add blank wiki pagef
        // ServerRelativeUrl is /sites/technical/sp/Examples/_NewPage.aspx
    var newName = _spPageContextInfo.webServerRelativeUrl + "/" + libraryName + "/" + newPageName;
     return $.ajax({
    url: _spPageContextInfo.webServerRelativeUrl +
    "/_api/web/GetFolderByServerRelativeUrl('" + libraryName + "')/Files" +
    "/AddTemplateFile(urlOfFile='" + newName + "', templateFileType=1)",
    type: "POST",
    headers: {
        "accept": "application/json;odata=verbose",
        "content-type": "application/json;odata=verbose",
        "X-RequestDigest": $("#__REQUESTDIGEST").val(),
    },
    success: function (data) {
        // call function do fill wiki with content
    //  alert('created, now update with template '  );
     },
    error: function (err) {
        // handle error
        alert('bummer create page ' + JSON.stringify(err));
    }
});

}

I knew what my new page was called, so I could go back and get its ID by:

function getPageID() {
    return $.ajax({
    url: _spPageContextInfo.webServerRelativeUrl +
    "/_api/web/GetFolderByServerRelativeUrl('" + libraryName + "')/Files/getbyurl('" + newPageName + "')/ListItemAllFields" ,
    type: "GET",
    headers: {
        "accept": "application/json;odata=verbose",
        "content-type": "application/json;odata=verbose",
     },
    success: function (data) {
        // call function do fill wiki with content

     },
    error: function (err) {
        // handle error
        alert('get id ' + JSON.stringify(err));
     }
    });
}

Then I went to get the information from my original page:

function getTemplate() {
    return $.ajax({
    url: _spPageContextInfo.webServerRelativeUrl +
    "/_api/web/GetFolderByServerRelativeUrl('" + templateLibrary + "')/Files/getbyurl('" + templatePage + "')/ListItemAllFields" ,
    type: "GET",
    headers: {
        "accept": "application/json;odata=verbose",
        "content-type": "application/json;odata=verbose",
     },
    success: function (data) {

     },
    error: function (err) {
        alert('bummer get template ' + JSON.stringify(err));
     }
});

}

And used that to update the new page I just created.

function updatePage(newPageData) {
    getTemplate().then(function (data) {
         //success code here, use data.d.WikiField 

        $.ajax({
        url:  _spPageContextInfo.webServerRelativeUrl + "/_api/web/lists/getbytitle('" + libraryTitle + "')/items(" + pageID + ")",
        type: "POST",
        headers: {
            "accept": "application/json;odata=verbose",
            "content-type": "application/json;odata=verbose",
            "X-RequestDigest": $("#__REQUESTDIGEST").val(),
            "X-HTTP-Method": "MERGE",
            "If-Match": "*"
        },
        data: JSON.stringify({
        "__metadata": { "type": listItemEntityType },
        "WikiField": data.d.WikiField

        } ),
        success: function(data) {
            window.location.href =  _spPageContextInfo.webServerRelativeUrl + "/" + libraryName + "/" + newPageName;
        },
        error: function(err) {
            alert('update error: ' + JSON.stringify(err));
        }

        }) ;
    }); // then

}

Here's the code for getting the list type:

function getListItemType() {
    return $.ajax(
{
    "url": "/<YOURSITE>/_api/web/lists/getbytitle('" + libraryTitle + "')?$Select=ListItemEntityTypeFullName",
    "method": "GET",
    "headers": {
        "accept": "application/json; odata=verbose"
    },
        success: function(data) {
            listItemEntityType = data.d.ListItemEntityTypeFullName;
        },
        error: function(err) {
            alert('type error: ' + JSON.stringify(err));
        }
});
}

Now some of these functions need the library Name, the one used in the URL, and some of the functions get the information by the library Title. I used a hard coded select statement to give the user the library names available:

<select id="fmgLibraryName">
<option value="LAGOWiki">LAGOWiki</option>
</select>

Usually the name and title will be the same, but if someone has been messing around with names, or they look messy, you'll need something like this (the switch is if things are really messed up, that was the only way I could deal with a very mixed up library) This is actually badish code - you basically just need to have the name that is in the URL, and the Title that is the display title. Folders will mess you up as well if you've got any - usually you don't, but we started out with folders and then got rid of them, but my code stayed the same.

function getLibraryNameTitle() {
            // get library name
    libraryName = $('#fmgLibraryName').val();
    // if the title of your library is different than the library name
    // removes any folders
    // used in the url, you're going to have to add it to the
    // the case statement below.
    libraryTitle = libraryName.split('/')[0];
    switch(libraryTitle) {
        case "LAGOWiki": {libraryTitle = "LAGO-Wiki";break;}
    }

}
10
  • You are my hero! Seriously! This is exactly what I was looking for. Thanks a ton, gonna try and implement this and see if I can get it working :)
    – Nick
    Oct 6, 2017 at 17:32
  • Is there any chance you could post your code for creating a page too? (the createPage() function)
    – Nick
    Oct 6, 2017 at 17:42
  • Also, I'm not sure what to use for wikitype and wikigroup
    – Nick
    Oct 6, 2017 at 18:35
  • the wikitype and wikigroup you can ignore - those were fields we added to help organize the library. Remove those lines. I'll add in my createPage() function in a sec Oct 6, 2017 at 18:45
  • Thanks a ton Robin. There's one more thing I'm unsure about, and that's the libraryTitle. Does your function getLibraryNameTitle(); get that information? url: _spPageContextInfo.webServerRelativeUrl + "/_api/web/lists/getbytitle('" + libraryTitle + "')/items(" + pageID + ")",
    – Nick
    Oct 6, 2017 at 19:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.