1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

merge from dev

This commit is contained in:
Luke Pulverenti 2016-01-30 13:52:33 -05:00
parent 8436c7ff3c
commit db793b9d25
46 changed files with 646 additions and 356 deletions

View file

@ -35,8 +35,6 @@ define(function () {
var url = cssId + '.css'; var url = cssId + '.css';
var packageName = '';
if (url.indexOf('http') != 0 && url.indexOf('file:') != 0) { if (url.indexOf('http') != 0 && url.indexOf('file:') != 0) {
url = config.baseUrl + url; url = config.baseUrl + url;
} }
@ -46,10 +44,6 @@ define(function () {
var link = document.createElement('link'); var link = document.createElement('link');
if (packageName) {
link.setAttribute('data-package', packageName);
}
link.setAttribute('rel', 'stylesheet'); link.setAttribute('rel', 'stylesheet');
link.setAttribute('type', 'text/css'); link.setAttribute('type', 'text/css');
link.onload = load; link.onload = load;
@ -61,19 +55,11 @@ define(function () {
} }
window.requireCss = { window.requireCss = {
unloadPackage: function (packageName) { removeStylesheet: function (stylesheet) {
// Todo: unload css here
var stylesheets = document.head.querySelectorAll("link[data-package='" + packageName + "']");
for (var i = 0, length = stylesheets.length; i < length; i++) {
var stylesheet = stylesheets[i];
console.log('Unloading stylesheet: ' + stylesheet.href);
stylesheet.parentNode.removeChild(stylesheet); stylesheet.parentNode.removeChild(stylesheet);
removeFromLoadHistory(stylesheet.href); removeFromLoadHistory(stylesheet.href);
} }
}
}; };
return requireCss; return requireCss;

View file

@ -1,6 +1,6 @@
{ {
"name": "hls.js", "name": "hls.js",
"version": "0.4.6", "version": "0.4.7",
"description": "Media Source Extension - HLS library, by/for Dailymotion", "description": "Media Source Extension - HLS library, by/for Dailymotion",
"homepage": "https://github.com/dailymotion/hls.js", "homepage": "https://github.com/dailymotion/hls.js",
"authors": [ "authors": [
@ -15,11 +15,11 @@
"test", "test",
"tests" "tests"
], ],
"_release": "0.4.6", "_release": "0.4.7",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v0.4.6", "tag": "v0.4.7",
"commit": "eb4bfb0ebadda9797d8020e7b3a2d2c699444cab" "commit": "9c1a7e7d768346dcc4012e8b80f73e823af5ff20"
}, },
"_source": "git://github.com/dailymotion/hls.js.git", "_source": "git://github.com/dailymotion/hls.js.git",
"_target": "~0.4.5", "_target": "~0.4.5",

View file

@ -99,6 +99,7 @@ each error is categorized by :
- ```Hls.ErrorDetails.FRAG_PARSING_ERROR```raised when fragment parsing fails - ```Hls.ErrorDetails.FRAG_PARSING_ERROR```raised when fragment parsing fails
- ```Hls.ErrorDetails.BUFFER_APPEND_ERROR```raised when exception is raised while preparing buffer append - ```Hls.ErrorDetails.BUFFER_APPEND_ERROR```raised when exception is raised while preparing buffer append
- ```Hls.ErrorDetails.BUFFER_APPENDING_ERROR```raised when exception is raised during buffer appending - ```Hls.ErrorDetails.BUFFER_APPENDING_ERROR```raised when exception is raised during buffer appending
- ```Hls.ErrorDetails.BUFFER_STALLED_ERROR```raised when playback stalls because the buffer runs out
- its fatality: - its fatality:
- ```false```if error is not fatal, hls.js will try to recover it - ```false```if error is not fatal, hls.js will try to recover it
- ```true```if error is fatal, an action is required to (try to) recover it. - ```true```if error is fatal, an action is required to (try to) recover it.

View file

@ -838,7 +838,8 @@ var State = {
PARSING: 5, PARSING: 5,
PARSED: 6, PARSED: 6,
APPENDING: 7, APPENDING: 7,
BUFFER_FLUSHING: 8 BUFFER_FLUSHING: 8,
ENDED: 9
}; };
var MSEMediaController = (function (_EventHandler) { var MSEMediaController = (function (_EventHandler) {
@ -902,6 +903,7 @@ var MSEMediaController = (function (_EventHandler) {
this.mp4segments = []; this.mp4segments = [];
this.flushRange = []; this.flushRange = [];
this.bufferRange = []; this.bufferRange = [];
this.stalled = false;
var frag = this.fragCurrent; var frag = this.fragCurrent;
if (frag) { if (frag) {
if (frag.loader) { if (frag.loader) {
@ -1083,13 +1085,23 @@ var MSEMediaController = (function (_EventHandler) {
// have we reached end of VOD playlist ? // have we reached end of VOD playlist ?
if (!levelDetails.live) { if (!levelDetails.live) {
var mediaSource = this.mediaSource; var mediaSource = this.mediaSource;
if (mediaSource && mediaSource.readyState === 'open') { if (mediaSource) {
// ensure sourceBuffer are not in updating states switch (mediaSource.readyState) {
case 'open':
var sb = this.sourceBuffer; var sb = this.sourceBuffer;
if (!(sb.audio && sb.audio.updating || sb.video && sb.video.updating)) { if (!(sb.audio && sb.audio.updating || sb.video && sb.video.updating)) {
_utilsLogger.logger.log('all media data available, signal endOfStream() to MediaSource'); _utilsLogger.logger.log('all media data available, signal endOfStream() to MediaSource and stop loading fragment');
//Notify the media element that it now has all of the media data //Notify the media element that it now has all of the media data
mediaSource.endOfStream(); mediaSource.endOfStream();
this.state = State.ENDED;
}
break;
case 'ended':
_utilsLogger.logger.log('all media data available and mediaSource ended, stop loading fragment');
this.state = State.ENDED;
break;
default:
break;
} }
} }
} }
@ -1275,6 +1287,8 @@ var MSEMediaController = (function (_EventHandler) {
each time sourceBuffer updateend() callback will be triggered each time sourceBuffer updateend() callback will be triggered
*/ */
break; break;
case State.ENDED:
break;
default: default:
break; break;
} }
@ -1682,6 +1696,9 @@ var MSEMediaController = (function (_EventHandler) {
// switch to IDLE state to load new fragment // switch to IDLE state to load new fragment
this.state = State.IDLE; this.state = State.IDLE;
} }
} else if (this.state === State.ENDED) {
// switch to IDLE state to check for potential new fragment
this.state = State.IDLE;
} }
if (this.media) { if (this.media) {
this.lastCurrentTime = this.media.currentTime; this.lastCurrentTime = this.media.currentTime;
@ -2017,17 +2034,27 @@ var MSEMediaController = (function (_EventHandler) {
var currentTime = media.currentTime, var currentTime = media.currentTime,
bufferInfo = this.bufferInfo(currentTime, 0), bufferInfo = this.bufferInfo(currentTime, 0),
isPlaying = !(media.paused || media.ended || media.seeking || readyState < 3), isPlaying = !(media.paused || media.ended || media.seeking || readyState < 3),
jumpThreshold = 0.2; jumpThreshold = 0.2,
playheadMoving = currentTime > media.playbackRate * this.lastCurrentTime;
if (this.stalled && playheadMoving) {
this.stalled = false;
}
// check buffer upfront // check buffer upfront
// if less than 200ms is buffered, and media is playing but playhead is not moving, // if less than 200ms is buffered, and media is playing but playhead is not moving,
// and we have a new buffer range available upfront, let's seek to that one // and we have a new buffer range available upfront, let's seek to that one
if (bufferInfo.len <= jumpThreshold) { if (bufferInfo.len <= jumpThreshold) {
if (currentTime > media.playbackRate * this.lastCurrentTime || !isPlaying) { if (playheadMoving || !isPlaying) {
// playhead moving or media not playing // playhead moving or media not playing
jumpThreshold = 0; jumpThreshold = 0;
} else { } else {
// playhead not moving AND media playing
_utilsLogger.logger.log('playback seems stuck'); _utilsLogger.logger.log('playback seems stuck');
if (!this.stalled) {
this.hls.trigger(_events2['default'].ERROR, { type: _errors.ErrorTypes.MEDIA_ERROR, details: _errors.ErrorDetails.BUFFER_STALLED_ERROR, fatal: false });
this.stalled = true;
}
} }
// if we are below threshold, try to jump if next buffer range is close // if we are below threshold, try to jump if next buffer range is close
if (bufferInfo.len <= jumpThreshold) { if (bufferInfo.len <= jumpThreshold) {
@ -3821,6 +3848,8 @@ var TSDemuxer = (function () {
value: function switchLevel() { value: function switchLevel() {
this.pmtParsed = false; this.pmtParsed = false;
this._pmtId = -1; this._pmtId = -1;
this.lastAacPTS = null;
this.aacOverFlow = null;
this._avcTrack = { type: 'video', id: -1, sequenceNumber: 0, samples: [], len: 0, nbNalu: 0 }; this._avcTrack = { type: 'video', id: -1, sequenceNumber: 0, samples: [], len: 0, nbNalu: 0 };
this._aacTrack = { type: 'audio', id: -1, sequenceNumber: 0, samples: [], len: 0 }; this._aacTrack = { type: 'audio', id: -1, sequenceNumber: 0, samples: [], len: 0 };
this._id3Track = { type: 'id3', id: -1, sequenceNumber: 0, samples: [], len: 0 }; this._id3Track = { type: 'id3', id: -1, sequenceNumber: 0, samples: [], len: 0 };
@ -4231,7 +4260,7 @@ var TSDemuxer = (function () {
case 3: case 3:
if (value === 0) { if (value === 0) {
state = 3; state = 3;
} else if (value === 1) { } else if (value === 1 && i < len) {
unitType = array[i] & 0x1f; unitType = array[i] & 0x1f;
//logger.log('find NALU @ offset:' + i + ',type:' + unitType); //logger.log('find NALU @ offset:' + i + ',type:' + unitType);
if (lastUnitStart) { if (lastUnitStart) {
@ -4289,6 +4318,8 @@ var TSDemuxer = (function () {
startOffset = 0, startOffset = 0,
duration = this._duration, duration = this._duration,
audioCodec = this.audioCodec, audioCodec = this.audioCodec,
aacOverFlow = this.aacOverFlow,
lastAacPTS = this.lastAacPTS,
config, config,
frameLength, frameLength,
frameDuration, frameDuration,
@ -4298,10 +4329,11 @@ var TSDemuxer = (function () {
stamp, stamp,
len, len,
aacSample; aacSample;
if (this.aacOverFlow) { if (aacOverFlow) {
var tmp = new Uint8Array(this.aacOverFlow.byteLength + data.byteLength); var tmp = new Uint8Array(aacOverFlow.byteLength + data.byteLength);
tmp.set(this.aacOverFlow, 0); tmp.set(aacOverFlow, 0);
tmp.set(data, this.aacOverFlow.byteLength); tmp.set(data, aacOverFlow.byteLength);
//logger.log(`AAC: append overflowing ${aacOverFlow.byteLength} bytes to beginning of new PES`);
data = tmp; data = tmp;
} }
// look for ADTS header (0xFFFx) // look for ADTS header (0xFFFx)
@ -4337,17 +4369,28 @@ var TSDemuxer = (function () {
} }
frameIndex = 0; frameIndex = 0;
frameDuration = 1024 * 90000 / track.audiosamplerate; frameDuration = 1024 * 90000 / track.audiosamplerate;
// if last AAC frame is overflowing, we should ensure timestamps are contiguous:
// first sample PTS should be equal to last sample PTS + frameDuration
if (aacOverFlow && lastAacPTS) {
var newPTS = lastAacPTS + frameDuration;
if (Math.abs(newPTS - pts) > 1) {
_utilsLogger.logger.log('AAC: align PTS for overlapping frames by ' + Math.round((newPTS - pts) / 90));
pts = newPTS;
}
}
while (offset + 5 < len) { while (offset + 5 < len) {
// The protection skip bit tells us if we have 2 bytes of CRC data at the end of the ADTS header // The protection skip bit tells us if we have 2 bytes of CRC data at the end of the ADTS header
headerLength = !!(data[offset + 1] & 0x01) ? 7 : 9; headerLength = !!(data[offset + 1] & 0x01) ? 7 : 9;
// retrieve frame size // retrieve frame size
frameLength = (data[offset + 3] & 0x03) << 11 | data[offset + 4] << 3 | (data[offset + 5] & 0xE0) >>> 5; frameLength = (data[offset + 3] & 0x03) << 11 | data[offset + 4] << 3 | (data[offset + 5] & 0xE0) >>> 5;
frameLength -= headerLength; frameLength -= headerLength;
stamp = Math.round(pts + frameIndex * frameDuration);
//stamp = pes.pts; //stamp = pes.pts;
//console.log('AAC frame, offset/length/pts:' + (offset+headerLength) + '/' + frameLength + '/' + stamp.toFixed(0));
if (frameLength > 0 && offset + headerLength + frameLength <= len) { if (frameLength > 0 && offset + headerLength + frameLength <= len) {
stamp = Math.round(pts + frameIndex * frameDuration);
//logger.log(`AAC frame, offset/length/total/pts:${offset+headerLength}/${frameLength}/${data.byteLength}/${(stamp/90).toFixed(0)}`);
aacSample = { unit: data.subarray(offset + headerLength, offset + headerLength + frameLength), pts: stamp, dts: stamp }; aacSample = { unit: data.subarray(offset + headerLength, offset + headerLength + frameLength), pts: stamp, dts: stamp };
track.samples.push(aacSample); track.samples.push(aacSample);
track.len += frameLength; track.len += frameLength;
@ -4364,10 +4407,13 @@ var TSDemuxer = (function () {
} }
} }
if (offset < len) { if (offset < len) {
this.aacOverFlow = data.subarray(offset, len); aacOverFlow = data.subarray(offset, len);
//logger.log(`AAC: overflow detected:${len-offset}`);
} else { } else {
this.aacOverFlow = null; aacOverFlow = null;
} }
this.aacOverFlow = aacOverFlow;
this.lastAacPTS = stamp;
} }
}, { }, {
key: '_parseID3PES', key: '_parseID3PES',
@ -4438,7 +4484,9 @@ var ErrorDetails = {
// Identifier for a buffer append error - data: append error description // Identifier for a buffer append error - data: append error description
BUFFER_APPEND_ERROR: 'bufferAppendError', BUFFER_APPEND_ERROR: 'bufferAppendError',
// Identifier for a buffer appending error event - data: appending error description // Identifier for a buffer appending error event - data: appending error description
BUFFER_APPENDING_ERROR: 'bufferAppendingError' BUFFER_APPENDING_ERROR: 'bufferAppendingError',
// Identifier for a buffer stalled error event
BUFFER_STALLED_ERROR: 'bufferStalledError'
}; };
exports.ErrorDetails = ErrorDetails; exports.ErrorDetails = ErrorDetails;
@ -6475,7 +6523,8 @@ var MP4Remuxer = (function () {
if (delta) { if (delta) {
if (delta > 0) { if (delta > 0) {
_utilsLogger.logger.log(delta + ' ms hole between AAC samples detected,filling it'); _utilsLogger.logger.log(delta + ' ms hole between AAC samples detected,filling it');
} else if (delta < 0) { // if we have frame overlap, overlapping for more than half a frame duraion
} else if (delta < -12) {
// drop overlapping audio frames... browser will deal with it // drop overlapping audio frames... browser will deal with it
_utilsLogger.logger.log(-delta + ' ms overlapping between AAC samples detected, drop frame'); _utilsLogger.logger.log(-delta + ' ms overlapping between AAC samples detected, drop frame');
track.len -= unit.byteLength; track.len -= unit.byteLength;
@ -6683,7 +6732,7 @@ var AttrList = (function () {
}], [{ }], [{
key: 'parseAttrList', key: 'parseAttrList',
value: function parseAttrList(input) { value: function parseAttrList(input) {
var re = /(.+?)=((?:\".*?\")|.*?)(?:,|$)/g; var re = /\s*(.+?)\s*=((?:\".*?\")|.*?)(?:,|$)/g;
var match, var match,
attrs = {}; attrs = {};
while ((match = re.exec(input)) !== null) { while ((match = re.exec(input)) !== null) {
@ -6983,7 +7032,14 @@ var XhrLoader = (function () {
}, { }, {
key: 'loadInternal', key: 'loadInternal',
value: function loadInternal() { value: function loadInternal() {
var xhr = this.loader = new XMLHttpRequest(); var xhr;
if (typeof XDomainRequest !== 'undefined') {
xhr = this.loader = new XDomainRequest();
} else {
xhr = this.loader = new XMLHttpRequest();
}
xhr.onloadend = this.loadend.bind(this); xhr.onloadend = this.loadend.bind(this);
xhr.onprogress = this.loadprogress.bind(this); xhr.onprogress = this.loadprogress.bind(this);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -21,7 +21,8 @@ const State = {
PARSING : 5, PARSING : 5,
PARSED : 6, PARSED : 6,
APPENDING : 7, APPENDING : 7,
BUFFER_FLUSHING : 8 BUFFER_FLUSHING : 8,
ENDED : 9
}; };
class MSEMediaController extends EventHandler { class MSEMediaController extends EventHandler {
@ -86,6 +87,7 @@ class MSEMediaController extends EventHandler {
this.mp4segments = []; this.mp4segments = [];
this.flushRange = []; this.flushRange = [];
this.bufferRange = []; this.bufferRange = [];
this.stalled = false;
var frag = this.fragCurrent; var frag = this.fragCurrent;
if (frag) { if (frag) {
if (frag.loader) { if (frag.loader) {
@ -264,13 +266,23 @@ class MSEMediaController extends EventHandler {
// have we reached end of VOD playlist ? // have we reached end of VOD playlist ?
if (!levelDetails.live) { if (!levelDetails.live) {
var mediaSource = this.mediaSource; var mediaSource = this.mediaSource;
if (mediaSource && mediaSource.readyState === 'open') { if (mediaSource) {
// ensure sourceBuffer are not in updating states switch(mediaSource.readyState) {
case 'open':
var sb = this.sourceBuffer; var sb = this.sourceBuffer;
if (!((sb.audio && sb.audio.updating) || (sb.video && sb.video.updating))) { if (!((sb.audio && sb.audio.updating) || (sb.video && sb.video.updating))) {
logger.log('all media data available, signal endOfStream() to MediaSource'); logger.log('all media data available, signal endOfStream() to MediaSource and stop loading fragment');
//Notify the media element that it now has all of the media data //Notify the media element that it now has all of the media data
mediaSource.endOfStream(); mediaSource.endOfStream();
this.state = State.ENDED;
}
break;
case 'ended':
logger.log('all media data available and mediaSource ended, stop loading fragment');
this.state = State.ENDED;
break;
default:
break;
} }
} }
} }
@ -456,6 +468,8 @@ class MSEMediaController extends EventHandler {
each time sourceBuffer updateend() callback will be triggered each time sourceBuffer updateend() callback will be triggered
*/ */
break; break;
case State.ENDED:
break;
default: default:
break; break;
} }
@ -864,6 +878,9 @@ class MSEMediaController extends EventHandler {
// switch to IDLE state to load new fragment // switch to IDLE state to load new fragment
this.state = State.IDLE; this.state = State.IDLE;
} }
} else if (this.state === State.ENDED) {
// switch to IDLE state to check for potential new fragment
this.state = State.IDLE;
} }
if (this.media) { if (this.media) {
this.lastCurrentTime = this.media.currentTime; this.lastCurrentTime = this.media.currentTime;
@ -1188,17 +1205,27 @@ _checkBuffer() {
var currentTime = media.currentTime, var currentTime = media.currentTime,
bufferInfo = this.bufferInfo(currentTime,0), bufferInfo = this.bufferInfo(currentTime,0),
isPlaying = !(media.paused || media.ended || media.seeking || readyState < 3), isPlaying = !(media.paused || media.ended || media.seeking || readyState < 3),
jumpThreshold = 0.2; jumpThreshold = 0.2,
playheadMoving = currentTime > media.playbackRate*this.lastCurrentTime;
if (this.stalled && playheadMoving) {
this.stalled = false;
}
// check buffer upfront // check buffer upfront
// if less than 200ms is buffered, and media is playing but playhead is not moving, // if less than 200ms is buffered, and media is playing but playhead is not moving,
// and we have a new buffer range available upfront, let's seek to that one // and we have a new buffer range available upfront, let's seek to that one
if(bufferInfo.len <= jumpThreshold) { if(bufferInfo.len <= jumpThreshold) {
if(currentTime > media.playbackRate*this.lastCurrentTime || !isPlaying) { if(playheadMoving || !isPlaying) {
// playhead moving or media not playing // playhead moving or media not playing
jumpThreshold = 0; jumpThreshold = 0;
} else { } else {
// playhead not moving AND media playing
logger.log('playback seems stuck'); logger.log('playback seems stuck');
if(!this.stalled) {
this.hls.trigger(Event.ERROR, {type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.BUFFER_STALLED_ERROR, fatal: false});
this.stalled = true;
}
} }
// if we are below threshold, try to jump if next buffer range is close // if we are below threshold, try to jump if next buffer range is close
if(bufferInfo.len <= jumpThreshold) { if(bufferInfo.len <= jumpThreshold) {

View file

@ -37,6 +37,8 @@
switchLevel() { switchLevel() {
this.pmtParsed = false; this.pmtParsed = false;
this._pmtId = -1; this._pmtId = -1;
this.lastAacPTS = null;
this.aacOverFlow = null;
this._avcTrack = {type: 'video', id :-1, sequenceNumber: 0, samples : [], len : 0, nbNalu : 0}; this._avcTrack = {type: 'video', id :-1, sequenceNumber: 0, samples : [], len : 0, nbNalu : 0};
this._aacTrack = {type: 'audio', id :-1, sequenceNumber: 0, samples : [], len : 0}; this._aacTrack = {type: 'audio', id :-1, sequenceNumber: 0, samples : [], len : 0};
this._id3Track = {type: 'id3', id :-1, sequenceNumber: 0, samples : [], len : 0}; this._id3Track = {type: 'id3', id :-1, sequenceNumber: 0, samples : [], len : 0};
@ -412,7 +414,7 @@
case 3: case 3:
if( value === 0) { if( value === 0) {
state = 3; state = 3;
} else if (value === 1) { } else if (value === 1 && i < len) {
unitType = array[i] & 0x1f; unitType = array[i] & 0x1f;
//logger.log('find NALU @ offset:' + i + ',type:' + unitType); //logger.log('find NALU @ offset:' + i + ',type:' + unitType);
if (lastUnitStart) { if (lastUnitStart) {
@ -469,11 +471,14 @@
startOffset = 0, startOffset = 0,
duration = this._duration, duration = this._duration,
audioCodec = this.audioCodec, audioCodec = this.audioCodec,
aacOverFlow = this.aacOverFlow,
lastAacPTS = this.lastAacPTS,
config, frameLength, frameDuration, frameIndex, offset, headerLength, stamp, len, aacSample; config, frameLength, frameDuration, frameIndex, offset, headerLength, stamp, len, aacSample;
if (this.aacOverFlow) { if (aacOverFlow) {
var tmp = new Uint8Array(this.aacOverFlow.byteLength + data.byteLength); var tmp = new Uint8Array(aacOverFlow.byteLength + data.byteLength);
tmp.set(this.aacOverFlow, 0); tmp.set(aacOverFlow, 0);
tmp.set(data, this.aacOverFlow.byteLength); tmp.set(data, aacOverFlow.byteLength);
//logger.log(`AAC: append overflowing ${aacOverFlow.byteLength} bytes to beginning of new PES`);
data = tmp; data = tmp;
} }
// look for ADTS header (0xFFFx) // look for ADTS header (0xFFFx)
@ -509,6 +514,17 @@
} }
frameIndex = 0; frameIndex = 0;
frameDuration = 1024 * 90000 / track.audiosamplerate; frameDuration = 1024 * 90000 / track.audiosamplerate;
// if last AAC frame is overflowing, we should ensure timestamps are contiguous:
// first sample PTS should be equal to last sample PTS + frameDuration
if(aacOverFlow && lastAacPTS) {
var newPTS = lastAacPTS+frameDuration;
if(Math.abs(newPTS-pts) > 1) {
logger.log(`AAC: align PTS for overlapping frames by ${Math.round((newPTS-pts)/90)}`);
pts=newPTS;
}
}
while ((offset + 5) < len) { while ((offset + 5) < len) {
// The protection skip bit tells us if we have 2 bytes of CRC data at the end of the ADTS header // The protection skip bit tells us if we have 2 bytes of CRC data at the end of the ADTS header
headerLength = (!!(data[offset + 1] & 0x01) ? 7 : 9); headerLength = (!!(data[offset + 1] & 0x01) ? 7 : 9);
@ -517,11 +533,11 @@
(data[offset + 4] << 3) | (data[offset + 4] << 3) |
((data[offset + 5] & 0xE0) >>> 5); ((data[offset + 5] & 0xE0) >>> 5);
frameLength -= headerLength; frameLength -= headerLength;
stamp = Math.round(pts + frameIndex * frameDuration);
//stamp = pes.pts; //stamp = pes.pts;
//console.log('AAC frame, offset/length/pts:' + (offset+headerLength) + '/' + frameLength + '/' + stamp.toFixed(0));
if ((frameLength > 0) && ((offset + headerLength + frameLength) <= len)) { if ((frameLength > 0) && ((offset + headerLength + frameLength) <= len)) {
stamp = Math.round(pts + frameIndex * frameDuration);
//logger.log(`AAC frame, offset/length/total/pts:${offset+headerLength}/${frameLength}/${data.byteLength}/${(stamp/90).toFixed(0)}`);
aacSample = {unit: data.subarray(offset + headerLength, offset + headerLength + frameLength), pts: stamp, dts: stamp}; aacSample = {unit: data.subarray(offset + headerLength, offset + headerLength + frameLength), pts: stamp, dts: stamp};
track.samples.push(aacSample); track.samples.push(aacSample);
track.len += frameLength; track.len += frameLength;
@ -538,10 +554,13 @@
} }
} }
if (offset < len) { if (offset < len) {
this.aacOverFlow = data.subarray(offset, len); aacOverFlow = data.subarray(offset, len);
//logger.log(`AAC: overflow detected:${len-offset}`);
} else { } else {
this.aacOverFlow = null; aacOverFlow = null;
} }
this.aacOverFlow = aacOverFlow;
this.lastAacPTS = stamp;
} }
_parseID3PES(pes) { _parseID3PES(pes) {

View file

@ -37,5 +37,7 @@ export const ErrorDetails = {
// Identifier for a buffer append error - data: append error description // Identifier for a buffer append error - data: append error description
BUFFER_APPEND_ERROR: 'bufferAppendError', BUFFER_APPEND_ERROR: 'bufferAppendError',
// Identifier for a buffer appending error event - data: appending error description // Identifier for a buffer appending error event - data: appending error description
BUFFER_APPENDING_ERROR: 'bufferAppendingError' BUFFER_APPENDING_ERROR: 'bufferAppendingError',
// Identifier for a buffer stalled error event
BUFFER_STALLED_ERROR: 'bufferStalledError'
}; };

View file

@ -295,7 +295,8 @@ class MP4Remuxer {
if (delta) { if (delta) {
if (delta > 0) { if (delta > 0) {
logger.log(`${delta} ms hole between AAC samples detected,filling it`); logger.log(`${delta} ms hole between AAC samples detected,filling it`);
} else if (delta < 0) { // if we have frame overlap, overlapping for more than half a frame duraion
} else if (delta < -12) {
// drop overlapping audio frames... browser will deal with it // drop overlapping audio frames... browser will deal with it
logger.log(`${(-delta)} ms overlapping between AAC samples detected, drop frame`); logger.log(`${(-delta)} ms overlapping between AAC samples detected, drop frame`);
track.len -= unit.byteLength; track.len -= unit.byteLength;

View file

@ -64,7 +64,7 @@ class AttrList {
} }
static parseAttrList(input) { static parseAttrList(input) {
const re = /(.+?)=((?:\".*?\")|.*?)(?:,|$)/g; const re = /\s*(.+?)\s*=((?:\".*?\")|.*?)(?:,|$)/g;
var match, attrs = {}; var match, attrs = {};
while ((match = re.exec(input)) !== null) { while ((match = re.exec(input)) !== null) {
var value = match[2], quote = '"'; var value = match[2], quote = '"';

View file

@ -48,7 +48,14 @@ class XhrLoader {
} }
loadInternal() { loadInternal() {
var xhr = this.loader = new XMLHttpRequest(); var xhr;
if (typeof XDomainRequest !== 'undefined') {
xhr = this.loader = new XDomainRequest();
} else {
xhr = this.loader = new XMLHttpRequest();
}
xhr.onloadend = this.loadend.bind(this); xhr.onloadend = this.loadend.bind(this);
xhr.onprogress = this.loadprogress.bind(this); xhr.onprogress = this.loadprogress.bind(this);

View file

@ -1,14 +1,14 @@
{ {
"name": "howler.js", "name": "howler.js",
"version": "1.1.28",
"description": "Javascript audio library for the modern web.", "description": "Javascript audio library for the modern web.",
"main": "howler.js", "main": "howler.js",
"homepage": "https://github.com/goldfire/howler.js", "homepage": "https://github.com/goldfire/howler.js",
"_release": "1.1.28", "version": "1.1.29",
"_release": "1.1.29",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.1.28", "tag": "v1.1.29",
"commit": "34c22ab507f847bba7bd2eb2b003197cfc54f274" "commit": "169feb2702632459cb0eb37bf24a20e1d840f78c"
}, },
"_source": "git://github.com/goldfire/howler.js.git", "_source": "git://github.com/goldfire/howler.js.git",
"_target": "~1.1.27", "_target": "~1.1.27",

View file

@ -1,3 +1,9 @@
## 1.1.29 (January 22, 2016)
- `ADDED`: Error messages added onto each `loaderror` event (thanks Philip Silva).
- `FIXED`: Fixed various edge-case bugs by no longer comparing functions by string in `.off()` (thanks richard-livingston).
- `FIXED`: Edge case where multiple overlapping instances of the same sound won't all fire `end` (thanks richard-livingston).
- `FIXED`: `end` event now fires correctly when changing the `rate` of a sound.
## 1.1.28 (October 22, 2015) ## 1.1.28 (October 22, 2015)
- `FIXED`: Fixed typo with iOS enabler that was preventing it from working. - `FIXED`: Fixed typo with iOS enabler that was preventing it from working.

View file

@ -1,6 +1,5 @@
{ {
"name": "howler.js", "name": "howler.js",
"version": "1.1.27",
"description": "Javascript audio library for the modern web.", "description": "Javascript audio library for the modern web.",
"main": "howler.js" "main": "howler.js"
} }

View file

@ -1,8 +1,8 @@
/*! /*!
* howler.js v1.1.28 * howler.js v1.1.29
* howlerjs.com * howlerjs.com
* *
* (c) 2013-2015, James Simpson of GoldFire Studios * (c) 2013-2016, James Simpson of GoldFire Studios
* goldfirestudios.com * goldfirestudios.com
* *
* MIT License * MIT License
@ -139,7 +139,7 @@
/** /**
* Check for codec support. * Check for codec support.
* @param {String} ext Audio file extention. * @param {String} ext Audio file extension.
* @return {Boolean} * @return {Boolean}
*/ */
codecs: function(ext) { codecs: function(ext) {
@ -284,7 +284,7 @@
// if no audio is available, quit immediately // if no audio is available, quit immediately
if (noAudio) { if (noAudio) {
self.on('loaderror'); self.on('loaderror', new Error('No audio support.'));
return; return;
} }
@ -306,7 +306,7 @@
if (ext) { if (ext) {
ext = ext[1].toLowerCase(); ext = ext[1].toLowerCase();
} else { } else {
self.on('loaderror'); self.on('loaderror', new Error('Could not extract format from passed URLs, please add format parameter.'));
return; return;
} }
} }
@ -318,7 +318,7 @@
} }
if (!url) { if (!url) {
self.on('loaderror'); self.on('loaderror', new Error('No codec support for selected audio sources.'));
return; return;
} }
@ -483,7 +483,7 @@
// fire ended event // fire ended event
self.on('end', soundId); self.on('end', soundId);
}, duration * 1000); }, (duration / self._rate) * 1000);
// store the reference to the timer // store the reference to the timer
self._onendTimer.push({timer: timerId, id: data.id}); self._onendTimer.push({timer: timerId, id: data.id});
@ -1060,7 +1060,7 @@
*/ */
_clearEndTimer: function(soundId) { _clearEndTimer: function(soundId) {
var self = this, var self = this,
index = 0; index = -1;
// loop through the timers to find the one associated with this sound // loop through the timers to find the one associated with this sound
for (var i=0; i<self._onendTimer.length; i++) { for (var i=0; i<self._onendTimer.length; i++) {
@ -1136,13 +1136,12 @@
*/ */
off: function(event, fn) { off: function(event, fn) {
var self = this, var self = this,
events = self['_on' + event], events = self['_on' + event];
fnString = fn ? fn.toString() : null;
if (fnString) { if (fn) {
// loop through functions in the event for comparison // loop through functions in the event for comparison
for (var i=0; i<events.length; i++) { for (var i=0; i<events.length; i++) {
if (fnString === events[i].toString()) { if (fn === events[i]) {
events.splice(i, 1); events.splice(i, 1);
break; break;
} }
@ -1269,7 +1268,7 @@
} }
}, },
function(err) { function(err) {
obj.on('loaderror'); obj.on('loaderror', err);
} }
); );
}; };

File diff suppressed because one or more lines are too long

View file

@ -16,7 +16,7 @@
"url": "git://github.com/goldfire/howler.js.git" "url": "git://github.com/goldfire/howler.js.git"
}, },
"main": "howler.js", "main": "howler.js",
"version": "1.1.27", "version": "1.1.29",
"license": { "license": {
"type": "MIT", "type": "MIT",
"url": "https://raw.githubusercontent.com/goldfire/howler.js/master/LICENSE.md" "url": "https://raw.githubusercontent.com/goldfire/howler.js/master/LICENSE.md"

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-icons", "name": "iron-icons",
"version": "1.1.1", "version": "1.1.2",
"description": "A set of icons for use with iron-icon", "description": "A set of icons for use with iron-icon",
"authors": [ "authors": [
"The Polymer Authors" "The Polymer Authors"
@ -28,17 +28,18 @@
"iron-component-page": "polymerelements/iron-component-page#1.0.0", "iron-component-page": "polymerelements/iron-component-page#1.0.0",
"iron-flex-layout": "polymerelements/iron-flex-layout#^1.0.0", "iron-flex-layout": "polymerelements/iron-flex-layout#^1.0.0",
"iron-meta": "polymerelements/iron-meta#^1.0.0", "iron-meta": "polymerelements/iron-meta#^1.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
"web-component-tester": "^4.0.0"
}, },
"ignore": [ "ignore": [
"util", "util",
"update-icons.sh" "update-icons.sh"
], ],
"_release": "1.1.1", "_release": "1.1.2",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.1.1", "tag": "v1.1.2",
"commit": "77a8e0190d6c481d8b5df0495fa484928880ea53" "commit": "14a4138f7da753ee8bebeb9ed4abd6053b2496dd"
}, },
"_source": "git://github.com/PolymerElements/iron-icons.git", "_source": "git://github.com/PolymerElements/iron-icons.git",
"_target": "^1.0.0", "_target": "^1.0.0",

View file

@ -1,22 +1,25 @@
language: node_js language: node_js
sudo: false sudo: false
before_script: before_script:
- npm install web-component-tester - npm install -g bower polylint web-component-tester
- npm install bower
- 'export PATH=$PWD/node_modules/.bin:$PATH'
- bower install - bower install
- polylint
env: env:
global: global:
- secure: itlu3qIX/3ggZQIuzTJc62A5MD2Rdms+zB1EvNEWFiQZQgNGu2+hhp72PcVB/urybOTFmMeq4W12RGr53KMvwj6mwNlXPhQxeP1oyR+icZZVbuLDfj5pF8OvNf4OXEkGv0yH+OTuNTB8CU4msJzgB2W8iuC+pFH/dIas6fQDTfE= - secure: itlu3qIX/3ggZQIuzTJc62A5MD2Rdms+zB1EvNEWFiQZQgNGu2+hhp72PcVB/urybOTFmMeq4W12RGr53KMvwj6mwNlXPhQxeP1oyR+icZZVbuLDfj5pF8OvNf4OXEkGv0yH+OTuNTB8CU4msJzgB2W8iuC+pFH/dIas6fQDTfE=
- secure: LBT0VumsEPWUYm0OLhqHU1XWmVY18QP64cMeqZAwASnYYyH/R5OGYAcI7aH8To29FWpkZSL85NPto37bN+f8DWRSULq4p+1wl2HviYHsam8x1NzN7hKq6nv+203qaT9SflheaNy6sSDfZJQ+36bRcGQ5khKkVeDpw7h8D/osSQ4= - secure: LBT0VumsEPWUYm0OLhqHU1XWmVY18QP64cMeqZAwASnYYyH/R5OGYAcI7aH8To29FWpkZSL85NPto37bN+f8DWRSULq4p+1wl2HviYHsam8x1NzN7hKq6nv+203qaT9SflheaNy6sSDfZJQ+36bRcGQ5khKkVeDpw7h8D/osSQ4=
node_js: 4 - CXX=g++-4.8
node_js: stable
addons: addons:
firefox: latest firefox: latest
apt: apt:
sources: sources:
- google-chrome - google-chrome
- ubuntu-toolchain-r-test
packages: packages:
- google-chrome-stable - google-chrome-stable
- g++-4.8
sauce_connect: true
script: script:
- xvfb-run wct - xvfb-run wct
- "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi" - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-icons", "name": "iron-icons",
"version": "1.1.1", "version": "1.1.2",
"description": "A set of icons for use with iron-icon", "description": "A set of icons for use with iron-icon",
"authors": [ "authors": [
"The Polymer Authors" "The Polymer Authors"
@ -28,7 +28,8 @@
"iron-component-page": "polymerelements/iron-component-page#1.0.0", "iron-component-page": "polymerelements/iron-component-page#1.0.0",
"iron-flex-layout": "polymerelements/iron-flex-layout#^1.0.0", "iron-flex-layout": "polymerelements/iron-flex-layout#^1.0.0",
"iron-meta": "polymerelements/iron-meta#^1.0.0", "iron-meta": "polymerelements/iron-meta#^1.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
"web-component-tester": "^4.0.0"
}, },
"ignore": [ "ignore": [
"util", "util",

View file

@ -28,7 +28,7 @@ See [iron-icon](#iron-icon) for more information about working with icons.
See [iron-iconset](#iron-iconset) and [iron-iconset-svg](#iron-iconset-svg) for more information about how to create a custom iconset. See [iron-iconset](#iron-iconset) and [iron-iconset-svg](#iron-iconset-svg) for more information about how to create a custom iconset.
@group Polymer Core Elements @group Polymer Core Elements
@element iron-icons @pseudoElement iron-icons
@homepage polymer.github.io @homepage polymer.github.io
--> -->
<link rel="import" href="../iron-icon/iron-icon.html"> <link rel="import" href="../iron-icon/iron-icon.html">

View file

@ -1,7 +1,7 @@
{ {
"name": "neon-animation", "name": "neon-animation",
"description": "A system for animating Polymer-based web components", "description": "A system for animating Polymer-based web components",
"version": "1.0.9", "version": "1.1.0",
"authors": [ "authors": [
"The Polymer Authors" "The Polymer Authors"
], ],
@ -34,7 +34,6 @@
"iron-meta": "PolymerElements/iron-meta#^1.0.0", "iron-meta": "PolymerElements/iron-meta#^1.0.0",
"iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0", "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
"iron-selector": "PolymerElements/iron-selector#^1.0.0", "iron-selector": "PolymerElements/iron-selector#^1.0.0",
"paper-styles": "PolymerElements/paper-styles#^1.0.0",
"web-animations-js": "web-animations/web-animations-js#2.1.3" "web-animations-js": "web-animations/web-animations-js#2.1.3"
}, },
"devDependencies": { "devDependencies": {
@ -42,18 +41,19 @@
"paper-toolbar": "PolymerElements/paper-toolbar#^1.0.0", "paper-toolbar": "PolymerElements/paper-toolbar#^1.0.0",
"iron-component-page": "PolymerElements/iron-component-page#^1.0.0", "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
"test-fixture": "PolymerElements/test-fixture#^1.0.0", "test-fixture": "PolymerElements/test-fixture#^1.0.0",
"web-component-tester": "*", "web-component-tester": "^4.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0", "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
"paper-item": "PolymerElements/paper-item#^1.0.0", "paper-item": "PolymerElements/paper-item#^1.0.0",
"paper-styles": "PolymerElements/paper-styles#^1.0.0",
"iron-icon": "PolymerElements/iron-icon#^1.0.0", "iron-icon": "PolymerElements/iron-icon#^1.0.0",
"iron-icons": "PolymerElements/iron-icons#^1.0.0", "iron-icons": "PolymerElements/iron-icons#^1.0.0",
"paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0" "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0"
}, },
"_release": "1.0.9", "_release": "1.1.0",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.9", "tag": "v1.1.0",
"commit": "ab40f4e4a777153cb5c27c9b62ee82b94d53eb76" "commit": "564e0dc92724f2bc0bf0f76bf2ac392d4905b2ff"
}, },
"_source": "git://github.com/polymerelements/neon-animation.git", "_source": "git://github.com/polymerelements/neon-animation.git",
"_target": "^1.0.0", "_target": "^1.0.0",

View file

@ -1,18 +1,20 @@
language: node_js language: node_js
sudo: false sudo: false
node_js: 4 node_js: stable
addons: addons:
firefox: latest firefox: latest
apt: apt:
sources: sources:
- google-chrome - google-chrome
- ubuntu-toolchain-r-test
packages: packages:
- google-chrome-stable - google-chrome-stable
- g++-4.8
sauce_connect: true
before_script: before_script:
- npm install web-component-tester - npm install -g bower polylint web-component-tester
- npm install bower
- 'export PATH=$PWD/node_modules/.bin:$PATH'
- bower install - bower install
- polylint
script: script:
- xvfb-run wct - xvfb-run wct
- "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi" - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
@ -20,3 +22,4 @@ env:
global: global:
- secure: AnPpB3uzTWU0hmrDmPyOb/3mJZRv4BgPFJrpaT/mQ/9979IBeFfFHJX6MqQlgo894lJWvKSvAjEutgK5Z3LQh6cLB3JuhPBInwKgFPUx/V14VIju+Z7jwx6RycE3flb2f9Y6y5My13ovswsTNnhJEkpDGlbRnJlh5c+HeP+6D0oFPFaGWvULZsAHQnEykir1TMPL2TD8SfuYWifmBj7QYQ2vsYnqZoAkPNedv/OtdoA3rziFXSG3GqXX2NJVnYqlaLj/HiHK7xLlZu/ODfo6En12DMtqJajBP7NfJkEUAF72ScOsYxlwiI1aYcVSUy6upkxxPwkBj5x7wDZ0tRFmlautyq2skDAh/fgIfRw9AMe8kj/YLef+T8bmZNT9IIelNaNcpfTQHpYWcOpPk2uBT3iIOcmp+Ys8RZKqzYmekBtHTwCGmQcfQrjBXjrjz5xlUaoMH7vauh7Ct7SkD7Fu87XSUvks4v2yypxxmHXO8jUilKuUdtAzb3dtOboO0ptsoLuBm/qSeURco4be6KPyVnDxdWdbYOxIZtE8JeY2DbonS45OgFtL1NKeEIhiTQIcOuSs0qwJFFzaBBAfek1tkTvBhMJP3JPWpIbNJhdZWzSd0LUSe892sbiZJY67FA4xcY8vK5JZNWnxFyKX1+A8ljPEd1yBImxMzUDMNS9t0G0= - secure: AnPpB3uzTWU0hmrDmPyOb/3mJZRv4BgPFJrpaT/mQ/9979IBeFfFHJX6MqQlgo894lJWvKSvAjEutgK5Z3LQh6cLB3JuhPBInwKgFPUx/V14VIju+Z7jwx6RycE3flb2f9Y6y5My13ovswsTNnhJEkpDGlbRnJlh5c+HeP+6D0oFPFaGWvULZsAHQnEykir1TMPL2TD8SfuYWifmBj7QYQ2vsYnqZoAkPNedv/OtdoA3rziFXSG3GqXX2NJVnYqlaLj/HiHK7xLlZu/ODfo6En12DMtqJajBP7NfJkEUAF72ScOsYxlwiI1aYcVSUy6upkxxPwkBj5x7wDZ0tRFmlautyq2skDAh/fgIfRw9AMe8kj/YLef+T8bmZNT9IIelNaNcpfTQHpYWcOpPk2uBT3iIOcmp+Ys8RZKqzYmekBtHTwCGmQcfQrjBXjrjz5xlUaoMH7vauh7Ct7SkD7Fu87XSUvks4v2yypxxmHXO8jUilKuUdtAzb3dtOboO0ptsoLuBm/qSeURco4be6KPyVnDxdWdbYOxIZtE8JeY2DbonS45OgFtL1NKeEIhiTQIcOuSs0qwJFFzaBBAfek1tkTvBhMJP3JPWpIbNJhdZWzSd0LUSe892sbiZJY67FA4xcY8vK5JZNWnxFyKX1+A8ljPEd1yBImxMzUDMNS9t0G0=
- secure: jdh0G/FDRghnjasav0/8nOZsYgXUd5DLKgD5XrDCVrBvPwXly+AnMXE+Hr/bztEXylcEmcqrWUUfB1ODUdVn1EGk8CJaYpHyKcoMcpJiEjHYS/3i1rXRsnHs2o3dcRO69rA8A5LZeG3yYfiPVUiKlyl7MWOal3pNohDGi8dZcT0CoWnA8UaV//0uXG3GGG3X8KcbVfB2hQvG1mK6wM6W4eHVOplcBaE2xnnFDMxfU2KnRgjLSPw66PeJGczWOBR9fZql9p6kV38ZM2s4qnUsMlTZkNqn0f6CuEPqcG6+S6Tk9+0dvAHet+Ky9fgiyJPq+p6sDGfdm1ZJwOjz5MoyudzGSuHAJHH2nscQf8pUBQ1gxKaGg7GV9LUj0cjLDAFWA2KpxTlabDZhZPIMoMKFpqpvJG49gDVga5gGabom21nd/+E1i/2vvoP16kY9rjf+Gd5+tIzajXCu8Tq06Xz63idZDJbt38GjArfFFqe5k7CqE+m2vpWx/iTwe+cT70wnIq/xigvaNq6CgUuNdzkVnVBj/C7yVqwwZkfbBC7HhRna9Nyzts/j2M2vwy0oYB73WzuhpYSweaAOZq2kcUIQ5ZMGO3UkZRjwWnHxAi5mrvZhRcRIqkvJJhoMQnjwJSTah/3cz0cJh19DL+Ozde24/tuY+vOnhFb+ddo1OKD6FtM= - secure: jdh0G/FDRghnjasav0/8nOZsYgXUd5DLKgD5XrDCVrBvPwXly+AnMXE+Hr/bztEXylcEmcqrWUUfB1ODUdVn1EGk8CJaYpHyKcoMcpJiEjHYS/3i1rXRsnHs2o3dcRO69rA8A5LZeG3yYfiPVUiKlyl7MWOal3pNohDGi8dZcT0CoWnA8UaV//0uXG3GGG3X8KcbVfB2hQvG1mK6wM6W4eHVOplcBaE2xnnFDMxfU2KnRgjLSPw66PeJGczWOBR9fZql9p6kV38ZM2s4qnUsMlTZkNqn0f6CuEPqcG6+S6Tk9+0dvAHet+Ky9fgiyJPq+p6sDGfdm1ZJwOjz5MoyudzGSuHAJHH2nscQf8pUBQ1gxKaGg7GV9LUj0cjLDAFWA2KpxTlabDZhZPIMoMKFpqpvJG49gDVga5gGabom21nd/+E1i/2vvoP16kY9rjf+Gd5+tIzajXCu8Tq06Xz63idZDJbt38GjArfFFqe5k7CqE+m2vpWx/iTwe+cT70wnIq/xigvaNq6CgUuNdzkVnVBj/C7yVqwwZkfbBC7HhRna9Nyzts/j2M2vwy0oYB73WzuhpYSweaAOZq2kcUIQ5ZMGO3UkZRjwWnHxAi5mrvZhRcRIqkvJJhoMQnjwJSTah/3cz0cJh19DL+Ozde24/tuY+vOnhFb+ddo1OKD6FtM=
- CXX=g++-4.8

View file

@ -22,7 +22,7 @@ Configuration:
name: 'cascaded-animation', name: 'cascaded-animation',
animation: <animation-name>, animation: <animation-name>,
nodes: <array-of-nodes>, nodes: <array-of-nodes>,
nodedelay: <node-delay-in-ms>, nodeDelay: <node-delay-in-ms>,
timing: <animation-timing> timing: <animation-timing>
} }
``` ```

View file

@ -47,8 +47,8 @@ Configuration:
} }
this._effect = new KeyframeEffect(node, [ this._effect = new KeyframeEffect(node, [
{'transform': 'translateY(-100%)'}, {'transform': 'translateY(0%)'},
{'transform': 'none'} {'transform': 'translateY(100%)'}
], this.timingFromConfig(config)); ], this.timingFromConfig(config));
return this._effect; return this._effect;

View file

@ -0,0 +1,59 @@
<!--
@license
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../../polymer/polymer.html">
<link rel="import" href="../neon-animation-behavior.html">
<link rel="import" href="../web-animations.html">
<!--
`<slide-from-bottom-animation>` animates the transform of an element from `none` to `translateY(100%)`.
The `transformOrigin` defaults to `50% 0`.
Configuration:
```
{
name: 'slide-from-bottom-animation',
node: <node>,
transformOrigin: <transform-origin>,
timing: <animation-timing>
}
```
-->
<script>
Polymer({
is: 'slide-from-bottom-animation',
behaviors: [
Polymer.NeonAnimationBehavior
],
configure: function(config) {
var node = config.node;
if (config.transformOrigin) {
this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
} else {
this.setPrefixedProperty(node, 'transformOrigin', '50% 0');
}
this._effect = new KeyframeEffect(node, [
{'transform': 'translateY(100%)'},
{'transform': 'translateY(0)'}
], this.timingFromConfig(config));
return this._effect;
}
});
</script>

View file

@ -0,0 +1,59 @@
<!--
@license
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../../polymer/polymer.html">
<link rel="import" href="../neon-animation-behavior.html">
<link rel="import" href="../web-animations.html">
<!--
`<slide-from-top-animation>` animates the transform of an element from `translateY(-100%)` to
`none`. The `transformOrigin` defaults to `50% 0`.
Configuration:
```
{
name: 'slide-from-top-animation',
node: <node>,
transformOrigin: <transform-origin>,
timing: <animation-timing>
}
```
-->
<script>
Polymer({
is: 'slide-from-top-animation',
behaviors: [
Polymer.NeonAnimationBehavior
],
configure: function(config) {
var node = config.node;
if (config.transformOrigin) {
this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
} else {
this.setPrefixedProperty(node, 'transformOrigin', '50% 0');
}
this._effect = new KeyframeEffect(node, [
{'transform': 'translateY(-100%)'},
{'transform': 'translateY(0%)'}
], this.timingFromConfig(config));
return this._effect;
}
});
</script>

View file

@ -1,7 +1,7 @@
{ {
"name": "neon-animation", "name": "neon-animation",
"description": "A system for animating Polymer-based web components", "description": "A system for animating Polymer-based web components",
"version": "1.0.9", "version": "1.1.0",
"authors": [ "authors": [
"The Polymer Authors" "The Polymer Authors"
], ],
@ -34,7 +34,6 @@
"iron-meta": "PolymerElements/iron-meta#^1.0.0", "iron-meta": "PolymerElements/iron-meta#^1.0.0",
"iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0", "iron-resizable-behavior": "PolymerElements/iron-resizable-behavior#^1.0.0",
"iron-selector": "PolymerElements/iron-selector#^1.0.0", "iron-selector": "PolymerElements/iron-selector#^1.0.0",
"paper-styles": "PolymerElements/paper-styles#^1.0.0",
"web-animations-js": "web-animations/web-animations-js#2.1.3" "web-animations-js": "web-animations/web-animations-js#2.1.3"
}, },
"devDependencies": { "devDependencies": {
@ -42,9 +41,10 @@
"paper-toolbar": "PolymerElements/paper-toolbar#^1.0.0", "paper-toolbar": "PolymerElements/paper-toolbar#^1.0.0",
"iron-component-page": "PolymerElements/iron-component-page#^1.0.0", "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
"test-fixture": "PolymerElements/test-fixture#^1.0.0", "test-fixture": "PolymerElements/test-fixture#^1.0.0",
"web-component-tester": "*", "web-component-tester": "^4.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0", "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
"paper-item": "PolymerElements/paper-item#^1.0.0", "paper-item": "PolymerElements/paper-item#^1.0.0",
"paper-styles": "PolymerElements/paper-styles#^1.0.0",
"iron-icon": "PolymerElements/iron-icon#^1.0.0", "iron-icon": "PolymerElements/iron-icon#^1.0.0",
"iron-icons": "PolymerElements/iron-icons#^1.0.0", "iron-icons": "PolymerElements/iron-icons#^1.0.0",
"paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0" "paper-icon-button": "PolymerElements/paper-icon-button#^1.0.0"

View file

@ -32,7 +32,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
} }
.toolbar { .toolbar {
position: relative;
padding: 8px; padding: 8px;
background-color: white;
z-index: 12;
} }
neon-animated-pages { neon-animated-pages {
@ -74,8 +80,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<template is="dom-bind"> <template is="dom-bind">
<div class="toolbar"> <div class="toolbar">
<button on-click="_onPrevClick">&lt;&lt;</button> <button on-click="_onPrevClick">&#8678;</button>
<button on-click="_onNextClick">&gt;&gt;</button> <button on-click="_onNextClick">&#8680;</button>
<button on-click="_onUpClick">&#8679;</button>
<button on-click="_onDownClick">&#8681;</button>
</div> </div>
<neon-animated-pages id="pages" selected="[[selected]]" entry-animation="[[entryAnimation]]" exit-animation="[[exitAnimation]]"> <neon-animated-pages id="pages" selected="[[selected]]" entry-animation="[[entryAnimation]]" exit-animation="[[exitAnimation]]">
@ -105,6 +113,18 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
this.selected = this.selected === 4 ? 0 : (this.selected + 1); this.selected = this.selected === 4 ? 0 : (this.selected + 1);
} }
scope._onUpClick = function() {
this.entryAnimation = 'slide-from-top-animation';
this.exitAnimation = 'slide-down-animation';
this.selected = this.selected === 4 ? 0 : (this.selected + 1);
}
scope._onDownClick = function() {
this.entryAnimation = 'slide-from-bottom-animation';
this.exitAnimation = 'slide-up-animation';
this.selected = this.selected === 0 ? 4 : (this.selected - 1);
}
</script> </script>
</body> </body>

View file

@ -39,7 +39,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<template is="dom-bind"> <template is="dom-bind">
<neon-animated-pages id="pages" selected="0"> <neon-animated-pages id="pages" selected="0">
<animated-grid on-tile-click="_onTileClick"></animated-grid> <animated-grid on-tile-click="_onTileClick"></animated-grid>
<fullsize-page-with-card id="fullsize-card" hero-id="hero" on-click="_onFullsizeClick"> <fullsize-page-with-card id="fullsize-card" on-click="_onFullsizeClick">
</fullsize-page-with-card> </fullsize-page-with-card>
</neon-animated-pages> </neon-animated-pages>
</template> </template>

View file

@ -280,12 +280,14 @@ The new page will slide in from the right, and the old page slide away to the le
Single element animations: Single element animations:
* `fade-in-animation` Animates opacity from `0` to `1`. * `fade-in-animation` Animates opacity from `0` to `1`;
* `fade-out-animation` Animates opacity from `1` to `0`. * `fade-out-animation` Animates opacity from `1` to `0`;
* `scale-down-animation` Animates transform from `scale(1)` to `scale(0)`. * `scale-down-animation` Animates transform from `scale(1)` to `scale(0)`;
* `scale-up-animation` Animates transform from `scale(0)` to `scale(1)`. * `scale-up-animation` Animates transform from `scale(0)` to `scale(1)`;
* `slide-down-animation` Animates transform from `translateY(-100%)` to `none`. * `slide-down-animation` Animates transform from `none` to `translateY(100%)`;
* `slide-up-animation` Animates transform from `none` to `translateY(-100%)`. * `slide-up-animation` Animates transform from `none` to `translateY(-100%)`;
* `slide-from-top-animation` Animates transform from `translateY(-100%)` to `none`;
* `slide-from-bottom-animation` Animates transform from `translateY(100%)` to `none`;
* `slide-left-animation` Animates transform from `none` to `translateX(-100%)`; * `slide-left-animation` Animates transform from `none` to `translateX(-100%)`;
* `slide-right-animation` Animates transform from `none` to `translateX(100%)`; * `slide-right-animation` Animates transform from `none` to `translateX(100%)`;
* `slide-from-left-animation` Animates transform from `translateX(-100%)` to `none`; * `slide-from-left-animation` Animates transform from `translateX(-100%)` to `none`;

View file

@ -95,6 +95,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
return; return;
} }
if(this.animationConfig.value && typeof this.animationConfig.value === 'function') {
this._warn(this._logf('playAnimation', "Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));
return;
}
// type is optional // type is optional
var thisConfig; var thisConfig;
if (type) { if (type) {

View file

@ -8,6 +8,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
--> -->
<link rel="import" href="../polymer/polymer.html"> <link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../iron-resizable-behavior/iron-resizable-behavior.html">
<link rel="import" href="neon-animatable-behavior.html"> <link rel="import" href="neon-animatable-behavior.html">
<!-- <!--

View file

@ -213,7 +213,7 @@ animations to be run when switching to or switching out of the page.
}, },
_notifyPageResize: function() { _notifyPageResize: function() {
var selectedPage = this.selectedItem; var selectedPage = this.selectedItem || this._valueToItem(this.selected);
this.resizerShouldNotify = function(element) { this.resizerShouldNotify = function(element) {
return element == selectedPage; return element == selectedPage;
} }

View file

@ -18,6 +18,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<link rel="import" href="animations/scale-up-animation.html"> <link rel="import" href="animations/scale-up-animation.html">
<link rel="import" href="animations/slide-from-left-animation.html"> <link rel="import" href="animations/slide-from-left-animation.html">
<link rel="import" href="animations/slide-from-right-animation.html"> <link rel="import" href="animations/slide-from-right-animation.html">
<link rel="import" href="animations/slide-from-top-animation.html">
<link rel="import" href="animations/slide-from-bottom-animation.html">
<link rel="import" href="animations/slide-left-animation.html"> <link rel="import" href="animations/slide-left-animation.html">
<link rel="import" href="animations/slide-right-animation.html"> <link rel="import" href="animations/slide-right-animation.html">
<link rel="import" href="animations/slide-up-animation.html"> <link rel="import" href="animations/slide-up-animation.html">

View file

@ -1,14 +1,11 @@
<!doctype html> <!DOCTYPE html><!--
<!--
Copyright (c) 2015 The Polymer Project Authors. All rights reserved. Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
--> --><html><head>
<html>
<head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes"> <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>neon-animation tests</title> <title>neon-animation tests</title>
@ -17,8 +14,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<body> <body>
<script> <script>
WCT.loadSuites([ WCT.loadSuites([
'neon-animated-pages.html' 'neon-animated-pages.html',
'neon-animated-pages.html?dom=shadow'
]); ]);
</script> </script>
</body>
</html>
</body></html>

View file

@ -1,6 +1,6 @@
{ {
"name": "paper-material", "name": "paper-material",
"version": "1.0.5", "version": "1.0.6",
"description": "A material design container that looks like a lifted sheet of paper", "description": "A material design container that looks like a lifted sheet of paper",
"private": true, "private": true,
"authors": [ "authors": [
@ -27,15 +27,16 @@
}, },
"devDependencies": { "devDependencies": {
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0", "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
"web-component-tester": "polymer/web-component-tester#^3.4.0", "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
"web-component-tester": "^4.0.0",
"test-fixture": "polymerelements/test-fixture#^1.0.0", "test-fixture": "polymerelements/test-fixture#^1.0.0",
"iron-component-page": "PolymerElements/iron-component-page#^1.0.0" "iron-component-page": "PolymerElements/iron-component-page#^1.0.0"
}, },
"_release": "1.0.5", "_release": "1.0.6",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.5", "tag": "v1.0.6",
"commit": "8a906004d8d0071004aafcd4bc4536ed2cf14bde" "commit": "6aef0896fcbc25f9f5bd1dd55f7679e6ab7f92ad"
}, },
"_source": "git://github.com/polymerelements/paper-material.git", "_source": "git://github.com/polymerelements/paper-material.git",
"_target": "^1.0.0", "_target": "^1.0.0",

View file

@ -1,22 +1,25 @@
language: node_js language: node_js
sudo: false sudo: false
before_script: before_script:
- npm install web-component-tester - npm install -g bower polylint web-component-tester
- npm install bower
- 'export PATH=$PWD/node_modules/.bin:$PATH'
- bower install - bower install
- polylint
env: env:
global: global:
- secure: PEaqY+YpV0ZhnQbJlNQbmfIFLqy7UvvCtii0sPoGKT5/P7ulMqMOPQV9l/zLAtYi14HEz63FKLqDrpnGaVe7Cz7jtt2WRWrWqTBdarqwSHs73Z2XqztD1+2wW6vgz/lfK00B8UplAk28B7d5dbWzwUF6Kg02zOfQMsawMpulFjo= - secure: PEaqY+YpV0ZhnQbJlNQbmfIFLqy7UvvCtii0sPoGKT5/P7ulMqMOPQV9l/zLAtYi14HEz63FKLqDrpnGaVe7Cz7jtt2WRWrWqTBdarqwSHs73Z2XqztD1+2wW6vgz/lfK00B8UplAk28B7d5dbWzwUF6Kg02zOfQMsawMpulFjo=
- secure: f/3XYrYjM8aXLe9kqM/MjHQ6IEsDRuoxDqM+l2JiR3v2Nw7lP6ZyXSNvKm8bN+VNU7ubSzAmRbUGnRU7e61BhnGzuLXjOqxYeJLWZaqoSm9TDz3re3rd7wB2ddAhRokeSSPO2KeAgr6C02P9M3Au1DiO1G66fuWVH62WtzW4+qY= - secure: f/3XYrYjM8aXLe9kqM/MjHQ6IEsDRuoxDqM+l2JiR3v2Nw7lP6ZyXSNvKm8bN+VNU7ubSzAmRbUGnRU7e61BhnGzuLXjOqxYeJLWZaqoSm9TDz3re3rd7wB2ddAhRokeSSPO2KeAgr6C02P9M3Au1DiO1G66fuWVH62WtzW4+qY=
node_js: 4 - CXX=g++-4.8
node_js: stable
addons: addons:
firefox: latest firefox: latest
apt: apt:
sources: sources:
- google-chrome - google-chrome
- ubuntu-toolchain-r-test
packages: packages:
- google-chrome-stable - google-chrome-stable
- g++-4.8
sauce_connect: true
script: script:
- xvfb-run wct - xvfb-run wct
- "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi" - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"

View file

@ -1,6 +1,6 @@
{ {
"name": "paper-material", "name": "paper-material",
"version": "1.0.5", "version": "1.0.6",
"description": "A material design container that looks like a lifted sheet of paper", "description": "A material design container that looks like a lifted sheet of paper",
"private": true, "private": true,
"authors": [ "authors": [
@ -27,7 +27,8 @@
}, },
"devDependencies": { "devDependencies": {
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0", "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
"web-component-tester": "polymer/web-component-tester#^3.4.0", "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
"web-component-tester": "^4.0.0",
"test-fixture": "polymerelements/test-fixture#^1.0.0", "test-fixture": "polymerelements/test-fixture#^1.0.0",
"iron-component-page": "PolymerElements/iron-component-page#^1.0.0" "iron-component-page": "PolymerElements/iron-component-page#^1.0.0"
} }

View file

@ -17,82 +17,52 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes"> <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
<script src="../../webcomponentsjs/webcomponents-lite.js"></script> <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="../../iron-flex-layout/iron-flex-layout.html"> <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
<link rel="import" href="../../paper-styles/typography.html"> <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
<link rel="import" href="../paper-material.html"> <link rel="import" href="../paper-material.html">
<link rel="stylesheet" href="../../paper-styles/demo.css">
</head> <style is="custom-style" include="demo-pages-shared-styles">
<body unresolved>
<template is="dom-bind" id="demo">
<style is="custom-style">
paper-material { paper-material {
display: inline-block; display: inline-block;
background: white; background: white;
box-sizing: border-box; box-sizing: border-box;
margin: 16px; margin: 8px;
padding: 16px; padding: 16px;
border-radius: 2px; border-radius: 2px;
} }
.fab {
display: inline-block;
background: white;
box-sizing: border-box;
width: 56px;
height: 56px;
margin: 16px;
padding: 16px;
border-radius: 50%;
text-align: center;
cursor: pointer;
@apply(--layout-center-center);
}
</style> </style>
<section> </head>
<div>Paper Elevations</div> <body unresolved>
<div class="vertical-section-container centered">
<paper-material elevation="0"> <h3>Paper-materials can have different elevations</h3>
elevation = 0 <demo-snippet class="centered-demo">
</paper-material> <template>
<paper-material elevation="0">0</paper-material>
<paper-material elevation="1"> <paper-material elevation="1">1</paper-material>
elevation = 1 <paper-material elevation="2">2</paper-material>
</paper-material> <paper-material elevation="3">3</paper-material>
<paper-material elevation="4">4</paper-material>
<paper-material elevation="2"> <paper-material elevation="5">5</paper-material>
elevation = 2
</paper-material>
<paper-material elevation="3">
elevation = 3
</paper-material>
<paper-material elevation="4">
elevation = 4
</paper-material>
<paper-material elevation="5">
elevation = 5
</paper-material>
</section>
<section on-click="tapAction">
<div>Animated</div>
<paper-material elevation="0" animated>
tap
</paper-material>
<paper-material class="fab" elevation="0" animated>
tap
</paper-material>
</section>
</template> </template>
</demo-snippet>
<h3>Changes in elevation can be animated</h3>
<demo-snippet class="centered-demo">
<template>
<style>
#a1, #a2 { cursor: pointer; }
</style>
Tap each of these boxes!
<div>
<paper-material elevation="0" animated id="a1">animated</paper-material>
<paper-material elevation="3" id="a2">not animated</paper-material>
</div>
<script> <script>
document.addEventListener('WebComponentsReady', function() {
demo.tapAction = function(e) { a1.addEventListener('click', _onTap);
a2.addEventListener('click', _onTap);
});
function _onTap(e) {
var target = e.target; var target = e.target;
if (!target.down) { if (!target.down) {
target.elevation += 1; target.elevation += 1;
@ -106,8 +76,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
} }
} }
}; };
</script> </script>
</template>
</demo-snippet>
</div>
</body> </body>
</html> </html>

View file

@ -8,6 +8,8 @@ Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
--> -->
<link rel="import" href="../paper-styles/shadow.html">
<dom-module id="paper-material-shared-styles"> <dom-module id="paper-material-shared-styles">
<template> <template>
<style> <style>

View file

@ -1,4 +1,4 @@
define(['components/paperdialoghelper', 'paper-checkbox', 'paper-dialog', 'paper-input'], function (paperDialogHelper) { define(['components/paperdialoghelper', 'paper-checkbox', 'paper-dialog', 'paper-input', 'paper-item-body', 'paper-icon-item'], function (paperDialogHelper) {
var currentDialog; var currentDialog;
var metadataEditorInfo; var metadataEditorInfo;
@ -43,6 +43,45 @@
return false; return false;
} }
function parentWithClass(elem, className) {
while (!elem.classList || !elem.classList.contains(className)) {
elem = elem.parentNode;
if (!elem) {
return null;
}
}
return elem;
}
function editableListViewValues(list) {
return list.find('.textValue').map(function () { return $(this).text(); }).get();
}
function addElementToEditableListview(source, sortCallback) {
require(['prompt'], function (prompt) {
prompt({
text: 'Value:',
callback: function (text) {
if (text == '') return;
var parent = $(source).parents('.editableListviewContainer');
var list = parent.find('.paperList');
var items = editableListViewValues(list);
items.push(text);
populateListView(list[0], items, sortCallback);
}
});
});
}
function removeElementFromListview(source) {
$(source).parents('paper-icon-item').remove();
}
function init(context) { function init(context) {
$('.btnCancel', context).on('click', function () { $('.btnCancel', context).on('click', function () {
@ -50,6 +89,20 @@
closeDialog(false); closeDialog(false);
}); });
context.addEventListener('click', function (e) {
var btnRemoveFromEditorList = parentWithClass(e.target, 'btnRemoveFromEditorList');
if (btnRemoveFromEditorList) {
removeElementFromListview(btnRemoveFromEditorList);
}
var btnAddTextItem = parentWithClass(e.target, 'btnAddTextItem');
if (btnAddTextItem) {
addElementToEditableListview(btnAddTextItem);
}
});
$('form', context).off('submit', onSubmit).on('submit', onSubmit); $('form', context).off('submit', onSubmit).on('submit', onSubmit);
} }
@ -339,13 +392,13 @@
if (item.Type == "Person") { if (item.Type == "Person") {
context.querySelector('#txtProductionYear').label = Globalize.translate('LabelBirthYear'); context.querySelector('#txtProductionYear').label = Globalize.translate('LabelBirthYear');
context.querySelector("label[for='txtPremiereDate']").innerHTML = Globalize.translate('LabelBirthDate'); context.querySelector("#txtPremiereDate").innerHTML = Globalize.translate('LabelBirthDate');
context.querySelector("label[for='txtEndDate']").innerHTML = Globalize.translate('LabelDeathDate'); context.querySelector("#txtEndDate").innerHTML = Globalize.translate('LabelDeathDate');
$('#fldPlaceOfBirth', context).show(); $('#fldPlaceOfBirth', context).show();
} else { } else {
context.querySelector('#txtProductionYear').label = Globalize.translate('LabelYear'); context.querySelector('#txtProductionYear').label = Globalize.translate('LabelYear');
context.querySelector("label[for='txtPremiereDate']").innerHTML = Globalize.translate('LabelReleaseDate'); context.querySelector("#txtPremiereDate").innerHTML = Globalize.translate('LabelReleaseDate');
context.querySelector("label[for='txtEndDate']").innerHTML = Globalize.translate('LabelEndDate'); context.querySelector("#txtEndDate").innerHTML = Globalize.translate('LabelEndDate');
$('#fldPlaceOfBirth', context).hide(); $('#fldPlaceOfBirth', context).hide();
} }
@ -439,14 +492,14 @@
}); });
populateListView($('#listCountries', context), item.ProductionLocations || []); populateListView($('#listCountries', context)[0], item.ProductionLocations || []);
populateListView($('#listGenres', context), item.Genres); populateListView($('#listGenres', context)[0], item.Genres);
populatePeople(context, item.People || []); populatePeople(context, item.People || []);
populateListView($('#listStudios', context), (item.Studios || []).map(function (element) { return element.Name || ''; })); populateListView($('#listStudios', context)[0], (item.Studios || []).map(function (element) { return element.Name || ''; }));
populateListView($('#listTags', context), item.Tags); populateListView($('#listTags', context)[0], item.Tags);
populateListView($('#listKeywords', context), item.Keywords); populateListView($('#listKeywords', context)[0], item.Keywords);
var lockData = (item.LockData || false); var lockData = (item.LockData || false);
var chkLockData = context.querySelector("#chkLockData"); var chkLockData = context.querySelector("#chkLockData");
@ -613,17 +666,35 @@
} }
function populateListView(list, items, sortCallback) { function populateListView(list, items, sortCallback) {
//items = items || [];
//if (typeof (sortCallback) === 'undefined') { items = items || [];
// items.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); }); if (typeof (sortCallback) === 'undefined') {
//} else { items.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); });
// items = sortCallback(items); } else {
//} items = sortCallback(items);
//var html = ''; }
//for (var i = 0; i < items.length; i++) { var html = '';
// html += '<li data-mini="true"><a class="data">' + items[i] + '</a><a href="#" onclick="EditItemMetadataPage.removeElementFromListview(this)" class="btnRemoveFromEditorList"></a></li>'; for (var i = 0; i < items.length; i++) {
//} html += '<paper-icon-item>';
//list.html(html).listview('refresh');
html += '<paper-fab mini style="background-color:#444;" icon="live-tv" item-icon></paper-fab>';
html += '<paper-item-body>';
html += '<div class="textValue">';
html += items[i];
html += '</div>';
html += '</paper-item-body>';
html += '<paper-icon-button icon="delete" data-index="' + i + '" class="btnRemoveFromEditorList"></paper-icon-button>';
html += '</paper-icon-item>';
//html += '<li data-mini="true"><a class="data">' + items[i] + '</a><a href="#" onclick="EditItemMetadataPage.removeElementFromListview(this)" class="btnRemoveFromEditorList"></a></li>';
}
list.innerHTML = html;
} }
function populatePeople(context, people) { function populatePeople(context, people) {
@ -793,7 +864,8 @@
var template = this.response; var template = this.response;
var dlg = paperDialogHelper.createDialog({ var dlg = paperDialogHelper.createDialog({
removeOnClose: true removeOnClose: true,
size: 'small'
}); });
dlg.classList.add('formDialog'); dlg.classList.add('formDialog');

View file

@ -76,9 +76,8 @@
<div id="fldShortOverview" style="display: none;"> <div id="fldShortOverview" style="display: none;">
<paper-input id="txtShortOverview" type="text" label="${LabelShortOverview}"></paper-input> <paper-input id="txtShortOverview" type="text" label="${LabelShortOverview}"></paper-input>
</div> </div>
<div id="fldPremiereDate" style="display: none;"> <div id="fldPremiereDate">
<label for="txtPremiereDate" class="likePaperLabel">${LabelReleaseDate}</label> <paper-input id="txtPremiereDate" label="${LabelReleaseDate}" type="date"></paper-input>
<input id="txtPremiereDate" type="date" class="likePaperText" data-role="none" />
</div> </div>
<div id="fldYear" style="display: none;"> <div id="fldYear" style="display: none;">
<paper-input id="txtProductionYear" type="number" label="${LabelYear}"></paper-input> <paper-input id="txtProductionYear" type="number" label="${LabelYear}"></paper-input>
@ -86,9 +85,8 @@
<div id="fldPlaceOfBirth" style="display: none;"> <div id="fldPlaceOfBirth" style="display: none;">
<paper-input id="txtPlaceOfBirth" type="text" label="${LabelPlaceOfBirth}"></paper-input> <paper-input id="txtPlaceOfBirth" type="text" label="${LabelPlaceOfBirth}"></paper-input>
</div> </div>
<div id="fldEndDate" style="display: none;"> <div id="fldEndDate">
<label for="txtEndDate" class="likePaperLabel">${LabelEndDate}</label> <paper-input id="txtEndDate" label="${LabelEndDate}" type="date"></paper-input>
<input id="txtEndDate" type="date" class="likePaperText" data-role="none" />
</div> </div>
<div id="fldAirDays" style="display: none;"> <div id="fldAirDays" style="display: none;">
<p>${LabelAirDays}</p> <p>${LabelAirDays}</p>
@ -210,74 +208,67 @@
</div> </div>
</div> </div>
<div data-role="collapsible" data-mini="true" id="countriesCollapsible" style="display: none; margin-top: 1em;"> <div id="countriesCollapsible" class="editableListviewContainer" style="display: none; margin-top: 3em;">
<h3>${HeaderCountries}</h3> <h1 style="margin:.6em 0;vertical-align:middle;display:inline-block;">
<div data-role="editableListviewContainer"> ${HeaderCountries}
</h1>
<paper-button raised class="btnAddTextItem submit mini" style="margin-left:1em;" title="${ButtonAdd}">
<iron-icon icon="add"></iron-icon>
<span>${ButtonAdd}</span>
</paper-button>
<div class="paperList" id="listCountries"></div>
</div>
<div id="genresCollapsible" class="editableListviewContainer" style="display: none; margin-top: 3em;">
<h1 style="margin:.6em 0;vertical-align:middle;display:inline-block;">
${HeaderGenres}
</h1>
<paper-button raised class="btnAddTextItem submit mini" style="margin-left:1em;" title="${ButtonAdd}">
<iron-icon icon="add"></iron-icon>
<span>${ButtonAdd}</span>
</paper-button>
<div class="paperList" id="listGenres"></div>
</div>
<div data-mini="true" data-role="collapsible" id="peopleCollapsible" style="display: none; margin-top: 3em;">
<h1 style="margin:.6em 0;vertical-align:middle;display:inline-block;">
${HeaderPeople}
</h1>
<paper-button raised id="btnAddPerson" class="btnAddPerson submit mini" style="margin-left:1em;" title="${ButtonAdd}">
<iron-icon icon="add"></iron-icon>
<span>${ButtonAdd}</span>
</paper-button>
<div> <div>
<div style="display: inline-block; width: 80%;">
<input type="text" class="txtEditableListview" />
</div>
<paper-icon-button icon="add" onclick="EditItemMetadataPage.addElementToEditableListview(this)"></paper-icon-button>
</div>
<ul data-role="listview" data-inset="true" data-split-icon="delete" id="listCountries"></ul>
</div>
</div>
<div data-role="collapsible" data-mini="true" id="genresCollapsible" style="display: none; margin-top: 1em;">
<h3>${HeaderGenres}</h3>
<div data-role="editableListviewContainer">
<div>
<div style="display: inline-block; width: 80%;">
<input type="text" class="txtEditableListview" />
</div>
<paper-icon-button icon="add" onclick="EditItemMetadataPage.addElementToEditableListview(this)"></paper-icon-button>
</div>
<ul data-role="listview" data-inset="true" data-split-icon="delete" id="listGenres"></ul>
</div>
</div>
<div data-mini="true" data-role="collapsible" id="peopleCollapsible" style="display: none; margin-top: 1em;">
<h3>${HeaderPeople}</h3>
<div>
<br />
<button type="button" id="btnAddPerson" data-icon="plus" data-mini="true" data-theme="a">${ButtonAdd}</button>
<br />
<ul data-role="listview" data-inset="true" data-split-icon="delete" id="peopleList"></ul> <ul data-role="listview" data-inset="true" data-split-icon="delete" id="peopleList"></ul>
</div> </div>
</div> </div>
<div data-mini="true" data-role="collapsible" id="keywordsCollapsible" style="display: none; margin-top: 1em;"> <div id="keywordsCollapsible" class="editableListviewContainer" style="display: none; margin-top: 3em;">
<h3>${HeaderPlotKeywords}</h3> <h1 style="margin:.6em 0;vertical-align:middle;display:inline-block;">
<div data-role="editableListviewContainer"> ${HeaderPlotKeywords}
<div> </h1>
<div style="display: inline-block; width: 80%;"> <paper-button raised class="btnAddTextItem submit mini" style="margin-left:1em;" title="${ButtonAdd}">
<input type="text" class="txtEditableListview" /> <iron-icon icon="add"></iron-icon>
<span>${ButtonAdd}</span>
</paper-button>
<div class="paperList" id="listKeywords"></div>
</div> </div>
<paper-icon-button icon="add" onclick="EditItemMetadataPage.addElementToEditableListview(this)"></paper-icon-button> <div id="studiosCollapsible" class="editableListviewContainer" style="display: none; margin-top: 3em;">
</div> <h1 style="margin:.6em 0;vertical-align:middle;display:inline-block;">
<ul data-role="listview" data-inset="true" data-split-icon="delete" id="listKeywords"></ul> ${HeaderStudios}
</div> </h1>
</div> <paper-button raised class="btnAddTextItem submit mini" style="margin-left:1em;" title="${ButtonAdd}">
<div data-role="collapsible" data-mini="true" id="studiosCollapsible" style="display: none; margin-top: 1em;"> <iron-icon icon="add"></iron-icon>
<h3>${HeaderStudios}</h3> <span>${ButtonAdd}</span>
<div data-role="editableListviewContainer"> </paper-button>
<div> <div class="paperList" id="listStudios"></div>
<div style="display: inline-block; width: 80%;">
<input type="text" class="txtEditableListview" />
</div>
<paper-icon-button icon="add" onclick="EditItemMetadataPage.addElementToEditableListview(this)"></paper-icon-button>
</div>
<ul data-role="listview" data-inset="true" data-split-icon="delete" id="listStudios"></ul>
</div>
</div>
<div data-mini="true" data-role="collapsible" id="tagsCollapsible" style="display: none; margin-top: 1em;">
<h3>${HeaderTags}</h3>
<div data-role="editableListviewContainer">
<div>
<div style="display: inline-block; width: 80%;">
<input type="text" class="txtEditableListview" />
</div>
<paper-icon-button icon="add" onclick="EditItemMetadataPage.addElementToEditableListview(this)"></paper-icon-button>
</div>
<ul data-role="listview" data-inset="true" data-split-icon="delete" id="listTags"></ul>
</div> </div>
<div id="tagsCollapsible" class="editableListviewContainer" style="display: none; margin-top: 3em;">
<h1 style="margin:.6em 0;vertical-align:middle;display:inline-block;">
${HeaderTags}
</h1>
<paper-button raised class="btnAddTextItem submit mini" style="margin-left:1em;" title="${ButtonAdd}">
<iron-icon icon="add"></iron-icon>
<span>${ButtonAdd}</span>
</paper-button>
<div class="paperList" id="listTags"></div>
</div> </div>
<div id="metadataSettingsCollapsible" style="display: none; margin-top: 3em;"> <div id="metadataSettingsCollapsible" style="display: none; margin-top: 3em;">
<h1>${HeaderMetadataSettings}</h1> <h1>${HeaderMetadataSettings}</h1>

View file

@ -54,10 +54,6 @@
} }
} }
.largeCardMargin .cardBox {
margin: 10px;
}
.defaultBackground .cardImage { .defaultBackground .cardImage {
background-color: #333; background-color: #333;
} }
@ -338,7 +334,7 @@
} }
.portraitCard { .portraitCard {
width: 33.334%; width: 33.333%;
} }
.overflowPortraitCard { .overflowPortraitCard {
@ -383,11 +379,11 @@
@media all and (min-width: 500px) { @media all and (min-width: 500px) {
.smallBackdropCard { .smallBackdropCard {
width: 33.334%; width: 33.333%;
} }
.squareCard { .squareCard {
width: 33.334%; width: 33.333%;
} }
} }
@ -418,7 +414,7 @@
@media all and (min-width: 770px) { @media all and (min-width: 770px) {
.backdropCard { .backdropCard {
width: 33.334%; width: 33.333%;
} }
} }
@ -477,7 +473,7 @@
} }
.bannerCard { .bannerCard {
width: 33.334%; width: 33.333%;
} }
.portraitCard { .portraitCard {
@ -576,7 +572,7 @@
@media all and (min-width: 800px) { @media all and (min-width: 800px) {
.detailPage169Card { .detailPage169Card {
width: 33.334%; width: 33.333%;
} }
} }
@ -595,7 +591,7 @@
.detailPagePortraitCard { .detailPagePortraitCard {
width: 33.334%; width: 33.333%;
} }
@media all and (min-width: 540px) { @media all and (min-width: 540px) {
@ -621,7 +617,7 @@
.detailPageSquareCard { .detailPageSquareCard {
width: 33.334%; width: 33.333%;
} }
@media all and (min-width: 540px) { @media all and (min-width: 540px) {
@ -644,7 +640,7 @@
@media all and (min-width: 540px) { @media all and (min-width: 540px) {
.homePageSmallBackdropCard { .homePageSmallBackdropCard {
width: 33.334%; width: 33.333%;
} }
} }

View file

@ -1584,7 +1584,6 @@ var AppInfo = {};
AppInfo.enableDetailPageChapters = false; AppInfo.enableDetailPageChapters = false;
AppInfo.enableDetailsMenuImages = false; AppInfo.enableDetailsMenuImages = false;
AppInfo.enableMovieHomeSuggestions = false; AppInfo.enableMovieHomeSuggestions = false;
AppInfo.cardMargin = 'largeCardMargin';
AppInfo.forcedImageFormat = 'jpg'; AppInfo.forcedImageFormat = 'jpg';
} }
@ -1759,10 +1758,6 @@ var AppInfo = {};
elem.classList.add('touch'); elem.classList.add('touch');
} }
if (AppInfo.cardMargin) {
elem.classList.add(AppInfo.cardMargin);
}
if (!AppInfo.enableStudioTabs) { if (!AppInfo.enableStudioTabs) {
elem.classList.add('studioTabDisabled'); elem.classList.add('studioTabDisabled');
} }