bugfix for safari, searchresults

This commit is contained in:
woutervanwijk 2013-12-02 12:32:17 +01:00
parent ad09970695
commit a3d4cddcb1
10 changed files with 1485 additions and 157 deletions

View File

@ -316,13 +316,13 @@
.currenttrack2 {
background-image: url('../images/icons/play_alt_12x12.png');
background-repeat: no-repeat;
background-position: 4px center;
background-position: 4px 51%;
}
.currenttrack {
background-image: url('../images/icons/play_alt_16x16.png');
background-repeat: no-repeat;
background-color: #eee;
background-position: 6px center;
background-position: 4px 50%;
}
.currenttrack2 a {
@ -584,10 +584,18 @@ a {
}
/* disable text selection for mouse swipe */
body * {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
/* but fix for text input (safari certainly needs it)*/
input[type=text] {
-moz-user-select: text;
-webkit-user-select: text;
-o-user-select: text;
user-select: text;
}

View File

@ -264,8 +264,10 @@ function setRandom(nwrandom) {
function doRandom() {
if (random == false) {
//mopidy.tracklist.setRandom(true).then();
mopidy.playback.setRandom(true).then();
} else {
//mopidy.tracklist.setRandom(false).then();
mopidy.playback.setRandom(false).then();
}
setRandom(!random);
@ -273,8 +275,10 @@ function doRandom() {
function doRepeat() {
if (repeat == false) {
//mopidy.tracklist.setRepeat(true).then();
mopidy.playback.setRepeat(true).then();
} else {
//mopidy.tracklist.setRepeat(false).then();
mopidy.playback.setRepeat(false).then();
}
setRepeat(!repeat);

View File

@ -135,7 +135,7 @@ function albumTracksToTable(pl, target, uri) {
for (var i = 0; i < pl.length; i++) {
popupData[pl[i].uri] = pl[i];
liID = targetmin + '-' + pl[i].uri;
tmp += renderSongLi(pl[i], liID, uri, target);
tmp += renderSongLi(pl[i], liID, uri, 'playTrackByUri');
//child = '<li id="' + targetmin + '-' + pl[i].uri + '"><a href="#" onclick="return popupTracks(event, \'' + uri + '\',\'' + pl[i].uri + '\');">';
// child += '<p style="float:right; display: inline;">' + timeFromSeconds(pl[i].length / 1000) + '</p><h1>' + pl[i].name + '</h1></a></li>';

View File

@ -380,6 +380,9 @@ function updateStatusOfAll() {
mopidy.playback.getTimePosition().then(processCurrentposition, console.error);
mopidy.playback.getState().then(processPlaystate, console.error);
// mopidy.tracklist.getRepeat().then(processRepeat, console.error);
// mopidy.tracklist.getRandom().then(processRandom, console.error);
mopidy.playback.getRepeat().then(processRepeat, console.error);
mopidy.playback.getRandom().then(processRandom, console.error);
@ -484,6 +487,7 @@ $(document).ready(function(event) {
switchContent("playlists");
}
initgui = false;
window.onhashchange = locationHashChanged;
// Log all events
@ -571,4 +575,15 @@ $(document).ready(function(event) {
$("#panel").panel("close");
event.stopImmediatePropagation(); }
} );
//mopidy.on("state:online", debug);
});
function debug() {
if (mopidy.tracklist === undefined) {
alert('Broke at ' + new Date());
} else {
setTimeout(debug, 100);
}
}

View File

@ -46,7 +46,7 @@ function processSearchResults(resultArr) {
var results = {'tracks': [], 'artists': [], 'albums': []};
var emptyResult = true;
console.log(resultArr, 'resultArr');
// console.log(resultArr, 'resultArr');
for (var i = 0; i < resultArr.length; ++i) {
for (var prop in results) {
@ -134,7 +134,8 @@ function processSearchResults(resultArr) {
$('#expandsearch').show();
// Track results
playlisttotable(results.tracks, SEARCH_TRACK_TABLE, 'trackresultscache');
// playlisttotable(results.tracks, SEARCH_TRACK_TABLE, 'trackresultscache');
resultsToTables(results.tracks, SEARCH_TRACK_TABLE, 'trackresultscache');
setSongInfo();
showLoading(false);

0
webclient/css/jquery.mobile.iscrollview.css Executable file → Normal file
View File

View File

@ -1,17 +1,18 @@
/********************************************************
* play an uri from a tracklist
* play an uri from a tracklist
*********************************************************/
function playTrack(addtoqueue) {
//stop directly, for user feedback
if (!addtoqueue) {
mopidy.playback.stop(true);
mopidy.tracklist.clear();
mopidy.tracklist.clear();
}
$('#popupTracks').popup('close');
$('#controlspopup').popup('close');
toast('Loading...');
playlisturi = $('#popupTracks').data("list");
uri = $('#popupTracks').data("track");
var trackslist = new Array();
@ -19,54 +20,44 @@ function playTrack(addtoqueue) {
var tracks = getTracksFromUri(playlisturi);
//find track that was selected
for (var selected = 0; selected < tracks.length; selected++) {
for (var selected = 0; selected < tracks.length; selected++) {
if (tracks[selected].uri == uri) {
break;
}
break;
}
}
//find track that is playing
for (var playing = 0; playing < currentplaylist.length; playing++) {
if (currentplaylist[playing].uri == songdata.uri) {
break;
}
break;
}
}
//switch popup options
switch (addtoqueue) {
case ADD_THIS_BOTTOM:
case ADD_THIS_BOTTOM:
mopidy.tracklist.add(tracks.slice(selected, selected + 1));
return false;
case PLAY_NEXT:
mopidy.tracklist.add(tracks.slice(selected, selected + 1), playing + 1);
return false;
case ADD_ALL_BOTTOM:
return false;
case PLAY_NEXT:
mopidy.tracklist.add(tracks.slice(selected, selected + 1), playing + 1);
return false;
case ADD_ALL_BOTTOM:
mopidy.tracklist.add(tracks);
return false;
return false;
}
mopidy.tracklist.add(tracks);
for (var i = 0; i <= selected; i++) {
mopidy.playback.next();
}
mopidy.playback.play();
// first add track to be played, then the other tracks
/*
// mopidy.tracklist.add(null, 0, playlisturi);
mopidy.tracklist.add( tracks.slice(selected, selected + 1) );
//wait .5 second before adding the rest to give server the time to start playing
setTimeout(function() {
mopidy.tracklist.add(tracks.slice(0, selected), 0);
if (selected < tracks.length) {
mopidy.tracklist.add(tracks.slice(selected + 1) );
}
}, 500);
// mopidy.tracklist.add(null, 0, playlisturi);
mopidy.tracklist.add(tracks); //.slice(selected, selected + 1) );
//wait 1.5 second before adding the rest to give server the time to start playing
/* setTimeout(function() {
mopidy.tracklist.add(tracks.slice(0, selected), 0);
if (selected < tracks.length) {
mopidy.tracklist.add(tracks.slice(selected + 1) );
}
}, 1500);
*/
// mopidy.playback.changeTrack(tracks[selected]);
for (var i = 0; i <= selected; i++) {
@ -74,23 +65,75 @@ function playTrack(addtoqueue) {
}
mopidy.playback.play(); //tracks[selected]);
*/
console.log(selected);
//console.log(selected);
return false;
}
/***
* Plays a Track given by an URI
* @param uri
* @returns {boolean}
*/
function playTrackByUri(uri, playlisturi){
//console.log('playuri');
//stop directly, for user feedback
mopidy.playback.stop(true);
mopidy.tracklist.clear();
//this is deprecated, remove when popuptracks is removed completly
$('#popupTracks').popup('close');
$('#controlspopup').popup('close');
//end of deprecated
toast('Loading...');
var trackslist = new Array();
var track, tracksbefore, tracksafter;
var tracks = getTracksFromUri(playlisturi);
//find track that was selected
for (var selected = 0; selected < tracks.length; selected++) {
if (tracks[selected].uri == uri) {
break;
}
}
//find track that is playing
for (var playing = 0; playing < currentplaylist.length; playing++) {
if (currentplaylist[playing].uri == songdata.uri) {
break;
}
}
mopidy.tracklist.add(tracks);
for (var i = 0; i <= selected; i++) {
mopidy.playback.next();
}
mopidy.playback.play(); //tracks[selected]);
// console.log(selected);
return false;
}
/********************************************************
* play an uri from the queue
*********************************************************/
function playTrackQueue() {
/***
* Plays a Track from a Playlist.
* @param uri
* @param playlisturi
* @returns {boolean}
*/
function playTrackQueueByUri(uri, playlisturi){
//console.log('playqu');
//stop directly, for user feedback
//console.log('qu');
mopidy.playback.stop(true);
$('#popupQueue').popup('close');
toast('Loading...');
playlisturi = $('#popupQueue').data("list");
uri = $('#popupQueue').data("track");
var track;
for (var i = 0; i < currentplaylist.length; i++) {
if (currentplaylist[i].uri == uri) {
@ -103,10 +146,20 @@ function playTrackQueue() {
}
mopidy.playback.play(); //currentplaylist[track]);
console.log(track, currentplaylist[track]);
//console.log(track, currentplaylist[track]);
return false;
}
/***
* @deprecated
* @returns {boolean}
*/
function playTrackQueue() {
playlisturi = $('#popupQueue').data("list");
uri = $('#popupQueue').data("track");
return playTrackByUri(uri, playlisturi);
}
/********************************************************
* remove a track from the queue
*********************************************************/
@ -128,7 +181,7 @@ function removeTrack() {
console.log(currentplaylist[i].uri);
}
function clearQueue () {
function clearQueue() {
mopidy.tracklist.clear();
return false;
}
@ -147,8 +200,10 @@ function doShuffle() {
function setPlayState(nwplay) {
if (nwplay) {
$("#playimg").attr('src', 'images/icons/pause_32x32.png');
$("#btplayNowPlaying >i").removeClass('fa-play').addClass('fa-pause');
} else {
$("#playimg").attr('src', 'images/icons/play_alt_32x32.png');
$("#btplayNowPlaying >i").removeClass('fa-pause').addClass('fa-play');
}
play = nwplay;
}
@ -209,22 +264,70 @@ function setRandom(nwrandom) {
function doRandom() {
if (random == false) {
mopidy.playback.setRandom(true);
mopidy.tracklist.setRandom(true).then();
// mopidy.playback.setRandom(true).then();
} else {
mopidy.playback.setRandom(false);
mopidy.tracklist.setRandom(false).then();
// mopidy.playback.setRandom(false).then();
}
setRandom(!random);
}
function doRepeat() {
if (repeat == false) {
mopidy.playback.setRepeat(true).then();
mopidy.tracklist.setRepeat(true).then();
// mopidy.playback.setRepeat(true).then();
} else {
mopidy.playback.setRepeat(false).then();
mopidy.tracklist.setRepeat(false).then();
// mopidy.playback.setRepeat(false).then();
}
setRepeat(!repeat);
}
/*
function setRepeat(nwrepeat) {
if (repeat == nwrepeat) {
return
}
if (!nwrepeat) {
$("#repeatbt").attr('src', 'images/icons/reload_alt_18x21.png');
} else {
$("#repeatbt").attr('src', 'images/icons/reload_18x21.png');
}
repeat = nwrepeat;
}
function setRandom(nwrandom) {
if(nwrandom){
$("#flip-random").val('On');
}else{
$("#flip-random").val('Off');
}
console.log('function setRandom called: '+nwrandom);
}
function doRandom() {
console.log('obsolete function doRandom called');
}
*/
//$("#flip-random").change(function () {
// if ($(this).val() == "on") {
// mopidy.tracklist.setRandom(true).then();
// } else if ($(this).val() == "off") {
// mopidy.tracklist.setRandom(false).then();
// }
//});
//
//$("#flip-repeat").change(function () {
// if ($(this).val() == "on") {
// mopidy.tracklist.setRepeat(true).then();
// } else if ($(this).val() == "off") {
// mopidy.tracklist.setRepeat(false).then();
// }
//});
/*********************
* Track Slider
* Use a timer to prevent looping of commands
@ -237,7 +340,7 @@ function doSeekPos(value) {
pauseTimer();
//set timer to not trigger it too much
clearTimeout(seekTimer);
$("#songelapsed").html(timeFromSeconds(val / 1000));
$("#songelapsed").html(timeFromSeconds(val / 1000));
seekTimer = setTimeout(triggerPos, 500);
}
}
@ -249,7 +352,7 @@ function triggerPos() {
// console.log(newposition);
mopidy.playback.seek(newposition);
// mopidy.playback.resume();
resumeTimer();
resumeTimer();
posChanging = false;
}
}
@ -322,8 +425,8 @@ function updateTimer() {
function resumeTimer() {
pauseTimer();
if(songlength > 0) {
posTimer = setInterval(updateTimer, TRACK_TIMER);
if (songlength > 0) {
posTimer = setInterval(updateTimer, TRACK_TIMER);
}
}
@ -352,43 +455,44 @@ function addRadioUri(name, uri) {
//value of name is based on the passing of an uri as a parameter or not
var name = '';
if (!uri) {
name = $('#radionameinput').val();
name = $('#radionameinput').val();
} else {
$('#radionameinput').val('');
$('#radionameinput').val('');
}
uri = uri || $('#radiouriinput').val();
if (validUri(uri)) {
toast('Selecting radiostation...');
//stop directly, for user feedback
mopidy.playback.stop(true);
//stop directly, for user feedback
mopidy.playback.stop(true);
//hide ios/android keyboard
document.activeElement.blur();
$("input").blur();
clearQueue();
mopidy.tracklist.add(null,0, uri );
clearQueue();
mopidy.tracklist.add(null, 0, uri);
mopidy.playback.play();
var tmpname = name || '';
var i = 0;
//add station to list and check for doubles and add no more than 25
var tmpname = name || '';
var i = 0;
//add station to list and check for doubles and add no more than 25
for (var key in radioStations) {
rs = radioStations[key];
if (i > 25) {
delete radioStations[key];
continue;
}
i++;
if (rs && rs[1] == uri) {
tmpname = name || radioStations[key][0];
delete radioStations[key];
}
};
$('#radionameinput').val(tmpname);
$('#radiouriinput').val(uri);
radioStations.unshift([tmpname, uri]);
saveRadioStations();
updateRadioStations();
rs = radioStations[key];
if (i > 25) {
delete radioStations[key];
continue;
}
i++;
if (rs && rs[1] == uri) {
tmpname = name || radioStations[key][0];
delete radioStations[key];
}
}
;
$('#radionameinput').val(tmpname);
$('#radiouriinput').val(uri);
radioStations.unshift([tmpname, uri]);
saveRadioStations();
updateRadioStations();
} else {
toast ('No valid url!');
toast('No valid url!');
}
return false;
}
@ -398,14 +502,15 @@ function updateRadioStations() {
$('#radiostationstable').empty();
var child = '';
for (var key in radioStations) {
var rs = radioStations[key];
if(rs) {
name = rs[0] || rs[1];
child = '<li><a href="#" onclick="return addRadioUri(\'' + rs[0] + '\', \'' + rs[1] + '\');">';
child += '<h1>' + name + '</h1></a></li>';
tmp += child;
}
};
var rs = radioStations[key];
if (rs) {
name = rs[0] || rs[1];
child = '<li><a href="#" onclick="return addRadioUri(\'' + rs[0] + '\', \'' + rs[1] + '\');">';
child += '<h1>' + name + '</h1></a></li>';
tmp += child;
}
}
;
$('#radiostationstable').html(tmp);
}

1104
webclient/js/iscroll.bk Executable file

File diff suppressed because it is too large Load Diff

73
webclient/js/iscroll.js Executable file → Normal file
View File

@ -1,5 +1,5 @@
/*!
* iScroll v4.2.5 ~ Copyright (c) 2012 Matteo Spinelli, http://cubiq.org
* iScroll v4.2 ~ Copyright (c) 2012 Matteo Spinelli, http://cubiq.org
* Released under MIT license, http://cubiq.org/license
*/
(function(window, doc){
@ -37,7 +37,7 @@ var m = Math,
has3d = prefixStyle('perspective') in dummyStyle,
hasTouch = 'ontouchstart' in window && !isTouchPad,
hasTransform = vendor !== false,
hasTransform = !!vendor,
hasTransitionEnd = prefixStyle('transition') in dummyStyle,
RESIZE_EV = 'onorientationchange' in window ? 'orientationchange' : 'resize',
@ -45,6 +45,7 @@ var m = Math,
MOVE_EV = hasTouch ? 'touchmove' : 'mousemove',
END_EV = hasTouch ? 'touchend' : 'mouseup',
CANCEL_EV = hasTouch ? 'touchcancel' : 'mouseup',
WHEEL_EV = vendor == 'Moz' ? 'DOMMouseScroll' : 'mousewheel',
TRNEND_EV = (function () {
if ( vendor === false ) return false;
@ -52,7 +53,7 @@ var m = Math,
'' : 'transitionend',
'webkit' : 'webkitTransitionEnd',
'Moz' : 'transitionend',
'O' : 'otransitionend',
'O' : 'oTransitionEnd',
'ms' : 'MSTransitionEnd'
};
@ -176,10 +177,9 @@ var m = Math,
that._bind(RESIZE_EV, window);
that._bind(START_EV);
if (!hasTouch) {
if (that.options.wheelAction != 'none') {
that._bind('DOMMouseScroll');
that._bind('mousewheel');
}
that._bind('mouseout', that.wrapper);
if (that.options.wheelAction != 'none')
that._bind(WHEEL_EV);
}
if (that.options.checkDOMChanges) that.checkDOMTime = setInterval(function () {
@ -210,7 +210,8 @@ iScroll.prototype = {
case END_EV:
case CANCEL_EV: that._end(e); break;
case RESIZE_EV: that._resize(); break;
case 'DOMMouseScroll': case 'mousewheel': that._wheel(e); break;
case WHEEL_EV: that._wheel(e); break;
case 'mouseout': that._mouseout(e); break;
case TRNEND_EV: that._transitionEnd(e); break;
}
},
@ -376,11 +377,11 @@ iScroll.prototype = {
if (that.options.useTransform) {
// Very lame general purpose alternative to CSSMatrix
matrix = getComputedStyle(that.scroller, null)[transform].replace(/[^0-9\-.,]/g, '').split(',');
x = +(matrix[12] || matrix[4]);
y = +(matrix[13] || matrix[5]);
x = matrix[4] * 1;
y = matrix[5] * 1;
} else {
x = +getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, '');
y = +getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, '');
x = getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, '') * 1;
y = getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, '') * 1;
}
if (x != that.x || y != that.y) {
@ -388,7 +389,6 @@ iScroll.prototype = {
else cancelFrame(that.aniTime);
that.steps = [];
that._pos(x, y);
if (that.options.onScrollEnd) that.options.onScrollEnd.call(that);
}
}
@ -404,9 +404,9 @@ iScroll.prototype = {
if (that.options.onScrollStart) that.options.onScrollStart.call(that, e);
that._bind(MOVE_EV, window);
that._bind(END_EV, window);
that._bind(CANCEL_EV, window);
that._bind(MOVE_EV);
that._bind(END_EV);
that._bind(CANCEL_EV);
},
_move: function (e) {
@ -506,9 +506,9 @@ iScroll.prototype = {
snap,
scale;
that._unbind(MOVE_EV, window);
that._unbind(END_EV, window);
that._unbind(CANCEL_EV, window);
that._unbind(MOVE_EV);
that._unbind(END_EV);
that._unbind(CANCEL_EV);
if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e);
@ -566,7 +566,7 @@ iScroll.prototype = {
}
}
that._resetPos(400);
that._resetPos(200);
if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
return;
@ -700,6 +700,19 @@ iScroll.prototype = {
}
},
_mouseout: function (e) {
var t = e.relatedTarget;
if (!t) {
this._end(e);
return;
}
while (t = t.parentNode) if (t == this.wrapper) return;
this._end(e);
},
_transitionEnd: function (e) {
var that = this;
@ -886,13 +899,13 @@ iScroll.prototype = {
// Remove the event listeners
that._unbind(RESIZE_EV, window);
that._unbind(START_EV);
that._unbind(MOVE_EV, window);
that._unbind(END_EV, window);
that._unbind(CANCEL_EV, window);
that._unbind(MOVE_EV);
that._unbind(END_EV);
that._unbind(CANCEL_EV);
if (!that.options.hasTouch) {
that._unbind('DOMMouseScroll');
that._unbind('mousewheel');
that._unbind('mouseout', that.wrapper);
that._unbind(WHEEL_EV);
}
if (that.options.useTransition) that._unbind(TRNEND_EV);
@ -972,7 +985,7 @@ iScroll.prototype = {
if (!that.zoomed) {
that.scroller.style[transitionDuration] = '0';
that._resetPos(400);
that._resetPos(200);
}
},
@ -1043,9 +1056,9 @@ iScroll.prototype = {
this.enabled = false;
// If disabled after touchstart we make sure that there are no left over events
this._unbind(MOVE_EV, window);
this._unbind(END_EV, window);
this._unbind(CANCEL_EV, window);
this._unbind(MOVE_EV);
this._unbind(END_EV);
this._unbind(CANCEL_EV);
},
enable: function () {
@ -1101,4 +1114,4 @@ dummyStyle = null; // for the sake of it
if (typeof exports !== 'undefined') exports.iScroll = iScroll;
else window.iScroll = iScroll;
})(window, document);
})(window, document);

154
webclient/js/jquery.mobile.iscrollview.js Executable file → Normal file
View File

@ -31,7 +31,7 @@ regexp:false, todo:true */
/*
jquery.mobile.iscrollview.js
Version: 1.2.6
Version: 1.3.7
jQuery Mobile iScroll4 view widget
Copyright (c), 2012, 2013 Watusiware Corporation
Distributed under the MIT License
@ -64,14 +64,29 @@ Further changes: @addyosmani
Licensed under the MIT license
dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provided in demo)
jQuery 1.6.4 (JQM 1.0.1) or 1.7.1 (JQM 1.1) or 1.7.2 (JQM 1.2)
JQuery Mobile = 1.0.1 or 1.1 or 1.2-alpha1
jQuery - see jQuery Mobile documentation, depends on JQM version
JQuery Mobile = 1.0.1 through 1.3.1
*/
; // Ignore jslint/jshint warning - for safety - terminate previous file if unterminated
(function ($, window, document, undefined) { /* Ignore islint warning on "undefined" */
"use strict";
// Prevent annoying "layerX/Y is deprecated" console messages when running in some Webkit browsers
// See also _doCallback() function.
//
// This needs to be a global function, (well, outside of the widget self-invoking function, anyway),
// because this code will generate warnings ("cannot delete") if executed within a strict function.
// The warnings are not generated, though, if executed within a non-strict function CALLED from a
// strict function.
//
// (Other than this little bit, the entirety of this widget is strict.)
function jqmIscrollviewRemoveLayerXYProps(e) {
delete e.layerX;
delete e.layerY;
}
(function ($, window, document, undefined) { /* Ignore jslint warning on "undefined" */
"use strict"; // Comment this out whilst debugging with Safari Web Inspector
// Otherwise, you will not be able to see variables when stopped at breakpoints
//----------------------------------
// "class constants"
@ -159,6 +174,10 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
// Perform an iScroll callback.
this._doCallback = function(callbackName, e, f) {
if (typeof e === "object") { // Prevent annoying "layerX/layerY is deprecated" console messages
jqmIscrollviewRemoveLayerXYProps(e);
}
var v = this.iscrollview,
then = v._logCallback(callbackName, e);
if (f) { f.call(this, e); } // Perform passed function if present
@ -312,15 +331,17 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
bottomOffset: 0,
emulateBottomOffset: true,
pageClass: "iscroll-page", // Class to be applied to pages containing this widget
wrapperClass: "iscroll-wrapper", // Class to be applied to wrapper containing this widget
scrollerClass: "iscroll-scroller", // Class to be applied to scroller within wrapper
pullDownClass: "iscroll-pulldown", // Class for pulldown element (if any)
pullUpClass: "iscroll-pullup", // Class for pullup element (if any)
pullLabelClass: "iscroll-pull-label", // Class for pull element label span
pullUpSpacerClass: "iscroll-pullup-spacer", // Class added to generated pullup spacer
scrollerContentClass: "iscroll-content", // Real content of scroller, not including pull-up, pull-down
fixedHeightClass: "iscroll-fixed", // Class applied to elements that match fixedHeightSelector
pageClass: "iscroll-page", // Class to be applied to pages containing this widget
wrapperClass: "iscroll-wrapper", // Class to be applied to wrapper containing this widget
scrollerClass: "iscroll-scroller", // Class to be applied to scroller within wrapper
pullDownClass: "iscroll-pulldown", // Class for pulldown element (if any)
pullUpClass: "iscroll-pullup", // Class for pullup element (if any)
pullLabelClass: "iscroll-pull-label", // Class for pull element label span
pullUpSpacerClass: "iscroll-pullup-spacer", // Class added to generated pullup spacer
topSpacerClass: "iscroll-top-spacer",
bottomSpacerClass: "iscroll-bottom-spacer",
scrollerContentClass: "iscroll-content", // Real content of scroller, not including pull-up, pull-down
fixedHeightClass: "iscroll-fixed", // Class applied to elements that match fixedHeightSelector
// The widget adds the fixedHeightClass to all elements that match fixedHeightSelector.
// Don't add the fixedHeightClass to elements manually. Use data-iscroll-fixed instead.
@ -379,13 +400,19 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
// inside any pull-down/pull-up to replace the padding removed from the wrapper.
addScrollerPadding: true,
// Add convenient spacer divs at top and bottom of content.
// These initially have no height. They are useful in situations
// where padding collapses into the document. For example, can be
// used to work with fullscreen header/footer
addSpacers: true,
// On some platforms (iOS, for example) we need to scroll to top after orientation change,
// because the address bar pushed the window down. jQuery Mobile handles this for page links,
// but doesn't for orientationchange.
// If you have multiple scrollers, only enable this for one of them
scrollTopOnResize: true,
scrollTopOnOrientatationChange: true,
scrollTopOnOrientationChange: true,
// iScroll scrolls the first child of the wrapper. I don't see a use case for having more
// than one child. What kind of mess is going to be shown in that case? So, by default, we
@ -503,6 +530,9 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
"scrollerContentClass",
"pullLabelClass",
"pullUpSpacerClass",
"topSpacerClass",
"bottomSpacerClass",
"addSpacer",
"fixedHeightSelector",
"resizeWrapper",
"resizeEvents",
@ -536,7 +566,8 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
"onpullup",
"onbeforerefresh",
"onafterrefresh",
"fastDestroy"
"fastDestroy",
"preventPageScroll"
],
//-----------------------------------------------------------------------
@ -819,7 +850,7 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
},
_unbindPage: function(types_in) {
var types = this._addEventsNamespace(types_in, this._instanceEventNamespace());
var types = this._addEventsNamespace(types_in, this._pageEventNamespace());
this._logWidgetEvent("unbind $page", types);
this.$page.unbind(types);
},
@ -983,13 +1014,23 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
if (this._instanceCount() === 1) {
this.$page.addClass(this.options.pageClass);
this.$page.find(this.options.fixedHeightSelector).each(function() { // Iterate over headers/footers/etc.
$(this).addClass(_this.options.fixedHeightClass);
});
var
$fixedHeightElement = $(this),
// We need to exclude headers/footers in popups and panels.
// We cannot simply use a selector that requires the fixed-height element
// to be a child of .ui-page, because of the complication that JQM
// moves persistent headers/footers out of the page during transitions.
isPopup = $fixedHeightElement.closest(".ui-popup").length !== 0,
isPanel = $fixedHeightElement.closest(".ui-panel").length !== 0;
if (!isPopup && !isPanel) {
$fixedHeightElement.addClass(_this.options.fixedHeightClass);
}
});
if (HasTouch && this.options.preventPageScroll) {
this._bindPage("touchmove", _pageTouchmoveFunc);
}
}
},
}
},
_undoAdaptPage: function() {
var _this = this;
@ -1008,17 +1049,17 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
var barsHeight = 0,
fixedHeightSelector = "." + this.options.fixedHeightClass,
// Persistent footers are sometimes inside the page, sometimes outside of all pages! (as
// direct descendant of <body>). And sometimes both. During transitions, the page that
// direct descendant of <body>/.ui-mobile-viewport). And sometimes both. During transitions, the page that
// is transitioning in will have had it's persistent footer moved outside of the page,
// while all other pages will have their persistent footer internal to the page.
//
// To deal with this, we find iscroll-fixed elements in the page, as well as outside
// of the page (as direct descendants of <body>). We avoid double-counting persistent
// of the page (as direct descendants of <body>/.ui-mobile-viewport). We avoid double-counting persistent
// footers that have the same data-id. (Experimentally, then, we also permit the user
// to place fixed-height elements outside of the page, but unsure if this is of any
// practical use.)
$barsInPage = this.$page.find(fixedHeightSelector),
$barsOutsidePage = $("body").children(fixedHeightSelector);
$barsOutsidePage = $(".ui-mobile-viewport").children(fixedHeightSelector);
$barsInPage.each(function() { // Iterate over headers/footers/etc.
barsHeight += $(this).outerHeight(true);
@ -1080,8 +1121,15 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
case "content-box": // AKA W3C Ignore jshint warning
default: // Ignore jslint warning
// We will subtract padding, border, margin
adjust = $elem.outerHeight(true) - $elem.height();
break;
// However...
// wrapper will never have padding, at least once we are done
// modifying it. This function is called before any removal of
// padding, though. So, if $wrapper, use same calculation as for padding-box,
// ignoring padding.
// (We actually don't call this for anything but $wrapper, but preseve
// functionality in case we ever use it on another element)
adjust = $elem.outerHeight($elem !== this.$wrapper ) - $elem.height();
break;
}
return adjust;
},
@ -1185,7 +1233,7 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
// will not be visible until the user pulls up.
//--------------------------------------------------------
_expandScrollerToFillWrapper: function() {
if (this.options.scrollShortContent || this.$pullDown.length || this.pullUp.length) {
if (this.options.scrollShortContent || this.$pullDown.length || this.$pullUp.length) {
if (this._firstScrollerExpand) {
this._origScrollerStyle = this.$scroller.attr("style") || null;
this._firstScrollerExpand = false;
@ -1402,7 +1450,9 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
hidden = _this._setPageVisible();
if (_callbackBefore) { _callbackBefore(); }
_this._triggerWidget("onbeforerefresh");
_this.iscroll.refresh();
// The if below is reportedly needed when using BackboneJS views when switching
// from one view to another. See pull request #80
if (_this.iscroll) { _this.iscroll.refresh(); }
_this._triggerWidget("onafterrefresh");
if (_callbackAfter) { _callbackAfter(); }
_this._restorePageVisibility(hidden);
@ -1453,6 +1503,22 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
}
},
//-----------------------------------------
// Create spacers
//-----------------------------------------
_addSpacers: function() {
if(this.options.addSpacers) {
this.$scrollerContent.before( $( '<div class="' + this.options.topSpacerClass + '"></div>' ) );
this.$scrollerContent.after( $( '<div class="' + this.options.bottomSpacerClass + '"></div>' ) );
}
},
_undoAddSpacers: function() {
this.$wrapper.find(this.options.topSpacerClass).remove();
this.$wrapper.find(this.options.bottomSpacerClass).remove();
},
// Temporarily change page CSS to make it "visible" so that dimensions can be read.
// This can be used in any event callback, and so can be used in _create(), since it's called
// from pageinit event. Because event processing is synchronous, the browser won't render the
@ -1486,6 +1552,9 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
this.$wrapper = this.element; // JQuery object containing the element we are creating this widget for
this.$page = this.$wrapper.parents(":jqmData(role='page')"); // The page containing the wrapper
// Merge options from data-iscroll, if present
$.extend(true, this.options, this.$wrapper.jqmData("iscroll"));
if (this.options.debug && this.options.traceCreateDestroy) {
this._log("_create() start", then);
}
@ -1493,7 +1562,7 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
this.createdAt = then;
this._instanceCount(this._instanceCount() + 1); // The count of extant instances of this widget on the page
this.instanceID = this._nextInstanceID(); // The serial ID of this instance of this widget on the page
this._nextInstanceID(this._instanceID + 1);
this._nextInstanceID(this.instanceID + 1);
if (this.instanceID === 1) {
this._pageID(nextPageID);
nextPageID += 1;
@ -1510,14 +1579,10 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
// Find pull elements, if present
this.$pullDown = $("." + this.options.pullDownClass, this.$scroller);
this._modifyPullDown();
this.$pullUp = $("." + this.options.pullUpClass, this.$scroller);
this._modifyPullUp();
// Merge options from data-iscroll, if present
$.extend(true, this.options, this.$wrapper.jqmData("iscroll"));
this._modifyWrapper(); // Various changes to the wrapper
this._modifyWrapper(); // Various changes to the wrapper
// Need this for deferred refresh processing
this._bindPage("pagebeforeshow", this._pageBeforeShowFunc);
@ -1525,7 +1590,9 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
this._setTopOffsetForPullDown(); // If there's a pull-down, set the top offset
this._setBottomOffsetForPullUp(); // If there's a pull-up, set the bottom offset
this._resizeWrapper(); // Resize the wrapper to fill available space
this._addScrollerPadding(); // Put back padding removed from wrapper
this._addScrollerPadding(); // Put back padding removed from wrapper
this.$scrollerContent = this.$scroller.find("." + this.options.scrollerContentClass);
this._addSpacers(); // Add top/bottom spacers
this._create_iscroll_object();
this._merge_from_iscroll_options(); // Merge iscroll options into widget options
this._restorePageVisibility(hidden);
@ -1533,14 +1600,15 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
// Setup bindings for window resize and orientationchange
if (this.options.resizeWrapper) {
this._isvBind(this.$window, this.options.resizeEvents, this._windowResizeFunc, "$window");
if (this.options.resizeEvents.length) {
this._isvBind(this.$window, this.options.resizeEvents, this._windowResizeFunc, "$window");
}
if (this.options.scrollTopOnOrientationChange) {
this._isvBind(this.$window, "orientationchange", this._orientationChangeFunc, "$window");
}
}
// Refresh on trigger of updatelayout of content
this.$scrollerContent = this.$scroller.find("." + this.options.scrollerContentClass);
this._isvBind(this.$scrollerContent, "updatelayout", this._updateLayoutFunc, "$scrollerContent");
if (this.options.debug && this.options.traceCreateDestroy) {
@ -1560,7 +1628,9 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
// Unbind events
this._isvUnbind(this.$scrollerContent, "updatelayout", "$scrollerContent");
this._isvUnbind(this.$window, this.options.resizeEvents, "$window");
if (this.options.resizeEvents.length) {
this._isvUnbind(this.$window, this.options.resizeEvents, "$window");
}
this._isvUnbind(this.$window, "orientationchange", "$window");
if (this._instanceCount() === 1) {
this._unbindPage("pagebeforeshow");
@ -1578,6 +1648,7 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
this._undoExpandScrollerToFillWrapper();
this._undoModifyPullDown();
this._undoModifyPullUp();
this._undoAddSpacers();
this._undoAddScrollerPadding();
this._undoModifyWrapper();
this.$wrapper.removeClass(this.options.wrapperClass);
@ -1721,8 +1792,13 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
// Reset a pull block to the initial state
_pullSetStateReset: function ($pull, text) {
if ($pull.is("." + this.options.pullLoadingClass + ", ." + this.options.pullPulledClass)) {
var
$iconSpan = $pull.find(".iscroll-pull-icon"),
$iconSpanClone = $iconSpan.clone();
$pull.removeClass(this.options.pullPulledClass + " " + this.options.pullLoadingClass);
this._replacePullText($pull, text);
//force animations to stop on iOS, which doesn't seem to want to give up. Stubborn bugger.
$iconSpan.replaceWith($iconSpanClone);
}
},
@ -1841,6 +1917,8 @@ dependency: iScroll 4.1.9 https://github.com/cubiq/iscroll or later (4.2 provid
}( jQuery, window, document ));
jQuery(document).trigger("iscroll_init");
// Self-init
jQuery(document).bind("pagecreate", function (e) {
"use strict";