diff --git a/src/Components/CardRepository/CardRepository.php b/src/Components/CardRepository/CardRepository.php
index 53a0fd38d..0b15eb0b5 100644
--- a/src/Components/CardRepository/CardRepository.php
+++ b/src/Components/CardRepository/CardRepository.php
@@ -22,6 +22,7 @@ public function __construct(private readonly EntityRepository $cardRepository)
public function saveCard(
CustomerEntity $customer,
+ string $cardHolder,
string $truncatedCardPan,
string $pseudoCardPan,
string $cardType,
@@ -39,6 +40,7 @@ public function saveCard(
$data = [
'id' => $card === null ? Uuid::randomHex() : $card->getId(),
+ 'cardHolder' => $cardHolder,
'pseudoCardPan' => $pseudoCardPan,
'truncatedCardPan' => $truncatedCardPan,
'cardType' => $cardType,
@@ -96,15 +98,15 @@ public function removeAllCardsForCustomer(CustomerEntity $customer, Context $con
}
public function getExistingCard(
- CustomerEntity $customer,
+ CustomerEntity|string $customer,
string $pseudoCardPan,
Context $context
): ?PayonePaymentCardEntity {
$criteria = new Criteria();
$criteria->addFilter(
- new EqualsFilter('payone_payment_card.pseudoCardPan', $pseudoCardPan),
- new EqualsFilter('payone_payment_card.customerId', $customer->getId())
+ new EqualsFilter('pseudoCardPan', $pseudoCardPan),
+ new EqualsFilter('customerId', \is_string($customer) ? $customer : $customer->getId())
);
/** @var PayonePaymentCardEntity|null $card */
@@ -112,4 +114,19 @@ public function getExistingCard(
return $card;
}
+
+ /**
+ * TODO-card-holder-requirement: remove this method (please see credit-card handler)
+ * @deprecated
+ */
+ public function saveMissingCardHolder(string $cardId, string $customerId, mixed $cardHolder, Context $context): void
+ {
+ $this->cardRepository->upsert([
+ [
+ 'id' => $cardId,
+ 'customerId' => $customerId,
+ 'cardHolder' => $cardHolder,
+ ],
+ ], $context);
+ }
}
diff --git a/src/Components/CardRepository/CardRepositoryInterface.php b/src/Components/CardRepository/CardRepositoryInterface.php
index 8a30a7bde..6e1b4ee3a 100644
--- a/src/Components/CardRepository/CardRepositoryInterface.php
+++ b/src/Components/CardRepository/CardRepositoryInterface.php
@@ -13,6 +13,7 @@ interface CardRepositoryInterface
{
public function saveCard(
CustomerEntity $customer,
+ string $cardHolder,
string $truncatedCardPan,
string $pseudoCardPan,
string $cardType,
@@ -37,8 +38,14 @@ public function removeAllCardsForCustomer(
): void;
public function getExistingCard(
- CustomerEntity $customer,
+ CustomerEntity|string $customer,
string $pseudoCardPan,
Context $context
): ?PayonePaymentCardEntity;
+
+ /**
+ * TODO-card-holder-requirement: remove this method (please see credit-card handler)
+ * @deprecated
+ */
+ public function saveMissingCardHolder(string $cardId, string $customerId, mixed $cardHolder, Context $context): void;
}
diff --git a/src/Components/GenericExpressCheckout/PaymentHandler/AbstractGenericExpressCheckoutPaymentHandler.php b/src/Components/GenericExpressCheckout/PaymentHandler/AbstractGenericExpressCheckoutPaymentHandler.php
index 862dd02ac..a9e5c61a6 100644
--- a/src/Components/GenericExpressCheckout/PaymentHandler/AbstractGenericExpressCheckoutPaymentHandler.php
+++ b/src/Components/GenericExpressCheckout/PaymentHandler/AbstractGenericExpressCheckoutPaymentHandler.php
@@ -10,6 +10,7 @@
use Shopware\Core\Checkout\Payment\Cart\AsyncPaymentTransactionStruct;
use Shopware\Core\Checkout\Payment\Exception\AsyncPaymentProcessException;
use Shopware\Core\Checkout\Payment\PaymentException;
+use Shopware\Core\Framework\Validation\DataBag\DataBag;
use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Symfony\Component\HttpFoundation\RedirectResponse;
@@ -26,9 +27,9 @@ public static function isCapturable(array $transactionData, array $payoneTransAc
return static::isTransactionAppointedAndCompleted($transactionData) || static::matchesIsCapturableDefaults($transactionData);
}
- public function getValidationDefinitions(SalesChannelContext $salesChannelContext): array
+ public function getValidationDefinitions(DataBag $dataBag, SalesChannelContext $salesChannelContext): array
{
- return array_merge(parent::getValidationDefinitions($salesChannelContext), [
+ return array_merge(parent::getValidationDefinitions($dataBag, $salesChannelContext), [
RequestConstants::WORK_ORDER_ID => [new NotBlank()],
RequestConstants::CART_HASH => [new NotBlank()],
]);
diff --git a/src/DataAbstractionLayer/Entity/Card/PayonePaymentCardDefinition.php b/src/DataAbstractionLayer/Entity/Card/PayonePaymentCardDefinition.php
index 8231c4234..fe63e4000 100644
--- a/src/DataAbstractionLayer/Entity/Card/PayonePaymentCardDefinition.php
+++ b/src/DataAbstractionLayer/Entity/Card/PayonePaymentCardDefinition.php
@@ -49,6 +49,7 @@ protected function defineFields(): FieldCollection
(new IdField('id', 'id'))->setFlags(new PrimaryKey(), new Required()),
(new FkField('customer_id', 'customerId', CustomerDefinition::class))->addFlags(new Required()),
+ (new StringField('card_holder', 'cardHolder'))->setFlags(new Required()),
$pseudoCardPanField,
(new StringField('truncated_card_pan', 'truncatedCardPan'))->setFlags(new Required()),
diff --git a/src/DataAbstractionLayer/Entity/Card/PayonePaymentCardEntity.php b/src/DataAbstractionLayer/Entity/Card/PayonePaymentCardEntity.php
index 8965db62e..bae5001bb 100644
--- a/src/DataAbstractionLayer/Entity/Card/PayonePaymentCardEntity.php
+++ b/src/DataAbstractionLayer/Entity/Card/PayonePaymentCardEntity.php
@@ -24,6 +24,11 @@ class PayonePaymentCardEntity extends Entity
protected string $customerId;
+ /**
+ * @since 6.2.0
+ */
+ protected string $cardHolder;
+
public function getPseudoCardPan(): string
{
return $this->pseudoCardPan;
@@ -83,4 +88,9 @@ public function getCustomerId(): string
{
return $this->customerId;
}
+
+ public function getCardHolder(): string
+ {
+ return $this->cardHolder;
+ }
}
diff --git a/src/DependencyInjection/requestParameter/builder.xml b/src/DependencyInjection/requestParameter/builder.xml
index 355fad2fe..0beee6860 100644
--- a/src/DependencyInjection/requestParameter/builder.xml
+++ b/src/DependencyInjection/requestParameter/builder.xml
@@ -160,7 +160,7 @@
+ parent="PayonePayment\Payone\RequestParameter\Builder\AbstractRequestParameterBuilder" autowire="true">
diff --git a/src/Migration/Migration1718642595CreditCardAddCardHolder.php b/src/Migration/Migration1718642595CreditCardAddCardHolder.php
new file mode 100644
index 000000000..5737c8be6
--- /dev/null
+++ b/src/Migration/Migration1718642595CreditCardAddCardHolder.php
@@ -0,0 +1,30 @@
+executeStatement(
+ <<get(self::REQUEST_PARAM_SAVED_PSEUDO_CARD_PAN))) {
+ $definitions[self::REQUEST_PARAM_PSEUDO_CARD_PAN] = [new NotBlank()];
+ $definitions[self::REQUEST_PARAM_TRUNCATED_CARD_PAN] = [new NotBlank()];
+ $definitions[self::REQUEST_PARAM_CARD_EXPIRE_DATE] = [new NotBlank()];
+ $definitions[self::REQUEST_PARAM_CARD_TYPE] = [new NotBlank()];
+ }
+
+ return $definitions;
+ }
+
public static function isCapturable(array $transactionData, array $payoneTransActionData): bool
{
if (static::isNeverCapturable($payoneTransActionData)) {
return false;
}
- $txAction = isset($transactionData['txaction']) ? strtolower((string) $transactionData['txaction']) : null;
+ $txAction = isset($transactionData['txaction']) ? strtolower((string)$transactionData['txaction']) : null;
if ($txAction === TransactionStatusService::ACTION_APPOINTED) {
return true;
@@ -106,6 +133,9 @@ protected function handleResponse(
$customer = $salesChannelContext->getCustomer();
$savedPseudoCardPan = $dataBag->get(self::REQUEST_PARAM_SAVED_PSEUDO_CARD_PAN);
+ // TODO-card-holder-requirement: move the next line into the if-block if the $savedPseudoCardPan is empty (please see credit-card handler)
+ $cardHolder = $dataBag->get(self::REQUEST_PARAM_CARD_HOLDER);
+
if (empty($savedPseudoCardPan)) {
$truncatedCardPan = $dataBag->get(self::REQUEST_PARAM_TRUNCATED_CARD_PAN);
$cardExpireDate = $dataBag->get(self::REQUEST_PARAM_CARD_EXPIRE_DATE);
@@ -117,6 +147,7 @@ protected function handleResponse(
if (!empty($expiresAt) && $customer !== null && $saveCreditCard) {
$this->cardRepository->saveCard(
$customer,
+ $cardHolder,
$truncatedCardPan,
$pseudoCardPan,
$cardType,
@@ -134,6 +165,11 @@ protected function handleResponse(
$salesChannelContext->getContext()
);
+ // TODO-card-holder-requirement: remove this if-statement incl. content (please see credit-card handler)
+ if ($savedCard instanceof PayonePaymentCardEntity && empty($savedCard->getCardHolder())) {
+ $this->cardRepository->saveMissingCardHolder($savedCard->getId(), $customer->getId(), $cardHolder, $salesChannelContext->getContext());
+ }
+
$cardType = $savedCard ? $savedCard->getCardType() : '';
}
}
@@ -152,7 +188,7 @@ protected function handleResponse(
protected function getRedirectResponse(SalesChannelContext $context, array $request, array $response): RedirectResponse
{
- if (strtolower((string) $response['status']) === 'redirect') {
+ if (strtolower((string)$response['status']) === 'redirect') {
return new RedirectResponse($response['redirecturl']);
}
diff --git a/src/Payone/RequestParameter/Builder/CreditCard/AuthorizeRequestParameterBuilder.php b/src/Payone/RequestParameter/Builder/CreditCard/AuthorizeRequestParameterBuilder.php
index f44a5a860..5d7359842 100644
--- a/src/Payone/RequestParameter/Builder/CreditCard/AuthorizeRequestParameterBuilder.php
+++ b/src/Payone/RequestParameter/Builder/CreditCard/AuthorizeRequestParameterBuilder.php
@@ -4,24 +4,41 @@
namespace PayonePayment\Payone\RequestParameter\Builder\CreditCard;
+use PayonePayment\Components\CardRepository\CardRepository;
use PayonePayment\PaymentHandler\PayoneCreditCardPaymentHandler;
use PayonePayment\Payone\RequestParameter\Builder\AbstractRequestParameterBuilder;
+use PayonePayment\Payone\RequestParameter\Builder\RequestBuilderServiceAccessor;
use PayonePayment\Payone\RequestParameter\Struct\AbstractRequestParameterStruct;
use PayonePayment\Payone\RequestParameter\Struct\PaymentTransactionStruct;
class AuthorizeRequestParameterBuilder extends AbstractRequestParameterBuilder
{
+ public function __construct(
+ RequestBuilderServiceAccessor $serviceAccessor,
+ private readonly CardRepository $cardRepository
+ ) {
+ parent::__construct($serviceAccessor);
+ }
+
/**
* @param PaymentTransactionStruct $arguments
*/
public function getRequestParameter(AbstractRequestParameterStruct $arguments): array
{
+ $cardHolder = $arguments->getRequestData()->get(PayoneCreditCardPaymentHandler::REQUEST_PARAM_CARD_HOLDER);
$cardType = $arguments->getRequestData()->get(PayoneCreditCardPaymentHandler::REQUEST_PARAM_CARD_TYPE);
$pseudoCardPan = $arguments->getRequestData()->get(PayoneCreditCardPaymentHandler::REQUEST_PARAM_PSEUDO_CARD_PAN);
$savedPseudoCardPan = $arguments->getRequestData()->get(PayoneCreditCardPaymentHandler::REQUEST_PARAM_SAVED_PSEUDO_CARD_PAN);
- if (!empty($savedPseudoCardPan)) {
- $pseudoCardPan = $savedPseudoCardPan;
+ $salesChannelContext = $arguments->getSalesChannelContext();
+ if (!empty($savedPseudoCardPan) && !empty($salesChannelContext->getCustomerId())) {
+ $savedCard = $this->cardRepository->getExistingCard(
+ $salesChannelContext->getCustomerId(),
+ $savedPseudoCardPan,
+ $salesChannelContext->getContext()
+ );
+ $pseudoCardPan = $savedCard?->getPseudoCardPan() ?: '';
+ $cardHolder = $savedCard?->getCardHolder() ?: $cardHolder;
}
return [
@@ -29,6 +46,7 @@ public function getRequestParameter(AbstractRequestParameterStruct $arguments):
'request' => $arguments->getAction(),
'pseudocardpan' => $pseudoCardPan,
'cardtype' => $cardType,
+ 'cardholder' => $cardHolder,
];
}
@@ -39,6 +57,6 @@ public function supports(AbstractRequestParameterStruct $arguments): bool
}
return $arguments->getPaymentMethod() === PayoneCreditCardPaymentHandler::class
- && in_array($arguments->getAction(), [self::REQUEST_ACTION_PREAUTHORIZE, self::REQUEST_ACTION_AUTHORIZE]);
+ && \in_array($arguments->getAction(), [self::REQUEST_ACTION_PREAUTHORIZE, self::REQUEST_ACTION_AUTHORIZE], true);
}
}
diff --git a/src/Resources/app/storefront/cypress/e2e/payment-method/creditcard.cy.js b/src/Resources/app/storefront/cypress/e2e/payment-method/creditcard.cy.js
index 5e0f1638a..8eecf64cb 100644
--- a/src/Resources/app/storefront/cypress/e2e/payment-method/creditcard.cy.js
+++ b/src/Resources/app/storefront/cypress/e2e/payment-method/creditcard.cy.js
@@ -41,13 +41,14 @@ describe('Credit Card', () => {
cy.checkoutConfirmAndComplete(
() => {
cy.get('@creditCardPan').then((storedPan) => {
- cy.get('#savedpseudocardpan').select(storedPan)
+ cy.get('#savedpseudocardpan').select(storedPan);
cy.get('.credit-card-input').should('not.be.visible');
})
});
});
function fillIframe(iban = '4111111111111111') {
+ cy.get('#creditCardHolder').type('credit card holder');
setIframeValue('cardpan', 'input', iban);
setIframeValue('cardcvc2', 'input', '123');
setIframeValue('cardexpiremonth', 'select', 5);
diff --git a/src/Resources/app/storefront/dist/storefront/js/payone-payment/payone-payment.js b/src/Resources/app/storefront/dist/storefront/js/payone-payment/payone-payment.js
index 9151d0238..ca5c5abe6 100644
--- a/src/Resources/app/storefront/dist/storefront/js/payone-payment/payone-payment.js
+++ b/src/Resources/app/storefront/dist/storefront/js/payone-payment/payone-payment.js
@@ -1 +1 @@
-(()=>{"use strict";var e={857:e=>{var t=function(e){var t;return!!e&&"object"==typeof e&&"[object RegExp]"!==(t=Object.prototype.toString.call(e))&&"[object Date]"!==t&&e.$$typeof!==n},n="function"==typeof Symbol&&Symbol.for?Symbol.for("react.element"):60103;function r(e,t){return!1!==t.clone&&t.isMergeableObject(e)?s(Array.isArray(e)?[]:{},e,t):e}function a(e,t,n){return e.concat(t).map(function(e){return r(e,n)})}function i(e){return Object.keys(e).concat(Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(e).filter(function(t){return Object.propertyIsEnumerable.call(e,t)}):[])}function o(e,t){try{return t in e}catch(e){return!1}}function s(e,n,l){(l=l||{}).arrayMerge=l.arrayMerge||a,l.isMergeableObject=l.isMergeableObject||t,l.cloneUnlessOtherwiseSpecified=r;var d,c,u=Array.isArray(n);return u!==Array.isArray(e)?r(n,l):u?l.arrayMerge(e,n,l):(c={},(d=l).isMergeableObject(e)&&i(e).forEach(function(t){c[t]=r(e[t],d)}),i(n).forEach(function(t){(!o(e,t)||Object.hasOwnProperty.call(e,t)&&Object.propertyIsEnumerable.call(e,t))&&(o(e,t)&&d.isMergeableObject(n[t])?c[t]=(function(e,t){if(!t.customMerge)return s;var n=t.customMerge(e);return"function"==typeof n?n:s})(t,d)(e[t],n[t],d):c[t]=r(n[t],d))}),c)}s.all=function(e,t){if(!Array.isArray(e))throw Error("first argument should be an array");return e.reduce(function(e,n){return s(e,n,t)},{})},e.exports=s}},t={};function n(r){var a=t[r];if(void 0!==a)return a.exports;var i=t[r]={exports:{}};return e[r](i,i.exports,n),i.exports}(()=>{n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t}})(),(()=>{n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})}})(),(()=>{n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t)})(),(()=>{var e=n(857),t=n.n(e);class r{static ucFirst(e){return e.charAt(0).toUpperCase()+e.slice(1)}static lcFirst(e){return e.charAt(0).toLowerCase()+e.slice(1)}static toDashCase(e){return e.replace(/([A-Z])/g,"-$1").replace(/^-/,"").toLowerCase()}static toLowerCamelCase(e,t){let n=r.toUpperCamelCase(e,t);return r.lcFirst(n)}static toUpperCamelCase(e,t){return t?e.split(t).map(e=>r.ucFirst(e.toLowerCase())).join(""):r.ucFirst(e.toLowerCase())}static parsePrimitive(e){try{return/^\d+(.|,)\d+$/.test(e)&&(e=e.replace(",",".")),JSON.parse(e)}catch(t){return e.toString()}}}class a{static isNode(e){return"object"==typeof e&&null!==e&&(e===document||e===window||e instanceof Node)}static hasAttribute(e,t){if(!a.isNode(e))throw Error("The element must be a valid HTML Node!");return"function"==typeof e.hasAttribute&&e.hasAttribute(t)}static getAttribute(e,t){let n=!(arguments.length>2)||void 0===arguments[2]||arguments[2];if(n&&!1===a.hasAttribute(e,t))throw Error('The required property "'.concat(t,'" does not exist!'));if("function"!=typeof e.getAttribute){if(n)throw Error("This node doesn't support the getAttribute function!");return}return e.getAttribute(t)}static getDataAttribute(e,t){let n=!(arguments.length>2)||void 0===arguments[2]||arguments[2],i=t.replace(/^data(|-)/,""),o=r.toLowerCamelCase(i,"-");if(!a.isNode(e)){if(n)throw Error("The passed node is not a valid HTML Node!");return}if(void 0===e.dataset){if(n)throw Error("This node doesn't support the dataset attribute!");return}let s=e.dataset[o];if(void 0===s){if(n)throw Error('The required data attribute "'.concat(t,'" does not exist on ').concat(e,"!"));return s}return r.parsePrimitive(s)}static querySelector(e,t){let n=!(arguments.length>2)||void 0===arguments[2]||arguments[2];if(n&&!a.isNode(e))throw Error("The parent node is not a valid HTML Node!");let r=e.querySelector(t)||!1;if(n&&!1===r)throw Error('The required element "'.concat(t,'" does not exist in parent node!'));return r}static querySelectorAll(e,t){let n=!(arguments.length>2)||void 0===arguments[2]||arguments[2];if(n&&!a.isNode(e))throw Error("The parent node is not a valid HTML Node!");let r=e.querySelectorAll(t);if(0===r.length&&(r=!1),n&&!1===r)throw Error('At least one item of "'.concat(t,'" must exist in parent node!'));return r}}class i{publish(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=new CustomEvent(e,{detail:t,cancelable:n});return this.el.dispatchEvent(r),r}subscribe(e,t){let n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=this,a=e.split("."),i=n.scope?t.bind(n.scope):t;if(n.once&&!0===n.once){let t=i;i=function(n){r.unsubscribe(e),t(n)}}return this.el.addEventListener(a[0],i),this.listeners.push({splitEventName:a,opts:n,cb:i}),!0}unsubscribe(e){let t=e.split(".");return this.listeners=this.listeners.reduce((e,n)=>([...n.splitEventName].sort().toString()===t.sort().toString()?this.el.removeEventListener(n.splitEventName[0],n.cb):e.push(n),e),[]),!0}reset(){return this.listeners.forEach(e=>{this.el.removeEventListener(e.splitEventName[0],e.cb)}),this.listeners=[],!0}get el(){return this._el}set el(e){this._el=e}get listeners(){return this._listeners}set listeners(e){this._listeners=e}constructor(e=document){this._el=e,e.$emitter=this,this._listeners=[]}}class o{init(){throw Error('The "init" method for the plugin "'.concat(this._pluginName,'" is not defined.'))}update(){}_init(){this._initialized||(this.init(),this._initialized=!0)}_update(){this._initialized&&this.update()}_mergeOptions(e){let n=r.toDashCase(this._pluginName),i=a.getDataAttribute(this.el,"data-".concat(n,"-config"),!1),o=a.getAttribute(this.el,"data-".concat(n,"-options"),!1),s=[this.constructor.options,this.options,e];i&&s.push(window.PluginConfigManager.get(this._pluginName,i));try{o&&s.push(JSON.parse(o))}catch(e){throw console.error(this.el),Error('The data attribute "data-'.concat(n,'-options" could not be parsed to json: ').concat(e.message))}return t().all(s.filter(e=>e instanceof Object&&!(e instanceof Array)).map(e=>e||{}))}_registerInstance(){window.PluginManager.getPluginInstancesFromElement(this.el).set(this._pluginName,this),window.PluginManager.getPlugin(this._pluginName,!1).get("instances").push(this)}_getPluginName(e){return e||(e=this.constructor.name),e}constructor(e,t={},n=!1){if(!a.isNode(e))throw Error("There is no valid element given.");this.el=e,this.$emitter=new i(this.el),this._pluginName=this._getPluginName(n),this.options=this._mergeOptions(t),this._initialized=!1,this._registerInstance(),this._init()}}class s{static iterate(e,t){if(e instanceof Map||Array.isArray(e))return e.forEach(t);if(e instanceof FormData){for(var n of e.entries())t(n[1],n[0]);return}if(e instanceof NodeList)return e.forEach(t);if(e instanceof HTMLCollection)return Array.from(e).forEach(t);if(e instanceof Object)return Object.keys(e).forEach(n=>{t(e[n],n)});throw Error("The element type ".concat(typeof e," is not iterable!"))}}let l="loader",d={BEFORE:"before",INNER:"inner"};class c{create(){if(!this.exists()){if(this.position===d.INNER){this.parent.innerHTML=c.getTemplate();return}this.parent.insertAdjacentHTML(this._getPosition(),c.getTemplate())}}remove(){let e=this.parent.querySelectorAll(".".concat(l));s.iterate(e,e=>e.remove())}exists(){return this.parent.querySelectorAll(".".concat(l)).length>0}_getPosition(){return this.position===d.BEFORE?"afterbegin":"beforeend"}static getTemplate(){return'
\n Loading...\n
')}static SELECTOR_CLASS(){return l}constructor(e,t=d.BEFORE){this.parent=e instanceof Element?e:document.body.querySelector(e),this.position=t}}class u extends c{create(){super.create(),this.parent.disabled=!0}remove(){super.remove(),this.parent.disabled=!1}_isButtonElement(){return"button"===this.parent.tagName.toLowerCase()}constructor(e,t="before"){if(super(e,t),!1===this._isButtonElement())throw Error("Parent element is not of type