在线编辑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:
点击“确定”,成功以只读打开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赋权限了。