Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,231 @@
'use strict';
var utils = window.utils || {};
if (!utils.alphaScroll) {
(function initScrollbar(doc) {
var alphaScroll = utils.alphaScroll = {};
var scrollToCallback, jumper, overlay,
overlayStyle, groupSelector, liSearch, liFavorites;
var isScrolling = false;
var alreadyRendered = false;
var isDesktop = false;
// Callback invoked when scrolling is neded
var P_SCROLLTO_CB = 'scrollToCb';
// Element that represents the alpha scroll bar
var P_JUMPER = 'jumper';
// Element that shows the current letter
var P_OVERLAY = 'overlay';
// Selector that will allow to get the group that should be scrolled to
// Group will be identified by this selector plus the corresponding letter
var P_GROUP_SELECTOR = 'groupSelector';
var TRANSITION_DELAY = '0.3s';
var TRANSITION_DURATION = '0.2s';
var RESET_TRANSITION = '0s';
var offset = 0, lastY = 0;
var isTouch = 'ontouchstart' in window;
var touchstart = isTouch ? 'touchstart' : 'mousedown';
var touchmove = isTouch ? 'touchmove' : 'mousemove';
var touchend = isTouch ? 'touchend' : 'mouseup';
var getY = (function getYWrapper() {
return isTouch ? function(e) { return e.touches[0].pageY; } :
function(e) { return e.pageY; };
})();
var getTarget = (function getTargetWrapper() {
if (isTouch) {
return function(e) {
var touch = e.touches[0];
return document.elementFromPoint(touch.pageX, touch.pageY);
};
} else {
return function(e) {
return e.target;
};
}
})();
alphaScroll.init = function(params, desktop) {
isDesktop = params && params.desktop;
if (alreadyRendered && !isDesktop) {
return;
}
scrollToCallback = params[P_SCROLLTO_CB];
jumper = params[P_JUMPER];
overlay = params[P_OVERLAY];
groupSelector = params[P_GROUP_SELECTOR];
overlay.textContent = '';
overlayStyle = overlay.style;
jumper.addEventListener(touchstart, scrollStart);
jumper.addEventListener(touchmove, scrollTo);
jumper.addEventListener(touchend, scrollEnd);
// Determine if the content for this scrollbar is statically defined
// in the index.html. If there are no templates, then do not attempt
// to render it.
if (typeof jumper === 'string') {
jumper = document.querySelector(jumper);
}
var template = jumper.querySelector('*[data-template]');
if (!template) {
alreadyRendered = true;
return;
}
// Otherwise render the content via templating.
var frag = document.createDocumentFragment();
var alphabet = [];
for (var i = 65; i <= 90; i++) {
alphabet.push({ anchor: String.fromCharCode(i) });
}
alphabet.push({
anchor: '#'
});
utils.templates.append(jumper, alphabet, frag);
jumper.appendChild(frag);
alreadyRendered = true;
};
// Provide a mechanism to hide/show groups at will
alphaScroll.showGroup = function(name) {
var selector = '[data-anchor="group-'+ name + '"]';
var group = jumper.querySelector(selector);
if (group) {
group.classList.remove('hide');
}
};
alphaScroll.hideGroup = function(name) {
var selector = '[data-anchor="group-'+ name + '"]';
var group = jumper.querySelector(selector);
if (group) {
group.classList.add('hide');
}
};
function hideExtraItems(value) {
if (!liSearch) {
liSearch = jumper.querySelector('li[data-anchor="search-container"]');
}
if (!liFavorites) {
liFavorites = jumper.querySelector('li[data-anchor="group-favorites"]');
}
liSearch.hidden = value;
liFavorites.hidden = value;
}
alphaScroll.toggleFormat = function(type) {
hideExtraItems(type === 'short');
};
function scrollTo(evt) {
evt.preventDefault();
evt.stopPropagation();
if (!isScrolling) {
return;
}
var currentY = getY(evt);
// We set the threshold of updating the shortcut to half of the offset
// to avoid when touch already moved to center of the certain letter but
// shows another letter.
if (Math.abs(lastY - currentY) < offset / 2 && !isDesktop) {
return;
}
lastY = currentY;
var elem = getTarget(evt);
if (!elem) {
return;
}
var dataset = elem.dataset;
// Render
if (dataset.letter) {
overlay.textContent = dataset.letter;
} else if (dataset.img) {
overlay.textContent = '';
var img = new Image();
img.src = 'style/images/' + dataset.img;
overlay.appendChild(img);
}
// The headers are sticky, and can have wrong offsetTop,
// so scroll to the top of each section on jump click.
var anch = dataset.anchor;
var selector = anch === 'group-#' ? 'group-und' : anch;
var domTarget = doc.querySelector('#section-' + selector +
', #' + selector);
if (!domTarget) {
return;
}
scrollToCallback(domTarget, selector.replace('group-', ''));
}
function scrollStart(evt) {
var dataset = getTarget(evt).dataset;
evt.preventDefault();
evt.stopPropagation();
// There is no need to show overlay if the target doesn't contain
// any valid data for overlay block.
if (!dataset.letter && !dataset.img) {
return;
}
offset = offset || jumper.querySelector('[data-anchor]').offsetHeight;
overlayStyle.MozTransitionDelay = RESET_TRANSITION;
overlayStyle.MozTransitionDuration = RESET_TRANSITION;
overlayStyle.opacity = '1';
isScrolling = true;
scrollTo(evt);
}
function scrollEnd(evt) {
evt.preventDefault();
evt.stopPropagation();
var transitionDelay = TRANSITION_DELAY;
var transitionDuration = TRANSITION_DURATION;
// In the case of the scroll ending when we are at the
// bottom or the top, remove the transition inmediately
if (overlay.textContent === '#' || overlay.textContent === '') {
transitionDelay = RESET_TRANSITION;
transitionDuration = RESET_TRANSITION;
}
overlayStyle.MozTransitionDelay = transitionDelay;
overlayStyle.MozTransitionDuration = transitionDuration;
overlayStyle.opacity = '0';
overlay.textContent = null;
isScrolling = false;
lastY = 0;
}
// Cache images refered in 'data-img'es
(function(doc) {
var images = doc.querySelectorAll('li[data-img]');
Object.keys(images).forEach(function(value) {
var img = new Image();
img.src = 'contacts/style/images/' + images[value].dataset.img;
});
}(doc));
})(document);
}