在线编辑Office文件

前言

第一次用SharePoint的时候感觉很惊奇,竟然可以在本地编辑服务器上的Office文件!不过不知道为什么一直没有想要知道为什么可以这样做。

前两天园子里有一篇文章引发了激烈的讨论。其中有人问楼主一些问题,其中就有这个。OK,那就看看到底的为什么吧。

准备

此部分可忽略,可直接看正文部分。

找原因的过程蛮简单。随便打开了公司SharePoint上的Document页,看HTML源码。发现链接的onfocus事件OnLink(this)。

好吧,那就找找这个函数吧。还是看源码,里面没有找到这个函数。那就去引用的两个js文件里看看吧。

最终在init.js里找到了。

function OnLink(elm)
{
    DeferCall('OnLinkDeferCall', elm);
}

DeferCall函数是干嘛的就先不管了,找找OnLinkDeferCall函数。然后在core.js里找着了。

function OnLinkDeferCall(elm)
{
    if (!IsMenuEnabled())
        return false;
    elm.onblur=OutItem;
    elm.onkeydown=PopMenu;
    var elmTmp=FindSTSMenuTable(elm, "CTXName");
    if (elmTmp==null)
        return false;
    OnItem(elmTmp);
    return false;
}

没什么值得注意的,再找PopMenu函数。

function PopMenu(e)
{
    if (!IsMenuEnabled())
        return true;
    if (e==null)
        e=window.event;
    var nKeyCode;
    if (browseris.nav6up)
        nKeyCode=e.which;
    else
        nKeyCode=e.keyCode;
    if (!IsMenuOn() && ((e.shiftKey && nKeyCode==13) || (e.altKey && nKeyCode==40)))
    {
        onKeyPress=true;
        CreateMenu(e);
        onKeyPress=false;
        return false;
    }
    else
        return true;
}

真他娘的悲剧,找CreateMenu函数;继续悲剧,找CreateMenuEx函数;再次悲剧,找AddDocLibMenuItems函数。好吧,在这个函数里有一句:

strAction="editDocumentWithProgID2('"+currentItemFileUrl+"', '"+currentItemProgId+"', '"
+currentItemOpenControl+"', '"+bIsCheckout+"', '"+ctx.HttpRoot+"', '"+currentItemCheckedoutToLocal+"')";

editDocumentWithProgID2函数又调用editDocumentWithProgIDNoUI函数。

editDocumentWithProgIDNoUI里面有一段是这样的:

objEditor=new ActiveXObject(varEditor+".3");
if (objEditor !=null )
{
    if (bCheckout=="1")
    {
        if (!objEditor.CheckoutDocumentPrompt(strDocument, true, varProgID))
        return 1;
    }
    else
    {
        if (strCheckouttolocal=="1")
        fUseLocalCopy=true;
        if (!objEditor.EditDocument3(window, strDocument, fUseLocalCopy, varProgID))
        return 1;
    }
    var  fRefreshOnNextFocus=false;
    fRefreshOnNextFocus=objEditor.PromptedOnLastOpen();
    if (fRefreshOnNextFocus)
    {
        window.onfocus=RefreshOnNextFocus;
    }
    else
    {
        SetWindowRefreshOnFocus();
    }
    return;
}

objEditor.EditDocument3,看来就是varEditor参数的问题了。然后往回找,到AddDocLibMenuItems函数这里卡住了。

function AddDocLibMenuItems(m, ctx)

就两个参数,真他大爷的!

找找currentItemOpenControl参数,没什么有价值的内容。

那就随便看看吧,AddCheckinCheckoutMenuItem函数应该是签入签出用的。函数里有一句:

strAction="CheckoutDocument('"+ctx.HttpRoot+"', '"+url+"', '"+opencontrol+"')";

继续找:

function CheckoutDocument(strhttpRoot, strDocument, strOpenControl)
{
    var stsOpen=null;
    var fRet=true;
    var fClientCheckout=false;
    if (strDocument.charAt(0)=="/" || strDocument.substr(0,3).toLowerCase()=="%2f")
        strDocument=document.location.protocol+"//"+document.location.host+strDocument;
    var strextension=SzExtension(unescapeProperly(strDocument));
    if (FSupportCheckoutToLocal(strextension) &&
        strOpenControl=="SharePoint.OpenDocuments.3")  //应该就是这玩意儿了吧
    {
        stsOpen=StsOpenEnsureEx(strOpenControl);
    }
    if (stsOpen !=null)
    {
        try
        {
            fRet=stsOpen.CheckoutDocumentPrompt(unescapeProperly(strDocument), false, "");
            SetWindowRefreshOnFocus();
            fClientCheckout=true;
            return;
        }
        catch (e)
        {
        }
    }
     if (!fClientCheckout)
        NavigateToCheckinAspx(strhttpRoot, "FileName="+escapeProperly(unescapeProperly(strDocument))+"&Checkout=true");
}

OK,google一下。在MSDN里提到%ProgramFiles%\Microsoft Office\Office14\OWSSUPP.dll 。我的电脑里只有OFFICE11。所以实例化var obj = new ActiveXObject('SharePoint.OpenDocuments.3');用不了。

再看看其他资源,看来还有SharePoint.OpenDocuments.2和SharePoint.OpenDocuments.1,测试一下,都可以用。

 

正文

好吧,既然找着了就试试怎么用的吧。

查了下MSDN,SharePoint.OpenDocuments控件在安装了Office2007后将3用做版本号,Office2003是将2作版本号,Office2003之前的版本以1作版本号。

1.新建网站。

2.网站里新建文件夹,并在文件夹里放拷贝一个word文件test.doc,一个excel文件test.xls。

3.在Default.aspx里写javascript。

var objEditor;
try{
    objEditor = new ActiveXObject("SharePoint.OpenDocuments.3");
}catch(e){
    try{
        objEditor = new ActiveXObject("SharePoint.OpenDocuments.2");
    }catch(e){
        try{
            objEditor = new ActiveXObject("SharePoint.OpenDocuments.1");
        }catch(e){
            alert("你还是洗洗睡吧!");//当然,洗洗睡是解决不了问题的,先装Office吧
        }
    }
}

试试打开,编辑和新建。

expression.ViewDocument(bstrDocumentLocation, varProgID) //俗称“打开”
expression.EditDocument(bstrDocumentLocation, varProgID) //编辑
expression.CreateNewDocument(bstrTemplateLocation, bstrDefaultSaveLocation)//新建文档
/**********************************************************************
参数
expression:一个返回 OpenDocuments 控件 对象的表达式。
bstrDocumentLocation:一个字符串,其中包含要打开以读取的文档的 URL。
varProgID:一个可选字符串,其中包含要用来打开文档的应用程序的 ProgID。如果省略此参数,将使用文档的默认查看器。
bstrTemplateLocation:一个字符串,包含从中创建文档的文档模板的 URL 或创建文档时要调用的应用程序的编程标识符 (progID)。
bstrDefaultSaveLocation:一个字符串,包含可指定用于保存新文档的建议默认位置的路径。
返回值
3个函数返回值都是成功为 true;失败为 false。
***********************************************************************/

按规则分别些好3个函数,然后用3个A标签调用。建个模版,用来创建文件。但是路径不清楚,浏览一遍Default.aspx,把路径改好。刷新一下。

objEditor.ViewDocument("http://localhost:1773/WebSite1/Documents/Test.doc");
objEditor.EditDocument("http://localhost:1773/WebSite1/Documents/Test.xls");
objEditor.CreateNewDocument("http://localhost:1773/WebSite1/Documents/Template.dot","http://localhost:1773/WebSite1/Documents/");

试试Open:

image

点击“确定”,成功以只读打开Test.doc文件。

试试Edit,成功以只读打开。干嘛是只读啊?

Create呢?好吧,可以打开一个新文档,当然是跟模版一个样儿的。在文档中写“Hello Kitty”,保存。见鬼,保存不了。

看来还是只读的问题啊。赋予Documents文件夹Users用户修改、写入权限,问题依然。

部署到IIS看看,毕竟网站最终要靠它的。配置完成,再次修改函数里的路径。然后通过IIS浏览,My God!怎么还是没法保存?明明有修改和写入的权限啊?再通过IIS赋予Documents目录写入权限。大功告成!

结语

OpenDocuments对象的公共方法有十几个,具体可查看MSDN:http://msdn.microsoft.com/zh-cn/library/cc264316(v=office.12).aspx

然后需要注意权限问题。我是在本机测试,IIS是5.1的,如果是IIS6,应该不需要再通过IIS赋权限了。

原文地址:https://www.cnblogs.com/ainijiutian/p/1912305.html