/ Gists

Gists

On gists

Options API vs Composition API

Vue.js

fight.md #

Source:
https://medium.com/arcana-network-blog/vue-3-composition-api-basics-and-patterns-44813f2c785d

Options API vs Composition API

Mixin vs Composition API

Comparison


On gists

AfterSaveAction, events (own Kdyby implementation)

AW PHP Patterns

aftersaveEvent.php #

<?php

final class EshopOrderAfterSaveRegister extends Nette\Object {

	/**
	 * Nette callback array of after order save actions
	 * 
	 * @var array
	 */
	public $onAfterSave;

	/**
	 * Array with IAfterSaveAction objects
	 * 
	 * @var array
	 */
	private $afterSaveActions = array();

	/**
	 * Nette callback array of actions after success payment
	 * 
	 * @var array
	 */
	public $onAfterSuccessPayment;

	/**
	 * Array with IAfterSaveAction objects
	 * 
	 * @var array
	 */
	private $afterSuccessPaymentActions = array();

	/**
	 * Nette callback array of actions after fail payment
	 * 
	 * @var array
	 */
	public $onAfterFailPayment;

	/**
	 * Array with IAfterSaveAction objects
	 * 
	 * @var array
	 */
	private $afterFailPaymentActions = array();

	/**
	 * Instance of current presenter
	 * 
	 * @var Presenter
	 */
	private $presenter;

	/**
	 * Model EshopOrder
	 * 
	 * @var EshopOrder
	 */
	private $modelEshopOrder;

	public function __construct(EshopOrder $modelEshopOrder) {
		$this->modelEshopOrder = $modelEshopOrder;
	}

	/**
	 * Register after save action
	 * 
	 * @param IAfterSaveAction
	 */
	public function addAfterSaveAction(IAfterSaveAction $action) {
		$this->afterSaveActions[] = $action;
		return $this;
	}

	/**
	 * Register after success payment action
	 * 
	 * @param IAfterSaveAction
	 */
	public function addAfterSuccessPaymentAction(IAfterSaveAction $action) {
		$this->afterSuccessPaymentActions[] = $action;
		return $this;
	}

	/**
	 * Register after success payment action
	 * 
	 * @param IAfterSaveAction
	 */
	public function addAfterFailPaymentAction(IAfterSaveAction $action) {
		$this->afterFailPaymentActions[] = $action;
		return $this;
	}

	/**
	 * Application presenter setter
	 * 
	 * @param Presenter
	 */
	public function setPresenter(Presenter $presenter) {
		$this->presenter = $presenter;
		return $this;
	}

	/**
	 * Inicialize and invoke after save actions
	 * 
	 * @param  int
	 * @return void
	 */
	public function invokeAfterSaveActions($orderId) {
		foreach($this->afterSaveActions as $action) {
			$action->setPresenter($this->presenter);
			$this->onAfterSave[] = array($action, 'doAction');
		}

		$eshopOrder 	= $this->modelEshopOrder->getOrder($orderId);
		$orderItems 	= $this->modelEshopOrder->getOrderItems($orderId);
		$orderVouchers 	= $this->modelEshopOrder->getOrderVouchers($orderId);

		$this->onAfterSave($eshopOrder, $orderItems, $orderVouchers);
	}

	/**
	 * Inicialize and invoke after success payment actions
	 * 
	 * @param  int
	 * @return void
	 */
	public function invokeAfterSuccessPaymentActions($orderId) {
		foreach($this->afterSuccessPaymentActions as $action) {
			$action->setPresenter($this->presenter);
			$this->onAfterSuccessPayment[] = array($action, 'doAction');
		}

		$eshopOrder 	= $this->modelEshopOrder->getOrder($orderId);
		$orderItems 	= $this->modelEshopOrder->getOrderItems($orderId);
		$orderVouchers 	= $this->modelEshopOrder->getOrderVouchers($orderId);

		$this->onAfterSuccessPayment($eshopOrder, $orderItems, $orderVouchers);
	}

	/**
	 * Inicialize and invoke after success payment actions
	 * 
	 * @param  int
	 * @return void
	 */
	public function invokeAfterFailPaymentActions($orderId) {
		foreach($this->afterFailPaymentActions as $action) {
			$action->setPresenter($this->presenter);
			$this->onAfterFailPayment[] = array($action, 'doAction');
		}

		$eshopOrder 	= $this->modelEshopOrder->getOrder($orderId);
		$orderItems 	= $this->modelEshopOrder->getOrderItems($orderId);
		$orderVouchers 	= $this->modelEshopOrder->getOrderVouchers($orderId);

		$this->onAfterFailPayment($eshopOrder, $orderItems, $orderVouchers);
	}

}

On gists

Observe

JavaScript

observe.js #

const callback = (entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      // `entry.target` 是 dom 元素
      console.log(`${entry.target.id} is visible`);
    }
  });
};
const options = {
  threshold: 1.0,
};
const observer = new IntersectionObserver(callback, options);
const btn = document.getElementById( btn );
const bottomBtn = document.getElementById( bottom-btn );
observer.observe(btn);
observer.observe(bottomBtn);

On gists

Detect device type

JavaScript JS oneliners

snippet.js #

const detectDeviceType = () =>
  /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
    navigator.userAgent
  )
    ?  Mobile 
    :  Desktop ;
console.log(detectDeviceType());

On gists

Video header

CSS CSS trick

video-header.css #

/*
https://jsbin.com/razumivece/edit?css,output
https://jsbin.com/qejuforoba/edit?css,output
*/


header {
  position: relative;
  background-color: black;
  height: 400px;
  width: 100%;
  overflow: hidden;
}

 video {
  position: absolute;
  top: 50%;
  left: 50%;
  min-width: 100%;
  min-height: 100%;
  width: auto;
  height: auto;
  z-index: 0;
  transform: translateX(-50%) translateY(-50%);
}

/* or */
video {
	position: absolute;
	height: 100%;
	width: 100%;
	object-fit: cover;
}

On gists

Composables vs Mixins

Vue.js

explanation.js #

/*
https://vueschool.io/articles/vuejs-tutorials/what-is-a-vue-js-composable/
*/

/*
Clarity of Data/Methods Source
Mixins = Data Source Obscured
Composables = Transparent Source of Data and Functions
*/

//MyComponent.vue
import ProductMixin from './ProductMixin'
import BrandMixin from './BrandMixin'
import UserMixin from './UserMixin'
export default{
    mixins:[ProductMixin, BrandMixin, UserMixin],
    created(){
        // Where in the world did name come from? 
        // Let me look through each of the registered mixins to find out
        // Oh man, it's not in any of them...
        // It must be from a globally registered mixin
        console.log(this.site)

        // Oh, I got lucky here turns out the first mixin I inspected has the name
        console.log(this.name)
    }
}

//MyComponent.vue
import useProduct from './useProduct'
import useBrand from './useBrand'
import useUser from './useUser'
export default{
    setup(){
        const { name } = useProduct()

        return { name }
  }
    created(){
        // Where in the world did name come from? 
        // ah, it's not in setup anywhere... this doesn't exist and is an error
        console.log(this.site)

        // Oh, nice I can see directly in setup this came from useProduct
        console.log(this.name)
    }
}



/*
Naming Collisions
Mixins = Risk of Naming Collisions
Composables = NO risk of naming collisions
*/

//MyComponent.vue

import ProductMixin from './ProductMixin' // name = AirMax
import BrandMixin from './BrandMixin' // name = Nike
import UserMixin from './UserMixin' // name = John Doe
export default{
    mixins:[ProductMixin, BrandMixin, UserMixin],
    created(){  
        // Actually I'm not so lucky,
        // yeah I found the name in ProductMixin
        // but turns out UserMixin had a name too
        console.log(this.name) // John Doe
    }
}

//MyComponent.vue
import useProduct from './useProduct' // name = AirMax
import useBrand from './useBrand' // name = Nike
import useUser from './useUser' // name = John Doe
export default{
    setup(){
        const { name: productName } = useProduct()
        const { name: brandName } = useBrand()
        const { name: userName } = useUser()

        return { productName, brandName, userName }
  }
    created(){
        // Yay! Nothing is lost and I can get the name of each of the things
        // together in my component but when writing the composables
        // I don't have to think at all about what variable names might collide
        // with names in other composables
        console.log(this.productName)
        console.log(this.brandName)
        console.log(this.userName)
    }
}


/*
Mutating Module's Reactive Data from the Component
Mixins = Can NOT Safeguard Own Reactive Data
Composables = Can Safeguard Own Reactive Data
*/
// RequestMixin.js
 export default {
  data(){
        return {
            loading: false,
            payload: null
        }
  },
    methods:{
        async makeRequest(url){
            this.loading = true
            const res = await fetch(url)
            this.payload = await res.json()
            this.loading = false
        }
    }
}

// useRequest.js
import { readonly, ref } from "vue";
export default () => {
    // data
  const loading = ref(false);
  const payload = ref(null);

    // methods
  const makeRequest = async (url) => {
    loading.value = true;
    const res = await fetch(url);
    payload.value = await res.json();
  };

    // exposed
  return {
    payload: readonly(payload), //notice the readonly here
    loading: readonly(loading), // and here
    makeRequest
  };
};



/*
Global State with Composables
*/
//CounterMixins.js
export default{
    data(){
        return { count: 0 }
    },
    methods:{
        increment(){
            this.count ++
        }
    }
}

//useCounter.js
import {ref, readonly} from 'vue'
export default () => {
  const count = ref(0)
    const increment = ()=> count.value++

    return {
        count: readonly(count), 
        increment
    }
}

//useCounter.js
import {ref, readonly} from 'vue'
const count = ref(0)
export default () => {
    const increment = ()=> count.value++

    return {
        count: readonly(count), 
        increment
    }
}

On gists

JS lambda closure

JavaScript-OOP JavaScript

example.js #

function counter() {
  let count = 0;

  function increment() {
    return count += 1;
  };

  return increment;
}

const generateId = counter();

generateId(); // 1
generateId(); // 2
generateId(); // 3



// ES 6 ;)

const test = () => {
	let temp = 0;
	 return () => {
		temp++;
		console.log(temp);
	}
}

const invoke = test();

invoke();
invoke();
invoke();


On gists

Audio api

JavaScript

example.js #

   <script>
        var audios = [];
        audios[0] = new Audio("/sounds/audio_2019-12-20_11-12-44.mp3");    
        audios[1] = new Audio("/sounds/audio_2019-12-20_11-13-32.mp3");    
        audios[2] = new Audio("/sounds/audio_2019-12-20_11-13-43.mp3");    
        audios[3] = new Audio("/sounds/makak-oda.mp3");    
        
        var sound;
        var playAudio = function(index)
        {
            for (i = 0; i < audios.length; i++)
            {
                sound = audios[i];
                sound.pause();
                sound.currentTime = 0;
            }

            audios[index].play();
        };
        
    </script>

On gists

Workaround

AW

selection-workaround.php #

<?php

	public function filterAllowedPayments(&$payments)
	{
		// pokud je v kosiku la degustacion nelze platit kartou
		if ($this->isLDBBInBasket() && isset($payments[2])) {
			// $payments->where('NOT id', 2);
			unset($payments[2]);
		}

		// pokud je v kosiku merche, neumoznime platbu kartou pri prevzeti
		if ($this->isMerchInBasket() && isset($payments[4])) {
			// $payments->where('NOT id', 4);
			unset($payments[4]);
		}

		if (!$this->isLDBBInBasket() && isset($payments[4])) {
			unset($payments[4]);
		}

	}

	public function filterAllowedTransports(&$transports)
	{
		// pokud v kosiku neni merche, nelze vyzvednout v ambi kancelari
		if (!$this->isMerchInBasket() && isset($transports[2047])) {
			// $transports->where('NOT id', 2047);
			unset($transports[2047]);
		}
	}

On gists

MSP Vat resolver

PHP AW PHP Patterns

solution.php #

<?php

namespace Model;
use Nette;


class VatCzSkResolver
{
	private static $instance;

	public $eshopOrderFormMasoprofit;
	
	public function __construct(EshopOrderFormMasoprofit $eshopOrderFormMasoprofit)
	{
		self::$instance = $this;
		$this->eshopOrderFormMasoprofit = $eshopOrderFormMasoprofit;
	}

	public static function getDphRewrite()
	{
		if (!self::$instance) { // nejsme na frontendu
			return null;
		}
		
		if ($billingAddress = self::$instance->eshopOrderFormMasoprofit->getBillingAddress()) {
			if (isset($billingAddress['country_id']) && $billingAddress['country_id'] == 186) {
				if (isset($billingAddress['ic_vat']) && $billingAddress['ic_vat'] && isset($billingAddress['dic']) && $billingAddress['dic']) {
					return 0;
				}

				return 20;
			}
		}

		return null;
	}
}