IBM Content Navigator 3.x - 在 AddContentItemDialog 中预填充 ChoiceList 值

IBM Content Navigator 3.x - Pre-filling ChoiceList values in AddContentItemDialog

我们的目标是使用从 PluginService 对象中检索到的值来实现一个预填充的文档创建表单。

当用户右键单击文档并 select "New document from this one" 时,它会触发 Action 打开 AddContentItemDialog。然后,调用该服务来检索 selected 文档的属性(也许没有必要,通过 Firefox 开发者面板我看到大多数,也许所有自定义属性都已经被获取)。

我可以填充文本字段属性,但不能填充 ChoiceList 的属性:它们不会更新,尽管它们 可能 会在内部填充。

这是一段注释过的代码示例:

require(["dojo/_base/declare",
         "dojo/_base/lang",
         "dojo/aspect", 
         "ecm/model/Request",
         "ecm/widget/dialog/AddContentItemDialog"], 
function(declare, lang, aspect, Request, AddContentItemDialog) {        

    // Parameters passed to the service as HttpServletRequest
    // (Custom function)
    var serviceParams = getServicesParams(items[0]);

    // Object store and parentFolder retrieving (needed below)
    var parentFolder = items[0].parent;
    var objectStore = items[0].objectStore;

    // Retrieving the template to use for the dialog
    // (Custom function)
    var entryTemplate = retrieveTemplate(objectStore, parentFolder); 

    // Service call 
    Request.invokePluginService("FormPlugin", "FormService", {
        requestParams: serviceParams,
        requestCompleteCallback: function(response) {
            // Creating the global dialog  box
            var addContentItemDialog  = new AddContentItemDialog();
            // Box containing the document properties
            var addContentItemPropertiesPane =
                addContentItemDialog.addContentItemPropertiesPane;
            // Box containing general stuff
            var addContentItemGeneralPane =
                addContentItemDialog.addContentItemGeneralPane;

            // Showing the dialog box 
            addContentItemDialog.show(
                repository,
                parentFolder,  /* parent folder       */
                true,          /* document being added*/
                false,         /* not virtual          */
                null,          /* no callback function */
                null,          /* no teamspace */
                true,          /* use an entry template */
                entryTemplate, /* entry template */
                true           /* can't choose directory from another rep */
           );

            // Waiting for complete rendering before filling the properties and general fields
            aspect.after(addContentItemPropertiesPane,
                         "onCompleteRendering",
                         function() {
                             // Setting the destination and lock it
                             var folderSelector = addContentItemGeneralPane.folderSelector;
                             folderSelector.setRoot(parentFolder, objectStore);
                             folderSelector .setDisabled(true);

                             // Property filling - Work :-)
                             addContentItemDialog.setTitle("New document from another");
                             addContentItemDialog.setIntroText("This form allow you to create a document from another one.");
                             addContentItemPropertiesPane.setPropertyValue("DocumentTitle", "Prefilled title");                            
                             // Property filling - Doesn't work :-(
                             addContentItemPropertiesPane.setPropertyValue("A_ChoiceList_Prop",
                                    [ "Value\1", "Value\2", "Value\3"]);

                         }, true);
            }
        });
    });
});

也许我错过了一些神奇的 IBM 代码行来完成它。

已更新。 1) 代码现在可以正确等待条目模板内容的检索。 2) 此答案也适用于以前版本的 ICN。 3)这个答案定义了全局范围内的功能。 要格外小心,您可能会遇到与其他插件和 ICN 代码冲突的名称。 请改用回调函数,或为您的函数命名 "strongly"。

我按照以下步骤编写了插件操作:

  1. 检索源文档和父文件夹
  2. 调用插件服务获取被点击文档的属性
  3. 检索条目模板并使用获取的属性填充其默认值
  4. 创建一个 AddContentItemDialog 对象并通过将条目模板传递给它来显示它。

条目模板EntryTemplate 对象描述。它有一个引用数组的键 propertiesOptions 。该数组的每个元素代表一个文档 属性。每个元素都包含一个名为 defaultValue:

的键
EntryTemplate {
    addClassDescription: "An Entry Template",
    ​addClassLabel: "An Entry Template",
    ​addClassName: "AnEntryTemplate",
    ​// [...]
    propertiesOptions: [
        {
            dataType: "xs:string",
            id: "a_prop",
            name: "A Property",
            // [...]
            defaultValue: "A default value",
            // [...]
        },
        // [...]
    ],
    // [...]
}

字符串值作为(显然)字符串传递,日期作为 ISO8601 格式的字符串(yyyy-MM-ddTHH:mm:ss)和列表作为数组传递。

例如,给定 n1n2n3 propertyOption 个条目:

// "xs:string" dataType
entryTemplate.propertiesOptions[n1].defaultValue = "Duck";

// "xs:timestamp" dataType
entryTemplate.propertiesOptions[n2].defaultValue = "1938-04-15T00:00:00";

// "xs:string" dataType, "LIST" cardinality
entryTemplate.propertiesOptions[n3].defaultValue = ["Huey", "Dewey", "Louie"]; 

下面是 PluginAction 的 Javascript client-side 代码的实现。我没有提供服务实现,也没有提供填充条目模板的代码,因为它有点离题。 (更多关于编写ICN插件的内容,可以参考ICN红皮书Customizing and Extending IBM Content Navigator。)

另请注意,我不认为这个答案是设计动作插件的最佳方式,请不要犹豫建议 optimizations/good 实践相关版本。我只是发现重叠回调函数很痛苦,所以我的目标是在 top-level 定义它们中的大部分,我不喜欢单一的代码。

首先,主要块部分:

require(["dojo/_base/declare",
         "dojo/_base/lang",
         "dojo/aspect", 
         "ecm/model/Request",
         "ecm/widget/dialog/AddContentItemDialog"], 
         function(declare, lang, aspect, Request, AddContentItemDialog) {
    /**
     * Use this function to add any global JavaScript methods your plug-in requires.
     */

    lang.setObject("openFilledCreateDocumentFormAction",
            function(repository, items, callback, teamspace, resultSet, parameterMap) {

                // Parameters passed to the service as HttpServletRequest

                var serviceParams = new Object();
                serviceParams.server = items[0].repository.id;
                serviceParams.serverType = items[0].repository.type;
                serviceParams.id = items[0].id;

                // Object store and parentFolder retrieving (needed below)
                var objectStore = items[0].objectStore;
                var parentFolder = items[0].parent;
                var entryTemplateClassName = null;

                // Service call. "FormService" fetch the source document
                // properties, then put them as JSON in the response.
                // The response will be passed to the function
                // requestCompleteCallback (see below)
                Request.invokePluginService(
                        "FormPlugin",
                        "FormService", {
                            requestParams: serviceParams,
                            // Parameters below are for response callback
                            etClassName:"AnEntryTemplate",
                            repository:repository,
                            objectStore:objectStore,
                            parentFolder:parentFolder,
                            AddContentItemDialog:AddContentItemDialog,
                            aspect:aspect,
                            requestCompleteCallback: processRetrievalResponse
                        });
            });
});

FormService 完成后调用 processRetrievalResponse()。在这一篇中,我们将从检索我们想要的模板开始。

function processRetrievalResponse(response) {
    // Some data passed to the parent object of this callback (see above)
    var etClassName = this.etClassName;
    var repository = this.repository;
    var objectStore = this.objectStore;
    var parentFolder = this.parentFolder;
    var AddContentItemDialog = this.AddContentItemDialog;
    var aspect = this.aspect;

    // First we'll retrieve all the templates
    repository.retrieveEntryTemplates(
            function (entryTemplates, document_ET_count, folder_ET_count) {
                var entryTemplate = null;
                // Then we'll search for the one that we want
                for (var i = 0; i < entryTemplates.length; i++) {
                    if (entryTemplates[i] &&
                            entryTemplates[i].addClassName == etClassName) {
                        entryTemplate = entryTemplates[i];
                        break;
                    }
                }
                // No Entry Template = abort.
                if (!entryTemplate) {
                    alert("The Entry Template " +
                            "\"" + etClassName + "\" " +
                            "was not found. Please contact the administrators");
                    return;
                }

                // Now we got the Entry Template, time to retrieve its content
                // First, we design a "waiter" object.
                // We assume here the PluginService returns the values in
                // the "properties" entry of the object response

                retrievalWaiter =
                    new RetrievalWaiter (repository,
                                         objectStore,
                                         parentFolder,
                                         entryTemplate,
                                         response.properties,
                                         AddContentItemDialog,
                                         aspect);
                // Then a call to retrieve its content
                entryTemplate.retrieveEntryTemplate(null, false, true);

                // We ignite the waiter. When the retrieval will be performed,
                // It will fill its default values and use it to display
                // the creation document dialog.                    
                retrievalWaiter.wait();


            }, "Document", parentFolder.id, null, objectStore);
}

RetrievalWaiter代码。在这里,没有 while 循环,因为它会像恶心一样消耗。 该对象仅依赖于 setTimeOut() 来定期检查条目模板内容的检索。

function RetrievalWaiter(repository, objectStore, parentFolder,
                         entryTemplate, properties,
                         AddContentItemDialog, aspect) {
    this.repository = repository;
    this.objectStore = objectStore;
    this.parentFolder = parentFolder;
    this.entryTemplate = entryTemplate;
    this.properties = properties;
    this.aspect = aspect;
    this.wait = 
        function() {
            // If the Entry Template is not yet loaded, wait 500 ms
            // and recheck
            if (!this.entryTemplate.isRetrieved) {
                var _this = this;
                setTimeout(function() {_this.wait();}, 500);                    
                return;
            }
            // Fill the Entry Template with defaults value
            // (got from the PluginServer response, see above)
            fillEntryTemplate(this.entryTemplate, this.properties);

            // Show the document creation dialog with the 
            showDialog(AddContentItemDialog,
                    this.aspect,
                    this.repository, this.objectStore,
                    this.parentFolder, this.entryTemplate);
        }
}

现在,该显示对话框了。

function showDialog(AddContentItemDialog, aspect,
                    repository, objectStore,
                    parentFolder,
                    entryTemplate) {
    var addContentItemDialog  = new AddContentItemDialog();
    var addContentItemPropertiesPane =
        addContentItemDialog.addContentItemPropertiesPane;
    var addContentItemGeneralPane =
        addContentItemDialog.addContentItemGeneralPane;

    addContentItemDialog.show(
            repository,
            parentFolder,  // parent folder 
            true,          // document being added
            false,         // not virtual 
            null,          // no callback function 
            null,          // no teamspace 
            true,          // Use an Entry Template 
            entryTemplate, // Entry template 
            true           // don't allow choosing directory
                           // from another repository
    );

    // Use aspect to set the value *after* the complete rendering
    // of the properties pane   
    aspect.after(
            addContentItemPropertiesPane,
            "onCompleteRendering",
            function() {
                addContentItemDialog.setTitle("Duplicate a document");
                addContentItemDialog.setIntroText(
                        "This form is loaded from a right-clicked document.");
                // Removing the help link to make the form looks like
                // the document creation one
                addContentItemDialog.setIntroTextRef("","");
                // Set parent folder and prevent it from being edited.
                addContentItemGeneralPane.folderSelector.setRoot(parentFolder, objectStore);
                addContentItemGeneralPane.folderSelector.setDisabled(true);

            }, true);
}

// This function relies on the PluginService response.
// It takes the Entry Template, a JSON formatted response
function fillEntryTemplate(entryTemplate, jsonResponse) {
    // My mission ends here. :-)
}