本文是该系列文章的第三篇。在前两篇文章里研究了使用非 Dojo 的 JavaScript 工具库如 jQuery,和 Dojo 在 IBM Content Navigator 插件开发中混用的可能性。在文章中,介绍了很多 Dojo 和 jQuery 混用的例子,例如使用 Dojo 和 jQuery 的 Ajax 调用如 dojo/query/xhr 和 $.ajax() 去实现一些功能。
在本文中我们想提供更多的例子去说明如何使用 jQuery 去直接调用 JavaScript model API,而不是使用 Dojo 和 jQuery 的 Ajax 调用。在这篇文章中代码相较于第二部分,代码中的 Dojo 模块被去掉了,因为实际上我们并不需要真正的去得到 security token。我们把主要的业务逻辑放在了 JQuery 模块中。这样熟悉 jQuery 的编程人员只需要知道一些 Dojo AMD 的知识,就能够专注于在 jQuery 模块中去实现他们的业务逻辑。
本文中的例子是一个纯粹的 jQuery 插件,通过调用 ICN JavaScript model API(会在下面的章节中介绍)来得到当前的 desktop 和 repository,并且展示它们。接着插件会从当前的 repository 中取到可用的 classes,并且通过 jQuery 的下拉列表来展示其中的前十个。插件在 jQuery UI 的 menu 控件中默认显示第一个类的所有有效的属性,或者展示被选中类的所有有效属性。
回页首
IBM Content Navigator 提供了 Java 和 JavaScript 的 API,这样用户可以通过它们去创建自己的应用。而 JavaScript API 又包含可见的 widget 层以及 model 层。Model 层中的类为 ICN 提供的业务逻辑以及数据。Model 层中类也被 Widget 层用来访问以及表示内容服务器中和 ICN 配置文件中的数据。
下面的图显示的了 Model 层中主要类的层级关系。
图 1. ICN JavaScript model 层主要类的层级关系
如图中所示,一个 Desktop 类的实例包含了 Model 层中的其他对象,Desktop 对象具体说明一个用户有权限访问的 repositories, features, actions, 和 viewers。
一个 Repository 类的实例代表了一个具体的存储库。这个存储库可以是一个 IBM Content Manager 或者 IBM Content Manager OnDemand 服务器,或者是一个 IBM FileNet Content Engine 对象存储库(object store)。
Repository 对象使得用户能够访问并且操作一个存储库中的对象。这些对象在 Model 层中被表示为类(classes)。
ContentClass 类代表一个 IBM FileNet P8 存储库中的文档或者文件夹,或者 IBM Content Manager 存储库中项目类型(item type)。一个 ContentClass 对象使得用户能够访问项目并且编辑项目的属性。每一个属性由 AttributeDefinition 类的实例来代表,其包含了属性信息比如类型以及是否允许等。
回页首
我们同样使用在第二篇文章中介绍的方法,通过 Eclipse 扩展插件来创建一个 ICN 的插件。在这个新的 ICN 插件中,我们将主要的业务逻辑代码放在 JQueryModule.js 文件中,而其他的逻辑代码基本与第二部分文章中介绍的一样。所以下面我们主要来介绍一下 JQuery 模块中的逻辑代码。
插件首先会取得当前的桌面和存储库并且展示他们。ecm.model.desktop 代表了当前的桌面对象,getDefaultRepository() 方法会返回一个ecm.model.Repository 类的实例。类 ecm.model.Repository 表示服务器上一个单独的存储库。对于 IBM FileNet P8 内容服务器来说就表示一个单独的对象存储库。
接着插件从当前的存储库中取出所有的可用类。ecm.model.Repository 类有个 retrieveContentClasses() 方法能够取出一个包含 ecm.model.ContentClass 类的数组。这个方法可以添加一个回调函数作为参数。回调函数会在 ecm.model.ContentClass 类的数组被取得并返回后而被调用,数组会作为参数传入回调函数中。
清单 1. 从当前存储库中返回有效的类
var repository = ecm.model.desktop.getDefaultRepository(); repository.retrieveContentClasses(function(contentClasses){…})
插件将使用 jQuery UI 的下拉列表空间来显示前十个 classes。下拉列表控件是一个 jQueryUI 的一种部件。它复制并且扩展了原生的 HTML 中的 selelt 元素,并且克服了原生控件的一些限制。
清单 2. 在 jQueryUI 下拉列表中显示前十个类
var selectmenuId = this.selectmenuId; $("#classes").append("<select id='" + selectmenuId + "'></select>"); $.each(contentClasses, function (i, val) { if (i >= 10) return; $("#" + selectmenuId).append("<option value='" + i + "'>" + val.id + "</option>"); }); $("#" + selectmenuId).selectmenu({…});
插件会在 jQuery UI 的菜单控件中默认显示选择列表中第一个类的所有有效属性,或者是显示被选择类的所有有效属性。ecm.model.ContentClass 类代表了存储库中项目的类。而这个类代表的含义是由存储库类型决定的。对于 IBM FileNet P8 内容服务器,这个类代表了 P8 类(Class)。
类 ecm.model._HasAttributesMixin 提供了用于处理类属性的方法。ContentClass 与_HasAttributesMixin 混合以使用这些方法。其中有一个方法 retrieveAttributeDefinitions() 将类的所有的属性信息返回。并且它可以添加一个回调函数作为参数。当属性信息被返回后,这个回调函数将被调用。而返回的属性信息 ecm.model.AttributeDefinition 数组作为参数传给回调函数。
由于返回的属性中有系统属性和隐藏属性,我们还可以将返回的信息过滤,只保留并显示用户属性。
清单 3. 显示当前选择类的属性
change: function( event, data ) { var contentClass = contentClasses[data.item.value]; contentClass.retrieveAttributeDefinitions(function(attributes){ var menuId = "menu1"; $("#message2").html("<h3>Dojo model returns "+ attributes.length+" attributes.</h3>" ); $("#attributes").empty(); $("#attributes").append("<ul id='" + menuId + "'></ul>"); $.each(attributes, function (i, val) { if(!val.system && !val.hidden){ $("#" + menuId).append("<li>" + val.id + "</li>"); } }); $("#" + menuId).menu(); $("#" + menuId).width("600px"); }); },
图 2. 新插件在 IBM Content Navigator 中的界面显示
清单 4. JQueryModule 代码
jQueryPlugin/JQueryModule.js define(["dojo/_base/declare", "ecm/model/Desktop"], function(declare,Desktop) { var JQueryModule = declare("jQueryPlugin.JQueryModule", [], { jQueryVersion: "jquery-2.1.1", jQueryUiVersion:"jquery-ui-1.11.1", selectmenuId: "selectmenu1", menuId: "menu1", loadJQuery: function(callback) { var _this = this; require({paths: {"jquery":"../plugin/JQueryPlugin/getResource/jQuery/" + this.jQueryVersion, "jqueryui": "../plugin/JQueryPlugin/getResource/jQuery/" + this.jQueryUiVersion + "/jquery-ui"}}, ["jquery", "jqueryui", ], function(jquery, jqueryui) { _this._loadJQueryCSS(); console.log("jQuery ready"); if(callback) { callback(); } }); }, _loadJQueryCSS: function() { $('head').append('<link rel="stylesheet" type="text/css" href="./plugin/JQueryPlugin/getResource/jQuery/' + this.jQueryUiVersion + '/jquery-ui.css">'); }, execute: function() { console.log("assuming jQuery has loaded"); this.showClassesAndAttributes(); }, showClassesAndAttributes: function() { //get the current desktop and repository var repository = ecm.model.desktop.getDefaultRepository(); //it retrieves the available classes from current repository repository.retrieveContentClasses(function(contentClasses){ $("#hello").html("<h3>Hello, world from jquery</h3>"); $("#desktop").html("<h3>Desktop Login: " + ecm.model.desktop.name + "</h3>"); $("#repository").html("<h3>Repository Login: " + repository.id + "</h3>"); $("#message").html("<h3>Dojo model returns "+ contentClasses.length+" classes.</h3>" ); var selectmenuId = this.selectmenuId; //displays the top 10 classes in select menu widget from jQuery UI $("#classes").append("<select id='" + selectmenuId + "'></select>"); $.each(contentClasses, function (i, val) { if (i >= 10) return; $("#" + selectmenuId).append("<option value='" + i + "'>" + val.id + "</option>"); }); $("#" + selectmenuId).selectmenu({ //displays the attributes of selected class in menu widget of jQuery UI change: function( event, data ) { var contentClass = contentClasses[data.item.value]; //retrieves detailed attribute information for the content class contentClass.retrieveAttributeDefinitions(function(attributes){ var menuId = "menu1"; $("#message2").html("<h3>Dojo model returns "+ attributes.length+" attributes.</h3>" ); $("#attributes").empty(); $("#attributes").append("<ul id='" + menuId + "'></ul>"); $.each(attributes, function (i, val) { //filter the attributes and let customer attributes shown if(!val.system && !val.hidden){ $("#" + menuId).append("<li>" + val.id + "</li>"); } }); $("#" + menuId).menu(); $("#" + menuId).width("600px"); }); }, //displays the available attributes of first class by default create: function( event, data ) { var contentClass = contentClasses[0]; if(contentClass){ // retrieves detailed attribute information for the content class contentClass.retrieveAttributeDefinitions(function(attributes){ var menuId = "menu1"; $("#message2").html("<h3>Dojo model returns "+ attributes.length+" attributes.</h3>" ); $("#attributes").empty(); $("#attributes").append("<ul id='" + menuId + "'></ul>"); $.each(attributes, function (i, val) { ////filter the attributes and let customer attributes shown if(!val.system && !val.hidden){ $("#" + menuId).append("<li>" + val.id + "</li>"); } }); $("#" + menuId).menu(); $("#" + menuId).width("600px"); }); }} }); }); }, EOF: null }); return JQueryModule; });
清单 5. 相关的模板文件代码
jQueryPlugin/templates/JQueryFeaturePane.html <div class="ecmjQueryPane"> <div id="hello"></div> <div id="desktop"></div> <div id="repository"></div> <div id="message"></div> <div id="classes"></div> <div id="message2"></div> <div id="attributes"></div> </div>
回页首
插件通过使用 ICN JavaScript model API 中的方法去得到当前的桌面和存储库并显示它们。插件从当前的存储库中去的所有的可用的类,并在 jQueryUI 的选择列表控件中显示其中的前十个。并且显示第一个或者是被选中的类的属性信息。
本文中所作的工作:
本文说明我们能够使用 ICN JavaScript model 层中方法代替 Dojo 和 jQuery 的 Ajax 请求方法直接调用 ICN 服务器。