JavaScript Extension Development API for Oracle Visual Builder Cloud Service - Classic Applications

Source: components.dt/js/api/ComponentFactory.js

define([
    'components.dt/js/api/ComponentProviderRegistry',
    'components.dt/js/api/constants/Collection',
    'components.dt/js/api/constants/EntityDetail',
    'components.dt/js/api/constants/Link',
    'components.dt/js/api/constants/Property',
    'components.dt/js/creators/ViewComposer',
    'components.dt/js/creators/impl/ButtonCreator',
    'components.dt/js/creators/impl/ComboBoxCreator',
    'components.dt/js/creators/impl/DateInputCreator',
    'components.dt/js/creators/impl/DateTimeInputCreator',
    'components.dt/js/creators/impl/EmailInputCreator',
    'components.dt/js/creators/impl/ImageCreator',
    'components.dt/js/creators/impl/LinkCreator',
    'components.dt/js/creators/impl/ListCreator',
    'components.dt/js/creators/impl/NumberInputCreator',
    'components.dt/js/creators/impl/ParagraphCreator',
    'components.dt/js/creators/impl/PropertyCreator',
    'components.dt/js/creators/impl/RichTextCreator',
    'components.dt/js/creators/impl/TableCreator',
    'components.dt/js/creators/impl/TextAreaCreator',
    'components.dt/js/creators/impl/TextInputCreator',
    'components.dt/js/creators/impl/TimeInputCreator',
    'components.dt/js/creators/impl/URLInputCreator',
    'pagedesigner.dt/js/grid/GridOperations',
    'pages.dt/js/api/Pages',
    'pages.dt/js/api/Properties',
    'pages.dt/js/api/View',
    'pages.dt/js/api/ViewType',
    'viewmodel/js/api/ArchetypeFactory',
    'viewmodel/js/api/ArchetypeType',
    'viewmodel.dt/js/api/ArchetypeUtils'
], function (
        componentProviderRegistry,
        Collection,
        EntityDetail,
        Link,
        Property,
        ViewComposer,
        ButtonCreator,
        ComboBoxCreator,
        DateInputCreator,
        DateTimeInputCreator,
        EmailInputCreator,
        ImageCreator,
        LinkCreator,
        ListCreator,
        NumberInputCreator,
        ParagraphCreator,
        PropertyCreator,
        RichTextCreator,
        TableCreator,
        TextAreaCreator,
        TextInputCreator,
        TimeInputCreator,
        URLInputCreator,
        GridOperations,
        Pages,
        Properties,
        View,
        ViewType,
        ArchetypeFactory,
        ArchetypeType,
        ArchetypeUtils
        ) {

    'use strict';

    /**
     * Helper class for component Creators providing various methods for
     * creating views for the associated page. {@link components.dt/js/spi/creators/Creator Creator}
     * implementors should create any view instances through this class instead
     * of trying to instantiate {@link pages.dt/js/api/View View}s on their own.
     *
     * <p>Start with acquiring an instance with {@link components.dt/js/api/ComponentFactory.create ComponentFactory.create},
     * then you can call its instance methods to create various built-in components.</p>
     *
     * @AbcsExtension stable
     * @exports components.dt/js/api/ComponentFactory
     * @param {pages.dt/js/api/Page} page page you will create components for.
     * @version 16.3.5
     * @constructor
     * @private
     */
    var ComponentFactory = function (page) {
        AbcsLib.checkDefined(page, 'page');
        AbcsLib.checkThis(this);
        this._page = page;
    };

    ComponentFactory.ERROR_EXPECTED_LIST = 'Expecting a list view.';
    ComponentFactory.ERROR_CREATOR_NOT_FOUND = function (type) {
        return 'Component creator for \'' + type + '\' not found.';
    };
    ComponentFactory._ERROR_LINK_UNKNOWN_TARGET_TYPE = function (type) {
        return 'Unknown link target type: \'' + type + '\'.';
    };
    ComponentFactory._ERROR_EMPTY_PROPERTIES = function (parameterName) {
        return 'At least one property must be set for \'' + parameterName + '\'';
    };

    /**
     * Factory create method returning an instance of this class.
     *
     * @AbcsExtension stable
     * @static
     * @param {pages.dt/js/api/Page} page page you will create components for.
     * @returns {components.dt/js/api/ComponentFactory}
     * @version 16.3.5
     */
    ComponentFactory.create = function (page) {
        AbcsLib.checkDefined(page, 'page');
        return new ComponentFactory(page);
    };

    ComponentFactory.prototype.createButton = function (createContext) {
        return new ButtonCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Creates a text input component with properties set to the defaults passed in
     * the createContext.
     *
     * @AbcsExtension unstable
     * @param {Object} createContext create context with default component
     * properties to set when the component is created.
     * @param {viewmodel/js/api/Archetype} createContext.archetype bound archetype instance
     * @param {entity/js/api/Property} createContext.boundProperty bound entity field instance
     * @param {String} [createContext.label] input component's label text
     * @param {String} [createContext.labelPosition] input component's label position.
     * Choose one of {@link components.dt/js/api/constants/Input.LabelPosition Input.LabelPosition}
     * @param {String} [createContext.placeholderText] placeholderText text value.
     * @param {Boolean} [createContext.readOnly] flag marking the input component as read-only
     * @param {String} [createContext.helpDefinition] text displayed as the help tooltip
     * next to the component's label.
     * @param {String} [createContext.helpSource] URL of a resource with more detailed help
     * about the component. The URL will be opened when the help icon next to the help
     * icon next to the component's label is clicked.
     *
     * @returns {pages.dt/js/api/View} created text input view
     *
     * @example <caption>Create a required component bound to a property of an entity archetype</caption>
     * var componentFactory = ComponentFactory.create(activePage);
     * var component = componentFactory.createTextInput({
     *     label: 'LABEL',
     *     labelPosition: Link.LabelPosition.LEFT,
     *     archetype: archetypeInstance,
     *     boundProperty: boundPropertyInstance,
     *     placeholderText: 'Enter value',
     *     required: true,
     * });
     *
     * @example <caption>Create a component bound to a property of an entity archetype
     * with clickable help icon opening a URL with detailed help.</caption>
     * var componentFactory = ComponentFactory.create(activePage);
     * var component = componentFactory.createTextInput({
     *     archetype: archetypeInstance,
     *     boundProperty: boundPropertyInstance,
     *     helpDefinition: 'This is help, click to see more',
     *     helpSource: 'http://docs.oracle.com/'
     * });
     */
    ComponentFactory.prototype.createTextInput = function (createContext) {
        AbcsLib.checkParameterCount(1);
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['archetype', 'boundProperty', 'label',
            'labelPosition', 'placeholderText', 'readOnly', 'required', 'helpDefinition', 'helpSource']);
        AbcsLib.checkDefined(createContext.archetype, 'createContext.archetype');
        AbcsLib.checkDefined(createContext.boundProperty, 'createContext.boundProperty');
        return new TextInputCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Creates a date input view with properties set to the defaults passed in
     * the createContext.
     *
     * @AbcsExtension unstable
     * @param {Object} createContext create context with default component
     * properties to set when the view is created.
     * @param {viewmodel/js/api/Archetype} createContext.archetype bound archetype instance
     * @param {entity/js/api/Property} createContext.boundProperty bound entity field instance
     * @param {String} [createContext.label] input component's label text
     * @param {String} [createContext.labelPosition] input component's label position.
     * Choose one of {@link components.dt/js/api/constants/Input.LabelPosition Input.LabelPosition}
     * @param {String} [createContext.placeholderText] placeholderText text value.
     * @param {Boolean} [createContext.readOnly] flag marking the input component as read-only
     * @param {String} [createContext.helpDefinition] text displayed as the help tooltip
     * next to the component's label.
     * @param {String} [createContext.helpSource] URL of a resource with more detailed help
     * about the component. The URL will be opened when the help icon next to the help
     * icon next to the component's label is clicked.
     *
     * @returns {pages.dt/js/api/View} created date input view
     */
    ComponentFactory.prototype.createDateInput = function (createContext) {
        AbcsLib.checkParameterCount(1);
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['archetype', 'boundProperty', 'label',
            'labelPosition', 'placeholderText', 'readOnly', 'required', 'helpDefinition', 'helpSource']);
        AbcsLib.checkDefined(createContext.archetype, 'createContext.archetype');
        AbcsLib.checkDefined(createContext.boundProperty, 'createContext.boundProperty');
        return new DateInputCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Creates a date-time input view with properties set to the defaults passed in
     * the createContext.
     *
     * @AbcsExtension unstable
     * @param {Object} createContext create context with default component
     * properties to set when the view is created.
     * @param {viewmodel/js/api/Archetype} createContext.archetype bound archetype instance
     * @param {entity/js/api/Property} createContext.boundProperty bound entity field instance
     * @param {String} [createContext.label] input component's label text
     * @param {String} [createContext.labelPosition] input component's label position.
     * Choose one of {@link components.dt/js/api/constants/Input.LabelPosition Input.LabelPosition}
     * @param {String} [createContext.placeholderText] placeholderText text value.
     * @param {Boolean} [createContext.readOnly] flag marking the input component as read-only
     * @param {String} [createContext.helpDefinition] text displayed as the help tooltip
     * next to the component's label.
     * @param {String} [createContext.helpSource] URL of a resource with more detailed help
     * about the component. The URL will be opened when the help icon next to the help
     * icon next to the component's label is clicked.
     *
     * @returns {pages.dt/js/api/View} created datetime input view
     */
    ComponentFactory.prototype.createDateTimeInput = function (createContext) {
        AbcsLib.checkParameterCount(1);
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['archetype', 'boundProperty', 'label',
            'labelPosition', 'placeholderText', 'readOnly', 'required', 'helpDefinition', 'helpSource']);
        AbcsLib.checkDefined(createContext.archetype, 'createContext.archetype');
        AbcsLib.checkDefined(createContext.boundProperty, 'createContext.boundProperty');
        return new DateTimeInputCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Creates a time input view with properties set to the defaults passed in
     * the createContext.
     *
     * @AbcsExtension unstable
     * @param {Object} createContext create context with default component
     * properties to set when the view is created.
     * @param {viewmodel/js/api/Archetype} createContext.archetype bound archetype instance
     * @param {entity/js/api/Property} createContext.boundProperty bound entity field instance
     * @param {String} [createContext.label] input component's label text
     * @param {String} [createContext.labelPosition] input component's label position.
     * Choose one of {@link components.dt/js/api/constants/Input.LabelPosition Input.LabelPosition}
     * @param {String} [createContext.placeholderText] placeholderText text value.
     * @param {Boolean} [createContext.readOnly] flag marking the input component as read-only
     * @param {String} [createContext.helpDefinition] text displayed as the help tooltip
     * next to the component's label.
     * @param {String} [createContext.helpSource] URL of a resource with more detailed help
     * about the component. The URL will be opened when the help icon next to the help
     * icon next to the component's label is clicked.
     *
     * @returns {pages.dt/js/api/View} created time view
     */
    ComponentFactory.prototype.createTimeInput = function (createContext) {
        AbcsLib.checkParameterCount(1);
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['archetype', 'boundProperty', 'label',
            'labelPosition', 'placeholderText', 'readOnly', 'required', 'helpDefinition', 'helpSource']);
        AbcsLib.checkDefined(createContext.archetype, 'createContext.archetype');
        AbcsLib.checkDefined(createContext.boundProperty, 'createContext.boundProperty');
        return new TimeInputCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Creates a number input view with properties set to the defaults passed in
     * the createContext.
     *
     * @AbcsExtension unstable
     * @param {Object} createContext create context with default component
     * properties to set when the view is created.
     * @param {viewmodel/js/api/Archetype} createContext.archetype bound archetype instance
     * @param {entity/js/api/Property} createContext.boundProperty bound entity field instance
     * @param {String} [createContext.label] input component's label text
     * @param {String} [createContext.labelPosition] input component's label position.
     * Choose one of {@link components.dt/js/api/constants/Input.LabelPosition Input.LabelPosition}
     * @param {String} [createContext.placeholderText] placeholderText text value.
     * @param {Boolean} [createContext.readOnly] flag marking the input component as read-only
     * @param {String} [createContext.helpDefinition] text displayed as the help tooltip
     * next to the component's label.
     * @param {String} [createContext.helpSource] URL of a resource with more detailed help
     * about the component. The URL will be opened when the help icon next to the help
     * icon next to the component's label is clicked.
     *
     * @returns {pages.dt/js/api/View} created number view
     */
    ComponentFactory.prototype.createNumberInput = function (createContext) {
        AbcsLib.checkParameterCount(1);
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['archetype', 'boundProperty', 'label',
            'labelPosition', 'placeholderText', 'readOnly', 'required', 'helpDefinition', 'helpSource']);
        AbcsLib.checkDefined(createContext.archetype, 'createContext.archetype');
        AbcsLib.checkDefined(createContext.boundProperty, 'createContext.boundProperty');
        return new NumberInputCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Creates an email input view with properties set to the defaults passed in
     * the createContext.
     *
     * @AbcsExtension unstable
     * @param {Object} createContext create context with default component
     * properties to set when the view is created.
     * @param {viewmodel/js/api/Archetype} createContext.archetype bound archetype instance
     * @param {entity/js/api/Property} createContext.boundProperty bound entity field instance
     * @param {String} [createContext.label] input component's label text
     * @param {String} [createContext.labelPosition] input component's label position.
     * Choose one of {@link components.dt/js/api/constants/Input.LabelPosition Input.LabelPosition}
     * @param {String} [createContext.placeholderText] placeholderText text value.
     * @param {Boolean} [createContext.readOnly] flag marking the input component as read-only
     * @param {String} [createContext.helpDefinition] text displayed as the help tooltip
     * next to the component's label.
     * @param {String} [createContext.helpSource] URL of a resource with more detailed help
     * about the component. The URL will be opened when the help icon next to the help
     * icon next to the component's label is clicked.
     *
     * @returns {pages.dt/js/api/View} created email view
     */
    ComponentFactory.prototype.createEmailInput = function (createContext) {
        AbcsLib.checkParameterCount(1);
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['archetype', 'boundProperty', 'label',
            'labelPosition', 'placeholderText', 'readOnly', 'required', 'helpDefinition', 'helpSource']);
        AbcsLib.checkDefined(createContext.archetype, 'createContext.archetype');
        AbcsLib.checkDefined(createContext.boundProperty, 'createContext.boundProperty');
        return new EmailInputCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Creates a URL input view with properties set to the defaults passed in
     * the createContext.
     *
     * @AbcsExtension unstable
     * @param {Object} createContext create context with default component
     * properties to set when the view is created.
     * @param {viewmodel/js/api/Archetype} createContext.archetype bound archetype instance
     * @param {entity/js/api/Property} createContext.boundProperty bound entity field instance
     * @param {String} [createContext.label] input component's label text
     * @param {String} [createContext.labelPosition] input component's label position.
     * Choose one of {@link components.dt/js/api/constants/Input.LabelPosition Input.LabelPosition}
     * @param {String} [createContext.placeholderText] placeholderText text value.
     * @param {Boolean} [createContext.readOnly] flag marking the input component as read-only
     * @param {String} [createContext.helpDefinition] text displayed as the help tooltip
     * next to the component's label.
     * @param {String} [createContext.helpSource] URL of a resource with more detailed help
     * about the component. The URL will be opened when the help icon next to the help
     * icon next to the component's label is clicked.
     *
     * @returns {pages.dt/js/api/View} created URL input view
     */
    ComponentFactory.prototype.createURLInput = function (createContext) {
        AbcsLib.checkParameterCount(1);
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['archetype', 'boundProperty', 'label',
            'labelPosition', 'placeholderText', 'readOnly', 'required', 'helpDefinition', 'helpSource']);
        AbcsLib.checkDefined(createContext.archetype, 'createContext.archetype');
        AbcsLib.checkDefined(createContext.boundProperty, 'createContext.boundProperty');
        return new URLInputCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Creates a paragraph component with properties set to the defaults passed
     * in the createContext.
     *
     * @AbcsExtension unstable
     * @param {Object} createContext create context with default component
     * properties to set when the view is created.
     * @param {String} [createContext.text] default textual content of the paragraph.
     * @param {viewmodel/js/api/Archetype} [createContext.archetype] optional bound archetype instance.
     * When not specified the paragraph will stay unbound and static.
     * @param {entity/js/api/Property} createContext.boundProperty optional bound entity field instance.
     * When not specified the paragraph will stay unbound and static.
     * @param {String[]} [createContext.styleFormat] optional formatting options.
     * Can be chosen from {@link components.dt/js/api/constants/Paragraph Paragraph} predefined
     * options.
     * @param {String} [createContext.styleSize] optional font size options.
     * Can be chosen from {@link components.dt/js/api/constants/Paragraph Paragraph} predefined
     * options.
     *
     * @returns {pages.dt/js/api/View} created paragraph component's view
     */
    ComponentFactory.prototype.createParagraph = function (createContext) {
        AbcsLib.checkParameterCount(1);
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['text', 'archetype', 'boundProperty', 'styleFormat', 'styleSize']);
        if (createContext.styleFormat) {
            AbcsLib.checkDataType(createContext.styleFormat, AbcsLib.Type.ARRAY);
        }

        return new ParagraphCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Create a Rich Text component.
     *
     * @AbcsExtension unstable
     *
     * @param {object} createContext - Create context with default Rich Text
     * properties to set when the view is created.
     * @param {viewmodel/js/api/Archetype} createContext.archetype - Bound archetype instance.
     * @param {entity/js/api/Property} createContext.boundProperty - Bound entity field instance.
     * @param {boolean} [createContext.readOnly] - Flag marking the rich text as read-only.
     * @param {boolean} [createContext.pairView] - Flag to create as pair view (label + rich text).
     *
     * @returns {pages.dt/js/api/View} Created Rich Text component's view.
     */
    ComponentFactory.prototype.createRichText = function (createContext) {
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkDefined(createContext.archetype, 'createContext.archetype');
        AbcsLib.checkDefined(createContext.boundProperty, 'createContext.boundProperty');
        // Backward compatibility: If createContext.pairView is undefined, double
        // negation converts it to false (no pair view), which was the default
        // behavior in previous versions.
        return new RichTextCreator().createView(this._page, undefined, createContext, !!createContext.pairView);
    };

    /**
     * Creates a text area component with properties set to the defaults passed in
     * the createContext.
     *
     * @AbcsExtension unstable
     * @param {Object} createContext create context with default component
     * properties to set when the component is created.
     * @param {viewmodel/js/api/Archetype} [createContext.archetype] bound archetype instance
     * @param {entity/js/api/Property} [createContext.boundProperty] bound entity field instance
     * @param {String} [createContext.label] input component's label text
     * @param {String} [createContext.labelPosition] input component's label position.
     * Choose one of {@link components.dt/js/api/constants/Input.LabelPosition Input.LabelPosition}
     * @param {String} [createContext.placeholderText] placeholderText text value.
     * @param {Boolean} [createContext.readOnly] flag marking the input component as read-only
     * @param {String} [createContext.helpDefinition] text displayed as the help tooltip
     * next to the component's label.
     * @param {String} [createContext.helpSource] URL of a resource with more detailed help
     * about the component. The URL will be opened when the help icon next to the help
     * icon next to the component's label is clicked.
     * @param {Number} [createContext.rows] number of rows the text area should occupy
     * by default.
     *
     * @returns {pages.dt/js/api/View} created text input view
     */
    ComponentFactory.prototype.createTextArea = function (createContext) {
        AbcsLib.checkParameterCount(1);
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['archetype', 'boundProperty', 'label',
            'labelPosition', 'placeholderText', 'readOnly', 'required', 'helpDefinition', 'helpSource', 'rows']);
        if (createContext.rows) {
            AbcsLib.checkDataType(createContext.rows, AbcsLib.Type.NUMBER);
        }
        return new TextAreaCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Creates a combo box view with properties set to the defaults passed in
     * the createContext.
     *
     * @AbcsExtension unstable
     * @param {Object} createContext create context with default combo box
     * properties to set when the view is created.
     * @param {viewmodel/js/api/Archetype} createContext.archetype bound archetype instance
     * @param {entity/js/api/Property} createContext.boundProperty bound entity field instance
     * @param {String} [createContext.label] combo box label text
     * @param {String} [createContext.labelPosition] combo box's label position.
     * Choose one of {@link components.dt/js/api/constants/Input.LabelPosition Input.LabelPosition}
     * @param {String} [createContext.placeholderText] placeholderText text value.
     * @param {entity/js/api/Property} [createContext.displayField] combo box's display field.
     * This specifies what field from the referenced entity will be displayed
     * as the textual value of the combo box items.
     * @param {Boolean} [createContext.readOnly] flag marking the combo box as read-only
     * @param {String} [createContext.helpDefinition] text displayed as the help tooltip
     * next to the component's label.
     * @param {String} [createContext.helpSource] URL of a resource with more detailed help
     * about the component. The URL will be opened when the help icon next to the help
     * icon next to the component's label is clicked.
     *
     * @returns {pages.dt/js/api/View} created combo box view
     */
    ComponentFactory.prototype.createComboBox = function (createContext) {
        AbcsLib.checkParameterCount(1);
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['archetype', 'boundProperty', 'label', 'labelPosition',
            'placeholderText', 'displayField', 'readOnly', 'required', 'helpDefinition', 'helpSource']);
        AbcsLib.checkDefined(createContext.archetype, 'createContext.archetype');
        AbcsLib.checkDefined(createContext.boundProperty, 'createContext.boundProperty');
        return new ComboBoxCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Creates a link component with properties set to the defaults passed in
     * the createContext.
     *
     * @AbcsExtension unstable
     * @param {Object} createContext create context with default link properties
     * to set when the component is created.
     * @param {String} createContext.label text of the link label
     * @param {components.dt/js/api/constants/Link.LabelPosition} createContext.labelPosition positioning of the link label.
     * @param {String} createContext.displayText textual representation of the link target displayed in the page
     * @param {Object} createContext.target a target to open when the link is clicked. May be a page or a URL.
     * @param {components.dt/js/api/constants/Link.TargetType} createContext.target.type type of the target, may be a URL or an ABCS page
     * @param {pages.dt/js/api/Page} createContext.target.page an existing ABCS page opened when the link is clicked.
     * It is required when <code>target.type</code> is set to {@link components.dt/js/api/constants/Link.TargetType Link.TargetType.PAGE}
     * @param {String} createContext.target.url a URl to open when the link is clicked.
     * It is required when <code>target.type</code> is set to {@link components.dt/js/api/constants/Link.TargetType Link.TargetType.URL}
     *
     * @returns {pages.dt/js/api/View} created combo box view
     * @example <caption>Create a link component bound to a static URL</caption>
     * var componentFactory = ComponentFactory.create(activePage);
     * var linkComponent = componentFactory.createLink({
     *     label: 'LABEL',
     *     labelPosition: Link.LabelPosition.LEFT,
     *     displayText: 'My Custom Link',
     *     target: {
     *         type: Link.TargetType.URL,
     *         url: 'http://www.oracle.com'
     *     }
     * });
     * @example <caption>Create a link component bound to an existing ABCS page</caption>
     * var componentFactory = ComponentFactory.create(activePage);
     * var linkComponent = componentFactory.createLink({
     *     label: 'LABEL',
     *     labelPosition: Link.LabelPosition.LEFT,
     *     displayText: 'My Custom Link',
     *     target: {
     *         type: Link.TargetType.PAGE,
     *         page: existingABCSPageInstance
     *     }
     * });
     */
    ComponentFactory.prototype.createLink = function (createContext) {
        AbcsLib.checkParameterCount(1);
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['label', 'labelPosition', 'displayText', 'target']);
        AbcsLib.checkDefined(createContext.label, 'createContext.label');
        AbcsLib.checkDataType(createContext.label, AbcsLib.Type.STRING);
        AbcsLib.checkDefined(createContext.labelPosition, 'createContext.labelPosition');
        AbcsLib.checkDefined(createContext.displayText, 'createContext.displayText');
        AbcsLib.checkDataType(createContext.displayText, AbcsLib.Type.STRING);
        AbcsLib.checkDefined(createContext.target, 'createContext.target');
        AbcsLib.checkObjectLiteral(createContext.target, ['type', 'url', 'page']);
        AbcsLib.checkDefined(createContext.target.type, 'createContext.target.type');
        switch (createContext.target.type) {
            case Link.TargetType.PAGE:
                AbcsLib.checkDefined(createContext.target.page, 'createContext.target.page');
                break;
            case Link.TargetType.URL:
                AbcsLib.checkDefined(createContext.target.url, 'createContext.target.url');
                AbcsLib.checkDataType(createContext.target.url, AbcsLib.Type.STRING);
                break;
            default:
                throw new Error(ComponentFactory._ERROR_LINK_UNKNOWN_TARGET_TYPE(createContext.target.type));
        }
        return new LinkCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Create an Image component.
     *
     * @AbcsExtension unstable
     *
     * @param {object} createContext - Create context with default Image component
     * properties to set when the view is created.
     * @param {Object} createContext.image specification of the image the component
     * will dispay.
     * @param {String} createContext.imagePath Path to the image, specifying this
     * parameter will make the image component static.
     * @param {String} [createContext.altText] Alternative textual representation
     * when the image cannot be loaded.
     *
     * @returns {pages.dt/js/api/View} Created Image component's view.
     * @example <caption>Create a built-in static image component</caption>
     * // create a built-in image component
     * var image = componentFactory.createImage({
     *     imagePath: 'package/path_to_resource.png',
     *     altText: 'ALTERNATE TEXT'
     * });
     */
    ComponentFactory.prototype.createImage = function (createContext) {
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['altText', 'imagePath']);
        AbcsLib.checkDefined(createContext.imagePath, 'imagePath');
        return new ImageCreator().createView(this._page, undefined, createContext);
    };

    ComponentFactory.prototype.createGrid = function (context) {
        var Properties = require('pages.dt/js/api/Properties');
        var properties;
        properties = new Properties();
        properties.setValue('designerIsDroppable', context.designerIsDroppable === false ? false : true);
        //will not by default generate wrapping ABCS element, one of the consequence - the component can't be selected
        properties.setValue('designerIsWrappable', context.designerIsDroppable === true ? true : false);
        return this._page.getViewFactory().createView({
            id: this._page.createViewId(ViewType.GRID),
            type: ViewType.GRID,
            properties: properties
        });
    };

    ComponentFactory.prototype.createEntityDetail = function (context) {
        // TODO deleter for ENTITY_DETAIL
        var archetype = this._createArchetype(context[EntityDetail.ENTITY], !!context[EntityDetail.REUSE_ARCHETYPE]);
        var form = this.createGrid(context);
        form.setType(ViewType.ENTITY_DETAIL);
        form.setArchetype(archetype);
        return form;
    };

    ComponentFactory.prototype.createOneToOneEntityDetail = function (context) {

        var parentArchetype;
        var parentEntity = context.parentEntity;
        if (!parentEntity) {
            throw new Error('parentEntity was not set');
        }
        var page = this._page;
        var viewModelDefinition = page.getViewModelDefinition();
        viewModelDefinition.findArchetypesByType(ArchetypeType.ENTITY_DETAIL).forEach(function(candidateArchetype) {
            if (candidateArchetype.getEntityId() === parentEntity.getId()) {
                //found
                parentArchetype = candidateArchetype;
            }
        });
        if (!parentArchetype) {
            throw new Error('in order to add ' + context[EntityDetail.ENTITY].getId() +
                    ' to this page the page must already contain detail archetype for ' +
                    parentEntity.getId());
        }

        // TODO deleter for ENTITY_DETAIL
        var archetype = this._createArchetype(context[EntityDetail.ENTITY], !!context[EntityDetail.REUSE_ARCHETYPE]);
        var form = this.createGrid(context);
        form.setType(ViewType.ENTITY_DETAIL);
        form.setArchetype(archetype);

        archetype.setMasterArchetype(parentArchetype.getInstancePath());
        viewModelDefinition.refreshArchetype(archetype);

        return form;
    };

    ComponentFactory.prototype.findListArchetypeFor = function (entity) {
        ComponentFactory.findListArchetypeFor(entity, this._page);
    };

    ComponentFactory.prototype.findListArchetypeFor = function (entity, page) {

        var listArchetype;
        var viewModelDefinition = page.getViewModelDefinition();
        viewModelDefinition.findArchetypesByType(ArchetypeType.LIST).forEach(function(candidateArchetype) {
            if (candidateArchetype.getEntityId() === entity.getId()) {
                //found
                listArchetype = candidateArchetype;
            }
        });
        if (listArchetype === undefined) {
            throw new Error('in order to add Question query the page must alrady contain list archetype for answers');
        }

        return listArchetype;
    };

    ComponentFactory.prototype.findPageForListArchetype = function (entity) {

        var listArchetypePage;
        Pages.getPages().forEach(function (page) {

            var viewModelDefinition = page.getViewModelDefinition();
            viewModelDefinition.findArchetypesByType(ArchetypeType.LIST).forEach(function (candidateArchetype) {
                if (candidateArchetype.getEntityId() === entity.getId()) {
                    //found
                    listArchetypePage = page;
                }
            });

        });

        if (listArchetypePage === undefined) {
            throw new Error('in order to add Question query one page must already contain list archetype for answers');
        }

        return listArchetypePage;
    };

    /**
     * Appends the component at the end of requested page.
     * @param {pages.dt/js/api/Page} page page to modify
     * @param {pages.dt/js/api/View} component component's top view to add to the page
     * @param {Object} layoutConstraints layout constraints
     * @param {Number} layoutConstraints.column zero-based column index (max 11)
     * defining where to put the component in the pages's layout.
     * @param {Number} layoutConstraints.width number of columns the component view
     * is about to occupy.
     */
    ComponentFactory.appendToPage = function (page, component, layoutConstraints) {
        AbcsLib.checkParameterCount(3);
        AbcsLib.checkDefined(page, 'page');
        AbcsLib.checkDefined(component, 'component');
        AbcsLib.checkDefined(layoutConstraints, 'layoutConstraints');
        var view = page.getView();
        var rowIndex = GridOperations.getLayout(view).length;
        ComponentFactory.addChildView(view, component, {
            row: rowIndex,
            column: layoutConstraints.column || 0,
            width: layoutConstraints.width,
            createRow: true
        });
    };

    ComponentFactory.prototype.createQuery = function (context) {
        // TODO deleter for QUERY_FORM
        var archetype = this._createArchetype(context[EntityDetail.ENTITY],
            !!context[EntityDetail.REUSE_ARCHETYPE],
            ArchetypeType.QUERY_DATA, {
                queryName: 'something',
                queryDescriptionId: context.query
            });
        var form = this.createGrid(context);
        form.setType(ViewType.QUERY_FORM);
        form.setArchetype(archetype);

        return form;
    };

    /**
     * Creates table component with predefined properties and bahaviour.
     *
     * @AbcsExtension unstable
     *
     * @param {Object} createContext properties defining the created table's
     * bahaviour.
     * @param {entity/js/api/Entity} createContext.entity entity the table will
     * be bound to.
     * @param {entity/js/api/Property[]} createContext.selectedProperties properties
     * to show in the table. Pass at least one property as table with no columns
     * cannot be created.
     * @param {String} [createContext.caption] optional text used as the table's
     * caption. While it is optional you should still set it to a non-empty text
     * as filled table caption is one of the rules of accessibility.
     * For now it's optional but will be required once official public API.
     * @param {operation/js/api/Condition} [createContext.customCondition] optional
     * condition that will be automatically used as the table's default query.
     *
     * @param {Object} [createContext.createAction] options defining how and if the create action
     * is to be set up. When not set the create action will be set up as if
     * {@link components.dt/js/api/constants/Table.ActionMode Table.ActionMode.DEFAULT}
     * is set as <code>createAction.mode</code>.
     * @param {components.dt/js/api/constants/Table.ActionMode} createContext.createAction.mode defines
     * the way the create action is created.
     * @param {pages.dt/js/api/Page} [createContext.createAction.page] required when <code>createAction.mode</code>
     * is set to {@link components.dt/js/api/constants/Table.ActionMode Table.ActionMode.OPEN_PAGE}
     * and represents the page to open when the action is invoked.
     * @param {components.dt/js/api/ComponentFactory~createCollectionAction} [createContext.createAction.createAction]
     * Required when <code>createAction.mode</code> is set to {@link components.dt/js/api/constants/Table.ActionMode Table.ActionMode.CUSTOM}
     * and will be called when table creator is about to set up the action.
     *
     * @param {Object} [createContext.detailAction] options defining how and if the open detail action
     * is to be set up. When not set the detail action will be set up as if
     * {@link components.dt/js/api/constants/Table.ActionMode Table.ActionMode.DEFAULT}
     * is set as <code>detailAction.mode</code>.
     * @param {components.dt/js/api/constants/Table.ActionMode} createContext.detailAction.mode defines
     * the way the open detail action is created.
     * @param {pages.dt/js/api/Page} [createContext.detailAction.page] required when <code>detailAction.mode</code>
     * is set to {@link components.dt/js/api/constants/Table.ActionMode Table.ActionMode.OPEN_PAGE}
     * and represents the page to open when the action is invoked.
     * @param {components.dt/js/api/ComponentFactory~createCollectionAction} [createContext.detailAction.createAction]
     * Required when <code>detailAction.mode</code> is set to {@link components.dt/js/api/constants/Table.ActionMode Table.ActionMode.CUSTOM}
     * and will be called when table creator is about to set up the action.
     * @param {entity/js/api/Property} [createContext.detailAction.link] set up a column displaying
     * this property as a link activating the action (opening the detail page).
     *
     * @param {Object} [createContext.deleteAction] options defining how and if the create action
     * is to be set up. When not set the delete action will be set up as if
     * {@link components.dt/js/api/constants/Table.ActionMode Table.ActionMode.DEFAULT}
     * is set as <code>deleteAction.mode</code>.
     * @param {components.dt/js/api/constants/Table.ActionMode} createContext.deleteAction.mode defines
     * the way the delete action is created.
     * <strong>Note that</strong> only {@link components.dt/js/api/constants/Table.ActionMode DEFAULT}
     * and {@link components.dt/js/api/constants/Table.ActionMode NONE} are allowed
     * for delete action.
     *
     * @param {Object} [createContext.editAction] options defining how and if the edit action
     * is to be set up. When not set the edit action will be set up as if
     * {@link components.dt/js/api/constants/Table.ActionMode Table.ActionMode.DEFAULT}
     * is set as <code>editAction.mode</code>.
     * @param {components.dt/js/api/constants/Table.ActionMode} createContext.editAction.mode defines
     * the way the edit action is created.
     * @param {pages.dt/js/api/Page} [createContext.editAction.page] required when <code>editAction.mode</code>
     * is set to {@link components.dt/js/api/constants/Table.ActionMode Table.ActionMode.OPEN_PAGE}
     * and represents the page to open when the action is invoked.
     * @param {components.dt/js/api/ComponentFactory~createCollectionAction} [createContext.editAction.createAction]
     * Required when <code>editAction.mode</code> is set to {@link components.dt/js/api/constants/Table.ActionMode Table.ActionMode.CUSTOM}
     * and will be called when table creator is about to set up the action.
     * @param {entity/js/api/Property} [createContext.editAction.link] set up a column displaying
     * this property as a link activating the action (opening the edit page).
     * @returns {pages.dt/js/api/View} created table view
     * @example <caption>Create simple table</caption>
     * var entity = Abcs.Entities().findById('my.custom.bop.Employee');
     * var nameProperty = entity.getProperty('firstname');
     * var lastnameProperty = entity.getProperty('lastname');
     * // create table for employee BO
     * // with most of the settings set to defaults
     * var table = factory.createTable({
     *     entity: Abcs.Entities().findById('my.custom.bop.Employee'),
     *     selectedProperties: [nameProperty, lastnameProperty],
     *     caption: 'Employee Table'
     * });
     *
     * @example <caption>Create table with customized actions</caption>
     * var entity = Abcs.Entities().findById('my.custom.bop.Employee');
     * var nameProperty = entity.getProperty('firstname');
     * var lastnameProperty = entity.getProperty('lastname');
     * // create table for employee BO
     * var table = factory.createTable({
     *     entity: Abcs.Entities().findById('my.custom.bop.Employee'),
     *     selectedProperties: [nameProperty, lastnameProperty],
     *     caption: 'Employee Table',
     *     // neither create action or create page will not be generated
     *     createAction: {
     *         mode: Table.ActionMode.NONE
     *     },
     *     // edit action will open not default but a customized
     *     // 'myCustomEditPage' page
     *     editAction: {
     *         mode: Table.ActionMode.OPEN_PAGE,
     *         page: Pages.getPage('myCustomEditPage')
     *     },
     *     // detail action will open default detail page and the lastnameProperty
     *     // column will render as a link invoking the action on click
     *     detailAction: {
     *         mode: Table.ActionMode.DEFAULT,
     *         link: lastnameProperty
     *     }
     * });
     */
    // TODO createContext.caption should not be optional i guess
    ComponentFactory.prototype.createTable = function (createContext) {
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['entity', 'selectedProperties', 'linkDetail', 'linkEdit',
            'sortingEnabled', 'sortingProperty', 'sortingOrder',
            'filterEnabled', 'filterProperty', 'advancedSearchEnabled',
            'createAction', 'detailAction', 'editAction', 'deleteAction',
            'caption', 'customCondition'
        ]);
        AbcsLib.checkDefined(createContext.entity, 'createContext.entity');
        AbcsLib.checkDefined(createContext.selectedProperties, 'createContext.selectedProperties');
        if (!createContext.selectedProperties.length) {
            throw new Error(ComponentFactory._ERROR_EMPTY_PROPERTIES('createContext.selectedProperties'));
        }
        if (createContext.caption) {
            AbcsLib.checkDataType(createContext.caption, AbcsLib.Type.STRING);
        }
        ComponentFactory._upgradeCollectionContextInput(createContext);
        ComponentFactory._checkCollectionActionsInput(createContext);

        return new TableCreator().createView(this._page, undefined, createContext);
    };

    /**
     * Creates list component with predefined properties and bahaviour.
     *
     * @AbcsExtension unstable
     *
     * @param {Object} createContext properties defining the created list's
     * bahaviour.
     * @param {entity/js/api/Entity} createContext.entity entity the list will
     * be bound to.
     * @param {String} createContext.layout layout to select for the list component,
     * should be one of {@link components.dt/js/api/constants/List.LayoutMode List.LayoutMode}.
     * @param {operation/js/api/Condition} [createContext.customCondition] optional
     * condition that will be automatically used as the list's default query.
     *
     * @param {Object} [createContext.createAction] options defining how and if the create action
     * is to be set up. When not set the create action will be set up as if
     * {@link components.dt/js/api/constants/List.ActionMode List.ActionMode.DEFAULT}
     * is set as <code>createAction.mode</code>.
     * @param {components.dt/js/api/constants/List.ActionMode} createContext.createAction.mode defines
     * the way the create action is created.
     * @param {pages.dt/js/api/Page} [createContext.createAction.page] required when <code>createAction.mode</code>
     * is set to {@link components.dt/js/api/constants/List.ActionMode List.ActionMode.OPEN_PAGE}
     * and represents the page to open when the action is invoked.
     * @param {components.dt/js/api/ComponentFactory~createCollectionAction} [createContext.createAction.createAction]
     * Required when <code>createAction.mode</code> is set to {@link components.dt/js/api/constants/List.ActionMode List.ActionMode.CUSTOM}
     * and will be called when list creator is about to set up the action.
     *
     * @param {Object} [createContext.detailAction] options defining how and if the open detail action
     * is to be set up. When not set the detail action will be set up as if
     * {@link components.dt/js/api/constants/List.ActionMode List.ActionMode.DEFAULT}
     * is set as <code>detailAction.mode</code>.
     * @param {components.dt/js/api/constants/List.ActionMode} createContext.detailAction.mode defines
     * the way the open detail action is created.
     * @param {pages.dt/js/api/Page} [createContext.detailAction.page] required when <code>detailAction.mode</code>
     * is set to {@link components.dt/js/api/constants/List.ActionMode List.ActionMode.OPEN_PAGE}
     * and represents the page to open when the action is invoked.
     * @param {components.dt/js/api/ComponentFactory~createCollectionAction} [createContext.detailAction.createAction]
     * Required when <code>detailAction.mode</code> is set to {@link components.dt/js/api/constants/List.ActionMode List.ActionMode.CUSTOM}
     * and will be called when list creator is about to set up the action.
     * @param {entity/js/api/Property} [createContext.detailAction.link] set up a column displaying
     * this property as a link activating the action (opening the detail page).
     *
     * @param {Object} [createContext.deleteAction] options defining how and if the create action
     * is to be set up. When not set the delete action will be set up as if
     * {@link components.dt/js/api/constants/List.ActionMode List.ActionMode.DEFAULT}
     * is set as <code>deleteAction.mode</code>.
     * @param {components.dt/js/api/constants/List.ActionMode} createContext.deleteAction.mode defines
     * the way the delete action is created.
     * <strong>Note that</strong> only {@link components.dt/js/api/constants/List.ActionMode DEFAULT}
     * and {@link components.dt/js/api/constants/List.ActionMode NONE} are allowed
     * for delete action.
     *
     * @param {Object} [createContext.editAction] options defining how and if the edit action
     * is to be set up. When not set the edit action will be set up as if
     * {@link components.dt/js/api/constants/List.ActionMode List.ActionMode.DEFAULT}
     * is set as <code>editAction.mode</code>.
     * @param {components.dt/js/api/constants/List.ActionMode} createContext.editAction.mode defines
     * the way the edit action is created.
     * @param {pages.dt/js/api/Page} [createContext.editAction.page] required when <code>editAction.mode</code>
     * is set to {@link components.dt/js/api/constants/List.ActionMode List.ActionMode.OPEN_PAGE}
     * and represents the page to open when the action is invoked.
     * @param {components.dt/js/api/ComponentFactory~createCollectionAction} [createContext.editAction.createAction]
     * Required when <code>editAction.mode</code> is set to {@link components.dt/js/api/constants/List.ActionMode List.ActionMode.CUSTOM}
     * and will be called when list creator is about to set up the action.
     * @param {entity/js/api/Property} [createContext.editAction.link] set up a column displaying
     * this property as a link activating the action (opening the edit page).
     * @returns {pages.dt/js/api/View} created list view
     * @example <caption>Create simple list</caption>
     * var entity = Abcs.Entities().findById('my.custom.bop.Employee');
     * var nameProperty = entity.getProperty('firstname');
     * var lastnameProperty = entity.getProperty('lastname');
     * // create list for employee BO with most of the settings set to defaults
     * var list = factory.createList({
     *     entity: Abcs.Entities().findById('my.custom.bop.Employee'),
     *     layout: List.Layout.ONE_COLUMN
     * });
     *
     * @example <caption>Create list with customized actions</caption>
     * var entity = Abcs.Entities().findById('my.custom.bop.Employee');
     * var nameProperty = entity.getProperty('firstname');
     * var lastnameProperty = entity.getProperty('lastname');
     * // create list for employee BO with most of the settings set to defaults
     * var list = factory.createList({
     *     entity: Abcs.Entities().findById('my.custom.bop.Employee'),
     *     layout: List.LayoutMode.ONE_COLUMN,
     *     // neither create action or create page will not be generated
     *     createAction: {
     *         mode: List.ActionMode.NONE
     *     },
     *     // edit action will open not default but a customized
     *     // 'myCustomEditPage' page
     *     editAction: {
     *         mode: List.ActionMode.OPEN_PAGE,
     *         page: Pages.getPage('myCustomEditPage')
     *     }
     * });
     */
    ComponentFactory.prototype.createList = function (createContext) {
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['entity', 'layout', 'linkDetail', 'linkEdit',
            'sortingEnabled', 'sortingProperty', 'sortingOrder',
            'filterEnabled', 'filterProperty', 'advancedSearchEnabled',
            'createActionDetail', 'selectedProperties',
            'createAction', 'detailAction', 'editAction', 'deleteAction',
            'customCondition'
        ]);
        AbcsLib.checkDefined(createContext.entity, 'createContext.entity');
        AbcsLib.checkDefined(createContext.layout, 'createContext.layout');
        ComponentFactory._upgradeCollectionContextInput(createContext);
        ComponentFactory._checkCollectionActionsInput(createContext);
        var listView = new ListCreator().createView(this._page, undefined, createContext);

        // temporary as a BW compatibility, will be removed once
        if (createContext.detailAction && createContext.detailAction.link) {
            listView._creator_api_link_detail = createContext.detailAction.link.getId();
        } else if (createContext.editAction && createContext.editAction.link) {
            listView._creator_api_link_edit = createContext.editAction.link.getId();
        }
        return listView;
    };

    /**
     * Creates a list property component with properties set to the defaults passed in
     * the createContext.
     *
     * @AbcsExtension unstable
     * @param {pages.dt/js/api/View} listView instance of list view component as it was
     * returned from {@link components.dt/js/api/ComponentFactory#createList ComponentFactory.createList}.
     * @param {Object} createContext create context with default component
     * properties to set when the component is created.
     * @param {entity/js/api/Property} createContext.property instance of a BO
     * field the view will be bound to.
     * @param {String} [createContext.label] input component's label text
     * @param {String} [createContext.labelPosition] input component's label position.
     * Choose one of {@link components.dt/js/api/constants/Input.LabelPosition Input.LabelPosition}
     * @param {String} [createContext.rendererComponent] special renderer that will
     * be used when the component is building its DOM. By default the component
     * renders a single-line text DOM element, but lets you specify a specific
     * renderer such as multi-line text. The value should be one of renderers
     * defined in {@link components.dt/js/api/constants/Property Property} and
     * is specific to the property's type (will throw an error for unsupported
     * renderer).
     *
     * Be careful when choosing the renderer and use proper enums based on the
     * property's type:
     *
     * <ul>
     * <li>{@link components.dt/js/api/constants/Property.TextRenderingComponentType Property.TextRenderingComponentType}
     * for properties of type {@link entity/js/api/PropertyType.TEXT PropertyType.TEXT}</li>
     * </ul>
     *
     * @returns {pages.dt/js/api/View} created list property view
     *
     * @example Create multi-line list property bound to incident's description field
     * var incidentBO = Abcs.Entities().findById('my.custom.bop.Incident');
     * var descriptionProperty = incidentBO.getproperty('description');
     *
     * // create new list view
     * var listView = componentFactory.createList({
     *     entity: Abcs.Entities().findById('my.custom.bop.Employee'),
     *     layout: List.Layout.ONE_COLUMN
     * });
     *
     * // create list property bound to description
     * var descriptionView = componentFactory.createListProperty(listView, {
     *     boundProperty: descriptionProperty,
     *     rendererComponent: Property.TextRenderingComponentType.MULTI_LINE_TEXT
     * });
     *
     * // add the view to the list into the first row
     * componentFactory.addChildToList(list, descriptionView, {
     *     listColumn: 0,
     *     row: 0,
     *     column: 0,
     *     width: 6,
     *     createRow: true
     * });
     */
    ComponentFactory.prototype.createListProperty = function (listView, createContext) {
        AbcsLib.checkParameterCount(arguments, 2);
        AbcsLib.checkDefined(listView, 'listView');
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkObjectLiteral(createContext, ['boundProperty', 'property', 'label', 'labelPosition', 'rendererComponent']);
        if (createContext.property) {
            // BW compatibility
            createContext.boundProperty = createContext.property;
        }
        AbcsLib.checkDefined(createContext.boundProperty, 'createContext.' + createContext.boundProperty);
        if (listView.getType() !== ViewType.TOP_LIST_CONTAINER) {
            throw new Error(ComponentFactory.ERROR_EXPECTED_LIST);
        }
        if (createContext.rendererComponent) {
            Property.checkRenderer(createContext.boundProperty.getType(), createContext.rendererComponent);
        }
        createContext.property = createContext.boundProperty;
        createContext.entity = listView.getEnclosingArchetype().getEntity();

        if (listView._creator_api_link_detail === createContext.boundProperty.getId()) {
            createContext.detailActionLink = true;
        } else if (listView._creator_api_link_edit === createContext.boundProperty.getId()) {
            createContext.editActionLink = true;
        }

        return new PropertyCreator().createView(this._page, listView, createContext);
    };

    ComponentFactory.prototype.createCustom = function (type, createContext) {
        AbcsLib.checkDefined(type, 'type');
        createContext = createContext || {};
        var creator = componentProviderRegistry.findCreator(type);
        if (!creator) {
            throw new Error(ComponentFactory.ERROR_CREATOR_NOT_FOUND(type));
        }

        var view = creator.createView(this._page, undefined, createContext);
        view.getProperties().setValue(View.MIN_WIDTH_KEY, creator.getOptions().minWidth);
        return view;
    };

    ComponentFactory.prototype.addChildToList = function (listView, childView, layoutConstraints) {
        AbcsLib.checkDefined(listView, 'listView');
        AbcsLib.checkDefined(childView, 'childView');
        AbcsLib.checkDefined(layoutConstraints, 'layoutConstraints');
        AbcsLib.checkDefined(layoutConstraints.listColumn, 'layoutConstraints.listColumn');

        var listRow = listView.findChildOfType(ViewType.LIST_ROW);
        var listColumns = listRow.getChildren();
        var container = listColumns[layoutConstraints.listColumn];

        var viewComposer = new ViewComposer(childView);
        viewComposer.composeViews(container, layoutConstraints);
    };

    /**
     * Creates a generic view of given type with defined properties.
     * <p>In custom Creators you should use this method to create your views
     * instead of trying to construct View instances directly though their
     * constructors.</p>
     *
     * @AbcsExtension stable
     * @param {Object} createContext
     * @param {String} createContext.displayName view display name, for example
     * 'Text Field', 'Opportunity Table' etc.
     * @param {String} createContext.type view type you want to create
     * @param {Object} [createContext.properties] a map of view properties.
     * <p>You do not have to construct view {@link pages.dt/js/api/Properties Properties}
     * yourself, instead pass a simple key-value map of your view properties and
     * the instance will be created and injected into the created view by this
     * method automatically (and obtained later with {@link pages.dt/js/api/View#getProperties View.getProperties}).</p>
     * @returns {pages.dt/js/api/View} created view
     * @version 16.3.5
     * @example <caption>How to create a view in my Creator</caption>
     * Creator.prototype.createView = function (activePage) {
     *     var componentFactory = ComponentFactory.create(activePage);
     *     var properties = {
     *         myProp: 'prop value'
     *     };
     *
     *     // create the view for this component
     *     var view = componentFactory.createView({
     *         displayName: 'My Custom Component',
     *         type: 'my.componentId',
     *         properties: properties
     *     });
     *
     *     view.getProperties().setValue('myProp', 'modified prop value');
     *
     *     return view;
     * };
     */
    ComponentFactory.prototype.createView = function (createContext) {
        AbcsLib.checkDefined(createContext, 'createContext');
        AbcsLib.checkDefined(createContext.displayName, 'createContext.displayName');
        AbcsLib.checkDefined(createContext.type, 'createContext.type');
        AbcsLib.checkObjectLiteral(createContext, ['displayName', 'type', 'properties']);
        var properties = createContext.properties;
        if (properties && (typeof properties.getKeys !== 'function' || typeof properties.getValue !== 'function')) {
            properties = new Properties(properties);
        }
        var view = this._page.getViewFactory().createView({
            id: this._page.createViewId(createContext.type),
            displayName: createContext.displayName,
            properties: properties,
            type: createContext.type
        });
        return view;
    };

    /**
     * Organizes two views into a hierarchy, i.e. adds <code>childView</code>
     * as a child of <code>parentView</code>. In case the parent view is a container
     * such as a panel or a grid, you should pass also the <code>layoutConstraints</code>
     * to properly set the parent view's layout.
     *
     * @param {pages.dt/js/api/View} parentView parent view
     * @param {pages.dt/js/api/View} childView child view to add into the parent.
     * @param {Object} [layoutConstraints] layout constraints
     * @param {Number} layoutConstraints.row zero-based row index defining where to
     * put the child in the parent's layout
     * @param {Number} layoutConstraints.column zero-based column index (max 11)
     * defining where to put the child in the parent's layout.
     * @param {Number} layoutConstraints.width number of columns the child view
     * is about to occupy.
     * @param {Boolean} [layoutConstraints.createRow] if set to <code>true</code>
     * the child view will be added to a completely new row added at the row index.
     * @example <caption>How to add child to a parent</caption>
     * var parentView;
     * var buttonView;
     * // adds the button view as a child of the parent view without any layout
     * ComponentFactory.addChildView(parentView, buttonView);
     * @example <caption>How to add child to a container with layout</caption>
     * var gridView;
     * var buttonView;
     *
     * // will add the button to the third column of the third row in the panel
     * // layout. The button will be stretched over two panel columns.
     * ComponentFactory.addChildView(panelView, buttonView, {
     *     row: 2,
     *     column: 2,
     *     width: 2
     * });
     *
     * // will create a new row above the previous third row inside the panel
     * // and add the button to the third column of the created row. The button
     * will be stretched over four panel columns.
     * ComponentFactory.addChildView(panelView, buttonView, {
     *     row: 2,
     *     column: 2,
     *     width: 4,
     *     createRow: true
     * });
     */
    ComponentFactory.addChildView = function (parentView, childView, layoutConstraints) {
        if (layoutConstraints) {
            GridOperations.addView(parentView, childView, layoutConstraints);
        } else {
            parentView.addChild(childView);
        }
    };

    ComponentFactory.prototype._createArchetype = function (entity, reuseExisting, archType, descriptorOptions) {
        if (!archType) {
            archType = ArchetypeType.ENTITY_DETAIL;
        }
        var page = this._page;
        var viewModelDefinition = page.getViewModelDefinition();
        var archetype;
        if (reuseExisting) {
            viewModelDefinition.findArchetypesByType(archType).forEach(function(candidateArchetype) {
                if (candidateArchetype.getEntityId() === entity.getId()) {
                    //found
                    archetype = candidateArchetype;
                }
            });
        }
        if (!archetype) {
            //create
            var archetypeId = ArchetypeUtils.generateArchetypeId(entity, archType, viewModelDefinition);
            var descriptor = {
                id: archetypeId,
                type: archType
            };
            if (descriptorOptions) {
                descriptor = $.extend(descriptor, descriptorOptions);
            }
            archetype = ArchetypeFactory.create(entity, descriptor);
            viewModelDefinition.addArchetype(archetype);
        }
        return archetype;
    };

    ComponentFactory._upgradeCollectionContextInput = function (createContext) {
        if (createContext.createActionDetail) {
            createContext.detailAction = createContext.detailAction || {
                mode: Collection.ActionMode.CUSTOM,
                createAction: createContext.createActionDetail
            };
        }
        if (createContext.linkDetail) {
            createContext.detailAction = createContext.detailAction || {
                mode: Collection.ActionMode.DEFAULT
            };
            createContext.detailAction.link = createContext.linkDetail;
        }
        if (createContext.linkEdit) {
            createContext.editAction = createContext.editAction || {
                mode: Collection.ActionMode.DEFAULT
            };
            createContext.editAction.link = createContext.linkEdit;
        }
    };

    ComponentFactory._checkCollectionActionInput = function (actionContext, prefix) {
        AbcsLib.checkDefined(actionContext.mode, prefix + '.mode');
        if (actionContext.mode === Collection.ActionMode.OPEN_PAGE) {
            AbcsLib.checkDefined(actionContext.mode, prefix + '.page');
        } else if (actionContext.mode === Collection.ActionMode.CUSTOM) {
            AbcsLib.checkDefined(actionContext.createAction, prefix + '.createAction');
            AbcsLib.checkDataType(actionContext.createAction, AbcsLib.Type.FUNCTION);
        }
    };

    ComponentFactory._checkCollectionActionsInput = function (createContext) {
        if (createContext.createAction) {
            ComponentFactory._checkCollectionActionInput(createContext.createAction, 'createContext.createAction');
        }
        if (createContext.detailAction) {
            ComponentFactory._checkCollectionActionInput(createContext.detailAction, 'createContext.detailAction');
        }
        if (createContext.editAction) {
            ComponentFactory._checkCollectionActionInput(createContext.editAction, 'createContext.editAction');
        }
    };

    /**
     * Creates a business action invoked from a collection when user clicks on
     * a link or selects the action from the popup menu.
     * @AbcsExtension unstable
     * @callback components.dt/js/api/ComponentFactory~createCollectionAction
     * @param {viewmodel/js/api/Archetype} archetype instance of table archetype
     * @return {BusinessCode} business code action
     */

    var ContextBuilder = function () {
        AbcsLib.checkThis(this);
        this._context = {};
    };

    ContextBuilder.prototype.setProperty = function (propertyName, value) {
        this._context[propertyName] = value;
        return this;
    };

    ContextBuilder.prototype.build = function () {
        return this._context;
    };

    ComponentFactory.ContextBuilder = ContextBuilder;

    return ComponentFactory;

});