qlik-oss/sn-action-button

View on GitHub
src/components/action-button.js

Summary

Maintainability
B
6 hrs
Test Coverage
B
87%
/* eslint-disable no-await-in-loop */
import allActions from "../utils/actions";
import navigationActions from "../utils/navigation-actions";
import styleFormatter from "../utils/style-formatter";

export const runActions = async ({ actionCallList, model, layout, app }) => {
  const properties = await model.getEffectiveProperties();
  for (let i = 0; i < actionCallList.length; i++) {
    if (layout.runtimeExpressionEvaluation) {
      const overrideValue =
        properties.actions[i].value?.qStringExpression?.qExpr &&
        (await app.evaluate(properties.actions[i].value.qStringExpression.qExpr));
      const overrideVariable =
        properties.actions[i].variable?.qStringExpression?.qExpr &&
        (await app.evaluate(properties.actions[i].variable.qStringExpression.qExpr));
      await actionCallList[i](overrideValue, overrideVariable);
    } else {
      await actionCallList[i]();
    }
  }
};

export const renderButton = ({
  layout,
  theme,
  app,
  interactions,
  senseNavigation,
  element,
  multiUserAutomation,
  translator,
  model,
}) => {
  const isSense = !!senseNavigation;
  const button = element.firstElementChild;
  const { style, qStateName, navigation } = layout;
  const disabled = layout.useEnabledCondition && layout.enabledCondition === 0;
  const isClickable = !disabled && interactions.active;
  const formattedStyles = styleFormatter.getStyles({
    style,
    disabled,
    theme,
    element,
    app,
  });

  button.setAttribute("style", formattedStyles);
  button.setAttribute("tabindex", "-1");
  styleFormatter.createLabelAndIcon({ button, theme, style, isSense });

  button.onclick = async () => {
    if (isClickable) {
      const actionCallList = [];
      const { actions } = layout;
      actions.forEach((action) => {
        const actionObj = allActions.find((act) => act.value === action.actionType);
        actionObj
          ? actionCallList.push(
              actionObj.getActionCall({
                app,
                qStateName,
                ...action,
                senseNavigation,
                multiUserAutomation,
                translator,
              })
            )
          : actionCallList.push(() => {});
      });
      button.setAttribute("disabled", true);
      await runActions({ actionCallList, model, layout, app });
      if (senseNavigation && !senseNavigation.getCurrentStoryId()) {
        const navigationObject = navigation && navigationActions.find((nav) => nav.value === navigation.action);
        if (senseNavigation && navigationObject && typeof navigationObject.navigationCall === "function") {
          await navigationObject.navigationCall({
            app,
            senseNavigation,
            ...navigation,
            element,
          });
        }
      }
      button.removeAttribute("disabled");
    }
  };

  const scale = () => {
    if (isClickable) {
      const { offsetWidth, offsetHeight } = button;
      button.style.transform =
        offsetHeight > offsetWidth
          ? `scale(${0.98}, ${1 - (offsetWidth / offsetHeight) * 0.02})`
          : `scale(${1 - (offsetHeight / offsetWidth) * 0.02}, ${0.98})`;
    }
  };

  const resetScale = () => {
    const { transform } = button.style;
    if (isClickable && transform !== "" && transform !== "scale(1)") {
      button.style.transform = "scale(1)";
    }
  };

  button.onmousedown = (event) => {
    if (event.button === 0) {
      scale();
    }
  };
  button.onmouseup = resetScale;
  button.onmouseleave = resetScale;
  button.ontouchstart = scale;
  button.ontouchend = resetScale;
  button.ontouchcancel = resetScale;

  return () => {
    button.onclick = undefined;
    button.onmousedown = undefined;
    button.onmouseup = undefined;
    button.onmouseleave = undefined;
    button.ontouchstart = undefined;
    button.ontouchend = undefined;
    button.ontouchcancel = undefined;
  };
};