Skip to content

Commit

Permalink
First release
Browse files Browse the repository at this point in the history
  • Loading branch information
vienthuong committed Aug 27, 2021
0 parents commit f1fbe1a
Show file tree
Hide file tree
Showing 30 changed files with 1,636 additions and 0 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG_de-DE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# 1.0.0 - Erste Veröffentlichung
- Variantenschalter auf der Produktliste anzeigen
- Variantenschalter beim Hovern über eine Produkteigenschaft auf der Produktliste
- Variantenschalter auf dem Off-Canvas-Warenkorb anzeigen
- Variantenschalter auf der Warenkorbseite anzeigen</label>
- Variantenschalter auf der Bestätigungsseite der Kaufabwicklung anzeigen
- Alle diese Optionen sind konfigurierbar
7 changes: 7 additions & 0 deletions CHANGELOG_en-GB.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# 1.0.0 - First release
- Show variant switch on product listing card
- Variant switch when hovering a variant property on product listing
- Show variant switch on off-canvas cart
- Show variant switch on cart page</label>
- Show variant switch on checkout confirm page
- All these options are configurable
21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# The MIT License (MIT)

Copyright (c) 2020 vienthuong <levienthuong@gmail.com>

> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Variant switch for Shopware 6

## A plugin for [Shopware 6](https://github.com/shopware/platform)

## [Demo](https://imgur.com/gallery/FGEqepO):

![](https://media.giphy.com/media/jPe0KX39d0oT5sxtqR/giphy.gif)

![](https://i.imgur.com/H5ndVwE.png)

## Features

- Show variant switch on product listing card
- Variant switch when hovering a variant property on product listing
- Show variant switch on off-canvas cart
- Show variant switch on cart page</label>
- Show variant switch on checkout confirm page
- All these options are configurable

## Requirements

| Version | Requirements |
|--------- |---------------------------- |
| 1.0.0 | Shopware 6.4 >= |

## License

Plugin's Icon by [flaticon](https://www.flaticon.com).

The plugin is released under MIT. For a full overview check the [LICENSE](./LICENSE) file.
28 changes: 28 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "sas/variant-switch",
"description": "Variant switch",
"type": "shopware-platform-plugin",
"license": "MIT",
"autoload": {
"psr-4": {
"SasVariantSwitch\\": "src"
}
},
"require": {
"shopware/core": "^6.3",
"shopware/storefront": "^6.3"
},
"extra": {
"shopware-plugin-class": "SasVariantSwitch\\SasVariantSwitch",
"plugin-icon": "src/Resources/config/plugin.png",
"copyright": "(c) by Thuong Le<levienthuong@gmail.com>",
"description": {
"de-DE": "Schnellwechsel der Produktvariante",
"en-GB": "Quick switch product's variant"
},
"label": {
"de-DE": "Variant Schalter",
"en-GB": "Variant switch"
}
}
}

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions src/Resources/app/storefront/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import VariantHoverSwitchPlugin from './plugin/variant-hover-switch.plugin';
import OffCanvasCartSwitchOptionPlugin from "./plugin/offcanvas-cart-switch-option.plugin";

const PluginManager = window.PluginManager;

if (window.sasShowOnProductCard) {
PluginManager.register('VariantHoverSwitch', VariantHoverSwitchPlugin, '[data-variant-hover-switch]');
}

if (window.sasShowOnOffCanvasCart) {
PluginManager.override('OffCanvasCart', OffCanvasCartSwitchOptionPlugin, '[data-offcanvas-cart]');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import DomAccess from 'src/helper/dom-access.helper';
import Iterator from 'src/helper/iterator.helper';
import OffCanvasCartPlugin from 'src/plugin/offcanvas-cart/offcanvas-cart.plugin';

export default class OffCanvasCartSwitchOptionPlugin extends OffCanvasCartPlugin {

_registerEvents() {
super._registerEvents();

this.switchOptions = {
switchOptionTriggerSelector: '.js-offcanvas-cart-switch-option'
}

this._registerSwitchOptionEvents();
}

_registerSwitchOptionEvents() {
const selects = DomAccess.querySelectorAll(document, this.switchOptions.switchOptionTriggerSelector, false);

if (selects) {
Iterator.iterate(selects, select => select.addEventListener('change', this._onSwitchLineItemOption.bind(this)));
}
}

_onSwitchLineItemOption(event) {
const select = event.target;
const form = select.closest('form');
const switchedInput = form.querySelector('.form-switched');
switchedInput.value = event.target.id;

const selector = this.options.cartItemSelector;

this.$emitter.publish('onSwitchLineItemOption');

this._fireRequest(form, selector);
}
}
204 changes: 204 additions & 0 deletions src/Resources/app/storefront/src/plugin/variant-hover-switch.plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import Plugin from 'src/plugin-system/plugin.class';
import HttpClient from 'src/service/http-client.service';
import ElementLoadingIndicatorUtil from 'src/utility/loading-indicator/element-loading-indicator.util';
import DomAccess from 'src/helper/dom-access.helper';
import Iterator from 'src/helper/iterator.helper';
import queryString from 'query-string';

export default class VariantHoverSwitchPlugin extends Plugin {
static options = {
radioFieldSelector: '.sas-product-configurator-option-input',
selectFieldSelector: '.sas-product-configurator-select-input',
urlAttribute: 'data-url',
cardType: 'standard'
};

init() {
this._httpClient = new HttpClient();
this._radioFields = DomAccess.querySelectorAll(this.el, this.options.radioFieldSelector, false);
this._selectFields = DomAccess.querySelectorAll(this.el, this.options.selectFieldSelector, false);

this._productBox = this.el.closest('.product-box');
window.variantResponseCached = window.variantResponseCached || {};
this._hoveringValue = null;

this._preserveCurrentValues();
this._registerEvents();
}

/**
* saves the current value on each form element
* to be able to retrieve it once it has changed
*
* @private
*/
_preserveCurrentValues() {
if(this._radioFields) {
Iterator.iterate(this._radioFields, field => {
if (VariantHoverSwitchPlugin._isFieldSerializable(field)) {
if (field.dataset) {
field.dataset.variantSwitchValue = field.value;
}
}
});
}
}

/**
* register all needed events
*
* @private
*/
_registerEvents() {
if(this._radioFields) {
Iterator.iterate(this._radioFields, field => {
field.addEventListener('change', event => this._onChange(event.target));
const label = field.parentElement.querySelector('label');

if (window.sasPreviewVariantOnHover) {
label.addEventListener('mouseenter', event => {
const input = event.target.parentElement.querySelector('input');
this._hoveringValue = input.value;

if (input && !input.checked) {
setTimeout(() => {
if (this._hoveringValue && this._hoveringValue === input.value) {
input.click();
}
}, 200)
}
});

label.addEventListener('mouseleave', event => {
this._hoveringValue = null;
});
}
});
}

if(this._selectFields) {
Iterator.iterate(this._selectFields, field => {
field.addEventListener('change', event => this._onChange(event.target));
});
}
}

/**
* callback when the form has changed
*
* @param element
* @private
*/
_onChange(element) {
const switchedOptionId = this._getSwitchedOptionId(element);
const selectedOptions = this._getFormValue();
this._preserveCurrentValues();

this.$emitter.publish('onChange');

const query = {
switched: switchedOptionId,
options: JSON.stringify(selectedOptions),
cardType: this.options.cardType
};

ElementLoadingIndicatorUtil.create(this.el);

let url = DomAccess.getAttribute(element, this.options.urlAttribute);

url = url + '?' + queryString.stringify({ ...query });

if (window.variantResponseCached[url]) {
if (this._productBox) {
this._productBox.outerHTML = window.variantResponseCached[url];
}

ElementLoadingIndicatorUtil.remove(this.el);

window.PluginManager.initializePlugins();

return;
}

this._httpClient.get(url, (response) => {
window.variantResponseCached[url] = response;
if (this._productBox) {
this._productBox.outerHTML = response;
}
ElementLoadingIndicatorUtil.remove(this.el);

window.PluginManager.initializePlugins()
});
}

/**
* returns the option id of the recently switched field
*
* @param field
* @returns {*}
* @private
*/
_getSwitchedOptionId(field) {
if (!VariantHoverSwitchPlugin._isFieldSerializable(field)) {
return false;
}

return DomAccess.getAttribute(field, 'data-name');
}

/**
* returns the current selected
* variant options from the form
*
* @private
*/
_getFormValue() {
const serialized = {};
if(this._radioFields) {
Iterator.iterate(this._radioFields, field => {
if (VariantHoverSwitchPlugin._isFieldSerializable(field)) {
if (field.checked) {
serialized[DomAccess.getAttribute(field, 'data-name')] = field.value;
}
}
});
}

if(this._selectFields) {
Iterator.iterate(this._selectFields, field => {
if (VariantHoverSwitchPlugin._isFieldSerializable(field)) {
const selectedOption = [...field.options].find(option => option.selected);
serialized[DomAccess.getAttribute(field, 'data-name')] = selectedOption.value;
}
});
}

return serialized;
}

/**
* checks id the field is a value field
* and therefore serializable
*
* @param field
* @returns {boolean|*}
*
* @private
*/
static _isFieldSerializable(field) {
return !field.name || field.disabled || ['file', 'reset', 'submit', 'button'].indexOf(field.type) === -1;
}

/**
* disables all form fields on the form submit
*
* @private
*/
_disableFields() {
Iterator.iterate(this._radioFields, field => {
if (field.classList) {
field.classList.add('disabled', 'disabled');
}
});
}
}
Loading

0 comments on commit f1fbe1a

Please sign in to comment.