    api.require({
      namespace: ["sol"]
    }, function () {

      /**
    	 * This is a utility class for user interaction.
    	 */
      sol.define("sol.common.web.ApiUtils", {
        singleton: true,
        /**
         * Finds a users workflow node based on its flowId and nodeId.
         * Since collecting tasks is expensive, the guid should be passed in order to limit search results.
         * A maximum of 100 tasks is retrieved in order to find the required node.
         *
         * @param {String} guid
         * @param {String} flowId
         * @param {String} nodeId
         * @param {Object} successFct
         * @param {Object} failureFct
         */
        getWfNode: function (guid, flowId, nodeId, successFct, failureFct) {
          var findTaskInfo = new de.elo.ix.client.FindTasksInfo();
          findTaskInfo.allUsers = false;
          findTaskInfo.inclWorkflows = true;
          findTaskInfo.objId = guid;
          findTaskInfo.highestPriority = elo.CONST.USER_TASK_PRIORITY.HIGHEST;
          findTaskInfo.lowestPriority = elo.CONST.USER_TASK_PRIORITY.LOWEST;
          findTaskInfo.sortOrder = elo.CONST.USER_TASK_SORT_ORDER.PRIORITY_DATE_NAME_INV;

          elo.IX.ix().findFirstTasks(findTaskInfo, 100, new de.elo.ix.client.AsyncCallback(function (findResult) {
            // success
            var tasks = findResult.tasks,
                task, i;
            for (i = 0; i < tasks.length; i++) {
              task = tasks[i];
              if (task.wfNode.flowId === flowId && task.wfNode.nodeId === nodeId) {
                successFct.call(this, task.wfNode);
                return;
              }
            }
            if (failureFct) {
              failureFct.call(this, "Workflow node not found.");
            }
          }, function (ex) {
            if (failureFct) {
              failureFct.call(this, ex);
            }
          }));
        },

        /**
         * Displays an info box.
         * @param {String} msg
         */
        showInfoMessage: function (msg) {
          elo.ModelRegistry.setDataInstance({
            scope: this,
            id: elo.ModelRegistry.getModelConstant("logMessage"),
            obj: {
              displayType: "window",
              type: "info",
              title: "",
              bodyTitle: msg
            }
          });
        },

        /**
         * Displays a toast/ message popup.
         * @param {String} msg
         */
        showPopupMessage: function (msg) {
          var me = this;

          elo.ModelRegistry.setDataInstance({
            scope: me,
            id: elo.ModelRegistry.getModelConstant("logMessage"),
            obj: {
              displayType: "popup",
              bodyTitle: msg
            }
          });
        }
      });
    });

    //# sourceURL=sol.common.web.ApiExtensions.js

    api.require({
      namespace: ["sol"]
    }, function () {

      var chars = [],
          pressed = false,
          timeout,
          minBarcodeLength;

      /**
       * @private
       *
       * This is an experimental class that might change in the future.
       * Don't rely on its existance.
       */
      sol.define("sol.common.web.BarcodeHandler", {
        singleton: true,

        initialize: function (config) {
          var me = this;
          me.$super("sol.Base", "initialize", arguments);

          window.addEventListener("keypress", me.handleKeyEvent);
          timeout = me.timeout;
          minBarcodeLength = me.minBarcodeLength;
        },

        /**
         * @cfg {Number} minimum amount of characters that identifies a barcode.
         */
        minBarcodeLength: 10,
        /**
         * @cfg {Number} timout in ms for the barcode sequence.
         */
        timeout: 500,

        handleKeyEvent: function (e) {
          chars.push(String.fromCharCode(e.which));
          if (pressed == false) {
            setTimeout(function () {
              if (chars.length >= minBarcodeLength) {
                var barcode = chars.join("");
                sol.common.web.BarcodeHandler.handleBarcode(barcode);
              }
              chars = [];
              pressed = false;
            }, timeout);
          }
          pressed = true;
        },
        handleBarcode: function (barcode) {
          var me = this,
              regex, guid, objId;
          me.logger.info("Barcode scanned: " + barcode);
          // if barcode was regognized in child component,
          // redirect to parent handler.
          if (api &&
              api.communication &&
              api.communication.Parent &&
              api.communication.Parent.hasParent()) {
            me.logger.info("Barcode scanned within child component. Redirect to parent.");

            // not implemented yet.

            return;
          }

          if (barcode.indexOf("elodms") == 0) {
            // handle wrong char set by some barcode readers [- equals ?ß]
            if (barcode.indexOf("elodmsÖ--") == 0) {
              barcode = barcode.replace(/[?ß]/g, "-");
            }
            regex = /[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}/i.exec(barcode);
            if (regex) {
              guid = "(" + regex[0] + ")";
              me.logger.info("Barcode contains elodms link. Goto element with GUID: " + guid);
              try {
                objId = elo.IX.ix().checkoutSord(guid, elo.CONST.SORD.mbOnlyId, elo.CONST.LOCK.NO).id;
                api.Webclient.gotoEntry(objId);
              } catch (e) {
                me.logger.info("Object not found for GUID: " + guid);
              }
            } else {
              me.logger.info("Barcode contains wrong guid format: " + guid);
            }
          } else if (sol.common.web.BarcodeRegistry.isValidBarcode(barcode)) {
            sol.common.web.BarcodeRegistry.execute(barcode);
          }
        }

      });

    });

    api.require({
      namespace: ["sol"]
    }, function () {

      /**
       * @private
       *
       * This is an experimental class that might change in the future.
       * Don't rely on its existance.
       */
      sol.define("sol.common.web.BarcodeRegistry", {
        singleton: true,
        splitCharacter: ".",

        /**
         * @property registered barcode handlers
         * @private
         */
        registeredHandlers: {},

        /**
         * registers a new handler for incoming barcodes.
         * @param {String} identifier
         * @param {String} name name for the barcode handler
         * @param {function} handler
         */
        register: function (identifier, name, handler) {
          var me = this;
          me.logger.info(["Register handler '{1}' for identifier '{0}'.", identifier, name]);
          if (me.registeredHandlers.hasOwnProperty(identifier)) {
            me.logger.warn(["Override exisiting barcode handler for {0}.", identifier]);
          }
          me.registeredHandlers[identifier] = {
            name: name,
            handler: handler
          };
        },

        /**
         * processes and executes a barcode by its handler.
         * @param {String} barcode
         * @return {Boolean}
         */
        execute: function (barcode) {
          var me = this,
              parts,
              objId,
              identifier;

          if (!me.isValidBarcode(barcode)) {
            return false;
          }

          parts = barcode.split(me.splitCharacter);
          identifier = parts[0];
          objId = Number.parseFloat(parts[1]) || undefined;

          if (me.registeredHandlers.hasOwnProperty(identifier)
                  && me.registeredHandlers[identifier].handler) {
            me.registeredHandlers[identifier].handler.call(me, identifier, objId, {
              parts: parts,
              barcode: barcode
            });
          } else {
            sol.common.web.ApiUtils.showPopupMessage("No handler found for barcode");
          }
          return true;
        },

        /**
         * checks if a given barcode is a valid source for executing actions.
         * @param {String} barcode
         * @return {Boolean}
         */
        isValidBarcode: function (barcode) {
          var me = this;
          return (barcode.indexOf(me.splitCharacter) > 0);
        }
      });
    });

    api.require({
      namespace: ["sol"],
      locales: ["sol.common.client.ActionHandler"]
    }, function (locales) {

      /**
       * This class provides helper functions for executing complex actions.
       *
       * @elojc
       * @requires sol.common.web.ActionHandler
       */
      sol.define("sol.common.web.ActionHelper", {
        singleton: true,

        executeSimpleAction: function (objId, cfg) {
          var me = this,
              cfgObject;

          elo.helpers.Console.info("[sol.common.web.ActionHelper] executing advanced action on objId: " + objId, cfg);

          if (!cfg || !cfg.fct) {
            throw "executing a simple action requires mandatory config properties.";
          }

          cfgObject = (cfg.cfgTemplate) ? me.getConfigObject(cfg.cfgTemplate, me.initActionCfg(objId)) : {};

          sol.common.web.ActionHandler.execute(
            cfg.fct,
            cfgObject
          );
        },

        /**
         * Helps in executing advanced actions that include precondition checks and
         * different object types.
         *
         * Advanced action configurations are handled in the following order:
         *
         * 1.  select types (optional)
         * 2.  check preconditions (type selection possible if returned by check) (optional)
         * 3.  select target (optional)
         * 4.  execute action (IX/ AS) (required)
         *
         * Please note that step 1 and 2 can be used for selecting types. If a special function
         * is used for type selection (Step 1), the user selection is overriden if a second
         * type selection is handled by step 2.
         *
         *     {
         *       preconditions: {
         *         fct: 'RF_sol_contact_service_CheckContactPreconditions',
         *       },
         *       fct: 'RF_sol_contact_action_CreateContact',
         *       cfgTemplate: '{
         *              "parentId": "{{objId}}",
         *              "contactType": "{{type.name}},
         *              "templateId": "{{type.objId}}
         *       }',
         *       locale: {
         *           errorDlgTitle: locale['sol.contact.client.contact.create.dialog.error.title'],
         *           typesDlgTitle: locale['sol.contact.client.contact.create.dialog.title'],
         *           typesDlgHeader: locale['sol.contact.client.contact.create.dialog.header'],
         *           typesDlgText: locale['sol.contact.client.contact.create.dialog.text'],
         *           typesDlgNoTypes: locale['sol.contact.client.contact.create.msg.notype'],
         *
         *           targetDlgTitle: locale['sol.contact.client.contact.create.dialog.title'],
         *           targetDlgHeader: locale['sol.contact.client.contact.create.dialog.header'],
         *           targetDlgText: locale['sol.contact.client.contact.create.dialog.text'],
         *       }
         *     }
         *
         * @param {String} objId
         * @param {Object} cfg
         */
        executeAdvancedAction: function (objId, cfg) {
          var me = this,
              actionCfg = me.initActionCfg(objId),
              handler_selectTypes, handler_preconditions, handler_selectTarget, handler_executeAction;

          elo.helpers.Console.info("[sol.common.web.ActionHelper] executing advanced action on objId: " + objId, cfg);

          if (!cfg || !cfg.fct || !cfg.cfgTemplate) {
            throw "executing an advanced action requires mandatory config properties.";
          }

          actionCfg.buttonName = cfg.buttonName;

          // asynchronous calls require synchonisation between ajax responses.
          // therefore several handlers are linked.
          handler_selectTypes = function (objId, cfg, actionCfg) {
            if (cfg.selectType && cfg.selectType.fct) {
              // action requires precondition checks
              me.handleTypeSelection(objId, cfg, actionCfg, function (objId, cfg, actionCfg) {
                // preconditions handled
                handler_preconditions(objId, cfg, actionCfg);
              });
            } else {
              handler_preconditions(objId, cfg, actionCfg);
            }
          };
          handler_preconditions = function (objId, cfg, actionCfg) {
            if (cfg.preconditions && cfg.preconditions.fct) {
              // action requires precondition checks
              me.handlePrecondition(objId, cfg, actionCfg, function (objId, cfg, actionCfg) {
                // preconditions handled
                handler_selectTarget(objId, cfg, actionCfg);
              });
            } else {
              handler_selectTarget(objId, cfg, actionCfg);
            }
          };
          handler_selectTarget = function (objId, cfg, actionCfg) {
            if (cfg.selectTree) {
              me.handleTreeSelection(objId, cfg, actionCfg, function (objId, cfg, actionCfg) {
                handler_executeAction(objId, cfg, actionCfg);
              });
            } else {
              handler_executeAction(objId, cfg, actionCfg);
            }
          };
          handler_executeAction = function (objId, cfg, actionCfg) {
            me.handleExecuteAction(objId, cfg, actionCfg);
          };

          // call first handler
          handler_selectTypes(objId, cfg, actionCfg);
        },

        /**
         * @private
         * handles precondition checks for advanced actions.
         * @param {String} objId
         * @param {Object} cfg
         * @param {Object} actionCfg
         * @param {Object} readyFct
         */
        handlePrecondition: function (objId, cfg, actionCfg, readyFct) {
          var me = this;

          sol.common.IxUtils.execute(cfg.preconditions.fct, {
            targetId: objId
          }, function (checkResult) {
            // sucess
            elo.helpers.Console.info("[sol.common.web.ActionHelper] prepare action successful.", checkResult);

            if (checkResult.valid !== true) {
              elo.helpers.Console.info("[sol.common.web.ActionHelper] prepare action returned invalid result. Cancel execution.");
              api.Webclient.alert(cfg.locale.errorDlgTitle || locales["sol.common.client.ActionHandler.errordlg.title"], checkResult.msg);
              return;
            }

            if (checkResult.targetId && checkResult.targetId != objId) {
              elo.helpers.Console.info("[sol.common.web.ActionHelper] changed objId by preconditions to: " + checkResult.targetId);
              objId = checkResult.targetId;
            }

            actionCfg.objId = objId;
            actionCfg.preconditions = checkResult;

            if (checkResult.types && checkResult.types.length >= 0) {
              me.handleSimpleActionTypes(checkResult.types, objId, cfg, actionCfg, function (objId, cfg, actionCfg) {
                // call ready
                readyFct(objId, cfg, actionCfg);
              });
            } else {
              // call ready
              readyFct(objId, cfg, actionCfg);
            }
          }, function (error) {
            elo.helpers.Console.error("[sol.common.web.ActionHelper] prepare action returned an unexpected error.", error);
            api.Webclient.alert(cfg.locale.errorDlgTitle || locales["sol.common.client.ActionHandler.errordlg.title"], error.msg + ": " + error.details);
          });
        },

        /**
         * @private
         * handles simple selection of different types.
         * @param {String} types
         * @param {String} objId
         * @param {Object} cfg
         * @param {Object} actionCfg
         * @param {Object} readyFct
         */
        handleSimpleActionTypes: function (types, objId, cfg, actionCfg, readyFct) {
          var choices, type, i;

          if (types && types.length > 1) {
            choices = [];
            for (i = 0; i < types.length; i++) {
              type = types[i];
              choices.push({ title: type.name, text: type.desc, data: type });
            }

            elo.helpers.Console.info("[sol.common.web.ActionHelper] prepare action returned multiple type choices.", choices);
            api.Webclient.showCommandLinkDialog(
              cfg.locale.typesDlgTitle,
              cfg.locale.typesDlgHeader,
              cfg.locale.typesDlgText,
              choices,
              function (choice) { // selected type
                actionCfg.type = choice.data;
                // call ready
                readyFct(objId, cfg, actionCfg);
              }, function () { // clicked cancel
                elo.helpers.Console.info("[sol.common.web.ActionHelper] closed file selection dialog. cancel execution.");
              }
            );
          } else if (types && types.length > 0) {
            actionCfg.type = types[0];
            // call ready
            readyFct(objId, cfg, actionCfg);
          } else {
            api.Webclient.alert(cfg.locale.typesDlgTitle || locales["sol.common.client.ActionHandler.errordlg.title"], cfg.locale.typesDlgNoTypes);
          }
        },

        handleTypeSelection: function (objId, cfg, actionCfg, readyFct) {
          var me = this,
              typeServiceCfg = {};

          if (cfg.selectType && cfg.selectType.cfgTemplate) {
            typeServiceCfg = me.getConfigObject(cfg.selectType.cfgTemplate, actionCfg);
          }

          sol.common.IxUtils.execute(cfg.selectType.fct, typeServiceCfg, function (types) {
            // sucess
            me.handleSimpleActionTypes(types, objId, cfg, actionCfg, readyFct);
          }, function (error) {
            elo.helpers.Console.error("[sol.common.web.ActionHelper] prepare action returned an unexpected error.", error);
            api.Webclient.alert(cfg.locale.errorDlgTitle || locales["sol.common.client.ActionHandler.errordlg.title"], error.msg + ": " + error.details);
          });
        },

        handleTreeSelection: function (objId, cfg, actionCfg, readyFct) {
          var me = this,
              rootId = 1;

          if (cfg.selectTree.root) {
            rootId = elo.IX.ix().checkoutSord(cfg.selectTree.root, elo.CONST.SORD.mbOnlyId, elo.CONST.LOCK.NO).id;
          } else if (cfg.selectTree.rootFromCfgFile && cfg.selectTree.rootFromCfgProperty) {
            sol.common.IxUtils.execute("RF_sol_common_service_GetConfig", {
              objId: cfg.selectTree.rootFromCfgFile
            }, function (cfgResult) {
              // set root id and recall handleTreeSelection
              try {
                cfg.selectTree.root = me.getConfigObject(cfg.selectTree.rootFromCfgProperty, cfgResult);
                me.handleTreeSelection(objId, cfg, actionCfg, readyFct);
              } catch (msg) {
                api.Webclient.alert(locales["sol.common.client.ActionHandler.errordlg.title"], "Invalid configuration for tree selection. rootFromCfgProperty should return a valid json object. " + msg);
              }
            }, function (err) {
              //console.error(o);
            });
            return;
          }

          elo.helpers.Console.info("[sol.common.web.ActionHelper] action requires target selection. Using root: " + rootId);

          api.Webclient.showTreeSelectDialog(
            cfg.locale.treeDlgTitle || "",
            cfg.locale.treeDlgHeader || "",
            rootId,
            cfg.locale.treeDlgRootName || "..",
            function (selection) {
              // selected target
              actionCfg.tree = {
                name: selection.name,
                objId: selection.id
              };
              // call ready
              readyFct(objId, cfg, actionCfg);
            },
            function () {
              // canceled
            }
          );
        },

        prepareCfgObj: function (cfgTemplate, actionCfg) {
          var cfgObj, regex, objIdReplacement;

          cfgTemplate = cfgTemplate.replace(/\\{{/g, "{{");
          if (cfgTemplate.indexOf("\"{{objId}}\"") > -1) {
            regex = new RegExp("\"{{objId}}\"", "g");
            objIdReplacement = (actionCfg.objId) ? "\"" + actionCfg.objId + "\"" : null;
          } else {
            regex = new RegExp("{{objId}}", "g");
            objIdReplacement = (actionCfg.objId) ? actionCfg.objId : null;
          }
          cfgTemplate = cfgTemplate.replace(regex, objIdReplacement);

          cfgObj = cfgTemplate ? JSON.parse(cfgTemplate) : {};

          cfgObj.$templating = { $type: actionCfg.type, $tree: actionCfg.tree, $preconditions: actionCfg.preconditions };

          return cfgObj;
        },

        /**
         * @private
         * handles the final execution of the action.
         * @param {String} objId
         * @param {Object} cfg
         * @param {Object} actionCfg
         */
        handleExecuteAction: function (objId, cfg, actionCfg) {
          var me = this, cfgObj;

          cfgObj = me.prepareCfgObj(cfg.cfgTemplate, actionCfg); // render objId and setup serverside templating data

          switch (cfg.type) {
            case "AS":
              sol.common.web.ActionHandler.executeAs(cfg.solution, cfg.fct, cfgObj);
              break;
            default:
              sol.common.web.ActionHandler.execute(cfg.fct, cfgObj);
          }
        },

        initActionCfg: function (objId) {
          var actionCfg = { objId: objId };
          return actionCfg;
        },

        getConfigObject: function (cfgTemplate, data) {
          var str = Handlebars.compile(cfgTemplate)(data);
          return JSON.parse(str);
        }

      });

      /**
       * This class provides utility functions to call IX or AS functions and handle the response in a standardized way.
       *
       * @eloweb
       * @requires sol.common.IxUtils
       */
      sol.define("sol.common.web.ActionHandler", {
        singleton: true,

        /**
         * Executes a IX registered function and handles the response in a standardized way.
         *
         * If spezial handling is needed a custom callback can be spezified as parameter.
         * This callback get's the result Object of the registered function as only parameter.
         *
         * @param {String} registeredFunctionName
         * @param {Object} params (optional) The configuration object which will be send to the registered function
         * @param {Function} callback (optional) Should not be used anymore
         * @param {String} loadingMessage (optional) Message that is displayed while performing async operations.
         */
        execute: function (registeredFunctionName, params, callback, loadingMessage) {
          var me = this;

          me.showLoadingIndicator(loadingMessage);
          sol.common.IxUtils.execute(registeredFunctionName, params, function (resultObj) {
            if (callback && Object.prototype.toString.call(callback) === "[object Function]") {
              me.logger.warn("Use of 'callback' parameter is depricated and therefore not recommended.");
              callback.call(me, resultObj);
              me.hideLoadingIndicator();
              return;
            }
            if (resultObj) {
              me.handleEvents(resultObj.events);
              // loading indicator is hidden by event handler
            } else {
              me.hideLoadingIndicator();
            }
          }, function (err) {
            me.hideLoadingIndicator();
            // error
            var msg = "";
            if (err && err.msg) {
              msg = err.msg;
            }
            api.Webclient.alert(locales["sol.common.client.ActionHandler.errordlg.title.unexpected"], msg);
          });
        },

        executeAs: function (solutionName, asRuleName, params, callback, loadingMessage) {
          var me = this;

          me.showLoadingIndicator(loadingMessage);
          sol.common.IxUtils.execute("RF_sol_common_service_ExecuteAsAction", {
            solution: solutionName,
            action: asRuleName,
            config: params,
            connParams: {
              language: elo.IX.getLoginResult().clientInfo.language
            }
          }, function (resultObj) {
            if (resultObj && resultObj.content) {
              try {
                resultObj = JSON.parse(resultObj.content);
              } catch (ex) {
                if (!resultObj.events) {
                  console.error(resultObj);
                  me.hideLoadingIndicator();
                  api.Webclient.alert(locales["sol.common.client.ActionHandler.errordlg.title.unexpected"], locales["sol.common.client.ActionHandler.errordlg.msg.unexpected"]);
                  return;
                }
              }
            }
            if (resultObj && resultObj.events && resultObj.events.length > 0 && resultObj.events[0].ID && resultObj.events[0].ID === "ERROR") {
              // handle IX Exceptions
              console.error(resultObj);
              me.hideLoadingIndicator();
              if (resultObj.events[0].obj && resultObj.events[0].obj.msg) {
                var error = resultObj.events[0].obj.msg;
                api.Webclient.alert(locales["sol.common.client.ActionHandler.errordlg.title.unexpected"], error);
              }
              return;
            }
            if (callback && Object.prototype.toString.call(callback) === "[object Function]") {
              me.logger.warn("Use of 'callback' parameter is depricated and therefore not recommended.");
              callback.call(me, resultObj);
              me.hideLoadingIndicator();
              return;
            }
            if (resultObj && resultObj.events) {
              me.handleEvents(resultObj.events);
              // loading indicator is hidden by event handler
            } else {
              me.hideLoadingIndicator();
            }
          }, function (err) {
            // error
            api.Webclient.alert(locales["sol.common.client.ActionHandler.errordlg.title.unexpected"], locales["sol.common.client.ActionHandler.errordlg.msg.unexpected"]);
            console.error(err);
            me.hideLoadingIndicator();
          });
        },

        /**
         * @private
         * Handler for events passed by an Action. This function is called recursively for all events since event
         * handlers might perform async operations.
         * @param {Object} events
         * @param {Object} context
         */
        handleEvents: function (events, context) {
          var me = this,
              eventTypes = sol.common.IxUtils.CONST.EVENT_TYPES,
              event, handler;

          context = context || { dirtySord: true, dirtyWfStatus: true };

          if (events && events.length > 0) {
            event = events.shift();

            if (!me.checkExecution(event, context)) {
              me.handleEvents(events, context);
              return;
            }

            switch (event.ID) {
              case eventTypes.REFRESH:
                handler = sol.create("sol.common.web.ActionHandler.Refresh");
                me.hideLoadingIndicator();
                break;
              case eventTypes.GOTO:
                handler = sol.create("sol.common.web.ActionHandler.Goto");
                me.hideLoadingIndicator();
                break;
              case eventTypes.DIALOG:
                handler = sol.create("sol.common.web.ActionHandler.Dialog", {
                  actionHandler: me,
                  hideLoadingIndicator: me.hideLoadingIndicator
                });
                // loading indicator is hidden by Action Handler
                break;
              case eventTypes.ACTION:
                handler = sol.create("sol.common.web.ActionHandler.Action", {
                  actionHandler: me,
                  hideLoadingIndicator: me.hideLoadingIndicator
                });
                // loading indicator is hidden by Action Handler
                break;
              case eventTypes.FEEDBACK:
                handler = sol.create("sol.common.web.ActionHandler.Feedback");
                me.hideLoadingIndicator();
                break;
              case eventTypes.ERROR:
                handler = sol.create("sol.common.web.ActionHandler.Error");
                me.hideLoadingIndicator();
                break;
              default:
            }

            if (handler && me.isFunction(handler.execute)) {
              handler.execute(event, context, function () {
                me.handleEvents(events, context);
              });
            } else {
              me.logger.warn(["No handler for event of type '{0}'", event.ID]);
            }
          } else {
            me.hideLoadingIndicator();
          }
        },

        /**
         * @private
         * @param {Object} event
         * @param {Object} context
         * @return {Boolean}
         */
        checkExecution: function (event, context) {
          var me = this,
              checkValue, mapitems;

          if (event.ON) {
            if (context.dirtySord && event.ON.objId) {
              context.sord = elo.IX.ix().checkoutSord(event.ON.objId, elo.CONST.SORD.mbAllIndex, elo.CONST.LOCK.NO);
              context.dirtySord = false;
            }

            if (context.dirtyWfStatus && event.ON.flowId) {
              context.wfStatus = sol.common.IxUtils.execute("RF_sol_common_service_GetWorkflowMetadata", { flowId: event.ON.flowId }).status;
              context.dirtyWfStatus = false;
            }

            switch (event.ON.type) {
              case "WF_STATUS":
                checkValue = context.wfStatus;
                break;
              case "GRP":
                checkValue = context.sord.getLineByGroup(event.ON.key);
                break;
              case "SORD":
                checkValue = context.sord[event.ON.key];
                break;
              case "MAP":
                mapitems = elo.IX.ix().checkoutMap(elo.CONST.MAP_CONFIG.DOMAIN_SORD, event.ON.objId, [event.ON.key], elo.CONST.LOCK.NO).items;
                if (mapitems && mapitems.length === 1) {
                  checkValue = mapitems[0].value;
                }
                break;
              default:
                me.logger.warn(["event defines non existing ON.type={0}, ON condition will be ignored", event.ON.type]);
                return true;
            }

            return checkValue == event.ON.value;
          }
          return true;
        },

        /**
         * @private
         * @param {Object} obj
         * @return {Object}
         */
        isFunction: function (obj) {
          return obj && Object.prototype.toString.call(obj) === "[object Function]";
        },

        showLoadingIndicator: function (text) {
          var me = this;
          me.loadingIndicator = Ext.MessageBox.show({
            msg: text || "Loading...",
            //modal: false,
            width: 300,
            wait: true,
            waitConfig: { interval: 200 }
          });
        },

        hideLoadingIndicator: function () {
          var me = this;
          if (me.loadingIndicator) {
            me.loadingIndicator.hide();
          }
        }

      });

      sol.define("sol.common.web.ActionHandler.Refresh", {
        tryCheckoutTimes: 100,

        execute: function (event, context, callback) {
          var eventConfig;

          if (event.ID !== sol.common.IxUtils.CONST.EVENT_TYPES.REFRESH) {
            throw "'sol.common.jc.ActionHandler.REFRESH' can only handle '" + sol.common.IxUtils.CONST.EVENT_TYPES.REFRESH + "' events, but event-ID was '" + event.ID + "'";
          }

          if (event.obj) {
            eventConfig = event.obj;

            if (eventConfig.objId) {
              window.setTimeout(function () {
                api.Webclient.refreshView();
                callback.call(this);
              }, 1);
            }
          }
        }
      });

      sol.define("sol.common.web.ActionHandler.Goto", {
        tryCheckoutTimes: 100,

        execute: function (event, context, callback) {
          var me = this,
              eventConfig;

          if (event.ID !== sol.common.IxUtils.CONST.EVENT_TYPES.GOTO) {
            throw "'sol.common.jc.ActionHandler.GOTO' can only handle '" + sol.common.IxUtils.CONST.EVENT_TYPES.GOTO + "' events, but event-ID was '" + event.ID + "'";
          }

          if (event.obj) {
            eventConfig = event.obj;

            if (eventConfig.flowId && eventConfig.nodeId) {
              window.setTimeout(function () {
                // internal Web Client access
                api.Webclient.gotoTask({ flowId: Number(eventConfig.flowId), nodeId: Number(eventConfig.nodeId) });
                callback.call(this);
              }, 1);
            } else if (eventConfig.objId) {
              window.setTimeout(function () {
                // internal Web Client access
                api.Webclient.gotoEntry(Number(eventConfig.objId));
                if (eventConfig.checkout) {
                  me.checkoutSord(eventConfig.objId, 0);
                }
                callback.call(this);
              }, 1);
            }
          }
        },

        checkoutSord: function (objId, times) {
          var me = this,
              sord;

          // internal Web Client access
          sord = elo.ModelRegistry.getDataInstance(elo.MainCtrl.modelNames.selectedSord);

          if (sord && Object.prototype.toString.call(sord) === "[object Array]") {
            sord = sord[0];
          }

          if (sord && sord.get && String(sord.get("id")) === String(objId)) {
            elo.EventRegistry.callBusEvent("BTN_EDITINOFFICE");
          } else if (times < me.tryCheckoutTimes) {
            window.setTimeout(function () {
              me.checkoutSord(objId, times + 1);
            }, 50);
          } else {
            console.error("Checkout document failed.");
          }
        }
      });

      sol.define("sol.common.web.ActionHandler.Dialog", {

        execute: function (event, context, callback) {
          var me = this,
              eventConfig;

          if (event.ID !== sol.common.IxUtils.CONST.EVENT_TYPES.DIALOG) {
            throw "'sol.common.web.ActionHandler.DIALOG' can only handle '" + sol.common.IxUtils.CONST.EVENT_TYPES.DIALOG + "' events, but event-ID was '" + event.ID + "'";
          }

          context.dirtySord = true;
          context.dirtyWfStatus = true;

          if (event.obj) {
            eventConfig = event.obj;
            if (eventConfig.url) {
              if (me.hideLoadingIndicator) {
                // prevent background flickering
                Ext.suspendLayouts();
                me.hideLoadingIndicator.call(me.actionHandler);
                Ext.resumeLayouts();
              }

              me.registerOpenWindow(event.obj.flowId, event.obj.nodeId);
              api.Webclient.showAppDialog(eventConfig.title || "", {
                url: eventConfig.url,
                doneHandler: function () {
                  me.unregisterOpenWindow();
                  callback.call(this);
                },
                closeHandler: function () {
                  me.closeForm(event.obj.flowId, event.obj.nodeId);
                  me.unregisterOpenWindow();
                  callback.call(this);
                }
              });
            } else if (eventConfig.flowId && eventConfig.nodeId) {
              Ext.suspendLayouts();
              me.hideLoadingIndicator.call(me.actionHandler);

              event.obj.flowId = Number(event.obj.flowId);
              event.obj.nodeId = Number(event.obj.nodeId);

              me.registerOpenWindow(event.obj.flowId, event.obj.nodeId);
              api.Webclient.showAppDialog(eventConfig.title || "", {
                flowId: event.obj.flowId,
                nodeId: event.obj.nodeId,
                doneHandler: function () {
                  me.unregisterOpenWindow();
                  callback.call(this);
                },
                closeHandler: function () {
                  me.closeForm(event.obj.flowId, event.obj.nodeId);
                  me.unregisterOpenWindow();
                  callback.call(this);
                }
              });
              Ext.resumeLayouts();
            } else {
              if (me.hideLoadingIndicator) {
                me.hideLoadingIndicator.call(me.actionHandler);
              }
              callback.call(me);
            }
          }
        },

        registerOpenWindow: function (flowId, nodeId) {
          var me = this;
          me.originalonunload = window.onbeforeunload;
          me.flowId = flowId;
          me.nodeId = nodeId;
          window.onbeforeunload = function () {
            me.closeForm(me.flowId, me.nodeId);
            if (me.originalonunload) {
              me.originalonunload();
            }
          };
          me.registeredWindow = true;
        },

        unregisterOpenWindow: function () {
          var me = this;
          if (me.registeredWindow) {
            window.onbeforeunload = me.originalonunload;
            me.flowId = null;
            me.nodeId = null;
            me.registeredWindow = false;
          }
        },

        /**
         * Aborts the current form if the user clicks cancel or reloads the page.
         * @param {Number} flowId
         * @param {Number} nodeId
         */
        closeForm: function (flowId, nodeId) {
          var me = this;
          if (me.registeredWindow && me.flowId && me.nodeId) {
            sol.common.IxUtils.execute("RF_sol_common_service_ActionCancelForm", {
              flowId: flowId, nodeId: nodeId
            }, function () {
              console.info("sol.common.client.ActionHandler: Closed open process.");
            }, function (error) {
              console.error("sol.common.client.ActionHandler: Closing open process failed.", error);
            });
          }
        }
      });

      sol.define("sol.common.web.ActionHandler.Error", {

        execute: function (event, context, callback) {
          var eventConfig;

          if (event.ID !== sol.common.IxUtils.CONST.EVENT_TYPES.ERROR) {
            throw "'sol.common.web.ActionHandler.ERROR' can only handle '" + sol.common.IxUtils.CONST.EVENT_TYPES.ERROR + "' events, but event-ID was '" + event.ID + "'";
          }

          if (event.obj) {
            eventConfig = event.obj;
            api.Webclient.alert(locales["sol.common.client.ActionHandler.errordlg.title"], eventConfig.msg);
          }

          callback.call(this);
        }
      });

      sol.define("sol.common.web.ActionHandler.Feedback", {

        execute: function (event, context, callback) {
          var eventConfig;

          if (event.ID !== sol.common.IxUtils.CONST.EVENT_TYPES.FEEDBACK) {
            throw "'sol.common.web.ActionHandler.FEEDBACK' can only handle '" + sol.common.IxUtils.CONST.EVENT_TYPES.FEEDBACK + "' events, but event-ID was '" + event.ID + "'";
          }

          setTimeout(function () {
            if (event.obj) {
              eventConfig = event.obj;
              if (eventConfig.permanent === true) {
                sol.common.web.ApiUtils.showInfoMessage(eventConfig.msg);
              } else {
                sol.common.web.ApiUtils.showPopupMessage(eventConfig.msg);
              }
            }
            callback.call(this);
          }, 0);
        }
      });

      sol.define("sol.common.web.ActionHandler.Action", {
        execute: function (event, context, callback) {
          if (event.ID !== sol.common.IxUtils.CONST.EVENT_TYPES.ACTION) {
            throw "'sol.common.web.ActionHandler.ACTION' can only handle '" + sol.common.IxUtils.CONST.EVENT_TYPES.ACTION + "' events, but event-ID was '" + event.ID + "'";
          }

          context.dirtySord = true;
          context.dirtyWfStatus = true;

          if (event.COMPONENT === sol.common.IxUtils.CONST.COMPONENTS.IX) {
            sol.common.web.ActionHandler.execute(event.obj.registeredFunction, event.obj.params);
          } else if (event.COMPONENT === sol.common.IxUtils.CONST.COMPONENTS.AS) {
            sol.common.web.ActionHandler.executeAs(event.obj.solution, event.obj.directRule, event.obj.params, null, "");
          }

          callback.call(this);
        }
      });

    });

    api.require({
      namespace: ["sol", "sol.common.web.BarcodeRegistry"],
      promise: new Promise(function (resolve, reject) {
        var any;
        try {
          any = new de.elo.ix.client.Any();
          any.type = elo.CONST.ANY.TYPE_STRING;
          any.stringValue = "{}";
          api.Webclient.getIXConnection().ix().executeRegisteredFunction("RF_sol_common_services_ActionDefinitionCollector", any, new de.elo.ix.client.AsyncCallback(function (successAnyResult) {
            // sucess
            sol.$actionDefinitionsLoaded = true;
            sol.$actionDefinitionCollectorResult = successAnyResult;
            resolve();
          }, function (ex) {
            // failure
            console.error("[sol.common.web.ActionDefinitionUtils] loading ribbon definition failed (async failure callback): " + ex);
            reject();
          }));
        } catch (e) {
          console.error("[sol.common.web.ActionDefinitionUtils] loading ribbon definition failed (promise error): " + e);
          reject();
        }
      })
    }, function () {

      /**
       * This class loads ELO Business Solutions action definitions and creates the ribbon, button groups and buttons.
       *
       * This class is automatically called during client startup.
       *
       * @requires sol.common.IxUtils
       */
      sol.define("sol.common.web.ActionDefinitionUtils", {
        singleton: true,

        TAB_CONST: {
          HOME: { name: "START" },
          DOCUMENT: { name: "EXTENDED" },
          ARCHIVE: {},
          VIEW: { name: "VIEW" },
          WORKFLOW: { name: "TASK" },
          INTRAY: {},
          SEARCH: { name: "SEARCH" }
        },

        TAB_CONST_20: {
          HOME: { name: "START" },
          DOCUMENT: { name: "DOCUMENT" },
          ARCHIVE: {},
          VIEW: { name: "VIEW" },
          WORKFLOW: { name: "TASK" },
          INTRAY: {},
          SEARCH: { name: "SEARCH" },
          NEW: { name: "NEW" },
          OUTPUT: { name: "OUTPUT" },
          ORGANIZE: { name: "MANAGEMENT" }
        },

        // this is a mapping between the ELO20 JavaClient and WebClient band names
        // within an action you can use the JavaClient name - it will map it to the WebClient band name
        BAND_MAPPING_20: {
          NEW: {
            INSERT: "NEW_INSERT",
            START: "NEW_CREATETASK"
          },
          OUTPUT: {
             SEND: "OUTPUT_SEND",
             SAVE: "OUTPUT_SAVE",
             EXTERN: "OUTPUT_EXTERNALCONNECTION",
             PRINT: "OUTPUT_PRINT"
          },
          VIEW: {
            NAVIGATION: "VIEW_NAVIGATION",
            REFRESH: "VIEW_REFRESH",
            FUNCTIONALAREAS: "VIEW_REGIONS",
            VIEWPANELMODES_PREVIEW: "VIEW_VIEWPANELMODES_PREVIEW"
          },
          ORGANIZE: {
            STRUCTURE: "MANAGEMENT_STRUCTURE",
            PROPERTIES: "MANAGEMENT_PROPERTIES",
            OVERVIEWS: "MANAGEMENT_OVERVIEW",
            DELETE: "MANAGEMENT_DELETE"
          },
          SEARCH: {
            RESULT: "SEARCH_RESULT",
            FAVORITES: "SEARCH_FAVORITE",
            FILTERS: "SEARCH_FILTER",
            SEARCHAREA: "SEARCH_INDEX"
          },
          DOCUMENT: {
            VERSIONS: "DOCUMENT_VERSION",
            ATTACHMENT: "DOCUMENT_ATTACHMENT",
            NOTES: "DOCUMENT_NOTES",
          },
          WORKFLOW: {
            EDIT: "TASK_EDIT",
            VIEW: "TASK_SETTINGS"
          }
        },

        STD_ICONS: {
          small: "sol-scriptbutton16",
          smallHighRes: "sol-scriptbutton16-200",
          big: "sol-scriptbutton32",
          bigHighRes: "sol-scriptbutton32-200"
        },

        /**
    	   * Initializes ribbon buttons, groups and tabs for ELO Business Solutions.
    	   * @param {Object} contect. The current script scope.
    	   */
        initializeRibbon: function () {
          var me = this,
              any, anyResult, result;

          try {
            if (sol.$actionDefinitionsLoaded === true) {
              // use result of promise in current WebClient versions
              anyResult = sol.$actionDefinitionCollectorResult;
            } else {
              // force synchronous call -> fallback in case promises are not supoorted in WebClient version
              any = new de.elo.ix.client.Any();
              any.type = elo.CONST.ANY.TYPE_STRING;
              any.stringValue = "{}";
              anyResult = api.Webclient.getIXConnection().ix().executeRegisteredFunction("RF_sol_common_services_ActionDefinitionCollector", any);
            }

            result = JSON.parse((anyResult && anyResult.stringValue) ? String(anyResult.stringValue) : "{}");

            if (result && result.definitions) {
              me.wcVersion20OrLater = (elo && elo.data && elo.data.server && elo.data.server.webclientVersion) ? sol.common.IxUtils.checkVersion(elo.data.server.webclientVersion, "20.00.000") : false;
              me.TAB_CONST = (me.wcVersion20OrLater === true) ? me.TAB_CONST_20 : me.TAB_CONST;
              me.buildRibbonFromDefinition(result.definitions);
            }
          } catch (e) {
            console.error("[sol.common.web.ActionDefinitionUtils] loading ribbon definition failed: " + e);
          }
        },

        /**
         * Builds the web client ribbon based on ribbon button/ group/ tab definitions given by RF_sol_common_services_ActionDefinitionCollector.
         * @private
         * @param {Object[]} defs action/ ribbon definition
         */
        buildRibbonFromDefinition: function (defs) {
          var me = this,
              i, j, k, def, localDef, group, button, tab, webclientStdTab, iconNames, webclientStdGroup, groupName,
              dynRibbon = {
                _buttons: {},
                buttons: [],
                _groups: {},
                groups: [],
                _tabs: {},
                tabs: []
              },
              groupsForStandardRibbons = [],
              addedGroupsForStandardRibbons = {},
              handler = function (def, objId) {
                switch (def.type) {
                  case "ADVANCED_ACTION":
                    sol.common.web.ActionHelper.executeAdvancedAction(objId, def.action);
                    break;
                  case "SIMPLE_ACTION":
                    sol.common.web.ActionHelper.executeSimpleAction(objId, def.action);
                    break;
                  default:
                    console.error("No handler found for ribbon definition", def);
                }
              },
              getLineByGroup = function (sord, fieldName) {
                var fieldIdx, objKeys = sord.get("objKeys");
                if (sord === null || objKeys === undefined) {
                  return null;
                }
                for (fieldIdx = 0; fieldIdx < objKeys.length; fieldIdx += 1) {
                  if (objKeys[fieldIdx].name === fieldName && objKeys[fieldIdx].data && objKeys[fieldIdx].data.length > 0) {
                    return objKeys[fieldIdx].data[0];
                  }
                }
                return null;
              },
              checkAccess = function (sord, access, targetName) {
                var solType, conditions, fieldValue, visible = false;
                if (!sord) {
                  return false;
                }
                if ((access.document !== true || access.folder !== true) && ((access.document === true && sord.isFolder()) || (access.folder === true && !sord.isFolder()))) {
                  return false;
                }
                if (!access.solTypes || (access.solTypes.length <= 0)) {
                  return true;
                }

                solType = getLineByGroup(sord, "SOL_TYPE");

                if (solType && solType != "" && access.solTypes.indexOf(solType) !== -1) {
                  conditions = access.conditions;
                  if (conditions && Array.isArray(conditions)) {
                    // we're checking if one of our filter criterias is not
                    // true. This is when our some-function returns true
                    // (and we're inverting this for the 'visible' variable)
                    visible = !conditions.some(function (condition) {
                      if (condition.key && condition.value) {
                        fieldValue = getLineByGroup(sord, condition.key);
                        if (!fieldValue) {
                          console.warn("Button/Tab access check failed. Condition Field %s does not exist in mask of clicked object %s. %s", condition.key, sord.data.name, targetName);
                          return true;
                        }
                        return fieldValue != condition.value;
                      } else {
                        console.error("Button/Tab access check failed. Bad condition configuration. %s", targetName);
                        return true;
                      }
                    });
                  } else {
                    visible = true;
                  }
                }

                return visible;
              },
              btnAccess = function (state) {
                var access = this.access, targetName = this.targetName;
                if (!access || (!access.document && !access.folder && !access.multi && (!access.solTypes || access.solTypes.length <= 0))) {
                  return true; // nothing set, button will always be enabled
                }
                if (!state.sord && !state.sords) {
                  return false; // nothing selected
                }
                // check single access
                if (access.multi !== true) {
                  return checkAccess(state.sord, access, targetName);
                }
                // check multi select
                if (state.sords) {
                  return !state.sords.some(function (sord) {
                    return !checkAccess(sord, access, targetName);
                  });
                }
                return true;
              },
              btnHandler = function (state) {
                var def = this.def, objId = null;

                // we need to pass the buttonName to our action to allow
                // for some button-specific filtering in our type selection
                def.action.buttonName = this.name;

                if (state.hasSord()) {
                  objId = state.getSord().get("id");
                } else if (state.sords && (state.sords.length > 0)) {
                  objId = state.sords.map(function (sord) {
                    return sord.get("id");
                  });
                }
                handler(def, objId);
              };
          for (i = 0; i < defs.length; i++) {
            def = defs[i];

            // legacy action definition - just one ribbon definition instead of an array
            if (def.ribbon) {
              def.ribbons = [def.ribbon];
            }

            if (def.ribbons) {
              for (j = 0; j < def.ribbons.length; j++) {
                rib = def.ribbons[j];

                if (rib && rib.button && rib.ribbonTab && rib.buttongroup) {
                  iconNames = me.getIconNames(rib.button);

                  // create web client ribbon button
                  if (!dynRibbon._buttons[rib.button.name]) {
                    dynRibbon._buttons[rib.button.name] = new api.Button({
                      name: rib.button.name,
                      def: {
                        type: def.type,
                        action: def.action
                      },
                      access: btnAccess.bind({ access: rib.button.access, targetName: rib.button.name }),
                      handler: btnHandler,
                      text: rib.button.text,
                      splitText: rib.button.splitText,
                      tooltipTitle: "<span class='title'>" + rib.button.text + "</span>",
                      tooltipText: "<p>" + rib.button.tooltipText + "</p>",
                      bigIconCls: iconNames.bigIcon,
                      smallIconCls: iconNames.smallIcon,
                      position: rib.button.position,
                      asTile: !!rib.button.asTile,
                      iconName: iconNames.tileIcon
                    });
                    me.logger.info("registered button: " + rib.button.name);
                    dynRibbon.buttons.push(dynRibbon._buttons[rib.button.name]);
                  }

                  webclientStdTab = me.TAB_CONST[rib.ribbonTab.name];

                  // read ribbon tab if new
                  if (!webclientStdTab && !dynRibbon._tabs[rib.ribbonTab.name]) {
                    me.logger.info("new ribbon tab: " + rib.ribbonTab.name);
                    dynRibbon._tabs[rib.ribbonTab.name] = {
                      cfg: rib.ribbonTab,
                      name: rib.ribbonTab.name,
                      text: rib.ribbonTab.text,
                      position: rib.ribbonTab.position,
                      access: rib.ribbonTab.access,
                      groups: [], // group names
                      _groups: [] // group definitions
                    };
                    dynRibbon.tabs.push(dynRibbon._tabs[rib.ribbonTab.name]);
                  }

                  // read ribbon group if new
                  if (!dynRibbon._groups[rib.buttongroup.name]) {
                    me.logger.info("new button group: " + rib.buttongroup.name);

                    try {
                      webclientStdGroup = me.BAND_MAPPING_20[rib.ribbonTab.name.toUpperCase()][rib.buttongroup.name.toUpperCase()];
                    } catch(e) {
                      webclientStdGroup = undefined;
                    }

                    dynRibbon._groups[rib.buttongroup.name] = {
                      cfg: rib.buttongroup,
                      name: rib.buttongroup.name,
                      text: rib.buttongroup.text,
                      mode: rib.buttongroup.mode,
                      buttons: [], // button names
                      _buttons: [], // button definitions,
                      webClientStdGroup: webclientStdGroup
                    };
                    dynRibbon.groups.push(dynRibbon._groups[rib.buttongroup.name]);

                    if (dynRibbon._tabs[rib.ribbonTab.name]) {
                      // is dynamic tab
                      dynRibbon._tabs[rib.ribbonTab.name]._groups.push();
                      dynRibbon._tabs[rib.ribbonTab.name]._groups.push(dynRibbon._groups[rib.buttongroup.name]);
                    } else if (webclientStdTab && webclientStdTab.name && !webclientStdGroup) {
                      // expect web client tab
                      groupsForStandardRibbons.push({
                        def: rib,
                        stdTab: webclientStdTab
                      });
                    }
                  }

                  // register button in group
                  if (dynRibbon._groups[rib.buttongroup.name] && !dynRibbon._groups[rib.buttongroup.name].webclientStdGroup) {
                    // is dynamic group
                    dynRibbon._groups[rib.buttongroup.name]._buttons.push({
                      def: rib,
                      btn: dynRibbon._buttons[rib.button.name]
                    });
                  } else {
                    // expect web client group
                    //         api.Registry.addRibbonButton(rib.button.name, rib.buttongroup.name, rib.button.position);
                  }
                }
              }
            }

            // register barcode handlers
            if (def.barcode && def.barcode.identifier) {
              localDef = def;
              sol.common.web.BarcodeRegistry.register(def.barcode.identifier, def.action.fct,
                function (identifier, objId, data) {
                  handler(localDef, objId);
                });
            }
          }

          // register groups
          for (j = 0; j < dynRibbon.groups.length; j++) {
            group = dynRibbon.groups[j];
            group._buttons = group._buttons.sort(function (a, b) {
              return a.def.button.position > b.def.button.position ? 1 : -1;
            });

            groupName = group.webClientStdGroup ? group.webClientStdGroup : group.name;

            // add buttons to group
            for (k = 0; k < group._buttons.length; k++) {
              button = group._buttons[k];

              if (me.wcVersion20OrLater === true) {
                // BS-855 separate button registration needed for default pinned state
                api.Registry.addRibbonButton(button.def.button.name, groupName, button.def.button.position * 100, !!button.def.button.pinned);
              } else {
                group.buttons.push(button.def.button.name);
              }
            }

            me.logger.info("registered button group: " + group.name);

            if (!me.wcVersion20OrLater || !group.webClientStdGroup) {
              group._group = new api.ButtonGroup(group);
            }
          }

          for (j = 0; j < groupsForStandardRibbons.length; j++) {
            var grpForStdtTab = groupsForStandardRibbons[j];
            if (grpForStdtTab.def && grpForStdtTab.stdTab && !addedGroupsForStandardRibbons[grpForStdtTab.def.buttongroup.name]) {
              addedGroupsForStandardRibbons[grpForStdtTab.def.buttongroup.name] = true;
              api.Registry.addButtonGroup(grpForStdtTab.def.buttongroup.name, grpForStdtTab.stdTab.name, grpForStdtTab.def.buttongroup.position * 100);
            }
          }

          // register tabs
          for (j = 0; j < dynRibbon.tabs.length; j++) {
            tab = dynRibbon.tabs[j];
            tab._groups = tab._groups.sort(function (a, b) {
              return a.cfg.position > b.cfg.position ? 1 : -1;
            });

            // add groups to tabs
            for (k = 0; k < tab._groups.length; k++) {
              group = tab._groups[k];
              tab.groups.push(group.name);
            }

            me.logger.info("registered tab: " + tab.name);
            if (tab.access && (me.wcVersion20OrLater === true)) {
              tab.visibilityFct = btnAccess.bind({ access: tab.access, targetName: tab.name });
            }
            tab._tab = new api.RibbonTab(tab);
            api.Registry.addRibbonTab(tab.name, tab.position * 100);
          }
        },

        getIconNames: function (buttonDef) {
          var me = this,
              webButtonDef, dpi, bigIcon, smallIcon, tileIcon;

          if (buttonDef.iconName && (me.wcVersion20OrLater === true)) {
            bigIcon = smallIcon = tileIcon = buttonDef.iconName;
          } else {
            webButtonDef = buttonDef.web;
            dpi = (elo && elo.data && elo.data.dpi) ? elo.data.dpi : 100;
            if (dpi > 150) {
              bigIcon = (webButtonDef && webButtonDef.bigIconHighRes) ? webButtonDef.bigIconHighRes : me.STD_ICONS.bigHighRes;
              smallIcon = (webButtonDef && webButtonDef.smallIconHighRes) ? webButtonDef.smallIconHighRes : me.STD_ICONS.smallHighRes;
            } else {
              bigIcon = (webButtonDef && webButtonDef.bigIcon) ? webButtonDef.bigIcon : me.STD_ICONS.big;
              smallIcon = (webButtonDef && webButtonDef.smallIcon) ? webButtonDef.smallIcon : me.STD_ICONS.small;
            }
            tileIcon = (webButtonDef && webButtonDef.iconName) ? webButtonDef.iconName : "";
          }

          return {
            bigIcon: bigIcon,
            smallIcon: smallIcon,
            tileIcon: tileIcon
          };
        }

      });

      sol.common.web.ActionDefinitionUtils.initializeRibbon();
    });

    //# sourceURL=sol.common.web.js