Kill web interface files
@ -1,6 +1,6 @@
|
||||
|
||||
EXTRA_DIST = configure CREDITS
|
||||
SUBDIRS = src tools admin-root contrib
|
||||
SUBDIRS = src tools contrib
|
||||
|
||||
|
||||
|
||||
|
@ -1,150 +0,0 @@
|
||||
|
||||
I've received lots of help from people on this project.
|
||||
|
||||
These are the people who have contributed to whatever
|
||||
small success this project enjoys (in order of contribution).
|
||||
If I've forgotten anyone, I apologize -- email me and I'll
|
||||
make it right.
|
||||
|
||||
The Plone project
|
||||
* css files for the admin interface
|
||||
|
||||
Aubin Paul
|
||||
* Patches for Debian package generation
|
||||
* Precompiled Debian binaries
|
||||
|
||||
Paul Forgey
|
||||
* Tons of troubleshooting on Solaris
|
||||
* Fixes for readdir_r
|
||||
* Fixes for alignment problems in XING header parsing
|
||||
|
||||
Paul Hubbard
|
||||
* T/S and patch testing to resolve scanning bugs
|
||||
|
||||
David Buttrick
|
||||
* Webmastering, FAQ maintenance, Doc maintenance
|
||||
|
||||
Hans-Christoph Steiner
|
||||
* Webmastering, FAQ maintenance, Doc maintenance
|
||||
* Amazing amounts of troubleshooting, testing on OSX 10.2
|
||||
|
||||
David Imhoff
|
||||
* Code cleanup patches (_XOPEN_SOURCE, declaration problems)
|
||||
|
||||
James Turner
|
||||
* Fixes for OSX 10.2
|
||||
* configure.in suggestions
|
||||
|
||||
Hiren Joshi
|
||||
* Dynamic art code
|
||||
|
||||
David W. Berry
|
||||
* Tons of protocol compliance fixes.
|
||||
* Browse, query, and index support
|
||||
|
||||
Paul Kim
|
||||
* Dynamic art code for AAC
|
||||
* Various AAC meta-info cleanups
|
||||
* Compilation tag support (aac and mp3)
|
||||
* ogg/vorbis tag handling
|
||||
|
||||
Stephen Lee
|
||||
* Patches for proper url decoding
|
||||
|
||||
Rob Nunn
|
||||
* gentoo rc script
|
||||
|
||||
Frank Schwichtenberg
|
||||
* patches for static playlist bug
|
||||
|
||||
Gavin Shelley
|
||||
* patches for Solaris strftime
|
||||
|
||||
Stephen Rubner
|
||||
* fixes for ulong ino_t
|
||||
|
||||
Ciamac Moallemi
|
||||
* gzip content-encoding
|
||||
|
||||
Roger Mundt
|
||||
* troubleshooting and debugging help
|
||||
|
||||
dirkthedaring2 (?)
|
||||
* fixes for inverted playlist
|
||||
* speedups on connect
|
||||
|
||||
Adrian Schroeter
|
||||
* fixes for AMD64
|
||||
* -Wall cleanups
|
||||
|
||||
Timo J. Rinne
|
||||
* Server-side format conversion (on-the-fly transcoding)
|
||||
|
||||
Herman I. May
|
||||
* Web wrangling and forums question answering
|
||||
* HTML interface fixes
|
||||
|
||||
North Overby
|
||||
* Patches for disc number
|
||||
* alac speedups for nslu2
|
||||
|
||||
Joe Holt
|
||||
* Fixes for web config stupidness
|
||||
|
||||
Mark Woehrer
|
||||
* Patches for "Date Added" in iTunes xml scanner
|
||||
|
||||
Stefan Bruns
|
||||
* Speedups for javascript in playlist page, konq fixes, css fixes
|
||||
* Fixes for mlit -> xml serialization when block len = 0
|
||||
|
||||
blech (from the forums)
|
||||
* Fixes for iTunes 5 view persistence
|
||||
|
||||
Phil Packer
|
||||
* Patches for returning static playlists in order
|
||||
|
||||
Diego Penneno
|
||||
* Patches for multiple PID files to facilitate gentoo init scripts
|
||||
* configure patches
|
||||
|
||||
Patrick Kolla
|
||||
* Popup "wizard" for smart playlists
|
||||
* Stylish new web interface look.. woohoo!
|
||||
|
||||
slomo (from the forums)
|
||||
* Musepack tag parsing support.
|
||||
|
||||
Anders Betner
|
||||
* Web interface mojo -- ajaxy web config and playlist editor
|
||||
|
||||
MikeC
|
||||
* Win32 panel configurator
|
||||
|
||||
MikeK
|
||||
* OSX Preference pane/helper, and OSX packaging
|
||||
|
||||
Eddie Bindt
|
||||
* Dutch Translations
|
||||
|
||||
Julien Richefeu
|
||||
* French Translations
|
||||
|
||||
Helmut Wieser
|
||||
* German Translations
|
||||
|
||||
Luca Paolini
|
||||
* Italian Translations
|
||||
|
||||
Gareth Potter
|
||||
* Japanese Translations
|
||||
|
||||
Anton Johansson
|
||||
* Swedish Translations
|
||||
|
||||
Ian Burrell
|
||||
* configure patches to put plugins in libdir
|
||||
* RH/Centos/Fedora specfiles
|
||||
|
||||
Stephane Moreau
|
||||
* admin page updates to make apache rewrites easier
|
@ -1,24 +0,0 @@
|
||||
|
||||
SUBDIRS=lib-js
|
||||
|
||||
adminrootdir = ${pkgdatadir}/admin-root
|
||||
adminroot_DATA = ftr.html linkOpaque.gif about.html \
|
||||
gpl-license.txt linkTransparent.gif config-update.html hdr.html \
|
||||
firefly.css ff_logo_sm.gif config.html index.html required.gif \
|
||||
gpl-license.html thanks.html feedback.html \
|
||||
playlist.html playlist.js smart.html smart.js \
|
||||
smartpopup.html firefly.js CREDITS status.js \
|
||||
config.js config.xml spinner.gif spinner_stopped.gif util.js \
|
||||
pngfix.js no_access.html index.css config.css \
|
||||
xiph-license.html xiph-license.txt zlib-license.html zlib-license.txt
|
||||
|
||||
EXTRA_DIST = ftr.html linkOpaque.gif about.html \
|
||||
gpl-license.txt linkTransparent.gif config-update.html hdr.html \
|
||||
firefly.css ff_logo_sm.gif config.html index.html required.gif \
|
||||
gpl-license.html thanks.html feedback.html \
|
||||
playlist.html playlist.js smart.html smart.js \
|
||||
smartpopup.html firefly.js CREDITS status.js \
|
||||
config.js config.xml spinner.gif spinner_stopped.gif util.js \
|
||||
pngfix.js no_access.html index.css config.css \
|
||||
xiph-license.html xiph-license.txt zlib-license.html zlib-license.txt
|
||||
|
@ -1,56 +0,0 @@
|
||||
@include hdr.html@
|
||||
<div style="width: 50em;">
|
||||
<h2>About Firefly</h2>
|
||||
<p>
|
||||
This is the administrative web interface for the Firefly Media Server,
|
||||
version @version@.
|
||||
</p>
|
||||
|
||||
<h3>About</h3>
|
||||
<p>
|
||||
Firefly is an open-source media server for the Roku SoundBridge and
|
||||
Apple iTunes. It runs on POSIX platforms as well as Win32. It supports
|
||||
server-side transcoding and other advanced features. While every effort
|
||||
is taken to ensure quality, this software is released without warranty as
|
||||
described by the GNU General Public License. See the section below
|
||||
titled "No Warranty". This work,
|
||||
although released under the GNU General Public License, is Copyright
|
||||
© 2003-2006 Ron Pedde and others. See source file headers for
|
||||
more information. See the link named
|
||||
<a href="gpl-license.html">GPL License</a> for more details on the
|
||||
licensing of this software.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The project homepage is located at
|
||||
<a href="http://www.fireflymediaserver.org">
|
||||
http://www.fireflymediaserver.org</a>.
|
||||
|
||||
|
||||
<h3>Legal Info</h3>
|
||||
<p>
|
||||
This program makes use of the following libraries and packages:
|
||||
<ul>
|
||||
<li>Fabrice Bellard's <a href="http://ffmpeg.mplayerhq.hu/">FFmpeg</a>, licensed under the <a href="gpl-license.html">GPL License</a></li>
|
||||
<li>D. Richard Hipp's <a href="http://sqlite.org">SQLite</a> database, dedicated to the public domain</li>
|
||||
<li>Underbit Technologies' <a href="http://www.underbit.com/products/mad/">libid3tag</a>, licensed under the <a href="gpl-license.html">GPL License</a></li>
|
||||
<li>Jean-loup Gailly and Mark Adler's <a href="http://www.zlib.net">zlib</a>, licensed under the <a href="zlib-license.html">zlib license</a></li>
|
||||
<li>Josh Coalson's <a href="http://flac.sourceforge.net">libFLAC</a>, licensed under the <a href="xiph-license.html">Xiph</a> (BSD 3-clause) License</a></li>
|
||||
<li>xiph.org's <a href="http://xiph.org/ogg/">libOgg</a>, licensed under the <a href="xiph-license.html">Xiph</a> (BSD 3-clause) License</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<h3>No Warranty</h3>
|
||||
<p class="license">
|
||||
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
</p>
|
||||
</div>
|
||||
@include ftr.html@
|
@ -1,19 +0,0 @@
|
||||
@include hdr.html@
|
||||
|
||||
<h1>Configuration Updated</h1>
|
||||
|
||||
<div class="stx">
|
||||
|
||||
<table>
|
||||
<tr><th>Admin Password</th><td>@admin_pw@</td></tr>
|
||||
<tr><th>MP3 Password</th><td>@password@</td></tr>
|
||||
</table>
|
||||
|
||||
<br />
|
||||
|
||||
@SERVICE-STATUS@
|
||||
|
||||
</div>
|
||||
|
||||
@include ftr.html@
|
||||
|
@ -1,51 +0,0 @@
|
||||
label {
|
||||
float: left;
|
||||
width: 11em;
|
||||
font: icon;
|
||||
padding-top: .3em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
input {
|
||||
font: icon;
|
||||
}
|
||||
select {
|
||||
font: icon;
|
||||
}
|
||||
#config_path_label {
|
||||
float: left;
|
||||
width: 11em;
|
||||
font:icon;
|
||||
padding: .3em 0 .5em 1em;
|
||||
}
|
||||
#config_path {
|
||||
float: left;
|
||||
width: 40em;
|
||||
font: icon;
|
||||
padding: .3em 0 .5em 0;
|
||||
}
|
||||
.addItemHref {
|
||||
float: left;
|
||||
margin-left: 11em;
|
||||
font: icon;
|
||||
padding-left: 1.5em;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
.message_div {
|
||||
background-color: yellow;
|
||||
padding: 1em;
|
||||
border: 1px solid #8CACBB;
|
||||
}
|
||||
#messages {
|
||||
background-color: yellow;
|
||||
padding: .5em;
|
||||
border: 1px solid #8CACBB;
|
||||
width: 40em;
|
||||
float: left;
|
||||
margin-left: 1em;
|
||||
}
|
||||
#buttons {
|
||||
float: left;
|
||||
}
|
||||
#buttons input {
|
||||
width: 7em;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
@include hdr.html@
|
||||
<h2>Configuration</h2><span id="toggle_basic_advanced"></span>
|
||||
<div id="config_not_writable_warning" class="message_div" style="display: none;">Your config file is not writable, you can not change anything using this webpage</div>
|
||||
<form id="theform" method="get" action="#">
|
||||
</form>
|
||||
<div id="buttons"></div>
|
||||
<div id="messages" class="message_div" style="display: none;"></div>
|
||||
<div style="clear: both;"><br /><br /><br /></div>
|
||||
@include ftr.html@
|
@ -1,611 +0,0 @@
|
||||
Event.observe(window,'load',init);
|
||||
//###TODO
|
||||
// * Disable/enable save/cancel, Add key and onchange listeners keep a note on changed items
|
||||
// * create the path/file browser
|
||||
// * better errormessage for non writable config
|
||||
// * make tabs?
|
||||
// * add warning if leaving page without saving
|
||||
|
||||
// Config isn't defined until after the Event.observe above
|
||||
// I could have put it below Config = ... but I want all window.load events
|
||||
// at the start of the file
|
||||
var DEBUG = window.location.toString().match(/debug.*/);
|
||||
var g_messageTimeout;
|
||||
if ('debug=validate' == DEBUG) {
|
||||
DEBUG = 'validate';
|
||||
}
|
||||
function init() {
|
||||
Config.init();
|
||||
}
|
||||
var ConfigXML = {
|
||||
config: {},
|
||||
advancedSections: [],
|
||||
getItem: function (id) {
|
||||
return this.config[id];
|
||||
},
|
||||
getAllItems: function () {
|
||||
return $H(this.config).pluck('value');
|
||||
},
|
||||
addAdvancedSection: function (sectionName) {
|
||||
this.advancedSections.push(sectionName);
|
||||
},
|
||||
isAdvancedSection: function (sectionName) {
|
||||
return this.advancedSections.find(function (name) {
|
||||
return name == sectionName
|
||||
});
|
||||
},
|
||||
getAllAdvancedSections: function () {
|
||||
return this.advancedSections;
|
||||
},
|
||||
getSectionId: function (sectionName) {
|
||||
return 'firefly_'+sectionName.replace(/\ /g,'').toLowerCase();
|
||||
},
|
||||
parseXML: function(xmlDoc) {
|
||||
$A(xmlDoc.getElementsByTagName('section')).each(function (section) {
|
||||
if ('true' == section.getAttribute('advanced')) {
|
||||
// Only used by Config._showAdvancedConfig, Config._showBasicConfig
|
||||
ConfigXML.addAdvancedSection(section.getAttribute('name'));
|
||||
}
|
||||
$A(section.getElementsByTagName('item')).each(function (item) {
|
||||
var returnItem = {};
|
||||
$A(item.attributes).each(function (attr) {
|
||||
returnItem[attr.name] = attr.value;
|
||||
});
|
||||
Element.cleanWhitespace(item);
|
||||
$A(item.childNodes).each(function (node) {
|
||||
if (Element.textContent(node) == '') {
|
||||
return;
|
||||
}
|
||||
if ('options' == node.nodeName) {
|
||||
var options = [];
|
||||
$A(item.getElementsByTagName('option')).each(function (option) {
|
||||
options.push({value: option.getAttribute('value'),
|
||||
label: Element.textContent(option)});
|
||||
});
|
||||
returnItem['options'] = options;
|
||||
} else {
|
||||
returnItem[node.nodeName] = Element.textContent(node);
|
||||
}
|
||||
$A(node.attributes).each(function (attr) {
|
||||
returnItem[attr.name] = attr.value;
|
||||
});
|
||||
});
|
||||
ConfigXML.config[returnItem.id] = returnItem;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
var ConfigInitialValues = {
|
||||
values: {},
|
||||
getValue: function (id) {
|
||||
return ConfigInitialValues.values[id];
|
||||
},
|
||||
setValue: function (id,value) {
|
||||
this.values[id] = value;
|
||||
},
|
||||
parseXML: function (xmldoc) {
|
||||
// IE and w3c treat xmldoc differently make shore firstChild is firstchild of <config>
|
||||
if (xmldoc.childNodes[1] && xmldoc.childNodes[1].nodeName == 'config') {
|
||||
sections = $A(xmldoc.childNodes[1].childNodes);
|
||||
} else {
|
||||
sections = $A(xmldoc.firstChild.childNodes);
|
||||
}
|
||||
var missingItems = [];
|
||||
sections.each(function (section) {
|
||||
var sectionName = section.nodeName;
|
||||
$A(section.childNodes).each(function (node) {
|
||||
var itemId = sectionName + ':' + node.nodeName;
|
||||
if (node.firstChild && node.firstChild.hasChildNodes()) {
|
||||
var values = [];
|
||||
$A(node.childNodes).each(function (n) {
|
||||
values.push(Element.textContent(n));
|
||||
});
|
||||
ConfigInitialValues.values[itemId] = values;
|
||||
} else {
|
||||
ConfigInitialValues.values[itemId] = Element.textContent(node);
|
||||
}
|
||||
if (!ConfigXML.getItem(itemId)) {
|
||||
missingItems.push(itemId);
|
||||
}
|
||||
});
|
||||
});
|
||||
if (missingItems.length > 0) {
|
||||
//###FIXME A bit ugly, but add a section with values from mt-daapd.conf that aren't
|
||||
// in config.xml
|
||||
ConfigXML.addAdvancedSection('missing_items');
|
||||
var frag = document.createDocumentFragment();
|
||||
missingItems.each(function (el){
|
||||
frag.appendChild(document.createTextNode(el));
|
||||
frag.appendChild(document.createElement('br'));
|
||||
});
|
||||
var outerDiv = Builder.node('div',{id: ConfigXML.getSectionId('missing_items')});
|
||||
outerDiv.appendChild(Builder.node('div',{className: 'naviheader'},'Options missing from config.xml'));
|
||||
var contentDiv = Builder.node('div',{className: 'navibox'});
|
||||
contentDiv.appendChild(document.createTextNode('The options below are in your mt-daapd.conf and Firefly uses them,'));
|
||||
contentDiv.appendChild(document.createElement('br'));
|
||||
contentDiv.appendChild(document.createTextNode("but this web page can't handle them until they are added to config.xml"));
|
||||
contentDiv.appendChild(document.createElement('br'));
|
||||
contentDiv.appendChild(document.createElement('br'));
|
||||
contentDiv.style.paddingLeft = '1em';
|
||||
contentDiv.appendChild(frag);
|
||||
outerDiv.appendChild(contentDiv);
|
||||
if (!Cookie.getVar('show_advanced_config')) {
|
||||
outerDiv.style.display = 'none';
|
||||
}
|
||||
$('theform').appendChild(outerDiv);
|
||||
}
|
||||
}
|
||||
};
|
||||
var Config ={
|
||||
configPath: '',
|
||||
init: function () {
|
||||
new Ajax.Request('config.xml',{method: 'get',onComplete: Config.storeConfigLayout});
|
||||
},
|
||||
storeConfigLayout: function (request) {
|
||||
// Need to store this until showConfig is run
|
||||
Config.tmpConfigXML = request.responseXML;
|
||||
ConfigXML.parseXML(request.responseXML);
|
||||
ConfigXML.getAllItems().each(function (item) {
|
||||
if (item.multiple) {
|
||||
//###FIXME default values on item.multiple="true" not possible
|
||||
ConfigInitialValues.setValue(item.id,[]);
|
||||
} else {
|
||||
ConfigInitialValues.setValue(item.id,item.default_value || '');
|
||||
}
|
||||
});
|
||||
new Ajax.Request('xml-rpc?method=stats',{method: 'get',onComplete: Config.updateStatus});
|
||||
},
|
||||
updateStatus: function (request) {
|
||||
Config.configPath = Element.textContent(request.responseXML.getElementsByTagName('config_path')[0]);
|
||||
Config.isWritable = Element.textContent(request.responseXML.getElementsByTagName('writable_config')[0]) == '1';
|
||||
new Ajax.Request('xml-rpc?method=config',{method: 'get',onComplete: Config.showConfig});
|
||||
},
|
||||
showConfig: function (request) {
|
||||
ConfigInitialValues.parseXML(request.responseXML);
|
||||
$A(Config.tmpConfigXML.getElementsByTagName('section')).each(function (section) {
|
||||
var head = document.createElement('div');
|
||||
head.className= 'naviheader';
|
||||
var sectionName = section.getAttribute('name');
|
||||
head.appendChild(document.createTextNode(sectionName));
|
||||
var body = document.createElement('div');
|
||||
body.className = 'navibox';
|
||||
if ('Server' == sectionName) {
|
||||
body.appendChild(Builder.node('span',{id:'config_path_label'},'Config File Location'));
|
||||
var span = Builder.node('span',{id:'config_path'});
|
||||
span.appendChild(document.createTextNode(Config.configPath));
|
||||
body.appendChild(span);
|
||||
body.appendChild(Builder.node('br'));
|
||||
body.appendChild(Builder.node('div',{style: 'clear: both;'}));
|
||||
}
|
||||
$A(section.getElementsByTagName('item')).each(function (item) {
|
||||
body.appendChild(Config._buildItem(item.getAttribute('id')));
|
||||
});
|
||||
var div = document.createElement('div');
|
||||
div.id = ConfigXML.getSectionId(sectionName);
|
||||
if (!Cookie.getVar('show_advanced_config') && ConfigXML.isAdvancedSection(sectionName)) {
|
||||
div.style.display = 'none';
|
||||
}
|
||||
div.appendChild(head);
|
||||
div.appendChild(body);
|
||||
$('theform').appendChild(div);
|
||||
});
|
||||
// Won't be using the config.xml XML doc anymore get rid of it
|
||||
Config.tmpConfigXML = '';
|
||||
if (!Config.isWritable) {
|
||||
Effect.Appear('config_not_writable_warning');
|
||||
} else {
|
||||
// Create save and cancel buttons
|
||||
// var save = Builder.node('button',{id: 'button_save', disabled: 'disabled'},'Save');
|
||||
var save = Builder.node('input',{id: 'button_save',type: 'button', value:'Save',
|
||||
style: 'font: 1.2em Verdana, Helvetica, Arial, sans-serif'});
|
||||
Event.observe(save,'click',saveForm);
|
||||
var cancel = Builder.node('input',{id: 'button_cancel',type: 'button',value:'Cancel',
|
||||
style: 'font: 1.2em Verdana, Helvetica, Arial, sans-serif'});
|
||||
Event.observe(cancel,'click',cancelForm);
|
||||
var spacer = document.createTextNode('\u00a0\u00a0');
|
||||
var buttons = $('buttons');
|
||||
if (navigator.platform.toLowerCase().indexOf('mac') != -1) {
|
||||
// We're on mac
|
||||
buttons.appendChild(cancel);
|
||||
buttons.appendChild(spacer);
|
||||
buttons.appendChild(save);
|
||||
} else {
|
||||
//###TODO What about all them unix variants?
|
||||
buttons.appendChild(save);
|
||||
buttons.appendChild(spacer);
|
||||
buttons.appendChild(cancel);
|
||||
}
|
||||
}
|
||||
var advanced = Builder.node('a',{href: 'javascript://',id:'basic_config_button'},'Show basic config');
|
||||
Event.observe(advanced,'click',Config._showBasicConfig);
|
||||
var basic = Builder.node('a',{href: 'javascript://',id:'advanced_config_button'},'Show advanced config');
|
||||
Event.observe(basic,'click',Config._showAdvancedConfig);
|
||||
if (Cookie.getVar('show_advanced_config')) {
|
||||
basic.style.display = 'none';
|
||||
} else {
|
||||
advanced.style.display = 'none';
|
||||
}
|
||||
var div = $('toggle_basic_advanced');
|
||||
div.appendChild(advanced);
|
||||
div.appendChild(basic);
|
||||
},
|
||||
_buildItem: function(itemId) {
|
||||
var frag = document.createElement('div');
|
||||
var href;
|
||||
var item = ConfigXML.getItem(itemId);
|
||||
switch(item.type) {
|
||||
case 'text':
|
||||
if (item.multiple) {
|
||||
var values = ConfigInitialValues.getValue(itemId);
|
||||
if (!values || values.length === 0) {
|
||||
values = [''];
|
||||
}
|
||||
// var parentSpan = Builder.node('span');
|
||||
values.each(function (val,i) {
|
||||
var div = document.createElement('div');
|
||||
// Crappy IE wants a width on floated elements (or maybe it was w3c requiring it)
|
||||
div.style.width = '60em';
|
||||
div.appendChild(BuildElement.input(itemId+i,itemId,
|
||||
item.name,
|
||||
val || item.default_value || '',
|
||||
item.size || 20,
|
||||
item.short_description,
|
||||
''));
|
||||
// if (item.browse) {
|
||||
// href = Builder.node('a',{href: 'javascript://'},'Browse');
|
||||
// Event.observe(href,'click',Config._browse);
|
||||
// div.appendChild(href);
|
||||
// }
|
||||
div.appendChild(document.createTextNode('\u00a0\u00a0'));
|
||||
href = Builder.node('a',{style: 'width: 6em;',href: 'javascript://'},'Remove');
|
||||
Event.observe(href,'click',Config._removeItemEvent);
|
||||
div.appendChild(href);
|
||||
div.appendChild(Builder.node('br'));
|
||||
frag.appendChild(div);
|
||||
});
|
||||
// This is used by cancelForm to find out how
|
||||
// many options a multiple group has
|
||||
// frag.appendChild(parentSpan);
|
||||
href = Builder.node('a',{href:'javascript://',className:'addItemHref'},item.add_item_label);
|
||||
frag.appendChild(href);
|
||||
Event.observe(href,'click',Config._addItemEvent);
|
||||
frag.appendChild(Builder.node('div',{style:'clear: both'}));
|
||||
} else {
|
||||
frag.appendChild(BuildElement.input(itemId,itemId,
|
||||
item.name,
|
||||
ConfigInitialValues.getValue(itemId) || item.default_value || '',
|
||||
item.size || 20,
|
||||
item.short_description,
|
||||
''));
|
||||
// if (item.browse) {
|
||||
// href = Builder.node('a',{href: 'javascript://'},'Browse');
|
||||
// Event.observe(href,'click',Config._browse);
|
||||
// frag.appendChild(href);
|
||||
// }
|
||||
// frag.appendChild(Builder.node('br'));
|
||||
}
|
||||
break;
|
||||
case 'select':
|
||||
frag.appendChild(BuildElement.select(itemId,
|
||||
item.name,
|
||||
item.options,
|
||||
ConfigInitialValues.getValue(itemId) || item.default_value,
|
||||
item.short_description));
|
||||
// frag.appendChild(Builder.node('br'));
|
||||
break;
|
||||
default:
|
||||
alert('This should not happen (1)');
|
||||
break;
|
||||
}
|
||||
if (!Cookie.getVar('show_advanced_config') && item.advanced) {
|
||||
frag.style.display = 'none';
|
||||
}
|
||||
frag.style.clear = 'both';
|
||||
return frag;
|
||||
},
|
||||
_addItemEvent: function (e) {
|
||||
var div = Event.element(e).previousSibling;
|
||||
Config._addItem(div);
|
||||
},
|
||||
_addItem: function(div) {
|
||||
var newSpan = div.cloneNode(true);
|
||||
var id = newSpan.getElementsByTagName('input')[0].id;
|
||||
var num = parseInt(id.match(/\d+$/));
|
||||
num++;
|
||||
id = id.replace(/\d+$/,'') + num;
|
||||
|
||||
newSpan.getElementsByTagName('label')[0].setAttribute('for',id);
|
||||
newSpan.getElementsByTagName('input')[0].id = id;
|
||||
newSpan.getElementsByTagName('input')[0].value = '';
|
||||
newSpan.style.display = 'none';
|
||||
var hrefs = newSpan.getElementsByTagName('a');
|
||||
if ('Netscape' == navigator.appName) {
|
||||
// Firefox et al doesn't copy registered events on an element deep clone
|
||||
// Don't know if that is w3c or if IE has it right
|
||||
if (hrefs.length == 1) {
|
||||
Event.observe(hrefs[0],'click',Config._removeItemEvent);
|
||||
} else {
|
||||
Event.observe(hrefs[0],'click',Config._browse);
|
||||
Event.observe(hrefs[1],'click',Config._removeItemEvent);
|
||||
}
|
||||
}
|
||||
div.parentNode.insertBefore(newSpan,div.nextSibling);
|
||||
Effect.BlindDown(newSpan,{duration: 0.2});
|
||||
},
|
||||
_removeItemEvent: function (e) {
|
||||
var div = Event.element(e).parentNode;
|
||||
Config._removeItem(div);
|
||||
},
|
||||
_removeItem: function(div,noAnimation) {
|
||||
if (div.parentNode.getElementsByTagName('input').length > 1) {
|
||||
if (noAnimation) {
|
||||
// cancelForm uses a loop to delete elements, the loop can't wait
|
||||
// for Effect.BlindUp to finish
|
||||
Element.remove(div);
|
||||
} else {
|
||||
Effect.BlindUp(div,{duration: 0.2, afterFinish: function (){Element.remove(div);}});
|
||||
}
|
||||
} else {
|
||||
div.getElementsByTagName('input')[0].value='';
|
||||
}
|
||||
},
|
||||
_browse: function(e) {
|
||||
alert('Here goes UI to browse for files and dirs');
|
||||
},
|
||||
_showAdvancedConfig: function (e) {
|
||||
Element.toggle('advanced_config_button');
|
||||
Element.toggle('basic_config_button');
|
||||
Cookie.setVar('show_advanced_config','true',30);
|
||||
ConfigXML.getAllAdvancedSections().each(function (sectionName) {
|
||||
Effect.BlindDown(ConfigXML.getSectionId(sectionName));
|
||||
});
|
||||
ConfigXML.getAllItems().each(function (item) {
|
||||
if (item.advanced) {
|
||||
var element = $(item.id);
|
||||
if (!element) {
|
||||
// Handle options with multiple values
|
||||
$A(document.getElementsByName(item.id)).each(function (el) {
|
||||
Effect.BlindDown(el.parentNode.parentNode);
|
||||
});
|
||||
} else {
|
||||
Effect.BlindDown(element.parentNode);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
_showBasicConfig: function (e) {
|
||||
Element.toggle('advanced_config_button');
|
||||
Element.toggle('basic_config_button');
|
||||
Cookie.removeVar('show_advanced_config');
|
||||
ConfigXML.getAllAdvancedSections().each(function (sectionName) {
|
||||
Effect.BlindUp(ConfigXML.getSectionId(sectionName));
|
||||
});
|
||||
ConfigXML.getAllItems().each(function (item) {
|
||||
if (item.advanced) {
|
||||
var element = $(item.id);
|
||||
if (!element) {
|
||||
// Handle options with multiple values
|
||||
$A(document.getElementsByName(item.id)).each(function (el) {
|
||||
Effect.BlindUp(el.parentNode.parentNode);
|
||||
});
|
||||
} else {
|
||||
Effect.BlindUp(element.parentNode);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
var BuildElement = {
|
||||
input: function(id,name,displayName,value,size,short_description,long_description) {
|
||||
|
||||
var frag = document.createDocumentFragment();
|
||||
var label = document.createElement('label');
|
||||
|
||||
label.setAttribute('for',id);
|
||||
label.appendChild(document.createTextNode(displayName));
|
||||
frag.appendChild(label);
|
||||
var input;
|
||||
if (/KHTML/.test(navigator.userAgent) && (80 == size)) {
|
||||
// Safari & Konqueror input fields gets to long
|
||||
// This is a runner up in the ugly bug fix contest
|
||||
size = 60;
|
||||
}
|
||||
|
||||
if (Config.isWritable) {
|
||||
input = Builder.node('input',{id: id,name: name,className: 'text',
|
||||
value: value,size: size});
|
||||
} else {
|
||||
input = Builder.node('input',{id: id,name: name,className: 'text',
|
||||
value: value,size: size, disabled: 'disabled'});
|
||||
}
|
||||
if (/KHTML/.test(navigator.userAgent)) {
|
||||
// Safari & Konqueror doesn't do font: icon on inputs and selects
|
||||
input.style.fontSize = 'x-small';
|
||||
}
|
||||
frag.appendChild(input);
|
||||
frag.appendChild(document.createTextNode('\u00a0'));
|
||||
if (short_description) {
|
||||
frag.appendChild(document.createTextNode(short_description));
|
||||
}
|
||||
|
||||
return frag;
|
||||
},
|
||||
select: function(id,displayName,options,value,short_description,long_description) {
|
||||
var frag = document.createDocumentFragment();
|
||||
var label = document.createElement('label');
|
||||
label.setAttribute('for',id);
|
||||
label.appendChild(document.createTextNode(displayName));
|
||||
frag.appendChild(label);
|
||||
|
||||
var select = Builder.node('select',{id: id,name: id,size: 1});
|
||||
if (!Config.isWritable) {
|
||||
select.disabled = 'disabled';
|
||||
}
|
||||
$A(options).each(function (option) {
|
||||
select.appendChild(Builder.node('option',{value: option.value},
|
||||
option.label));
|
||||
});
|
||||
select.value = value;
|
||||
if (/KHTML/.test(navigator.userAgent)) {
|
||||
// Safari & Konqueror doesn't do font: icon on inputs and selects
|
||||
select.style.fontSize = 'x-small';
|
||||
}
|
||||
|
||||
frag.appendChild(select);
|
||||
frag.appendChild(document.createTextNode('\u00a0'));
|
||||
if (short_description) {
|
||||
frag.appendChild(document.createTextNode(short_description));
|
||||
}
|
||||
|
||||
return frag;
|
||||
}
|
||||
};
|
||||
|
||||
function saved(req) {
|
||||
if (g_messageTimeout) {
|
||||
window.clearTimeout(g_messageTimeout);
|
||||
}
|
||||
if ('200' == Element.textContent(req.responseXML.getElementsByTagName('status')[0])) {
|
||||
$('messages').innerHTML = 'Saved';
|
||||
Effect.Appear('messages',{duration: 0.2});
|
||||
g_messageTimeout = window.setTimeout(function(){
|
||||
Effect.Fade('messages',{duration: 0.2});
|
||||
},3000);
|
||||
} else {
|
||||
$('messages').innerHTML = 'Error: ' + req.responseText;
|
||||
Effect.Appear('messages',{duration: 0.2});
|
||||
}
|
||||
}
|
||||
function saveForm() {
|
||||
var postVars = [];
|
||||
var multiple = {};
|
||||
|
||||
$A($('theform').getElementsByTagName('select')).each(function (select) {
|
||||
if (DEBUG) {
|
||||
debug(select.id,select.value);
|
||||
} else {
|
||||
if (select.value != ConfigInitialValues.getValue(select.id)) {
|
||||
postVars.push(Form.Element.serialize(select.id));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$A($('theform').getElementsByTagName('input')).each(function (input) {
|
||||
if (ConfigXML.getItem(input.name).multiple) {
|
||||
var value = encodeURIComponent(input.value.replace(/,/g,',,'));
|
||||
if (multiple[input.name]) {
|
||||
multiple[input.name].push(value);
|
||||
} else {
|
||||
multiple[input.name] = [value];
|
||||
}
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
debug(input.id,input.value);
|
||||
} else {
|
||||
if (input.value != ConfigInitialValues.getValue(input.id)) {
|
||||
postVars.push(Form.Element.serialize(input.id));
|
||||
ConfigInitialValues.setValue(input.id,input.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$H(multiple).each(function (item) {
|
||||
if (DEBUG) {
|
||||
debug(item.key,item.value.join(','));
|
||||
} else {
|
||||
var currentValue = item.value.join(',');
|
||||
var initialValue = ConfigInitialValues.getValue(item.key).collect(function (value) {
|
||||
return encodeURIComponent(value.replace(/,/g,',,'));
|
||||
});
|
||||
if (currentValue != initialValue) {
|
||||
postVars.push(item.key + '=' + currentValue);
|
||||
ConfigInitialValues.setValue(item.key,item.value.collect(function (value) {
|
||||
return decodeURIComponent(value).replace(/,,/g,',');
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
if (DEBUG) {
|
||||
return;
|
||||
}
|
||||
if (postVars.length > 0 ) {
|
||||
new Ajax.Request('xml-rpc?method=updateconfig',
|
||||
{method: 'post',
|
||||
parameters: postVars.join('&'),
|
||||
onComplete: saved});
|
||||
}
|
||||
|
||||
function debug(id,value) {
|
||||
var getArr = [];
|
||||
var getString;
|
||||
if ('validate' == DEBUG) {
|
||||
var a = id.split(':');
|
||||
getArr.push('section='+encodeURIComponent(a[0]));
|
||||
getArr.push('key='+encodeURIComponent(a[1]));
|
||||
getArr.push('value='+encodeURIComponent(value));
|
||||
getArr.push('verify_only=1');
|
||||
getString = 'xml-rpc?method=setconfig&' + getArr.join('&');
|
||||
|
||||
} else {
|
||||
getString = 'xml-rpc?method=updateconfig&' + Form.Element.serialize(id);
|
||||
}
|
||||
var output = id + '=' + value;
|
||||
new Ajax.Request(getString,
|
||||
{method: 'get',
|
||||
onComplete: function(req){
|
||||
var errorString = Element.textContent(req.responseXML.getElementsByTagName('statusstring')[0]);
|
||||
if (errorString != 'Success') {
|
||||
console.log(output + ' => ' + errorString);
|
||||
}
|
||||
}});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
function cancelForm() {
|
||||
ConfigXML.getAllItems().each(function (item) {
|
||||
if (item.multiple) {
|
||||
var values = ConfigInitialValues.getValue(item.id);
|
||||
if (!values || values.length === 0) {
|
||||
values = [''];
|
||||
}
|
||||
var initialValuesCount = values.length;
|
||||
var currentElements = document.getElementsByName(item.id);
|
||||
var i=0;
|
||||
while (initialValuesCount < currentElements.length) {
|
||||
i++;
|
||||
if (i > 10) {
|
||||
alert('Getting dizzy; too many turns in this loop (silly errormessage 1)');
|
||||
return;
|
||||
}
|
||||
Config._removeItem(currentElements[0].parentNode,'noAnimation');
|
||||
}
|
||||
while (initialValuesCount > currentElements.length) {
|
||||
i++;
|
||||
if (i > 10) {
|
||||
alert('An important part came off (silly errormessage 2)');
|
||||
return;
|
||||
}
|
||||
Config._addItem(currentElements[currentElements.length-1].parentNode);
|
||||
}
|
||||
values.each(function (val,i){
|
||||
currentElements[i].value = val;
|
||||
});
|
||||
} else {
|
||||
//###TODO potential error a select without a default value
|
||||
$(item.id).value = ConfigInitialValues.getValue(item.id) || item.default_value || '';
|
||||
}
|
||||
$('messages').innerHTML = 'Cancelled';
|
||||
if (g_messageTimeout) {
|
||||
window.clearTimeout(g_messageTimeout);
|
||||
}
|
||||
Effect.Appear('messages',{duration: 0.2});
|
||||
g_messageTimeout = window.setTimeout(function(){
|
||||
Effect.Fade('messages',{duration: 0.2});
|
||||
},3000);
|
||||
|
||||
|
||||
});
|
||||
return;
|
||||
}
|
@ -1,345 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<config>
|
||||
<section name="Server">
|
||||
<item id="general:servername" restart="true">
|
||||
<name>Server Name</name>
|
||||
<short_description>
|
||||
The name iTunes and other daap clients should see
|
||||
</short_description>
|
||||
<long_description>
|
||||
This is both the name of the server as advertised via Bonjour, and the
|
||||
name of the database exported via DAAP. Also know as "What shows up in
|
||||
iTunes".
|
||||
</long_description>
|
||||
<type size="20">text</type>
|
||||
</item>
|
||||
<item id="general:web_root" advanced="true" required="true" restart="true">
|
||||
<name>Web Root</name>
|
||||
<short_description></short_description>
|
||||
<type size="80" browse="directory">text</type>
|
||||
</item>
|
||||
<item id="general:port" advanced="true" required="true" restart="true">
|
||||
<name>Port</name>
|
||||
<short_description>
|
||||
The port the server should run at; default is 3689
|
||||
</short_description>
|
||||
<type size="20">text</type>
|
||||
</item>
|
||||
<item id="general:logfile">
|
||||
<name>Logfile</name>
|
||||
<short_description></short_description>
|
||||
<type size="80" browse="file">text</type>
|
||||
</item>
|
||||
<item id="general:runas" advanced="true" required="true" restart="true">
|
||||
<name>Run As</name>
|
||||
<short_description></short_description>
|
||||
<type size="20">text</type>
|
||||
</item>
|
||||
<item id="general:admin_pw" required="true">
|
||||
<name>Admin password</name>
|
||||
<short_description>
|
||||
The password for this administration interface.
|
||||
</short_description>
|
||||
<type size="20">text</type>
|
||||
</item>
|
||||
<item id="general:password">
|
||||
<name>Music Password</name>
|
||||
<short_description>
|
||||
The password clients need to access this server.
|
||||
</short_description>
|
||||
<type size="20">text</type>
|
||||
</item>
|
||||
<item id="general:compress" advanced="true">
|
||||
<name>Compress</name>
|
||||
<short_description>
|
||||
Should browsing data be compressed on the way to the client?
|
||||
</short_description>
|
||||
<type default_value="0">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="general:truncate" advanced="true">
|
||||
<name>Truncate Logfile</name>
|
||||
<short_description>
|
||||
Should the logfile get truncated on startup?
|
||||
</short_description>
|
||||
<type default_value="0">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
|
||||
<item id="general:debuglevel" advanced="true">
|
||||
<name>Debug Level</name>
|
||||
<short_description>
|
||||
Possible values are 0 to 9, 9 being the most detailed debug level.
|
||||
</short_description>
|
||||
<type default_value="0">select</type>
|
||||
<options>
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
<option value="6">6</option>
|
||||
<option value="7">7</option>
|
||||
<option value="8">8</option>
|
||||
<option value="9">9</option>
|
||||
</options>
|
||||
</item>
|
||||
</section>
|
||||
|
||||
<section name="Music Files">
|
||||
<item id="general:mp3_dir" required="true">
|
||||
<name>Music Folder</name>
|
||||
<short_description></short_description>
|
||||
<type size="80" multiple="true" add_item_label="Add music folder" browse="directory">text</type>
|
||||
</item>
|
||||
<item id="general:extensions">
|
||||
<name>Extensions</name>
|
||||
<short_description></short_description>
|
||||
<type size="20">text</type>
|
||||
</item>
|
||||
<item id="general:playlist">
|
||||
<name>Playlist File</name>
|
||||
<short_description></short_description>
|
||||
<type size="80" browse="file">text</type>
|
||||
</item>
|
||||
<item id="general:compdirs" advanced="true">
|
||||
<name>Compilation Directories</name>
|
||||
<short_description></short_description>
|
||||
<type size="80" multiple="true" add_item_label="Add compilation directory" browse="directory">text</type>
|
||||
</item>
|
||||
</section>
|
||||
<section name="Scanning" advanced="true">
|
||||
<item id="scanning:mp3_tag_codepage">
|
||||
<name>MP3 Tag Codepage</name>
|
||||
<short_description>
|
||||
What codepage non-utf mp3 tags should be converted from (default: ISO-8859-1)
|
||||
</short_description>
|
||||
<type>text</type>
|
||||
</item>
|
||||
<item id="scanning:process_playlists">
|
||||
<name>Process Playlists</name>
|
||||
<short_description>
|
||||
Should static playlists (.m3u, etc) be processed?
|
||||
</short_description>
|
||||
<type default_value="1">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="scanning:process_itunes">
|
||||
<name>Process iTunes files</name>
|
||||
<short_description>
|
||||
Should iTunes xml-files be processed?
|
||||
</short_description>
|
||||
<type default_value="1">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="scanning:process_m3u">
|
||||
<name>Process .m3u files</name>
|
||||
<short_description>
|
||||
Should .m3u playlists be processed?
|
||||
</short_description>
|
||||
<type default_value="0">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="scanning:case_sensitive">
|
||||
<name>Case Sensitive</name>
|
||||
<short_description>
|
||||
Is the filesystem case sensitive?
|
||||
</short_description>
|
||||
<type default_value="1">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="scanning:ignore_appledouble">
|
||||
<name>Ignore appledouble</name>
|
||||
<short_description>
|
||||
Skip appledouble files when scanning
|
||||
</short_description>
|
||||
<type default_value="1">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="scanning:ignore_dotfiles">
|
||||
<name>Ignore dotfiles</name>
|
||||
<short_description>
|
||||
Ignore unix hidden dot files
|
||||
</short_description>
|
||||
<type default_value="0">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="scanning:concat_compilations">
|
||||
<name>Group compilations</name>
|
||||
<short_description>
|
||||
Compilations are grouped under "Various artist"
|
||||
</short_description>
|
||||
<type default_value="0">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="scanning:follow_symlinks">
|
||||
<name>Follow Symlinks</name>
|
||||
<short_description>
|
||||
Should symlinks be followed when scanning directories?
|
||||
</short_description>
|
||||
<type default_value="1">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="scanning:skip_first">
|
||||
<name>Skip First Scan</name>
|
||||
<short_description>
|
||||
Should the initial boot-up scan be skipped?
|
||||
</short_description>
|
||||
<type default_value="0">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
</section>
|
||||
<section name="Database">
|
||||
<item id="general:db_type" advanced="true" restart="true">
|
||||
<name>Database Type</name>
|
||||
<short_description></short_description>
|
||||
<type default_value="sqlite">select</type>
|
||||
<options>
|
||||
<option value="sqlite">sqlite</option>
|
||||
<option value="sqlite3">sqlite3</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="general:db_parms" advanced="true" restart="true">
|
||||
<name>Database Directory</name>
|
||||
<short_description></short_description>
|
||||
<type size="80" browse="directory">text</type>
|
||||
</item>
|
||||
<item id="general:scan_type" restart="true">
|
||||
<name>Scan Type</name>
|
||||
<short_description></short_description>
|
||||
<type default_value="2">select</type>
|
||||
<options>
|
||||
<option value="0">0 - Normal</option>
|
||||
<option value="1">1 - Aggressive</option>
|
||||
<option value="2">2 - Painfully aggressive</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="general:rescan_interval" restart="true">
|
||||
<name>Rescan Interval</name>
|
||||
<short_description>
|
||||
How often should Firefly look for new files? In seconds.
|
||||
</short_description>
|
||||
<type size="20">text</type>
|
||||
</item>
|
||||
<item id="general:always_scan" restart="true">
|
||||
<name>Always Scan</name>
|
||||
<short_description></short_description>
|
||||
<type default_value="0">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
</section>
|
||||
|
||||
<section name="Daap" advanced="true">
|
||||
<item id="daap:correct_order">
|
||||
<name>Ordered Playlists</name>
|
||||
<short_description>
|
||||
Should playlists be returned in the order specified in the playlist?
|
||||
</short_description>
|
||||
<type default_value="1">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="daap:empty_strings">
|
||||
<name>Empty strings</name>
|
||||
<short_description></short_description>
|
||||
<type default_value="0">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="daap:supports_update">
|
||||
<name>Supports update</name>
|
||||
<short_description></short_description>
|
||||
<type default_value="1">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
<item id="daap:supports_browse">
|
||||
<name>Supports browse</name>
|
||||
<short_description></short_description>
|
||||
<type default_value="1">select</type>
|
||||
<options>
|
||||
<option value="0">No</option>
|
||||
<option value="1">Yes</option>
|
||||
</options>
|
||||
</item>
|
||||
|
||||
</section>
|
||||
|
||||
<section name="Plugins" advanced="true">
|
||||
<item id="plugins:plugin_dir" config_section="plugins" restart="true">
|
||||
<name>Plugin Directory</name>
|
||||
<short_description></short_description>
|
||||
<type size="80" browse="directory">text</type>
|
||||
</item>
|
||||
</section>
|
||||
|
||||
<section name="Transcoding" advanced="true">
|
||||
<item id="general:ssc_prog">
|
||||
<name>SSC Program</name>
|
||||
<short_description></short_description>
|
||||
<type size="80" browse="file">text</type>
|
||||
</item>
|
||||
<item id="general:ssc_codectypes">
|
||||
<name>SSC Codec Types</name>
|
||||
<short_description></short_description>
|
||||
<type size="80">text</type>
|
||||
</item>
|
||||
<item id="general:never_transcode">
|
||||
<name>Never Transcode</name>
|
||||
<short_description>
|
||||
Codecs to not transcode, even if plugins are available
|
||||
</short_description>
|
||||
<type size="80">text</type>
|
||||
</item>
|
||||
<item id="general:always_transcode">
|
||||
<name>Always Transcode</name>
|
||||
<short_description>
|
||||
Codecs to always transcode, even if client plays it
|
||||
</short_description>
|
||||
<type size="80">text</type>
|
||||
</item>
|
||||
</section>
|
||||
</config>
|
Before Width: | Height: | Size: 35 KiB |
@ -1,105 +0,0 @@
|
||||
@include hdr.html@
|
||||
|
||||
<h1>Feedback</h1>
|
||||
|
||||
<p class="description">
|
||||
Here you can send feedback on your mt-daapd installation to the developer.
|
||||
</p>
|
||||
|
||||
<form action="http://www.pedde.com/mt-daapd/register.php" method="post">
|
||||
<table><tr>
|
||||
<th>Feedback</th>
|
||||
<th><input type="submit" value="Leave Feedback" /></th>
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="feedbackname" rowspan="2">Works?</td>
|
||||
<td class="feedbacktext">
|
||||
The most important question. Did this version work for you?
|
||||
If not, uncheck the box, and put an explanation in the NOTES
|
||||
entry below.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="feedbackdata"><input class="feedbackfield" type="checkbox" name="works" value="CHECKED" checked="checked" /></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="feedbackname" rowspan="2">Version</td>
|
||||
<td class="feedbacktext">
|
||||
This is the version of mt-daapd you are running. If you are using a
|
||||
public release, use the version number (0.1.0, 0.1.1, etc). If it is
|
||||
manually checked out of cvs, use 'cvs', if it is a nightly snapshot,
|
||||
use the snapshot name, for example: 'cvs-20040328'.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="feedbackdata"><input class="feedbackfield" type="text" size="40" name="version" value="@VERSION@" /></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="feedbackname" rowspan="2">System</td>
|
||||
<td class="feedbacktext">
|
||||
This is the operating system and version you are running.
|
||||
Use something like "Sparc Solaris 9" or "x86 Linux 2.6.3" or
|
||||
"Mac OSX 10.3" or something to help identify what platform and
|
||||
version you are running.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="feedbackdata"><input class="feedbackfield" type="text" size="40" name="system" value="@SYSTEM@" /></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="feedbackname" rowspan="2">Compile arguments</td>
|
||||
<td class="feedbacktext">
|
||||
If you used any compile flags, that would be helpful. Examples might include
|
||||
'--with-gdbm', or '--enable-howl' or something else.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="feedbackdata"><input class="feedbackfield" type="text" size="40" name="compile" value="@FLAGS@" /></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="feedbackname" rowspan="2">Notes</td>
|
||||
<td class="feedbacktext">
|
||||
If it didn't work for you, or if you just want to make a
|
||||
suggestion, leave those notes here. Remember that these
|
||||
notes are publicly viewable.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="feedbackdata"><textarea class="feedbackfield" rows="3" cols="40" name="notes"></textarea></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="feedbackname" rowspan="2">Rating</td>
|
||||
<td class="feedbacktext">
|
||||
Just for fun, give this release a rating from 1 to 10, 1 being
|
||||
so bad it started your computer on fire, 10 meaning works so
|
||||
well, it even made your breath fresher.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="feedbackdata">
|
||||
<select class="feedbackfield" name="rating">
|
||||
<option value="10">10 - it made my breath fresher</option>
|
||||
<option value="9">9</option>
|
||||
<option value="8">8</option>
|
||||
<option value="7">7</option>
|
||||
<option value="6" selected="SELECTED">6 - we're gonna wait and see</option>
|
||||
<option value="5">5</option>
|
||||
<option value="4">4</option>
|
||||
<option value="3">3</option>
|
||||
<option value="2">2</option>
|
||||
<option value="1">1 - it set my computer on fire</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
@include ftr.html@
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@ -1,167 +0,0 @@
|
||||
/* General */
|
||||
|
||||
body
|
||||
{ background: #ffffff;
|
||||
font: 0.7em Verdana, Helvetica, Arial, sans-serif;
|
||||
color: #000000;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#main_table {
|
||||
border-width: 0;
|
||||
}
|
||||
img {
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
/*
|
||||
div.ministatus
|
||||
{ text-align: right;
|
||||
padding: 1em;
|
||||
}
|
||||
*/
|
||||
|
||||
a
|
||||
{ color: blue;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover
|
||||
{ color: blue;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Navigation */
|
||||
div.naviheader {
|
||||
background-color: #A3C1E8;
|
||||
padding: 0.5em 0em 0.5em 1em;
|
||||
margin: 1em 0em 0em 0em;
|
||||
font-weight: bold;
|
||||
border-color: #A3C1E8;
|
||||
border-style: solid;
|
||||
border-width: 1px 1px 0 1px;
|
||||
}
|
||||
|
||||
div.navibox
|
||||
{ padding: 0.5em 0em 0.5em 0em;
|
||||
margin: 0em 0em 1em 0em;
|
||||
border-color: #A3C1E8;
|
||||
border-style: solid;
|
||||
border-width: 0 1px 1px 1px;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
|
||||
/* Main */
|
||||
|
||||
h1,h2,h3
|
||||
{ border-bottom: 1px solid #A3C1E8;
|
||||
}
|
||||
|
||||
|
||||
p.license {
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
.playlistfield {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
table {
|
||||
border: 1px solid #A3C1E8;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: bold;
|
||||
padding: 0 1em 0 1em;
|
||||
background: #A3C1E8;
|
||||
color: #000000;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0 1em 0 1em;
|
||||
}
|
||||
|
||||
#navigation {
|
||||
float: left;/*74A8F5*/
|
||||
background-color: #A3C1E8;
|
||||
padding-top: 1em;
|
||||
height: 500px;
|
||||
}
|
||||
#navigation ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
#navigation li {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
#navigation li a {
|
||||
font-size: 120%;
|
||||
display: block;
|
||||
width: 12em;
|
||||
text-decoration:none;
|
||||
color: #000000;
|
||||
padding: 2px 0.5em 2px 0.5em;
|
||||
border-color: #ffffff;
|
||||
border-width: 1px 0 1px 0;
|
||||
border-style: solid;
|
||||
}
|
||||
#navigation li a:hover {
|
||||
background-color: #F2BB73;
|
||||
color: #000000;
|
||||
/* border: 1px solid #F47D24;*/
|
||||
}
|
||||
#navigation li a.naviselected {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.links {
|
||||
padding-top: 1em;
|
||||
padding-left: .5em;
|
||||
}
|
||||
#tagline {
|
||||
padding: 0.25em 0 0.25em 0.5em;
|
||||
border-color: #F47D24;
|
||||
border-style: solid;
|
||||
border-width: 1px 0 1px 0;
|
||||
background-color: #F2BB73
|
||||
}
|
||||
#firefly_head {
|
||||
background-color: #f0f0f0;
|
||||
padding-top: 4px;
|
||||
padding-left: .5em;
|
||||
}
|
||||
#spinner {
|
||||
margin-left: 1em;
|
||||
}
|
||||
/* config.html */
|
||||
#toggle_basic_advanced {
|
||||
font: icon !important;
|
||||
}
|
||||
/* smart.html */
|
||||
#pl_editor {
|
||||
width: 400px;
|
||||
}
|
||||
#pl_editor label {
|
||||
float: left;
|
||||
width: 7em;
|
||||
font: icon;
|
||||
padding-top: .3em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
#playlist_buttons {
|
||||
float: right;
|
||||
}
|
||||
#pl_warning {
|
||||
background-color: yellow;
|
||||
padding: 1em;
|
||||
border: 1px solid #8CACBB;
|
||||
width: 40em;
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/* JavaScript file containing basic stuff */
|
||||
|
||||
var reqStatus;
|
||||
var globalStatus = new Array();
|
||||
|
||||
function popUp(URL)
|
||||
{ day = new Date();
|
||||
id = day.getTime();
|
||||
eval("pagemtdaapdplPop = window.open(URL, 'mtdaapdple', 'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=1,width=500,height=240,left=320,top=448');");
|
||||
}
|
||||
|
||||
/* Temporary stuff follows */
|
||||
|
||||
function processStatus()
|
||||
{ globalStatus['statistics'] = new Array();
|
||||
var xmldoc = reqStatus.responseXML;
|
||||
}
|
||||
|
||||
|
||||
function reqStatusStateChange()
|
||||
{ if(reqStatus.readyState == 4)
|
||||
{ if(reqStatus.status == 200)
|
||||
{ processStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getStatusXML(url, async)
|
||||
{ // branch for native XMLHttpRequest object
|
||||
if (window.XMLHttpRequest)
|
||||
{ reqStatus = new XMLHttpRequest();
|
||||
reqStatus.onreadystatechange = reqStatusStateChange;
|
||||
reqStatus.open("GET", url, async);
|
||||
return reqStatus.send(null);
|
||||
// branch for IE/Windows ActiveX version
|
||||
} else if (window.ActiveXObject)
|
||||
{ reqStatus = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
if (reqStatus)
|
||||
{ reqStatus.onreadystatechange = reqStatusStateChange;
|
||||
reqStatus.open("GET", url, async);
|
||||
return reqStatus.send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +0,0 @@
|
||||
</td></tr></table>
|
||||
</body>
|
||||
</html>
|
@ -1,9 +0,0 @@
|
||||
@include hdr.html@
|
||||
|
||||
<h2>GPL License</h2>
|
||||
|
||||
<p class="license"><pre>
|
||||
@include gpl-license.txt@
|
||||
</pre></p>
|
||||
|
||||
@include ftr.html@
|
@ -1,340 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
@ -1,71 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
|
||||
<head>
|
||||
<title>Firefly Media Server</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<link rel="stylesheet" type="text/css" href="firefly.css" />
|
||||
@ispage index.html:<script type="text/javascript" src="lib-js/prototype.js"></script>:@
|
||||
@ispage index.html:<script type="text/javascript" src="lib-js/script.aculo.us/effects.js"></script>:@
|
||||
@ispage index.html:<script type="text/javascript" src="util.js"></script>:@
|
||||
@ispage index.html:<script type="text/javascript" src="status.js"></script>:@
|
||||
@ispage index.html:<link rel="stylesheet" type="text/css" href="index.css"/>:@
|
||||
@ispage config.html:<script type="text/javascript" src="lib-js/prototype.js"></script>:@
|
||||
@ispage config.html:<script type="text/javascript" src="lib-js/script.aculo.us/scriptaculous.js"></script>:@
|
||||
@ispage config.html:<script type="text/javascript" src="util.js"></script>:@
|
||||
@ispage config.html:<script type="text/javascript" src="config.js"></script>:@
|
||||
@ispage config.html:<link rel="stylesheet" type="text/css" href="config.css"/>:@
|
||||
@ispage smart.html:<script type="text/javascript" src="lib-js/prototype.js"></script>:@
|
||||
@ispage smart.html:<script type="text/javascript" src="lib-js/script.aculo.us/effects.js"></script>:@
|
||||
@ispage smart.html:<script type="text/javascript" src="smart.js"></script>:@
|
||||
@ispage playlist.html:<script type="text/javascript" src="lib-js/prototype.js"></script>:@
|
||||
@ispage playlist.html:<script type="text/javascript" src="lib-js/script.aculo.us/builder.js"></script>:@
|
||||
@ispage playlist.html:<script type="text/javascript" src="util.js"></script>:@
|
||||
@ispage playlist.html:<script type="text/javascript" src="lib-js/rico.js"></script>:@
|
||||
@ispage playlist.html:<script type="text/javascript" src="playlist.js"></script>:@
|
||||
<script type="text/javascript" src="firefly.js"></script>
|
||||
</head>
|
||||
<body @ispage smart.html:onload="init()":@>
|
||||
|
||||
<!-- this is used on the status page to show a grey overlay when the server is stopped -->
|
||||
<div id="grey_screen" style="display: none;"></div>
|
||||
<div id="firefly_head">
|
||||
<a href="http://www.fireflymediaserver.org/" title="link to project home">
|
||||
<img src="ff_logo_sm.gif" width="136" height="36" alt="firefly logo" />
|
||||
</a>
|
||||
<!-- <div class="ministatus">Version @VERSION@</div> -->
|
||||
</div>
|
||||
|
||||
<div id="tagline">
|
||||
The best open-source media server for the <a
|
||||
href="http://www.rokulabs.com">Roku SoundBridge</a> and iTunes
|
||||
</div>
|
||||
<table id="main_table" cellpadding="0" border="0" cellspacing="0">
|
||||
<tr>
|
||||
<td valign="top" style="padding:0;">
|
||||
<div id="navigation">
|
||||
<img id="spinner" src="spinner_stopped.gif" alt="spinner" />
|
||||
<br /><br />
|
||||
<ul>
|
||||
<li><a @ispage index.html:class="naviselected":@ href="index.html">server status</a></li>
|
||||
<li><a @ispage smart.html:class="naviselected":@ href="smart.html">smart playlists</a></li>
|
||||
<li><a @ispage config.html:class="naviselected":@ href="config.html">configuration</a></li>
|
||||
<!-- <li><a @ispage feedback.html:class="naviselected":@ href="feedback.html">feedback</a></li> -->
|
||||
<li><a @ispage status.html:class="naviselected":@ href="about.html">about firefly</a></li>
|
||||
<li><a class="@ispage thanks.html:naviselected:navi@" href="thanks.html">thanks</a></li>
|
||||
</ul>
|
||||
<div class="links">
|
||||
Version @VERSION@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div class="naviheader">Experimental</div>
|
||||
<div class="navibox">
|
||||
<div class="navilink"><a class="@ispage playlist.html:naviselected:navi@" href="playlist.html">playlists</a></div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<!-- <div id="session_count" class="ministatus">@session-count@ Connected Users</div>-->
|
||||
</td>
|
||||
<td valign="top" style="padding-left: 2em; padding-top: 1em;">
|
@ -1,31 +0,0 @@
|
||||
#service, #stat {
|
||||
width: 70ex;
|
||||
}
|
||||
#thread {
|
||||
width: 80ex;
|
||||
}
|
||||
#server_stopped_message {
|
||||
position: absolute;
|
||||
background-color: yellow;
|
||||
padding: 1em;
|
||||
/* border: 1px solid #8CACBB;*/
|
||||
font-size: 120%;
|
||||
margin-bottom: 1em;
|
||||
z-index: 100;
|
||||
|
||||
}
|
||||
#grey_screen {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 1000px;
|
||||
background-color: #000;
|
||||
filter:alpha(opacity=60);
|
||||
opacity: 0.6;
|
||||
z-index: 10;
|
||||
}
|
||||
#button_stop_server, #button_start_scan, #button_start_full_scan {
|
||||
width: 10em;
|
||||
margin-bottom: .2em;
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
@include hdr.html@
|
||||
|
||||
<h2>Server Status</h2>
|
||||
|
||||
<div id="server_stopped_message" style="display: none;">The Firefly server is not running, this page will be inaccessible until you start the server again.</div>
|
||||
<table id="service" cellspacing="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Service</th>
|
||||
<th>Status</th>
|
||||
<th>Control</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Bonjour</td>
|
||||
<td id="rendezvous">Running</td>
|
||||
<td><!-- <a href="config-update.html?action=stopmdns">Stop MDNS Server</a> --></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Firefly Media Server</td>
|
||||
<td id="daap_server">Running</td>
|
||||
<td><input id="button_stop_server" type="button" value="Stop Server" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>File scanner</td>
|
||||
<td id="file_scanner">Idle</td>
|
||||
<td><input id="button_start_scan" type="button" value="Start Scan" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td><input id="button_start_full_scan" type="button" value="Start Full Scan" /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br />
|
||||
<table id="plugin" cellspacing="0">
|
||||
<col style="width: 20ex;" />
|
||||
<col />
|
||||
<thead>
|
||||
<tr><th>Plugin</th><th>Version</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td></td><td></tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br />
|
||||
<table id="stat" cellspacing="0">
|
||||
<col style="width: 20ex;" />
|
||||
<col />
|
||||
<tr>
|
||||
<th>Uptime</th>
|
||||
<td id="uptime"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Songs</th>
|
||||
<td id="songs"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Songs Served</th>
|
||||
<td id="songs_served"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>DB Version</th>
|
||||
<td>2</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br />
|
||||
<table id="thread" cellspacing="0">
|
||||
<col style="width: 20ex;" />
|
||||
<col />
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Client IP</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td></td><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@include ftr.html@
|
@ -1,7 +0,0 @@
|
||||
|
||||
SUBDIRS=script.aculo.us
|
||||
|
||||
jslibdir = ${pkgdatadir}/admin-root/lib-js
|
||||
jslib_DATA = prototype.js rico.js
|
||||
EXTRA_DIST = prototype.js rico.js
|
||||
|
1785
admin-root/lib-js/prototype.js
vendored
@ -1,8 +0,0 @@
|
||||
|
||||
scriptaculousdir = ${pkgdatadir}/admin-root/lib-js/script.aculo.us
|
||||
scriptaculous_DATA = builder.js controls.js dragdrop.js effects.js \
|
||||
scriptaculous.js slider.js unittest.js
|
||||
|
||||
EXTRA_DIST = builder.js controls.js dragdrop.js effects.js \
|
||||
scriptaculous.js slider.js unittest.js
|
||||
|
@ -1,101 +0,0 @@
|
||||
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
//
|
||||
// See scriptaculous.js for full license.
|
||||
|
||||
var Builder = {
|
||||
NODEMAP: {
|
||||
AREA: 'map',
|
||||
CAPTION: 'table',
|
||||
COL: 'table',
|
||||
COLGROUP: 'table',
|
||||
LEGEND: 'fieldset',
|
||||
OPTGROUP: 'select',
|
||||
OPTION: 'select',
|
||||
PARAM: 'object',
|
||||
TBODY: 'table',
|
||||
TD: 'table',
|
||||
TFOOT: 'table',
|
||||
TH: 'table',
|
||||
THEAD: 'table',
|
||||
TR: 'table'
|
||||
},
|
||||
// note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
|
||||
// due to a Firefox bug
|
||||
node: function(elementName) {
|
||||
elementName = elementName.toUpperCase();
|
||||
|
||||
// try innerHTML approach
|
||||
var parentTag = this.NODEMAP[elementName] || 'div';
|
||||
var parentElement = document.createElement(parentTag);
|
||||
try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
|
||||
parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
|
||||
} catch(e) {}
|
||||
var element = parentElement.firstChild || null;
|
||||
|
||||
// see if browser added wrapping tags
|
||||
if(element && (element.tagName != elementName))
|
||||
element = element.getElementsByTagName(elementName)[0];
|
||||
|
||||
// fallback to createElement approach
|
||||
if(!element) element = document.createElement(elementName);
|
||||
|
||||
// abort if nothing could be created
|
||||
if(!element) return;
|
||||
|
||||
// attributes (or text)
|
||||
if(arguments[1])
|
||||
if(this._isStringOrNumber(arguments[1]) ||
|
||||
(arguments[1] instanceof Array)) {
|
||||
this._children(element, arguments[1]);
|
||||
} else {
|
||||
var attrs = this._attributes(arguments[1]);
|
||||
if(attrs.length) {
|
||||
try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
|
||||
parentElement.innerHTML = "<" +elementName + " " +
|
||||
attrs + "></" + elementName + ">";
|
||||
} catch(e) {}
|
||||
element = parentElement.firstChild || null;
|
||||
// workaround firefox 1.0.X bug
|
||||
if(!element) {
|
||||
element = document.createElement(elementName);
|
||||
for(attr in arguments[1])
|
||||
element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
|
||||
}
|
||||
if(element.tagName != elementName)
|
||||
element = parentElement.getElementsByTagName(elementName)[0];
|
||||
}
|
||||
}
|
||||
|
||||
// text, or array of children
|
||||
if(arguments[2])
|
||||
this._children(element, arguments[2]);
|
||||
|
||||
return element;
|
||||
},
|
||||
_text: function(text) {
|
||||
return document.createTextNode(text);
|
||||
},
|
||||
_attributes: function(attributes) {
|
||||
var attrs = [];
|
||||
for(attribute in attributes)
|
||||
attrs.push((attribute=='className' ? 'class' : attribute) +
|
||||
'="' + attributes[attribute].toString().escapeHTML() + '"');
|
||||
return attrs.join(" ");
|
||||
},
|
||||
_children: function(element, children) {
|
||||
if(typeof children=='object') { // array can hold nodes and text
|
||||
children.flatten().each( function(e) {
|
||||
if(typeof e=='object')
|
||||
element.appendChild(e)
|
||||
else
|
||||
if(Builder._isStringOrNumber(e))
|
||||
element.appendChild(Builder._text(e));
|
||||
});
|
||||
} else
|
||||
if(Builder._isStringOrNumber(children))
|
||||
element.appendChild(Builder._text(children));
|
||||
},
|
||||
_isStringOrNumber: function(param) {
|
||||
return(typeof param=='string' || typeof param=='number');
|
||||
}
|
||||
}
|
815
admin-root/lib-js/script.aculo.us/controls.js
vendored
@ -1,815 +0,0 @@
|
||||
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
|
||||
// (c) 2005 Jon Tirsen (http://www.tirsen.com)
|
||||
// Contributors:
|
||||
// Richard Livsey
|
||||
// Rahul Bhargava
|
||||
// Rob Wills
|
||||
//
|
||||
// See scriptaculous.js for full license.
|
||||
|
||||
// Autocompleter.Base handles all the autocompletion functionality
|
||||
// that's independent of the data source for autocompletion. This
|
||||
// includes drawing the autocompletion menu, observing keyboard
|
||||
// and mouse events, and similar.
|
||||
//
|
||||
// Specific autocompleters need to provide, at the very least,
|
||||
// a getUpdatedChoices function that will be invoked every time
|
||||
// the text inside the monitored textbox changes. This method
|
||||
// should get the text for which to provide autocompletion by
|
||||
// invoking this.getToken(), NOT by directly accessing
|
||||
// this.element.value. This is to allow incremental tokenized
|
||||
// autocompletion. Specific auto-completion logic (AJAX, etc)
|
||||
// belongs in getUpdatedChoices.
|
||||
//
|
||||
// Tokenized incremental autocompletion is enabled automatically
|
||||
// when an autocompleter is instantiated with the 'tokens' option
|
||||
// in the options parameter, e.g.:
|
||||
// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' });
|
||||
// will incrementally autocomplete with a comma as the token.
|
||||
// Additionally, ',' in the above example can be replaced with
|
||||
// a token array, e.g. { tokens: [',', '\n'] } which
|
||||
// enables autocompletion on multiple tokens. This is most
|
||||
// useful when one of the tokens is \n (a newline), as it
|
||||
// allows smart autocompletion after linebreaks.
|
||||
|
||||
var Autocompleter = {}
|
||||
Autocompleter.Base = function() {};
|
||||
Autocompleter.Base.prototype = {
|
||||
baseInitialize: function(element, update, options) {
|
||||
this.element = $(element);
|
||||
this.update = $(update);
|
||||
this.hasFocus = false;
|
||||
this.changed = false;
|
||||
this.active = false;
|
||||
this.index = 0;
|
||||
this.entryCount = 0;
|
||||
|
||||
if (this.setOptions)
|
||||
this.setOptions(options);
|
||||
else
|
||||
this.options = options || {};
|
||||
|
||||
this.options.paramName = this.options.paramName || this.element.name;
|
||||
this.options.tokens = this.options.tokens || [];
|
||||
this.options.frequency = this.options.frequency || 0.4;
|
||||
this.options.minChars = this.options.minChars || 1;
|
||||
this.options.onShow = this.options.onShow ||
|
||||
function(element, update){
|
||||
if(!update.style.position || update.style.position=='absolute') {
|
||||
update.style.position = 'absolute';
|
||||
Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight});
|
||||
}
|
||||
Effect.Appear(update,{duration:0.15});
|
||||
};
|
||||
this.options.onHide = this.options.onHide ||
|
||||
function(element, update){ new Effect.Fade(update,{duration:0.15}) };
|
||||
|
||||
if (typeof(this.options.tokens) == 'string')
|
||||
this.options.tokens = new Array(this.options.tokens);
|
||||
|
||||
this.observer = null;
|
||||
|
||||
this.element.setAttribute('autocomplete','off');
|
||||
|
||||
Element.hide(this.update);
|
||||
|
||||
Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
|
||||
Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
|
||||
},
|
||||
|
||||
show: function() {
|
||||
if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update);
|
||||
if(!this.iefix &&
|
||||
(navigator.appVersion.indexOf('MSIE')>0) &&
|
||||
(navigator.userAgent.indexOf('Opera')<0) &&
|
||||
(Element.getStyle(this.update, 'position')=='absolute')) {
|
||||
new Insertion.After(this.update,
|
||||
'<iframe id="' + this.update.id + '_iefix" '+
|
||||
'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' +
|
||||
'src="javascript:false;" frameborder="0" scrolling="no"></iframe>');
|
||||
this.iefix = $(this.update.id+'_iefix');
|
||||
}
|
||||
if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50);
|
||||
},
|
||||
|
||||
fixIEOverlapping: function() {
|
||||
Position.clone(this.update, this.iefix);
|
||||
this.iefix.style.zIndex = 1;
|
||||
this.update.style.zIndex = 2;
|
||||
Element.show(this.iefix);
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this.stopIndicator();
|
||||
if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update);
|
||||
if(this.iefix) Element.hide(this.iefix);
|
||||
},
|
||||
|
||||
startIndicator: function() {
|
||||
if(this.options.indicator) Element.show(this.options.indicator);
|
||||
},
|
||||
|
||||
stopIndicator: function() {
|
||||
if(this.options.indicator) Element.hide(this.options.indicator);
|
||||
},
|
||||
|
||||
onKeyPress: function(event) {
|
||||
if(this.active)
|
||||
switch(event.keyCode) {
|
||||
case Event.KEY_TAB:
|
||||
case Event.KEY_RETURN:
|
||||
this.selectEntry();
|
||||
Event.stop(event);
|
||||
case Event.KEY_ESC:
|
||||
this.hide();
|
||||
this.active = false;
|
||||
Event.stop(event);
|
||||
return;
|
||||
case Event.KEY_LEFT:
|
||||
case Event.KEY_RIGHT:
|
||||
return;
|
||||
case Event.KEY_UP:
|
||||
this.markPrevious();
|
||||
this.render();
|
||||
if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
|
||||
return;
|
||||
case Event.KEY_DOWN:
|
||||
this.markNext();
|
||||
this.render();
|
||||
if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
|
||||
return;
|
||||
}
|
||||
else
|
||||
if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN)
|
||||
return;
|
||||
|
||||
this.changed = true;
|
||||
this.hasFocus = true;
|
||||
|
||||
if(this.observer) clearTimeout(this.observer);
|
||||
this.observer =
|
||||
setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000);
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this.changed = false;
|
||||
this.hasFocus = true;
|
||||
this.getUpdatedChoices();
|
||||
},
|
||||
|
||||
onHover: function(event) {
|
||||
var element = Event.findElement(event, 'LI');
|
||||
if(this.index != element.autocompleteIndex)
|
||||
{
|
||||
this.index = element.autocompleteIndex;
|
||||
this.render();
|
||||
}
|
||||
Event.stop(event);
|
||||
},
|
||||
|
||||
onClick: function(event) {
|
||||
var element = Event.findElement(event, 'LI');
|
||||
this.index = element.autocompleteIndex;
|
||||
this.selectEntry();
|
||||
this.hide();
|
||||
},
|
||||
|
||||
onBlur: function(event) {
|
||||
// needed to make click events working
|
||||
setTimeout(this.hide.bind(this), 250);
|
||||
this.hasFocus = false;
|
||||
this.active = false;
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if(this.entryCount > 0) {
|
||||
for (var i = 0; i < this.entryCount; i++)
|
||||
this.index==i ?
|
||||
Element.addClassName(this.getEntry(i),"selected") :
|
||||
Element.removeClassName(this.getEntry(i),"selected");
|
||||
|
||||
if(this.hasFocus) {
|
||||
this.show();
|
||||
this.active = true;
|
||||
}
|
||||
} else {
|
||||
this.active = false;
|
||||
this.hide();
|
||||
}
|
||||
},
|
||||
|
||||
markPrevious: function() {
|
||||
if(this.index > 0) this.index--
|
||||
else this.index = this.entryCount-1;
|
||||
},
|
||||
|
||||
markNext: function() {
|
||||
if(this.index < this.entryCount-1) this.index++
|
||||
else this.index = 0;
|
||||
},
|
||||
|
||||
getEntry: function(index) {
|
||||
return this.update.firstChild.childNodes[index];
|
||||
},
|
||||
|
||||
getCurrentEntry: function() {
|
||||
return this.getEntry(this.index);
|
||||
},
|
||||
|
||||
selectEntry: function() {
|
||||
this.active = false;
|
||||
this.updateElement(this.getCurrentEntry());
|
||||
},
|
||||
|
||||
updateElement: function(selectedElement) {
|
||||
if (this.options.updateElement) {
|
||||
this.options.updateElement(selectedElement);
|
||||
return;
|
||||
}
|
||||
var value = '';
|
||||
if (this.options.select) {
|
||||
var nodes = document.getElementsByClassName(this.options.select, selectedElement) || [];
|
||||
if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select);
|
||||
} else
|
||||
value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
|
||||
|
||||
var lastTokenPos = this.findLastToken();
|
||||
if (lastTokenPos != -1) {
|
||||
var newValue = this.element.value.substr(0, lastTokenPos + 1);
|
||||
var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
|
||||
if (whitespace)
|
||||
newValue += whitespace[0];
|
||||
this.element.value = newValue + value;
|
||||
} else {
|
||||
this.element.value = value;
|
||||
}
|
||||
this.element.focus();
|
||||
|
||||
if (this.options.afterUpdateElement)
|
||||
this.options.afterUpdateElement(this.element, selectedElement);
|
||||
},
|
||||
|
||||
updateChoices: function(choices) {
|
||||
if(!this.changed && this.hasFocus) {
|
||||
this.update.innerHTML = choices;
|
||||
Element.cleanWhitespace(this.update);
|
||||
Element.cleanWhitespace(this.update.firstChild);
|
||||
|
||||
if(this.update.firstChild && this.update.firstChild.childNodes) {
|
||||
this.entryCount =
|
||||
this.update.firstChild.childNodes.length;
|
||||
for (var i = 0; i < this.entryCount; i++) {
|
||||
var entry = this.getEntry(i);
|
||||
entry.autocompleteIndex = i;
|
||||
this.addObservers(entry);
|
||||
}
|
||||
} else {
|
||||
this.entryCount = 0;
|
||||
}
|
||||
|
||||
this.stopIndicator();
|
||||
|
||||
this.index = 0;
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
|
||||
addObservers: function(element) {
|
||||
Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this));
|
||||
Event.observe(element, "click", this.onClick.bindAsEventListener(this));
|
||||
},
|
||||
|
||||
onObserverEvent: function() {
|
||||
this.changed = false;
|
||||
if(this.getToken().length>=this.options.minChars) {
|
||||
this.startIndicator();
|
||||
this.getUpdatedChoices();
|
||||
} else {
|
||||
this.active = false;
|
||||
this.hide();
|
||||
}
|
||||
},
|
||||
|
||||
getToken: function() {
|
||||
var tokenPos = this.findLastToken();
|
||||
if (tokenPos != -1)
|
||||
var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,'');
|
||||
else
|
||||
var ret = this.element.value;
|
||||
|
||||
return /\n/.test(ret) ? '' : ret;
|
||||
},
|
||||
|
||||
findLastToken: function() {
|
||||
var lastTokenPos = -1;
|
||||
|
||||
for (var i=0; i<this.options.tokens.length; i++) {
|
||||
var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]);
|
||||
if (thisTokenPos > lastTokenPos)
|
||||
lastTokenPos = thisTokenPos;
|
||||
}
|
||||
return lastTokenPos;
|
||||
}
|
||||
}
|
||||
|
||||
Ajax.Autocompleter = Class.create();
|
||||
Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), {
|
||||
initialize: function(element, update, url, options) {
|
||||
this.baseInitialize(element, update, options);
|
||||
this.options.asynchronous = true;
|
||||
this.options.onComplete = this.onComplete.bind(this);
|
||||
this.options.defaultParams = this.options.parameters || null;
|
||||
this.url = url;
|
||||
},
|
||||
|
||||
getUpdatedChoices: function() {
|
||||
entry = encodeURIComponent(this.options.paramName) + '=' +
|
||||
encodeURIComponent(this.getToken());
|
||||
|
||||
this.options.parameters = this.options.callback ?
|
||||
this.options.callback(this.element, entry) : entry;
|
||||
|
||||
if(this.options.defaultParams)
|
||||
this.options.parameters += '&' + this.options.defaultParams;
|
||||
|
||||
new Ajax.Request(this.url, this.options);
|
||||
},
|
||||
|
||||
onComplete: function(request) {
|
||||
this.updateChoices(request.responseText);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// The local array autocompleter. Used when you'd prefer to
|
||||
// inject an array of autocompletion options into the page, rather
|
||||
// than sending out Ajax queries, which can be quite slow sometimes.
|
||||
//
|
||||
// The constructor takes four parameters. The first two are, as usual,
|
||||
// the id of the monitored textbox, and id of the autocompletion menu.
|
||||
// The third is the array you want to autocomplete from, and the fourth
|
||||
// is the options block.
|
||||
//
|
||||
// Extra local autocompletion options:
|
||||
// - choices - How many autocompletion choices to offer
|
||||
//
|
||||
// - partialSearch - If false, the autocompleter will match entered
|
||||
// text only at the beginning of strings in the
|
||||
// autocomplete array. Defaults to true, which will
|
||||
// match text at the beginning of any *word* in the
|
||||
// strings in the autocomplete array. If you want to
|
||||
// search anywhere in the string, additionally set
|
||||
// the option fullSearch to true (default: off).
|
||||
//
|
||||
// - fullSsearch - Search anywhere in autocomplete array strings.
|
||||
//
|
||||
// - partialChars - How many characters to enter before triggering
|
||||
// a partial match (unlike minChars, which defines
|
||||
// how many characters are required to do any match
|
||||
// at all). Defaults to 2.
|
||||
//
|
||||
// - ignoreCase - Whether to ignore case when autocompleting.
|
||||
// Defaults to true.
|
||||
//
|
||||
// It's possible to pass in a custom function as the 'selector'
|
||||
// option, if you prefer to write your own autocompletion logic.
|
||||
// In that case, the other options above will not apply unless
|
||||
// you support them.
|
||||
|
||||
Autocompleter.Local = Class.create();
|
||||
Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), {
|
||||
initialize: function(element, update, array, options) {
|
||||
this.baseInitialize(element, update, options);
|
||||
this.options.array = array;
|
||||
},
|
||||
|
||||
getUpdatedChoices: function() {
|
||||
this.updateChoices(this.options.selector(this));
|
||||
},
|
||||
|
||||
setOptions: function(options) {
|
||||
this.options = Object.extend({
|
||||
choices: 10,
|
||||
partialSearch: true,
|
||||
partialChars: 2,
|
||||
ignoreCase: true,
|
||||
fullSearch: false,
|
||||
selector: function(instance) {
|
||||
var ret = []; // Beginning matches
|
||||
var partial = []; // Inside matches
|
||||
var entry = instance.getToken();
|
||||
var count = 0;
|
||||
|
||||
for (var i = 0; i < instance.options.array.length &&
|
||||
ret.length < instance.options.choices ; i++) {
|
||||
|
||||
var elem = instance.options.array[i];
|
||||
var foundPos = instance.options.ignoreCase ?
|
||||
elem.toLowerCase().indexOf(entry.toLowerCase()) :
|
||||
elem.indexOf(entry);
|
||||
|
||||
while (foundPos != -1) {
|
||||
if (foundPos == 0 && elem.length != entry.length) {
|
||||
ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" +
|
||||
elem.substr(entry.length) + "</li>");
|
||||
break;
|
||||
} else if (entry.length >= instance.options.partialChars &&
|
||||
instance.options.partialSearch && foundPos != -1) {
|
||||
if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) {
|
||||
partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" +
|
||||
elem.substr(foundPos, entry.length) + "</strong>" + elem.substr(
|
||||
foundPos + entry.length) + "</li>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foundPos = instance.options.ignoreCase ?
|
||||
elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) :
|
||||
elem.indexOf(entry, foundPos + 1);
|
||||
|
||||
}
|
||||
}
|
||||
if (partial.length)
|
||||
ret = ret.concat(partial.slice(0, instance.options.choices - ret.length))
|
||||
return "<ul>" + ret.join('') + "</ul>";
|
||||
}
|
||||
}, options || {});
|
||||
}
|
||||
});
|
||||
|
||||
// AJAX in-place editor
|
||||
//
|
||||
// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor
|
||||
|
||||
// Use this if you notice weird scrolling problems on some browsers,
|
||||
// the DOM might be a bit confused when this gets called so do this
|
||||
// waits 1 ms (with setTimeout) until it does the activation
|
||||
Field.scrollFreeActivate = function(field) {
|
||||
setTimeout(function() {
|
||||
Field.activate(field);
|
||||
}, 1);
|
||||
}
|
||||
|
||||
Ajax.InPlaceEditor = Class.create();
|
||||
Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99";
|
||||
Ajax.InPlaceEditor.prototype = {
|
||||
initialize: function(element, url, options) {
|
||||
this.url = url;
|
||||
this.element = $(element);
|
||||
|
||||
this.options = Object.extend({
|
||||
okButton: true,
|
||||
okText: "ok",
|
||||
cancelLink: true,
|
||||
cancelText: "cancel",
|
||||
savingText: "Saving...",
|
||||
clickToEditText: "Click to edit",
|
||||
okText: "ok",
|
||||
rows: 1,
|
||||
onComplete: function(transport, element) {
|
||||
new Effect.Highlight(element, {startcolor: this.options.highlightcolor});
|
||||
},
|
||||
onFailure: function(transport) {
|
||||
alert("Error communicating with the server: " + transport.responseText.stripTags());
|
||||
},
|
||||
callback: function(form) {
|
||||
return Form.serialize(form);
|
||||
},
|
||||
handleLineBreaks: true,
|
||||
loadingText: 'Loading...',
|
||||
savingClassName: 'inplaceeditor-saving',
|
||||
loadingClassName: 'inplaceeditor-loading',
|
||||
formClassName: 'inplaceeditor-form',
|
||||
highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor,
|
||||
highlightendcolor: "#FFFFFF",
|
||||
externalControl: null,
|
||||
submitOnBlur: false,
|
||||
ajaxOptions: {},
|
||||
evalScripts: false
|
||||
}, options || {});
|
||||
|
||||
if(!this.options.formId && this.element.id) {
|
||||
this.options.formId = this.element.id + "-inplaceeditor";
|
||||
if ($(this.options.formId)) {
|
||||
// there's already a form with that name, don't specify an id
|
||||
this.options.formId = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.externalControl) {
|
||||
this.options.externalControl = $(this.options.externalControl);
|
||||
}
|
||||
|
||||
this.originalBackground = Element.getStyle(this.element, 'background-color');
|
||||
if (!this.originalBackground) {
|
||||
this.originalBackground = "transparent";
|
||||
}
|
||||
|
||||
this.element.title = this.options.clickToEditText;
|
||||
|
||||
this.onclickListener = this.enterEditMode.bindAsEventListener(this);
|
||||
this.mouseoverListener = this.enterHover.bindAsEventListener(this);
|
||||
this.mouseoutListener = this.leaveHover.bindAsEventListener(this);
|
||||
Event.observe(this.element, 'click', this.onclickListener);
|
||||
Event.observe(this.element, 'mouseover', this.mouseoverListener);
|
||||
Event.observe(this.element, 'mouseout', this.mouseoutListener);
|
||||
if (this.options.externalControl) {
|
||||
Event.observe(this.options.externalControl, 'click', this.onclickListener);
|
||||
Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener);
|
||||
Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener);
|
||||
}
|
||||
},
|
||||
enterEditMode: function(evt) {
|
||||
if (this.saving) return;
|
||||
if (this.editing) return;
|
||||
this.editing = true;
|
||||
this.onEnterEditMode();
|
||||
if (this.options.externalControl) {
|
||||
Element.hide(this.options.externalControl);
|
||||
}
|
||||
Element.hide(this.element);
|
||||
this.createForm();
|
||||
this.element.parentNode.insertBefore(this.form, this.element);
|
||||
Field.scrollFreeActivate(this.editField);
|
||||
// stop the event to avoid a page refresh in Safari
|
||||
if (evt) {
|
||||
Event.stop(evt);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
createForm: function() {
|
||||
this.form = document.createElement("form");
|
||||
this.form.id = this.options.formId;
|
||||
Element.addClassName(this.form, this.options.formClassName)
|
||||
this.form.onsubmit = this.onSubmit.bind(this);
|
||||
|
||||
this.createEditField();
|
||||
|
||||
if (this.options.textarea) {
|
||||
var br = document.createElement("br");
|
||||
this.form.appendChild(br);
|
||||
}
|
||||
|
||||
if (this.options.okButton) {
|
||||
okButton = document.createElement("input");
|
||||
okButton.type = "submit";
|
||||
okButton.value = this.options.okText;
|
||||
okButton.className = 'editor_ok_button';
|
||||
this.form.appendChild(okButton);
|
||||
}
|
||||
|
||||
if (this.options.cancelLink) {
|
||||
cancelLink = document.createElement("a");
|
||||
cancelLink.href = "#";
|
||||
cancelLink.appendChild(document.createTextNode(this.options.cancelText));
|
||||
cancelLink.onclick = this.onclickCancel.bind(this);
|
||||
cancelLink.className = 'editor_cancel';
|
||||
this.form.appendChild(cancelLink);
|
||||
}
|
||||
},
|
||||
hasHTMLLineBreaks: function(string) {
|
||||
if (!this.options.handleLineBreaks) return false;
|
||||
return string.match(/<br/i) || string.match(/<p>/i);
|
||||
},
|
||||
convertHTMLLineBreaks: function(string) {
|
||||
return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, "");
|
||||
},
|
||||
createEditField: function() {
|
||||
var text;
|
||||
if(this.options.loadTextURL) {
|
||||
text = this.options.loadingText;
|
||||
} else {
|
||||
text = this.getText();
|
||||
}
|
||||
|
||||
var obj = this;
|
||||
|
||||
if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) {
|
||||
this.options.textarea = false;
|
||||
var textField = document.createElement("input");
|
||||
textField.obj = this;
|
||||
textField.type = "text";
|
||||
textField.name = "value";
|
||||
textField.value = text;
|
||||
textField.style.backgroundColor = this.options.highlightcolor;
|
||||
textField.className = 'editor_field';
|
||||
var size = this.options.size || this.options.cols || 0;
|
||||
if (size != 0) textField.size = size;
|
||||
if (this.options.submitOnBlur)
|
||||
textField.onblur = this.onSubmit.bind(this);
|
||||
this.editField = textField;
|
||||
} else {
|
||||
this.options.textarea = true;
|
||||
var textArea = document.createElement("textarea");
|
||||
textArea.obj = this;
|
||||
textArea.name = "value";
|
||||
textArea.value = this.convertHTMLLineBreaks(text);
|
||||
textArea.rows = this.options.rows;
|
||||
textArea.cols = this.options.cols || 40;
|
||||
textArea.className = 'editor_field';
|
||||
if (this.options.submitOnBlur)
|
||||
textArea.onblur = this.onSubmit.bind(this);
|
||||
this.editField = textArea;
|
||||
}
|
||||
|
||||
if(this.options.loadTextURL) {
|
||||
this.loadExternalText();
|
||||
}
|
||||
this.form.appendChild(this.editField);
|
||||
},
|
||||
getText: function() {
|
||||
return this.element.innerHTML;
|
||||
},
|
||||
loadExternalText: function() {
|
||||
Element.addClassName(this.form, this.options.loadingClassName);
|
||||
this.editField.disabled = true;
|
||||
new Ajax.Request(
|
||||
this.options.loadTextURL,
|
||||
Object.extend({
|
||||
asynchronous: true,
|
||||
onComplete: this.onLoadedExternalText.bind(this)
|
||||
}, this.options.ajaxOptions)
|
||||
);
|
||||
},
|
||||
onLoadedExternalText: function(transport) {
|
||||
Element.removeClassName(this.form, this.options.loadingClassName);
|
||||
this.editField.disabled = false;
|
||||
this.editField.value = transport.responseText.stripTags();
|
||||
},
|
||||
onclickCancel: function() {
|
||||
this.onComplete();
|
||||
this.leaveEditMode();
|
||||
return false;
|
||||
},
|
||||
onFailure: function(transport) {
|
||||
this.options.onFailure(transport);
|
||||
if (this.oldInnerHTML) {
|
||||
this.element.innerHTML = this.oldInnerHTML;
|
||||
this.oldInnerHTML = null;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
onSubmit: function() {
|
||||
// onLoading resets these so we need to save them away for the Ajax call
|
||||
var form = this.form;
|
||||
var value = this.editField.value;
|
||||
|
||||
// do this first, sometimes the ajax call returns before we get a chance to switch on Saving...
|
||||
// which means this will actually switch on Saving... *after* we've left edit mode causing Saving...
|
||||
// to be displayed indefinitely
|
||||
this.onLoading();
|
||||
|
||||
if (this.options.evalScripts) {
|
||||
new Ajax.Request(
|
||||
this.url, Object.extend({
|
||||
parameters: this.options.callback(form, value),
|
||||
onComplete: this.onComplete.bind(this),
|
||||
onFailure: this.onFailure.bind(this),
|
||||
asynchronous:true,
|
||||
evalScripts:true
|
||||
}, this.options.ajaxOptions));
|
||||
} else {
|
||||
new Ajax.Updater(
|
||||
{ success: this.element,
|
||||
// don't update on failure (this could be an option)
|
||||
failure: null },
|
||||
this.url, Object.extend({
|
||||
parameters: this.options.callback(form, value),
|
||||
onComplete: this.onComplete.bind(this),
|
||||
onFailure: this.onFailure.bind(this)
|
||||
}, this.options.ajaxOptions));
|
||||
}
|
||||
// stop the event to avoid a page refresh in Safari
|
||||
if (arguments.length > 1) {
|
||||
Event.stop(arguments[0]);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
onLoading: function() {
|
||||
this.saving = true;
|
||||
this.removeForm();
|
||||
this.leaveHover();
|
||||
this.showSaving();
|
||||
},
|
||||
showSaving: function() {
|
||||
this.oldInnerHTML = this.element.innerHTML;
|
||||
this.element.innerHTML = this.options.savingText;
|
||||
Element.addClassName(this.element, this.options.savingClassName);
|
||||
this.element.style.backgroundColor = this.originalBackground;
|
||||
Element.show(this.element);
|
||||
},
|
||||
removeForm: function() {
|
||||
if(this.form) {
|
||||
if (this.form.parentNode) Element.remove(this.form);
|
||||
this.form = null;
|
||||
}
|
||||
},
|
||||
enterHover: function() {
|
||||
if (this.saving) return;
|
||||
this.element.style.backgroundColor = this.options.highlightcolor;
|
||||
if (this.effect) {
|
||||
this.effect.cancel();
|
||||
}
|
||||
Element.addClassName(this.element, this.options.hoverClassName)
|
||||
},
|
||||
leaveHover: function() {
|
||||
if (this.options.backgroundColor) {
|
||||
this.element.style.backgroundColor = this.oldBackground;
|
||||
}
|
||||
Element.removeClassName(this.element, this.options.hoverClassName)
|
||||
if (this.saving) return;
|
||||
this.effect = new Effect.Highlight(this.element, {
|
||||
startcolor: this.options.highlightcolor,
|
||||
endcolor: this.options.highlightendcolor,
|
||||
restorecolor: this.originalBackground
|
||||
});
|
||||
},
|
||||
leaveEditMode: function() {
|
||||
Element.removeClassName(this.element, this.options.savingClassName);
|
||||
this.removeForm();
|
||||
this.leaveHover();
|
||||
this.element.style.backgroundColor = this.originalBackground;
|
||||
Element.show(this.element);
|
||||
if (this.options.externalControl) {
|
||||
Element.show(this.options.externalControl);
|
||||
}
|
||||
this.editing = false;
|
||||
this.saving = false;
|
||||
this.oldInnerHTML = null;
|
||||
this.onLeaveEditMode();
|
||||
},
|
||||
onComplete: function(transport) {
|
||||
this.leaveEditMode();
|
||||
this.options.onComplete.bind(this)(transport, this.element);
|
||||
},
|
||||
onEnterEditMode: function() {},
|
||||
onLeaveEditMode: function() {},
|
||||
dispose: function() {
|
||||
if (this.oldInnerHTML) {
|
||||
this.element.innerHTML = this.oldInnerHTML;
|
||||
}
|
||||
this.leaveEditMode();
|
||||
Event.stopObserving(this.element, 'click', this.onclickListener);
|
||||
Event.stopObserving(this.element, 'mouseover', this.mouseoverListener);
|
||||
Event.stopObserving(this.element, 'mouseout', this.mouseoutListener);
|
||||
if (this.options.externalControl) {
|
||||
Event.stopObserving(this.options.externalControl, 'click', this.onclickListener);
|
||||
Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener);
|
||||
Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ajax.InPlaceCollectionEditor = Class.create();
|
||||
Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype);
|
||||
Object.extend(Ajax.InPlaceCollectionEditor.prototype, {
|
||||
createEditField: function() {
|
||||
if (!this.cached_selectTag) {
|
||||
var selectTag = document.createElement("select");
|
||||
var collection = this.options.collection || [];
|
||||
var optionTag;
|
||||
collection.each(function(e,i) {
|
||||
optionTag = document.createElement("option");
|
||||
optionTag.value = (e instanceof Array) ? e[0] : e;
|
||||
if(this.options.value==optionTag.value) optionTag.selected = true;
|
||||
optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e));
|
||||
selectTag.appendChild(optionTag);
|
||||
}.bind(this));
|
||||
this.cached_selectTag = selectTag;
|
||||
}
|
||||
|
||||
this.editField = this.cached_selectTag;
|
||||
if(this.options.loadTextURL) this.loadExternalText();
|
||||
this.form.appendChild(this.editField);
|
||||
this.options.callback = function(form, value) {
|
||||
return "value=" + encodeURIComponent(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Delayed observer, like Form.Element.Observer,
|
||||
// but waits for delay after last key input
|
||||
// Ideal for live-search fields
|
||||
|
||||
Form.Element.DelayedObserver = Class.create();
|
||||
Form.Element.DelayedObserver.prototype = {
|
||||
initialize: function(element, delay, callback) {
|
||||
this.delay = delay || 0.5;
|
||||
this.element = $(element);
|
||||
this.callback = callback;
|
||||
this.timer = null;
|
||||
this.lastValue = $F(this.element);
|
||||
Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));
|
||||
},
|
||||
delayedListener: function(event) {
|
||||
if(this.lastValue == $F(this.element)) return;
|
||||
if(this.timer) clearTimeout(this.timer);
|
||||
this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000);
|
||||
this.lastValue = $F(this.element);
|
||||
},
|
||||
onTimerEvent: function() {
|
||||
this.timer = null;
|
||||
this.callback(this.element, $F(this.element));
|
||||
}
|
||||
};
|
674
admin-root/lib-js/script.aculo.us/dragdrop.js
vendored
@ -1,674 +0,0 @@
|
||||
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
//
|
||||
// See scriptaculous.js for full license.
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
var Droppables = {
|
||||
drops: [],
|
||||
|
||||
remove: function(element) {
|
||||
this.drops = this.drops.reject(function(d) { return d.element==$(element) });
|
||||
},
|
||||
|
||||
add: function(element) {
|
||||
element = $(element);
|
||||
var options = Object.extend({
|
||||
greedy: true,
|
||||
hoverclass: null
|
||||
}, arguments[1] || {});
|
||||
|
||||
// cache containers
|
||||
if(options.containment) {
|
||||
options._containers = [];
|
||||
var containment = options.containment;
|
||||
if((typeof containment == 'object') &&
|
||||
(containment.constructor == Array)) {
|
||||
containment.each( function(c) { options._containers.push($(c)) });
|
||||
} else {
|
||||
options._containers.push($(containment));
|
||||
}
|
||||
}
|
||||
|
||||
if(options.accept) options.accept = [options.accept].flatten();
|
||||
|
||||
Element.makePositioned(element); // fix IE
|
||||
options.element = element;
|
||||
|
||||
this.drops.push(options);
|
||||
},
|
||||
|
||||
isContained: function(element, drop) {
|
||||
var parentNode = element.parentNode;
|
||||
return drop._containers.detect(function(c) { return parentNode == c });
|
||||
},
|
||||
|
||||
isAffected: function(point, element, drop) {
|
||||
return (
|
||||
(drop.element!=element) &&
|
||||
((!drop._containers) ||
|
||||
this.isContained(element, drop)) &&
|
||||
((!drop.accept) ||
|
||||
(Element.classNames(element).detect(
|
||||
function(v) { return drop.accept.include(v) } ) )) &&
|
||||
Position.within(drop.element, point[0], point[1]) );
|
||||
},
|
||||
|
||||
deactivate: function(drop) {
|
||||
if(drop.hoverclass)
|
||||
Element.removeClassName(drop.element, drop.hoverclass);
|
||||
this.last_active = null;
|
||||
},
|
||||
|
||||
activate: function(drop) {
|
||||
if(drop.hoverclass)
|
||||
Element.addClassName(drop.element, drop.hoverclass);
|
||||
this.last_active = drop;
|
||||
},
|
||||
|
||||
show: function(point, element) {
|
||||
if(!this.drops.length) return;
|
||||
|
||||
if(this.last_active) this.deactivate(this.last_active);
|
||||
this.drops.each( function(drop) {
|
||||
if(Droppables.isAffected(point, element, drop)) {
|
||||
if(drop.onHover)
|
||||
drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
|
||||
if(drop.greedy) {
|
||||
Droppables.activate(drop);
|
||||
throw $break;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
fire: function(event, element) {
|
||||
if(!this.last_active) return;
|
||||
Position.prepare();
|
||||
|
||||
if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
|
||||
if (this.last_active.onDrop)
|
||||
this.last_active.onDrop(element, this.last_active.element, event);
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
if(this.last_active)
|
||||
this.deactivate(this.last_active);
|
||||
}
|
||||
}
|
||||
|
||||
var Draggables = {
|
||||
drags: [],
|
||||
observers: [],
|
||||
|
||||
register: function(draggable) {
|
||||
if(this.drags.length == 0) {
|
||||
this.eventMouseUp = this.endDrag.bindAsEventListener(this);
|
||||
this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
|
||||
this.eventKeypress = this.keyPress.bindAsEventListener(this);
|
||||
|
||||
Event.observe(document, "mouseup", this.eventMouseUp);
|
||||
Event.observe(document, "mousemove", this.eventMouseMove);
|
||||
Event.observe(document, "keypress", this.eventKeypress);
|
||||
}
|
||||
this.drags.push(draggable);
|
||||
},
|
||||
|
||||
unregister: function(draggable) {
|
||||
this.drags = this.drags.reject(function(d) { return d==draggable });
|
||||
if(this.drags.length == 0) {
|
||||
Event.stopObserving(document, "mouseup", this.eventMouseUp);
|
||||
Event.stopObserving(document, "mousemove", this.eventMouseMove);
|
||||
Event.stopObserving(document, "keypress", this.eventKeypress);
|
||||
}
|
||||
},
|
||||
|
||||
activate: function(draggable) {
|
||||
window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
|
||||
this.activeDraggable = draggable;
|
||||
},
|
||||
|
||||
deactivate: function() {
|
||||
this.activeDraggable = null;
|
||||
},
|
||||
|
||||
updateDrag: function(event) {
|
||||
if(!this.activeDraggable) return;
|
||||
var pointer = [Event.pointerX(event), Event.pointerY(event)];
|
||||
// Mozilla-based browsers fire successive mousemove events with
|
||||
// the same coordinates, prevent needless redrawing (moz bug?)
|
||||
if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
|
||||
this._lastPointer = pointer;
|
||||
this.activeDraggable.updateDrag(event, pointer);
|
||||
},
|
||||
|
||||
endDrag: function(event) {
|
||||
if(!this.activeDraggable) return;
|
||||
this._lastPointer = null;
|
||||
this.activeDraggable.endDrag(event);
|
||||
this.activeDraggable = null;
|
||||
},
|
||||
|
||||
keyPress: function(event) {
|
||||
if(this.activeDraggable)
|
||||
this.activeDraggable.keyPress(event);
|
||||
},
|
||||
|
||||
addObserver: function(observer) {
|
||||
this.observers.push(observer);
|
||||
this._cacheObserverCallbacks();
|
||||
},
|
||||
|
||||
removeObserver: function(element) { // element instead of observer fixes mem leaks
|
||||
this.observers = this.observers.reject( function(o) { return o.element==element });
|
||||
this._cacheObserverCallbacks();
|
||||
},
|
||||
|
||||
notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag'
|
||||
if(this[eventName+'Count'] > 0)
|
||||
this.observers.each( function(o) {
|
||||
if(o[eventName]) o[eventName](eventName, draggable, event);
|
||||
});
|
||||
},
|
||||
|
||||
_cacheObserverCallbacks: function() {
|
||||
['onStart','onEnd','onDrag'].each( function(eventName) {
|
||||
Draggables[eventName+'Count'] = Draggables.observers.select(
|
||||
function(o) { return o[eventName]; }
|
||||
).length;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
var Draggable = Class.create();
|
||||
Draggable.prototype = {
|
||||
initialize: function(element) {
|
||||
var options = Object.extend({
|
||||
handle: false,
|
||||
starteffect: function(element) {
|
||||
new Effect.Opacity(element, {duration:0.2, from:1.0, to:0.7});
|
||||
},
|
||||
reverteffect: function(element, top_offset, left_offset) {
|
||||
var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
|
||||
element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur});
|
||||
},
|
||||
endeffect: function(element) {
|
||||
new Effect.Opacity(element, {duration:0.2, from:0.7, to:1.0});
|
||||
},
|
||||
zindex: 1000,
|
||||
revert: false,
|
||||
scroll: false,
|
||||
scrollSensitivity: 20,
|
||||
scrollSpeed: 15,
|
||||
snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] }
|
||||
}, arguments[1] || {});
|
||||
|
||||
this.element = $(element);
|
||||
|
||||
if(options.handle && (typeof options.handle == 'string'))
|
||||
this.handle = Element.childrenWithClassName(this.element, options.handle)[0];
|
||||
if(!this.handle) this.handle = $(options.handle);
|
||||
if(!this.handle) this.handle = this.element;
|
||||
|
||||
if(options.scroll) options.scroll = $(options.scroll);
|
||||
|
||||
Element.makePositioned(this.element); // fix IE
|
||||
|
||||
this.delta = this.currentDelta();
|
||||
this.options = options;
|
||||
this.dragging = false;
|
||||
|
||||
this.eventMouseDown = this.initDrag.bindAsEventListener(this);
|
||||
Event.observe(this.handle, "mousedown", this.eventMouseDown);
|
||||
|
||||
Draggables.register(this);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
|
||||
Draggables.unregister(this);
|
||||
},
|
||||
|
||||
currentDelta: function() {
|
||||
return([
|
||||
parseInt(Element.getStyle(this.element,'left') || '0'),
|
||||
parseInt(Element.getStyle(this.element,'top') || '0')]);
|
||||
},
|
||||
|
||||
initDrag: function(event) {
|
||||
if(Event.isLeftClick(event)) {
|
||||
// abort on form elements, fixes a Firefox issue
|
||||
var src = Event.element(event);
|
||||
if(src.tagName && (
|
||||
src.tagName=='INPUT' ||
|
||||
src.tagName=='SELECT' ||
|
||||
src.tagName=='OPTION' ||
|
||||
src.tagName=='BUTTON' ||
|
||||
src.tagName=='TEXTAREA')) return;
|
||||
|
||||
if(this.element._revert) {
|
||||
this.element._revert.cancel();
|
||||
this.element._revert = null;
|
||||
}
|
||||
|
||||
var pointer = [Event.pointerX(event), Event.pointerY(event)];
|
||||
var pos = Position.cumulativeOffset(this.element);
|
||||
this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
|
||||
|
||||
Draggables.activate(this);
|
||||
Event.stop(event);
|
||||
}
|
||||
},
|
||||
|
||||
startDrag: function(event) {
|
||||
this.dragging = true;
|
||||
|
||||
if(this.options.zindex) {
|
||||
this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
|
||||
this.element.style.zIndex = this.options.zindex;
|
||||
}
|
||||
|
||||
if(this.options.ghosting) {
|
||||
this._clone = this.element.cloneNode(true);
|
||||
Position.absolutize(this.element);
|
||||
this.element.parentNode.insertBefore(this._clone, this.element);
|
||||
}
|
||||
|
||||
if(this.options.scroll) {
|
||||
this.originalScrollLeft = this.options.scroll.scrollLeft;
|
||||
this.originalScrollTop = this.options.scroll.scrollTop;
|
||||
}
|
||||
|
||||
Draggables.notify('onStart', this, event);
|
||||
if(this.options.starteffect) this.options.starteffect(this.element);
|
||||
},
|
||||
|
||||
updateDrag: function(event, pointer) {
|
||||
if(!this.dragging) this.startDrag(event);
|
||||
Position.prepare();
|
||||
Droppables.show(pointer, this.element);
|
||||
Draggables.notify('onDrag', this, event);
|
||||
this.draw(pointer);
|
||||
if(this.options.change) this.options.change(this);
|
||||
|
||||
if(this.options.scroll) {
|
||||
//if(this.scrollInterval) this.scroll();
|
||||
this.stopScrolling();
|
||||
var p = Position.page(this.options.scroll);
|
||||
p[0] += this.options.scroll.scrollLeft;
|
||||
p[1] += this.options.scroll.scrollTop;
|
||||
p.push(p[0]+this.options.scroll.offsetWidth);
|
||||
p.push(p[1]+this.options.scroll.offsetHeight);
|
||||
var speed = [0,0];
|
||||
if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
|
||||
if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
|
||||
if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
|
||||
if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
|
||||
this.startScrolling(speed);
|
||||
}
|
||||
|
||||
// fix AppleWebKit rendering
|
||||
if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
|
||||
|
||||
Event.stop(event);
|
||||
},
|
||||
|
||||
finishDrag: function(event, success) {
|
||||
this.dragging = false;
|
||||
|
||||
if(this.options.ghosting) {
|
||||
Position.relativize(this.element);
|
||||
Element.remove(this._clone);
|
||||
this._clone = null;
|
||||
}
|
||||
|
||||
if(success) Droppables.fire(event, this.element);
|
||||
Draggables.notify('onEnd', this, event);
|
||||
|
||||
var revert = this.options.revert;
|
||||
if(revert && typeof revert == 'function') revert = revert(this.element);
|
||||
|
||||
var d = this.currentDelta();
|
||||
if(revert && this.options.reverteffect) {
|
||||
this.options.reverteffect(this.element,
|
||||
d[1]-this.delta[1], d[0]-this.delta[0]);
|
||||
} else {
|
||||
this.delta = d;
|
||||
}
|
||||
|
||||
if(this.options.zindex)
|
||||
this.element.style.zIndex = this.originalZ;
|
||||
|
||||
if(this.options.endeffect)
|
||||
this.options.endeffect(this.element);
|
||||
|
||||
Draggables.deactivate(this);
|
||||
Droppables.reset();
|
||||
},
|
||||
|
||||
keyPress: function(event) {
|
||||
if(event.keyCode!=Event.KEY_ESC) return;
|
||||
this.finishDrag(event, false);
|
||||
Event.stop(event);
|
||||
},
|
||||
|
||||
endDrag: function(event) {
|
||||
if(!this.dragging) return;
|
||||
this.stopScrolling();
|
||||
this.finishDrag(event, true);
|
||||
Event.stop(event);
|
||||
},
|
||||
|
||||
draw: function(point) {
|
||||
var pos = Position.cumulativeOffset(this.element);
|
||||
var d = this.currentDelta();
|
||||
pos[0] -= d[0]; pos[1] -= d[1];
|
||||
|
||||
if(this.options.scroll) {
|
||||
pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
|
||||
pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
|
||||
}
|
||||
|
||||
var p = [0,1].map(function(i){
|
||||
return (point[i]-pos[i]-this.offset[i])
|
||||
}.bind(this));
|
||||
|
||||
if(this.options.snap) {
|
||||
if(typeof this.options.snap == 'function') {
|
||||
p = this.options.snap(p[0],p[1]);
|
||||
} else {
|
||||
if(this.options.snap instanceof Array) {
|
||||
p = p.map( function(v, i) {
|
||||
return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
|
||||
} else {
|
||||
p = p.map( function(v) {
|
||||
return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
|
||||
}
|
||||
}}
|
||||
|
||||
var style = this.element.style;
|
||||
if((!this.options.constraint) || (this.options.constraint=='horizontal'))
|
||||
style.left = p[0] + "px";
|
||||
if((!this.options.constraint) || (this.options.constraint=='vertical'))
|
||||
style.top = p[1] + "px";
|
||||
if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
|
||||
},
|
||||
|
||||
stopScrolling: function() {
|
||||
if(this.scrollInterval) {
|
||||
clearInterval(this.scrollInterval);
|
||||
this.scrollInterval = null;
|
||||
}
|
||||
},
|
||||
|
||||
startScrolling: function(speed) {
|
||||
this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
|
||||
this.lastScrolled = new Date();
|
||||
this.scrollInterval = setInterval(this.scroll.bind(this), 10);
|
||||
},
|
||||
|
||||
scroll: function() {
|
||||
var current = new Date();
|
||||
var delta = current - this.lastScrolled;
|
||||
this.lastScrolled = current;
|
||||
this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
|
||||
this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
|
||||
|
||||
Position.prepare();
|
||||
Droppables.show(Draggables._lastPointer, this.element);
|
||||
Draggables.notify('onDrag', this);
|
||||
this.draw(Draggables._lastPointer);
|
||||
|
||||
if(this.options.change) this.options.change(this);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
var SortableObserver = Class.create();
|
||||
SortableObserver.prototype = {
|
||||
initialize: function(element, observer) {
|
||||
this.element = $(element);
|
||||
this.observer = observer;
|
||||
this.lastValue = Sortable.serialize(this.element);
|
||||
},
|
||||
|
||||
onStart: function() {
|
||||
this.lastValue = Sortable.serialize(this.element);
|
||||
},
|
||||
|
||||
onEnd: function() {
|
||||
Sortable.unmark();
|
||||
if(this.lastValue != Sortable.serialize(this.element))
|
||||
this.observer(this.element)
|
||||
}
|
||||
}
|
||||
|
||||
var Sortable = {
|
||||
sortables: new Array(),
|
||||
|
||||
options: function(element){
|
||||
element = $(element);
|
||||
return this.sortables.detect(function(s) { return s.element == element });
|
||||
},
|
||||
|
||||
destroy: function(element){
|
||||
element = $(element);
|
||||
this.sortables.findAll(function(s) { return s.element == element }).each(function(s){
|
||||
Draggables.removeObserver(s.element);
|
||||
s.droppables.each(function(d){ Droppables.remove(d) });
|
||||
s.draggables.invoke('destroy');
|
||||
});
|
||||
this.sortables = this.sortables.reject(function(s) { return s.element == element });
|
||||
},
|
||||
|
||||
create: function(element) {
|
||||
element = $(element);
|
||||
var options = Object.extend({
|
||||
element: element,
|
||||
tag: 'li', // assumes li children, override with tag: 'tagname'
|
||||
dropOnEmpty: false,
|
||||
tree: false, // fixme: unimplemented
|
||||
overlap: 'vertical', // one of 'vertical', 'horizontal'
|
||||
constraint: 'vertical', // one of 'vertical', 'horizontal', false
|
||||
containment: element, // also takes array of elements (or id's); or false
|
||||
handle: false, // or a CSS class
|
||||
only: false,
|
||||
hoverclass: null,
|
||||
ghosting: false,
|
||||
scroll: false,
|
||||
format: /^[^_]*_(.*)$/,
|
||||
onChange: Prototype.emptyFunction,
|
||||
onUpdate: Prototype.emptyFunction
|
||||
}, arguments[1] || {});
|
||||
|
||||
// clear any old sortable with same element
|
||||
this.destroy(element);
|
||||
|
||||
// build options for the draggables
|
||||
var options_for_draggable = {
|
||||
revert: true,
|
||||
scroll: options.scroll,
|
||||
ghosting: options.ghosting,
|
||||
constraint: options.constraint,
|
||||
handle: options.handle };
|
||||
|
||||
if(options.starteffect)
|
||||
options_for_draggable.starteffect = options.starteffect;
|
||||
|
||||
if(options.reverteffect)
|
||||
options_for_draggable.reverteffect = options.reverteffect;
|
||||
else
|
||||
if(options.ghosting) options_for_draggable.reverteffect = function(element) {
|
||||
element.style.top = 0;
|
||||
element.style.left = 0;
|
||||
};
|
||||
|
||||
if(options.endeffect)
|
||||
options_for_draggable.endeffect = options.endeffect;
|
||||
|
||||
if(options.zindex)
|
||||
options_for_draggable.zindex = options.zindex;
|
||||
|
||||
// build options for the droppables
|
||||
var options_for_droppable = {
|
||||
overlap: options.overlap,
|
||||
containment: options.containment,
|
||||
hoverclass: options.hoverclass,
|
||||
onHover: Sortable.onHover,
|
||||
greedy: !options.dropOnEmpty
|
||||
}
|
||||
|
||||
// fix for gecko engine
|
||||
Element.cleanWhitespace(element);
|
||||
|
||||
options.draggables = [];
|
||||
options.droppables = [];
|
||||
|
||||
// make it so
|
||||
|
||||
// drop on empty handling
|
||||
if(options.dropOnEmpty) {
|
||||
Droppables.add(element,
|
||||
{containment: options.containment, onHover: Sortable.onEmptyHover, greedy: false});
|
||||
options.droppables.push(element);
|
||||
}
|
||||
|
||||
(this.findElements(element, options) || []).each( function(e) {
|
||||
// handles are per-draggable
|
||||
var handle = options.handle ?
|
||||
Element.childrenWithClassName(e, options.handle)[0] : e;
|
||||
options.draggables.push(
|
||||
new Draggable(e, Object.extend(options_for_draggable, { handle: handle })));
|
||||
Droppables.add(e, options_for_droppable);
|
||||
options.droppables.push(e);
|
||||
});
|
||||
|
||||
// keep reference
|
||||
this.sortables.push(options);
|
||||
|
||||
// for onupdate
|
||||
Draggables.addObserver(new SortableObserver(element, options.onUpdate));
|
||||
|
||||
},
|
||||
|
||||
// return all suitable-for-sortable elements in a guaranteed order
|
||||
findElements: function(element, options) {
|
||||
if(!element.hasChildNodes()) return null;
|
||||
var elements = [];
|
||||
$A(element.childNodes).each( function(e) {
|
||||
if(e.tagName && e.tagName.toUpperCase()==options.tag.toUpperCase() &&
|
||||
(!options.only || (Element.hasClassName(e, options.only))))
|
||||
elements.push(e);
|
||||
if(options.tree) {
|
||||
var grandchildren = this.findElements(e, options);
|
||||
if(grandchildren) elements.push(grandchildren);
|
||||
}
|
||||
});
|
||||
|
||||
return (elements.length>0 ? elements.flatten() : null);
|
||||
},
|
||||
|
||||
onHover: function(element, dropon, overlap) {
|
||||
if(overlap>0.5) {
|
||||
Sortable.mark(dropon, 'before');
|
||||
if(dropon.previousSibling != element) {
|
||||
var oldParentNode = element.parentNode;
|
||||
element.style.visibility = "hidden"; // fix gecko rendering
|
||||
dropon.parentNode.insertBefore(element, dropon);
|
||||
if(dropon.parentNode!=oldParentNode)
|
||||
Sortable.options(oldParentNode).onChange(element);
|
||||
Sortable.options(dropon.parentNode).onChange(element);
|
||||
}
|
||||
} else {
|
||||
Sortable.mark(dropon, 'after');
|
||||
var nextElement = dropon.nextSibling || null;
|
||||
if(nextElement != element) {
|
||||
var oldParentNode = element.parentNode;
|
||||
element.style.visibility = "hidden"; // fix gecko rendering
|
||||
dropon.parentNode.insertBefore(element, nextElement);
|
||||
if(dropon.parentNode!=oldParentNode)
|
||||
Sortable.options(oldParentNode).onChange(element);
|
||||
Sortable.options(dropon.parentNode).onChange(element);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onEmptyHover: function(element, dropon) {
|
||||
if(element.parentNode!=dropon) {
|
||||
var oldParentNode = element.parentNode;
|
||||
dropon.appendChild(element);
|
||||
Sortable.options(oldParentNode).onChange(element);
|
||||
Sortable.options(dropon).onChange(element);
|
||||
}
|
||||
},
|
||||
|
||||
unmark: function() {
|
||||
if(Sortable._marker) Element.hide(Sortable._marker);
|
||||
},
|
||||
|
||||
mark: function(dropon, position) {
|
||||
// mark on ghosting only
|
||||
var sortable = Sortable.options(dropon.parentNode);
|
||||
if(sortable && !sortable.ghosting) return;
|
||||
|
||||
if(!Sortable._marker) {
|
||||
Sortable._marker = $('dropmarker') || document.createElement('DIV');
|
||||
Element.hide(Sortable._marker);
|
||||
Element.addClassName(Sortable._marker, 'dropmarker');
|
||||
Sortable._marker.style.position = 'absolute';
|
||||
document.getElementsByTagName("body").item(0).appendChild(Sortable._marker);
|
||||
}
|
||||
var offsets = Position.cumulativeOffset(dropon);
|
||||
Sortable._marker.style.left = offsets[0] + 'px';
|
||||
Sortable._marker.style.top = offsets[1] + 'px';
|
||||
|
||||
if(position=='after')
|
||||
if(sortable.overlap == 'horizontal')
|
||||
Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px';
|
||||
else
|
||||
Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px';
|
||||
|
||||
Element.show(Sortable._marker);
|
||||
},
|
||||
|
||||
sequence: function(element) {
|
||||
element = $(element);
|
||||
var options = Object.extend(this.options(element), arguments[1] || {});
|
||||
|
||||
return $(this.findElements(element, options) || []).map( function(item) {
|
||||
return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
|
||||
});
|
||||
},
|
||||
|
||||
setSequence: function(element, new_sequence) {
|
||||
element = $(element);
|
||||
var options = Object.extend(this.options(element), arguments[2] || {});
|
||||
|
||||
var nodeMap = {};
|
||||
this.findElements(element, options).each( function(n) {
|
||||
if (n.id.match(options.format))
|
||||
nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode];
|
||||
n.parentNode.removeChild(n);
|
||||
});
|
||||
|
||||
new_sequence.each(function(ident) {
|
||||
var n = nodeMap[ident];
|
||||
if (n) {
|
||||
n[1].appendChild(n[0]);
|
||||
delete nodeMap[ident];
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
serialize: function(element) {
|
||||
element = $(element);
|
||||
var name = encodeURIComponent(
|
||||
(arguments[1] && arguments[1].name) ? arguments[1].name : element.id);
|
||||
return Sortable.sequence(element, arguments[1]).map( function(item) {
|
||||
return name + "[]=" + encodeURIComponent(item);
|
||||
}).join('&');
|
||||
}
|
||||
}
|
910
admin-root/lib-js/script.aculo.us/effects.js
vendored
@ -1,910 +0,0 @@
|
||||
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
// Contributors:
|
||||
// Justin Palmer (http://encytemedia.com/)
|
||||
// Mark Pilgrim (http://diveintomark.org/)
|
||||
// Martin Bialasinki
|
||||
//
|
||||
// See scriptaculous.js for full license.
|
||||
|
||||
/* ------------- element ext -------------- */
|
||||
|
||||
// converts rgb() and #xxx to #xxxxxx format,
|
||||
// returns self (or first argument) if not convertable
|
||||
String.prototype.parseColor = function() {
|
||||
var color = '#';
|
||||
if(this.slice(0,4) == 'rgb(') {
|
||||
var cols = this.slice(4,this.length-1).split(',');
|
||||
var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);
|
||||
} else {
|
||||
if(this.slice(0,1) == '#') {
|
||||
if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();
|
||||
if(this.length==7) color = this.toLowerCase();
|
||||
}
|
||||
}
|
||||
return(color.length==7 ? color : (arguments[0] || this));
|
||||
}
|
||||
|
||||
Element.collectTextNodes = function(element) {
|
||||
return $A($(element).childNodes).collect( function(node) {
|
||||
return (node.nodeType==3 ? node.nodeValue :
|
||||
(node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
|
||||
}).flatten().join('');
|
||||
}
|
||||
|
||||
Element.collectTextNodesIgnoreClass = function(element, className) {
|
||||
return $A($(element).childNodes).collect( function(node) {
|
||||
return (node.nodeType==3 ? node.nodeValue :
|
||||
((node.hasChildNodes() && !Element.hasClassName(node,className)) ?
|
||||
Element.collectTextNodesIgnoreClass(node, className) : ''));
|
||||
}).flatten().join('');
|
||||
}
|
||||
|
||||
Element.setStyle = function(element, style) {
|
||||
element = $(element);
|
||||
for(k in style) element.style[k.camelize()] = style[k];
|
||||
}
|
||||
|
||||
Element.setContentZoom = function(element, percent) {
|
||||
Element.setStyle(element, {fontSize: (percent/100) + 'em'});
|
||||
if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
|
||||
}
|
||||
|
||||
Element.getOpacity = function(element){
|
||||
var opacity;
|
||||
if (opacity = Element.getStyle(element, 'opacity'))
|
||||
return parseFloat(opacity);
|
||||
if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/))
|
||||
if(opacity[1]) return parseFloat(opacity[1]) / 100;
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
Element.setOpacity = function(element, value){
|
||||
element= $(element);
|
||||
if (value == 1){
|
||||
Element.setStyle(element, { opacity:
|
||||
(/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ?
|
||||
0.999999 : null });
|
||||
if(/MSIE/.test(navigator.userAgent))
|
||||
Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')});
|
||||
} else {
|
||||
if(value < 0.00001) value = 0;
|
||||
Element.setStyle(element, {opacity: value});
|
||||
if(/MSIE/.test(navigator.userAgent))
|
||||
Element.setStyle(element,
|
||||
{ filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') +
|
||||
'alpha(opacity='+value*100+')' });
|
||||
}
|
||||
}
|
||||
|
||||
Element.getInlineOpacity = function(element){
|
||||
return $(element).style.opacity || '';
|
||||
}
|
||||
|
||||
Element.childrenWithClassName = function(element, className) {
|
||||
return $A($(element).getElementsByTagName('*')).select(
|
||||
function(c) { return Element.hasClassName(c, className) });
|
||||
}
|
||||
|
||||
Array.prototype.call = function() {
|
||||
var args = arguments;
|
||||
this.each(function(f){ f.apply(this, args) });
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
var Effect = {
|
||||
tagifyText: function(element) {
|
||||
var tagifyStyle = 'position:relative';
|
||||
if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1';
|
||||
element = $(element);
|
||||
$A(element.childNodes).each( function(child) {
|
||||
if(child.nodeType==3) {
|
||||
child.nodeValue.toArray().each( function(character) {
|
||||
element.insertBefore(
|
||||
Builder.node('span',{style: tagifyStyle},
|
||||
character == ' ' ? String.fromCharCode(160) : character),
|
||||
child);
|
||||
});
|
||||
Element.remove(child);
|
||||
}
|
||||
});
|
||||
},
|
||||
multiple: function(element, effect) {
|
||||
var elements;
|
||||
if(((typeof element == 'object') ||
|
||||
(typeof element == 'function')) &&
|
||||
(element.length))
|
||||
elements = element;
|
||||
else
|
||||
elements = $(element).childNodes;
|
||||
|
||||
var options = Object.extend({
|
||||
speed: 0.1,
|
||||
delay: 0.0
|
||||
}, arguments[2] || {});
|
||||
var masterDelay = options.delay;
|
||||
|
||||
$A(elements).each( function(element, index) {
|
||||
new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
|
||||
});
|
||||
},
|
||||
PAIRS: {
|
||||
'slide': ['SlideDown','SlideUp'],
|
||||
'blind': ['BlindDown','BlindUp'],
|
||||
'appear': ['Appear','Fade']
|
||||
},
|
||||
toggle: function(element, effect) {
|
||||
element = $(element);
|
||||
effect = (effect || 'appear').toLowerCase();
|
||||
var options = Object.extend({
|
||||
queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
|
||||
}, arguments[2] || {});
|
||||
Effect[Element.visible(element) ?
|
||||
Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
|
||||
}
|
||||
};
|
||||
|
||||
var Effect2 = Effect; // deprecated
|
||||
|
||||
/* ------------- transitions ------------- */
|
||||
|
||||
Effect.Transitions = {}
|
||||
|
||||
Effect.Transitions.linear = function(pos) {
|
||||
return pos;
|
||||
}
|
||||
Effect.Transitions.sinoidal = function(pos) {
|
||||
return (-Math.cos(pos*Math.PI)/2) + 0.5;
|
||||
}
|
||||
Effect.Transitions.reverse = function(pos) {
|
||||
return 1-pos;
|
||||
}
|
||||
Effect.Transitions.flicker = function(pos) {
|
||||
return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
|
||||
}
|
||||
Effect.Transitions.wobble = function(pos) {
|
||||
return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
|
||||
}
|
||||
Effect.Transitions.pulse = function(pos) {
|
||||
return (Math.floor(pos*10) % 2 == 0 ?
|
||||
(pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10)));
|
||||
}
|
||||
Effect.Transitions.none = function(pos) {
|
||||
return 0;
|
||||
}
|
||||
Effect.Transitions.full = function(pos) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------- core effects ------------- */
|
||||
|
||||
Effect.ScopedQueue = Class.create();
|
||||
Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
|
||||
initialize: function() {
|
||||
this.effects = [];
|
||||
this.interval = null;
|
||||
},
|
||||
_each: function(iterator) {
|
||||
this.effects._each(iterator);
|
||||
},
|
||||
add: function(effect) {
|
||||
var timestamp = new Date().getTime();
|
||||
|
||||
var position = (typeof effect.options.queue == 'string') ?
|
||||
effect.options.queue : effect.options.queue.position;
|
||||
|
||||
switch(position) {
|
||||
case 'front':
|
||||
// move unstarted effects after this effect
|
||||
this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
|
||||
e.startOn += effect.finishOn;
|
||||
e.finishOn += effect.finishOn;
|
||||
});
|
||||
break;
|
||||
case 'end':
|
||||
// start effect after last queued effect has finished
|
||||
timestamp = this.effects.pluck('finishOn').max() || timestamp;
|
||||
break;
|
||||
}
|
||||
|
||||
effect.startOn += timestamp;
|
||||
effect.finishOn += timestamp;
|
||||
|
||||
if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
|
||||
this.effects.push(effect);
|
||||
|
||||
if(!this.interval)
|
||||
this.interval = setInterval(this.loop.bind(this), 40);
|
||||
},
|
||||
remove: function(effect) {
|
||||
this.effects = this.effects.reject(function(e) { return e==effect });
|
||||
if(this.effects.length == 0) {
|
||||
clearInterval(this.interval);
|
||||
this.interval = null;
|
||||
}
|
||||
},
|
||||
loop: function() {
|
||||
var timePos = new Date().getTime();
|
||||
this.effects.invoke('loop', timePos);
|
||||
}
|
||||
});
|
||||
|
||||
Effect.Queues = {
|
||||
instances: $H(),
|
||||
get: function(queueName) {
|
||||
if(typeof queueName != 'string') return queueName;
|
||||
|
||||
if(!this.instances[queueName])
|
||||
this.instances[queueName] = new Effect.ScopedQueue();
|
||||
|
||||
return this.instances[queueName];
|
||||
}
|
||||
}
|
||||
Effect.Queue = Effect.Queues.get('global');
|
||||
|
||||
Effect.DefaultOptions = {
|
||||
transition: Effect.Transitions.sinoidal,
|
||||
duration: 1.0, // seconds
|
||||
fps: 25.0, // max. 25fps due to Effect.Queue implementation
|
||||
sync: false, // true for combining
|
||||
from: 0.0,
|
||||
to: 1.0,
|
||||
delay: 0.0,
|
||||
queue: 'parallel'
|
||||
}
|
||||
|
||||
Effect.Base = function() {};
|
||||
Effect.Base.prototype = {
|
||||
position: null,
|
||||
start: function(options) {
|
||||
this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
|
||||
this.currentFrame = 0;
|
||||
this.state = 'idle';
|
||||
this.startOn = this.options.delay*1000;
|
||||
this.finishOn = this.startOn + (this.options.duration*1000);
|
||||
this.event('beforeStart');
|
||||
if(!this.options.sync)
|
||||
Effect.Queues.get(typeof this.options.queue == 'string' ?
|
||||
'global' : this.options.queue.scope).add(this);
|
||||
},
|
||||
loop: function(timePos) {
|
||||
if(timePos >= this.startOn) {
|
||||
if(timePos >= this.finishOn) {
|
||||
this.render(1.0);
|
||||
this.cancel();
|
||||
this.event('beforeFinish');
|
||||
if(this.finish) this.finish();
|
||||
this.event('afterFinish');
|
||||
return;
|
||||
}
|
||||
var pos = (timePos - this.startOn) / (this.finishOn - this.startOn);
|
||||
var frame = Math.round(pos * this.options.fps * this.options.duration);
|
||||
if(frame > this.currentFrame) {
|
||||
this.render(pos);
|
||||
this.currentFrame = frame;
|
||||
}
|
||||
}
|
||||
},
|
||||
render: function(pos) {
|
||||
if(this.state == 'idle') {
|
||||
this.state = 'running';
|
||||
this.event('beforeSetup');
|
||||
if(this.setup) this.setup();
|
||||
this.event('afterSetup');
|
||||
}
|
||||
if(this.state == 'running') {
|
||||
if(this.options.transition) pos = this.options.transition(pos);
|
||||
pos *= (this.options.to-this.options.from);
|
||||
pos += this.options.from;
|
||||
this.position = pos;
|
||||
this.event('beforeUpdate');
|
||||
if(this.update) this.update(pos);
|
||||
this.event('afterUpdate');
|
||||
}
|
||||
},
|
||||
cancel: function() {
|
||||
if(!this.options.sync)
|
||||
Effect.Queues.get(typeof this.options.queue == 'string' ?
|
||||
'global' : this.options.queue.scope).remove(this);
|
||||
this.state = 'finished';
|
||||
},
|
||||
event: function(eventName) {
|
||||
if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
|
||||
if(this.options[eventName]) this.options[eventName](this);
|
||||
},
|
||||
inspect: function() {
|
||||
return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>';
|
||||
}
|
||||
}
|
||||
|
||||
Effect.Parallel = Class.create();
|
||||
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
|
||||
initialize: function(effects) {
|
||||
this.effects = effects || [];
|
||||
this.start(arguments[1]);
|
||||
},
|
||||
update: function(position) {
|
||||
this.effects.invoke('render', position);
|
||||
},
|
||||
finish: function(position) {
|
||||
this.effects.each( function(effect) {
|
||||
effect.render(1.0);
|
||||
effect.cancel();
|
||||
effect.event('beforeFinish');
|
||||
if(effect.finish) effect.finish(position);
|
||||
effect.event('afterFinish');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Effect.Opacity = Class.create();
|
||||
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
|
||||
initialize: function(element) {
|
||||
this.element = $(element);
|
||||
// make this work on IE on elements without 'layout'
|
||||
if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout))
|
||||
Element.setStyle(this.element, {zoom: 1});
|
||||
var options = Object.extend({
|
||||
from: Element.getOpacity(this.element) || 0.0,
|
||||
to: 1.0
|
||||
}, arguments[1] || {});
|
||||
this.start(options);
|
||||
},
|
||||
update: function(position) {
|
||||
Element.setOpacity(this.element, position);
|
||||
}
|
||||
});
|
||||
|
||||
Effect.Move = Class.create();
|
||||
Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
|
||||
initialize: function(element) {
|
||||
this.element = $(element);
|
||||
var options = Object.extend({
|
||||
x: 0,
|
||||
y: 0,
|
||||
mode: 'relative'
|
||||
}, arguments[1] || {});
|
||||
this.start(options);
|
||||
},
|
||||
setup: function() {
|
||||
// Bug in Opera: Opera returns the "real" position of a static element or
|
||||
// relative element that does not have top/left explicitly set.
|
||||
// ==> Always set top and left for position relative elements in your stylesheets
|
||||
// (to 0 if you do not need them)
|
||||
Element.makePositioned(this.element);
|
||||
this.originalLeft = parseFloat(Element.getStyle(this.element,'left') || '0');
|
||||
this.originalTop = parseFloat(Element.getStyle(this.element,'top') || '0');
|
||||
if(this.options.mode == 'absolute') {
|
||||
// absolute movement, so we need to calc deltaX and deltaY
|
||||
this.options.x = this.options.x - this.originalLeft;
|
||||
this.options.y = this.options.y - this.originalTop;
|
||||
}
|
||||
},
|
||||
update: function(position) {
|
||||
Element.setStyle(this.element, {
|
||||
left: this.options.x * position + this.originalLeft + 'px',
|
||||
top: this.options.y * position + this.originalTop + 'px'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// for backwards compatibility
|
||||
Effect.MoveBy = function(element, toTop, toLeft) {
|
||||
return new Effect.Move(element,
|
||||
Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
|
||||
};
|
||||
|
||||
Effect.Scale = Class.create();
|
||||
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
|
||||
initialize: function(element, percent) {
|
||||
this.element = $(element)
|
||||
var options = Object.extend({
|
||||
scaleX: true,
|
||||
scaleY: true,
|
||||
scaleContent: true,
|
||||
scaleFromCenter: false,
|
||||
scaleMode: 'box', // 'box' or 'contents' or {} with provided values
|
||||
scaleFrom: 100.0,
|
||||
scaleTo: percent
|
||||
}, arguments[2] || {});
|
||||
this.start(options);
|
||||
},
|
||||
setup: function() {
|
||||
this.restoreAfterFinish = this.options.restoreAfterFinish || false;
|
||||
this.elementPositioning = Element.getStyle(this.element,'position');
|
||||
|
||||
this.originalStyle = {};
|
||||
['top','left','width','height','fontSize'].each( function(k) {
|
||||
this.originalStyle[k] = this.element.style[k];
|
||||
}.bind(this));
|
||||
|
||||
this.originalTop = this.element.offsetTop;
|
||||
this.originalLeft = this.element.offsetLeft;
|
||||
|
||||
var fontSize = Element.getStyle(this.element,'font-size') || '100%';
|
||||
['em','px','%'].each( function(fontSizeType) {
|
||||
if(fontSize.indexOf(fontSizeType)>0) {
|
||||
this.fontSize = parseFloat(fontSize);
|
||||
this.fontSizeType = fontSizeType;
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
|
||||
|
||||
this.dims = null;
|
||||
if(this.options.scaleMode=='box')
|
||||
this.dims = [this.element.offsetHeight, this.element.offsetWidth];
|
||||
if(/^content/.test(this.options.scaleMode))
|
||||
this.dims = [this.element.scrollHeight, this.element.scrollWidth];
|
||||
if(!this.dims)
|
||||
this.dims = [this.options.scaleMode.originalHeight,
|
||||
this.options.scaleMode.originalWidth];
|
||||
},
|
||||
update: function(position) {
|
||||
var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
|
||||
if(this.options.scaleContent && this.fontSize)
|
||||
Element.setStyle(this.element, {fontSize: this.fontSize * currentScale + this.fontSizeType });
|
||||
this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
|
||||
},
|
||||
finish: function(position) {
|
||||
if (this.restoreAfterFinish) Element.setStyle(this.element, this.originalStyle);
|
||||
},
|
||||
setDimensions: function(height, width) {
|
||||
var d = {};
|
||||
if(this.options.scaleX) d.width = width + 'px';
|
||||
if(this.options.scaleY) d.height = height + 'px';
|
||||
if(this.options.scaleFromCenter) {
|
||||
var topd = (height - this.dims[0])/2;
|
||||
var leftd = (width - this.dims[1])/2;
|
||||
if(this.elementPositioning == 'absolute') {
|
||||
if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
|
||||
if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
|
||||
} else {
|
||||
if(this.options.scaleY) d.top = -topd + 'px';
|
||||
if(this.options.scaleX) d.left = -leftd + 'px';
|
||||
}
|
||||
}
|
||||
Element.setStyle(this.element, d);
|
||||
}
|
||||
});
|
||||
|
||||
Effect.Highlight = Class.create();
|
||||
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
|
||||
initialize: function(element) {
|
||||
this.element = $(element);
|
||||
var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
|
||||
this.start(options);
|
||||
},
|
||||
setup: function() {
|
||||
// Prevent executing on elements not in the layout flow
|
||||
if(Element.getStyle(this.element, 'display')=='none') { this.cancel(); return; }
|
||||
// Disable background image during the effect
|
||||
this.oldStyle = {
|
||||
backgroundImage: Element.getStyle(this.element, 'background-image') };
|
||||
Element.setStyle(this.element, {backgroundImage: 'none'});
|
||||
if(!this.options.endcolor)
|
||||
this.options.endcolor = Element.getStyle(this.element, 'background-color').parseColor('#ffffff');
|
||||
if(!this.options.restorecolor)
|
||||
this.options.restorecolor = Element.getStyle(this.element, 'background-color');
|
||||
// init color calculations
|
||||
this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
|
||||
this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
|
||||
},
|
||||
update: function(position) {
|
||||
Element.setStyle(this.element,{backgroundColor: $R(0,2).inject('#',function(m,v,i){
|
||||
return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
|
||||
},
|
||||
finish: function() {
|
||||
Element.setStyle(this.element, Object.extend(this.oldStyle, {
|
||||
backgroundColor: this.options.restorecolor
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
Effect.ScrollTo = Class.create();
|
||||
Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
|
||||
initialize: function(element) {
|
||||
this.element = $(element);
|
||||
this.start(arguments[1] || {});
|
||||
},
|
||||
setup: function() {
|
||||
Position.prepare();
|
||||
var offsets = Position.cumulativeOffset(this.element);
|
||||
if(this.options.offset) offsets[1] += this.options.offset;
|
||||
var max = window.innerHeight ?
|
||||
window.height - window.innerHeight :
|
||||
document.body.scrollHeight -
|
||||
(document.documentElement.clientHeight ?
|
||||
document.documentElement.clientHeight : document.body.clientHeight);
|
||||
this.scrollStart = Position.deltaY;
|
||||
this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
|
||||
},
|
||||
update: function(position) {
|
||||
Position.prepare();
|
||||
window.scrollTo(Position.deltaX,
|
||||
this.scrollStart + (position*this.delta));
|
||||
}
|
||||
});
|
||||
|
||||
/* ------------- combination effects ------------- */
|
||||
|
||||
Effect.Fade = function(element) {
|
||||
var oldOpacity = Element.getInlineOpacity(element);
|
||||
var options = Object.extend({
|
||||
from: Element.getOpacity(element) || 1.0,
|
||||
to: 0.0,
|
||||
afterFinishInternal: function(effect) { with(Element) {
|
||||
if(effect.options.to!=0) return;
|
||||
hide(effect.element);
|
||||
setStyle(effect.element, {opacity: oldOpacity}); }}
|
||||
}, arguments[1] || {});
|
||||
return new Effect.Opacity(element,options);
|
||||
}
|
||||
|
||||
Effect.Appear = function(element) {
|
||||
var options = Object.extend({
|
||||
from: (Element.getStyle(element, 'display') == 'none' ? 0.0 : Element.getOpacity(element) || 0.0),
|
||||
to: 1.0,
|
||||
beforeSetup: function(effect) { with(Element) {
|
||||
setOpacity(effect.element, effect.options.from);
|
||||
show(effect.element); }}
|
||||
}, arguments[1] || {});
|
||||
return new Effect.Opacity(element,options);
|
||||
}
|
||||
|
||||
Effect.Puff = function(element) {
|
||||
element = $(element);
|
||||
var oldStyle = { opacity: Element.getInlineOpacity(element), position: Element.getStyle(element, 'position') };
|
||||
return new Effect.Parallel(
|
||||
[ new Effect.Scale(element, 200,
|
||||
{ sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }),
|
||||
new Effect.Opacity(element, { sync: true, to: 0.0 } ) ],
|
||||
Object.extend({ duration: 1.0,
|
||||
beforeSetupInternal: function(effect) { with(Element) {
|
||||
setStyle(effect.effects[0].element, {position: 'absolute'}); }},
|
||||
afterFinishInternal: function(effect) { with(Element) {
|
||||
hide(effect.effects[0].element);
|
||||
setStyle(effect.effects[0].element, oldStyle); }}
|
||||
}, arguments[1] || {})
|
||||
);
|
||||
}
|
||||
|
||||
Effect.BlindUp = function(element) {
|
||||
element = $(element);
|
||||
Element.makeClipping(element);
|
||||
return new Effect.Scale(element, 0,
|
||||
Object.extend({ scaleContent: false,
|
||||
scaleX: false,
|
||||
restoreAfterFinish: true,
|
||||
afterFinishInternal: function(effect) { with(Element) {
|
||||
[hide, undoClipping].call(effect.element); }}
|
||||
}, arguments[1] || {})
|
||||
);
|
||||
}
|
||||
|
||||
Effect.BlindDown = function(element) {
|
||||
element = $(element);
|
||||
var elementDimensions = Element.getDimensions(element);
|
||||
return new Effect.Scale(element, 100,
|
||||
Object.extend({ scaleContent: false,
|
||||
scaleX: false,
|
||||
scaleFrom: 0,
|
||||
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
|
||||
restoreAfterFinish: true,
|
||||
afterSetup: function(effect) { with(Element) {
|
||||
makeClipping(effect.element);
|
||||
setStyle(effect.element, {height: '0px'});
|
||||
show(effect.element);
|
||||
}},
|
||||
afterFinishInternal: function(effect) {
|
||||
Element.undoClipping(effect.element);
|
||||
}
|
||||
}, arguments[1] || {})
|
||||
);
|
||||
}
|
||||
|
||||
Effect.SwitchOff = function(element) {
|
||||
element = $(element);
|
||||
var oldOpacity = Element.getInlineOpacity(element);
|
||||
return new Effect.Appear(element, {
|
||||
duration: 0.4,
|
||||
from: 0,
|
||||
transition: Effect.Transitions.flicker,
|
||||
afterFinishInternal: function(effect) {
|
||||
new Effect.Scale(effect.element, 1, {
|
||||
duration: 0.3, scaleFromCenter: true,
|
||||
scaleX: false, scaleContent: false, restoreAfterFinish: true,
|
||||
beforeSetup: function(effect) { with(Element) {
|
||||
[makePositioned,makeClipping].call(effect.element);
|
||||
}},
|
||||
afterFinishInternal: function(effect) { with(Element) {
|
||||
[hide,undoClipping,undoPositioned].call(effect.element);
|
||||
setStyle(effect.element, {opacity: oldOpacity});
|
||||
}}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Effect.DropOut = function(element) {
|
||||
element = $(element);
|
||||
var oldStyle = {
|
||||
top: Element.getStyle(element, 'top'),
|
||||
left: Element.getStyle(element, 'left'),
|
||||
opacity: Element.getInlineOpacity(element) };
|
||||
return new Effect.Parallel(
|
||||
[ new Effect.Move(element, {x: 0, y: 100, sync: true }),
|
||||
new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
|
||||
Object.extend(
|
||||
{ duration: 0.5,
|
||||
beforeSetup: function(effect) { with(Element) {
|
||||
makePositioned(effect.effects[0].element); }},
|
||||
afterFinishInternal: function(effect) { with(Element) {
|
||||
[hide, undoPositioned].call(effect.effects[0].element);
|
||||
setStyle(effect.effects[0].element, oldStyle); }}
|
||||
}, arguments[1] || {}));
|
||||
}
|
||||
|
||||
Effect.Shake = function(element) {
|
||||
element = $(element);
|
||||
var oldStyle = {
|
||||
top: Element.getStyle(element, 'top'),
|
||||
left: Element.getStyle(element, 'left') };
|
||||
return new Effect.Move(element,
|
||||
{ x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
|
||||
new Effect.Move(effect.element,
|
||||
{ x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
|
||||
new Effect.Move(effect.element,
|
||||
{ x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
|
||||
new Effect.Move(effect.element,
|
||||
{ x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
|
||||
new Effect.Move(effect.element,
|
||||
{ x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) {
|
||||
new Effect.Move(effect.element,
|
||||
{ x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { with(Element) {
|
||||
undoPositioned(effect.element);
|
||||
setStyle(effect.element, oldStyle);
|
||||
}}}) }}) }}) }}) }}) }});
|
||||
}
|
||||
|
||||
Effect.SlideDown = function(element) {
|
||||
element = $(element);
|
||||
Element.cleanWhitespace(element);
|
||||
// SlideDown need to have the content of the element wrapped in a container element with fixed height!
|
||||
var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
|
||||
var elementDimensions = Element.getDimensions(element);
|
||||
return new Effect.Scale(element, 100, Object.extend({
|
||||
scaleContent: false,
|
||||
scaleX: false,
|
||||
scaleFrom: 0,
|
||||
scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
|
||||
restoreAfterFinish: true,
|
||||
afterSetup: function(effect) { with(Element) {
|
||||
makePositioned(effect.element);
|
||||
makePositioned(effect.element.firstChild);
|
||||
if(window.opera) setStyle(effect.element, {top: ''});
|
||||
makeClipping(effect.element);
|
||||
setStyle(effect.element, {height: '0px'});
|
||||
show(element); }},
|
||||
afterUpdateInternal: function(effect) { with(Element) {
|
||||
setStyle(effect.element.firstChild, {bottom:
|
||||
(effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
|
||||
afterFinishInternal: function(effect) { with(Element) {
|
||||
undoClipping(effect.element);
|
||||
// IE will crash if child is undoPositioned first
|
||||
if(/MSIE/.test(navigator.userAgent)){
|
||||
undoPositioned(effect.element);
|
||||
undoPositioned(effect.element.firstChild);
|
||||
}else{
|
||||
undoPositioned(effect.element.firstChild);
|
||||
undoPositioned(effect.element);
|
||||
}
|
||||
setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
|
||||
}, arguments[1] || {})
|
||||
);
|
||||
}
|
||||
|
||||
Effect.SlideUp = function(element) {
|
||||
element = $(element);
|
||||
Element.cleanWhitespace(element);
|
||||
var oldInnerBottom = Element.getStyle(element.firstChild, 'bottom');
|
||||
return new Effect.Scale(element, 0,
|
||||
Object.extend({ scaleContent: false,
|
||||
scaleX: false,
|
||||
scaleMode: 'box',
|
||||
scaleFrom: 100,
|
||||
restoreAfterFinish: true,
|
||||
beforeStartInternal: function(effect) { with(Element) {
|
||||
makePositioned(effect.element);
|
||||
makePositioned(effect.element.firstChild);
|
||||
if(window.opera) setStyle(effect.element, {top: ''});
|
||||
makeClipping(effect.element);
|
||||
show(element); }},
|
||||
afterUpdateInternal: function(effect) { with(Element) {
|
||||
setStyle(effect.element.firstChild, {bottom:
|
||||
(effect.dims[0] - effect.element.clientHeight) + 'px' }); }},
|
||||
afterFinishInternal: function(effect) { with(Element) {
|
||||
[hide, undoClipping].call(effect.element);
|
||||
undoPositioned(effect.element.firstChild);
|
||||
undoPositioned(effect.element);
|
||||
setStyle(effect.element.firstChild, {bottom: oldInnerBottom}); }}
|
||||
}, arguments[1] || {})
|
||||
);
|
||||
}
|
||||
|
||||
// Bug in opera makes the TD containing this element expand for a instance after finish
|
||||
Effect.Squish = function(element) {
|
||||
return new Effect.Scale(element, window.opera ? 1 : 0,
|
||||
{ restoreAfterFinish: true,
|
||||
beforeSetup: function(effect) { with(Element) {
|
||||
makeClipping(effect.element); }},
|
||||
afterFinishInternal: function(effect) { with(Element) {
|
||||
hide(effect.element);
|
||||
undoClipping(effect.element); }}
|
||||
});
|
||||
}
|
||||
|
||||
Effect.Grow = function(element) {
|
||||
element = $(element);
|
||||
var options = Object.extend({
|
||||
direction: 'center',
|
||||
moveTransition: Effect.Transitions.sinoidal,
|
||||
scaleTransition: Effect.Transitions.sinoidal,
|
||||
opacityTransition: Effect.Transitions.full
|
||||
}, arguments[1] || {});
|
||||
var oldStyle = {
|
||||
top: element.style.top,
|
||||
left: element.style.left,
|
||||
height: element.style.height,
|
||||
width: element.style.width,
|
||||
opacity: Element.getInlineOpacity(element) };
|
||||
|
||||
var dims = Element.getDimensions(element);
|
||||
var initialMoveX, initialMoveY;
|
||||
var moveX, moveY;
|
||||
|
||||
switch (options.direction) {
|
||||
case 'top-left':
|
||||
initialMoveX = initialMoveY = moveX = moveY = 0;
|
||||
break;
|
||||
case 'top-right':
|
||||
initialMoveX = dims.width;
|
||||
initialMoveY = moveY = 0;
|
||||
moveX = -dims.width;
|
||||
break;
|
||||
case 'bottom-left':
|
||||
initialMoveX = moveX = 0;
|
||||
initialMoveY = dims.height;
|
||||
moveY = -dims.height;
|
||||
break;
|
||||
case 'bottom-right':
|
||||
initialMoveX = dims.width;
|
||||
initialMoveY = dims.height;
|
||||
moveX = -dims.width;
|
||||
moveY = -dims.height;
|
||||
break;
|
||||
case 'center':
|
||||
initialMoveX = dims.width / 2;
|
||||
initialMoveY = dims.height / 2;
|
||||
moveX = -dims.width / 2;
|
||||
moveY = -dims.height / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
return new Effect.Move(element, {
|
||||
x: initialMoveX,
|
||||
y: initialMoveY,
|
||||
duration: 0.01,
|
||||
beforeSetup: function(effect) { with(Element) {
|
||||
hide(effect.element);
|
||||
makeClipping(effect.element);
|
||||
makePositioned(effect.element);
|
||||
}},
|
||||
afterFinishInternal: function(effect) {
|
||||
new Effect.Parallel(
|
||||
[ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
|
||||
new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
|
||||
new Effect.Scale(effect.element, 100, {
|
||||
scaleMode: { originalHeight: dims.height, originalWidth: dims.width },
|
||||
sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
|
||||
], Object.extend({
|
||||
beforeSetup: function(effect) { with(Element) {
|
||||
setStyle(effect.effects[0].element, {height: '0px'});
|
||||
show(effect.effects[0].element); }},
|
||||
afterFinishInternal: function(effect) { with(Element) {
|
||||
[undoClipping, undoPositioned].call(effect.effects[0].element);
|
||||
setStyle(effect.effects[0].element, oldStyle); }}
|
||||
}, options)
|
||||
)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Effect.Shrink = function(element) {
|
||||
element = $(element);
|
||||
var options = Object.extend({
|
||||
direction: 'center',
|
||||
moveTransition: Effect.Transitions.sinoidal,
|
||||
scaleTransition: Effect.Transitions.sinoidal,
|
||||
opacityTransition: Effect.Transitions.none
|
||||
}, arguments[1] || {});
|
||||
var oldStyle = {
|
||||
top: element.style.top,
|
||||
left: element.style.left,
|
||||
height: element.style.height,
|
||||
width: element.style.width,
|
||||
opacity: Element.getInlineOpacity(element) };
|
||||
|
||||
var dims = Element.getDimensions(element);
|
||||
var moveX, moveY;
|
||||
|
||||
switch (options.direction) {
|
||||
case 'top-left':
|
||||
moveX = moveY = 0;
|
||||
break;
|
||||
case 'top-right':
|
||||
moveX = dims.width;
|
||||
moveY = 0;
|
||||
break;
|
||||
case 'bottom-left':
|
||||
moveX = 0;
|
||||
moveY = dims.height;
|
||||
break;
|
||||
case 'bottom-right':
|
||||
moveX = dims.width;
|
||||
moveY = dims.height;
|
||||
break;
|
||||
case 'center':
|
||||
moveX = dims.width / 2;
|
||||
moveY = dims.height / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
return new Effect.Parallel(
|
||||
[ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
|
||||
new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
|
||||
new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
|
||||
], Object.extend({
|
||||
beforeStartInternal: function(effect) { with(Element) {
|
||||
[makePositioned, makeClipping].call(effect.effects[0].element) }},
|
||||
afterFinishInternal: function(effect) { with(Element) {
|
||||
[hide, undoClipping, undoPositioned].call(effect.effects[0].element);
|
||||
setStyle(effect.effects[0].element, oldStyle); }}
|
||||
}, options)
|
||||
);
|
||||
}
|
||||
|
||||
Effect.Pulsate = function(element) {
|
||||
element = $(element);
|
||||
var options = arguments[1] || {};
|
||||
var oldOpacity = Element.getInlineOpacity(element);
|
||||
var transition = options.transition || Effect.Transitions.sinoidal;
|
||||
var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) };
|
||||
reverser.bind(transition);
|
||||
return new Effect.Opacity(element,
|
||||
Object.extend(Object.extend({ duration: 3.0, from: 0,
|
||||
afterFinishInternal: function(effect) { Element.setStyle(effect.element, {opacity: oldOpacity}); }
|
||||
}, options), {transition: reverser}));
|
||||
}
|
||||
|
||||
Effect.Fold = function(element) {
|
||||
element = $(element);
|
||||
var oldStyle = {
|
||||
top: element.style.top,
|
||||
left: element.style.left,
|
||||
width: element.style.width,
|
||||
height: element.style.height };
|
||||
Element.makeClipping(element);
|
||||
return new Effect.Scale(element, 5, Object.extend({
|
||||
scaleContent: false,
|
||||
scaleX: false,
|
||||
afterFinishInternal: function(effect) {
|
||||
new Effect.Scale(element, 1, {
|
||||
scaleContent: false,
|
||||
scaleY: false,
|
||||
afterFinishInternal: function(effect) { with(Element) {
|
||||
[hide, undoClipping].call(effect.element);
|
||||
setStyle(effect.element, oldStyle);
|
||||
}} });
|
||||
}}, arguments[1] || {}));
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
var Scriptaculous = {
|
||||
Version: '1.5.3',
|
||||
require: function(libraryName) {
|
||||
// inserting via DOM fails in Safari 2.0, so brute force approach
|
||||
document.write('<script type="text/javascript" src="'+libraryName+'"></script>');
|
||||
},
|
||||
load: function() {
|
||||
if((typeof Prototype=='undefined') ||
|
||||
parseFloat(Prototype.Version.split(".")[0] + "." +
|
||||
Prototype.Version.split(".")[1]) < 1.4)
|
||||
throw("script.aculo.us requires the Prototype JavaScript framework >= 1.4.0");
|
||||
|
||||
$A(document.getElementsByTagName("script")).findAll( function(s) {
|
||||
return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
|
||||
}).each( function(s) {
|
||||
var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,'');
|
||||
var includes = s.src.match(/\?.*load=([a-z,]*)/);
|
||||
(includes ? includes[1] : 'builder,effects,dragdrop,controls,slider').split(',').each(
|
||||
function(include) { Scriptaculous.require(path+include+'.js') });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Scriptaculous.load();
|
@ -1,283 +0,0 @@
|
||||
// Copyright (c) 2005 Marty Haught, Thomas Fuchs
|
||||
//
|
||||
// See http://script.aculo.us for more info
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
if(!Control) var Control = {};
|
||||
Control.Slider = Class.create();
|
||||
|
||||
// options:
|
||||
// axis: 'vertical', or 'horizontal' (default)
|
||||
//
|
||||
// callbacks:
|
||||
// onChange(value)
|
||||
// onSlide(value)
|
||||
Control.Slider.prototype = {
|
||||
initialize: function(handle, track, options) {
|
||||
var slider = this;
|
||||
|
||||
if(handle instanceof Array) {
|
||||
this.handles = handle.collect( function(e) { return $(e) });
|
||||
} else {
|
||||
this.handles = [$(handle)];
|
||||
}
|
||||
|
||||
this.track = $(track);
|
||||
this.options = options || {};
|
||||
|
||||
this.axis = this.options.axis || 'horizontal';
|
||||
this.increment = this.options.increment || 1;
|
||||
this.step = parseInt(this.options.step || '1');
|
||||
this.range = this.options.range || $R(0,1);
|
||||
|
||||
this.value = 0; // assure backwards compat
|
||||
this.values = this.handles.map( function() { return 0 });
|
||||
this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
|
||||
this.options.startSpan = $(this.options.startSpan || null);
|
||||
this.options.endSpan = $(this.options.endSpan || null);
|
||||
|
||||
this.restricted = this.options.restricted || false;
|
||||
|
||||
this.maximum = this.options.maximum || this.range.end;
|
||||
this.minimum = this.options.minimum || this.range.start;
|
||||
|
||||
// Will be used to align the handle onto the track, if necessary
|
||||
this.alignX = parseInt(this.options.alignX || '0');
|
||||
this.alignY = parseInt(this.options.alignY || '0');
|
||||
|
||||
this.trackLength = this.maximumOffset() - this.minimumOffset();
|
||||
this.handleLength = this.isVertical() ? this.handles[0].offsetHeight : this.handles[0].offsetWidth;
|
||||
|
||||
this.active = false;
|
||||
this.dragging = false;
|
||||
this.disabled = false;
|
||||
|
||||
if(this.options.disabled) this.setDisabled();
|
||||
|
||||
// Allowed values array
|
||||
this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
|
||||
if(this.allowedValues) {
|
||||
this.minimum = this.allowedValues.min();
|
||||
this.maximum = this.allowedValues.max();
|
||||
}
|
||||
|
||||
this.eventMouseDown = this.startDrag.bindAsEventListener(this);
|
||||
this.eventMouseUp = this.endDrag.bindAsEventListener(this);
|
||||
this.eventMouseMove = this.update.bindAsEventListener(this);
|
||||
|
||||
// Initialize handles in reverse (make sure first handle is active)
|
||||
this.handles.each( function(h,i) {
|
||||
i = slider.handles.length-1-i;
|
||||
slider.setValue(parseFloat(
|
||||
(slider.options.sliderValue instanceof Array ?
|
||||
slider.options.sliderValue[i] : slider.options.sliderValue) ||
|
||||
slider.range.start), i);
|
||||
Element.makePositioned(h); // fix IE
|
||||
Event.observe(h, "mousedown", slider.eventMouseDown);
|
||||
});
|
||||
|
||||
Event.observe(this.track, "mousedown", this.eventMouseDown);
|
||||
Event.observe(document, "mouseup", this.eventMouseUp);
|
||||
Event.observe(document, "mousemove", this.eventMouseMove);
|
||||
|
||||
this.initialized = true;
|
||||
},
|
||||
dispose: function() {
|
||||
var slider = this;
|
||||
Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
|
||||
Event.stopObserving(document, "mouseup", this.eventMouseUp);
|
||||
Event.stopObserving(document, "mousemove", this.eventMouseMove);
|
||||
this.handles.each( function(h) {
|
||||
Event.stopObserving(h, "mousedown", slider.eventMouseDown);
|
||||
});
|
||||
},
|
||||
setDisabled: function(){
|
||||
this.disabled = true;
|
||||
},
|
||||
setEnabled: function(){
|
||||
this.disabled = false;
|
||||
},
|
||||
getNearestValue: function(value){
|
||||
if(this.allowedValues){
|
||||
if(value >= this.allowedValues.max()) return(this.allowedValues.max());
|
||||
if(value <= this.allowedValues.min()) return(this.allowedValues.min());
|
||||
|
||||
var offset = Math.abs(this.allowedValues[0] - value);
|
||||
var newValue = this.allowedValues[0];
|
||||
this.allowedValues.each( function(v) {
|
||||
var currentOffset = Math.abs(v - value);
|
||||
if(currentOffset <= offset){
|
||||
newValue = v;
|
||||
offset = currentOffset;
|
||||
}
|
||||
});
|
||||
return newValue;
|
||||
}
|
||||
if(value > this.range.end) return this.range.end;
|
||||
if(value < this.range.start) return this.range.start;
|
||||
return value;
|
||||
},
|
||||
setValue: function(sliderValue, handleIdx){
|
||||
if(!this.active) {
|
||||
this.activeHandle = this.handles[handleIdx];
|
||||
this.activeHandleIdx = handleIdx;
|
||||
this.updateStyles();
|
||||
}
|
||||
handleIdx = handleIdx || this.activeHandleIdx || 0;
|
||||
if(this.initialized && this.restricted) {
|
||||
if((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
|
||||
sliderValue = this.values[handleIdx-1];
|
||||
if((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
|
||||
sliderValue = this.values[handleIdx+1];
|
||||
}
|
||||
sliderValue = this.getNearestValue(sliderValue);
|
||||
this.values[handleIdx] = sliderValue;
|
||||
this.value = this.values[0]; // assure backwards compat
|
||||
|
||||
this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] =
|
||||
this.translateToPx(sliderValue);
|
||||
|
||||
this.drawSpans();
|
||||
if(!this.dragging || !this.event) this.updateFinished();
|
||||
},
|
||||
setValueBy: function(delta, handleIdx) {
|
||||
this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta,
|
||||
handleIdx || this.activeHandleIdx || 0);
|
||||
},
|
||||
translateToPx: function(value) {
|
||||
return Math.round(
|
||||
((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) *
|
||||
(value - this.range.start)) + "px";
|
||||
},
|
||||
translateToValue: function(offset) {
|
||||
return ((offset/(this.trackLength-this.handleLength) *
|
||||
(this.range.end-this.range.start)) + this.range.start);
|
||||
},
|
||||
getRange: function(range) {
|
||||
var v = this.values.sortBy(Prototype.K);
|
||||
range = range || 0;
|
||||
return $R(v[range],v[range+1]);
|
||||
},
|
||||
minimumOffset: function(){
|
||||
return(this.isVertical() ? this.alignY : this.alignX);
|
||||
},
|
||||
maximumOffset: function(){
|
||||
return(this.isVertical() ?
|
||||
this.track.offsetHeight - this.alignY : this.track.offsetWidth - this.alignX);
|
||||
},
|
||||
isVertical: function(){
|
||||
return (this.axis == 'vertical');
|
||||
},
|
||||
drawSpans: function() {
|
||||
var slider = this;
|
||||
if(this.spans)
|
||||
$R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
|
||||
if(this.options.startSpan)
|
||||
this.setSpan(this.options.startSpan,
|
||||
$R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
|
||||
if(this.options.endSpan)
|
||||
this.setSpan(this.options.endSpan,
|
||||
$R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
|
||||
},
|
||||
setSpan: function(span, range) {
|
||||
if(this.isVertical()) {
|
||||
span.style.top = this.translateToPx(range.start);
|
||||
span.style.height = this.translateToPx(range.end - range.start + this.range.start);
|
||||
} else {
|
||||
span.style.left = this.translateToPx(range.start);
|
||||
span.style.width = this.translateToPx(range.end - range.start + this.range.start);
|
||||
}
|
||||
},
|
||||
updateStyles: function() {
|
||||
this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
|
||||
Element.addClassName(this.activeHandle, 'selected');
|
||||
},
|
||||
startDrag: function(event) {
|
||||
if(Event.isLeftClick(event)) {
|
||||
if(!this.disabled){
|
||||
this.active = true;
|
||||
|
||||
var handle = Event.element(event);
|
||||
var pointer = [Event.pointerX(event), Event.pointerY(event)];
|
||||
if(handle==this.track) {
|
||||
var offsets = Position.cumulativeOffset(this.track);
|
||||
this.event = event;
|
||||
this.setValue(this.translateToValue(
|
||||
(this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
|
||||
));
|
||||
var offsets = Position.cumulativeOffset(this.activeHandle);
|
||||
this.offsetX = (pointer[0] - offsets[0]);
|
||||
this.offsetY = (pointer[1] - offsets[1]);
|
||||
} else {
|
||||
// find the handle (prevents issues with Safari)
|
||||
while((this.handles.indexOf(handle) == -1) && handle.parentNode)
|
||||
handle = handle.parentNode;
|
||||
|
||||
this.activeHandle = handle;
|
||||
this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
|
||||
this.updateStyles();
|
||||
|
||||
var offsets = Position.cumulativeOffset(this.activeHandle);
|
||||
this.offsetX = (pointer[0] - offsets[0]);
|
||||
this.offsetY = (pointer[1] - offsets[1]);
|
||||
}
|
||||
}
|
||||
Event.stop(event);
|
||||
}
|
||||
},
|
||||
update: function(event) {
|
||||
if(this.active) {
|
||||
if(!this.dragging) this.dragging = true;
|
||||
this.draw(event);
|
||||
// fix AppleWebKit rendering
|
||||
if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
|
||||
Event.stop(event);
|
||||
}
|
||||
},
|
||||
draw: function(event) {
|
||||
var pointer = [Event.pointerX(event), Event.pointerY(event)];
|
||||
var offsets = Position.cumulativeOffset(this.track);
|
||||
pointer[0] -= this.offsetX + offsets[0];
|
||||
pointer[1] -= this.offsetY + offsets[1];
|
||||
this.event = event;
|
||||
this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
|
||||
if(this.initialized && this.options.onSlide)
|
||||
this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
|
||||
},
|
||||
endDrag: function(event) {
|
||||
if(this.active && this.dragging) {
|
||||
this.finishDrag(event, true);
|
||||
Event.stop(event);
|
||||
}
|
||||
this.active = false;
|
||||
this.dragging = false;
|
||||
},
|
||||
finishDrag: function(event, success) {
|
||||
this.active = false;
|
||||
this.dragging = false;
|
||||
this.updateFinished();
|
||||
},
|
||||
updateFinished: function() {
|
||||
if(this.initialized && this.options.onChange)
|
||||
this.options.onChange(this.values.length>1 ? this.values : this.value, this);
|
||||
this.event = null;
|
||||
}
|
||||
}
|
@ -1,372 +0,0 @@
|
||||
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
|
||||
// (c) 2005 Jon Tirsen (http://www.tirsen.com)
|
||||
// (c) 2005 Michael Schuerig (http://www.schuerig.de/michael/)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
// experimental, Firefox-only
|
||||
Event.simulateMouse = function(element, eventName) {
|
||||
var options = Object.extend({
|
||||
pointerX: 0,
|
||||
pointerY: 0,
|
||||
buttons: 0
|
||||
}, arguments[2] || {});
|
||||
var oEvent = document.createEvent("MouseEvents");
|
||||
oEvent.initMouseEvent(eventName, true, true, document.defaultView,
|
||||
options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
|
||||
false, false, false, false, 0, $(element));
|
||||
|
||||
if(this.mark) Element.remove(this.mark);
|
||||
this.mark = document.createElement('div');
|
||||
this.mark.appendChild(document.createTextNode(" "));
|
||||
document.body.appendChild(this.mark);
|
||||
this.mark.style.position = 'absolute';
|
||||
this.mark.style.top = options.pointerY + "px";
|
||||
this.mark.style.left = options.pointerX + "px";
|
||||
this.mark.style.width = "5px";
|
||||
this.mark.style.height = "5px;";
|
||||
this.mark.style.borderTop = "1px solid red;"
|
||||
this.mark.style.borderLeft = "1px solid red;"
|
||||
|
||||
if(this.step)
|
||||
alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options));
|
||||
|
||||
$(element).dispatchEvent(oEvent);
|
||||
};
|
||||
|
||||
// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2.
|
||||
// You need to downgrade to 1.0.4 for now to get this working
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much
|
||||
Event.simulateKey = function(element, eventName) {
|
||||
var options = Object.extend({
|
||||
ctrlKey: false,
|
||||
altKey: false,
|
||||
shiftKey: false,
|
||||
metaKey: false,
|
||||
keyCode: 0,
|
||||
charCode: 0
|
||||
}, arguments[2] || {});
|
||||
|
||||
var oEvent = document.createEvent("KeyEvents");
|
||||
oEvent.initKeyEvent(eventName, true, true, window,
|
||||
options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
|
||||
options.keyCode, options.charCode );
|
||||
$(element).dispatchEvent(oEvent);
|
||||
};
|
||||
|
||||
Event.simulateKeys = function(element, command) {
|
||||
for(var i=0; i<command.length; i++) {
|
||||
Event.simulateKey(element,'keypress',{charCode:command.charCodeAt(i)});
|
||||
}
|
||||
};
|
||||
|
||||
var Test = {}
|
||||
Test.Unit = {};
|
||||
|
||||
// security exception workaround
|
||||
Test.Unit.inspect = Object.inspect;
|
||||
|
||||
Test.Unit.Logger = Class.create();
|
||||
Test.Unit.Logger.prototype = {
|
||||
initialize: function(log) {
|
||||
this.log = $(log);
|
||||
if (this.log) {
|
||||
this._createLogTable();
|
||||
}
|
||||
},
|
||||
start: function(testName) {
|
||||
if (!this.log) return;
|
||||
this.testName = testName;
|
||||
this.lastLogLine = document.createElement('tr');
|
||||
this.statusCell = document.createElement('td');
|
||||
this.nameCell = document.createElement('td');
|
||||
this.nameCell.appendChild(document.createTextNode(testName));
|
||||
this.messageCell = document.createElement('td');
|
||||
this.lastLogLine.appendChild(this.statusCell);
|
||||
this.lastLogLine.appendChild(this.nameCell);
|
||||
this.lastLogLine.appendChild(this.messageCell);
|
||||
this.loglines.appendChild(this.lastLogLine);
|
||||
},
|
||||
finish: function(status, summary) {
|
||||
if (!this.log) return;
|
||||
this.lastLogLine.className = status;
|
||||
this.statusCell.innerHTML = status;
|
||||
this.messageCell.innerHTML = this._toHTML(summary);
|
||||
},
|
||||
message: function(message) {
|
||||
if (!this.log) return;
|
||||
this.messageCell.innerHTML = this._toHTML(message);
|
||||
},
|
||||
summary: function(summary) {
|
||||
if (!this.log) return;
|
||||
this.logsummary.innerHTML = this._toHTML(summary);
|
||||
},
|
||||
_createLogTable: function() {
|
||||
this.log.innerHTML =
|
||||
'<div id="logsummary"></div>' +
|
||||
'<table id="logtable">' +
|
||||
'<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
|
||||
'<tbody id="loglines"></tbody>' +
|
||||
'</table>';
|
||||
this.logsummary = $('logsummary')
|
||||
this.loglines = $('loglines');
|
||||
},
|
||||
_toHTML: function(txt) {
|
||||
return txt.escapeHTML().replace(/\n/g,"<br/>");
|
||||
}
|
||||
}
|
||||
|
||||
Test.Unit.Runner = Class.create();
|
||||
Test.Unit.Runner.prototype = {
|
||||
initialize: function(testcases) {
|
||||
this.options = Object.extend({
|
||||
testLog: 'testlog'
|
||||
}, arguments[1] || {});
|
||||
this.options.resultsURL = this.parseResultsURLQueryParameter();
|
||||
if (this.options.testLog) {
|
||||
this.options.testLog = $(this.options.testLog) || null;
|
||||
}
|
||||
if(this.options.tests) {
|
||||
this.tests = [];
|
||||
for(var i = 0; i < this.options.tests.length; i++) {
|
||||
if(/^test/.test(this.options.tests[i])) {
|
||||
this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"]));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.options.test) {
|
||||
this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])];
|
||||
} else {
|
||||
this.tests = [];
|
||||
for(var testcase in testcases) {
|
||||
if(/^test/.test(testcase)) {
|
||||
this.tests.push(new Test.Unit.Testcase(testcase, testcases[testcase], testcases["setup"], testcases["teardown"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.currentTest = 0;
|
||||
this.logger = new Test.Unit.Logger(this.options.testLog);
|
||||
setTimeout(this.runTests.bind(this), 1000);
|
||||
},
|
||||
parseResultsURLQueryParameter: function() {
|
||||
return window.location.search.parseQuery()["resultsURL"];
|
||||
},
|
||||
// Returns:
|
||||
// "ERROR" if there was an error,
|
||||
// "FAILURE" if there was a failure, or
|
||||
// "SUCCESS" if there was neither
|
||||
getResult: function() {
|
||||
var hasFailure = false;
|
||||
for(var i=0;i<this.tests.length;i++) {
|
||||
if (this.tests[i].errors > 0) {
|
||||
return "ERROR";
|
||||
}
|
||||
if (this.tests[i].failures > 0) {
|
||||
hasFailure = true;
|
||||
}
|
||||
}
|
||||
if (hasFailure) {
|
||||
return "FAILURE";
|
||||
} else {
|
||||
return "SUCCESS";
|
||||
}
|
||||
},
|
||||
postResults: function() {
|
||||
if (this.options.resultsURL) {
|
||||
new Ajax.Request(this.options.resultsURL,
|
||||
{ method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false });
|
||||
}
|
||||
},
|
||||
runTests: function() {
|
||||
var test = this.tests[this.currentTest];
|
||||
if (!test) {
|
||||
// finished!
|
||||
this.postResults();
|
||||
this.logger.summary(this.summary());
|
||||
return;
|
||||
}
|
||||
if(!test.isWaiting) {
|
||||
this.logger.start(test.name);
|
||||
}
|
||||
test.run();
|
||||
if(test.isWaiting) {
|
||||
this.logger.message("Waiting for " + test.timeToWait + "ms");
|
||||
setTimeout(this.runTests.bind(this), test.timeToWait || 1000);
|
||||
} else {
|
||||
this.logger.finish(test.status(), test.summary());
|
||||
this.currentTest++;
|
||||
// tail recursive, hopefully the browser will skip the stackframe
|
||||
this.runTests();
|
||||
}
|
||||
},
|
||||
summary: function() {
|
||||
var assertions = 0;
|
||||
var failures = 0;
|
||||
var errors = 0;
|
||||
var messages = [];
|
||||
for(var i=0;i<this.tests.length;i++) {
|
||||
assertions += this.tests[i].assertions;
|
||||
failures += this.tests[i].failures;
|
||||
errors += this.tests[i].errors;
|
||||
}
|
||||
return (
|
||||
this.tests.length + " tests, " +
|
||||
assertions + " assertions, " +
|
||||
failures + " failures, " +
|
||||
errors + " errors");
|
||||
}
|
||||
}
|
||||
|
||||
Test.Unit.Assertions = Class.create();
|
||||
Test.Unit.Assertions.prototype = {
|
||||
initialize: function() {
|
||||
this.assertions = 0;
|
||||
this.failures = 0;
|
||||
this.errors = 0;
|
||||
this.messages = [];
|
||||
},
|
||||
summary: function() {
|
||||
return (
|
||||
this.assertions + " assertions, " +
|
||||
this.failures + " failures, " +
|
||||
this.errors + " errors" + "\n" +
|
||||
this.messages.join("\n"));
|
||||
},
|
||||
pass: function() {
|
||||
this.assertions++;
|
||||
},
|
||||
fail: function(message) {
|
||||
this.failures++;
|
||||
this.messages.push("Failure: " + message);
|
||||
},
|
||||
error: function(error) {
|
||||
this.errors++;
|
||||
this.messages.push(error.name + ": "+ error.message + "(" + Test.Unit.inspect(error) +")");
|
||||
},
|
||||
status: function() {
|
||||
if (this.failures > 0) return 'failed';
|
||||
if (this.errors > 0) return 'error';
|
||||
return 'passed';
|
||||
},
|
||||
assert: function(expression) {
|
||||
var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"';
|
||||
try { expression ? this.pass() :
|
||||
this.fail(message); }
|
||||
catch(e) { this.error(e); }
|
||||
},
|
||||
assertEqual: function(expected, actual) {
|
||||
var message = arguments[2] || "assertEqual";
|
||||
try { (expected == actual) ? this.pass() :
|
||||
this.fail(message + ': expected "' + Test.Unit.inspect(expected) +
|
||||
'", actual "' + Test.Unit.inspect(actual) + '"'); }
|
||||
catch(e) { this.error(e); }
|
||||
},
|
||||
assertEnumEqual: function(expected, actual) {
|
||||
var message = arguments[2] || "assertEnumEqual";
|
||||
try { $A(expected).length == $A(actual).length &&
|
||||
expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ?
|
||||
this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) +
|
||||
', actual ' + Test.Unit.inspect(actual)); }
|
||||
catch(e) { this.error(e); }
|
||||
},
|
||||
assertNotEqual: function(expected, actual) {
|
||||
var message = arguments[2] || "assertNotEqual";
|
||||
try { (expected != actual) ? this.pass() :
|
||||
this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); }
|
||||
catch(e) { this.error(e); }
|
||||
},
|
||||
assertNull: function(obj) {
|
||||
var message = arguments[1] || 'assertNull'
|
||||
try { (obj==null) ? this.pass() :
|
||||
this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); }
|
||||
catch(e) { this.error(e); }
|
||||
},
|
||||
assertHidden: function(element) {
|
||||
var message = arguments[1] || 'assertHidden';
|
||||
this.assertEqual("none", element.style.display, message);
|
||||
},
|
||||
assertNotNull: function(object) {
|
||||
var message = arguments[1] || 'assertNotNull';
|
||||
this.assert(object != null, message);
|
||||
},
|
||||
assertInstanceOf: function(expected, actual) {
|
||||
var message = arguments[2] || 'assertInstanceOf';
|
||||
try {
|
||||
(actual instanceof expected) ? this.pass() :
|
||||
this.fail(message + ": object was not an instance of the expected type"); }
|
||||
catch(e) { this.error(e); }
|
||||
},
|
||||
assertNotInstanceOf: function(expected, actual) {
|
||||
var message = arguments[2] || 'assertNotInstanceOf';
|
||||
try {
|
||||
!(actual instanceof expected) ? this.pass() :
|
||||
this.fail(message + ": object was an instance of the not expected type"); }
|
||||
catch(e) { this.error(e); }
|
||||
},
|
||||
_isVisible: function(element) {
|
||||
element = $(element);
|
||||
if(!element.parentNode) return true;
|
||||
this.assertNotNull(element);
|
||||
if(element.style && Element.getStyle(element, 'display') == 'none')
|
||||
return false;
|
||||
|
||||
return this._isVisible(element.parentNode);
|
||||
},
|
||||
assertNotVisible: function(element) {
|
||||
this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1]));
|
||||
},
|
||||
assertVisible: function(element) {
|
||||
this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1]));
|
||||
}
|
||||
}
|
||||
|
||||
Test.Unit.Testcase = Class.create();
|
||||
Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), {
|
||||
initialize: function(name, test, setup, teardown) {
|
||||
Test.Unit.Assertions.prototype.initialize.bind(this)();
|
||||
this.name = name;
|
||||
this.test = test || function() {};
|
||||
this.setup = setup || function() {};
|
||||
this.teardown = teardown || function() {};
|
||||
this.isWaiting = false;
|
||||
this.timeToWait = 1000;
|
||||
},
|
||||
wait: function(time, nextPart) {
|
||||
this.isWaiting = true;
|
||||
this.test = nextPart;
|
||||
this.timeToWait = time;
|
||||
},
|
||||
run: function() {
|
||||
try {
|
||||
try {
|
||||
if (!this.isWaiting) this.setup.bind(this)();
|
||||
this.isWaiting = false;
|
||||
this.test.bind(this)();
|
||||
} finally {
|
||||
if(!this.isWaiting) {
|
||||
this.teardown.bind(this)();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(e) { this.error(e); }
|
||||
}
|
||||
});
|
Before Width: | Height: | Size: 102 B |
Before Width: | Height: | Size: 102 B |
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
|
||||
<head>
|
||||
<title>Firefly Media Server</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<title>No access</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>No access</h1>
|
||||
You have no password set in your config file.<br />
|
||||
Without a password access is only permitted from the computer where<br
|
||||
/> Firefly Media Server is running.<br />
|
||||
<br />
|
||||
To enable Firefly remote administration open your config file:<br />
|
||||
<br />
|
||||
<tt>@CONFFILE@</tt> <br /><br />
|
||||
Find the section marked <code>[general]</code> and add the following line after the mark: <br />
|
||||
<br />
|
||||
<code>
|
||||
admin_pw = your_password
|
||||
</code>
|
||||
<br />
|
||||
<br />
|
||||
You will need to restart Firefly for the change to take effect.
|
||||
</body>
|
||||
</html>
|
@ -1,141 +0,0 @@
|
||||
@include hdr.html@
|
||||
<style type="text/css">
|
||||
#genre_div select, #artist_div select, #album_div select {
|
||||
font: icon;
|
||||
width: 30ex;
|
||||
overflow: hidden;
|
||||
}
|
||||
#source_div select {
|
||||
font: icon;
|
||||
width: 25ex;
|
||||
}
|
||||
#songs th {
|
||||
text-align: center;
|
||||
}
|
||||
#songs_data td {
|
||||
text-align: left;
|
||||
}
|
||||
#genre_div, #artist_div, #album_div {
|
||||
float: left;
|
||||
padding-left: 2ex;
|
||||
}
|
||||
#search_div {
|
||||
float: right;
|
||||
}
|
||||
#source_div {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
#songs_div {
|
||||
float: left;
|
||||
padding-left: 2ex;
|
||||
padding-top: 1ex;
|
||||
}
|
||||
#edit_playlist_name {
|
||||
position: absolute;
|
||||
font: icon;
|
||||
width: 25ex;
|
||||
display: none;
|
||||
}
|
||||
#songs_data {
|
||||
table-layout: fixed;
|
||||
}
|
||||
#songs_data td {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.row_selected {
|
||||
background-color: #8CACBB;
|
||||
}
|
||||
#spinner {
|
||||
float: right;
|
||||
margin-right: 2em;
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
||||
<div id="search_div">
|
||||
<label for="search">search</label>
|
||||
<input type="text" name="search" id="search" size="30" title="search songs, artists, albums, genres" />
|
||||
</div>
|
||||
<img id="spinner" src="/spinner.gif" />
|
||||
<div style="clear: both;"><!-- buggy IE div --></div>
|
||||
<div id="source_div">
|
||||
<label for="source">Source<br /></label>
|
||||
<select id="source" name="select" size="20">
|
||||
|
||||
<option value="1">Library</option>
|
||||
</select><br />
|
||||
<input type="text" id="edit_playlist_name" value="" />
|
||||
<div id="busymsg" style="text-align:center;color:red; visibility: hidden;">Busy ...</div>
|
||||
<a href="javascript://" id="add_playlist_href">Add static playlist</a>
|
||||
<br /> <br />
|
||||
<strong>Things that work:</strong><br />
|
||||
* Browse Library and playlists<br />
|
||||
* Search Library and playlists<br />
|
||||
* Dblclick playlist = rename<br />
|
||||
* Add static playlist<br />
|
||||
* Delete playlist (hit delete)<br />
|
||||
<br />
|
||||
<strong>Broken stuff</strong><br />
|
||||
* Truncated song info<br />
|
||||
* IE no playlist rename<br />
|
||||
* IE no add playlist<br />
|
||||
* IE scrollbar misaligned<br />
|
||||
</div>
|
||||
<div id="genre_div">
|
||||
Genre<br />
|
||||
|
||||
<select id="genres" name="select" multiple="multiple" size="15">
|
||||
<option value="all">all</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="artist_div">
|
||||
Artist<br />
|
||||
<select id="artists" name="select" multiple="multiple" size="15">
|
||||
<option value="all">all</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="album_div">
|
||||
Album<br />
|
||||
<select id="albums" name="select" multiple="multiple" size="15">
|
||||
<option value="all">all</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="songs_div" style="float: left; width:549px;">
|
||||
<table id="songs" style="width:530px;" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<th style="width: 240px;">Song</th>
|
||||
<th style="width: 50px;">Time</th>
|
||||
<th style="width: 120px;">Artist</th>
|
||||
<th style="width: 120px;">Album</th>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="songs_data" style="width:530px;" border="0" cellspacing="0" cellpadding="0">
|
||||
<col style="width: 240px;" />
|
||||
<col style="width: 50px;" />
|
||||
<col style="width: 120px;" />
|
||||
<col style="width: 120px;" />
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
<tr><td> </td><td></td><td></td><td></td><td></td></tr>
|
||||
</table>
|
||||
</div>
|
||||
@include ftr.html@
|
@ -1,706 +0,0 @@
|
||||
// TODO
|
||||
// move stuff to responsehandler
|
||||
// handle source change events (keyPress etc)
|
||||
// If playlist is empty don't confirm delete
|
||||
var CustomDraggable = Class.create();
|
||||
CustomDraggable.removeOnDrop = false;
|
||||
CustomDraggable.revereNamesOnDrop = true;
|
||||
|
||||
CustomDraggable.prototype = (new Rico.Draggable()).extend( {
|
||||
|
||||
initialize: function( htmlElement, name ) {
|
||||
this.type = 'Custom';
|
||||
this.htmlElement = htmlElement;
|
||||
this.name = name;
|
||||
},
|
||||
|
||||
log: function(str) {
|
||||
// alert(str);
|
||||
},
|
||||
|
||||
select: function() {
|
||||
this.selected = true;
|
||||
},
|
||||
|
||||
deselect: function() {
|
||||
this.selected = false;
|
||||
},
|
||||
|
||||
startDrag: function() {
|
||||
var el = this.htmlElement;
|
||||
this.log("startDrag: [" + this.name +"]");
|
||||
},
|
||||
|
||||
cancelDrag: function() {
|
||||
var el = this.htmlElement;
|
||||
this.log("cancelDrag: [" + this.name +"]");
|
||||
},
|
||||
|
||||
endDrag: function() {
|
||||
var el = this.htmlElement;
|
||||
this.log("endDrag: [" + this.name +"]");
|
||||
if ( CustomDraggable.removeOnDrop )
|
||||
this.htmlElement.style.display = 'none';
|
||||
|
||||
},
|
||||
|
||||
getSingleObjectDragGUI: function() {
|
||||
var el = this.htmlElement;
|
||||
|
||||
var div = document.createElement("div");
|
||||
div.className = 'customDraggable';
|
||||
div.style.width = (this.htmlElement.offsetWidth - 10) + "px";
|
||||
new Insertion.Top( div, "some songs" );
|
||||
return div;
|
||||
},
|
||||
|
||||
getMultiObjectDragGUI: function( draggables ) {
|
||||
var el = this.htmlElement;
|
||||
|
||||
var names = "";
|
||||
names = "some song(s)";
|
||||
|
||||
var div = document.createElement("div");
|
||||
div.className = 'customDraggable';
|
||||
div.style.width = (this.htmlElement.offsetWidth - 10) + "px";
|
||||
new Insertion.Top( div, names );
|
||||
return div;
|
||||
},
|
||||
|
||||
getDroppedGUI: function() {
|
||||
var el = this.htmlElement;
|
||||
|
||||
var div = document.createElement("div");
|
||||
var names = this.name.split(",");
|
||||
if ( CustomDraggable.revereNamesOnDrop )
|
||||
new Insertion.Top( div, "<span class='nameSpan'>[" + names[1].substring(1) + " " + names[0]+ "]</span>" );
|
||||
else
|
||||
new Insertion.Top( div, "<span class='nameSpan'>[" + this.name + "]</span>" );
|
||||
return div;
|
||||
},
|
||||
|
||||
toString: function() {
|
||||
return this.name;
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
var CustomDropzone = Class.create();
|
||||
CustomDropzone.prototype = (new Rico.Dropzone()).extend( {
|
||||
initialize: function( htmlElement, header) {
|
||||
this.htmlElement = htmlElement;
|
||||
this.header = header;
|
||||
this.absoluteRect = null;
|
||||
this.acceptedObjects = [];
|
||||
|
||||
this.offset = navigator.userAgent.toLowerCase().indexOf("msie") >= 0 ? 0 : 1;
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
},
|
||||
|
||||
deactivate: function() {
|
||||
},
|
||||
|
||||
showHover: function() {
|
||||
if ( this.showingHover )
|
||||
return;
|
||||
this.header.style.color = "#1111bb";
|
||||
this.showingHover = true;
|
||||
},
|
||||
|
||||
hideHover: function() {
|
||||
if ( !this.showingHover )
|
||||
return;
|
||||
this.header.style.color = "#000000";
|
||||
this.showingHover = false;
|
||||
},
|
||||
|
||||
accept: function(draggableObjects) {
|
||||
var songids = '';
|
||||
for (var i = SelectedRows.songId.length - 1; i >= 0; --i) {
|
||||
if (SelectedRows.songId[i]) {
|
||||
if (songids != '') {
|
||||
songids += ",";
|
||||
}
|
||||
songids += i;
|
||||
}
|
||||
}
|
||||
|
||||
this._insert(songids);
|
||||
},
|
||||
|
||||
_insert: function(songids) {
|
||||
var url = 'databases/1/containers/' + this.htmlElement.value + "/items/add?output=xml&dmap.itemid=" + songids;
|
||||
new Ajax.Request(url ,{method: 'get',onComplete:this.responseAdd});
|
||||
},
|
||||
|
||||
responseAdd: function(request) {
|
||||
var status = Element.textContent(request.responseXML.getElementsByTagName('dmap.status')[0]);
|
||||
if ('200' != status) {
|
||||
alert("Couldn't add songs to playlist");
|
||||
return;
|
||||
}
|
||||
alert("Added songs to playlist");
|
||||
},
|
||||
|
||||
canAccept: function(draggableObjects) {
|
||||
return true;
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
Event.observe(window,'load',initPlaylist);
|
||||
|
||||
var SEARCH_DELAY = 500; // # ms without typing before the search box searches
|
||||
var BROWSE_TEXT_LEN = 30; // genres/artists/albums select options longer than this will have
|
||||
// a title attribute (to show a tool tip for items that doesn't fit the box
|
||||
var g_myLiveGrid; // the live grid;
|
||||
function initPlaylist() {
|
||||
Ajax.Responders.register({ onCreate: Spinner.incRequestCount,
|
||||
onComplete: Spinner.decRequestCount});
|
||||
|
||||
new Ajax.Request('databases/1/containers?output=xml',{method: 'get',onComplete:rsSource});
|
||||
Query.send('genres');
|
||||
Event.observe('search','keypress',EventHandler.searchKeyPress);
|
||||
Event.observe('source','change',EventHandler.sourceChange);
|
||||
Event.observe('source','click',EventHandler.sourceClick);
|
||||
Event.observe('source','keypress',EventHandler.sourceKeyPress);
|
||||
Event.observe('genres','change',EventHandler.genresChange);
|
||||
Event.observe('artists','change',EventHandler.artistsChange);
|
||||
Event.observe('albums','change',EventHandler.albumsChange);
|
||||
Event.observe('add_playlist_href','click',EventHandler.addPlaylistHrefClick);
|
||||
|
||||
Event.observe(document,'click',GlobalEvents.click);
|
||||
Event.observe('edit_playlist_name','keypress',EventHandler.editPlaylistNameKeyPress);
|
||||
Event.observe('songs_data','click',SelectedRows.click);
|
||||
// Firefox remebers the search box value on page reload
|
||||
Field.clear('search');
|
||||
g_myLiveGrid = new Rico.LiveGrid('songs_data',20,1000,'',{prefetchBuffer: false});
|
||||
|
||||
for (var i = $('songs_data').rows.length - 1; i >= 0; --i) {
|
||||
dndMgr.registerDraggable(new CustomDraggable($('songs_data').rows[i], "bob " + i));
|
||||
}
|
||||
}
|
||||
var Spinner = {
|
||||
count: 0,
|
||||
incRequestCount: function (ca) {
|
||||
Spinner.count++;
|
||||
$('spinner').style.visibility = 'visible';
|
||||
},
|
||||
decRequestCount: function (caller) {
|
||||
Spinner.count--;
|
||||
if (/type=browse/.test(caller.url)) {
|
||||
Spinner.count = 0;
|
||||
$('spinner').style.visibility = 'hidden';
|
||||
}
|
||||
}
|
||||
};
|
||||
var GlobalEvents = {
|
||||
_clickListeners: [],
|
||||
click: function (e) {
|
||||
GlobalEvents._clickListeners.each(function (name) {
|
||||
name.click(e);
|
||||
});
|
||||
},
|
||||
addClickListener: function (el) {
|
||||
this._clickListeners.push(el);
|
||||
},
|
||||
removeClickListener: function (el) {
|
||||
this._clickListeners = this._clickListeners.findAll(function (element) {
|
||||
return (element != el);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var Source = {
|
||||
playlistId: '',
|
||||
playlistName: '',
|
||||
_getOptionElement: function (id) {
|
||||
return option = $A($('source').getElementsByTagName('option')).find(function (el) {
|
||||
return (el.value == id);
|
||||
});
|
||||
},
|
||||
addPlaylist: function () {
|
||||
var url = 'databases/1/containers/add?output=xml';
|
||||
var name= 'untitled playlist';
|
||||
if (this._playlistExists(name)) {
|
||||
var i=1;
|
||||
while (this._playlistExists(name +' ' + i)) {
|
||||
i++;
|
||||
}
|
||||
name += ' ' +i;
|
||||
}
|
||||
this.playlistName = name;
|
||||
url += '&org.mt-daapd.playlist-type=0&dmap.itemname=' + encodeURIComponent(name);
|
||||
new Ajax.Request(url ,{method: 'get',onComplete:this.responseAdd});
|
||||
},
|
||||
_playlistExists: function (name) {
|
||||
return $A($('source').getElementsByTagName('option')).pluck('firstChild').find(function (el) {
|
||||
return el.nodeValue == name;
|
||||
});
|
||||
},
|
||||
removePlaylist: function () {
|
||||
if (window.confirm('Really delete playlist?')) {
|
||||
var url = 'databases/1/containers/del?output=xml';
|
||||
url += '&dmap.itemid=' + $('source').value;
|
||||
new Ajax.Request(url ,{method: 'get',onComplete:this.response});
|
||||
var option = this._getOptionElement($('source').value);
|
||||
Element.remove(option);
|
||||
}
|
||||
},
|
||||
savePlaylistName: function () {
|
||||
input = $('edit_playlist_name');
|
||||
var url = 'databases/1/containers/edit?output=xml';
|
||||
url += '&dmap.itemid=' + Source.playlistId;
|
||||
url += '&dmap.itemname=' + encodeURIComponent(input.value);
|
||||
new Ajax.Request(url ,{method: 'get',onComplete:this.response});
|
||||
var option = this._getOptionElement(Source.playlistId);
|
||||
option.text = input.value;
|
||||
this.hideEditPlaylistName();
|
||||
},
|
||||
editPlaylistName: function () {
|
||||
input = $('edit_playlist_name');
|
||||
Source.playlistId = $('source').value;
|
||||
playlistName = Element.textContent(this._getOptionElement(Source.playlistId));
|
||||
//###FIXME use prototype Position instead
|
||||
input.style.top = RicoUtil.toDocumentPosition(this._getOptionElement(Source.playlistId)).y + 'px';
|
||||
input.value = playlistName;
|
||||
input.style.display = 'block';
|
||||
Field.activate(input);
|
||||
GlobalEvents.addClickListener(this);
|
||||
},
|
||||
hideEditPlaylistName: function () {
|
||||
$('edit_playlist_name').style.display = 'none';
|
||||
Field.activate('source');
|
||||
Source.playlistId = '';
|
||||
GlobalEvents.removeClickListener(this);
|
||||
},
|
||||
response: function (request) {
|
||||
// Check that the save gave response 200 OK
|
||||
},
|
||||
responseAdd: function(request) {
|
||||
var status = Element.textContent(request.responseXML.getElementsByTagName('dmap.status')[0]);
|
||||
if ('200' != status) {
|
||||
//###FIXME if someone else adds a playlist with the same name
|
||||
// as mine, (before My page is refreshed) won't happen that often
|
||||
alert('There is a playlist with that name, write some code to handle this');
|
||||
return;
|
||||
}
|
||||
Source.playlistId = Element.textContent(request.responseXML.getElementsByTagName('dmap.itemid')[0]);
|
||||
var o = document.createElement('option');
|
||||
o.value = Source.playlistId;
|
||||
o.text = Source.playlistName;
|
||||
$('static_playlists').appendChild(o);
|
||||
$('source').value = Source.playlistId;
|
||||
Source.editPlaylistName();
|
||||
Query.setSource(Source.playlistId);
|
||||
Query.send('genres');
|
||||
},
|
||||
click: function (e) {
|
||||
//###FIXME use prototype Position instead
|
||||
var x = Event.pointerX(e);
|
||||
var y = Event.pointerY(e);
|
||||
var el = $('edit_playlist_name');
|
||||
var pos = RicoUtil.toViewportPosition(el);
|
||||
if ((x > pos.x) && (x < pos.x + el.offsetWidth) &&
|
||||
(y > pos.y) && (y < pos.y + el.offsetHeight)) {
|
||||
// Click was in input box
|
||||
return;
|
||||
}
|
||||
Source.savePlaylistName();
|
||||
}
|
||||
};
|
||||
|
||||
var EventHandler = {
|
||||
searchTimeOut: '',
|
||||
sourceClickCount: [],
|
||||
sourceClick: function (e) {
|
||||
var playlistId = Event.element(e).value;
|
||||
if (1 == playlistId) {
|
||||
// do nothing for Library
|
||||
return;
|
||||
}
|
||||
if (EventHandler.sourceClickCount[playlistId]) {
|
||||
EventHandler.sourceClickCount[playlistId]++;
|
||||
} else {
|
||||
EventHandler.sourceClickCount[playlistId] = 1;
|
||||
}
|
||||
if (EventHandler.sourceClickCount[playlistId] > 1) {
|
||||
el = Event.element(e);
|
||||
if (!document.all && !el.text) {
|
||||
// IE sends the select in the event, not the option
|
||||
// Firefox generates and event when clicking in and empty area
|
||||
// of the select box
|
||||
return;
|
||||
}
|
||||
Source.editPlaylistName();
|
||||
}
|
||||
},
|
||||
sourceChange: function (e) {
|
||||
EventHandler.sourceClickCount = [];
|
||||
Field.clear('search');
|
||||
var playlistId = $('source').value;
|
||||
Query.setSource(playlistId);
|
||||
Query.send('genres');
|
||||
},
|
||||
sourceKeyPress: function (e) {
|
||||
if (e.keyCode == Event.KEY_DELETE) {
|
||||
Source.removePlaylist();
|
||||
}
|
||||
if (113 == e.keyCode) {
|
||||
// F2
|
||||
//TODO edit playist, what is the key on a mac?
|
||||
}
|
||||
},
|
||||
editPlaylistNameKeyPress: function (e) {
|
||||
input = $('edit_playlist_name');
|
||||
if (e.keyCode == Event.KEY_ESC) {
|
||||
Source.hideEditPlaylistName();
|
||||
}
|
||||
if (e.keyCode == Event.KEY_RETURN) {
|
||||
Source.savePlaylistName();
|
||||
}
|
||||
},
|
||||
addPlaylistHrefClick: function (e) {
|
||||
Source.addPlaylist();
|
||||
},
|
||||
searchKeyPress: function (e) {
|
||||
if (EventHandler.searchTimeOut) {
|
||||
window.clearTimeout(EventHandler.searchTimeOut);
|
||||
}
|
||||
if (e.keyCode == Event.KEY_RETURN) {
|
||||
EventHandler._search();
|
||||
} else {
|
||||
EventHandler.searchTimeOut = window.setTimeout(EventHandler._search,SEARCH_DELAY);
|
||||
}
|
||||
},
|
||||
_search: function () {
|
||||
Query.setSearchString($('search').value);
|
||||
Query.send('genres');
|
||||
},
|
||||
genresChange: function (e) {
|
||||
EventHandler._setSelected('genres');
|
||||
Query.send('artists');
|
||||
},
|
||||
artistsChange: function (e) {
|
||||
EventHandler._setSelected('artists');
|
||||
Query.send('albums');
|
||||
},
|
||||
albumsChange: function (e) {
|
||||
EventHandler._setSelected('albums');
|
||||
SelectedRows.clearAll();
|
||||
g_myLiveGrid.resetContents();
|
||||
g_myLiveGrid.requestContentRefresh(0);
|
||||
// Query.send('songs');
|
||||
},
|
||||
_setSelected: function (type) {
|
||||
var options = $A($(type).options);
|
||||
Query.clearSelection(type);
|
||||
if ($(type).value != 'all') {
|
||||
options.each(function (option) {
|
||||
if (option.selected) {
|
||||
Query.addSelection(type,option.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var Query = {
|
||||
baseUrl: '/rsp/db/',
|
||||
playlistId: '1',
|
||||
genres: [],
|
||||
artists:[],
|
||||
albums: [],
|
||||
busy: '',
|
||||
searchString: '',
|
||||
clearSelection: function (type) {
|
||||
this[type] = [];
|
||||
},
|
||||
addSelection: function (type,value){
|
||||
this[type].push(value);
|
||||
},
|
||||
setSearchString: function (string) {
|
||||
this.searchString = string;
|
||||
},
|
||||
setSource: function (playlistId) {
|
||||
Query.clearSelection('genres');
|
||||
Query.clearSelection('artists');
|
||||
Query.clearSelection('albums');
|
||||
Query.setSearchString('');
|
||||
Query.playlistId = playlistId;
|
||||
},
|
||||
getUrl: function (type) {
|
||||
var query=[];
|
||||
switch (type) {
|
||||
case 'artists':
|
||||
if (this.genres.length > 0) {
|
||||
query = this.genres.collect(function(value){return 'genre%3D"'+value.encode()+'"';});
|
||||
}
|
||||
break;
|
||||
case 'albums':
|
||||
if (this.artists.length > 0) {
|
||||
query = this.artists.collect(function(value){return 'artist%3D"'+value.encode()+'"';});
|
||||
} else if (this.genres.length > 0) {
|
||||
query = this.genres.collect(function(value){return 'genre%3D"'+value.encode()+'"';});
|
||||
}
|
||||
break;
|
||||
case 'songs':
|
||||
if (this.albums.length > 0) {
|
||||
query = this.albums.collect(function(value){return 'album%3D"'+value.encode()+'"';});
|
||||
} else if (this.artists.length > 0) {
|
||||
query = this.artists.collect(function(value){return 'artist%3D"'+value.encode()+'"';});
|
||||
} else if (this.genres.length > 0) {
|
||||
query = this.genres.collect(function(value){return 'genre%3D"'+value.encode()+'"';});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
if (this.searchString) {
|
||||
var search = [];
|
||||
var string = this.searchString.encode();
|
||||
['genre','artist','album','title'].each(function (item) {
|
||||
search.push(item +' includes "' + string + '"');
|
||||
});
|
||||
if (query.length > 0) {
|
||||
return '&query=(' + search.join(' or ') + ') and ('.encode() + query.join(' or ')+ ')';
|
||||
} else {
|
||||
return '&query=' + search.join(' or ');
|
||||
}
|
||||
} else {
|
||||
if (query.length > 0) {
|
||||
return '&query=' + query.join(' or ');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
getFullUrl: function (type) {
|
||||
this.busy = true;
|
||||
var url;
|
||||
var handler;
|
||||
var meta = '';
|
||||
switch (type) {
|
||||
case 'genres':
|
||||
url = '/genre';
|
||||
break;
|
||||
case 'artists':
|
||||
url = '/artist';
|
||||
break;
|
||||
case 'albums':
|
||||
url = '/album';
|
||||
break;
|
||||
case 'songs':
|
||||
url = '';
|
||||
meta = '&type=browse';
|
||||
break;
|
||||
default:
|
||||
alert("Shouldn't happen 2");
|
||||
break;
|
||||
}
|
||||
return this.baseUrl + this.playlistId + url + '?dummy=' + meta + this.getUrl(type);
|
||||
},
|
||||
send: function(type) {
|
||||
if (('genres' == type) || ('artists' == type) || ('albums' == type)) {
|
||||
handler = ResponseHandler[type];
|
||||
} else {
|
||||
return;
|
||||
// handler = rsSongs;
|
||||
}
|
||||
new Ajax.Request(this.getFullUrl(type), {method: 'get',onComplete:handler});
|
||||
}
|
||||
};
|
||||
var ResponseHandler = {
|
||||
genres: function (request) {
|
||||
ResponseHandler._genreAlbumArtist(request,'genres');
|
||||
},
|
||||
artists: function (request) {
|
||||
ResponseHandler._genreAlbumArtist(request,'artists');
|
||||
},
|
||||
albums: function (request) {
|
||||
ResponseHandler._genreAlbumArtist(request,'albums');
|
||||
},
|
||||
_genreAlbumArtist: function (request,type) {
|
||||
var items = $A(request.responseXML.getElementsByTagName('item'));
|
||||
items = items.collect(function (el) {
|
||||
return Element.textContent(el);
|
||||
}).sort();
|
||||
var select = $(type);
|
||||
Element.removeChildren(select);
|
||||
|
||||
var o = document.createElement('option');
|
||||
o.value = 'all';
|
||||
o.appendChild(document.createTextNode('All (' + items.length + ' ' + type + ')'));
|
||||
select.appendChild(o);
|
||||
var selected = {};
|
||||
Query[type].each(function(item) {
|
||||
selected[item] = true;
|
||||
});
|
||||
Query.clearSelection(type);
|
||||
if (ResponseHandler._addOptions(type,items,selected)) {
|
||||
select.value='all';
|
||||
}
|
||||
switch (type) {
|
||||
case 'genres':
|
||||
Query.send('artists');
|
||||
break;
|
||||
case 'artists':
|
||||
Query.send('albums');
|
||||
break;
|
||||
case 'albums':
|
||||
SelectedRows.clearAll();
|
||||
g_myLiveGrid.resetContents();
|
||||
g_myLiveGrid.requestContentRefresh(0);
|
||||
// Query.send('songs');
|
||||
break;
|
||||
default:
|
||||
alert("Shouldn't happen 3");
|
||||
break;
|
||||
}
|
||||
},
|
||||
_addOptions: function (type,options,selected) {
|
||||
el = $(type);
|
||||
var nothingSelected = true;
|
||||
options.each(function (option) {
|
||||
var node;
|
||||
//###FIXME I have no idea why the Builder.node can't create options
|
||||
// with the selected state I want.
|
||||
var o = document.createElement('option');
|
||||
o.value = option;
|
||||
if (option.length >= BROWSE_TEXT_LEN) {
|
||||
o.title = option;
|
||||
}
|
||||
o.appendChild(document.createTextNode(option));
|
||||
if (selected[option]) {
|
||||
o.selected = true;
|
||||
nothingSelected = false;
|
||||
Query.addSelection(type,option);
|
||||
} else {
|
||||
o.selected = false;
|
||||
}
|
||||
el.appendChild(o);
|
||||
});
|
||||
return nothingSelected;
|
||||
}
|
||||
};
|
||||
|
||||
function rsSource(request) {
|
||||
var items = $A(request.responseXML.getElementsByTagName('dmap.listingitem'));
|
||||
var sourceSelect = $('source');
|
||||
var smartPlaylists = [];
|
||||
var staticPlaylists = [];
|
||||
Element.removeChildren(sourceSelect);
|
||||
|
||||
items.each(function (item,index) {
|
||||
if (0 === index) {
|
||||
// Skip Library
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.getElementsByTagName('com.apple.itunes.smart-playlist').length > 0) {
|
||||
smartPlaylists.push({name: Element.textContent(item.getElementsByTagName('dmap.itemname')[0]),
|
||||
id: Element.textContent(item.getElementsByTagName('dmap.itemid')[0])});
|
||||
} else {
|
||||
staticPlaylists.push({name: Element.textContent(item.getElementsByTagName('dmap.itemname')[0]),
|
||||
id: Element.textContent(item.getElementsByTagName('dmap.itemid')[0])});
|
||||
}
|
||||
});
|
||||
sourceSelect.appendChild(Builder.node('option',{value: '1'},'Library'));
|
||||
if (smartPlaylists.length > 0) {
|
||||
optgroup = Builder.node('optgroup',{label: 'Smart playlists'});
|
||||
smartPlaylists.each(function (item) {
|
||||
var option = document.createElement('option');
|
||||
optgroup.appendChild(Builder.node('option',{value: item.id},item.name));
|
||||
});
|
||||
sourceSelect.appendChild(optgroup);
|
||||
}
|
||||
if (staticPlaylists.length > 0) {
|
||||
optgroup = Builder.node('optgroup',{label: 'Static playlists',id: 'static_playlists'});
|
||||
staticPlaylists.each(function (item) {
|
||||
var option = document.createElement('option');
|
||||
optgroup.appendChild(Builder.node('option',{value: item.id},item.name));
|
||||
});
|
||||
sourceSelect.appendChild(optgroup);
|
||||
|
||||
|
||||
var options = $('static_playlists').getElementsByTagName("option");
|
||||
for (var j = 0; j < options.length; j++) {
|
||||
dndMgr.registerDropZone(new CustomDropzone(options[j], $('static_playlists')));
|
||||
}
|
||||
}
|
||||
// Select Library
|
||||
sourceSelect.value = 1;
|
||||
}
|
||||
|
||||
SelectedRows = {
|
||||
songId: [],
|
||||
click: function(e) {
|
||||
var tr = Event.findElement(e,'tr');
|
||||
var id = tr.getAttribute('songid');
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
if (e.ctrlKey) {
|
||||
if (SelectedRows.isSelected(tr)) {
|
||||
SelectedRows.unsetSelected(tr);
|
||||
} else {
|
||||
SelectedRows.setSelected(tr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (e.shiftKey) {
|
||||
return;
|
||||
}
|
||||
if (SelectedRows.isSelected(tr)) {
|
||||
SelectedRows.clearAll();
|
||||
} else {
|
||||
SelectedRows.clearAll();
|
||||
SelectedRows.setSelected(tr);
|
||||
}
|
||||
},
|
||||
isSelected: function (tr) {
|
||||
return SelectedRows.songId[tr.getAttribute('songid')];
|
||||
},
|
||||
setSelected: function (tr) {
|
||||
SelectedRows.songId[tr.getAttribute('songid')] = tr.getAttribute('index');
|
||||
tr.style.backgroundColor = '#8CACBB';
|
||||
},
|
||||
unsetSelected: function (tr) {
|
||||
SelectedRows.songId[tr.getAttribute('songid')] = '';
|
||||
tr.style.backgroundColor = '';
|
||||
},
|
||||
clearAll: function () {
|
||||
SelectedRows.songId = [];
|
||||
$A($('songs_data').getElementsByTagName('tr')).each(SelectedRows.unsetSelected);
|
||||
},
|
||||
updateState: function (tr,songId,index) {
|
||||
if (songId && (index || 0 === index)) {
|
||||
// 0 == false but we want to catch index == 0
|
||||
tr.setAttribute('songid',songId);
|
||||
tr.setAttribute('index',index);
|
||||
if (SelectedRows.isSelected(tr)) {
|
||||
SelectedRows.setSelected(tr);
|
||||
} else {
|
||||
SelectedRows.unsetSelected(tr);
|
||||
}
|
||||
} else {
|
||||
tr.setAttribute('songid','');
|
||||
tr.setAttribute('index','');
|
||||
SelectedRows.unsetSelected(tr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
String.prototype.encode = function () {
|
||||
return encodeURIComponent(this).replace(/\'/g,"\\'");
|
||||
};
|
||||
// Stolen from prototype 1.5
|
||||
String.prototype.truncate = function(length, truncation) {
|
||||
length = length || 30;
|
||||
truncation = truncation === undefined ? '...' : truncation;
|
||||
var ret = (this.length > length) ? this.slice(0, length - truncation.length) + truncation : this;
|
||||
return '' + ret;
|
||||
};
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
|
||||
Correctly handle PNG transparency in Win IE 5.5 & 6.
|
||||
http://homepage.ntlworld.com/bobosola. Updated 18-Jan-2006.
|
||||
|
||||
Use in <HEAD> with DEFER keyword wrapped in conditional comments:
|
||||
<!--[if lt IE 7]>
|
||||
<script defer type="text/javascript" src="pngfix.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
*/
|
||||
|
||||
var arVersion = navigator.appVersion.split("MSIE")
|
||||
var version = parseFloat(arVersion[1])
|
||||
|
||||
if ((version >= 5.5) && (document.body.filters))
|
||||
{
|
||||
for(var i=0; i<document.images.length; i++)
|
||||
{
|
||||
var img = document.images[i]
|
||||
var imgName = img.src.toUpperCase()
|
||||
if (imgName.substring(imgName.length-3, imgName.length) == "PNG")
|
||||
{
|
||||
var imgID = (img.id) ? "id='" + img.id + "' " : ""
|
||||
var imgClass = (img.className) ? "class='" + img.className + "' " : ""
|
||||
var imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' "
|
||||
var imgStyle = "display:inline-block;" + img.style.cssText
|
||||
if (img.align == "left") imgStyle = "float:left;" + imgStyle
|
||||
if (img.align == "right") imgStyle = "float:right;" + imgStyle
|
||||
if (img.parentElement.href) imgStyle = "cursor:hand;" + imgStyle
|
||||
var strNewHTML = "<span " + imgID + imgClass + imgTitle
|
||||
+ " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
|
||||
+ "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
|
||||
+ "(src=\'" + img.src + "\', sizingMethod='scale');\"></span>"
|
||||
img.outerHTML = strNewHTML
|
||||
i = i-1
|
||||
}
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 47 B |
@ -1,44 +0,0 @@
|
||||
@include hdr.html@
|
||||
|
||||
<h2>Smart Playlists</h2>
|
||||
<table cellspacing="0" >
|
||||
<thead><tr><th>ID</th><th>Playlist Name</th><th>Type</th><th>Count</th><th>Action</th></tr></thead>
|
||||
<tbody id="playlists">
|
||||
<tr><td></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="javascript:pl_new();">Add new playlist</a>
|
||||
|
||||
<div id="pl_data">
|
||||
</div>
|
||||
|
||||
<div id="pl_editor" style="display: none;">
|
||||
<div class="naviheader">
|
||||
New playlist
|
||||
</div>
|
||||
<div class="navibox">
|
||||
<form id="pl_form" action="">
|
||||
<div>
|
||||
<input type="hidden" name="playlist_id" id="playlist_id" />
|
||||
<label for="playlist_name">Name</label>
|
||||
<input id="playlist_name" class="playlistfield" type="text" name="playlist_name" />
|
||||
<br />
|
||||
<label for="playlist_spec">Playlist criteria</label>
|
||||
<textarea id="playlist_spec" class="playlistfield" rows="5" cols="50" name="playlist_spec"></textarea>
|
||||
<br />
|
||||
<div id="playlist_buttons">
|
||||
<input type="button" onclick="javascript:pl_update();" name="submit_button" value="Submit"/>
|
||||
<input type="button" onclick="javascript:pl_cancel();" value="Cancel"/>
|
||||
<input type="button" onclick="javascript:popUp('smartpopup.html');" value="Wizard"/>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div id="pl_warning" class="message" style="display:none;">
|
||||
Error messages go here...
|
||||
</div>
|
||||
|
||||
@include ftr.html@
|
@ -1,265 +0,0 @@
|
||||
var req;
|
||||
var playlist_info={};
|
||||
var g_messageTimeout;
|
||||
|
||||
function pl_editor_state(state) {
|
||||
var pleditor = document.getElementById("pl_editor");
|
||||
if(!pleditor)
|
||||
return;
|
||||
|
||||
if(state) {
|
||||
pleditor.style.display="block";
|
||||
} else {
|
||||
pleditor.style.display="none";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
function pl_errormsg(msg) {
|
||||
if (g_messageTimeout) {
|
||||
window.clearTimeout(g_messageTimeout);
|
||||
}
|
||||
var msgdiv = document.getElementById("pl_warning");
|
||||
|
||||
if(!msgdiv)
|
||||
return;
|
||||
|
||||
msgdiv.innerHTML = msg + "\n";
|
||||
|
||||
if(msg == "") {
|
||||
msgdiv.style.display="none";
|
||||
} else {
|
||||
Effect.Appear(msgdiv,{duration: 0.2});
|
||||
if (('Success' == msg) || 'Cancelled' == msg) {
|
||||
g_messageTimeout = window.setTimeout(function(){
|
||||
Effect.Fade(msgdiv,{duration: 0.2});
|
||||
},3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pl_displayresults(xmldoc,query) {
|
||||
var status_string;
|
||||
var status;
|
||||
|
||||
if(!xmldoc) {
|
||||
pl_errormsg("No xmldoc!");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!xmldoc.getElementsByTagName("dmap.status")) {
|
||||
pl_errormsg("No dmap.status??");
|
||||
return;
|
||||
}
|
||||
|
||||
status = xmldoc.getElementsByTagName("dmap.status")[0].firstChild.nodeValue;
|
||||
|
||||
if(!status)
|
||||
return;
|
||||
|
||||
status = status * 1;
|
||||
|
||||
if(status != 200) {
|
||||
status_string = "Error " + status + ": ";
|
||||
|
||||
if(xmldoc.getElementsByTagName("dmap.statusstring")) {
|
||||
status_string = status_string + xmldoc.getElementsByTagName("dmap.statusstring")[0].firstChild.nodeValue;
|
||||
} else {
|
||||
status_string = status_string + "Unspecified error";
|
||||
}
|
||||
|
||||
pl_errormsg(status_string);
|
||||
} else {
|
||||
pl_editor_state(false);
|
||||
pl_errormsg("Success");
|
||||
}
|
||||
}
|
||||
|
||||
function pl_update() {
|
||||
/* this is either update or create, depending... */
|
||||
pl_errormsg('');
|
||||
var id, name, spec;
|
||||
|
||||
id = document.getElementById('playlist_id').value;
|
||||
name = encodeURIComponent(document.getElementById('playlist_name').value);
|
||||
spec = encodeURIComponent(document.getElementById('playlist_spec').value);
|
||||
|
||||
if(id == '0') {
|
||||
/* new playlist... post it! */
|
||||
var url = 'databases/1/containers/add?output=xml&org.mt-daapd.playlist-type=1&dmap.itemname=' + name + '&org.mt-daapd.smart-playlist-spec=' + spec;
|
||||
result = pl_exec(url,false);
|
||||
} else {
|
||||
var url='databases/1/containers/edit?output=xml&dmap.itemid=' + id + '&dmap.itemname=' + name + '&org.mt-daapd.smart-playlist-spec=' + spec;
|
||||
result = pl_exec(url,false);
|
||||
}
|
||||
|
||||
pl_displayresults(req.responseXML);
|
||||
|
||||
init();
|
||||
// pl_editor_state(false);
|
||||
}
|
||||
|
||||
function pl_cancel() {
|
||||
pl_errormsg("Cancelled");
|
||||
pl_editor_state(false);
|
||||
}
|
||||
|
||||
function pl_new() {
|
||||
var msgdiv = document.getElementById("pl_warning");
|
||||
var pleditor=document.getElementById("pl_editor");
|
||||
|
||||
pl_errormsg("");
|
||||
|
||||
document.forms['pl_form']['playlist_id'].value='0';
|
||||
document.forms['pl_form']['playlist_name'].value = 'New Playlist';
|
||||
document.forms['pl_form']['playlist_spec'].value = '';
|
||||
document.forms['pl_form']['submit_button'].value = 'Create';
|
||||
|
||||
pl_editor_state(true);
|
||||
}
|
||||
|
||||
function pl_delete(pl_id) {
|
||||
if(confirm('Are you sure you want to delete playlist "' + playlist_info[pl_id]['name'] + '"?')) {
|
||||
result=pl_exec("databases/1/containers/del?output=xml&dmap.itemid=" + pl_id,false);
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function pl_edit(pl_id) {
|
||||
var msgdiv = document.getElementById("pl_warning");
|
||||
var pleditor=document.getElementById("pl_editor");
|
||||
|
||||
if((!msgdiv)||(!pleditor))
|
||||
return;
|
||||
|
||||
msgdiv.style.display="none";
|
||||
pleditor.style.display="none";
|
||||
|
||||
if(pl_id == 1) {
|
||||
msgdiv.innerHTML="Cannot edit library playlist";
|
||||
msgdiv.style.display="block";
|
||||
return;
|
||||
}
|
||||
|
||||
if(playlist_info[pl_id]['type'] != 1) {
|
||||
msgdiv.innerHTML="Can only edit smart playlists";
|
||||
msgdiv.style.display="block";
|
||||
return;
|
||||
}
|
||||
|
||||
document.forms['pl_form']['playlist_id'].value = pl_id;
|
||||
document.forms['pl_form']['playlist_name'].value = playlist_info[pl_id]['name'];
|
||||
document.forms['pl_form']['playlist_spec'].value = playlist_info[pl_id]['spec'];
|
||||
document.forms['pl_form']['submit_button'].value = 'Update';
|
||||
|
||||
pleditor.style.display="block";
|
||||
|
||||
//alert(playlist_info[pl_id]['name']);
|
||||
}
|
||||
|
||||
function pl_process() {
|
||||
var xmldoc = req.responseXML;
|
||||
var playlists = xmldoc.getElementsByTagName("dmap.listingitem");
|
||||
var pl_table = document.getElementById("playlists");
|
||||
playlist_info = {};
|
||||
|
||||
while(pl_table.childNodes.length > 0) {
|
||||
pl_table.removeChild(pl_table.lastChild);
|
||||
}
|
||||
for(var x=0; x < playlists.length; x++) {
|
||||
var pl_id;
|
||||
var pl_name;
|
||||
var pl_type;
|
||||
var pl_count;
|
||||
|
||||
pl_id=playlists[x].getElementsByTagName("dmap.itemid")[0].firstChild.nodeValue;
|
||||
if(playlists[x].getElementsByTagName("dmap.itemname")[0].firstChild) {
|
||||
pl_name=playlists[x].getElementsByTagName("dmap.itemname")[0].firstChild.nodeValue;
|
||||
} else {
|
||||
pl_name = "";
|
||||
}
|
||||
pl_type=playlists[x].getElementsByTagName("org.mt-daapd.playlist-type")[0].firstChild.nodeValue;
|
||||
pl_count=playlists[x].getElementsByTagName("dmap.itemcount")[0].firstChild.nodeValue;
|
||||
|
||||
|
||||
playlist_info[String(pl_id)] = { 'name': pl_name, 'type': pl_type };
|
||||
if(pl_type == 1) {
|
||||
var pl_spec=playlists[x].getElementsByTagName("org.mt-daapd.smart-playlist-spec")[0].firstChild.nodeValue;
|
||||
playlist_info[String(pl_id)]['spec'] = pl_spec;
|
||||
}
|
||||
|
||||
switch(pl_type) {
|
||||
case "0":
|
||||
pl_type = "Static (Web Edited)";
|
||||
break;
|
||||
case "1":
|
||||
pl_type = "Smart";
|
||||
break;
|
||||
case "2":
|
||||
pl_type = "Static (m3u/pls file)";
|
||||
break;
|
||||
case "3":
|
||||
pl_type = "Static (iTunes xml)";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
var row = document.createElement("tr");
|
||||
var td1 = document.createElement("td");
|
||||
var td2 = document.createElement("td");
|
||||
var td3 = document.createElement("td");
|
||||
var td4 = document.createElement("td");
|
||||
var td5 = document.createElement("td");
|
||||
|
||||
td1.innerHTML=pl_id + '\n';
|
||||
td2.innerHTML=pl_name + '\n';
|
||||
td3.innerHTML=pl_type + '\n';
|
||||
td4.innerHTML=pl_count + '\n';
|
||||
if((pl_id != 1) && (playlist_info[pl_id]['type'] == 1)) {
|
||||
td5.innerHTML='<a href="javascript:pl_edit(' + pl_id + ')">Edit</a>';
|
||||
td5.innerHTML = td5.innerHTML + ' <a href="javascript:pl_delete(' + pl_id + ')">Delete</a>';
|
||||
} else {
|
||||
td5.innerHTML=" ";
|
||||
}
|
||||
|
||||
row.appendChild(td1);
|
||||
row.appendChild(td2);
|
||||
row.appendChild(td3);
|
||||
row.appendChild(td4);
|
||||
row.appendChild(td5);
|
||||
pl_table.appendChild(row);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function pl_state_change() {
|
||||
if(req.readyState == 4) {
|
||||
if(req.status == 200) {
|
||||
pl_process();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
pl_exec("databases/1/containers?output=xml&meta=dmap.itemid,dmap.itemname,org.mt-daapd.playlist-type,org.mt-daapd.smart-playlist-spec",true);
|
||||
}
|
||||
|
||||
function pl_exec(url, async) {
|
||||
// branch for native XMLHttpRequest object
|
||||
if (window.XMLHttpRequest) {
|
||||
req = new XMLHttpRequest();
|
||||
req.onreadystatechange = pl_state_change;
|
||||
req.open("GET", url, async);
|
||||
return req.send(null);
|
||||
// branch for IE/Windows ActiveX version
|
||||
} else if (window.ActiveXObject) {
|
||||
req = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
if (req) {
|
||||
req.onreadystatechange = pl_state_change;
|
||||
req.open("GET", url, async);
|
||||
return req.send();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,386 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>Firefly playlist wizard</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<link rel="stylesheet" type="text/css" href="firefly.css" />
|
||||
</head>
|
||||
<script language="JavaScript" type="text/javascript">
|
||||
|
||||
function loadOpenerCriteria()
|
||||
{
|
||||
objSpec = window.opener.document.getElementsByName("playlist_spec");
|
||||
args = objSpec[0].value.split(" ");
|
||||
comb = '';
|
||||
// 1. Convert string params with spaces to single array entries
|
||||
i = 2;
|
||||
while (i<args.length)
|
||||
{ s = args[i];
|
||||
cB = s.charAt(0);
|
||||
cE = s.charAt(s.length-1);
|
||||
if ( (cB=='"') & (cE!='"'))
|
||||
{ j = i;
|
||||
do
|
||||
{ j++;
|
||||
s += (" "+args[j]);
|
||||
cE = s.charAt(s.length-1);
|
||||
} while (cE!='"');
|
||||
args.splice(i,(j-i+1),s);
|
||||
}
|
||||
i += 4;
|
||||
}
|
||||
// 2. Parse array into list
|
||||
if (((args.length%4)==3))
|
||||
{ critIndex = Math.round(args.length / 4);
|
||||
critMax = critIndex;
|
||||
while (args.length>=3)
|
||||
{ eleData = args.pop();
|
||||
eleComp = args.pop();
|
||||
eleField = args.pop();
|
||||
plSetCriterion(critIndex,eleField,eleComp,eleData);
|
||||
|
||||
if (args.length>0)
|
||||
{ if (critIndex==critMax)
|
||||
{ comb = args.pop(); }
|
||||
else { blub = args.pop(); }
|
||||
critIndex--;
|
||||
}
|
||||
}
|
||||
if (comb=='AND') plSetCriteriaCombination(0);
|
||||
else if (comb=='OR') plSetCriteriaCombination(1);
|
||||
}
|
||||
}
|
||||
|
||||
function blocking(nr)
|
||||
{
|
||||
if (document.layers)
|
||||
{
|
||||
current = (document.layers[nr].display == 'none') ? 'block' : 'none';
|
||||
document.layers[nr].display = current;
|
||||
}
|
||||
else if (document.all)
|
||||
{
|
||||
current = (document.all[nr].style.display == 'none') ? 'block' : 'none';
|
||||
document.all[nr].style.display = current;
|
||||
}
|
||||
else if (document.getElementById)
|
||||
{
|
||||
vista = (document.getElementById(nr).style.display == 'none') ? 'block' : 'none';
|
||||
document.getElementById(nr).style.display = vista;
|
||||
}
|
||||
}
|
||||
|
||||
function visi(nr)
|
||||
{
|
||||
if (document.layers)
|
||||
{
|
||||
vista = (document.layers[nr].visibility == 'hide') ? 'show' : 'hide'
|
||||
document.layers[nr].visibility = vista;
|
||||
}
|
||||
else if (document.all)
|
||||
{
|
||||
vista = (document.all[nr].style.visibility == 'hidden') ? 'visible' : 'hidden';
|
||||
document.all[nr].style.visibility = vista;
|
||||
}
|
||||
else if (document.getElementById)
|
||||
{
|
||||
vista = (document.getElementById(nr).style.visibility == 'hidden') ? 'visible' : 'hidden';
|
||||
document.getElementById(nr).style.visibility = vista;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function plRowHide(x)
|
||||
{ //objRow = document.getElementById("rowcrit"+x);
|
||||
//objRow.visible = false;
|
||||
//visi("rowcrit"+x);
|
||||
}
|
||||
|
||||
function plRowShow(x)
|
||||
{ //objRow = document.getElementById("rowcrit"+x);
|
||||
//objRow.visible = true;
|
||||
//visi("rowcrit"+x);
|
||||
// vista = (document.getElementById("rowcrit"+x).style.visibility == 'hidden') ? 'visible' : 'hidden';
|
||||
// vista = 'visible';
|
||||
// document.getElementById("rowcrit"+x).style.visibility = vista;
|
||||
}
|
||||
|
||||
function plOutputRow(x,vis)
|
||||
{ document.write('<tr id="rowcrit',x,'" style="visibility:');
|
||||
document.write(vis?'visible':'hidden');
|
||||
document.write(';"><td>Criterion ',x,':<\/td>',
|
||||
'<td><select class="playlistfield" name="playlist_crit',x,'field" style="width:100%" onChange="javascript:plUpdateComp(\'',x,'\');plTemplateWizard()">',
|
||||
'<optgroup label="Basic">',
|
||||
'<option value="title">Title<\/option>',
|
||||
'<option value="artist">Artist<\/option>',
|
||||
'<option value="album">Album<\/option>',
|
||||
'<option value="genre">Genre<\/option>',
|
||||
'<option value="year">Year<\/option>',
|
||||
'<option value="rating">Rating<\/option>',
|
||||
'<option value="song_length">Length<\/option>',
|
||||
'<option value="play_count">Play count<\/option>',
|
||||
'<\/optgroup>',
|
||||
'<optgroup label="Advanced">',
|
||||
'<option value="track">Track<\/option>',
|
||||
'<option value="total_tracks">Tracks total<\/option>',
|
||||
'<option value="disc">Disc<\/option>',
|
||||
'<option value="total_discs">Discs total<\/option>',
|
||||
'<option value="comment">Comment<\/option>',
|
||||
'<option value="type">Type<\/option>',
|
||||
'<option value="composer">Composer<\/option>',
|
||||
'<option value="orchestra">Orchestra<\/option>',
|
||||
'<option value="grouping">Grouping<\/option>',
|
||||
'<option value="url">URL<\/option>',
|
||||
'<option value="description">Description<\/option>',
|
||||
'<\/optgroup>',
|
||||
'<optgroup label="Dates">',
|
||||
'<option value="time_added">Added<\/option>',
|
||||
'<option value="time_modified">Modified<\/option>',
|
||||
'<option value="time_played">Played<\/option>',
|
||||
'<\/optgroup>',
|
||||
'<optgroup label="Technical">',
|
||||
'<option value="bitrate">Bitrate<\/option>',
|
||||
'<option value="samplerate">Samplerate<\/option>',
|
||||
'<option value="file_size">Filesize<\/option>',
|
||||
'<option value="bpm">Beats per minute<\/option>',
|
||||
'<option value="compilation">Compilation<\/option>',
|
||||
'<option value="fname">Filename<\/option>',
|
||||
'<option value="path">Filepath<\/option>',
|
||||
'<\/optgroup>',
|
||||
'<\/select><\/td>',
|
||||
'<td><select class="playlistfield" name="playlist_crit',x,'comp" style="width:100%" onChange="javascript:plTemplateWizard()">',
|
||||
'<option value="=">=<\/option>',
|
||||
'<\/select><\/td>',
|
||||
'<td><input class="playlistfield" name="playlist_crit',x,'data" onChange="javascript:plTemplateWizard()" style="width:100%"/><\/td>');
|
||||
document.write('<\/tr>');
|
||||
}
|
||||
|
||||
function plGetCriterion(x)
|
||||
{ objField = document.getElementsByName("playlist_crit"+x+"field");
|
||||
objComp = document.getElementsByName("playlist_crit"+x+"comp");
|
||||
objData = document.getElementsByName("playlist_crit"+x+"data");
|
||||
y = '';
|
||||
if ((objField[0].value=='artist')
|
||||
|| (objField[0].value=='title')
|
||||
|| (objField[0].value=='album')
|
||||
|| (objField[0].value=='genre')
|
||||
|| (objField[0].value=='comment')
|
||||
|| (objField[0].value=='type')
|
||||
|| (objField[0].value=='composer')
|
||||
|| (objField[0].value=='orchestra')
|
||||
|| (objField[0].value=='conductor')
|
||||
|| (objField[0].value=='grouping')
|
||||
|| (objField[0].value=='url')
|
||||
|| (objField[0].value=='fname')
|
||||
|| (objField[0].value=='path')
|
||||
|| (objField[0].value=='description')
|
||||
|| (objField[0].value=='codectype'))
|
||||
y = '"';
|
||||
return objField[0].value+' '+objComp[0].value+' '+y+objData[0].value+y;
|
||||
}
|
||||
|
||||
function plSetCriterion(x,field,comp,data)
|
||||
{ objField = document.getElementsByName("playlist_crit"+x+"field");
|
||||
objField[0].value = field;
|
||||
plUpdateComp(x);
|
||||
objComp = document.getElementsByName("playlist_crit"+x+"comp");
|
||||
objData = document.getElementsByName("playlist_crit"+x+"data");
|
||||
objComp[0].value = comp;
|
||||
if (data.substr(0,1)=='"')
|
||||
objData[0].value = data.substr(1, data.length-2);
|
||||
else
|
||||
objData[0].value = data;
|
||||
}
|
||||
|
||||
function plSetCriteriaCombination(x)
|
||||
{ objSep = document.getElementsByName("playlist_combine");
|
||||
objSep[x].checked = true;
|
||||
}
|
||||
|
||||
function plIsUsed(x)
|
||||
{ objData = document.getElementsByName("playlist_crit"+x+"data");
|
||||
if (objData[0].value!='') return true; else return false;
|
||||
}
|
||||
|
||||
function plTemplateWizard()
|
||||
{ objSpec = window.opener.document.getElementsByName("playlist_spec");
|
||||
objSep = document.getElementsByName("playlist_combine");
|
||||
if (objSep[0].checked) sep = ' AND '; else sep = ' OR ';
|
||||
criteria = plGetCriterion('1');
|
||||
if (plIsUsed('2')) criteria = criteria + sep + plGetCriterion('2');
|
||||
objSpec[0].value = criteria;
|
||||
}
|
||||
|
||||
function plUpdateComp(x)
|
||||
{ objField = document.getElementsByName("playlist_crit"+x+"field");
|
||||
objComp = document.getElementsByName("playlist_crit"+x+"comp");
|
||||
objComp[0].options.length = 0;
|
||||
objComp[0].options[0] = new Option('=','=');
|
||||
objComp[0].options[1] = new Option('not =','not =');
|
||||
if ((objField[0].value=='artist')
|
||||
|| (objField[0].value=='title')
|
||||
|| (objField[0].value=='album')
|
||||
|| (objField[0].value=='genre')
|
||||
|| (objField[0].value=='comment')
|
||||
|| (objField[0].value=='type')
|
||||
|| (objField[0].value=='composer')
|
||||
|| (objField[0].value=='orchestra')
|
||||
|| (objField[0].value=='conductor')
|
||||
|| (objField[0].value=='grouping')
|
||||
|| (objField[0].value=='url')
|
||||
|| (objField[0].value=='fname')
|
||||
|| (objField[0].value=='path')
|
||||
|| (objField[0].value=='codectype'))
|
||||
{ objComp[0].options[2] = new Option('includes','includes');
|
||||
objComp[0].options[3] = new Option('not includes','not includes');
|
||||
objComp[0].options[4] = new Option('starts with','startswith');
|
||||
objComp[0].options[5] = new Option('not starts with','not startswith');
|
||||
objComp[0].options[6] = new Option('ends with','endswith');
|
||||
objComp[0].options[7] = new Option('not ends with','not endswith');
|
||||
} else if ((objField[0].value=='time_added')
|
||||
|| (objField[0].value=='time_modified')
|
||||
|| (objField[0].value=='time_played'))
|
||||
{ objComp[0].options[2] = new Option('before','before');
|
||||
objComp[0].options[3] = new Option('after','after');
|
||||
} else
|
||||
{ objComp[0].options[2] = new Option('>','>');
|
||||
objComp[0].options[3] = new Option('>=','>=');
|
||||
objComp[0].options[4] = new Option('<','<');
|
||||
objComp[0].options[5] = new Option('<=','<=');
|
||||
}
|
||||
}
|
||||
|
||||
function plTemplatePlaylist()
|
||||
{ objSpec = window.opener.document.getElementsByName("playlist_spec");
|
||||
objName = window.opener.document.getElementsByName("playlist_name");
|
||||
objTemplate = document.getElementsByName("playlist_template");
|
||||
switch (objTemplate[0].value)
|
||||
{ case "60s":
|
||||
objSpec[0].value = 'year >= 1960 AND year <= 1970';
|
||||
objName[0].value = 'Music from the 60s';
|
||||
plSetCriterion(1,'year','>=','1960');
|
||||
plSetCriterion(2,'year','<=','1970');
|
||||
plSetCriterion(3,'title','=','');
|
||||
plSetCriterion(4,'title','=','');
|
||||
plSetCriterion(5,'title','=','');
|
||||
plSetCriteriaCombination(0);
|
||||
break;
|
||||
case "70s":
|
||||
objSpec[0].value = 'year >= 1970 AND year <= 1980';
|
||||
objName[0].value = 'Music from the 70s';
|
||||
plSetCriterion(1,'year','>=','1970');
|
||||
plSetCriterion(2,'year','<=','1980');
|
||||
plSetCriterion(3,'title','=','');
|
||||
plSetCriterion(4,'title','=','');
|
||||
plSetCriterion(5,'title','=','');
|
||||
plSetCriteriaCombination(0);
|
||||
break;
|
||||
case "80s":
|
||||
objSpec[0].value = 'year >= 1980 AND year <= 1990';
|
||||
objName[0].value = 'Music from the 80s';
|
||||
plSetCriterion(1,'year','>=','1980');
|
||||
plSetCriterion(2,'year','<=','1990');
|
||||
plSetCriterion(3,'title','=','');
|
||||
plSetCriterion(4,'title','=','');
|
||||
plSetCriterion(5,'title','=','');
|
||||
plSetCriteriaCombination(0);
|
||||
break;
|
||||
case "90s":
|
||||
objSpec[0].value = 'year >= 1990 AND year <= 2000';
|
||||
objName[0].value = 'Music from the 90s';
|
||||
plSetCriterion(1,'year','>=','1990');
|
||||
plSetCriterion(2,'year','<=','2000');
|
||||
plSetCriterion(3,'title','=','');
|
||||
plSetCriterion(4,'title','=','');
|
||||
plSetCriterion(5,'title','=','');
|
||||
plSetCriteriaCombination(0);
|
||||
break;
|
||||
case "00s":
|
||||
objSpec[0].value = 'year >= 2000';
|
||||
objName[0].value = 'Music from today';
|
||||
plSetCriterion(1,'year','>=','2000');
|
||||
plSetCriterion(2,'title','=','');
|
||||
plSetCriterion(3,'title','=','');
|
||||
plSetCriterion(4,'title','=','');
|
||||
plSetCriterion(5,'title','=','');
|
||||
plSetCriteriaCombination(0);
|
||||
break;
|
||||
case "onemonth":
|
||||
objSpec[0].value = 'time_added after 1 month before today';
|
||||
objName[0].value = 'Recently added';
|
||||
plSetCriterion(1,'time_added','after','1 month before today');
|
||||
plSetCriterion(2,'title','=','');
|
||||
plSetCriterion(3,'title','=','');
|
||||
plSetCriterion(4,'title','=','');
|
||||
plSetCriterion(5,'title','=','');
|
||||
plSetCriteriaCombination(0);
|
||||
break;
|
||||
case "metal":
|
||||
objSpec[0].value = 'genre includes "Metal" OR genre includes "Goth" OR genre includes "Hard"';
|
||||
objName[0].value = 'Metalheads';
|
||||
plSetCriterion(1,'genre','includes','Metal');
|
||||
plSetCriterion(2,'genre','includes','Goth');
|
||||
plSetCriterion(3,'genre','includes','Hard');
|
||||
plSetCriterion(4,'title','=','');
|
||||
plSetCriterion(5,'title','=','');
|
||||
plSetCriteriaCombination(1);
|
||||
break;
|
||||
case "psych":
|
||||
objSpec[0].value = 'genre includes "psych" OR genre includes "Psych" OR genre includes "Synth" OR ARTIST = "Pink Floyd"';
|
||||
objName[0].value = 'Psychosynth';
|
||||
plSetCriterion(1,'genre','includes','psych');
|
||||
plSetCriterion(2,'genre','includes','Psych');
|
||||
plSetCriterion(3,'genre','includes','Synth');
|
||||
plSetCriterion(4,'artist','=','Pink Floyd');
|
||||
plSetCriterion(5,'title','=','');
|
||||
plSetCriteriaCombination(1);
|
||||
break;
|
||||
case "":
|
||||
objName[0].value = 'Custom playlist';
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<body onLoad="loadOpenerCriteria();">
|
||||
<form name="pleditor" action="">
|
||||
<input type="hidden" name="playlist_id"/>
|
||||
<table width="100%" cellspacing="0" style="font:icon;">
|
||||
|
||||
<tr><th>Wizard</th><th colspan="3"></th></tr>
|
||||
<tr><td>Template:</td>
|
||||
<td colspan="3"><select class="playlistfield" name="playlist_template" style="width:100%" onChange="javascript:plTemplatePlaylist()">
|
||||
<option value="" selected="SELECTED">Custom playlist</option>
|
||||
<option value="60s">Music from the 60s</option>
|
||||
<option value="70s">Music from the 70s</option>
|
||||
<option value="80s">Music from the 80s</option>
|
||||
<option value="90s">Music from the 90s</option>
|
||||
<option value="00s">Music from today</option>
|
||||
<option value="onemonth">Recently added</option>
|
||||
<option value="metal">Metalheads</option>
|
||||
<option value="psych">Psychosynth</option>
|
||||
</select></td></tr>
|
||||
|
||||
<script language="JavaScript" type="text/javascript">
|
||||
plOutputRow(1,true);
|
||||
plOutputRow(2,true);
|
||||
plOutputRow(3,true);
|
||||
plOutputRow(4,true);
|
||||
plOutputRow(5,true);
|
||||
</script>
|
||||
|
||||
<tr><td>Combine:</td>
|
||||
<td colspan="3">
|
||||
<input type="radio" name="playlist_combine" value=" AND " checked="CHECKED" onChange="javascript:plTemplateWizard()"> match all
|
||||
<input type="radio" name="playlist_combine" value=" OR " onChange="javascript:plTemplateWizard()"> match some
|
||||
</td></tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<script language="JavaScript" type="text/javascript">
|
||||
loadOpenerCriteria();
|
||||
</script>
|
||||
|
||||
<div style="text-align: center;">Check out the <a href="http://trac.fireflymediaserver.org/wiki/SmartPlaylists" target="_blank">Firefly Wiki</a> for details.</div>
|
||||
|
||||
</body></html>
|
Before Width: | Height: | Size: 842 B |
Before Width: | Height: | Size: 911 B |
@ -1,115 +0,0 @@
|
||||
Event.observe(window,'load',initStatus);
|
||||
|
||||
var UPDATE_FREQUENCY = 5000; // number of milliseconds between page updates
|
||||
|
||||
function initStatus(e) {
|
||||
Updater.update();
|
||||
// Bind events to the buttons
|
||||
Event.observe('button_stop_server','click',Updater.stopServer);
|
||||
Event.observe('button_start_scan','click',Updater.startScan);
|
||||
Event.observe('button_start_full_scan','click',Updater.startFullScan);
|
||||
}
|
||||
var Updater = {
|
||||
stop: false,
|
||||
wait: function () {
|
||||
Updater.updateTimeout = window.setTimeout(Updater.update,UPDATE_FREQUENCY);
|
||||
Updater.spinnerTimeout = window.setTimeout(Util.startSpinner,UPDATE_FREQUENCY-1000);
|
||||
},
|
||||
update: function () {
|
||||
if (Updater.updateTimeout) {
|
||||
window.clearTimeout(Updater.updateTimeout);
|
||||
}
|
||||
if (Updater.spinnerTimeout) {
|
||||
window.clearTimeout(Updater.spinnerTimeout);
|
||||
}
|
||||
if (Updater.stop) {
|
||||
return;
|
||||
}
|
||||
new Ajax.Request('xml-rpc?method=stats',{method: 'get',onComplete: Updater.rsStats});
|
||||
},
|
||||
rsStats: function(request) {
|
||||
Util.stopSpinner();
|
||||
['service','stat'].each(function (tag) {
|
||||
$A(request.responseXML.getElementsByTagName(tag)).each(function (element) {
|
||||
var node = $(Element.textContent(element.firstChild).toLowerCase().replace(/\ /,'_'));
|
||||
var status = Element.textContent(element.childNodes[1]);
|
||||
node.replaceChild(document.createTextNode(status),node.firstChild);
|
||||
if ('Idle' == status) {
|
||||
$('button_start_scan').disabled = false;
|
||||
$('button_start_full_scan').disabled = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
var thread = $A(request.responseXML.getElementsByTagName('thread'));
|
||||
var threadTable = new Table('thread');
|
||||
threadTable.removeTBodyRows();
|
||||
var users = 0;
|
||||
thread.each(function (element) {
|
||||
users++;
|
||||
row = [];
|
||||
row.push(Element.textContent(element.childNodes[1]));
|
||||
row.push(Element.textContent(element.childNodes[2]));
|
||||
threadTable.addTbodyRow(row);
|
||||
});
|
||||
|
||||
// Monkey see, monkey do
|
||||
var plugin = $A(request.responseXML.getElementsByTagName('plugin'));
|
||||
var pluginTable = new Table('plugin');
|
||||
pluginTable.removeTBodyRows();
|
||||
plugin.each(function(element) {
|
||||
row = [];
|
||||
info = Element.textContent(element.childNodes[0]).split('/',2);
|
||||
row.push(info[0]);
|
||||
row.push(info[1]);
|
||||
pluginTable.addTbodyRow(row);
|
||||
});
|
||||
|
||||
// $('session_count').replaceChild(document.createTextNode(users + ' Connected Users'),$('session_count').firstChild);
|
||||
if (!Updater.stop) {
|
||||
Updater.wait();
|
||||
}
|
||||
},
|
||||
stopServer: function() {
|
||||
Util.stopSpinner();
|
||||
new Ajax.Request('xml-rpc',{method:'post',parameters: 'method=shutdown',onComplete: Updater.rsStopServer});
|
||||
},
|
||||
rsStopServer: function(request) {
|
||||
Updater.stop = true;
|
||||
Updater.update(); // To clear the spinner timeout
|
||||
Element.show('grey_screen');
|
||||
Effect.Appear('server_stopped_message');
|
||||
},
|
||||
startScan: function(e) {
|
||||
Event.element(e).disabled = true;
|
||||
new Ajax.Request('xml-rpc',{method:'post',parameters: 'method=rescan',onComplete: Updater.rsStartScan});
|
||||
},
|
||||
rsStartScan: function(request) {
|
||||
Updater.update();
|
||||
},
|
||||
startFullScan: function(e) {
|
||||
Event.element(e).disabled = true;
|
||||
new Ajax.Request('xml-rpc',{method:'post',parameters: 'method=rescan&full=1',onComplete: Updater.rsStartFullScan});
|
||||
},
|
||||
rsStartFullScan: function(request) {
|
||||
Updater.update();
|
||||
}
|
||||
}
|
||||
|
||||
Table = Class.create();
|
||||
Object.extend(Table.prototype,{
|
||||
initialize: function (id) {
|
||||
this.tbody = $(id).getElementsByTagName('tbody')[0];
|
||||
},
|
||||
removeTBodyRows: function () {
|
||||
Element.removeChildren(this.tbody);
|
||||
},
|
||||
addTbodyRow: function (cells) {
|
||||
var tr = document.createElement('tr');
|
||||
cells.each(function (cell) {
|
||||
var td = document.createElement('td');
|
||||
td.appendChild(document.createTextNode(cell));
|
||||
tr.appendChild(td);
|
||||
});
|
||||
this.tbody.appendChild(tr);
|
||||
}
|
||||
});
|
@ -1,13 +0,0 @@
|
||||
@include hdr.html@
|
||||
|
||||
<h2>Thanks</h2>
|
||||
|
||||
<p class="description">
|
||||
Special thanks to the following people:
|
||||
</p>
|
||||
|
||||
<pre class="description">
|
||||
@include CREDITS@
|
||||
</pre>
|
||||
|
||||
@include ftr.html@
|
@ -1,46 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<root xmlns="urn:schemas-upnp-org:device-1-0">
|
||||
<specVersion>
|
||||
<major>1</major>
|
||||
<minor>0</minor>
|
||||
</specVersion>
|
||||
<device>
|
||||
<deviceType>urn:schemas-upnp-org:device:MediaServer:1</deviceType>
|
||||
<friendlyName>UPnP: @servername@</friendlyName>
|
||||
<manufacturer>Firefly Media Services</manufacturer>
|
||||
<manufacturerURL>http://www.fireflymediaserver.org/</manufacturerURL>
|
||||
<modelDescription>Firefly Media Server (version @version@)</modelDescription>
|
||||
<modelName>Firefly</modelName>
|
||||
<modelNumber>1</modelNumber>
|
||||
<modelURL>http://www.fireflymediaserver.org/</modelURL>
|
||||
<serialNumber>SERIAL-001</serialNumber>
|
||||
<UDN>uuid:@upnp@</UDN>
|
||||
<iconList>
|
||||
<icon>
|
||||
<mimetype>image/png</mimetype>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
<depth>32</depth>
|
||||
<url>/upnp/ff_logo_32.png</url>
|
||||
</icon>
|
||||
</iconList>
|
||||
<serviceList>
|
||||
<service>
|
||||
<serviceType>urn:schemas-upnp-org:service:ConnectionManager:1</serviceType>
|
||||
<serviceId>urn:upnp-org:serviceId:ConnectionManager</serviceId>
|
||||
<SCPDURL>/upnp-cm.xml</SCPDURL>
|
||||
<controlURL>/upnp/cm/control</controlURL>
|
||||
<eventSubURL>/upnp/cm/event</eventSubURL>
|
||||
</service>
|
||||
<service>
|
||||
<serviceType>urn:schemas-upnp-org:service:ContentDirectory:1</serviceType>
|
||||
<serviceId>urn:upnp-org:serviceId:ContentDirectory</serviceId>
|
||||
<SCPDURL>/upnp-cd.xml</SCPDURL>
|
||||
<controlURL>/upnp/cd/control</controlURL>
|
||||
<eventSubURL>/upnp/cd/event</eventSubURL>
|
||||
</service>
|
||||
</serviceList>
|
||||
<presentationURL>/index.html</presentationURL>
|
||||
</device>
|
||||
<URLBase>http://@host@:@config general/port@/</URLBase>
|
||||
</root>
|
@ -1,178 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
|
||||
<specVersion>
|
||||
<major>1</major>
|
||||
<minor>0</minor>
|
||||
</specVersion>
|
||||
<actionList>
|
||||
<action>
|
||||
<name>Browse</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>ObjectID</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_ObjectID</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>BrowseFlag</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_BrowseFlag</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>Filter</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_Filter</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>StartingIndex</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_Index</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>RequestedCount</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_Count</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>SortCriteria</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_SortCriteria</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>Result</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_Result</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>NumberReturned</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_Count</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>TotalMatches</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_Count</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>UpdateID</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_UpdateID</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
<action>
|
||||
<name>DestroyObject</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>ObjectID</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_ObjectID</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
<action>
|
||||
<name>GetSystemUpdateID</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>Id</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>SystemUpdateID</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
<action>
|
||||
<name>GetSearchCapabilities</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>SearchCaps</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>SearchCapabilities</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
<action>
|
||||
<name>GetSortCapabilities</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>SortCaps</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>SortCapabilities</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
<action>
|
||||
<name>UpdateObject</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>ObjectID</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_ObjectID</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>CurrentTagValue</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_TagValueList</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>NewTagValue</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_TagValueList</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
</actionList>
|
||||
<serviceStateTable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_BrowseFlag</name>
|
||||
<dataType>string</dataType>
|
||||
<allowedValueList>
|
||||
<allowedValue>BrowseMetadata</allowedValue>
|
||||
<allowedValue>BrowseDirectChildren</allowedValue>
|
||||
</allowedValueList>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="yes">
|
||||
<name>SystemUpdateID</name>
|
||||
<dataType>ui4</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_Count</name>
|
||||
<dataType>ui4</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_SortCriteria</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>SortCapabilities</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_Index</name>
|
||||
<dataType>ui4</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_ObjectID</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_UpdateID</name>
|
||||
<dataType>ui4</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_TagValueList</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_Result</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>SearchCapabilities</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_Filter</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
</serviceStateTable>
|
||||
</scpd>
|
@ -1,132 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
|
||||
<specVersion>
|
||||
<major>1</major>
|
||||
<minor>0</minor>
|
||||
</specVersion>
|
||||
<actionList>
|
||||
<action>
|
||||
<name>GetCurrentConnectionInfo</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>ConnectionID</name>
|
||||
<direction>in</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_ConnectionID</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>RcsID</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_RcsID</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>AVTransportID</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_AVTransportID</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>ProtocolInfo</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_ProtocolInfo</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>PeerConnectionManager</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_ConnectionManager</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>PeerConnectionID</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_ConnectionID</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>Direction</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_Direction</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>Status</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>A_ARG_TYPE_ConnectionStatus</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
<action>
|
||||
<name>GetProtocolInfo</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>Source</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>SourceProtocolInfo</relatedStateVariable>
|
||||
</argument>
|
||||
<argument>
|
||||
<name>Sink</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>SinkProtocolInfo</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
<action>
|
||||
<name>GetCurrentConnectionIDs</name>
|
||||
<argumentList>
|
||||
<argument>
|
||||
<name>ConnectionIDs</name>
|
||||
<direction>out</direction>
|
||||
<relatedStateVariable>CurrentConnectionIDs</relatedStateVariable>
|
||||
</argument>
|
||||
</argumentList>
|
||||
</action>
|
||||
</actionList>
|
||||
<serviceStateTable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_ProtocolInfo</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_ConnectionStatus</name>
|
||||
<dataType>string</dataType>
|
||||
<allowedValueList>
|
||||
<allowedValue>OK</allowedValue>
|
||||
<allowedValue>ContentFormatMismatch</allowedValue>
|
||||
<allowedValue>InsufficientBandwidth</allowedValue>
|
||||
<allowedValue>UnreliableChannel</allowedValue>
|
||||
<allowedValue>Unknown</allowedValue>
|
||||
</allowedValueList>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_AVTransportID</name>
|
||||
<dataType>i4</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_RcsID</name>
|
||||
<dataType>i4</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_ConnectionID</name>
|
||||
<dataType>i4</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_ConnectionManager</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="yes">
|
||||
<name>SourceProtocolInfo</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="yes">
|
||||
<name>SinkProtocolInfo</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="no">
|
||||
<name>A_ARG_TYPE_Direction</name>
|
||||
<dataType>string</dataType>
|
||||
<allowedValueList>
|
||||
<allowedValue>Input</allowedValue>
|
||||
<allowedValue>Output</allowedValue>
|
||||
</allowedValueList>
|
||||
</stateVariable>
|
||||
<stateVariable sendEvents="yes">
|
||||
<name>CurrentConnectionIDs</name>
|
||||
<dataType>string</dataType>
|
||||
</stateVariable>
|
||||
</serviceStateTable>
|
||||
</scpd>
|
Before Width: | Height: | Size: 362 B |
Before Width: | Height: | Size: 606 B |
Before Width: | Height: | Size: 838 B |
@ -1,81 +0,0 @@
|
||||
Object.extend(Element, {
|
||||
removeChildren: function(element) {
|
||||
while(element.hasChildNodes()) {
|
||||
element.removeChild(element.firstChild);
|
||||
}
|
||||
},
|
||||
textContent: function(node) {
|
||||
if ((!node) || !node.hasChildNodes()) {
|
||||
// Empty text node
|
||||
return '';
|
||||
}
|
||||
if (node.textContent) {
|
||||
// W3C ?
|
||||
return node.textContent;
|
||||
} else if (node.text) {
|
||||
// IE
|
||||
return node.text;
|
||||
} else if (node.firstChild) {
|
||||
// Safari
|
||||
return node.firstChild.nodeValue;
|
||||
}
|
||||
// We shouldn't end up here;
|
||||
return '';
|
||||
}
|
||||
});
|
||||
/* Detta script finns att hamta pa http://www.jojoxx.net och
|
||||
far anvandas fritt sa lange som dessa rader star kvar. */
|
||||
function DataDumper(obj,n,prefix){
|
||||
var str=""; prefix=(prefix)?prefix:""; n=(n)?n+1:1; var ind=""; for(var i=0;i<n;i++){ ind+=" "; }
|
||||
if(typeof(obj)=="string"){
|
||||
str+=ind+prefix+"String:\""+obj+"\"\n";
|
||||
} else if(typeof(obj)=="number"){
|
||||
str+=ind+prefix+"Number:"+obj+"\n";
|
||||
} else if(typeof(obj)=="function"){
|
||||
str+=ind+prefix+"Function:"+obj+"\n";
|
||||
} else if(typeof(obj) == 'boolean') {
|
||||
str+=ind+prefix+"Boolean:" + obj + "\n";
|
||||
} else {
|
||||
var type="Array";
|
||||
for(var i in obj){ type=(type=="Array"&&i==parseInt(i))?"Array":"Object"; }
|
||||
str+=ind+prefix+type+"[\n";
|
||||
if(type=="Array"){
|
||||
for(var i in obj){ str+=DataDumper(obj[i],n,i+"=>"); }
|
||||
} else {
|
||||
for(var i in obj){ str+=DataDumper(obj[i],n,i+"=>"); }
|
||||
}
|
||||
str+=ind+"]\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
var Cookie = {
|
||||
getVar: function(name) {
|
||||
var cookie = document.cookie;
|
||||
if (cookie.length > 0) {
|
||||
cookie += ';';
|
||||
}
|
||||
re = new RegExp(name + '\=(.*?);' );
|
||||
if (cookie.match(re)) {
|
||||
return RegExp.$1;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
setVar: function(name,value,days) {
|
||||
days = days || 30;
|
||||
var expire = new Date(new Date().getTime() + days*86400);
|
||||
document.cookie = name + '=' + value +';expires=' + expire.toUTCString();
|
||||
},
|
||||
removeVar: function(name) {
|
||||
var date = new Date(12);
|
||||
document.cookie = name + '=;expires=' + date.toUTCString();
|
||||
}
|
||||
};
|
||||
var Util = {
|
||||
startSpinner: function () {
|
||||
$('spinner').src = 'spinner.gif';
|
||||
},
|
||||
stopSpinner: function () {
|
||||
$('spinner').src = 'spinner_stopped.gif';
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
@include hdr.html@
|
||||
|
||||
<h2>Xiph License</h2>
|
||||
|
||||
<p class="license"><pre>
|
||||
@include xiph-license.txt@
|
||||
</pre></p>
|
||||
|
||||
@include ftr.html@
|
@ -1,28 +0,0 @@
|
||||
Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the Xiph.org Foundation nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@ -1,9 +0,0 @@
|
||||
@include hdr.html@
|
||||
|
||||
<h2>zlib License</h2>
|
||||
|
||||
<p class="license"><pre>
|
||||
@include zlib-license.txt@
|
||||
</pre></p>
|
||||
|
||||
@include ftr.html@
|
@ -1,25 +0,0 @@
|
||||
/* zlib.h -- interface of the 'zlib' general purpose compression library
|
||||
version 1.2.3, July 18th, 2005
|
||||
|
||||
Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Jean-loup Gailly jloup@@gzip.org
|
||||
Mark Adler madler@@alumni.caltech.edu
|
||||
|
||||
*/
|
@ -93,4 +93,4 @@ dnl Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
|
||||
AC_OUTPUT(src/Makefile tools/Makefile admin-root/Makefile admin-root/lib-js/Makefile admin-root/lib-js/script.aculo.us/Makefile contrib/Makefile contrib/init.d/Makefile Makefile)
|
||||
AC_OUTPUT(src/Makefile tools/Makefile contrib/Makefile contrib/init.d/Makefile Makefile)
|
||||
|