IBM Content Navigator 3.x - Предварительное заполнение значений ChoiceList в AddContentItemDialog
Мы стремимся реализовать предварительно заполненную форму создания документа со значениями, полученными из PluginService
объект.
Когда пользователь щелкает правой кнопкой мыши на документе и выбирает "Новый документ из этого", он запускает Action
который открывает AddContentItemDialog
, Затем служба вызывается для извлечения свойств выбранного документа (может быть, это и не нужно, через панель разработчиков 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 ответ
Обновлено. 1) Теперь код корректно ожидает получения содержимого шаблона записи. 2) Этот ответ также должен работать с предыдущими версиями ICN. 3) Этот ответ определяет функции в глобальном масштабе. Будьте предельно осторожны, вы можете столкнуться с конфликтным именем с другими плагинами и кодом ICN. Вместо этого используйте функцию обратного вызова или назовите "строго" ваши функции.
Я следовал за этими шагами, чтобы написать Действие Плагина:
- Получить исходный документ и родительскую папку
- Вызов службы плагинов, которая выбирает свойства выбранного документа.
- Получите шаблон ввода и заполните его значения по умолчанию извлеченными свойствами
- Создать
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
) и списки как массивы.
Например, учитывая n1
, n2
, n3
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"];
Ниже приведена реализация клиентского кода Javascript действия PluginAction. Я не предоставил ни реализацию сервиса, ни код для заполнения шаблона ввода, потому что это немного не по теме. (Для получения дополнительной информации о написании подключаемого модуля ICN вы можете обратиться к разделу Настройка и расширение IBM Redbook IBM Content Navigator.)
Также обратите внимание, что я не считаю этот ответ лучшим способом разработки подключаемого модуля действий, не стесняйтесь предлагать варианты оптимизации / передовой практики. Я просто нашел затруднительным использовать функцию обратного вызова, поэтому я решил определить большинство из них на верхнем уровне, мне не нравится монолитный код.
Во-первых, основная часть блока:
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. :-)
}