153 lines
5.4 KiB
Plaintext
153 lines
5.4 KiB
Plaintext
<div class="w-annc widget-announcement-16">
|
|
|
|
<h2 class="w-annc__widget-title">
|
|
<span>{{widget-title}}</span>
|
|
</h2>
|
|
|
|
<div class="slide-button">
|
|
<button class="cycle-prev btn btn-warning" title="上一張" aria-label="上一張"> <i class="fa fa-angle-left"></i></button>
|
|
<button class="cycle-next btn btn-warning" title="下一張" aria-label="下一張"> <i class="fa fa-angle-right"></i></button>
|
|
<a class="w-annc__more btn btn-primary pull-right" href="{{more_url}}"><%= (I18n.locale.to_s =="zh_tw") ? "更多+" : "More NEWS" %></a>
|
|
</div>
|
|
|
|
<div class="w-annc__wrap "
|
|
data-level="0"
|
|
data-list="announcements"
|
|
>
|
|
|
|
<div class="w-annc__item">
|
|
<div class="w-annc__img-wrap">
|
|
<img class="w-annc__img" src="{{img_src}}" alt="{{img_description}}" title="{{img_description}}">
|
|
</div>
|
|
<div class="w-annc__content-wrap">
|
|
<div class="w-annc__meta">
|
|
<span class="w-annc__status-wrap" data-list="statuses" data-level="1">
|
|
<span class="w-annc__status label {{status-class}}">{{status}}</span>
|
|
</span>
|
|
<span class="w-annc__postdate-wrap" date-format="%Y-%m-%d">
|
|
<span class="w-annc__postdate">{{postdate}}</span>
|
|
</span>
|
|
</div>
|
|
<h3 class="w-annc__entry-title">
|
|
<a class="w-annc__title" href="{{link_to_show}}">{{title}}</a>
|
|
</h3>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
$(function(){
|
|
// initialize all widgets (scoped)
|
|
$('.w-annc').each(function(){
|
|
var $widget = $(this);
|
|
var $wrap = $widget.find('.w-annc__wrap').first();
|
|
if (!$wrap.length) return;
|
|
|
|
// prepare markup: add class, create track and move slides in
|
|
$wrap.addClass('custom-carousel');
|
|
var $items = $wrap.children('.w-annc__item');
|
|
if ($items.length <= 1) {
|
|
// nothing to carousel
|
|
$items.attr('aria-hidden', 'false');
|
|
return;
|
|
}
|
|
|
|
// create track and move items into it
|
|
var $track = $('<div class="w-annc__track" aria-live="polite"></div>');
|
|
$items.each(function(){
|
|
// ensure each item is block-level and has aria-hidden
|
|
$(this).attr('aria-hidden', 'true').appendTo($track);
|
|
});
|
|
$wrap.empty().append($track);
|
|
|
|
var count = $track.children('.w-annc__item').length;
|
|
var idx = 0;
|
|
var animating = false;
|
|
|
|
// controls - scoped in widget
|
|
var $prev = $widget.find('.cycle-prev').first();
|
|
var $next = $widget.find('.cycle-next').first();
|
|
|
|
// optional pager
|
|
var $pager = $('<div class="w-annc__pager" aria-hidden="true"></div>');
|
|
for (var i=0;i<count;i++){
|
|
var $btn = $('<button type="button" aria-label="第 '+(i+1)+' 則"></button>');
|
|
(function(i, $b){ $b.on('click', function(){ goTo(i, true); }); }) (i, $btn);
|
|
$pager.append($btn);
|
|
}
|
|
$widget.append($pager);
|
|
|
|
function updateUI(){
|
|
// transform track
|
|
$track.css('transform', 'translateX(-' + (idx * 100) + '%)');
|
|
// aria-hidden mark
|
|
$track.children('.w-annc__item').each(function(i){
|
|
$(this).attr('aria-hidden', i===idx? 'false' : 'true');
|
|
});
|
|
// pager active
|
|
$pager.find('button').removeClass('active').attr('aria-pressed','false');
|
|
$pager.find('button').eq(idx).addClass('active').attr('aria-pressed','true');
|
|
}
|
|
|
|
function goTo(i, animate){
|
|
if (animating) return;
|
|
i = (i + count) % count; // wrap
|
|
if (i === idx) return;
|
|
animating = true;
|
|
idx = i;
|
|
updateUI();
|
|
// allow transition to finish
|
|
setTimeout(function(){ animating = false; }, 360);
|
|
}
|
|
|
|
// prev/next handlers (stopPropagation to avoid other handlers)
|
|
$prev.on('click', function(e){ e.preventDefault(); e.stopPropagation(); goTo(idx - 1, true); });
|
|
$next.on('click', function(e){ e.preventDefault(); e.stopPropagation(); goTo(idx + 1, true); });
|
|
|
|
// keyboard support when widget focused
|
|
$widget.attr('tabindex', -1).on('keydown', function(e){
|
|
if (e.key === 'ArrowLeft') { e.preventDefault(); goTo(idx - 1, true); }
|
|
if (e.key === 'ArrowRight') { e.preventDefault(); goTo(idx + 1, true); }
|
|
});
|
|
|
|
// touch / swipe support
|
|
(function(){
|
|
var startX = null, startY = null, distX = 0, isTouch = false;
|
|
var threshold = 30; // required min px for swipe
|
|
$wrap.on('touchstart mousedown', function(e){
|
|
var ev = e.originalEvent.touches ? e.originalEvent.touches[0] : e;
|
|
startX = ev.clientX; startY = ev.clientY; distX = 0; isTouch = true;
|
|
});
|
|
$wrap.on('touchmove mousemove', function(e){
|
|
if (!isTouch || startX === null) return;
|
|
var ev = e.originalEvent.touches ? e.originalEvent.touches[0] : e;
|
|
distX = ev.clientX - startX;
|
|
});
|
|
$wrap.on('touchend mouseup mouseleave', function(e){
|
|
if (!isTouch) return;
|
|
isTouch = false;
|
|
if (Math.abs(distX) > threshold) {
|
|
if (distX < 0) { // swipe left -> next
|
|
goTo(idx + 1, true);
|
|
} else { // swipe right -> prev
|
|
goTo(idx - 1, true);
|
|
}
|
|
}
|
|
startX = null; distX = 0;
|
|
});
|
|
})();
|
|
|
|
// pause-on-hover (if you add autoplay later)
|
|
$wrap.on('mouseenter', function(){ /* placeholder if needed */ });
|
|
$wrap.on('mouseleave', function(){ /* placeholder if needed */ });
|
|
|
|
// initial UI
|
|
updateUI();
|
|
|
|
// ensure images responsive inside
|
|
$track.find('img').css({ 'max-width': '100%', 'height': 'auto', 'display': 'block' });
|
|
});
|
|
});
|
|
|
|
|
|
</script> |