Skip to content

Commit

Permalink
extended trim extra support to all the *_js helpers:
Browse files Browse the repository at this point in the history
- refactored trim extra
- simplified MARK strings
- use of RegExp patterns in pagy.js
- added and improved tests
  • Loading branch information
ddnexus committed May 10, 2019
1 parent 29a6876 commit 96ad00f
Show file tree
Hide file tree
Showing 21 changed files with 183 additions and 227 deletions.
42 changes: 22 additions & 20 deletions lib/javascripts/pagy.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ Pagy.init = function(arg){
}
};

Pagy.nav = function(id, tags, sequels){
Pagy.nav = function(id, tags, sequels, param){
var pagyEl = document.getElementById(id),
container = pagyEl.parentElement,
lastWidth = undefined,
timeoutId = 0,
markRE = new RegExp('--pagy.page--', 'g'),
pageREg = new RegExp(/__pagy_page__/g),
widths = [];
for (var width in sequels) { widths.push(parseInt(width)) } // fine with sequels structure
widths.sort(function(a, b){return b-a});
Expand All @@ -28,17 +28,18 @@ Pagy.nav = function(id, tags, sequels){
if (container.clientWidth > widths[i]) { width = widths[i]; break }
}
if (width !== lastWidth) {
while (pagyEl.firstChild) { pagyEl.removeChild(pagyEl.firstChild) }
var html = tags.before,
series = sequels[width];
for (i = 0, len = series.length; i < len; i++) {
var item = series[i];
if (typeof(item) === 'number') { html += tags.link.replace(markRE, item) }
else if (item === 'gap') { html += tags.gap }
else if (typeof(item) === 'string') { html += tags.active.replace(markRE, item) }
if (typeof(param) === 'string' && item === 1) { html += Pagy.trim(tags.link.replace(pageREg, item), param) }
else if (typeof(item) === 'number') { html += tags.link.replace(pageREg, item) }
else if (item === 'gap') { html += tags.gap }
else if (typeof(item) === 'string') { html += tags.active.replace(pageREg, item) }
}
html += tags.after;
pagyEl.insertAdjacentHTML('beforeend', html);
pagyEl.innerHTML = '';
pagyEl.insertAdjacentHTML('afterbegin', html);
lastWidth = width;
}
},
Expand All @@ -54,35 +55,31 @@ Pagy.nav = function(id, tags, sequels){
render();
};

Pagy.combo_nav = function(id, page, links){
Pagy.combo_nav = function(id, page, link, param){
var pagyEl = document.getElementById(id),
input = pagyEl.getElementsByTagName('input')[0],
go = function(){
if (page !== input.value) {
if (links.hasOwnProperty('trimmed') && input.value === '1') {
pagyEl.insertAdjacentHTML('afterbegin', links.trimmed);
} else {
pagyEl.insertAdjacentHTML('afterbegin', links.standard.replace('--pagy.page--', input.value));
}
var html = link.replace(/__pagy_page__/, input.value);
if (typeof(param) === 'string' && input.value === '1') { html = Pagy.trim(html, param) }
pagyEl.insertAdjacentHTML('afterbegin', html);
pagyEl.getElementsByTagName('a')[0].click();
}
};
Pagy.addInputEventListeners(input, go);
};

Pagy.items_selector = function(id, from, links){
Pagy.items_selector = function(id, from, link, param){
var pagyEl = document.getElementById(id),
input = pagyEl.getElementsByTagName('input')[0],
current = input.value,
go = function(){
var items = input.value;
if (current !== items) {
var page = Math.max(Math.ceil(from / items),1);
if (links.hasOwnProperty('trimmed') && page === 1) {
pagyEl.insertAdjacentHTML('afterbegin', links.trimmed.replace('--pagy.items--', items));
} else {
pagyEl.insertAdjacentHTML('afterbegin', links.standard.replace('--pagy.page--', page).replace('--pagy.items--', items));
}
var page = Math.max(Math.ceil(from / items),1),
html = link.replace(/__pagy_page__/, page).replace(/__pagy_items__/, items);
if (typeof(param) === 'string' && page === 1){ html = Pagy.trim(html, param) }
pagyEl.insertAdjacentHTML('afterbegin', html);
pagyEl.getElementsByTagName('a')[0].click();
}
};
Expand All @@ -99,3 +96,8 @@ Pagy.addInputEventListeners = function(input, handler){
// … and when pressing enter inside the input
input.addEventListener('keyup', function(e){ if (e.which === 13) handler() }.bind(this));
};

Pagy.trim = function(html, param){
var re = new RegExp('[?&]' + param + '=1(?![&])|(?<=[?&])' + param + '=1&');
return html.replace(re, '');
};
4 changes: 2 additions & 2 deletions lib/pagy/extras/bootstrap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def pagy_bootstrap_nav_js(pagy, id=pagy_id)
'gap' => %(<li class="page-item gap disabled"><a href="#" class="page-link">#{pagy_t('pagy.nav.gap')}</a></li>),
'after' => p_next ? %(<li class="page-item next">#{link.call p_next, pagy_t('pagy.nav.next'), 'aria-label="next"'}</li></ul>)
: %(<li class="page-item next disabled"><a href="#" class="page-link">#{pagy_t('pagy.nav.next')}</a></li></ul>) }
%(<nav id="#{id}" class="pagy-bootstrap-nav-js pagination" role="navigation" aria-label="pager"></nav>#{pagy_json_tag(:nav, id, tags, pagy.sequels)})
%(<nav id="#{id}" class="pagy-bootstrap-nav-js pagination" role="navigation" aria-label="pager"></nav>#{pagy_json_tag(:nav, id, tags, pagy.sequels, defined?(TRIM) && pagy.vars[:page_param])})
end

# Javascript combo pagination for bootstrap: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
Expand All @@ -48,7 +48,7 @@ def pagy_bootstrap_combo_nav_js(pagy, id=pagy_id)
html << %(<div class="pagy-combo-input btn btn-primary disabled" style="white-space: nowrap;">#{pagy_t('pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages)}</div>)
html << (p_next ? link.call(p_next, pagy_t('pagy.nav.next'), 'aria-label="next" class="next btn btn-primary"')
: %(<a class="next btn btn-primary disabled" href="#">#{pagy_t('pagy.nav.next')}</a>))
html << %(</div></nav>#{pagy_json_tag(:combo_nav, id, p_page, pagy_links(link))})
html << %(</div></nav>#{pagy_json_tag(:combo_nav, id, p_page, pagy_marked_link(link), defined?(TRIM) && pagy.vars[:page_param])})
end

end
Expand Down
4 changes: 2 additions & 2 deletions lib/pagy/extras/bulma.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def pagy_bulma_nav_js(pagy, id=pagy_id)
'active' => %(<li>#{link.call(MARK, MARK, %(class="pagination-link is-current" aria-current="page" aria-label="page #{MARK}"))}</li>),
'gap' => %(<li><span class="pagination-ellipsis">#{pagy_t('pagy.nav.gap')}</span></li>),
'after' => '</ul>' }
%(<nav id="#{id}" class="pagy-bulma-nav-js pagination is-centered" role="navigation" aria-label="pagination"></nav>#{pagy_json_tag(:nav, id, tags, pagy.sequels)})
%(<nav id="#{id}" class="pagy-bulma-nav-js pagination is-centered" role="navigation" aria-label="pagination"></nav>#{pagy_json_tag(:nav, id, tags, pagy.sequels, defined?(TRIM) && pagy.vars[:page_param])})
end

# Javascript combo pagination for Bulma: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
Expand All @@ -53,7 +53,7 @@ def pagy_bulma_combo_nav_js(pagy, id=pagy_id)
html << %(<div class="pagy-combo-input control level is-mobile">#{pagy_t('pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages)}</div>)
html << (p_next ? %(<p class="control">#{link.call(p_next, pagy_t('pagy.nav.next'), 'class="button" aria-label="next page"')}</p>)
: %(<p class="control"><a class="button" disabled>#{pagy_t('pagy.nav.next')}</a></p>))
html << %(</div></nav>#{pagy_json_tag(:combo_nav, id, p_page, pagy_links(link))})
html << %(</div></nav>#{pagy_json_tag(:combo_nav, id, p_page, pagy_marked_link(link), defined?(TRIM) && pagy.vars[:page_param])})
end

end
Expand Down
4 changes: 2 additions & 2 deletions lib/pagy/extras/foundation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def pagy_foundation_nav_js(pagy, id=pagy_id)
'after' => ( (p_next ? %(<li class="next">#{link.call(p_next, pagy_t('pagy.nav.next'), 'aria-label="next"')}</li>)
: %(<li class="next disabled">#{pagy_t('pagy.nav.next')}</li>)) \
+ '</ul>' ) }
%(<nav id="#{id}" class="pagy-foundation-nav-js" role="navigation" aria-label="Pagination"></nav>#{pagy_json_tag(:nav, id, tags, pagy.sequels)})
%(<nav id="#{id}" class="pagy-foundation-nav-js" role="navigation" aria-label="Pagination"></nav>#{pagy_json_tag(:nav, id, tags, pagy.sequels, defined?(TRIM) && pagy.vars[:page_param])})
end

# Javascript combo pagination for Foundation: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
Expand All @@ -50,7 +50,7 @@ def pagy_foundation_combo_nav_js(pagy, id=pagy_id)
html << %(<span class="input-group-label">#{pagy_t('pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages)}</span>)
html << (p_next ? link.call(p_next, pagy_t('pagy.nav.next'), 'style="margin-bottom: 0px;" aria-label="next" class="next button primary"')
: %(<a style="margin-bottom: 0px;" class="next button primary disabled" href="#">#{pagy_t('pagy.nav.next')}</a>))
html << %(</div></nav>#{pagy_json_tag(:combo_nav, id, p_page, pagy_links(link))})
html << %(</div></nav>#{pagy_json_tag(:combo_nav, id, p_page, pagy_marked_link(link), defined?(TRIM) && pagy.vars[:page_param])})
end

end
Expand Down
6 changes: 3 additions & 3 deletions lib/pagy/extras/items.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ def pagy_url_for_with_items(page, pagy, url=false)
def pagy_items_selector_js(pagy, id=pagy_id)
p_vars = pagy.vars
p_items = p_vars[:items]
p_vars[:items] = '--pagy.items--'
links = pagy_links(pagy_link_proc(pagy))
p_vars[:items] = '__pagy_items__'
link = pagy_marked_link(pagy_link_proc(pagy))
p_vars[:items] = p_items # restore the items

html = EMPTY + %(<span id="#{id}">)
input = %(<input type="number" min="1" max="#{p_vars[:max_items]}" value="#{p_items}" style="padding: 0; text-align: center; width: #{p_items.to_s.length+1}rem;">)
html << %(#{pagy_t('pagy.items_selector_js', item_name: pagy_t(p_vars[:i18n_key], count: p_items), items_input: input, count: p_items)})
html << %(</span>#{pagy_json_tag(:items_selector, id, pagy.from, links)})
html << %(</span>#{pagy_json_tag(:items_selector, id, pagy.from, link, defined?(TRIM) && p_vars[:page_param])})
end

end
Expand Down
4 changes: 2 additions & 2 deletions lib/pagy/extras/materialize.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def pagy_materialize_nav_js(pagy, id=pagy_id)
'after' => ( (p_next ? %(<li class="waves-effect next">#{link.call(p_next, '<i class="material-icons">chevron_right</i>', 'aria-label="next"')}</li>)
: %(<li class="next disabled"><a href="#"><i class="material-icons">chevron_right</i></a></li>)) \
+ '</ul>' ) }
%(<div id="#{id}" class="pagy-materialize-nav-js" role="navigation" aria-label="pager"></div>#{pagy_json_tag(:nav, id, tags, pagy.sequels)})
%(<div id="#{id}" class="pagy-materialize-nav-js" role="navigation" aria-label="pager"></div>#{pagy_json_tag(:nav, id, tags, pagy.sequels, defined?(TRIM) && pagy.vars[:page_param])})
end

# Javascript combo pagination for materialize: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
Expand All @@ -52,7 +52,7 @@ def pagy_materialize_combo_nav_js(pagy, id=pagy_id)
html << %(<div class="pagy-combo-input btn-flat" style="cursor: default; padding: 0px">#{pagy_t('pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages)}</div>)
html << (p_next ? %(<li class="waves-effect next" #{li_style}>#{link.call p_next, '<i class="material-icons">chevron_right</i>', 'aria-label="next"'}</li>)
: %(<li class="next disabled" #{li_style}><a href="#"><i class="material-icons">chevron_right</i></a></li>))
html << %(</ul></div>#{pagy_json_tag(:combo_nav, id, p_page, pagy_links(link))})
html << %(</ul></div>#{pagy_json_tag(:combo_nav, id, p_page, pagy_marked_link(link), defined?(TRIM) && pagy.vars[:page_param])})
end

end
Expand Down
4 changes: 2 additions & 2 deletions lib/pagy/extras/navs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def pagy_nav_js(pagy, id=pagy_id)
'gap' => %(<span class="page gap">#{pagy_t('pagy.nav.gap')}</span> ),
'after' => p_next ? %(<span class="page next">#{link.call p_next, pagy_t('pagy.nav.next'), 'aria-label="next"'}</span>)
: %(<span class="page next disabled">#{pagy_t('pagy.nav.next')}</span>) }
%(<nav id="#{id}" class="pagy-nav-js pagination" role="navigation" aria-label="pager"></nav>#{pagy_json_tag(:nav, id, tags, pagy.sequels)})
%(<nav id="#{id}" class="pagy-nav-js pagination" role="navigation" aria-label="pager"></nav>#{pagy_json_tag(:nav, id, tags, pagy.sequels, defined?(TRIM) && pagy.vars[:page_param])})
end

# Javascript combo pagination: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
Expand All @@ -31,7 +31,7 @@ def pagy_combo_nav_js(pagy, id=pagy_id)
html << %(<span class="pagy-combo-input" style="margin: 0 0.6rem;">#{pagy_t('pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages)}</span> )
html << (p_next ? %(<span class="page next">#{link.call p_next, pagy_t('pagy.nav.next'), 'aria-label="next"'}</span>)
: %(<span class="page next disabled">#{pagy_t('pagy.nav.next')}</span>))
html << %(</nav>#{pagy_json_tag(:combo_nav, id, p_page, pagy_links(link))})
html << %(</nav>#{pagy_json_tag(:combo_nav, id, p_page, pagy_marked_link(link), defined?(TRIM) && pagy.vars[:page_param])})
end

end
Expand Down
4 changes: 2 additions & 2 deletions lib/pagy/extras/semantic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def pagy_semantic_nav_js(pagy, id=pagy_id)
'gap' => %(<div class="disabled item">#{pagy_t('pagy.nav.gap')}</div>),
'after' => (p_next ? %(#{link.call(p_next, '<i class="right small chevron icon"></i>', 'aria-label="next"')})
: %(<div class="item disabled"><i class="right small chevron icon"></i></div>)) }
%(<div id="#{id}" class="pagy-semantic-nav-js ui pagination menu" role="navigation" aria-label="pager"></div>#{pagy_json_tag(:nav, id, tags, pagy.sequels)})
%(<div id="#{id}" class="pagy-semantic-nav-js ui pagination menu" role="navigation" aria-label="pager"></div>#{pagy_json_tag(:nav, id, tags, pagy.sequels, defined?(TRIM) && pagy.vars[:page_param])})
end

# Combo pagination for semantic: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
Expand All @@ -48,7 +48,7 @@ def pagy_semantic_combo_nav_js(pagy, id=pagy_id)
html << %(<div class="pagy-combo-input item">#{pagy_t('pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages)}</div> )
html << (p_next ? %(#{link.call p_next, '<i class="right small chevron icon"></i>', 'aria-label="next"'})
: %(<div class="item disabled"><i class="right small chevron icon"></i></div>))
html << %(</div>#{pagy_json_tag(:combo_nav, id, p_page, pagy_links(link))})
html << %(</div>#{pagy_json_tag(:combo_nav, id, p_page, pagy_marked_link(link), defined?(TRIM) && pagy.vars[:page_param])})
end

end
Expand Down
8 changes: 3 additions & 5 deletions lib/pagy/extras/shared.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,9 @@ def pagy_id
"pagy-#{Digest::SHA1.hexdigest(caller(2..2)[0].split(':in')[0])}"
end

# it return the links hash to used by pagy.js
def pagy_links(link)
links = { 'standard' => link.call(MARK, '', 'style="display: none;"') }
links['trimmed'] = link.call(1, '', 'style="display: none;"') if defined?(TRIM)
links
# it returns the marked link to used by pagy.js
def pagy_marked_link(link)
link.call(MARK, '', 'style="display: none;"')
end

end
Expand Down
25 changes: 7 additions & 18 deletions lib/pagy/extras/trim.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,18 @@ class Pagy

module Frontend

# boolean used by the compact navs
TRIM = true
TRIM = true # boolean used by *_js helpers

alias_method :pagy_link_proc_without_trim, :pagy_link_proc
def pagy_link_proc_with_trim(pagy, link_extra='')
p_prev, p_next, p_vars = pagy.prev, pagy.next, pagy.vars
marked_url = pagy_url_for(MARK, pagy)
page1_url = pagy_trim_url(marked_url, "#{p_vars[:page_param]}=#{MARK}")
page1_link = %(<a href="#{page1_url}" #{p_vars[:link_extra]} #{link_extra})
a, b = %(<a href="#{marked_url}" #{p_vars[:link_extra]} #{link_extra}).split(MARK, 2)
lambda{|n, text=n, extra=''| start = n.to_i == 1 ? page1_link : "#{a}#{n}#{b}"
"#{start}#{ if n == p_prev ; ' rel="prev"'
elsif n == p_next ; ' rel="next"'
else '' end } #{extra}>#{text}</a>"}
link_proc = pagy_link_proc_without_trim(pagy, link_extra)
page_param = pagy.vars[:page_param]
lambda do |n, text=n, extra=''|
link = link_proc.call(n, text, extra)
n == 1 ? link.sub(/[?&]#{page_param}=1(?![&])|\b(?<=[?&])#{page_param}=1&/, '') : link
end
end
alias_method :pagy_link_proc, :pagy_link_proc_with_trim

private

# separate method easier to test
def pagy_trim_url(url, param_string)
url.sub(/((?:[?&])#{param_string}\z|\b(?<=[?&])#{param_string}&)/, '')
end

end
end
2 changes: 1 addition & 1 deletion lib/pagy/frontend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module Frontend
include Helpers

EMPTY = '' # EMPTY + 'string' is almost as fast as +'string' but is also 1.9 compatible
MARK = '--pagy.page--' # string used for search and replace, hardcoded also in the pagy.js file
MARK = '__pagy_page__' # string used for search and replace, hardcoded also in the pagy.js file

# Generic pagination: it returns the html with the series of links to the pages
def pagy_nav(pagy)
Expand Down
Loading

0 comments on commit 96ad00f

Please sign in to comment.