2017-05-04 99 views
0

開發一個Word插件,你可以選擇一個docx文件,並將它插入到新的空白文檔中 - 一個templateHandler類型。Word插件不能在線使用word

每個docx文件都有一個包含多個RTF - contentControrrs的頁腳。在加載文檔(insertFileFromBase64)之前,代碼中有一個thisDocument.body.clear()。

在當地wordclient有加載不同的文檔沒有問題,但在網上的話,我就得到一個body.clear錯誤(): 與Word不在線支持的行動

編輯:代碼調整爲使頁眉和頁腳與docx-file分離,並使用insertOoxml插入。當你打開插件時,它們會被初始化。 body.clear()不再是一個問題。

在頁腳中還有contenControllers的結果。他們可以在網絡版本中退出。

編輯:他們現在可見,因爲頁腳是從docx單獨加載。 現在只有一個很大的問題就是 - 當打開插件時,您只能在文檔的一行中進行編輯。如果你敲擊文字,它會變得不可見。如果您通過從插件加載一個docx文件更改爲另一個docx文件,則文本在body中不可見。

我使用office.js 1.1我跑的office365是開發商的evaluationversion:V 1609(建設7369.2127)

這是main.js的內容:

console.log("mains.js is present! "); 

(function() { 
"use strict"; 

// Initialize 
Office.initialize = function (reason) { 
    $(document).ready(function() { 
     app.initialize(); 
     // Use this to check whether the new API is supported in the Word client. 
     if (Office.context.requirements.isSetSupported("WordApi", "1.1")) { 

      console.log('Den här koden är optimerad för Word 2016.'); 

      // Load the doc names from the service into the UI. 
      getDocNames(); 
      console.log("Getting Documents"); 



      addFooter(); 
      //console.log("Adding Footer"); 

      addHeader(); 
      //console.log("Adding Header"); 

      //getDataFromSelection(); 
      //getAllContentControls(); 

      // Setup the event handlers for UI. 
      $('#selectDocument').change(selectDocumentHandler); 
      $('#changeContent').click(contentControlHandler); //TODO:validateFields 
      $('#clearContent').click(clearContent); 
      $('#get-data-from-selection').click(getDataFromSelection); 

     } 
     else { 
      console.log('Du måste använda Word 2016 för att det här ska fungera.'); 
     } 
    }); 
}; 
function clearContent() { 
    $('input[type=text]').val(''); 
} 

     // Function for getting header and footer 

function getHeaderFooter(fileName) { 

    var myOOXMLRequest = new XMLHttpRequest(); 

    var myXML; 

    myOOXMLRequest.open('GET', fileName, false); 

    myOOXMLRequest.send(); 

    if (myOOXMLRequest.status === 200) { 

     myXML = myOOXMLRequest.responseText; 
     return myXML; 
    } 
Office.context.document.setSelectedDataAsync(myXML, { coercionType: 'ooxml' }); 
    //return ""; 
} 

/* Word JS functions */ 

function addHeader() { 
    // Run a batch operation against the Word object model. 
    Word.run(function (context) { 

     // Create a proxy sectionsCollection object. 
     var sections = context.document.sections; 
     //mySections.body.clear(); 
     // Queue a commmand to load the sections. 
     context.load(sections, 'body/style'); 

     return context.sync().then(function() { 

      var header = sections.items[0].getHeader("primary"); 
      //header.clear(); 
      var templateHeader = getHeaderFooter('/xml/simrisHeader.xml'); 

      header.insertOoxml(templateHeader, Word.InsertLocation.replace); 

      return context.sync().then(function() { 
       console.log("Added a header to the first section."); 
      }); 
     }); 
    }) 
     .catch(function (error) { 
      console.log('Error: ' + JSON.stringify(error)); 
      if (error instanceof OfficeExtension.Error) { 
       console.log('Debug info: ' + JSON.stringify(error.debugInfo)); 
      } 
     }); 
} 

function addFooter() { 
    Word.run(function (context) { 

     var sections = context.document.sections; 
     //context.document.clear(); 
     context.load(sections, 'body/style'); 
     return context.sync().then(function() { 

      var footer = sections.items[0].getFooter("primary"); 
      //context.footer.clear(); 

      var templateFooter = getHeaderFooter('/xml/simrisFooter.xml'); 

      footer.insertOoxml(templateFooter, Word.InsertLocation.replace); 
      // var contentControls = footer.contentControls; 
      //getAllContentControls(); 

      return context.sync().then(function() { 
       console.log("Added a footer to the first section."); 
      }); 
     }) 
      .catch(function (error) { 
       console.log('Error: ' + JSON.stringify(error)); 
       if (error instanceof OfficeExtension.Error) { 
        console.log('Debug info: ' + JSON.stringify(error.debugInfo)) 
       } 
      }); 

    }); 
} 

    function displayContents(myBase64) { 
     Word.run(function (context) { 

      var thisDocument = context.document; 

      thisDocument.body.clear(); 

      var mySelection = thisDocument.getSelection(); 

      mySelection.insertFileFromBase64(myBase64, "replace"); 

      return context.sync() 
       .then(function() 
        getAllContentControls();   
       }); 
     }) 
      .catch(function (error) { 
       app.showNotification('Error: ' + JSON.stringify(error)); 
       if (error instanceof OfficeExtension.Error) { 
        app.showNotification('Debug info: ' + JSON.stringify(error.debugInfo)); 
       } 
      }); 
    } 

// Using the Word JS API. Gets all of the content controls that are in the loaded document. 
function getAllContentControls() { 
    Word.run(function (context) { 

     var thisDocument = context.document; 

     var contentControls = thisDocument.contentControls; 

     contentControls.load('tag, title'); 

     return context.sync(contentControls).then(function() { 

      var uniqueFields = removeDuplicateContentControls(contentControls); 

      // Create HTML inputfields based on the content controls. 
      createFields(uniqueFields); 

     }) 
    }) 
     .catch(function (error) { 
      app.showNotification('Error: ' + JSON.stringify(error)); 
      if (error instanceof OfficeExtension.Error) { 
       app.showNotification('Debug info: ' + JSON.stringify(error.debugInfo)); 
      } 
     }); 
} 

// Using the Word JS API. Set the values from the INPUT elements into the associated 
// content controls to make the doc. 
function contentControlHandler() { 

    var entryFields = document.getElementById("entryFields").querySelectorAll("input"); 

    // Loading the contentcontrols again. 
    Word.run(function (context) { 

     // Create a proxy object for the document. 
     var thisDocument = context.document; 

     // Create a proxy object for the contentcontrol collection in the document. 
     var contentControls = thisDocument.contentControls; 

     // Queue a command to load the contentcontrols collection with the tag and title properties. 
     contentControls.load('tag, title'); 

     return context.sync() 
      .then(function() { 

       var i, j; 

       // Map each input element to the associated content control. 
       for (i = 0; i < entryFields.length; i++) { 
        for (j = 0; j < contentControls.items.length; j++) { 
         // Matching content control tag with the tag set as the id on each input element. 
         if (contentControls.items[j].tag === entryFields[i].id && entryFields[i].value != 0) { 
          contentControls.items[j].insertText(entryFields[i].value.trim(), Word.InsertLocation.replace) 
         } 
        } 
       } 
      }) 
      .then(context.sync); 

    }) 
     .catch(function (error) { 
      app.showNotification('Error: ' + JSON.stringify(error)); //console.log 
      if (error instanceof OfficeExtension.Error) { 
       app.showNotification('Debug info: ' + JSON.stringify(error.debugInfo)); //console.log 
      } 
     }); 
} 

// Handles the doc selection in the add-in UI. Results in a call to the service to get 
// a docx file that contains a doc. The doc gets displayed in the Word UI. 
function selectDocumentHandler() { 

    // Form the URL to get the docx file. Need to remove the host information by slicing 
    // off the host information beginning at ?_host_Info. 
    var fileName = this.value; 
    var currentUrl = location.href.slice(0, location.href.indexOf('?')); 
    var getFileUrl = currentUrl + 'getfile?filename=' + fileName; 

    // Call the helper to get the selected file then insert the file into Word. 
    httpGetAsync(getFileUrl, function (response) { 
     displayContents(response); 
    }); 
} 

/* UI functions */ 

function getDocNames() { 

    // Form the URL to get the docx file list. Need to remove the host information by slicing 
    // off the host information beginning at ?_host_Info. 
    var currentUrl = location.href.slice(0, location.href.indexOf('?')); 
    var getFileNamesUrl = currentUrl + 'getfilenames'; 

    // Call the helper to get the file list and then create the dropdown listbox from the results. 
    httpGetAsync(getFileNamesUrl, function (rawResponse) { 

     // Helper that processes the response so that we have an array of filenames. 
     var response = processResponse(rawResponse); 

     // Get a handle on the empty drop down list box. 
     var select = document.getElementById("selectDocument"); 

     // Populate the drop down listbox.  
     for (var i = 0; i < response.length; i++) { 
      var opt = response[i]; 
      var el = document.createElement("option"); 
      el.text = opt; 
      el.value = opt; 
      select.appendChild(el); 
     }; 

     //$(".ms-Dropdown").Dropdown(); 
    }); 
} 

// Creates HTML inputfields 
function createFields(uniqueFields) { 

    // Get the DIV where we will add out INPUT-controls. 
    var entryFields = document.getElementById("entryFields"); 

    // Clear the contents in case it has already been populated with INPUT controls. 
    while (entryFields.hasChildNodes()) { 
     entryFields.removeChild(entryFields.lastChild); 
    } 

    // Create a unique INPUT element for each unique contentcontrol-tag. 
    for (var i = 0; i < uniqueFields.length; i++) { 

     var newLabel = document.createElement("label"); 
     newLabel.appendChild(document.createTextNode(uniqueFields[i].title + ': ')); 
     document.getElementById('entryFields').appendChild(newLabel); 

     var input = document.createElement("input"); 

     newLabel.className = 'ms-label'; 

     input.type = "text"; 

     input.id = uniqueFields[i].tag; 

     input.className = 'ms-TextField-field'; 

     entryFields.appendChild(input); //, input.value 

     entryFields.appendChild(document.createElement("br")); 

    } 

} 

// Get data from AAD and displays user information 
function getDataFromSelection() { 
    var baseEndpoint = 'https://graph.microsoft.com'; 
    var authContext = new AuthenticationContext(config); 

    Office.context.document.getSelectedDataAsync(Office.CoercionType.Text, 
     function (result) { 
      if (result.status === Office.AsyncResultStatus.Succeeded) { 

       authContext.acquireToken(baseEndpoint, function (error, token) { 
        if (error || !token) { 
         app.showNotification("Ingen token: ", "Du får logga in igen."); // + error 
        } 
        var email = authContext._user.userName; 
        var url = "https://graph.microsoft.com/v1.0/" + config.tenant + "https://stackoverflow.com/users/" + email; 

        var html = "<ul>"; 
        $.ajax({ 
         beforeSend: function (request) { 
          request.setRequestHeader("Accept", "application/json"); 
         }, 
         type: "GET", 
         url: url, 
         dataType: "json", 
         headers: { 
          'Authorization': 'Bearer ' + token, 
         }, 
         success: function (response) { 
          console.log('Hämtar inehåll och populerar Kontroller!'); 
          //utilize your callback function 
          postDataToContentControlers(response); 
         } 
        }).done(function (response) { 
         html += getPropertyHtml("Namn", response.displayName); 
         html += getPropertyHtml("Titel", response.jobTitle); 
         html += getPropertyHtml("Avdelning", response.officeLocation); 
         html += getPropertyHtml("Telefon jobb", response.businessPhones); 
         $("#results").html(html); 
        }).fail(function (response) { 
         app.showNotification('Inloggningen slutade att fungera!', 'Du får logga ut och prova att logga in igen'); //response.responseText 
        }); 
       }); 
      } else { 
       app.showNotification('Error:', 'Något gick fel. Du får logga in igen.'); //result.error.message 
      } 
     } 
    ); 
} 

function getPropertyHtml(key, value) { 
    return "<li><strong>" + key + "</strong> : " + value + "</li>"; 
} 

function postDataToContentControlers(response) { 
    // Loading the contentcontrols again. 
    Word.run(function (context) { 

     // Create a proxy object for the document. 
     var thisDocument = context.document; 

     // Create a proxy object for the contentcontrol collection in the document. 
     var contentControls = thisDocument.contentControls; 

     // Queue a command to load the contentcontrols collection with the tag and title properties. 
     contentControls.load('tag, title'); 

     return context.sync() 
      .then(function() { 

       var i, j; 

       var responseArrayKey = Object.keys(response).map(function (v) { return v }); 

       // Map each data element to the associated content control. 
       for (i = 0; i < responseArrayKey.length; i++) { 

        for (j = 0; j < contentControls.items.length; j++) { 

         console.log("responseArrayKey: ", responseArrayKey); 
         // Matching content control tag with the index of each responseArray. 
         if (contentControls.items[j].tag === responseArrayKey[i]) { 

          var responseArrayValue = Object.keys(response).map(function (k) { return response[k] }); 

          contentControls.items[j].insertText(responseArrayValue[i], Word.InsertLocation.replace) 

         } 
        } 
       } 
      }) 
      .then(context.sync); 
    }) 
     .catch(function (error) { 
      app.showNotification('Error: ' + JSON.stringify(error)); //console.log 
      if (error instanceof OfficeExtension.Error) { 
       app.showNotification('Debug info: ' + JSON.stringify(error.debugInfo)); //console.log 
      } 
     }); 
} 

/* Helper functions */ 

// Helper that deduplicates the set of contentcontrols. 
function removeDuplicateContentControls(contentControls) { 

    var i, 
     len = contentControls.items.length, 
     uniqueFields = [], 
     currentContentControl = {}; 

    for (i = 0; i < len; i++) { 
     currentContentControl[contentControls.items[i].tag] = contentControls.items[i].title; 
    } 

    for (i in currentContentControl) { 

     var obj = { 
      tag: i, 
      title: currentContentControl[i] 
     }; 

     uniqueFields.push(obj); 
    } 

    return uniqueFields; 
} 

// Helper for calls to the service. 
function httpGetAsync(theUrl, callback) { 
    var request = new XMLHttpRequest(); 
    request.open("GET", theUrl, false); 
    request.onreadystatechange = function() { 
     if (request.readyState === 4 && request.status === 200) 
      callback(request.responseText); 
    } 
    request.send(null); 
} 

    // Function for getting the HeaderTemplate 

    function getHeaderTemplate(fileName) { 

    var myOOXMLRequest = new XMLHttpRequest(); 

    var myXML; 

    myOOXMLRequest.open('GET', fileName, false); 

    myOOXMLRequest.send(); 

    if (myOOXMLRequest.status === 200) { 

     myXML = myOOXMLRequest.responseText; 
     return myXML; 
    } 

    return ""; 
} 

// Helper that processes file names into an array. 
function processResponse(rawResponse) { 

    // Remove quotes. 
    rawResponse = rawResponse.replace(/"/g, ""); 

    // Remove opening brackets. 
    rawResponse = rawResponse.replace("[", ""); 

    // Remove closing brackets. 
    rawResponse = rawResponse.replace("]", ""); 

    // Return an array of file names. 
    return rawResponse.split(','); 
} 

// Helper function for treating errors 
function errorHandler(error) { 
    showNotification(error, JSON.stringify(error.debugInfo)); 
    console.log("Error: " + error); 
    if (error instanceof OfficeExtension.Error) { 
     console.log("Debug info: " + JSON.stringify(error.debugInfo)); 
    } 
} 

function validateFields() { 
    //TODO: validating fields 
    console.log('Validating fields'); 
} 

})(); 
index.html

內容manifest

獲取文檔

內容與

的NodeJS處理

希望有人有問題的答案。謝謝=)

+1

你能提供你使用的代碼嗎? –

+0

我只是在你回答的同一時刻用一些代碼編輯它。那麼我把更多=) – MangeD66

回答

0

我是來自MS工程師的Word Rich Rich API的工程師。

而我已經在displayContents中試過了你的腳本代碼。如上所述,此處的腳本在加載文件(調用insertFileFromBase64)之前將調用body.clear()。 body.clear()操作不允許在單詞在線。

我想可能有一些內容在線上不支持字,如字段範圍,錶行內容控制。

如果您可以提供您正在使用的docx文件,那麼我們最好幫助驗證此觀點並找到根本原因。

+0

[鏈接](https://mdproduktion.se/codeandstuff/mainTemplate.docx) – MangeD66

+0

Klick上面的鏈接=) – MangeD66

0

感謝您提供docx文件。

正文中的內容控制之前的「選項卡」不受支持,並且它使內容控件不受支持。因此,body.clear()是不允許的,因爲裏面有一些不受支持的東西。

我建議你刪除本地wordclient中的「Tab」,並在線上傳docx文件。 Body.clear()將以這種方式很好地工作。

PS:段落中心可用於幫助對齊內容控制中心。

+0

謝謝@Jiajia它的工作更好,但我實際上已更改模板位 - 仍然在頭部下面有contentControl。現在我爲頁眉和頁腳執行InsertOoxml。稍後我會調整代碼,以便您可以看到。我現在得到的錯誤是:調試信息:{「code」:「NotAllowed」,「message」:「Word Online不支持該操作,請查看OfficeExtension.Error.debugInfo獲取更多信息。」,「errorLocation」: 「Body.insertOoxml。這是當我點擊選擇另一個docx文件 – MangeD66

+0

當涉及到doc文件。有5個不同的文件,現在只有contentControl在頂部,只是在標題下。當然,在我有imagelogo和文本在頂部之前,它通常不會在Word在線顯示,與footer相同,contentConrtols也不會顯示或填充inputFields – MangeD66

+0

現在我知道頁腳或header.xml:s filecontent導致了這個問題,7個contentControls在頁腳或圖像和文本在header中,我用開源的Word-Add-in-Get-Set-EditOpen-XML-master插件提取xml信息。也許我需要對這些文件進行一些修改,我怎麼知道?我只是將xml文件的內容替換掉了h開發人員應該能夠工作的xml示例 - 而且他們這樣做。唯一不起作用的是當你想改變我留下的1個contentController中的文本時。當我點擊按鈕時,它只啓動文檔的保存處理... – MangeD66