Skip to content

Commit

Permalink
Merge pull request #14 from peckadesign/13-pdbox-historie
Browse files Browse the repository at this point in the history
#13 Historie a pdbox
  • Loading branch information
zipper authored Mar 29, 2019
2 parents 0c81c37 + b4f1b2c commit 62daacf
Show file tree
Hide file tree
Showing 9 changed files with 696 additions and 95 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@ Vlastní extensions pro nette.ajax

## Changelog

### 1.4.0
- U pdboxu je možné nastavit způsob fungování historie po zavření. Výchozí je, že po zavření přejde prohlížeč zpět do stavu před otevřením a v historii prohlížeče je pdbox možno otevřít tlačítkem vpřed. Pomocí `data-pdbox-history="forwards"` je možné nastavit, že při zavření se vytvoří nový stav do historie, tj. tlačítko zpět v prohlížeči otevře znovu tento pdbox.
- V jednotlivých extension je v `settings.pd` dostupné pole pro request zapnutých pd extension.
- Do extension se neukládá každý `xhr`, ale pouze ty, které opravdu souvisí s `pdboxem`. Stejně tak k rušení dojde pouze v případě, že oba requesty (probíhající i nový) souvisí s `pdboxem`. Opravuje #7.
- Přesunutí automatického přidávání class `js-pdbox` (obecně dle nastavení `autoclass` u extension) tak, aby i při `popstate` došlo k nastavení class uvnitř pdboxu, opravuje #15.


- **Nové extension:** Přidáno extension `replaceState` pro zachování změny url bez vytváření nových stavů. Toto extension je možné použít obecně vždy, když chceme mít aktuální url, ale v historii nechceme vytvářet nový stav. Například přepínání barev produktů nebo formuláře v pdboxu.
- **Nové extension:** Přidáno extension `suggest` pro obsluhu našeptávače. Pro funkční použití je potřeba na formulář přidat class `js-suggest`, dále je nutné označit input (`js-suggest__input`), našeptávací tlačítko (`js-suggest__btn`) a snippet s výsledky našeptávání (`js-suggest__suggest`).
- **Nové extension:** Přidáno extension `inpCombined` pro styl inputů s labelem uvnitř.
- **Nové extension:** Přidáno extension `inpNumber` pro inputy s tlačítky + a −.

:warning: **BC break:** původní výchozí chování historie pdboxu bylo to, které je nyní volitelné, tj. vytváření nového stavu po zavření. Pro zachování tohoto chování je potřeba doplnit zmíněný data atribut `data-pdbox-history="forwards"`.

### 1.3.1
- Extension `uniqueForm` nechává tlačítka disabled, pokud v odpovědi přišel `forceRedirect`. V takovém případě není žádoucí odebrat `disabled`, nicméně běží dál 60s limit.

Expand Down Expand Up @@ -30,7 +44,7 @@ Vlastní extensions pro nette.ajax
### 1.2.0
- extension `pdbox` upraveno pro kompatibilitu s `jquery.pdbox` verze `~1.2.0` - tato verze je nyní vyžadována
- oprava JS chyby v extension `pdbox` v případě, kdy byl nějaký AJAXový požadavek vyslán dříve, než byl předán parametr `box`
- extension `btnSpinner` je možno vypnout i ne ne-AJAXových formulářích pomocí data atributu `data-no-spinner` nebo `data-no-btn-spinner`
- extension `btnSpinner` je možno vypnout i na ne-AJAXových formulářích pomocí data atributu `data-no-spinner` nebo `data-no-btn-spinner`

### 1.1.5
- oprava [#12](https://github.com/peckadesign/pd.ajax/issues/12)
Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"dependencies": {
"jquery": ">=1.12",
"nette-forms": "~2.2",
"nette.ajax.js": ">=2.0 <2.4",
"nette.ajax.js": "zipper/nette.ajax.js#~2.4.0",
"jquery.pdbox": "peckadesign/jquery.pdbox#^1.2.0"
}
}
52 changes: 52 additions & 0 deletions extensions/pd/inpCombined.ajax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
(function($, undefined) {

/**
* @author Radek Šerý
*
* Inicializace .inp-combined elementů
*/
$.nette.ext('inpCombined', {
init: function() {
var snippetsExt = this.ext('snippets', true);
var ext = this;


snippetsExt.after(function($el) {
$el.find(ext.selector + '__input')
.trigger('focusout')
.hide().show();
});


var className = ext.selector.substring(1);

$(document)
.on('focusin', this.selector + '__input', function(e) {
$(this).closest(ext.selector).addClass(className + '--focus');
})
.on('focusout change', ext.selector + '__input', function(e) {
var $inpCombined = $(this).closest(ext.selector);

if ($inpCombined.hasClass(className + '--static')) {
return;
}

if ($(this).val().length) {
$inpCombined.addClass(className + '--filled');
} else {
$inpCombined.removeClass(className + '--filled');
}

if (e.type === 'focusout') {
$inpCombined.removeClass(className + '--focus');
}
})
.find(ext.selector + '__input')
.trigger('focusout')
.hide().show();
}
}, {
selector: '.inp-combined'
});

})(jQuery);
205 changes: 205 additions & 0 deletions extensions/pd/inpNumber.ajax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
(function($, undefined) {

var InpNumber = function(el) {
var $el = $(el);
var _this = this;

this.$input = $el.find('.inp-number__input');

this.$inc = $('<a href="#" class="inp-number__btn inp-number__btn--inc"><span>+</span></a>');
this.$dec = $('<a href="#" class="inp-number__btn inp-number__btn--dec"><span>&minus;</span></a>');
this.$btns = this.$inc.add(this.$dec);

this.min = parseInt(this.$input.attr('min') || 0);
this.max = parseInt(this.$input.attr('max') || Number.MAX_SAFE_INTEGER);

this.timer = null;

$el.find('.inp-number__btn').remove();
$el
.data('initialized', true)
.prepend(this.$dec)
.append(this.$inc);

// inicializace, upravení hodnoty do intervalu <min;max>, vypnutí tlačítek
this.adjustValue();
this.setDisabledBtns();

// bind handlers
this.$btns
.on('click', $.proxy(this.handleClick, this))
.on('contextmenu', function(e) { e.preventDefault(); }) // longtap na Android zařízeních otevírá menu; pro iOS je nutné uvést v css -webkit-touch-callout: none;
.on('mousedown longtap', $.proxy(this.startRapidChange, this))
.on('mouseup mouseleave touchend touchcancel', $.proxy(this.stopRapidChange, this));

this.$input
.on('change', $.proxy(this.handleChange, this)) // mouseup není vyvoláno, pokud z tlačítka sjedeme, proto mouseleave
.on('focus', $.proxy(this.handleFocus, this));
};

InpNumber.prototype = {
getValue: function() {
return parseInt(this.$input.val()) || 0;
},
setValue: function(value) {
this.$input.val(value);
},
getOp: function(e) {
return e.currentTarget === this.$dec[0] ? 'getDecrement' : 'getIncrement';
},
isClickedBtnDisabled: function(e) {
return $(e.currentTarget).data('disabled');
},

getIncrement: function(value) {
value++;

return value > this.max ? this.max : value;
},
getDecrement: function(value) {
value--;

return value < this.min ? this.min : value;
},

valueChanged: function() {
this.$input.trigger('change');
},
adjustValue: function() {
var value = this.getValue();
value = value < this.min ? this.min : (value > this.max ? this.max : value);

this.setValue(value);
},
setDisabledBtns: function() {
var value = this.getValue();

this.$btns
.data('disabled', false)
.removeClass('inp-number__btn--disabled');

if (value === this.min) {
this.$dec
.data('disabled', true)
.addClass('inp-number__btn--disabled');
}
if (value === this.max) {
this.$inc
.data('disabled', true)
.addClass('inp-number__btn--disabled');
}
},

handleClick: function(e) {
e.preventDefault();

// rapidChangeFlag flag je nastavován v případě mousedown, tj. pokud měníme hodnotu vícenásobně
if (! this.rapidChangeFlag && ! this.isClickedBtnDisabled(e)) {
var value = this.getValue();
var op = this.getOp(e);

value = this[op](value);
this.setValue(value);

this.valueChanged();
}

// musíme nastavit zde, protože click je vyvolán až po mouseup události
this.rapidChangeFlag = false;
},
handleChange: function() {
this.adjustValue();
this.setDisabledBtns();
},
handleFocus: function() {
this.$input[0].select();
},

startRapidChange: function(e) {
e.preventDefault();

// už zpracováváme z click event -> desktop, takže longtap ignorujeme
if (e.type === 'longtap' && this.rapidChangeFlag) {
return;
}

var _this = this;
var value = this.getValue();
var op = this.getOp(e);
var counter = 0;

var rapidChange = function() {
counter++;
newValue = _this[op](value);

_this.rapidChangeFlag = true;

if (value !== newValue) {
value = newValue;

_this.valueChangedFlag = true;
_this.setValue(value);

if (counter === 1) {
_this.setDisabledBtns();
}
}
// hodnota se v této iteraci nezměnila -> narazili jsme na min/max hodnotu, urychlíme vyvolání change eventy
else {
if (_this.valueChangedFlag) {
_this.stopRapidChange();
}
return;
}

var delay = 150;
if (counter > 10) {
delay = Math.max(10, delay - 5 * counter);
}
_this.timer = setTimeout(rapidChange, delay);
};

this.timer = setTimeout(rapidChange, 300);
},
stopRapidChange: function(e) {
clearTimeout(this.timer);

if (this.valueChangedFlag) {
this.valueChanged();
this.valueChangedFlag = false;
}
}
};


/**
* @author Radek Šerý
*
* Inicializace .inp-number elementů, dynamicky vytvoří tlačítka a naváže eventy
*/
$.nette.ext('inpNumber', {
init: function() {
var snippetsExt = this.ext('snippets', true);
var ext = this;

snippetsExt.after(function($el) {
ext.init.call(ext, $el);
});

this.init($(document));
}
}, {
selector: '.inp-number',

init: function($el) {
var ext = this;

$el
.find(this.selector)
.each(function() {
var inpNumber = new InpNumber(this);
});
}
});

})(jQuery);
55 changes: 55 additions & 0 deletions extensions/pd/replaceState.ajax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
(function($, undefined) {

// Is History API reliably supported? (based on Modernizr & PJAX)
if (!(window.history && history.pushState && window.history.replaceState)) {
return;
}

/**
* @author Radek Šerý
*
* Extension pro AJAXové odkazy, které mění url, ale v historii nahrazují stávající state, tj. v historii se projeví
* pouze poslední request. Použito např. pro odkazy na varianty produktu - lze sdílet vždy aktuální variantu, ale
* klik na zpět vrací na výpis a ne na všechny proklikané varianty.
*/
$.nette.pd.ext('replaceState', {
init: function() {
this.historyExt = $.nette.ext('history');
this.snippetsExt = $.nette.ext('snippets');
},
before: function (xhr, settings) {
if (! settings.nette) {
this.href = null;
} else if (! settings.nette.form) {
this.href = settings.nette.ui.href;
} else if (settings.nette.form.get(0).method === 'get') {
this.href = settings.nette.form.get(0).action || window.location.href;
} else {
this.href = null;
}
},
success: function(payload) {
var redirect = payload.redirect || payload.url; // backwards compatibility for 'url'
if (redirect) {
var regexp = new RegExp('//' + window.location.host + '($|/)');
if ((redirect.substring(0,4) === 'http') ? regexp.test(redirect) : true) {
this.href = redirect;
} else {
window.location.href = redirect;
}
}

if (this.href && this.href !== window.location.href) {
history.replaceState({
nette: true,
href: this.href,
title: document.title,
ui: (this.historyExt && this.historyExt.cache && this.snippetsExt) ? this.snippetsExt.findSnippets() : null
}, document.title, this.href);
}

this.href = null;
}
});

})(jQuery);
Loading

0 comments on commit 62daacf

Please sign in to comment.