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

vulcanize

This commit is contained in:
Luke Pulverenti 2015-06-20 00:48:45 -04:00
parent 07df993238
commit 55e40bdcf7
52 changed files with 12309 additions and 33 deletions

View file

@ -1,24 +0,0 @@
(function (globalScope) {
globalScope.AjaxApi = {
param: function (params) {
return jQuery.param(params);
},
ajax: function (request) {
request.timeout = request.timeout || 30000;
try {
return jQuery.ajax(request);
} catch (err) {
var deferred = DeferredBuilder.Deferred();
deferred.reject();
return deferred.promise();
}
}
};
})(window);

View file

@ -1,126 +0,0 @@
(function (globalScope, angular) {
globalScope.AjaxApi = {
param: function(params) {
return serialize(params);
},
ajax: function(options) {
var request = getAngularRequest(options),
defer = globalScope.DeferredBuilder.Deferred();
request.then(function(results) {
defer.resolve(results.data);
}, function() {
defer.reject();
});
return defer.promise();
}
};
// Code from: http://stackoverflow.com/questions/1714786/querystring-encoding-of-a-javascript-object
function serialize (obj, prefix) {
var str = [];
for(var p in obj) {
if (obj.hasOwnProperty(p)) {
var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
str.push(typeof v == "object" ?
serialize(v, k) :
encodeURIComponent(k) + "=" + encodeURIComponent(v));
}
}
return str.join("&");
}
var $http = angular.injector(['ng']).get('$http');
function getAngularRequest(jParams) {
var optionTransforms = [],
promiseTransforms = [],
options = {},
// paramMap houses the param transforms in one of the following formats:
// string - This means there is a direct mapping from jQuery option to Angular option, but allows for a different option name
// function - This means some logic is required in applying this option to the Angular request. Functions should add functions
// to the optionTransforms or promiseTransforms arrays, which will be executed after direct mappings are complete.
paramMap = {
'accepts': undefined,
'async': undefined,
'beforeSend': undefined,
'cache': undefined,
'complete': undefined,
'contents': undefined,
'contentType': function(val) {
optionTransforms.push(function(opt) {
opt.headers = opt.headers || {};
opt.headers['Content-Type'] = val;
return opt;
});
},
'context': undefined,
'converters': undefined,
'crossDomain': undefined,
'data': 'data',
'dataFilter': undefined,
'dataType': 'responseType',
'error': undefined,
'global': undefined,
'headers': 'headers',
'ifModified': undefined,
'isLocal': undefined,
'jsonp': undefined,
'jsonpCallback': undefined,
'mimeType': undefined,
'password': undefined,
'processData': undefined,
'scriptCharset': undefined,
'statusCode': undefined,
'success': undefined,
'timeout': 'timeout',
'traditional': undefined,
'type': 'method',
'url': 'url',
'username': undefined,
'xhr': undefined,
'xhrFields': undefined,
};
// Iterate through each key in the jQuery format options object
for (var key in jParams) {
if (!paramMap[key]) {
// This parameter hasn't been implemented in the paramMap object
Logger.log('ERROR: ajax option property "' + key + '" not implemented by AjaxApi.');
continue;
}
if (typeof paramMap[key] === 'string') {
// Direct mapping between two properties
options[paramMap[key]] = jParams[key];
continue;
}
if (typeof paramMap[key] === 'function') {
// Extra logic required. Execute the function with the jQuery option as the only function argument
paramMap[key](jParams[key]);
}
}
// Iterate through any optionTransforms functions and execute them with the options object as argument
while (optionTransforms.length > 0) {
options = optionTransforms.pop()(options);
}
// Create the Angular http request (returns the request's promise object)
var promise = $http(options);
// Iterate through any promiseTransforms functions and execute them with the promise as argument.
while (promiseTransforms.length > 0) {
promiseTransforms.pop()(promise);
}
return promise;
}
})(window, angular);

View file

@ -1,736 +0,0 @@
(function (name, context, definition) {
if (typeof module != 'undefined' && module.exports) module.exports = definition()
else if (typeof define == 'function' && define.amd) define(definition)
else context[name] = definition()
})('bean', this, function (name, context) {
name = name || 'bean'
context = context || this
var win = window
, old = context[name]
, namespaceRegex = /[^\.]*(?=\..*)\.|.*/
, nameRegex = /\..*/
, addEvent = 'addEventListener'
, removeEvent = 'removeEventListener'
, doc = document || {}
, root = doc.documentElement || {}
, W3C_MODEL = root[addEvent]
, eventSupport = W3C_MODEL ? addEvent : 'attachEvent'
, ONE = {} // singleton for quick matching making add() do one()
, slice = Array.prototype.slice
, str2arr = function (s, d) { return s.split(d || ' ') }
, isString = function (o) { return typeof o == 'string' }
, isFunction = function (o) { return typeof o == 'function' }
// events that we consider to be 'native', anything not in this list will
// be treated as a custom event
, standardNativeEvents =
'click dblclick mouseup mousedown contextmenu ' + // mouse buttons
'mousewheel mousemultiwheel DOMMouseScroll ' + // mouse wheel
'mouseover mouseout mousemove selectstart selectend ' + // mouse movement
'keydown keypress keyup ' + // keyboard
'orientationchange ' + // mobile
'focus blur change reset select submit ' + // form elements
'load unload beforeunload resize move DOMContentLoaded ' + // window
'readystatechange message ' + // window
'error abort scroll ' // misc
// element.fireEvent('onXYZ'... is not forgiving if we try to fire an event
// that doesn't actually exist, so make sure we only do these on newer browsers
, w3cNativeEvents =
'show ' + // mouse buttons
'input invalid ' + // form elements
'touchstart touchmove touchend touchcancel ' + // touch
'gesturestart gesturechange gestureend ' + // gesture
'textinput ' + // TextEvent
'readystatechange pageshow pagehide popstate ' + // window
'hashchange offline online ' + // window
'afterprint beforeprint ' + // printing
'dragstart dragenter dragover dragleave drag drop dragend ' + // dnd
'loadstart progress suspend emptied stalled loadmetadata ' + // media
'loadeddata canplay canplaythrough playing waiting seeking ' + // media
'seeked ended durationchange timeupdate play pause ratechange ' + // media
'volumechange cuechange ' + // media
'checking noupdate downloading cached updateready obsolete ' // appcache
// convert to a hash for quick lookups
, nativeEvents = (function (hash, events, i) {
for (i = 0; i < events.length; i++) events[i] && (hash[events[i]] = 1)
return hash
}({}, str2arr(standardNativeEvents + (W3C_MODEL ? w3cNativeEvents : ''))))
// custom events are events that we *fake*, they are not provided natively but
// we can use native events to generate them
, customEvents = (function () {
var isAncestor = 'compareDocumentPosition' in root
? function (element, container) {
return container.compareDocumentPosition && (container.compareDocumentPosition(element) & 16) === 16
}
: 'contains' in root
? function (element, container) {
container = container.nodeType === 9 || container === window ? root : container
return container !== element && container.contains(element)
}
: function (element, container) {
while (element = element.parentNode) if (element === container) return 1
return 0
}
, check = function (event) {
var related = event.relatedTarget
return !related
? related == null
: (related !== this && related.prefix !== 'xul' && !/document/.test(this.toString())
&& !isAncestor(related, this))
}
return {
mouseenter: { base: 'mouseover', condition: check }
, mouseleave: { base: 'mouseout', condition: check }
, mousewheel: { base: /Firefox/.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel' }
}
}())
// we provide a consistent Event object across browsers by taking the actual DOM
// event object and generating a new one from its properties.
, Event = (function () {
// a whitelist of properties (for different event types) tells us what to check for and copy
var commonProps = str2arr('altKey attrChange attrName bubbles cancelable ctrlKey currentTarget ' +
'detail eventPhase getModifierState isTrusted metaKey relatedNode relatedTarget shiftKey ' +
'srcElement target timeStamp type view which propertyName path')
, mouseProps = commonProps.concat(str2arr('button buttons clientX clientY dataTransfer ' +
'fromElement offsetX offsetY pageX pageY screenX screenY toElement movementX movementY region'))
, mouseWheelProps = mouseProps.concat(str2arr('wheelDelta wheelDeltaX wheelDeltaY wheelDeltaZ ' +
'axis')) // 'axis' is FF specific
, keyProps = commonProps.concat(str2arr('char charCode key keyCode keyIdentifier ' +
'keyLocation location isComposing code'))
, textProps = commonProps.concat(str2arr('data'))
, touchProps = commonProps.concat(str2arr('touches targetTouches changedTouches scale rotation'))
, messageProps = commonProps.concat(str2arr('data origin source'))
, stateProps = commonProps.concat(str2arr('state'))
, overOutRegex = /over|out/
// some event types need special handling and some need special properties, do that all here
, typeFixers = [
{ // key events
reg: /key/i
, fix: function (event, newEvent) {
newEvent.keyCode = event.keyCode || event.which
return keyProps
}
}
, { // mouse events
reg: /click|mouse(?!(.*wheel|scroll))|menu|drag|drop/i
, fix: function (event, newEvent, type) {
newEvent.rightClick = event.which === 3 || event.button === 2
newEvent.pos = { x: 0, y: 0 }
if (event.pageX || event.pageY) {
newEvent.clientX = event.pageX
newEvent.clientY = event.pageY
} else if (event.clientX || event.clientY) {
newEvent.clientX = event.clientX + doc.body.scrollLeft + root.scrollLeft
newEvent.clientY = event.clientY + doc.body.scrollTop + root.scrollTop
}
if (overOutRegex.test(type)) {
newEvent.relatedTarget = event.relatedTarget
|| event[(type == 'mouseover' ? 'from' : 'to') + 'Element']
}
return mouseProps
}
}
, { // mouse wheel events
reg: /mouse.*(wheel|scroll)/i
, fix: function () { return mouseWheelProps }
}
, { // TextEvent
reg: /^text/i
, fix: function () { return textProps }
}
, { // touch and gesture events
reg: /^touch|^gesture/i
, fix: function () { return touchProps }
}
, { // message events
reg: /^message$/i
, fix: function () { return messageProps }
}
, { // popstate events
reg: /^popstate$/i
, fix: function () { return stateProps }
}
, { // everything else
reg: /.*/
, fix: function () { return commonProps }
}
]
, typeFixerMap = {} // used to map event types to fixer functions (above), a basic cache mechanism
, Event = function (event, element, isNative) {
if (!arguments.length) return
event = event || ((element.ownerDocument || element.document || element).parentWindow || win).event
this.originalEvent = event
this.isNative = isNative
this.isBean = true
if (!event) return
var type = event.type
, target = event.target || event.srcElement
, i, l, p, props, fixer
this.target = target && target.nodeType === 3 ? target.parentNode : target
if (isNative) { // we only need basic augmentation on custom events, the rest expensive & pointless
fixer = typeFixerMap[type]
if (!fixer) { // haven't encountered this event type before, map a fixer function for it
for (i = 0, l = typeFixers.length; i < l; i++) {
if (typeFixers[i].reg.test(type)) { // guaranteed to match at least one, last is .*
typeFixerMap[type] = fixer = typeFixers[i].fix
break
}
}
}
props = fixer(event, this, type)
for (i = props.length; i--;) {
if (!((p = props[i]) in this) && p in event) this[p] = event[p]
}
}
}
// preventDefault() and stopPropagation() are a consistent interface to those functions
// on the DOM, stop() is an alias for both of them together
Event.prototype.preventDefault = function () {
if (this.originalEvent.preventDefault) this.originalEvent.preventDefault()
else this.originalEvent.returnValue = false
}
Event.prototype.stopPropagation = function () {
if (this.originalEvent.stopPropagation) this.originalEvent.stopPropagation()
else this.originalEvent.cancelBubble = true
}
Event.prototype.stop = function () {
this.preventDefault()
this.stopPropagation()
this.stopped = true
}
// stopImmediatePropagation() has to be handled internally because we manage the event list for
// each element
// note that originalElement may be a Bean#Event object in some situations
Event.prototype.stopImmediatePropagation = function () {
if (this.originalEvent.stopImmediatePropagation) this.originalEvent.stopImmediatePropagation()
this.isImmediatePropagationStopped = function () { return true }
}
Event.prototype.isImmediatePropagationStopped = function () {
return this.originalEvent.isImmediatePropagationStopped && this.originalEvent.isImmediatePropagationStopped()
}
Event.prototype.clone = function (currentTarget) {
//TODO: this is ripe for optimisation, new events are *expensive*
// improving this will speed up delegated events
var ne = new Event(this, this.element, this.isNative)
ne.currentTarget = currentTarget
return ne
}
return Event
}())
// if we're in old IE we can't do onpropertychange on doc or win so we use doc.documentElement for both
, targetElement = function (element, isNative) {
return !W3C_MODEL && !isNative && (element === doc || element === win) ? root : element
}
/**
* Bean maintains an internal registry for event listeners. We don't touch elements, objects
* or functions to identify them, instead we store everything in the registry.
* Each event listener has a RegEntry object, we have one 'registry' for the whole instance.
*/
, RegEntry = (function () {
// each handler is wrapped so we can handle delegation and custom events
var wrappedHandler = function (element, fn, condition, args) {
var call = function (event, eargs) {
return fn.apply(element, args ? slice.call(eargs, event ? 0 : 1).concat(args) : eargs)
}
, findTarget = function (event, eventElement) {
return fn.__beanDel ? fn.__beanDel.ft(event.target, element) : eventElement
}
, handler = condition
? function (event) {
var target = findTarget(event, this) // deleated event
if (condition.apply(target, arguments)) {
if (event) event.currentTarget = target
return call(event, arguments)
}
}
: function (event) {
if (fn.__beanDel) event = event.clone(findTarget(event)) // delegated event, fix the fix
return call(event, arguments)
}
handler.__beanDel = fn.__beanDel
return handler
}
, RegEntry = function (element, type, handler, original, namespaces, args, root) {
var customType = customEvents[type]
, isNative
if (type == 'unload') {
// self clean-up
handler = once(removeListener, element, type, handler, original)
}
if (customType) {
if (customType.condition) {
handler = wrappedHandler(element, handler, customType.condition, args)
}
type = customType.base || type
}
this.isNative = isNative = nativeEvents[type] && !!element[eventSupport]
this.customType = !W3C_MODEL && !isNative && type
this.element = element
this.type = type
this.original = original
this.namespaces = namespaces
this.eventType = W3C_MODEL || isNative ? type : 'propertychange'
this.target = targetElement(element, isNative)
this[eventSupport] = !!this.target[eventSupport]
this.root = root
this.handler = wrappedHandler(element, handler, null, args)
}
// given a list of namespaces, is our entry in any of them?
RegEntry.prototype.inNamespaces = function (checkNamespaces) {
var i, j, c = 0
if (!checkNamespaces) return true
if (!this.namespaces) return false
for (i = checkNamespaces.length; i--;) {
for (j = this.namespaces.length; j--;) {
if (checkNamespaces[i] == this.namespaces[j]) c++
}
}
return checkNamespaces.length === c
}
// match by element, original fn (opt), handler fn (opt)
RegEntry.prototype.matches = function (checkElement, checkOriginal, checkHandler) {
return this.element === checkElement &&
(!checkOriginal || this.original === checkOriginal) &&
(!checkHandler || this.handler === checkHandler)
}
return RegEntry
}())
, registry = (function () {
// our map stores arrays by event type, just because it's better than storing
// everything in a single array.
// uses '$' as a prefix for the keys for safety and 'r' as a special prefix for
// rootListeners so we can look them up fast
var map = {}
// generic functional search of our registry for matching listeners,
// `fn` returns false to break out of the loop
, forAll = function (element, type, original, handler, root, fn) {
var pfx = root ? 'r' : '$'
if (!type || type == '*') {
// search the whole registry
for (var t in map) {
if (t.charAt(0) == pfx) {
forAll(element, t.substr(1), original, handler, root, fn)
}
}
} else {
var i = 0, l, list = map[pfx + type], all = element == '*'
if (!list) return
for (l = list.length; i < l; i++) {
if ((all || list[i].matches(element, original, handler)) && !fn(list[i], list, i, type)) return
}
}
}
, has = function (element, type, original, root) {
// we're not using forAll here simply because it's a bit slower and this
// needs to be fast
var i, list = map[(root ? 'r' : '$') + type]
if (list) {
for (i = list.length; i--;) {
if (!list[i].root && list[i].matches(element, original, null)) return true
}
}
return false
}
, get = function (element, type, original, root) {
var entries = []
forAll(element, type, original, null, root, function (entry) {
return entries.push(entry)
})
return entries
}
, put = function (entry) {
var has = !entry.root && !this.has(entry.element, entry.type, null, false)
, key = (entry.root ? 'r' : '$') + entry.type
;(map[key] || (map[key] = [])).push(entry)
return has
}
, del = function (entry) {
forAll(entry.element, entry.type, null, entry.handler, entry.root, function (entry, list, i) {
list.splice(i, 1)
entry.removed = true
if (list.length === 0) delete map[(entry.root ? 'r' : '$') + entry.type]
return false
})
}
// dump all entries, used for onunload
, entries = function () {
var t, entries = []
for (t in map) {
if (t.charAt(0) == '$') entries = entries.concat(map[t])
}
return entries
}
return { has: has, get: get, put: put, del: del, entries: entries }
}())
// we need a selector engine for delegated events, use querySelectorAll if it exists
// but for older browsers we need Qwery, Sizzle or similar
, selectorEngine
, setSelectorEngine = function (e) {
if (!arguments.length) {
selectorEngine = doc.querySelectorAll
? function (s, r) {
return r.querySelectorAll(s)
}
: function () {
throw new Error('Bean: No selector engine installed') // eeek
}
} else {
selectorEngine = e
}
}
// we attach this listener to each DOM event that we need to listen to, only once
// per event type per DOM element
, rootListener = function (event, type) {
if (!W3C_MODEL && type && event && event.propertyName != '_on' + type) return
var listeners = registry.get(this, type || event.type, null, false)
, l = listeners.length
, i = 0
event = new Event(event, this, true)
if (type) event.type = type
// iterate through all handlers registered for this type, calling them unless they have
// been removed by a previous handler or stopImmediatePropagation() has been called
for (; i < l && !event.isImmediatePropagationStopped(); i++) {
if (!listeners[i].removed) listeners[i].handler.call(this, event)
}
}
// add and remove listeners to DOM elements
, listener = W3C_MODEL
? function (element, type, add) {
// new browsers
element[add ? addEvent : removeEvent](type, rootListener, false)
}
: function (element, type, add, custom) {
// IE8 and below, use attachEvent/detachEvent and we have to piggy-back propertychange events
// to simulate event bubbling etc.
var entry
if (add) {
registry.put(entry = new RegEntry(
element
, custom || type
, function (event) { // handler
rootListener.call(element, event, custom)
}
, rootListener
, null
, null
, true // is root
))
if (custom && element['_on' + custom] == null) element['_on' + custom] = 0
entry.target.attachEvent('on' + entry.eventType, entry.handler)
} else {
entry = registry.get(element, custom || type, rootListener, true)[0]
if (entry) {
entry.target.detachEvent('on' + entry.eventType, entry.handler)
registry.del(entry)
}
}
}
, once = function (rm, element, type, fn, originalFn) {
// wrap the handler in a handler that does a remove as well
return function () {
fn.apply(this, arguments)
rm(element, type, originalFn)
}
}
, removeListener = function (element, orgType, handler, namespaces) {
var type = orgType && orgType.replace(nameRegex, '')
, handlers = registry.get(element, type, null, false)
, removed = {}
, i, l
for (i = 0, l = handlers.length; i < l; i++) {
if ((!handler || handlers[i].original === handler) && handlers[i].inNamespaces(namespaces)) {
// TODO: this is problematic, we have a registry.get() and registry.del() that
// both do registry searches so we waste cycles doing this. Needs to be rolled into
// a single registry.forAll(fn) that removes while finding, but the catch is that
// we'll be splicing the arrays that we're iterating over. Needs extra tests to
// make sure we don't screw it up. @rvagg
registry.del(handlers[i])
if (!removed[handlers[i].eventType] && handlers[i][eventSupport])
removed[handlers[i].eventType] = { t: handlers[i].eventType, c: handlers[i].type }
}
}
// check each type/element for removed listeners and remove the rootListener where it's no longer needed
for (i in removed) {
if (!registry.has(element, removed[i].t, null, false)) {
// last listener of this type, remove the rootListener
listener(element, removed[i].t, false, removed[i].c)
}
}
}
// set up a delegate helper using the given selector, wrap the handler function
, delegate = function (selector, fn) {
//TODO: findTarget (therefore $) is called twice, once for match and once for
// setting e.currentTarget, fix this so it's only needed once
var findTarget = function (target, root) {
var i, array = isString(selector) ? selectorEngine(selector, root) : selector
for (; target && target !== root; target = target.parentNode) {
for (i = array.length; i--;) {
if (array[i] === target) return target
}
}
}
, handler = function (e) {
var match = findTarget(e.target, this)
if (match) fn.apply(match, arguments)
}
// __beanDel isn't pleasant but it's a private function, not exposed outside of Bean
handler.__beanDel = {
ft : findTarget // attach it here for customEvents to use too
, selector : selector
}
return handler
}
, fireListener = W3C_MODEL ? function (isNative, type, element) {
// modern browsers, do a proper dispatchEvent()
var evt = doc.createEvent(isNative ? 'HTMLEvents' : 'UIEvents')
evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, win, 1)
element.dispatchEvent(evt)
} : function (isNative, type, element) {
// old browser use onpropertychange, just increment a custom property to trigger the event
element = targetElement(element, isNative)
isNative ? element.fireEvent('on' + type, doc.createEventObject()) : element['_on' + type]++
}
/**
* Public API: off(), on(), add(), (remove()), one(), fire(), clone()
*/
/**
* off(element[, eventType(s)[, handler ]])
*/
, off = function (element, typeSpec, fn) {
var isTypeStr = isString(typeSpec)
, k, type, namespaces, i
if (isTypeStr && typeSpec.indexOf(' ') > 0) {
// off(el, 't1 t2 t3', fn) or off(el, 't1 t2 t3')
typeSpec = str2arr(typeSpec)
for (i = typeSpec.length; i--;)
off(element, typeSpec[i], fn)
return element
}
type = isTypeStr && typeSpec.replace(nameRegex, '')
if (type && customEvents[type]) type = customEvents[type].base
if (!typeSpec || isTypeStr) {
// off(el) or off(el, t1.ns) or off(el, .ns) or off(el, .ns1.ns2.ns3)
if (namespaces = isTypeStr && typeSpec.replace(namespaceRegex, '')) namespaces = str2arr(namespaces, '.')
removeListener(element, type, fn, namespaces)
} else if (isFunction(typeSpec)) {
// off(el, fn)
removeListener(element, null, typeSpec)
} else {
// off(el, { t1: fn1, t2, fn2 })
for (k in typeSpec) {
if (typeSpec.hasOwnProperty(k)) off(element, k, typeSpec[k])
}
}
return element
}
/**
* on(element, eventType(s)[, selector], handler[, args ])
*/
, on = function(element, events, selector, fn) {
var originalFn, type, types, i, args, entry, first
//TODO: the undefined check means you can't pass an 'args' argument, fix this perhaps?
if (selector === undefined && typeof events == 'object') {
//TODO: this can't handle delegated events
for (type in events) {
if (events.hasOwnProperty(type)) {
on.call(this, element, type, events[type])
}
}
return
}
if (!isFunction(selector)) {
// delegated event
originalFn = fn
args = slice.call(arguments, 4)
fn = delegate(selector, originalFn, selectorEngine)
} else {
args = slice.call(arguments, 3)
fn = originalFn = selector
}
types = str2arr(events)
// special case for one(), wrap in a self-removing handler
if (this === ONE) {
fn = once(off, element, events, fn, originalFn)
}
for (i = types.length; i--;) {
// add new handler to the registry and check if it's the first for this element/type
first = registry.put(entry = new RegEntry(
element
, types[i].replace(nameRegex, '') // event type
, fn
, originalFn
, str2arr(types[i].replace(namespaceRegex, ''), '.') // namespaces
, args
, false // not root
))
if (entry[eventSupport] && first) {
// first event of this type on this element, add root listener
listener(element, entry.eventType, true, entry.customType)
}
}
return element
}
/**
* add(element[, selector], eventType(s), handler[, args ])
*
* Deprecated: kept (for now) for backward-compatibility
*/
, add = function (element, events, fn, delfn) {
return on.apply(
null
, !isString(fn)
? slice.call(arguments)
: [ element, fn, events, delfn ].concat(arguments.length > 3 ? slice.call(arguments, 5) : [])
)
}
/**
* one(element, eventType(s)[, selector], handler[, args ])
*/
, one = function () {
return on.apply(ONE, arguments)
}
/**
* fire(element, eventType(s)[, args ])
*
* The optional 'args' argument must be an array, if no 'args' argument is provided
* then we can use the browser's DOM event system, otherwise we trigger handlers manually
*/
, fire = function (element, type, args) {
var types = str2arr(type)
, i, j, l, names, handlers
for (i = types.length; i--;) {
type = types[i].replace(nameRegex, '')
if (names = types[i].replace(namespaceRegex, '')) names = str2arr(names, '.')
if (!names && !args && element[eventSupport]) {
fireListener(nativeEvents[type], type, element)
} else {
// non-native event, either because of a namespace, arguments or a non DOM element
// iterate over all listeners and manually 'fire'
handlers = registry.get(element, type, null, false)
args = [false].concat(args)
for (j = 0, l = handlers.length; j < l; j++) {
if (handlers[j].inNamespaces(names)) {
handlers[j].handler.apply(element, args)
}
}
}
}
return element
}
/**
* clone(dstElement, srcElement[, eventType ])
*
* TODO: perhaps for consistency we should allow the same flexibility in type specifiers?
*/
, clone = function (element, from, type) {
var handlers = registry.get(from, type, null, false)
, l = handlers.length
, i = 0
, args, beanDel
for (; i < l; i++) {
if (handlers[i].original) {
args = [ element, handlers[i].type ]
if (beanDel = handlers[i].handler.__beanDel) args.push(beanDel.selector)
args.push(handlers[i].original)
on.apply(null, args)
}
}
return element
}
, bean = {
'on' : on
, 'add' : add
, 'one' : one
, 'off' : off
, 'remove' : off
, 'clone' : clone
, 'fire' : fire
, 'Event' : Event
, 'setSelectorEngine' : setSelectorEngine
, 'noConflict' : function () {
context[name] = old
return this
}
}
// for IE, clean up on unload to avoid leaks
if (win.attachEvent) {
var cleanup = function () {
var i, entries = registry.entries()
for (i in entries) {
if (entries[i].type && entries[i].type !== 'unload') off(entries[i].element, entries[i].type)
}
win.detachEvent('onunload', cleanup)
win.CollectGarbage && win.CollectGarbage()
}
win.attachEvent('onunload', cleanup)
}
// initialize selector engine to internal default (qSA or throw Error)
setSelectorEngine()
return bean
});

View file

@ -1,314 +0,0 @@
(function (global) {
function isArray(arr) {
return Object.prototype.toString.call(arr) === '[object Array]';
}
function foreach(arr, handler) {
if (isArray(arr)) {
for (var i = 0; i < arr.length; i++) {
handler(arr[i]);
}
}
else
handler(arr);
}
function D(fn) {
var status = 'pending',
doneFuncs = [],
failFuncs = [],
progressFuncs = [],
resultArgs = null,
promise = {
done: function () {
for (var i = 0; i < arguments.length; i++) {
// skip any undefined or null arguments
if (!arguments[i]) {
continue;
}
if (isArray(arguments[i])) {
var arr = arguments[i];
for (var j = 0; j < arr.length; j++) {
// immediately call the function if the deferred has been resolved
if (status === 'resolved') {
arr[j].apply(this, resultArgs);
}
doneFuncs.push(arr[j]);
}
}
else {
// immediately call the function if the deferred has been resolved
if (status === 'resolved') {
arguments[i].apply(this, resultArgs);
}
doneFuncs.push(arguments[i]);
}
}
return this;
},
fail: function () {
for (var i = 0; i < arguments.length; i++) {
// skip any undefined or null arguments
if (!arguments[i]) {
continue;
}
if (isArray(arguments[i])) {
var arr = arguments[i];
for (var j = 0; j < arr.length; j++) {
// immediately call the function if the deferred has been resolved
if (status === 'rejected') {
arr[j].apply(this, resultArgs);
}
failFuncs.push(arr[j]);
}
}
else {
// immediately call the function if the deferred has been resolved
if (status === 'rejected') {
arguments[i].apply(this, resultArgs);
}
failFuncs.push(arguments[i]);
}
}
return this;
},
always: function () {
return this.done.apply(this, arguments).fail.apply(this, arguments);
},
progress: function () {
for (var i = 0; i < arguments.length; i++) {
// skip any undefined or null arguments
if (!arguments[i]) {
continue;
}
if (isArray(arguments[i])) {
var arr = arguments[i];
for (var j = 0; j < arr.length; j++) {
// immediately call the function if the deferred has been resolved
if (status === 'pending') {
progressFuncs.push(arr[j]);
}
}
}
else {
// immediately call the function if the deferred has been resolved
if (status === 'pending') {
progressFuncs.push(arguments[i]);
}
}
}
return this;
},
then: function () {
// fail callbacks
if (arguments.length > 1 && arguments[1]) {
this.fail(arguments[1]);
}
// done callbacks
if (arguments.length > 0 && arguments[0]) {
this.done(arguments[0]);
}
// notify callbacks
if (arguments.length > 2 && arguments[2]) {
this.progress(arguments[2]);
}
},
promise: function (obj) {
if (obj == null) {
return promise;
} else {
for (var i in promise) {
obj[i] = promise[i];
}
return obj;
}
},
state: function () {
return status;
},
debug: function () {
console.log('[debug]', doneFuncs, failFuncs, status);
},
isRejected: function () {
return status === 'rejected';
},
isResolved: function () {
return status === 'resolved';
},
pipe: function (done, fail, progress) {
return D(function (def) {
foreach(done, function (func) {
// filter function
if (typeof func === 'function') {
deferred.done(function () {
var returnval = func.apply(this, arguments);
// if a new deferred/promise is returned, its state is passed to the current deferred/promise
if (returnval && typeof returnval === 'function') {
returnval.promise().then(def.resolve, def.reject, def.notify);
}
else { // if new return val is passed, it is passed to the piped done
def.resolve(returnval);
}
});
}
else {
deferred.done(def.resolve);
}
});
foreach(fail, function (func) {
if (typeof func === 'function') {
deferred.fail(function () {
var returnval = func.apply(this, arguments);
if (returnval && typeof returnval === 'function') {
returnval.promise().then(def.resolve, def.reject, def.notify);
} else {
def.reject(returnval);
}
});
}
else {
deferred.fail(def.reject);
}
});
}).promise();
}
},
deferred = {
resolveWith: function (context) {
if (status === 'pending') {
status = 'resolved';
var args = resultArgs = (arguments.length > 1) ? arguments[1] : [];
for (var i = 0; i < doneFuncs.length; i++) {
doneFuncs[i].apply(context, args);
}
}
return this;
},
rejectWith: function (context) {
if (status === 'pending') {
status = 'rejected';
var args = resultArgs = (arguments.length > 1) ? arguments[1] : [];
for (var i = 0; i < failFuncs.length; i++) {
failFuncs[i].apply(context, args);
}
}
return this;
},
notifyWith: function (context) {
if (status === 'pending') {
var args = resultArgs = (arguments.length > 1) ? arguments[1] : [];
for (var i = 0; i < progressFuncs.length; i++) {
progressFuncs[i].apply(context, args);
}
}
return this;
},
resolve: function () {
return this.resolveWith(this, arguments);
},
reject: function () {
return this.rejectWith(this, arguments);
},
notify: function () {
return this.notifyWith(this, arguments);
}
}
var obj = promise.promise(deferred);
if (fn) {
fn.apply(obj, [obj]);
}
return obj;
}
D.when = function () {
if (arguments.length < 2) {
var obj = arguments.length ? arguments[0] : undefined;
if (obj && (typeof obj.isResolved === 'function' && typeof obj.isRejected === 'function')) {
return obj.promise();
}
else {
return D().resolve(obj).promise();
}
}
else {
return (function (args) {
var df = D(),
size = args.length,
done = 0,
rp = new Array(size); // resolve params: params of each resolve, we need to track down them to be able to pass them in the correct order if the master needs to be resolved
for (var i = 0; i < args.length; i++) {
(function (j) {
var obj = null;
if (args[j].done) {
args[j].done(function () { rp[j] = (arguments.length < 2) ? arguments[0] : arguments; if (++done == size) { df.resolve.apply(df, rp); } })
.fail(function () { df.reject(arguments); });
} else {
obj = args[j];
args[j] = new Deferred();
args[j].done(function () { rp[j] = (arguments.length < 2) ? arguments[0] : arguments; if (++done == size) { df.resolve.apply(df, rp); } })
.fail(function () { df.reject(arguments); }).resolve(obj);
}
})(i);
}
return df.promise();
})(arguments);
}
}
global.Deferred = D;
})(window);
(function (globalScope) {
globalScope.DeferredBuilder = {
Deferred: function () {
return new globalScope.Deferred();
},
when: function (promises) {
return globalScope.Deferred.when(promises);
}
};
})(window);

View file

@ -1,35 +0,0 @@
(function (globalScope) {
globalScope.Events = {
on: function (obj, eventName, selector, fn) {
Logger.log('event.on ' + eventName);
bean.on(obj, eventName, selector, fn);
},
off: function (obj, eventName, selector, fn) {
Logger.log('event.off ' + eventName);
bean.off(obj, eventName, selector);
},
trigger: function (obj, eventName, params) {
Logger.log('event.trigger ' + eventName);
// Need to push an extra param to make the argument order consistent with jquery
var newParams = [];
newParams.push({});
if (params && params.length) {
for (var i = 0, length = params.length; i < length; i++) {
newParams.push(params[i]);
}
}
bean.fire(obj, eventName, newParams);
}
};
})(window);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,34 +0,0 @@
(function (globalScope) {
if (!globalScope.MediaBrowser) {
globalScope.MediaBrowser = {};
}
function replaceAll(str, find, replace) {
return str.split(find).join(replace);
}
var connectService = {
cleanPassword: function (password) {
password = password || '';
password = replaceAll(password, "&", "&amp;");
password = replaceAll(password, "/", "&#092;");
password = replaceAll(password, "!", "&#33;");
password = replaceAll(password, "$", "&#036;");
password = replaceAll(password, "\"", "&quot;");
password = replaceAll(password, "<", "&lt;");
password = replaceAll(password, ">", "&gt;");
password = replaceAll(password, "'", "&#39;");
return password;
}
};
globalScope.MediaBrowser.ConnectService = connectService;
})(window);

View file

@ -1,112 +0,0 @@
(function (globalScope, JSON) {
if (!globalScope.MediaBrowser) {
globalScope.MediaBrowser = {};
}
globalScope.MediaBrowser.CredentialProvider = function (key) {
var self = this;
var credentials = null;
key = key || 'servercredentials3';
function ensure() {
if (!credentials) {
var json = appStorage.getItem(key) || '{}';
console.log('credentials initialized with: ' + json);
credentials = JSON.parse(json);
credentials.Servers = credentials.Servers || credentials.servers || [];
credentials.servers = null;
}
}
function get() {
ensure();
return credentials;
}
function set(data) {
if (data) {
credentials = data;
appStorage.setItem(key, JSON.stringify(data));
} else {
self.clear();
}
Events.trigger(self, 'credentialsupdated');
}
self.clear = function () {
credentials = null;
appStorage.removeItem(key);
};
self.credentials = function (data) {
if (data) {
set(data);
}
return get();
};
self.addOrUpdateServer = function (list, server) {
if (!server.Id) {
throw new Error('Server.Id cannot be null or empty');
}
var existing = list.filter(function (s) {
return s.Id == server.Id;
})[0];
if (existing) {
// Merge the data
existing.DateLastAccessed = Math.max(existing.DateLastAccessed || 0, server.DateLastAccessed || 0);
existing.UserLinkType = server.UserLinkType;
if (server.AccessToken) {
existing.AccessToken = server.AccessToken;
existing.UserId = server.UserId;
}
if (server.ExchangeToken) {
existing.ExchangeToken = server.ExchangeToken;
}
if (server.RemoteAddress) {
existing.RemoteAddress = server.RemoteAddress;
}
if (server.ManualAddress) {
existing.ManualAddress = server.ManualAddress;
}
if (server.LocalAddress) {
existing.LocalAddress = server.LocalAddress;
}
if (server.Name) {
existing.Name = server.Name;
}
if (server.WakeOnLanInfos && server.WakeOnLanInfos.length) {
existing.WakeOnLanInfos = server.WakeOnLanInfos;
}
if (server.LastConnectionMode != null) {
existing.LastConnectionMode = server.LastConnectionMode;
}
existing.DateLastLocalConnection = Math.max(existing.DateLastLocalConnection || 0, server.DateLastLocalConnection || 0);
return existing;
}
else {
list.push(server);
return server;
}
};
};
})(window, window.JSON);

View file

@ -1,16 +0,0 @@
(function (globalScope) {
globalScope.DeferredBuilder = {
Deferred: function () {
return jQuery.Deferred();
},
when: function (promises) {
return jQuery.when(promises);
}
};
})(window);

View file

@ -1,33 +0,0 @@
(function (globalScope) {
if (!globalScope.MediaBrowser) {
globalScope.MediaBrowser = {};
}
globalScope.MediaBrowser.generateDeviceId = function (keyName, seed) {
var keys = [];
keys.push(navigator.userAgent);
keys.push((navigator.cpuClass || ""));
if (seed) {
keys.push(seed);
}
var randomId = '';
// Since the above is not guaranteed to be unique per device, add a little more
randomId = appStorage.getItem(keyName);
if (!randomId) {
randomId = new Date().getTime();
appStorage.setItem(keyName, randomId.toString());
}
keys.push(randomId);
return CryptoJS.SHA1(keys.join('|')).toString();
};
})(window);

View file

@ -1,23 +0,0 @@
(function (globalScope) {
globalScope.Events = {
on: function (obj, eventName, selector, fn) {
Logger.log('event.on ' + eventName);
jQuery(obj).on(eventName, selector, fn);
},
off: function (obj, eventName, selector, fn) {
Logger.log('event.off ' + eventName);
jQuery(obj).off(eventName, selector, fn);
},
trigger: function (obj, eventName, params) {
Logger.log('event.trigger ' + eventName);
jQuery(obj).trigger(eventName, params);
}
};
})(window);

View file

@ -1,11 +0,0 @@
(function () {
function getLocalMediaSource(serverId, itemId) {
return null;
}
window.LocalAssetManager = {
getLocalMediaSource: getLocalMediaSource
};
})();

View file

@ -1,6 +0,0 @@
var Logger = {
log: function (str) {
console.log(str);
}
};

View file

@ -1,19 +0,0 @@
/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var CryptoJS=CryptoJS||function(s,p){var m={},l=m.lib={},n=function(){},r=l.Base={extend:function(b){n.prototype=this;var h=new n;b&&h.mixIn(b);h.hasOwnProperty("init")||(h.init=function(){h.$super.init.apply(this,arguments)});h.init.prototype=h;h.$super=this;return h},create:function(){var b=this.extend();b.init.apply(b,arguments);return b},init:function(){},mixIn:function(b){for(var h in b)b.hasOwnProperty(h)&&(this[h]=b[h]);b.hasOwnProperty("toString")&&(this.toString=b.toString)},clone:function(){return this.init.prototype.extend(this)}},
q=l.WordArray=r.extend({init:function(b,h){b=this.words=b||[];this.sigBytes=h!=p?h:4*b.length},toString:function(b){return(b||t).stringify(this)},concat:function(b){var h=this.words,a=b.words,j=this.sigBytes;b=b.sigBytes;this.clamp();if(j%4)for(var g=0;g<b;g++)h[j+g>>>2]|=(a[g>>>2]>>>24-8*(g%4)&255)<<24-8*((j+g)%4);else if(65535<a.length)for(g=0;g<b;g+=4)h[j+g>>>2]=a[g>>>2];else h.push.apply(h,a);this.sigBytes+=b;return this},clamp:function(){var b=this.words,h=this.sigBytes;b[h>>>2]&=4294967295<<
32-8*(h%4);b.length=s.ceil(h/4)},clone:function(){var b=r.clone.call(this);b.words=this.words.slice(0);return b},random:function(b){for(var h=[],a=0;a<b;a+=4)h.push(4294967296*s.random()|0);return new q.init(h,b)}}),v=m.enc={},t=v.Hex={stringify:function(b){var a=b.words;b=b.sigBytes;for(var g=[],j=0;j<b;j++){var k=a[j>>>2]>>>24-8*(j%4)&255;g.push((k>>>4).toString(16));g.push((k&15).toString(16))}return g.join("")},parse:function(b){for(var a=b.length,g=[],j=0;j<a;j+=2)g[j>>>3]|=parseInt(b.substr(j,
2),16)<<24-4*(j%8);return new q.init(g,a/2)}},a=v.Latin1={stringify:function(b){var a=b.words;b=b.sigBytes;for(var g=[],j=0;j<b;j++)g.push(String.fromCharCode(a[j>>>2]>>>24-8*(j%4)&255));return g.join("")},parse:function(b){for(var a=b.length,g=[],j=0;j<a;j++)g[j>>>2]|=(b.charCodeAt(j)&255)<<24-8*(j%4);return new q.init(g,a)}},u=v.Utf8={stringify:function(b){try{return decodeURIComponent(escape(a.stringify(b)))}catch(g){throw Error("Malformed UTF-8 data");}},parse:function(b){return a.parse(unescape(encodeURIComponent(b)))}},
g=l.BufferedBlockAlgorithm=r.extend({reset:function(){this._data=new q.init;this._nDataBytes=0},_append:function(b){"string"==typeof b&&(b=u.parse(b));this._data.concat(b);this._nDataBytes+=b.sigBytes},_process:function(b){var a=this._data,g=a.words,j=a.sigBytes,k=this.blockSize,m=j/(4*k),m=b?s.ceil(m):s.max((m|0)-this._minBufferSize,0);b=m*k;j=s.min(4*b,j);if(b){for(var l=0;l<b;l+=k)this._doProcessBlock(g,l);l=g.splice(0,b);a.sigBytes-=j}return new q.init(l,j)},clone:function(){var b=r.clone.call(this);
b._data=this._data.clone();return b},_minBufferSize:0});l.Hasher=g.extend({cfg:r.extend(),init:function(b){this.cfg=this.cfg.extend(b);this.reset()},reset:function(){g.reset.call(this);this._doReset()},update:function(b){this._append(b);this._process();return this},finalize:function(b){b&&this._append(b);return this._doFinalize()},blockSize:16,_createHelper:function(b){return function(a,g){return(new b.init(g)).finalize(a)}},_createHmacHelper:function(b){return function(a,g){return(new k.HMAC.init(b,
g)).finalize(a)}}});var k=m.algo={};return m}(Math);
(function(s){function p(a,k,b,h,l,j,m){a=a+(k&b|~k&h)+l+m;return(a<<j|a>>>32-j)+k}function m(a,k,b,h,l,j,m){a=a+(k&h|b&~h)+l+m;return(a<<j|a>>>32-j)+k}function l(a,k,b,h,l,j,m){a=a+(k^b^h)+l+m;return(a<<j|a>>>32-j)+k}function n(a,k,b,h,l,j,m){a=a+(b^(k|~h))+l+m;return(a<<j|a>>>32-j)+k}for(var r=CryptoJS,q=r.lib,v=q.WordArray,t=q.Hasher,q=r.algo,a=[],u=0;64>u;u++)a[u]=4294967296*s.abs(s.sin(u+1))|0;q=q.MD5=t.extend({_doReset:function(){this._hash=new v.init([1732584193,4023233417,2562383102,271733878])},
_doProcessBlock:function(g,k){for(var b=0;16>b;b++){var h=k+b,w=g[h];g[h]=(w<<8|w>>>24)&16711935|(w<<24|w>>>8)&4278255360}var b=this._hash.words,h=g[k+0],w=g[k+1],j=g[k+2],q=g[k+3],r=g[k+4],s=g[k+5],t=g[k+6],u=g[k+7],v=g[k+8],x=g[k+9],y=g[k+10],z=g[k+11],A=g[k+12],B=g[k+13],C=g[k+14],D=g[k+15],c=b[0],d=b[1],e=b[2],f=b[3],c=p(c,d,e,f,h,7,a[0]),f=p(f,c,d,e,w,12,a[1]),e=p(e,f,c,d,j,17,a[2]),d=p(d,e,f,c,q,22,a[3]),c=p(c,d,e,f,r,7,a[4]),f=p(f,c,d,e,s,12,a[5]),e=p(e,f,c,d,t,17,a[6]),d=p(d,e,f,c,u,22,a[7]),
c=p(c,d,e,f,v,7,a[8]),f=p(f,c,d,e,x,12,a[9]),e=p(e,f,c,d,y,17,a[10]),d=p(d,e,f,c,z,22,a[11]),c=p(c,d,e,f,A,7,a[12]),f=p(f,c,d,e,B,12,a[13]),e=p(e,f,c,d,C,17,a[14]),d=p(d,e,f,c,D,22,a[15]),c=m(c,d,e,f,w,5,a[16]),f=m(f,c,d,e,t,9,a[17]),e=m(e,f,c,d,z,14,a[18]),d=m(d,e,f,c,h,20,a[19]),c=m(c,d,e,f,s,5,a[20]),f=m(f,c,d,e,y,9,a[21]),e=m(e,f,c,d,D,14,a[22]),d=m(d,e,f,c,r,20,a[23]),c=m(c,d,e,f,x,5,a[24]),f=m(f,c,d,e,C,9,a[25]),e=m(e,f,c,d,q,14,a[26]),d=m(d,e,f,c,v,20,a[27]),c=m(c,d,e,f,B,5,a[28]),f=m(f,c,
d,e,j,9,a[29]),e=m(e,f,c,d,u,14,a[30]),d=m(d,e,f,c,A,20,a[31]),c=l(c,d,e,f,s,4,a[32]),f=l(f,c,d,e,v,11,a[33]),e=l(e,f,c,d,z,16,a[34]),d=l(d,e,f,c,C,23,a[35]),c=l(c,d,e,f,w,4,a[36]),f=l(f,c,d,e,r,11,a[37]),e=l(e,f,c,d,u,16,a[38]),d=l(d,e,f,c,y,23,a[39]),c=l(c,d,e,f,B,4,a[40]),f=l(f,c,d,e,h,11,a[41]),e=l(e,f,c,d,q,16,a[42]),d=l(d,e,f,c,t,23,a[43]),c=l(c,d,e,f,x,4,a[44]),f=l(f,c,d,e,A,11,a[45]),e=l(e,f,c,d,D,16,a[46]),d=l(d,e,f,c,j,23,a[47]),c=n(c,d,e,f,h,6,a[48]),f=n(f,c,d,e,u,10,a[49]),e=n(e,f,c,d,
C,15,a[50]),d=n(d,e,f,c,s,21,a[51]),c=n(c,d,e,f,A,6,a[52]),f=n(f,c,d,e,q,10,a[53]),e=n(e,f,c,d,y,15,a[54]),d=n(d,e,f,c,w,21,a[55]),c=n(c,d,e,f,v,6,a[56]),f=n(f,c,d,e,D,10,a[57]),e=n(e,f,c,d,t,15,a[58]),d=n(d,e,f,c,B,21,a[59]),c=n(c,d,e,f,r,6,a[60]),f=n(f,c,d,e,z,10,a[61]),e=n(e,f,c,d,j,15,a[62]),d=n(d,e,f,c,x,21,a[63]);b[0]=b[0]+c|0;b[1]=b[1]+d|0;b[2]=b[2]+e|0;b[3]=b[3]+f|0},_doFinalize:function(){var a=this._data,k=a.words,b=8*this._nDataBytes,h=8*a.sigBytes;k[h>>>5]|=128<<24-h%32;var l=s.floor(b/
4294967296);k[(h+64>>>9<<4)+15]=(l<<8|l>>>24)&16711935|(l<<24|l>>>8)&4278255360;k[(h+64>>>9<<4)+14]=(b<<8|b>>>24)&16711935|(b<<24|b>>>8)&4278255360;a.sigBytes=4*(k.length+1);this._process();a=this._hash;k=a.words;for(b=0;4>b;b++)h=k[b],k[b]=(h<<8|h>>>24)&16711935|(h<<24|h>>>8)&4278255360;return a},clone:function(){var a=t.clone.call(this);a._hash=this._hash.clone();return a}});r.MD5=t._createHelper(q);r.HmacMD5=t._createHmacHelper(q)})(Math);

View file

@ -1,19 +0,0 @@
(function (globalScope) {
globalScope.ServerDiscovery = {
findServers: function (timeoutMs) {
var deferred = DeferredBuilder.Deferred();
var servers = [];
// Expected server properties
// Name, Id, Address, EndpointAddress (optional)
deferred.resolveWith(null, [servers]);
return deferred.promise();
}
};
})(window);

View file

@ -1,43 +0,0 @@
/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var CryptoJS = CryptoJS || function (e, m) {
var p = {}, j = p.lib = {}, l = function () { }, f = j.Base = { extend: function (a) { l.prototype = this; var c = new l; a && c.mixIn(a); c.hasOwnProperty("init") || (c.init = function () { c.$super.init.apply(this, arguments) }); c.init.prototype = c; c.$super = this; return c }, create: function () { var a = this.extend(); a.init.apply(a, arguments); return a }, init: function () { }, mixIn: function (a) { for (var c in a) a.hasOwnProperty(c) && (this[c] = a[c]); a.hasOwnProperty("toString") && (this.toString = a.toString) }, clone: function () { return this.init.prototype.extend(this) } },
n = j.WordArray = f.extend({
init: function (a, c) { a = this.words = a || []; this.sigBytes = c != m ? c : 4 * a.length }, toString: function (a) { return (a || h).stringify(this) }, concat: function (a) { var c = this.words, q = a.words, d = this.sigBytes; a = a.sigBytes; this.clamp(); if (d % 4) for (var b = 0; b < a; b++) c[d + b >>> 2] |= (q[b >>> 2] >>> 24 - 8 * (b % 4) & 255) << 24 - 8 * ((d + b) % 4); else if (65535 < q.length) for (b = 0; b < a; b += 4) c[d + b >>> 2] = q[b >>> 2]; else c.push.apply(c, q); this.sigBytes += a; return this }, clamp: function () {
var a = this.words, c = this.sigBytes; a[c >>> 2] &= 4294967295 <<
32 - 8 * (c % 4); a.length = e.ceil(c / 4)
}, clone: function () { var a = f.clone.call(this); a.words = this.words.slice(0); return a }, random: function (a) { for (var c = [], b = 0; b < a; b += 4) c.push(4294967296 * e.random() | 0); return new n.init(c, a) }
}), b = p.enc = {}, h = b.Hex = {
stringify: function (a) { var c = a.words; a = a.sigBytes; for (var b = [], d = 0; d < a; d++) { var f = c[d >>> 2] >>> 24 - 8 * (d % 4) & 255; b.push((f >>> 4).toString(16)); b.push((f & 15).toString(16)) } return b.join("") }, parse: function (a) {
for (var c = a.length, b = [], d = 0; d < c; d += 2) b[d >>> 3] |= parseInt(a.substr(d,
2), 16) << 24 - 4 * (d % 8); return new n.init(b, c / 2)
}
}, g = b.Latin1 = { stringify: function (a) { var c = a.words; a = a.sigBytes; for (var b = [], d = 0; d < a; d++) b.push(String.fromCharCode(c[d >>> 2] >>> 24 - 8 * (d % 4) & 255)); return b.join("") }, parse: function (a) { for (var c = a.length, b = [], d = 0; d < c; d++) b[d >>> 2] |= (a.charCodeAt(d) & 255) << 24 - 8 * (d % 4); return new n.init(b, c) } }, r = b.Utf8 = { stringify: function (a) { try { return decodeURIComponent(escape(g.stringify(a))) } catch (c) { throw Error("Malformed UTF-8 data"); } }, parse: function (a) { return g.parse(unescape(encodeURIComponent(a))) } },
k = j.BufferedBlockAlgorithm = f.extend({
reset: function () { this._data = new n.init; this._nDataBytes = 0 }, _append: function (a) { "string" == typeof a && (a = r.parse(a)); this._data.concat(a); this._nDataBytes += a.sigBytes }, _process: function (a) { var c = this._data, b = c.words, d = c.sigBytes, f = this.blockSize, h = d / (4 * f), h = a ? e.ceil(h) : e.max((h | 0) - this._minBufferSize, 0); a = h * f; d = e.min(4 * a, d); if (a) { for (var g = 0; g < a; g += f) this._doProcessBlock(b, g); g = b.splice(0, a); c.sigBytes -= d } return new n.init(g, d) }, clone: function () {
var a = f.clone.call(this);
a._data = this._data.clone(); return a
}, _minBufferSize: 0
}); j.Hasher = k.extend({
cfg: f.extend(), init: function (a) { this.cfg = this.cfg.extend(a); this.reset() }, reset: function () { k.reset.call(this); this._doReset() }, update: function (a) { this._append(a); this._process(); return this }, finalize: function (a) { a && this._append(a); return this._doFinalize() }, blockSize: 16, _createHelper: function (a) { return function (c, b) { return (new a.init(b)).finalize(c) } }, _createHmacHelper: function (a) {
return function (b, f) {
return (new s.HMAC.init(a,
f)).finalize(b)
}
}
}); var s = p.algo = {}; return p
}(Math);
(function () {
var e = CryptoJS, m = e.lib, p = m.WordArray, j = m.Hasher, l = [], m = e.algo.SHA1 = j.extend({
_doReset: function () { this._hash = new p.init([1732584193, 4023233417, 2562383102, 271733878, 3285377520]) }, _doProcessBlock: function (f, n) {
for (var b = this._hash.words, h = b[0], g = b[1], e = b[2], k = b[3], j = b[4], a = 0; 80 > a; a++) {
if (16 > a) l[a] = f[n + a] | 0; else { var c = l[a - 3] ^ l[a - 8] ^ l[a - 14] ^ l[a - 16]; l[a] = c << 1 | c >>> 31 } c = (h << 5 | h >>> 27) + j + l[a]; c = 20 > a ? c + ((g & e | ~g & k) + 1518500249) : 40 > a ? c + ((g ^ e ^ k) + 1859775393) : 60 > a ? c + ((g & e | g & k | e & k) - 1894007588) : c + ((g ^ e ^
k) - 899497514); j = k; k = e; e = g << 30 | g >>> 2; g = h; h = c
} b[0] = b[0] + h | 0; b[1] = b[1] + g | 0; b[2] = b[2] + e | 0; b[3] = b[3] + k | 0; b[4] = b[4] + j | 0
}, _doFinalize: function () { var f = this._data, e = f.words, b = 8 * this._nDataBytes, h = 8 * f.sigBytes; e[h >>> 5] |= 128 << 24 - h % 32; e[(h + 64 >>> 9 << 4) + 14] = Math.floor(b / 4294967296); e[(h + 64 >>> 9 << 4) + 15] = b; f.sigBytes = 4 * e.length; this._process(); return this._hash }, clone: function () { var e = j.clone.call(this); e._hash = this._hash.clone(); return e }
}); e.SHA1 = j._createHelper(m); e.HmacSHA1 = j._createHmacHelper(m)
})();

View file

@ -1,50 +0,0 @@
(function (globalScope, localStorage, sessionStorage) {
function myStore(defaultObject) {
var self = this;
self.localData = {};
var isDefaultAvailable;
if (defaultObject) {
try {
defaultObject.setItem('_test', '0');
isDefaultAvailable = true;
} catch (e) {
}
}
self.setItem = function (name, value) {
if (isDefaultAvailable) {
defaultObject.setItem(name, value);
} else {
self.localData[name] = value;
}
};
self.getItem = function (name) {
if (isDefaultAvailable) {
return defaultObject.getItem(name);
}
return self.localData[name];
};
self.removeItem = function (name) {
if (isDefaultAvailable) {
defaultObject.removeItem(name);
} else {
self.localData[name] = null;
}
};
}
globalScope.appStorage = new myStore(localStorage);
globalScope.sessionStore = new myStore(sessionStorage);
})(window, window.localStorage, window.sessionStorage);

View file

@ -1,14 +0,0 @@
(function (globalScope) {
function send(info) {
var deferred = DeferredBuilder.Deferred();
deferred.resolve();
return deferred.promise();
}
globalScope.WakeOnLan = {
send: send
};
})(window);

View file

@ -1,46 +0,0 @@
(function () {
function updateCredentials() {
console.log('sending updated credentials to ApiClientBridge');
var json = JSON.stringify(ConnectionManager.credentialProvider().credentials());
var credentials = JSON.parse(json);
for (var i = 0, length = credentials.Servers.length; i < length; i++) {
var server = credentials.Servers[i];
if (server.DateLastAccessed != null) {
server.DateLastAccessed = new Date(server.DateLastAccessed).toISOString();
}
}
json = JSON.stringify(credentials);
ApiClientBridge.updateCredentials(json);
}
function initNativeConnectionManager() {
console.log('initNativeConnectionManager');
var capabilities = ConnectionManager.capabilities();
ApiClientBridge.init(AppInfo.appName, AppInfo.appVersion, AppInfo.deviceId, AppInfo.deviceName, JSON.stringify(capabilities));
//initAjax();
}
Events.on(ConnectionManager.credentialProvider(), 'credentialsupdated', updateCredentials);
updateCredentials();
initNativeConnectionManager();
window.AndroidAjax = {
onResponse: function (id, status, response) {
Events.trigger(AndroidAjax, 'response' + id, [status, response]);
}
};
})();

View file

@ -1,70 +0,0 @@
(function (globalScope, localStorage, sessionStorage) {
function myStore(defaultObject) {
var self = this;
self.localData = {};
var isDefaultAvailable;
if (defaultObject) {
try {
defaultObject.setItem('_test', '0');
isDefaultAvailable = true;
} catch (e) {
}
}
self.setItem = function (name, value) {
if (isDefaultAvailable) {
defaultObject.setItem(name, value);
} else {
self.localData[name] = value;
}
};
self.getItem = function (name) {
if (isDefaultAvailable) {
return defaultObject.getItem(name);
}
return self.localData[name];
};
self.removeItem = function (name) {
if (isDefaultAvailable) {
defaultObject.removeItem(name);
} else {
self.localData[name] = null;
}
};
}
function preferencesStore() {
var self = this;
self.setItem = function (name, value) {
AndroidSharedPreferences.set(name, value);
};
self.getItem = function (name) {
return AndroidSharedPreferences.get(name);
};
self.removeItem = function (name) {
AndroidSharedPreferences.remove(name);
};
}
globalScope.appStorage = new preferencesStore();
globalScope.sessionStore = new myStore(sessionStorage);
})(window, window.localStorage, window.sessionStorage);

View file

@ -1,14 +0,0 @@
(function () {
window.FileSystemBridge = {
fileExists: function (path) {
return NativeFileSystem.fileExists(path);
},
translateFilePath: function (path) {
return 'file://' + NativeFileSystem.translateFilePath(path);
}
};
})();

View file

@ -1,61 +0,0 @@
(function () {
var unlockId = "com.mb.android.unlock";
var updatedProducts = [];
function updateProductInfo(id, owned, price) {
updatedProducts = updatedProducts.filter(function (r) {
return r.id != id;
});
var product = {
id: id,
owned: owned,
price: price
};
updatedProducts.push(product);
Events.trigger(IapManager, 'productupdated', [product]);
}
function getProduct(id) {
var products = updatedProducts.filter(function (r) {
return r.id == id;
});
return products.length ? products[0] : null;
}
function isPurchaseAvailable(id) {
return NativeIapManager.isStoreAvailable();
}
function beginPurchase(id) {
return MainActivity.beginPurchase(id);
}
function onPurchaseComplete(result) {
if (result) {
refreshPurchases();
}
}
function refreshPurchases() {
NativeIapManager.isPurchased(unlockId, "window.IapManager.updateProduct");
}
window.IapManager = {
isPurchaseAvailable: isPurchaseAvailable,
getProductInfo: getProduct,
updateProduct: updateProductInfo,
beginPurchase: beginPurchase,
onPurchaseComplete: onPurchaseComplete
};
refreshPurchases();
})();

View file

@ -1,111 +0,0 @@
(function () {
function onSuccess() {
console.log('Immersive mode succeeded');
}
function onError() {
console.log('Immersive mode failed');
}
//// Is this plugin supported?
//AndroidFullScreen.isSupported();
//// Is immersive mode supported?
//AndroidFullScreen.isImmersiveModeSupported(onSuccess, onError);
//// The width of the screen in immersive mode
//AndroidFullScreen.immersiveWidth(trace, onError);
//// The height of the screen in immersive mode
//AndroidFullScreen.immersiveHeight(trace, onError);
//// Hide system UI until user interacts
//AndroidFullScreen.leanMode(onSuccess, onError);
//// Show system UI
//AndroidFullScreen.showSystemUI(onSuccess, onError);
//// Extend your app underneath the system UI (Android 4.4+ only)
//AndroidFullScreen.showUnderSystemUI(onSuccess, onError);
//// Hide system UI and keep it hidden (Android 4.4+ only)
//AndroidFullScreen.immersiveMode(onSuccess, onError);
var currentPlayer;
function onPlaybackStart(e, state) {
var player = this;
if (player.isLocalPlayer && state.NowPlayingItem && state.NowPlayingItem.MediaType == 'Video') {
AndroidFullScreen.immersiveMode(onSuccess, onError);
}
}
function onPlaybackStopped(e, state) {
var player = this;
if (player.isLocalPlayer && state.NowPlayingItem && state.NowPlayingItem.MediaType == 'Video') {
if (!AppSettings.enableFullScreen()) {
AndroidFullScreen.showSystemUI(onSuccess, onError);
}
}
}
function bindToPlayer(player) {
releaseCurrentPlayer();
currentPlayer = player;
if (!player.isLocalPlayer) {
return;
}
$(player).on('playbackstart.fullscreen', onPlaybackStart)
.on('playbackstop.fullscreen', onPlaybackStopped);
}
function releaseCurrentPlayer() {
if (currentPlayer) {
$(currentPlayer).off('.fullscreen');
}
}
function updateFromSetting(leaveFullScreen) {
if (AppSettings.enableFullScreen()) {
AndroidFullScreen.immersiveMode(onSuccess, onError);
}
else if (leaveFullScreen) {
AndroidFullScreen.showSystemUI(onSuccess, onError);
}
}
Dashboard.ready(function () {
console.log('binding fullscreen to MediaController');
$(MediaController).on('playerchange', function () {
bindToPlayer(MediaController.getCurrentPlayer());
});
bindToPlayer(MediaController.getCurrentPlayer());
updateFromSetting(false);
$(AppSettings).on('settingupdated', function (e, key) {
if (key == 'enableFullScreen') {
updateFromSetting(true);
}
});
});
})();

View file

@ -1,17 +0,0 @@
(function () {
function getLocalMediaSource(serverId, itemId) {
var json = ApiClientBridge.getLocalMediaSource(serverId, itemId);
if (json) {
return JSON.parse(json);
}
return null;
}
window.LocalAssetManager = {
getLocalMediaSource: getLocalMediaSource
};
})();

View file

@ -1,163 +0,0 @@
(function () {
// Reports media playback to the device for lock screen control
var currentPlayer;
var lastPlayerState;
var lastUpdateTime = 0;
function updatePlayerState(state, eventName) {
if (!state.NowPlayingItem) {
hideMediaControls();
return;
}
// dummy this up
if (eventName == 'init') {
eventName = 'positionchange';
}
lastPlayerState = state;
var playState = state.PlayState || {};
var nameHtml = MediaController.getNowPlayingNameHtml(state.NowPlayingItem) || '';
var parts = nameHtml.split('<br/>');
var artist = parts.length == 1 ? '' : parts[0];
var title = parts[parts.length - 1];
var album = state.NowPlayingItem.Album || '';
var duration = state.NowPlayingItem.RunTimeTicks ? (state.NowPlayingItem.RunTimeTicks / 10000000) : 0;
var position = playState.PositionTicks ? (playState.PositionTicks / 10000000) : 0;
var itemId = state.NowPlayingItem.Id;
var isPaused = playState.IsPaused || false;
var canSeek = playState.CanSeek || false;
var url = '';
var imgHeight = 400;
var nowPlayingItem = state.NowPlayingItem;
if (nowPlayingItem.PrimaryImageTag) {
url = ApiClient.getScaledImageUrl(nowPlayingItem.PrimaryImageItemId, {
type: "Primary",
height: imgHeight,
tag: nowPlayingItem.PrimaryImageTag
});
} else if (nowPlayingItem.ThumbImageTag) {
url = ApiClient.getScaledImageUrl(nowPlayingItem.ThumbImageItemId, {
type: "Thumb",
height: imgHeight,
tag: nowPlayingItem.ThumbImageTag
});
}
else if (nowPlayingItem.BackdropImageTag) {
url = ApiClient.getScaledImageUrl(nowPlayingItem.BackdropItemId, {
type: "Backdrop",
height: imgHeight,
tag: nowPlayingItem.BackdropImageTag,
index: 0
});
}
// Don't go crazy reporting position changes
if (eventName == 'positionchange') {
if (lastUpdateTime) {
// Only report if this item hasn't been reported yet, or if there's an actual playback change.
// Don't report on simple time updates
return;
}
}
var isLocalPlayer = MediaController.getPlayerInfo().isLocalPlayer || false;
MainActivity.updateMediaSession(eventName, isLocalPlayer, itemId, title, artist, album, parseInt(duration), parseInt(position), url, canSeek, isPaused);
lastUpdateTime = new Date().getTime();
}
function onStateChanged(e, state) {
updatePlayerState(state, e.type);
}
function onPlaybackStart(e, state) {
console.log('nowplaying event: ' + e.type);
var player = this;
player.beginPlayerUpdates();
onStateChanged.call(player, e, state);
}
function onPlaybackStopped(e, state) {
console.log('nowplaying event: ' + e.type);
var player = this;
player.endPlayerUpdates();
hideMediaControls();
}
function releaseCurrentPlayer() {
if (currentPlayer) {
$(currentPlayer).off('.cordovaremote');
currentPlayer.endPlayerUpdates();
currentPlayer = null;
hideMediaControls();
}
}
function hideMediaControls() {
MainActivity.hideMediaSession();
lastUpdateTime = 0;
}
function bindToPlayer(player) {
releaseCurrentPlayer();
currentPlayer = player;
console.log('binding remotecontrols to MediaPlayer');
player.getPlayerState().done(function (state) {
if (state.NowPlayingItem) {
player.beginPlayerUpdates();
}
onStateChanged.call(player, { type: 'init' }, state);
});
$(player).on('playbackstart.cordovaremote', onPlaybackStart)
.on('playbackstop.cordovaremote', onPlaybackStopped)
.on('playstatechange.cordovaremote', onStateChanged)
.on('positionchange.cordovaremote', onStateChanged);
}
Dashboard.ready(function () {
console.log('binding remotecontrols to MediaController');
$(MediaController).on('playerchange', function () {
bindToPlayer(MediaController.getCurrentPlayer());
});
bindToPlayer(MediaController.getCurrentPlayer());
});
})();

View file

@ -1,31 +0,0 @@
(function () {
var currentDeferred;
function chooseDirectory() {
var deferred = DeferredBuilder.Deferred();
AndroidDirectoryChooser.chooseDirectory();
currentDeferred = deferred;
return deferred.promise();
}
function onChosen(path) {
var deferred = currentDeferred;
if (deferred) {
if (path) {
deferred.resolveWith(null, [path]);
} else {
deferred.reject();
}
currentDeferred = null;
}
}
window.NativeDirectoryChooser = {
chooseDirectory: chooseDirectory,
onChosen: onChosen
};
})();

View file

@ -1,165 +0,0 @@
(function () {
function vlcRenderer(type) {
var self = this;
function onEnded() {
$(self).trigger('ended');
}
function onTimeUpdate() {
$(self).trigger('timeupdate');
}
function onVolumeChange() {
$(self).trigger('volumechange');
}
function onPlaying() {
$(self).trigger('playing');
}
function onPlay() {
$(self).trigger('play');
}
function onPause() {
$(self).trigger('pause');
}
function onClick() {
$(self).trigger('click');
}
function onDblClick() {
$(self).trigger('dblclick');
}
function onError() {
var errorCode = this.error ? this.error.code : '';
console.log('Media element error code: ' + errorCode);
$(self).trigger('error');
}
var playerState = {};
self.currentTime = function (val) {
if (val != null) {
AndroidVlcPlayer.sendVlcCommand("setposition", val.toString());
return;
}
return playerState.currentTime;
};
self.duration = function (val) {
if (playerState) {
return playerState.duration;
}
return null;
};
self.stop = function () {
AndroidVlcPlayer.sendVlcCommand("stop", null);
};
self.pause = function () {
AndroidVlcPlayer.sendVlcCommand("pause", null);
};
self.unpause = function () {
AndroidVlcPlayer.sendVlcCommand("unpause", null);
};
self.volume = function (val) {
if (playerState) {
if (val != null) {
AndroidVlcPlayer.sendVlcCommand("setvolume", (val * 100).toString());
return;
}
return playerState.volume;
}
};
self.setCurrentSrc = function (val) {
if (!val) {
self.destroy();
return;
}
if (type == 'audio') {
AndroidVlcPlayer.playAudioVlc(val);
} else {
AndroidVlcPlayer.playVideoVlc(val);
}
playerState.currentSrc = val;
};
self.currentSrc = function () {
if (playerState) {
return playerState.currentSrc;
}
};
self.paused = function () {
if (playerState) {
return playerState.paused;
}
return false;
};
self.destroy = function () {
AndroidVlcPlayer.destroyVlc();
playerState = {};
};
self.setPoster = function (url) {
};
self.report = function (eventName, duration, position, isPaused, volume) {
var state = playerState;
state.duration = duration;
state.currentTime = position;
state.paused = isPaused;
state.volume = (volume || 0) / 100;
if (eventName == 'playbackstop') {
onEnded();
}
else if (eventName == 'volumechange') {
onVolumeChange();
}
else if (eventName == 'positionchange') {
onTimeUpdate();
}
else if (eventName == 'paused') {
onPause();
}
else if (eventName == 'unpaused') {
onPlaying();
}
else if (eventName == 'playing') {
onPlaying();
}
};
window.AudioRenderer.Current = self;
}
window.AudioRenderer = vlcRenderer;
})();

View file

@ -1,24 +0,0 @@
(function () {
Dashboard.exit = function () {
if (navigator.app && navigator.app.exitApp) {
navigator.app.exitApp();
} else {
Dashboard.logout();
}
};
function onBackKeyDown(e) {
if (Dashboard.exitOnBack()) {
e.preventDefault();
Dashboard.exit();
}
else {
history.back();
}
}
document.addEventListener("backbutton", onBackKeyDown, false);
})();

View file

@ -1,664 +0,0 @@
(function () {
function chromecastPlayer() {
var self = this;
var PlayerName = "Chromecast";
var ApplicationID = "2D4B1DA3";
var currentWebAppSession;
var currentDevice;
var currentDeviceId;
// MediaController needs this
self.name = PlayerName;
self.getItemsForPlayback = function (query) {
var userId = Dashboard.getCurrentUserId();
query.Limit = query.Limit || 100;
query.ExcludeLocationTypes = "Virtual";
return ApiClient.getItems(userId, query);
};
var castPlayer = {};
$(castPlayer).on("connect", function (e) {
console.log('cc: connect');
// Reset this so the next query doesn't make it appear like content is playing.
self.lastPlayerData = {};
});
$(castPlayer).on("playbackstart", function (e, data) {
console.log('cc: playbackstart');
var state = self.getPlayerStateInternal(data);
$(self).trigger("playbackstart", [state]);
});
$(castPlayer).on("playbackstop", function (e, data) {
console.log('cc: playbackstop');
var state = self.getPlayerStateInternal(data);
$(self).trigger("playbackstop", [state]);
// Reset this so the next query doesn't make it appear like content is playing.
self.lastPlayerData = {};
});
$(castPlayer).on("playbackprogress", function (e, data) {
console.log('cc: positionchange');
var state = self.getPlayerStateInternal(data);
$(self).trigger("positionchange", [state]);
});
var endpointInfo;
function getEndpointInfo() {
if (endpointInfo) {
var deferred = $.Deferred();
deferred.resolveWith(null, [endpointInfo]);
return deferred.promise();
}
return ApiClient.getJSON(ApiClient.getUrl('System/Endpoint')).done(function (info) {
endpointInfo = info;
});
}
function sendMessageToDevice(message) {
var bitrateSetting = AppSettings.maxChromecastBitrate();
message = $.extend(message, {
userId: Dashboard.getCurrentUserId(),
deviceId: ApiClient.deviceId(),
accessToken: ApiClient.accessToken(),
serverAddress: ApiClient.serverAddress(),
maxBitrate: bitrateSetting,
receiverName: currentDevice.getFriendlyName(),
supportsAc3: AppSettings.enableChromecastAc3()
});
getEndpointInfo().done(function (endpoint) {
if (endpoint.IsLocal || endpoint.IsInNetwork) {
ApiClient.getPublicSystemInfo().done(function (info) {
message.serverAddress = info.LocalAddress;
sendMessageInternal(message);
});
} else {
sendMessageInternal(message);
}
});
}
function sendMessageInternal(message) {
currentWebAppSession.sendText(JSON.stringify(message));
}
self.play = function (options) {
Dashboard.getCurrentUser().done(function (user) {
if (options.items) {
self.playWithCommand(options, 'PlayNow');
} else {
self.getItemsForPlayback({
Ids: options.ids.join(',')
}).done(function (result) {
options.items = result.Items;
self.playWithCommand(options, 'PlayNow');
});
}
});
};
self.playWithCommand = function (options, command) {
if (!options.items) {
ApiClient.getItem(Dashboard.getCurrentUserId(), options.ids[0]).done(function (item) {
options.items = [item];
self.playWithCommand(options, command);
});
return;
}
// Convert the items to smaller stubs to send the minimal amount of information
options.items = options.items.map(function (i) {
return {
Id: i.Id,
Name: i.Name,
Type: i.Type,
MediaType: i.MediaType,
IsFolder: i.IsFolder
};
});
sendMessageToDevice({
options: options,
command: command
});
};
self.unpause = function () {
sendMessageToDevice({
command: 'Unpause'
});
};
self.pause = function () {
sendMessageToDevice({
command: 'Pause'
});
};
self.shuffle = function (id) {
var userId = Dashboard.getCurrentUserId();
ApiClient.getItem(userId, id).done(function (item) {
self.playWithCommand({
items: [item]
}, 'Shuffle');
});
};
self.instantMix = function (id) {
var userId = Dashboard.getCurrentUserId();
ApiClient.getItem(userId, id).done(function (item) {
self.playWithCommand({
items: [item]
}, 'InstantMix');
});
};
self.canQueueMediaType = function (mediaType) {
return mediaType == "Audio";
};
self.queue = function (options) {
self.playWithCommnd(options, 'PlayLast');
};
self.queueNext = function (options) {
self.playWithCommand(options, 'PlayNext');
};
self.stop = function () {
sendMessageToDevice({
command: 'Stop'
});
};
self.displayContent = function (options) {
sendMessageToDevice({
options: options,
command: 'DisplayContent'
});
};
self.mute = function () {
sendMessageToDevice({
command: 'Mute'
});
};
self.unMute = function () {
self.setVolume(getCurrentVolume() + 2);
};
self.toggleMute = function () {
var state = self.lastPlayerData || {};
state = state.PlayState || {};
if (state.IsMuted) {
self.unMute();
} else {
self.mute();
}
};
function getBaseTargetInfo() {
var target = {};
target.playerName = PlayerName;
target.playableMediaTypes = ["Audio", "Video"];
target.isLocalPlayer = false;
target.appName = PlayerName;
target.supportedCommands = [
"VolumeUp",
"VolumeDown",
"Mute",
"Unmute",
"ToggleMute",
"SetVolume",
"SetAudioStreamIndex",
"SetSubtitleStreamIndex",
"DisplayContent"
];
return target;
}
function convertDeviceToTarget(device) {
var target = getBaseTargetInfo();
target.name = target.deviceName = device.getFriendlyName();
target.id = device.getId();
return target;
}
function isChromecast(name) {
name = (name || '').toLowerCase();
var validTokens = ['nexusplayer', 'chromecast', 'eurekadongle'];
return validTokens.filter(function (t) {
return name.replace(' ', '').indexOf(t) != -1;
}).length > 0;
}
self.getTargets = function () {
return ConnectSDKHelper.getDeviceList().filter(function (d) {
return isChromecast(d.getModelName()) || isChromecast(d.getFriendlyName());
}).map(convertDeviceToTarget);
};
self.seek = function (position) {
position = parseInt(position);
position = position / 10000000;
sendMessageToDevice({
options: {
position: position
},
command: 'Seek'
});
};
self.setAudioStreamIndex = function (index) {
sendMessageToDevice({
options: {
index: index
},
command: 'SetAudioStreamIndex'
});
};
self.setSubtitleStreamIndex = function (index) {
sendMessageToDevice({
options: {
index: index
},
command: 'SetSubtitleStreamIndex'
});
};
self.nextTrack = function () {
sendMessageToDevice({
options: {},
command: 'NextTrack'
});
};
self.previousTrack = function () {
sendMessageToDevice({
options: {},
command: 'PreviousTrack'
});
};
self.beginPlayerUpdates = function () {
// Setup polling here
};
self.endPlayerUpdates = function () {
// Stop polling here
};
function getCurrentVolume() {
var state = self.lastPlayerData || {};
state = state.PlayState || {};
return state.VolumeLevel == null ? 100 : state.VolumeLevel;
}
self.volumeDown = function () {
sendMessageToDevice({
options: {},
command: 'VolumeDown'
});
};
self.volumeUp = function () {
sendMessageToDevice({
options: {},
command: 'VolumeUp'
});
};
self.setVolume = function (vol) {
vol = Math.min(vol, 100);
vol = Math.max(vol, 0);
sendMessageToDevice({
options: {
volume: vol
},
command: 'SetVolume'
});
};
self.getPlayerState = function () {
var deferred = $.Deferred();
var result = self.getPlayerStateInternal();
deferred.resolveWith(null, [result]);
return deferred.promise();
};
self.lastPlayerData = {};
self.getPlayerStateInternal = function (data) {
data = data || self.lastPlayerData;
self.lastPlayerData = data;
console.log(JSON.stringify(data));
return data;
};
function onMessage(message) {
if (message.type == 'playbackerror') {
var errorCode = message.data;
setTimeout(function () {
Dashboard.alert({
message: Globalize.translate('MessagePlaybackError' + errorCode),
title: Globalize.translate('HeaderPlaybackError')
});
}, 300);
}
else if (message.type == 'connectionerror') {
setTimeout(function () {
Dashboard.alert({
message: Globalize.translate('MessageChromecastConnectionError'),
title: Globalize.translate('HeaderError')
});
}, 300);
}
else if (message.type && message.type.indexOf('playback') == 0) {
$(castPlayer).trigger(message.type, [message.data]);
}
}
function handleMessage(message) {
// message could be either a string or an object
if (typeof message === 'string') {
onMessage(JSON.parse(message));
} else {
onMessage(message);
}
}
function handleSessionDisconnect() {
console.log("session disconnected");
cleanupSession();
MediaController.removeActivePlayer(PlayerName);
}
function onWebAppSessionConnect(webAppSession, device) {
currentWebAppSession = webAppSession;
console.log('session.connect succeeded');
webAppSession.setWebAppSessionListener();
MediaController.setActivePlayer(PlayerName, convertDeviceToTarget(device));
currentDevice = device;
currentDeviceId = device.getId();
$(castPlayer).trigger('connect');
sendIdentifyMessage();
}
function setupWebAppSession(device, session, connectToSession) {
// hold on to a reference
var currentSession = session.acquire();
currentSession.on('message', handleMessage);
currentSession.on('disconnect', handleSessionDisconnect);
if (connectToSession || $.browser.safari) {
currentSession.connect().success(function () {
onWebAppSessionConnect(currentSession, device);
}).error(handleSessionError);
} else {
onWebAppSessionConnect(currentSession, device);
}
}
function sendIdentifyMessage() {
sendMessageToDevice({
options: {},
command: 'Identify'
});
}
function handleSessionError() {
cleanupSession();
}
function cleanupSession() {
var session = currentWebAppSession;
if (session) {
// Clean up listeners
session.off("message");
session.off("disconnect");
// Release session to free up memory
session.disconnect();
session.release();
}
currentWebAppSession = null;
}
function tryLaunchWebSession(device) {
console.log('calling launchWebApp');
device.getWebAppLauncher().launchWebApp(ApplicationID).success(function (session) {
console.log('launchWebApp success. calling onSessionConnected');
setupWebAppSession(device, session, true);
}).error(function (err1) {
console.log('launchWebApp error:' + JSON.stringify(err1));
});
}
function tryJoinWebSession(device, enableRetry) {
// First try to join existing session. If it fails, launch a new one
console.log('calling joinWebApp');
device.getWebAppLauncher().joinWebApp(ApplicationID).success(function (session) {
console.log('joinWebApp success. calling onSessionConnected');
setupWebAppSession(device, session, false);
}).error(function (err) {
console.log('joinWebApp error: ' + JSON.stringify(err));
if (enableRetry) {
tryJoinWebSession(device, false);
return;
}
console.log('calling launchWebApp');
tryLaunchWebSession(device);
});
}
function launchWebApp(device) {
if (currentWebAppSession) {
cleanupSession();
}
tryJoinWebSession(device, true);
}
function onDeviceReady(device) {
device.off("ready");
console.log('creating webAppSession');
launchWebApp(device);
}
self.tryPair = function (target) {
var deferred = $.Deferred();
var device = ConnectSDKHelper.getDeviceList().filter(function (d) {
return d.getId() == target.id;
})[0];
if (device) {
self.tryPairWithDevice(device, deferred);
} else {
deferred.reject();
}
return deferred.promise();
};
self.tryPairWithDevice = function (device, deferred) {
console.log('Will attempt to connect to Chromecast');
device.on("disconnect", function () {
device.off("ready");
device.off("disconnect");
});
if (device.isReady()) {
console.log('Device is already ready, calling onDeviceReady');
onDeviceReady(device);
} else {
console.log('Binding device ready handler');
device.on("ready", function () {
console.log('device.ready fired');
onDeviceReady(device);
});
console.log('Calling device.connect');
device.connect();
}
};
$(MediaController).on('playerchange', function (e, newPlayer, newTarget) {
if (newTarget.id != currentDeviceId) {
if (currentWebAppSession) {
console.log('Disconnecting from chromecast');
//currentDevice.disconnect();
cleanupSession();
currentDevice = null;
currentDeviceId = null;
}
}
});
function onResume() {
var deviceId = currentDeviceId;
if (deviceId) {
self.tryPair({
id: deviceId
});
}
}
document.addEventListener("resume", onResume, false);
}
MediaController.registerPlayer(new chromecastPlayer());
})();

View file

@ -1,36 +0,0 @@
(function () {
function initSdk() {
var manager = ConnectSDK.discoveryManager;
//manager.setPairingLevel(ConnectSDK.PairingLevel.OFF);
manager.setAirPlayServiceMode(ConnectSDK.AirPlayServiceMode.Media);
// Show devices that support playing videos and pausing
//manager.setCapabilityFilters([
// new ConnectSDK.CapabilityFilter(["MediaPlayer.Display.Video", "MediaControl.Pause"])
//]);
manager.on('devicelistchanged', onDeviceListChanged);
manager.startDiscovery();
requirejs(['thirdparty/cordova/chromecast', 'thirdparty/cordova/generaldevice']);
}
function onDeviceListChanged(list) {
}
function getDeviceList() {
return ConnectSDK.discoveryManager.getDeviceList();
}
window.ConnectSDKHelper = {
getDeviceList: getDeviceList
};
Dashboard.ready(initSdk);
})();

View file

@ -1,23 +0,0 @@
(function () {
function showPlayerSelectionMenu(item, url, mimeType) {
window.plugins.launcher.launch({
uri: url,
dataType: mimeType
}, function () {
console.log('plugin launch success');
ExternalPlayer.onPlaybackStart();
}, function () {
console.log('plugin launch error');
ExternalPlayer.onPlaybackStart();
});
}
window.ExternalPlayer.showPlayerSelectionMenu = showPlayerSelectionMenu;
})();

View file

@ -1,14 +0,0 @@
(function () {
window.FileSystemBridge = {
fileExists: function (path) {
return false;
},
translateFilePath: function (path) {
return 'file://' + path;
}
};
})();

View file

@ -1,675 +0,0 @@
(function () {
function connectSDKPlayer() {
var self = this;
var PlayerName = "ConnectSDK";
var currentDevice;
var currentDeviceId;
var currentMediaControl;
// MediaController needs this
self.name = PlayerName;
self.getItemsForPlayback = function (query) {
var userId = Dashboard.getCurrentUserId();
query.Limit = query.Limit || 100;
query.ExcludeLocationTypes = "Virtual";
return ApiClient.getItems(userId, query);
};
var castPlayer = {};
$(castPlayer).on("playbackstart", function (e, data) {
console.log('cc: playbackstart');
var state = self.getPlayerStateInternal(data);
$(self).trigger("playbackstart", [state]);
});
$(castPlayer).on("playbackstop", function (e, data) {
console.log('cc: playbackstop');
var state = self.getPlayerStateInternal(data);
$(self).trigger("playbackstop", [state]);
// Reset this so the next query doesn't make it appear like content is playing.
self.lastPlayerData = {};
});
$(castPlayer).on("playbackprogress", function (e, data) {
console.log('cc: positionchange');
var state = self.getPlayerStateInternal(data);
$(self).trigger("positionchange", [state]);
});
self.play = function (options) {
Dashboard.getCurrentUser().done(function (user) {
if (options.items) {
self.playWithCommand(options, 'PlayNow');
} else {
self.getItemsForPlayback({
Ids: options.ids.join(',')
}).done(function (result) {
options.items = result.Items;
self.playWithCommand(options, 'PlayNow');
});
}
});
};
self.playWithCommand = function (options, command) {
if (!options.items) {
ApiClient.getItem(Dashboard.getCurrentUserId(), options.ids[0]).done(function (item) {
options.items = [item];
self.playWithCommand(options, command);
});
return;
}
playItemInternal(items[0], null, serverAddress);
};
function validatePlaybackInfoResult(result) {
if (result.ErrorCode) {
MediaController.showPlaybackInfoErrorMessage(result.ErrorCode);
return false;
}
return true;
}
function getOptimalMediaSource(mediaType, versions) {
var optimalVersion = versions.filter(function (v) {
v.enableDirectPlay = MediaController.supportsDirectPlay(v);
return v.enableDirectPlay;
})[0];
if (!optimalVersion) {
optimalVersion = versions.filter(function (v) {
return v.SupportsDirectStream;
})[0];
}
return optimalVersion || versions.filter(function (s) {
return s.SupportsTranscoding;
})[0];
}
function playItemInternal(item, startPosition) {
if (item == null) {
throw new Error("item cannot be null");
}
if (item.MediaType !== 'Audio' && item.MediaType !== 'Video') {
throw new Error("Unrecognized media type");
}
if (item.IsPlaceHolder) {
MediaController.showPlaybackInfoErrorMessage('PlaceHolder');
return;
}
var deviceProfile = self.getDeviceProfile();
if (item.MediaType === "Video") {
Dashboard.showModalLoadingMsg();
}
MediaController.getPlaybackInfo(item.Id, deviceProfile, startPosition).done(function (playbackInfoResult) {
if (validatePlaybackInfoResult(playbackInfoResult)) {
var mediaSource = getOptimalMediaSource(item.MediaType, playbackInfoResult.MediaSources);
if (mediaSource) {
if (mediaSource.RequiresOpening) {
getLiveStream(item.Id, playbackInfoResult.PlaySessionId, deviceProfile, startPosition, mediaSource, null, null).done(function (openLiveStreamResult) {
openLiveStreamResult.MediaSource.enableDirectPlay = supportsDirectPlay(openLiveStreamResult.MediaSource);
playInternalPostMediaSourceSelection(item, openLiveStreamResult.MediaSource, startPosition, callback);
});
} else {
playInternalPostMediaSourceSelection(item, mediaSource, startPosition, callback);
}
} else {
Dashboard.hideModalLoadingMsg();
MediaController.showPlaybackInfoErrorMessage('NoCompatibleStream');
}
}
});
}
function playInternalPostMediaSourceSelection(item, mediaSource, startPosition, deferred) {
Dashboard.hideModalLoadingMsg();
var streamInfo = MediaPlayer.createStreamInfo('Video', item, mediaSource, startPosition);
currentDevice.getMediaPlayer().playMedia(
streamInfo.url,
streamInfo.MimeType,
{
title: item.Name,
description: item.Overview || '',
shouldLoop: false
}
).success(function (launchSession, mediaControl) {
console.log("Video launch successful");
currentMediaControl = mediaControl && mediaControl.acquire();
}).error(function (err) {
console.log("error: " + err.message);
});
deferred.resolveWith(null, [streamInfo]);
}
self.unpause = function () {
if (currentMediaControl) {
currentMediaControl.pause();
}
};
self.pause = function () {
if (currentMediaControl) {
currentMediaControl.pause();
}
};
self.shuffle = function (id) {
var userId = Dashboard.getCurrentUserId();
ApiClient.getItem(userId, id).done(function (item) {
self.playWithCommand({
items: [item]
}, 'Shuffle');
});
};
self.instantMix = function (id) {
var userId = Dashboard.getCurrentUserId();
ApiClient.getItem(userId, id).done(function (item) {
self.playWithCommand({
items: [item]
}, 'InstantMix');
});
};
self.canQueueMediaType = function (mediaType) {
return mediaType == "Audio";
};
self.queue = function (options) {
self.playWithCommnd(options, 'PlayLast');
};
self.queueNext = function (options) {
self.playWithCommand(options, 'PlayNext');
};
self.stop = function () {
if (currentMediaControl) {
currentMediaControl.stop();
}
};
self.displayContent = function (options) {
// TODO
};
self.mute = function () {
if (currentDevice) {
currentDevice.getVolumeControl().setMute(true);
}
};
self.unMute = function () {
self.setVolume(getCurrentVolume() + 2);
};
self.toggleMute = function () {
var state = self.lastPlayerData || {};
state = state.PlayState || {};
if (state.IsMuted) {
self.unMute();
} else {
self.mute();
}
};
self.getDeviceProfile = function () {
var qualityOption = self.getVideoQualityOptions().filter(function (q) {
return q.selected;
})[0];
var bitrateSetting = AppSettings.maxStreamingBitrate();
var profile = {};
profile.MaxStreamingBitrate = bitrateSetting;
profile.MaxStaticBitrate = 40000000;
profile.MusicStreamingTranscodingBitrate = Math.min(bitrateSetting, 192000);
profile.DirectPlayProfiles = [];
profile.DirectPlayProfiles.push({
Container: 'mp4,m4v',
Type: 'Video',
VideoCodec: 'h264',
AudioCodec: 'aac,mp3,ac3'
});
profile.DirectPlayProfiles.push({
Container: 'mov',
Type: 'Video'
});
profile.DirectPlayProfiles.push({
Container: 'mp3',
Type: 'Audio'
});
profile.DirectPlayProfiles.push({
Container: 'aac',
Type: 'Audio'
});
profile.TranscodingProfiles = [];
profile.TranscodingProfiles.push({
Container: 'mp3',
Type: 'Audio',
AudioCodec: 'mp3',
Context: 'Streaming',
Protocol: 'http'
});
if (self.canPlayHls()) {
profile.TranscodingProfiles.push({
Container: 'ts',
Type: 'Video',
AudioCodec: 'aac',
VideoCodec: 'h264',
Context: 'Streaming',
Protocol: 'hls'
});
}
profile.TranscodingProfiles.push({
Container: 'mp4',
Type: 'Video',
AudioCodec: 'aac',
VideoCodec: 'h264',
Context: 'Streaming',
Protocol: 'http'
});
profile.ContainerProfiles = [];
profile.CodecProfiles = [];
profile.CodecProfiles.push({
Type: 'Audio',
Conditions: [{
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: '2'
}]
});
profile.CodecProfiles.push({
Type: 'VideoAudio',
Codec: 'aac,mp3',
Conditions: [
{
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: '6'
}
]
});
profile.CodecProfiles.push({
Type: 'Video',
Codec: 'h264',
Conditions: [
{
Condition: 'NotEquals',
Property: 'IsAnamorphic',
Value: 'true',
IsRequired: false
},
{
Condition: 'EqualsAny',
Property: 'VideoProfile',
Value: 'high|main|baseline|constrained baseline'
},
{
Condition: 'LessThanEqual',
Property: 'VideoLevel',
Value: '41'
},
{
Condition: 'LessThanEqual',
Property: 'Width',
Value: qualityOption.maxWidth
}]
});
// Subtitle profiles
profile.SubtitleProfiles = [];
profile.ResponseProfiles = [];
profile.ResponseProfiles.push({
Type: 'Video',
Container: 'm4v',
MimeType: 'video/mp4'
});
//profile.ResponseProfiles.push({
// Type: 'Video',
// Container: 'mkv',
// MimeType: 'video/webm'
//});
return profile;
};
function getBaseTargetInfo() {
var target = {};
target.playableMediaTypes = ["Audio", "Video"];
target.isLocalPlayer = false;
target.supportedCommands = [
"VolumeUp",
"VolumeDown",
"Mute",
"Unmute",
"ToggleMute",
"SetVolume"
];
return target;
}
function convertDeviceToTarget(device) {
var target = getBaseTargetInfo();
target.appName = target.name = target.deviceName = device.getFriendlyName();
target.playerName = PlayerName;
target.id = device.getId();
return target;
}
function isValid(device) {
var validTokens = ['AirPlay', 'Airplay', 'airplay'];
return validTokens.filter(function (t) {
return device.hasService(t);
}).length > 0;
}
self.getTargets = function () {
return ConnectSDKHelper.getDeviceList().filter(function (d) {
return isValid(d);
}).map(convertDeviceToTarget);
};
self.seek = function (position) {
position = parseInt(position);
position = position / 10000000;
// TODO
};
self.setAudioStreamIndex = function (index) {
// TODO
};
self.setSubtitleStreamIndex = function (index) {
// TODO
};
self.nextTrack = function () {
// TODO
};
self.previousTrack = function () {
// TODO
};
self.beginPlayerUpdates = function () {
// Setup polling here
};
self.endPlayerUpdates = function () {
// Stop polling here
};
function getCurrentVolume() {
var state = self.lastPlayerData || {};
state = state.PlayState || {};
return state.VolumeLevel == null ? 100 : state.VolumeLevel;
}
self.volumeDown = function () {
if (currentDevice) {
currentDevice.getVolumeControl().volumeDown();
}
};
self.volumeUp = function () {
if (currentDevice) {
currentDevice.getVolumeControl().volumeUp();
}
};
self.setVolume = function (vol) {
vol = Math.min(vol, 100);
vol = Math.max(vol, 0);
if (currentDevice) {
currentDevice.getVolumeControl().setVolume(vol / 100);
}
};
self.getPlayerState = function () {
var deferred = $.Deferred();
var result = self.getPlayerStateInternal();
deferred.resolveWith(null, [result]);
return deferred.promise();
};
self.lastPlayerData = {};
self.getPlayerStateInternal = function (data) {
data = data || self.lastPlayerData;
self.lastPlayerData = data;
console.log(JSON.stringify(data));
return data;
};
function handleSessionDisconnect() {
console.log("session disconnected");
cleanupSession();
MediaController.removeActivePlayer(PlayerName);
}
function cleanupSession() {
}
function launchWebApp(device) {
if (currentDevice) {
cleanupSession();
}
console.log('session.connect succeeded');
MediaController.setActivePlayer(PlayerName, convertDeviceToTarget(device));
currentDevice = device;
currentDeviceId = device.getId();
}
function onDeviceReady(device) {
device.off("ready");
console.log('creating webAppSession');
launchWebApp(device);
}
self.tryPair = function (target) {
var deferred = $.Deferred();
var device = ConnectSDKHelper.getDeviceList().filter(function (d) {
return d.getId() == target.id;
})[0];
if (device) {
self.tryPairWithDevice(device, deferred);
} else {
deferred.reject();
}
return deferred.promise();
};
self.tryPairWithDevice = function (device, deferred) {
console.log('Will attempt to connect to Connect Device');
device.on("disconnect", function () {
device.off("ready");
device.off("disconnect");
});
if (device.isReady()) {
console.log('Device is already ready, calling onDeviceReady');
onDeviceReady(device);
} else {
console.log('Binding device ready handler');
device.on("ready", function () {
console.log('device.ready fired');
onDeviceReady(device);
});
console.log('Calling device.connect');
device.connect();
}
};
$(MediaController).on('playerchange', function (e, newPlayer, newTarget) {
if (currentDevice) {
if (newTarget.id != currentDeviceId) {
if (currentDevice) {
console.log('Disconnecting from connect device');
//currentDevice.disconnect();
cleanupSession();
currentDevice = null;
currentDeviceId = null;
currentMediaControl = null;
}
}
}
});
function onResume() {
var deviceId = currentDeviceId;
if (deviceId) {
self.tryPair({
id: deviceId
});
}
}
document.addEventListener("resume", onResume, false);
}
MediaController.registerPlayer(new connectSDKPlayer());
})();

View file

@ -1,131 +0,0 @@
(function () {
var unlockAlias = "premium features";
var unlockAppProductId = 'appunlock';
var updatedProducts = [];
function updateProductInfo(product) {
updatedProducts = updatedProducts.filter(function (r) {
return r.id != product.id;
});
updatedProducts.push(product);
Events.trigger(IapManager, 'productupdated', [product]);
}
function normalizeId(id) {
// This is what i named it in itunes
id = id.replace('premiumunlock', 'appunlock');
return id;
}
function getProduct(id) {
id = normalizeId(id);
var products = updatedProducts.filter(function (r) {
return r.id == id;
});
return products.length ? products[0] : null;
}
function isPurchaseAvailable(id) {
var product = getProduct(id);
return product != null && product.valid /*&& product.canPurchase*/;
}
function beginPurchase(id) {
id = normalizeId(id);
store.order(id);
}
function validateProduct(product, callback) {
// product attributes:
// https://github.com/j3k0/cordova-plugin-purchase/blob/master/doc/api.md#validation-error-codes
callback(true, {
});
//callback(true, { ... transaction details ... }); // success!
//// OR
//callback(false, {
// error: {
// code: store.PURCHASE_EXPIRED,
// message: "XYZ"
// }
//});
//// OR
//callback(false, "Impossible to proceed with validation");
}
function initializeStore() {
// Let's set a pretty high verbosity level, so that we see a lot of stuff
// in the console (reassuring us that something is happening).
store.verbosity = store.INFO;
store.validator = validateProduct;
// iOS
store.register({
id: unlockAppProductId,
alias: unlockAlias,
type: store.NON_CONSUMABLE
});
// When purchase of the full version is approved,
// show some logs and finish the transaction.
store.when(unlockAppProductId).approved(function (order) {
log('You just unlocked the FULL VERSION!');
order.finish();
});
store.when(unlockAppProductId).verified(function (p) {
log("verified");
p.finish();
});
// The play button can only be accessed when the user
// owns the full version.
store.when(unlockAppProductId).updated(function (product) {
if (product.loaded && product.valid && product.state == store.APPROVED) {
console.log('finishing previously created transaction');
product.finish();
}
updateProductInfo(product);
});
// When every goes as expected, it's time to celebrate!
// The "ready" event should be welcomed with music and fireworks,
// go ask your boss about it! (just in case)
store.ready(function () {
console.log("Store ready");
});
// After we've done our setup, we tell the store to do
// it's first refresh. Nothing will happen if we do not call store.refresh()
store.refresh();
}
window.IapManager = {
isPurchaseAvailable: isPurchaseAvailable,
getProductInfo: getProduct,
beginPurchase: beginPurchase
};
initializeStore();
})();

View file

@ -1,120 +0,0 @@
(function () {
function setImageIntoElement(elem, url) {
if (elem.tagName === "DIV") {
elem.style.backgroundImage = "url('" + url + "')";
} else {
elem.setAttribute("src", url);
}
}
var fileSystem;
function getFileSystem() {
var deferred = DeferredBuilder.Deferred();
if (fileSystem) {
deferred.resolveWith(null, [fileSystem]);
} else {
requestFileSystem(PERSISTENT, 0, function (fs) {
fileSystem = fs;
deferred.resolveWith(null, [fileSystem]);
});
}
return deferred.promise();
}
function indexedDbBlobImageStore() {
var self = this;
function getCacheKey(url) {
// Try to strip off the domain to share the cache between local and remote connections
var index = url.indexOf('://');
if (index != -1) {
url = url.substring(index + 3);
index = url.indexOf('/');
if (index != -1) {
url = url.substring(index + 1);
}
}
return CryptoJS.MD5(url).toString();
}
function normalizeReturnUrl(url) {
if ($.browser.safari) {
// Use the embedded server for iOS8, and also if we don't know the iOS version, just to be safe
//if ($.browser.iOSVersion == 8 || !$.browser.iOSVersion)
{
return url.replace('file://', '');
}
}
return url;
}
self.getImageUrl = function (originalUrl) {
if ($.browser.android && originalUrl.indexOf('tag=') != -1) {
originalUrl += "&format=webp";
}
var deferred = DeferredBuilder.Deferred();
var key = getCacheKey(originalUrl);
console.log('getImageUrl:' + originalUrl);
getFileSystem().done(function (fileSystem) {
var path = fileSystem.root.toURL() + "/emby/cache/" + key;
resolveLocalFileSystemURL(path, function (fileEntry) {
var localUrl = normalizeReturnUrl(fileEntry.toURL());
console.log('returning cached file: ' + localUrl);
deferred.resolveWith(null, [localUrl]);
}, function () {
console.log('downloading: ' + originalUrl);
var ft = new FileTransfer();
ft.download(originalUrl, path, function (entry) {
var localUrl = normalizeReturnUrl(entry.toURL());
console.log(localUrl);
deferred.resolveWith(null, [localUrl]);
});
});
});
return deferred.promise();
};
self.setImageInto = function (elem, url) {
function onFail() {
setImageIntoElement(elem, url);
}
self.getImageUrl(url).done(function (localUrl) {
setImageIntoElement(elem, localUrl);
}).fail(onFail);
};
window.ImageStore = self;
}
new indexedDbBlobImageStore();
})();

View file

@ -1,38 +0,0 @@
(function () {
function show(options) {
// items
// positionTo
// showCancel
// title
var innerOptions = {
'title': options.title,
'buttonLabels': options.items.map(function (i) {
return i.name;
})
};
// Show cancel unless the caller explicitly set it to false
if (options.showCancel !== false) {
innerOptions.addCancelButtonWithLabel = Globalize.translate('ButtonCancel');
}
// Depending on the buttonIndex, you can now call shareViaFacebook or shareViaTwitter
// of the SocialSharing plugin (https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin)
window.plugins.actionsheet.show(innerOptions, function (index) {
if (options.callback) {
if (index >= 1) {
options.callback(options.items[index - 1].id);
}
}
});
}
window.ActionSheetElement = {
show: show
};
})();

View file

@ -1,21 +0,0 @@
(function () {
function forceScroll() {
var doc = $(document);
// Try to make it react quicker to the orientation change
doc.scrollTop(doc.scrollTop() + 1);
}
function onOrientationChange() {
forceScroll();
for (var i = 0; i <= 500; i += 100) {
setTimeout(forceScroll, i);
}
}
$(window).on('orientationchange', onOrientationChange);
})();

View file

@ -1,251 +0,0 @@
(function () {
function isAndroid() {
var platform = (device.platform || '').toLowerCase();
return platform.indexOf('android') != -1;
}
function getPremiumUnlockFeatureId() {
if (isAndroid()) {
return "com.mb.android.unlock";
}
return 'appunlock';
}
function validatePlayback(deferred) {
// Don't require validation on android
if (isAndroid()) {
deferred.resolve();
return;
}
validateFeature(getPremiumUnlockFeatureId(), deferred);
}
function validateLiveTV(deferred) {
if (!isAndroid()) {
deferred.resolve();
return;
}
validateFeature(getPremiumUnlockFeatureId(), deferred);
}
function validateServerManagement(deferred) {
deferred.resolve();
}
function getRegistrationInfo(feature, enableSupporterUnlock) {
if (!enableSupporterUnlock) {
var deferred = $.Deferred();
deferred.resolveWith(null, [{}]);
return deferred.promise();
}
return ConnectionManager.getRegistrationInfo(feature, ApiClient);
}
function validateFeature(id, deferred) {
var info = IapManager.getProductInfo(id) || {};
if (info.owned) {
deferred.resolve();
return;
}
var productInfo = {
enableSupporterUnlock: isAndroid(),
enableAppUnlock: IapManager.isPurchaseAvailable(id),
id: id,
price: info.price
};
var prefix = isAndroid() ? 'android' : 'ios';
// Get supporter status
getRegistrationInfo(prefix + 'appunlock', productInfo.enableSupporterUnlock).done(function (registrationInfo) {
if (registrationInfo.IsRegistered) {
deferred.resolve();
return;
}
showInAppPurchaseInfo(productInfo, registrationInfo, deferred);
}).fail(function () {
deferred.reject();
});
}
function getInAppPurchaseElement(info) {
cancelInAppPurchase();
var html = '';
html += '<div class="inAppPurchaseOverlay" style="background-image:url(css/images/splash.jpg);top:0;left:0;right:0;bottom:0;position:fixed;background-position:center center;background-size:100% 100%;background-repeat:no-repeat;z-index:999999;">';
html += '<div class="inAppPurchaseOverlayInner" style="background:rgba(10,10,10,.8);width:100%;height:100%;color:#eee;">';
html += '<div class="inAppPurchaseForm" style="margin: 0 auto;padding: 30px 1em 0;">';
html += '<h1 style="color:#fff;">' + Globalize.translate('HeaderUnlockApp') + '</h1>';
html += '<p style="margin:2em 0;">';
if (info.enableSupporterUnlock && info.enableAppUnlock) {
html += Globalize.translate('MessageUnlockAppWithPurchaseOrSupporter');
}
else if (info.enableSupporterUnlock) {
html += Globalize.translate('MessageUnlockAppWithSupporter');
} else if (info.enableAppUnlock) {
html += Globalize.translate('MessageUnlockAppWithPurchase');
} else {
html += '<span style="color:red;">';
html += Globalize.translate('MessagePaymentServicesUnavailable');
html += '</span>';
}
html += '</p>';
if (info.enableSupporterUnlock) {
html += '<p style="margin:2em 0;">';
html += Globalize.translate('MessageToValidateSupporter');
html += '</p>';
}
if (info.enableAppUnlock) {
var unlockText = Globalize.translate('ButtonUnlockWithPurchase');
if (info.price) {
unlockText = Globalize.translate('ButtonUnlockPrice', info.price);
}
html += '<button class="btn btnActionAccent btnAppUnlock" data-role="none" type="button"><span>' + unlockText + '</span><i class="fa fa-check"></i></button>';
}
if (info.enableSupporterUnlock) {
html += '<button class="btn btnSignInSupporter" data-role="none" type="button"><span>' + Globalize.translate('ButtonUnlockWithSupporter') + '</span><i class="fa fa-check"></i></button>';
}
html += '<button class="btn btnCancel" data-role="none" type="button"><span>' + Globalize.translate('ButtonCancel') + '</span><i class="fa fa-close"></i></button>';
html += '</div>';
html += '</div>';
html += '</div>';
$(document.body).append(html);
return $('.inAppPurchaseOverlay');
}
function cancelInAppPurchase() {
$('.inAppPurchaseOverlay').remove();
}
var currentDisplayingProductInfo = null;
var currentDisplayingDeferred = null;
function clearCurrentDisplayingInfo() {
currentDisplayingProductInfo = null;
currentDisplayingDeferred = null;
}
function showInAppPurchaseInfo(info, serverRegistrationInfo, deferred) {
var elem = getInAppPurchaseElement(info);
currentDisplayingProductInfo = info;
currentDisplayingDeferred = deferred;
$('.btnAppUnlock', elem).on('click', function () {
IapManager.beginPurchase(info.id);
});
$('.btnCancel', elem).on('click', function () {
clearCurrentDisplayingInfo();
cancelInAppPurchase();
deferred.reject();
});
$('.btnSignInSupporter', elem).on('click', function () {
clearCurrentDisplayingInfo();
Dashboard.alert({
message: Globalize.translate('MessagePleaseSignInLocalNetwork'),
callback: function () {
cancelInAppPurchase();
Dashboard.logout();
}
});
});
}
function onProductUpdated(e, product) {
var currentInfo = currentDisplayingProductInfo;
var deferred = currentDisplayingDeferred;
if (currentInfo && deferred) {
if (product.owned && product.id == currentInfo.id) {
clearCurrentDisplayingInfo();
cancelInAppPurchase();
deferred.resolve();
}
}
}
window.RegistrationServices = {
renderPluginInfo: function (page, pkg, pluginSecurityInfo) {
},
addRecurringFields: function (page, period) {
},
initSupporterForm: function (page) {
$('.recurringSubscriptionCancellationHelp', page).html('');
},
validateFeature: function (name) {
var deferred = DeferredBuilder.Deferred();
if (name == 'playback') {
validatePlayback(deferred);
} else if (name == 'livetv') {
validateLiveTV(deferred);
} else if (name == 'manageserver') {
validateServerManagement(deferred);
} else {
deferred.resolve();
}
return deferred.promise();
}
};
function onIapManagerLoaded() {
Events.on(IapManager, 'productupdated', onProductUpdated);
}
if (isAndroid()) {
requirejs(['thirdparty/cordova/android/iap'], onIapManagerLoaded);
} else {
requirejs(['thirdparty/cordova/iap'], onIapManagerLoaded);
}
})();

View file

@ -1,173 +0,0 @@
(function () {
// Reports media playback to the device for lock screen control
var currentPlayer;
var lastPlayerState;
function updatePlayerState(state) {
if (!state.NowPlayingItem) {
hideNowPlayingBar();
return;
}
lastPlayerState = state;
var playState = state.PlayState || {};
var nameHtml = MediaController.getNowPlayingNameHtml(state.NowPlayingItem) || '';
var parts = nameHtml.split('<br/>');
var artist = parts.length == 1 ? '' : parts[0];
var title = parts[parts.length - 1];
var album = state.NowPlayingItem.Album || '';
var duration = state.NowPlayingItem.RunTimeTicks ? (state.NowPlayingItem.RunTimeTicks / 10000000) : 0;
var elapsedTime = playState.PositionTicks ? (playState.PositionTicks / 10000000) : 0;
var url = '';
var imgHeight = 100;
var nowPlayingItem = state.NowPlayingItem;
if (nowPlayingItem.PrimaryImageTag) {
url = ApiClient.getScaledImageUrl(nowPlayingItem.PrimaryImageItemId, {
type: "Primary",
height: imgHeight,
tag: nowPlayingItem.PrimaryImageTag
});
}
else if (nowPlayingItem.BackdropImageTag) {
url = ApiClient.getScaledImageUrl(nowPlayingItem.BackdropItemId, {
type: "Backdrop",
height: imgHeight,
tag: nowPlayingItem.BackdropImageTag,
index: 0
});
} else if (nowPlayingItem.ThumbImageTag) {
url = ApiClient.getScaledImageUrl(nowPlayingItem.ThumbImageItemId, {
type: "Thumb",
height: imgHeight,
tag: nowPlayingItem.ThumbImageTag
});
}
var params = [artist, title, album, url, duration, elapsedTime];
try {
window.remoteControls.updateMetas(onUpdateMetasSuccess, onUpdateMetasFail, params);
} catch (err) {
onUpdateMetasFail(err);
}
}
function onStateChanged(e, state) {
updatePlayerState(state);
}
function onPlaybackStart(e, state) {
console.log('nowplaying event: ' + e.type);
var player = this;
player.beginPlayerUpdates();
onStateChanged.call(player, e, state);
}
function onPlaybackStopped(e, state) {
console.log('nowplaying event: ' + e.type);
var player = this;
player.endPlayerUpdates();
hideNowPlayingBar();
}
function releaseCurrentPlayer() {
if (currentPlayer) {
$(currentPlayer).off('.cordovaremote');
currentPlayer.endPlayerUpdates();
currentPlayer = null;
hideNowPlayingBar();
}
}
function hideNowPlayingBar() {
var artist = "";
var title = "";
var album = "";
var image = "";
var duration = 0;
var elapsedTime = 0;
var params = [artist, title, album, image, duration, elapsedTime];
try {
window.remoteControls.updateMetas(onUpdateMetasSuccess, onUpdateMetasFail, params);
} catch (err) {
onUpdateMetasFail(err);
}
}
function onUpdateMetasSuccess() {
console.log('onUpdateMetasSuccess');
}
function onUpdateMetasFail(fail) {
console.log('onUpdateMetasFail: ' + fail);
}
function bindToPlayer(player) {
releaseCurrentPlayer();
currentPlayer = player;
if (!player.isLocalPlayer) {
return;
}
console.log('binding remotecontrols to MediaPlayer');
player.getPlayerState().done(function (state) {
if (state.NowPlayingItem) {
player.beginPlayerUpdates();
}
onStateChanged.call(player, { type: 'init' }, state);
});
$(player).on('playbackstart.cordovaremote', onPlaybackStart)
.on('playbackstop.cordovaremote', onPlaybackStopped)
.on('playstatechange.cordovaremote', onStateChanged)
.on('positionchange.cordovaremote', onStateChanged);
}
Dashboard.ready(function () {
console.log('binding remotecontrols to MediaController');
$(MediaController).on('playerchange', function () {
bindToPlayer(MediaController.getCurrentPlayer());
});
bindToPlayer(MediaController.getCurrentPlayer());
});
})();

View file

@ -1,179 +0,0 @@
(function (globalScope) {
function stringToArrayBuffer(string) {
// UTF-16LE
var buf = new ArrayBuffer(string.length * 2);
var bufView = new Uint16Array(buf);
for (var i = 0, strLen = string.length; i < strLen; i++) {
bufView[i] = string.charCodeAt(i);
}
return buf;
}
function arrayBufferToString(buf) {
return String.fromCharCode.apply(null, new Uint16Array(buf));
}
function getResultCode(result) {
if (result != null && result.resultCode != null) {
return result.resultCode;
}
return result;
}
function closeSocket(socketId) {
try {
chrome.sockets.udp.close(socketId);
} catch (err) {
}
}
function findServersInternal(timeoutMs) {
var deferred = DeferredBuilder.Deferred();
var servers = [];
// Expected server properties
// Name, Id, Address, EndpointAddress (optional)
var chrome = globalScope.chrome;
if (!chrome) {
deferred.resolveWith(null, [servers]);
return deferred.promise();
}
var timeout;
var socketId;
function onTimerExpired() {
deferred.resolveWith(null, [servers]);
if (socketId) {
chrome.sockets.udp.onReceive.removeListener(onReceive);
closeSocket(socketId);
}
}
function startTimer() {
console.log('starting udp receive timer with timeout ms: ' + timeoutMs);
timeout = setTimeout(onTimerExpired, timeoutMs);
}
function onReceive(info) {
try {
console.log('ServerDiscovery message received');
console.log(info);
if (info != null && info.socketId == socketId) {
var json = arrayBufferToString(info.data);
console.log('Server discovery json: ' + json);
var server = JSON.parse(json);
server.RemoteAddress = info.remoteAddress;
if (info.remotePort) {
server.RemoteAddress += ':' + info.remotePort;
}
servers.push(server);
}
} catch (err) {
console.log('Error receiving server info: ' + err);
}
}
var port = 7359;
console.log('chrome.sockets.udp.create');
startTimer();
chrome.sockets.udp.create(function (createInfo) {
if (!createInfo) {
console.log('create fail');
return;
}
if (!createInfo.socketId) {
console.log('create fail');
return;
}
socketId = createInfo.socketId;
console.log('chrome.sockets.udp.bind');
chrome.sockets.udp.bind(createInfo.socketId, '0.0.0.0', 0, function (bindResult) {
if (getResultCode(bindResult) != 0) {
console.log('bind fail: ' + bindResult);
return;
}
var data = stringToArrayBuffer('who is EmbyServer?');
console.log('chrome.sockets.udp.send');
chrome.sockets.udp.send(createInfo.socketId, data, '255.255.255.255', port, function (sendResult) {
if (getResultCode(sendResult) != 0) {
console.log('send fail: ' + sendResult);
} else {
chrome.sockets.udp.onReceive.addListener(onReceive);
console.log('sendTo: success ' + port);
}
});
});
});
return deferred.promise();
}
globalScope.ServerDiscovery = {
findServers: function (timeoutMs) {
var deferred = DeferredBuilder.Deferred();
deviceReadyPromise.done(function () {
try {
findServersInternal(timeoutMs).done(function (result) {
deferred.resolveWith(null, [result]);
}).fail(function () {
deferred.resolveWith(null, [[]]);
});
} catch (err) {
deferred.resolveWith(null, [[]]);
}
});
return deferred.promise();
}
};
var deviceReadyDeferred = DeferredBuilder.Deferred();
var deviceReadyPromise = deviceReadyDeferred.promise();
document.addEventListener("deviceready", function () {
deviceReadyDeferred.resolve();
}, false);
})(window);

View file

@ -1,28 +0,0 @@
(function () {
// Handle the volume down button
//
function onVolumeDownKeyDown() {
MediaController.volumeDown();
}
// Handle the volume up button
//
function onVolumeUpKeyDown() {
MediaController.volumeUp();
}
$(MediaController).on('playerchange', function (e, newPlayer, newTarget) {
document.removeEventListener("volumedownbutton", onVolumeDownKeyDown, false);
document.removeEventListener("volumeupbutton", onVolumeUpKeyDown, false);
if (!newPlayer.localPlayer) {
document.addEventListener("volumedownbutton", onVolumeDownKeyDown, false);
document.addEventListener("volumeupbutton", onVolumeUpKeyDown, false);
}
});
})();

View file

@ -1,87 +0,0 @@
(function (globalScope) {
function getResultCode(result) {
if (result != null && result.resultCode != null) {
return result.resultCode;
}
return result;
}
function closeSocket(socketId) {
try {
chrome.sockets.udp.close(socketId);
} catch (err) {
}
}
function stringToArrayBuffer(string) {
// UTF-16LE
var buf = new ArrayBuffer(string.length * 2);
var bufView = new Uint16Array(buf);
for (var i = 0, strLen = string.length; i < strLen; i++) {
bufView[i] = string.charCodeAt(i);
}
return buf;
}
// https://github.com/agnat/node_wake_on_lan/blob/master/wake_on_lan.js
globalScope.WakeOnLan = {
send: function (info) {
var deferred = DeferredBuilder.Deferred();
var chrome = globalScope.chrome;
if (!chrome) {
deferred.resolve();
return deferred.promise();
}
var port = info.Port || 9;
//chrome.sockets.udp.create(function (createInfo) {
// if (!createInfo) {
// console.log('create fail');
// return;
// }
// if (!createInfo.socketId) {
// console.log('create fail');
// return;
// }
// var socketId = createInfo.socketId;
// console.log('chrome.sockets.udp.bind');
// chrome.sockets.udp.bind(createInfo.socketId, '0.0.0.0', 0, function (bindResult) {
// if (getResultCode(bindResult) != 0) {
// console.log('bind fail: ' + bindResult);
// deferred.resolve();
// closeSocket(socketId);
// }
// var data = stringToArrayBuffer('who is EmbyServer?');
// console.log('chrome.sockets.udp.send');
// chrome.sockets.udp.send(createInfo.socketId, data, '255.255.255.255', port, function (sendResult) {
// deferred.resolve();
// closeSocket(socketId);
// });
// });
//});
deferred.resolve();
return deferred.promise();
}
};
})(window);

View file

@ -43,6 +43,8 @@ See [iron-iconset](#iron-iconset) and [iron-iconset-svg](#iron-iconset-svg) for
<g id="add"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" /></g>
<g id="arrow-back"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" /></g>
<g id="arrow-forward"><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z" /></g>
<g id="delete"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" /></g>
<g id="file-download"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z" /></g>
<g id="info"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z" /></g>
<g id="lock"><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z" /></g>
<g id="settings"><path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z" /></g>

View file

@ -23,7 +23,7 @@
return 8000;
}
var screens = $.browser.mobile ? 2 : 1;
var screens = $.browser.mobile ? 2.5 : 1;
// This helps eliminate the draw-in effect as you scroll
return Math.max(screen.availHeight * screens, 1000);

View file

@ -196,6 +196,7 @@ paper-button.notext {
paper-dialog {
border-radius: 4px;
z-index: 999999 !important;
}
iron-overlay-backdrop {