ready4testing

This commit is contained in:
Gerrit Linnemann 2015-11-02 13:46:34 +01:00
parent 08cd6febee
commit 39ab69f570
53 changed files with 23846 additions and 20 deletions

View File

@ -47,6 +47,7 @@ app.set('Helper', Helper);
*/ */
var radioInstance = Radio.init(app, Conf); var radioInstance = Radio.init(app, Conf);
app.set('Radio', radioInstance); app.set('Radio', radioInstance);
radioInstance.play();
/** /**
@ -54,6 +55,7 @@ app.set('Radio', radioInstance);
*/ */
routes.init(app); routes.init(app);
app.set('Routes', routes); app.set('Routes', routes);
app.use('/action/play/:id/', routes.play);
app.use('/', routes.index); app.use('/', routes.index);
// catch 404 and forward to error handler // catch 404 and forward to error handler

View File

@ -55,24 +55,6 @@ exports.timeSince = function timeSince(date) {
return Math.floor(seconds) + " seconds"; return Math.floor(seconds) + " seconds";
} }
exports.isResultAvailable = function(res) {
return (
typeof res !== 'undefined' &&
res != null &&
typeof res.result !== 'undefined' &&
res.result != null
);
}
exports.isTypeAvailable = function(res) {
return (
typeof res !== 'undefined' &&
res != null &&
typeof res.type !== 'undefined' &&
res.type != null
);
}
exports.isJSON = function(toCheck) { exports.isJSON = function(toCheck) {
try { try {
JSON.parse(str); JSON.parse(str);

View File

@ -7,7 +7,7 @@
// load the things we need // load the things we need
//nothing yet var Mplayer = require('node-mplayer');
var App = null; var App = null;
@ -15,6 +15,8 @@ var Log = null
var Helper = null; var Helper = null;
var Conf = null; var Conf = null;
var player = new Mplayer();
exports.init = function(Express, Configuration) { exports.init = function(Express, Configuration) {
App = Express; App = Express;
@ -38,3 +40,45 @@ exports.countChannels = function() {
exports.getChannels = function() { exports.getChannels = function() {
return Conf.channels; return Conf.channels;
} }
exports.getChannel = function(idx) {
if(Helper.isDefinedAndNotNull(Conf.channels[idx])) {
return Conf.channels[idx];
} else {
return null;
}
}
exports.play = function(idx) {
var channel = Conf.channels[idx];
if(channel !== undefined) {
var stream2play;
try {
var parsers = require("playlist-parser");
var M3U = parsers.M3U;
var fs = require("fs");
var playlist = M3U.parse(fs.readFileSync('/Users/gerrit/Downloads/swr3_m.m3u', { encoding: "utf8" }));
Log.inspect('Radio: playlist', playlist);
if(Helper.isDefinedAndNotNull(playlist[0])) {
stream2play = playlist[0].file;
}
} catch(e) {
Log.error(e);
}
if(Helper.isDefinedAndNotNull(stream2play)) {
Log.debug('Radio: Load stream: ' + stream2play);
player.setFile(stream2play);
player.play();
} else {
Log.error('Radio: No stream defined!');
}
} else {
Log.error('Radio: No channel defined!');
}
}

25
kitchenradio/node_modules/node-mplayer/.npmignore generated vendored Normal file
View File

@ -0,0 +1,25 @@
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
# Deployed apps should consider commenting this line out:
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
node_modules

21
kitchenradio/node_modules/node-mplayer/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Loïc Stankovic
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.

152
kitchenradio/node_modules/node-mplayer/README.md generated vendored Normal file
View File

@ -0,0 +1,152 @@
node-mplayer
============
A node.js wrapper for MPlayer on Linux. Use it to play music on your sound card!
## Usage
First, install the module with (assuming you already installed MPlayer)
npm install node-mplayer
Then, you need to make a new instance of the module. The constructor of the module can take the path of the file to play.
var Mplayer = require('node-mplayer');
var player1 = new Mplayer('/home/node/Music/Kalimba.mp3');
var player2 = new Mplayer();
## Available methods
### play
This method will play the file defined when the player object was instanciated or setted with `setFile()`. This method MUST be called before any other.
It can take in parameter an object that contains the volume and the number of times to play the file (see `setVolume` and `setLoop`).
player.play();
player.play({volume: 50});
player.play({volume: 50,
loop: 10});
### checkPlaying
This method indicates if the player is currently playing something.
player.checkPlaying(); //returns true if playing, false if not
### stop
This method will stop the played file.
player.stop();
### quit
This Method will close the underlying process
player.quit();
### pause
This one will toggle pause.
player.pause();
### mute
The method to toggle mute
player.mute();
### setVolume
This method is used to set the volume. It takes one parameter, the volume value that can go from 1 to 100.
player.setVolume(52); //will set the volume to 52%
### seek
This method is used to navigate in the playing file. It take one parameter, the seek value in seconds that goes from 0 to the end of the file. This value is absolute.
player.seek(50); //will go to 50 seconds
### setLoop
This will set the number of times to replay the file. The parameter is the number of times, -1 is forever.
player.setLoop(20); //will play the file 20 times
### setSpeed
This will set the playing speed. It takes one parameter, the speed. 1 is the default speed.
player.setSpeed(0.5); //will play the file 0.5x slower
player.setSpeed(20); //will play the file 20x faster
### setFile
This one is used to set the file to play. The changes will take effect after calling the `play()` method. It takes the path of the file in parameter.
player.setFile('/home/node/Music/asdf.mp3');
### getTimeLength
Returns the length of the file in seconds. It needs a callback.
player.getTimeLength(function(length){
console.log(length);
});
### getTimePosition
Returns the elapsed play time in seconds. It needs a callback.
player.getTimePosition(function(elapsedTime){
console.log(elapsedTime);
});
### getPercentPosition
Return the elapsed time in percent. It needs a callback.
player.getPercentPosition(function(elapsedPercent){
console.log(elapsedPercent);
});
### getVolume
Return the current volume. It needs a callback.
player.getVolume(function(currentVolume){
console.log(currentVolume);
});
##Events
### end
The end event is emitted when the file has ended.
### error
The error event is emitted when an error has ocurred.
## Stability
This module uses the [`readline`](http://www.nodejs.org/api/readline.html) module, which is currently marked unstable.
This module has been tested on Ubuntu 14.04 LTS with MPlayer 1.1-4.8 and on Ubuntu 15.04 with MPlayer2 2.0-728-g2c378c7-4.
## Contributing
Any contribution is welcome! Just create a pull request, and I'll take a look as soon as possible.
## Credits
Here's a list of people who contributed to this project :
* [Maocx](https://github.com/Maocx)
* [lacrioque](https://github.com/lacrioque)
* [nkcr](https://github.com/nkcr)

View File

@ -0,0 +1,161 @@
/*globals require, module*/
var cp = require('child_process'),
events = require('events'),
fs = require('fs'),
readline = require('readline'),
spawn = cp.spawn;
function Mplayer(path){
this.childProc = null;
this.file = "";
this.rl = null;
this.playing = false;
this.volume = 100;
if(typeof path !== 'undefined')
this.setFile(path);
events.EventEmitter.call(this);
cp.exec('mplayer', function(err, stdout, stdin){
if(err)
throw new Error("Mplayer encountered an error or isn't installed.");
});
}
Object.setPrototypeOf(Mplayer.prototype, events.EventEmitter.prototype);
Mplayer.prototype.play = function(opts) {
if(this.file !== null){
if(opts && opts.volume)
this.volume = opts.volume;
var args = ['-slave', '-quiet', '--volume='+this.volume, this.file],
that = this;
this.childProc = spawn('mplayer', args);
this.playing = true;
if(opts && opts.loop)
this.setLoop(opts.loop);
this.childProc.on('error', function(error){
that.emit('error');
});
this.childProc.on('exit', function(code, sig){
if(code === 0 && sig === null){
that.playing = false;
that.emit('end');
}
});
this.rl = readline.createInterface({
input: this.childProc.stdout,
output: this.childProc.stdin
});
}
};
Mplayer.prototype.checkPlaying = function(){
return this.playing;
};
Mplayer.prototype.quit = function() {
if(this.childProc !== null){
this.playing = false;
this.childProc.stdin.write('quit\n');
}
};
Mplayer.prototype.getPercentPosition = function(callback) {
if(this.childProc !== null){
this.rl.question("get_percent_pos\n", function(answer) {
callback(answer.split('=')[1]);
});
}
};
Mplayer.prototype.stop = function() {
if(this.childProc !== null){
this.childProc.stdin.write('stop\n');
this.playing = false;
}
};
Mplayer.prototype.pause = function() {
if(this.childProc !== null){
this.childProc.stdin.write('pause\n');
}
};
Mplayer.prototype.mute = function() {
if(this.childProc !== null){
this.childProc.stdin.write('mute\n');
}
};
Mplayer.prototype.setVolume = function(volume) {
if(this.childProc !== null){
this.volume = volume;
this.childProc.stdin.write('volume ' + volume + ' 1\n');
}
};
Mplayer.prototype.seek = function(sec) {
if(this.childProc !== null){
this.childProc.stdin.write('seek ' + sec + ' 2\n');
}
};
Mplayer.prototype.setLoop = function(times) {
if(this.childProc !== null){
this.childProc.stdin.write('loop ' + times + '\n');
}
};
Mplayer.prototype.setSpeed = function(speed) {
if(this.childProc !== null){
this.childProc.stdin.write('speed_set ' + speed + '\n');
}
};
Mplayer.prototype.setFile = function(path) {
if(this.childProc){
this.quit();
}
if(fs.existsSync(path))
this.file = path;
else
throw new Error("File '" + path + "' not found!");
};
Mplayer.prototype.getTimeLength = function(callback) {
if(this.childProc !== null){
this.rl.question("get_time_length\n", function(answer) {
callback(answer.split('=')[1]);
});
}
};
Mplayer.prototype.getTimePosition = function(callback) {
if(this.childProc !== null){
var that = this;
this.rl.question("get_time_pos\n", function(answer) {
var splittedAns = answer.split('=');
if (splittedAns[0]=='ANS_TIME_POSITION'){
callback(splittedAns[1]);
}
else{
// Try again :(
that.getTimePosition(callback);
}
});
}
};
Mplayer.prototype.getVolume = function(callback) {
return callback(this.volume);
}
module.exports = Mplayer;

34
kitchenradio/node_modules/node-mplayer/package.json generated vendored Normal file
View File

@ -0,0 +1,34 @@
{
"name": "node-mplayer",
"version": "0.0.5",
"description": "Node.js wrapper for mplayer on linux.",
"main": "./lib/node-mplayer.js",
"repository": {
"type": "git",
"url": "https://github.com/loics2/node-mplayer.git"
},
"keywords": [
"mplayer",
"wrapper",
"music",
"player",
"sound",
"media"
],
"author": {
"name": "Loïc Stankovic"
},
"license": "MIT",
"readme": "node-mplayer\n============\n\nA node.js wrapper for MPlayer on Linux. Use it to play music on your sound card!\n\n## Usage\n\nFirst, install the module with (assuming you already installed MPlayer)\n\n npm install node-mplayer\n\nThen, you need to make a new instance of the module. The constructor of the module can take the path of the file to play. \n\n var Mplayer = require('node-mplayer'); \n \n var player1 = new Mplayer('/home/node/Music/Kalimba.mp3');\n var player2 = new Mplayer();\n \n## Available methods\n\n### play\n\nThis method will play the file defined when the player object was instanciated or setted with `setFile()`. This method MUST be called before any other. \nIt can take in parameter an object that contains the volume and the number of times to play the file (see `setVolume` and `setLoop`).\n\n player.play();\n player.play({volume: 50});\n player.play({volume: 50,\n loop: 10});\n\n### checkPlaying\n\nThis method indicates if the player is currently playing something.\n\n player.checkPlaying(); //returns true if playing, false if not\n\n### stop\n\nThis method will stop the played file. \n\n player.stop();\n\n\n### quit\n\nThis Method will close the underlying process\n\n player.quit();\n \n### pause\n\nThis one will toggle pause.\n\n player.pause();\n \n### mute\n\nThe method to toggle mute\n\n player.mute();\n \n### setVolume\n\nThis method is used to set the volume. It takes one parameter, the volume value that can go from 1 to 100.\n\n player.setVolume(52); //will set the volume to 52%\n\n### seek\n\nThis method is used to navigate in the playing file. It take one parameter, the seek value in seconds that goes from 0 to the end of the file. This value is absolute.\n\n player.seek(50); //will go to 50 seconds\n\n### setLoop\n\nThis will set the number of times to replay the file. The parameter is the number of times, -1 is forever.\n\n player.setLoop(20); //will play the file 20 times\n \n### setSpeed\n\nThis will set the playing speed. It takes one parameter, the speed. 1 is the default speed.\n\n player.setSpeed(0.5); //will play the file 0.5x slower\n player.setSpeed(20); //will play the file 20x faster\n \n### setFile\n\nThis one is used to set the file to play. The changes will take effect after calling the `play()` method. It takes the path of the file in parameter.\n\n player.setFile('/home/node/Music/asdf.mp3');\n\n### getTimeLength\n\nReturns the length of the file in seconds. It needs a callback.\n\n player.getTimeLength(function(length){\n console.log(length);\n });\n\n### getTimePosition\n\nReturns the elapsed play time in seconds. It needs a callback.\n\n player.getTimePosition(function(elapsedTime){\n console.log(elapsedTime);\n });\n\n### getPercentPosition\n\nReturn the elapsed time in percent. It needs a callback.\n\n player.getPercentPosition(function(elapsedPercent){\n console.log(elapsedPercent);\n });\n\n\n### getVolume\n\nReturn the current volume. It needs a callback.\n\n player.getVolume(function(currentVolume){\n console.log(currentVolume);\n });\n\n##Events\n\n### end\n\nThe end event is emitted when the file has ended.\n\n### error\n\nThe error event is emitted when an error has ocurred.\n\n## Stability\n\nThis module uses the [`readline`](http://www.nodejs.org/api/readline.html) module, which is currently marked unstable. \n\nThis module has been tested on Ubuntu 14.04 LTS with MPlayer 1.1-4.8 and on Ubuntu 15.04 with MPlayer2 2.0-728-g2c378c7-4.\n\n## Contributing\n\nAny contribution is welcome! Just create a pull request, and I'll take a look as soon as possible.\n\n## Credits\n\nHere's a list of people who contributed to this project :\n\n* [Maocx](https://github.com/Maocx)\n* [lacrioque](https://github.com/lacrioque)\n* [nkcr](https://github.com/nkcr)",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/loics2/node-mplayer/issues"
},
"homepage": "https://github.com/loics2/node-mplayer",
"_id": "node-mplayer@0.0.5",
"dist": {
"shasum": "fb7a7d950199f61dff0c905e06b0c67d8a6cbc11"
},
"_from": "node-mplayer@*",
"_resolved": "https://registry.npmjs.org/node-mplayer/-/node-mplayer-0.0.5.tgz"
}

3
kitchenradio/node_modules/playlist-parser/.npmignore generated vendored Normal file
View File

@ -0,0 +1,3 @@
src/
test/

View File

@ -0,0 +1,27 @@
license = require('fs').readFileSync './LICENSE', encoding: 'utf8'
module.exports = (grunt) ->
grunt.initConfig
coffee:
compile:
files:
'lib/parser.js': ['src/*.coffee']
mochaTest:
test:
options:
reporter: 'nyan'
src: ['test/test.coffee']
uglify:
options:
banner: "/*\n#{license}\n*/\n"
target:
files:
'lib/parser.min.js': ['lib/parser.js']
grunt.loadNpmTasks 'grunt-contrib-coffee'
grunt.loadNpmTasks 'grunt-mocha-test'
grunt.loadNpmTasks 'grunt-contrib-uglify'
grunt.registerTask 'default', ['coffee', 'uglify','mochaTest']
grunt.registerTask 'test', ['coffee', 'uglify', 'mochaTest']

28
kitchenradio/node_modules/playlist-parser/LICENSE generated vendored Normal file
View File

@ -0,0 +1,28 @@
This software is dual licensed under the MIT and Beerware license.
The MIT License (MIT)
Copyright (c) 2013 Nick Desaulniers
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.
"THE BEER-WARE LICENSE" (Revision 42):
<nick@mozilla.com> wrote this file. As long as you retain this
notice you can do whatever you want with this stuff. If we meet some day,
and you think this stuff is worth it, you can buy me a beer in return.
Nick Desaulniers

119
kitchenradio/node_modules/playlist-parser/README.md generated vendored Normal file
View File

@ -0,0 +1,119 @@
#javascript-playlist-parser#
Parse m3u, m3u extended, pls, and asx in JavaScript.
##Usage##
###Browser###
Adds `window.M3U.parse`, `window.PLS.parse`, and `window.ASX.parse` which take a
string and return a possibly empty array of objects.
```html
<script src="https://raw.github.com/nickdesaulniers/javascript-playlist-parser/master/lib/parser.min.js"></script>
```
```javascript
// Fetch the playlist file, using xhr for example
var xhr = new XMLHttpRequest();
xhr.open("GET", "my_playlist.m3u");
xhr.overrideMimeType("audio/x-mpegurl"); // Needed, see below.
xhr.onload = parse;
xhr.send();
// Parse it
function parse () {
var playlist = M3U.parse(this.response);
var audio = new Audio();
next(audio, playlist, 0);
};
// Play each song after a song finishes
function next (audio, playlist, i) {
if (i < playlist.length) {
audio.src = playlist[i++].file;
audio.onended = next.bind(null, audio, playlist, i);
audio.play();
}
};
```
[Demo](http://nickdesaulniers.github.io/javascript-playlist-parser/)
###Node.js###
Adds `require('playlist-parser').M3U.parse`,
`require('playlist-parser').PLS.parse`,
and `require('playlist-parser').ASX.parse`
which take a string and return
a possibly empty array of objects.
`npm install playlist-parser`
```javascript
var parsers = require("playlist-parser");
var M3U = parsers.M3U;
var fs = require("fs");
var playlist = M3U.parse(fs.readFileSync("my_playlist.m3u", { encoding: "utf8" }));
```
##Return Values##
Calls to parse return an array of objects that look like:
###M3U Simple or ASX###
```javascript
[{
file: "http://song.com/song.mp3"
}]
```
###M3U Extended###
```javascript
[{
length: 1234,
artist: "Iron Maiden",
title: "Rime of the Ancient Mariner",
file: "http://song.com/song.mp3"
}]
```
###PLS###
```javascript
[{
file: "http://song.com/song.mp3",
title: "My favorite song ever by my favorite artist",
length: 1234
}]
```
##MIME Types##
* m3u -> audio/x-mpegurl
* pls -> audio/x-scpls
* asx -> video/x-ms-asf
##License##
This software is dual licensed under the MIT and Beerware license.
The MIT License (MIT)
Copyright (c) 2013 Nick Desaulniers
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.
"THE BEER-WARE LICENSE" (Revision 42):
<nick@mozilla.com> wrote this file. As long as you retain this
notice you can do whatever you want with this stuff. If we meet some day,
and you think this stuff is worth it, you can buy me a beer in return.
Nick Desaulniers

132
kitchenradio/node_modules/playlist-parser/lib/parser.js generated vendored Normal file
View File

@ -0,0 +1,132 @@
(function() {
var DOMParser, find, parse;
DOMParser = (typeof window !== "undefined" && window !== null ? window.DOMParser : void 0) || (typeof require === "function" ? require('xmldom').DOMParser : void 0) || function() {};
find = function(node, list) {
var attributes, childNode, childNodeName, childNodes, i, match, x, _i, _j, _ref, _ref1;
if (node.hasChildNodes()) {
childNodes = node.childNodes;
for (i = _i = 0, _ref = childNodes.length; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
childNode = childNodes[i];
childNodeName = childNode.nodeName;
if (/REF/i.test(childNodeName)) {
attributes = childNode.attributes;
for (x = _j = 0, _ref1 = attributes.length; 0 <= _ref1 ? _j < _ref1 : _j > _ref1; x = 0 <= _ref1 ? ++_j : --_j) {
match = attributes[x].nodeName.match(/HREF/i);
if (match) {
list.push({
file: childNode.getAttribute(match[0]).trim()
});
break;
}
}
} else if (childNodeName !== '#text') {
find(childNode, list);
}
}
}
return null;
};
parse = function(playlist) {
var doc, ret;
ret = [];
doc = (new DOMParser()).parseFromString(playlist, 'text/xml').documentElement;
if (!doc) {
return ret;
}
find(doc, ret);
return ret;
};
(typeof module !== "undefined" && module !== null ? module.exports : window).ASX = {
name: 'asx',
parse: parse
};
}).call(this);
(function() {
var COMMENT_RE, EXTENDED, comments, empty, extended, parse, simple;
EXTENDED = '#EXTM3U';
COMMENT_RE = /:(?:(-?\d+),(.+)\s*-\s*(.+)|(.+))\n(.+)/;
extended = function(line) {
var match;
match = line.match(COMMENT_RE);
if (match && match.length === 6) {
return {
length: match[1] || 0,
artist: match[2] || '',
title: match[4] || match[3],
file: match[5].trim()
};
}
};
simple = function(string) {
return {
file: string.trim()
};
};
empty = function(line) {
return !!line.trim().length;
};
comments = function(line) {
return line[0] !== '#';
};
parse = function(playlist) {
var firstNewline;
playlist = playlist.replace(/\r/g, '');
firstNewline = playlist.search('\n');
if (playlist.substr(0, firstNewline) === EXTENDED) {
return playlist.substr(firstNewline).split('\n#').filter(empty).map(extended);
} else {
return playlist.split('\n').filter(empty).filter(comments).map(simple);
}
};
(typeof module !== "undefined" && module !== null ? module.exports : window).M3U = {
name: 'm3u',
parse: parse
};
}).call(this);
(function() {
var LISTING_RE, parse;
LISTING_RE = /(file|title|length)(\d+)=(.+)\r?/i;
parse = function(playlist) {
var index, key, line, match, tracks, value, _, _i, _len, _ref;
tracks = [];
_ref = playlist.trim().split('\n');
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
line = _ref[_i];
match = line.match(LISTING_RE);
if (match && match.length === 4) {
_ = match[0], key = match[1], index = match[2], value = match[3];
if (!tracks[index]) {
tracks[index] = {};
}
tracks[index][key.toLowerCase()] = value;
}
}
return tracks.filter(function(track) {
return track != null;
});
};
(typeof module !== "undefined" && module !== null ? module.exports : window).PLS = {
name: 'pls',
parse: parse
};
}).call(this);

View File

@ -0,0 +1,32 @@
/*
This software is dual licensed under the MIT and Beerware license.
The MIT License (MIT)
Copyright (c) 2013 Nick Desaulniers
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.
"THE BEER-WARE LICENSE" (Revision 42):
<nick@mozilla.com> wrote this file. As long as you retain this
notice you can do whatever you want with this stuff. If we meet some day,
and you think this stuff is worth it, you can buy me a beer in return.
Nick Desaulniers
*/
(function(){var a,b,c;a=("undefined"!=typeof window&&null!==window?window.DOMParser:void 0)||("function"==typeof require?require("xmldom").DOMParser:void 0)||function(){},b=function(a,c){var d,e,f,g,h,i,j,k,l,m,n;if(a.hasChildNodes())for(g=a.childNodes,h=k=0,m=g.length;m>=0?m>k:k>m;h=m>=0?++k:--k)if(e=g[h],f=e.nodeName,/REF/i.test(f)){for(d=e.attributes,j=l=0,n=d.length;n>=0?n>l:l>n;j=n>=0?++l:--l)if(i=d[j].nodeName.match(/HREF/i)){c.push({file:e.getAttribute(i[0]).trim()});break}}else"#text"!==f&&b(e,c);return null},c=function(c){var d,e;return e=[],(d=(new a).parseFromString(c,"text/xml").documentElement)?(b(d,e),e):e},("undefined"!=typeof module&&null!==module?module.exports:window).ASX={name:"asx",parse:c}}).call(this),function(){var a,b,c,d,e,f,g;b="#EXTM3U",a=/:(?:(-?\d+),(.+)\s*-\s*(.+)|(.+))\n(.+)/,e=function(b){var c;return c=b.match(a),c&&6===c.length?{length:c[1]||0,artist:c[2]||"",title:c[4]||c[3],file:c[5].trim()}:void 0},g=function(a){return{file:a.trim()}},d=function(a){return!!a.trim().length},c=function(a){return"#"!==a[0]},f=function(a){var f;return a=a.replace(/\r/g,""),f=a.search("\n"),a.substr(0,f)===b?a.substr(f).split("\n#").filter(d).map(e):a.split("\n").filter(d).filter(c).map(g)},("undefined"!=typeof module&&null!==module?module.exports:window).M3U={name:"m3u",parse:f}}.call(this),function(){var a,b;a=/(file|title|length)(\d+)=(.+)\r?/i,b=function(b){var c,d,e,f,g,h,i,j,k,l;for(g=[],l=b.trim().split("\n"),j=0,k=l.length;k>j;j++)e=l[j],f=e.match(a),f&&4===f.length&&(i=f[0],d=f[1],c=f[2],h=f[3],g[c]||(g[c]={}),g[c][d.toLowerCase()]=h);return g.filter(function(a){return null!=a})},("undefined"!=typeof module&&null!==module?module.exports:window).PLS={name:"pls",parse:b}}.call(this);

View File

@ -0,0 +1,2 @@
/node_modules
/.proof.out

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>xmldom</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
</natures>
</projectDescription>

View File

@ -0,0 +1,18 @@
language: node_js
node_js:
- 0.8
branches:
only:
- master
- proof
- travis-ci
# Not using `npm install --dev` because it is recursive. It will pull in the all
# development dependencies for CoffeeScript. Way too much spew in the Travis CI
# build output.
before_install:
- npm install
- npm install istanbul coveralls

View File

@ -0,0 +1,4 @@
this.addScript('dom.js',['DOMImplementation','XMLSerializer']);
this.addScript('dom-parser.js',['DOMHandler','DOMParser'],
['DOMImplementation','XMLReader']);
this.addScript('sax.js','XMLReader');

View File

@ -0,0 +1,14 @@
### Version 0.1.16
Sat May 4 14:58:03 UTC 2013
* Correctly handle multibyte Unicode greater than two byts. #57. #56.
* Initial unit testing and test coverage. #53. #46. #19.
* Create Bower `component.json` #52.
### Version 0.1.8
* Add: some test case from node-o3-xml(excludes xpath support)
* Fix: remove existed attribute before setting (bug introduced in v0.1.5)
* Fix: index direct access for childNodes and any NodeList collection(not w3c standard)
* Fix: remove last child bug

View File

@ -0,0 +1,10 @@
{
"name": "xmldom",
"version": "0.1.15",
"main": "dom-parser.js",
"ignore": [
"**/.*",
"node_modules",
"components"
]
}

View File

@ -0,0 +1,253 @@
function DOMParser(options){
this.options =
options != true && //To the version (0.1.12) compatible
options ||{locator:{}};
}
DOMParser.prototype.parseFromString = function(source,mimeType){
var sax = new XMLReader();
var options = this.options;
var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler
var errorHandler = options.errorHandler;
var locator = options.locator;
var defaultNSMap = {};
var entityMap = {'lt':'<','gt':'>','amp':'&','quot':'"','apos':"'"}
if(locator){
domBuilder.setDocumentLocator(locator)
}
sax.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator);
sax.domBuilder = options.domBuilder || domBuilder;
if(/\/x?html?$/.test(mimeType)){
entityMap.nbsp = '\xa0';
entityMap.copy = '\xa9';
defaultNSMap['']= 'http://www.w3.org/1999/xhtml';
}
sax.parse(source,defaultNSMap,entityMap);
return domBuilder.document;
}
function buildErrorHandler(errorImpl,domBuilder,locator){
if(!errorImpl){
if(domBuilder instanceof DOMHandler){
return domBuilder;
}
errorImpl = domBuilder ;
}
var errorHandler = {}
var isCallback = errorImpl instanceof Function;
locator = locator||{}
function build(key){
var fn = errorImpl[key];
if(!fn){
if(isCallback){
fn = errorImpl.length == 2?function(msg){errorImpl(key,msg)}:errorImpl;
}else{
var i=arguments.length;
while(--i){
if(fn = errorImpl[arguments[i]]){
break;
}
}
}
}
errorHandler[key] = fn && function(msg){
fn(msg+_locator(locator));
}||function(){};
}
build('warning','warn');
build('error','warn','warning');
build('fatalError','warn','warning','error');
return errorHandler;
}
/**
* +ContentHandler+ErrorHandler
* +LexicalHandler+EntityResolver2
* -DeclHandler-DTDHandler
*
* DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
* DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
* @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
*/
function DOMHandler() {
this.cdata = false;
}
function position(locator,node){
node.lineNumber = locator.lineNumber;
node.columnNumber = locator.columnNumber;
}
/**
* @see org.xml.sax.ContentHandler#startDocument
* @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
*/
DOMHandler.prototype = {
startDocument : function() {
this.document = new DOMImplementation().createDocument(null, null, null);
if (this.locator) {
this.document.documentURI = this.locator.systemId;
}
},
startElement:function(namespaceURI, localName, qName, attrs) {
var doc = this.document;
var el = doc.createElementNS(namespaceURI, qName||localName);
var len = attrs.length;
appendElement(this, el);
this.currentElement = el;
this.locator && position(this.locator,el)
for (var i = 0 ; i < len; i++) {
var namespaceURI = attrs.getURI(i);
var value = attrs.getValue(i);
var qName = attrs.getQName(i);
var attr = doc.createAttributeNS(namespaceURI, qName);
if( attr.getOffset){
position(attr.getOffset(1),attr)
}
attr.value = attr.nodeValue = value;
el.setAttributeNode(attr)
}
},
endElement:function(namespaceURI, localName, qName) {
var current = this.currentElement
var tagName = current.tagName;
this.currentElement = current.parentNode;
},
startPrefixMapping:function(prefix, uri) {
},
endPrefixMapping:function(prefix) {
},
processingInstruction:function(target, data) {
var ins = this.document.createProcessingInstruction(target, data);
this.locator && position(this.locator,ins)
appendElement(this, ins);
},
ignorableWhitespace:function(ch, start, length) {
},
characters:function(chars, start, length) {
chars = _toString.apply(this,arguments)
//console.log(chars)
if(this.currentElement && chars){
if (this.cdata) {
var charNode = this.document.createCDATASection(chars);
this.currentElement.appendChild(charNode);
} else {
var charNode = this.document.createTextNode(chars);
this.currentElement.appendChild(charNode);
}
this.locator && position(this.locator,charNode)
}
},
skippedEntity:function(name) {
},
endDocument:function() {
this.document.normalize();
},
setDocumentLocator:function (locator) {
if(this.locator = locator){// && !('lineNumber' in locator)){
locator.lineNumber = 0;
}
},
//LexicalHandler
comment:function(chars, start, length) {
chars = _toString.apply(this,arguments)
var comm = this.document.createComment(chars);
this.locator && position(this.locator,comm)
appendElement(this, comm);
},
startCDATA:function() {
//used in characters() methods
this.cdata = true;
},
endCDATA:function() {
this.cdata = false;
},
startDTD:function(name, publicId, systemId) {
var impl = this.document.implementation;
if (impl && impl.createDocumentType) {
var dt = impl.createDocumentType(name, publicId, systemId);
this.locator && position(this.locator,dt)
appendElement(this, dt);
}
},
/**
* @see org.xml.sax.ErrorHandler
* @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
*/
warning:function(error) {
console.warn(error,_locator(this.locator));
},
error:function(error) {
console.error(error,_locator(this.locator));
},
fatalError:function(error) {
console.error(error,_locator(this.locator));
throw error;
}
}
function _locator(l){
if(l){
return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']'
}
}
function _toString(chars,start,length){
if(typeof chars == 'string'){
return chars.substr(start,length)
}else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
if(chars.length >= start+length || start){
return new java.lang.String(chars,start,length)+'';
}
return chars;
}
}
/*
* @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
* used method of org.xml.sax.ext.LexicalHandler:
* #comment(chars, start, length)
* #startCDATA()
* #endCDATA()
* #startDTD(name, publicId, systemId)
*
*
* IGNORED method of org.xml.sax.ext.LexicalHandler:
* #endDTD()
* #startEntity(name)
* #endEntity(name)
*
*
* @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
* IGNORED method of org.xml.sax.ext.DeclHandler
* #attributeDecl(eName, aName, type, mode, value)
* #elementDecl(name, model)
* #externalEntityDecl(name, publicId, systemId)
* #internalEntityDecl(name, value)
* @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
* IGNORED method of org.xml.sax.EntityResolver2
* #resolveEntity(String name,String publicId,String baseURI,String systemId)
* #resolveEntity(publicId, systemId)
* #getExternalSubset(name, baseURI)
* @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
* IGNORED method of org.xml.sax.DTDHandler
* #notationDecl(name, publicId, systemId) {};
* #unparsedEntityDecl(name, publicId, systemId, notationName) {};
*/
"endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){
DOMHandler.prototype[key] = function(){return null}
})
/* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */
function appendElement (hander,node) {
if (!hander.currentElement) {
hander.document.appendChild(node);
} else {
hander.currentElement.appendChild(node);
}
}//appendChild and setAttributeNS are preformance key
if(typeof require == 'function'){
var XMLReader = require('./sax').XMLReader;
var DOMImplementation = exports.DOMImplementation = require('./dom').DOMImplementation;
exports.XMLSerializer = require('./dom').XMLSerializer ;
exports.DOMParser = DOMParser;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,213 @@
# XMLDOM [![Build Status](https://secure.travis-ci.org/bigeasy/xmldom.png?branch=master)](http://travis-ci.org/bigeasy/xmldom) [![Coverage Status](https://coveralls.io/repos/bigeasy/xmldom/badge.png?branch=master)](https://coveralls.io/r/bigeasy/xmldom) [![NPM version](https://badge.fury.io/js/xmldom.png)](http://badge.fury.io/js/xmldom)
A JavaScript implementation of W3C DOM for Node.js, Rhino and the browser. Fully
compatible with `W3C DOM level2`; and some compatible with `level3`. Supports
`DOMParser` and `XMLSerializer` interface such as in browser.
Install:
-------
>npm install xmldom
Example:
====
```javascript
var DOMParser = require('xmldom').DOMParser;
var doc = new DOMParser().parseFromString(
'<xml xmlns="a" xmlns:c="./lite">\n'+
'\t<child>test</child>\n'+
'\t<child></child>\n'+
'\t<child/>\n'+
'</xml>'
,'text/xml');
doc.documentElement.setAttribute('x','y');
doc.documentElement.setAttributeNS('./lite','c:x','y2');
var nsAttr = doc.documentElement.getAttributeNS('./lite','x')
console.info(nsAttr)
console.info(doc)
```
API Reference
=====
* [DOMParser](https://developer.mozilla.org/en/DOMParser):
```javascript
parseFromString(xmlsource,mimeType)
```
* **options extension** _by xmldom_(not BOM standard!!)
```javascript
//added the options argument
new DOMParser(options)
//errorHandler is supported
new DOMParser({
/**
* youcan override the errorHandler for xml parser
* @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
*/
errorHandler:{warning:callback,error:callback,fatalError:callback}
})
```
* [XMLSerializer](https://developer.mozilla.org/en/XMLSerializer)
```javascript
serializeToString(node)
```
DOM level2 method and attribute:
------
* [Node](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247)
attribute:
nodeValue|prefix
readonly attribute:
nodeName|nodeType|parentNode|childNodes|firstChild|lastChild|previousSibling|nextSibling|attributes|ownerDocument|namespaceURI|localName
method:
insertBefore(newChild, refChild)
replaceChild(newChild, oldChild)
removeChild(oldChild)
appendChild(newChild)
hasChildNodes()
cloneNode(deep)
normalize()
isSupported(feature, version)
hasAttributes()
* [DOMImplementation](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-102161490)
method:
hasFeature(feature, version)
createDocumentType(qualifiedName, publicId, systemId)
createDocument(namespaceURI, qualifiedName, doctype)
* [Document](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#i-Document) : Node
readonly attribute:
doctype|implementation|documentElement
method:
createElement(tagName)
createDocumentFragment()
createTextNode(data)
createComment(data)
createCDATASection(data)
createProcessingInstruction(target, data)
createAttribute(name)
createEntityReference(name)
getElementsByTagName(tagname)
importNode(importedNode, deep)
createElementNS(namespaceURI, qualifiedName)
createAttributeNS(namespaceURI, qualifiedName)
getElementsByTagNameNS(namespaceURI, localName)
getElementById(elementId)
* [DocumentFragment](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-B63ED1A3) : Node
* [Element](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-745549614) : Node
readonly attribute:
tagName
method:
getAttribute(name)
setAttribute(name, value)
removeAttribute(name)
getAttributeNode(name)
setAttributeNode(newAttr)
removeAttributeNode(oldAttr)
getElementsByTagName(name)
getAttributeNS(namespaceURI, localName)
setAttributeNS(namespaceURI, qualifiedName, value)
removeAttributeNS(namespaceURI, localName)
getAttributeNodeNS(namespaceURI, localName)
setAttributeNodeNS(newAttr)
getElementsByTagNameNS(namespaceURI, localName)
hasAttribute(name)
hasAttributeNS(namespaceURI, localName)
* [Attr](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-637646024) : Node
attribute:
value
readonly attribute:
name|specified|ownerElement
* [NodeList](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177)
readonly attribute:
length
method:
item(index)
* [NamedNodeMap](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1780488922)
readonly attribute:
length
method:
getNamedItem(name)
setNamedItem(arg)
removeNamedItem(name)
item(index)
getNamedItemNS(namespaceURI, localName)
setNamedItemNS(arg)
removeNamedItemNS(namespaceURI, localName)
* [CharacterData](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-FF21A306) : Node
method:
substringData(offset, count)
appendData(arg)
insertData(offset, arg)
deleteData(offset, count)
replaceData(offset, count, arg)
* [Text](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1312295772) : CharacterData
method:
splitText(offset)
* [CDATASection](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-667469212)
* [Comment](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1728279322) : CharacterData
* [DocumentType](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-412266927)
readonly attribute:
name|entities|notations|publicId|systemId|internalSubset
* Notation : Node
readonly attribute:
publicId|systemId
* Entity : Node
readonly attribute:
publicId|systemId|notationName
* EntityReference : Node
* ProcessingInstruction : Node
attribute:
data
readonly attribute:
target
DOM level 3 support:
-----
* [Node](http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-textContent)
attribute:
textContent
method:
isDefaultNamespace(namespaceURI){
lookupNamespaceURI(prefix)
DOM extension by xmldom
---
* [Node] Source position extension;
attribute:
//Numbered starting from '1'
lineNumber
//Numbered starting from '1'
columnNumber

View File

@ -0,0 +1,564 @@
//[4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
//[4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
//[5] Name ::= NameStartChar (NameChar)*
var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]///\u10000-\uEFFFF
var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\u00B7\u0300-\u036F\\ux203F-\u2040]");
var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$');
//var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
//var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',')
//S_TAG, S_ATTR, S_EQ, S_V
//S_ATTR_S, S_E, S_S, S_C
var S_TAG = 0;//tag name offerring
var S_ATTR = 1;//attr name offerring
var S_ATTR_S=2;//attr name end and space offer
var S_EQ = 3;//=space?
var S_V = 4;//attr value(no quot value only)
var S_E = 5;//attr value end and no space(quot end)
var S_S = 6;//(attr value end || tag end ) && (space offer)
var S_C = 7;//closed el<el />
function XMLReader(){
}
XMLReader.prototype = {
parse:function(source,defaultNSMap,entityMap){
var domBuilder = this.domBuilder;
domBuilder.startDocument();
_copy(defaultNSMap ,defaultNSMap = {})
parse(source,defaultNSMap,entityMap,
domBuilder,this.errorHandler);
domBuilder.endDocument();
}
}
function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
function fixedFromCharCode(code) {
// String.prototype.fromCharCode does not supports
// > 2 bytes unicode chars directly
if (code > 0xffff) {
code -= 0x10000;
var surrogate1 = 0xd800 + (code >> 10)
, surrogate2 = 0xdc00 + (code & 0x3ff);
return String.fromCharCode(surrogate1, surrogate2);
} else {
return String.fromCharCode(code);
}
}
function entityReplacer(a){
var k = a.slice(1,-1);
if(k in entityMap){
return entityMap[k];
}else if(k.charAt(0) === '#'){
return fixedFromCharCode(parseInt(k.substr(1).replace('x','0x')))
}else{
errorHandler.error('entity not found:'+a);
return a;
}
}
function appendText(end){//has some bugs
var xt = source.substring(start,end).replace(/&#?\w+;/g,entityReplacer);
locator&&position(start);
domBuilder.characters(xt,0,end-start);
start = end
}
function position(start,m){
while(start>=endPos && (m = linePattern.exec(source))){
startPos = m.index;
endPos = startPos + m[0].length;
locator.lineNumber++;
//console.log('line++:',locator,startPos,endPos)
}
locator.columnNumber = start-startPos+1;
}
var startPos = 0;
var endPos = 0;
var linePattern = /.+(?:\r\n?|\n)|.*$/g
var locator = domBuilder.locator;
var parseStack = [{currentNSMap:defaultNSMapCopy}]
var closeMap = {};
var start = 0;
while(true){
var i = source.indexOf('<',start);
if(i>start){
appendText(i);
}
switch(source.charAt(i+1)){
case '/':
var end = source.indexOf('>',i+3);
var tagName = source.substring(i+2,end);
var config = parseStack.pop();
var localNSMap = config.localNSMap;
if(config.tagName != tagName){
errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName );
}
domBuilder.endElement(config.uri,config.localName,tagName);
if(localNSMap){
for(var prefix in localNSMap){
domBuilder.endPrefixMapping(prefix) ;
}
}
end++;
break;
// end elment
case '?':// <?...?>
locator&&position(i);
end = parseInstruction(source,i,domBuilder);
break;
case '!':// <!doctype,<![CDATA,<!--
locator&&position(i);
end = parseDCC(source,i,domBuilder);
break;
default:
if(i<0){
if(!source.substr(start).match(/^\s*$/)){
errorHandler.error('source code out of document root');
}
return;
}else{
try{
locator&&position(i);
var el = new ElementAttributes();
//elStartEnd
var end = parseElementStartPart(source,i,el,entityReplacer,errorHandler);
var len = el.length;
//position fixed
if(len && locator){
var backup = copyLocator(locator,{});
for(var i = 0;i<len;i++){
var a = el[i];
position(a.offset);
a.offset = copyLocator(locator,{});
}
copyLocator(backup,locator);
}
el.closed = el.closed||fixSelfClosed(source,end,el.tagName,closeMap);
appendElement(el,domBuilder,parseStack);
if(el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed){
end = parseHtmlSpecialContent(source,end,el.tagName,entityReplacer,domBuilder)
}else{
end++;
}
}catch(e){
errorHandler.error('element parse error: '+e);
end = -1;
}
}
}
if(end<0){
//TODO: 这里有可能sax回退有位置错误风险
appendText(i+1);
}else{
start = end;
}
}
}
function copyLocator(f,t){
t.lineNumber = f.lineNumber;
t.columnNumber = f.columnNumber;
return t;
}
/**
* @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
* @return end of the elementStartPart(end of elementEndPart for selfClosed el)
*/
function parseElementStartPart(source,start,el,entityReplacer,errorHandler){
var attrName;
var value;
var p = ++start;
var s = S_TAG;//status
while(true){
var c = source.charAt(p);
switch(c){
case '=':
if(s === S_ATTR){//attrName
attrName = source.slice(start,p);
s = S_EQ;
}else if(s === S_ATTR_S){
s = S_EQ;
}else{
//fatalError: equal must after attrName or space after attrName
throw new Error('attribute equal must after attrName');
}
break;
case '\'':
case '"':
if(s === S_EQ){//equal
start = p+1;
p = source.indexOf(c,start)
if(p>0){
value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
el.add(attrName,value,start-1);
s = S_E;
}else{
//fatalError: no end quot match
throw new Error('attribute value no end \''+c+'\' match');
}
}else if(s == S_V){
value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
//console.log(attrName,value,start,p)
el.add(attrName,value,start);
//console.dir(el)
errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!');
start = p+1;
s = S_E
}else{
//fatalError: no equal before
throw new Error('attribute value must after "="');
}
break;
case '/':
switch(s){
case S_TAG:
el.setTagName(source.slice(start,p));
case S_E:
case S_S:
case S_C:
s = S_C;
el.closed = true;
case S_V:
case S_ATTR:
case S_ATTR_S:
break;
//case S_EQ:
default:
throw new Error("attribute invalid close char('/')")
}
break;
case '>':
switch(s){
case S_TAG:
el.setTagName(source.slice(start,p));
case S_E:
case S_S:
case S_C:
break;//normal
case S_V://Compatible state
case S_ATTR:
value = source.slice(start,p);
if(value.slice(-1) === '/'){
el.closed = true;
value = value.slice(0,-1)
}
case S_ATTR_S:
if(s === S_ATTR_S){
value = attrName;
}
if(s == S_V){
errorHandler.warning('attribute "'+value+'" missed quot(")!!');
el.add(attrName,value.replace(/&#?\w+;/g,entityReplacer),start)
}else{
errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!')
el.add(value,value,start)
}
break;
case S_EQ:
throw new Error('attribute value missed!!');
}
// console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
return p;
/*xml space '\x20' | #x9 | #xD | #xA; */
case '\u0080':
c = ' ';
default:
if(c<= ' '){//space
switch(s){
case S_TAG:
el.setTagName(source.slice(start,p));//tagName
s = S_S;
break;
case S_ATTR:
attrName = source.slice(start,p)
s = S_ATTR_S;
break;
case S_V:
var value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
errorHandler.warning('attribute "'+value+'" missed quot(")!!');
el.add(attrName,value,start)
case S_E:
s = S_S;
break;
//case S_S:
//case S_EQ:
//case S_ATTR_S:
// void();break;
//case S_C:
//ignore warning
}
}else{//not space
//S_TAG, S_ATTR, S_EQ, S_V
//S_ATTR_S, S_E, S_S, S_C
switch(s){
//case S_TAG:void();break;
//case S_ATTR:void();break;
//case S_V:void();break;
case S_ATTR_S:
errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead!!')
el.add(attrName,attrName,start);
start = p;
s = S_ATTR;
break;
case S_E:
errorHandler.warning('attribute space is required"'+attrName+'"!!')
case S_S:
s = S_ATTR;
start = p;
break;
case S_EQ:
s = S_V;
start = p;
break;
case S_C:
throw new Error("elements closed character '/' and '>' must be connected to");
}
}
}
p++;
}
}
/**
* @return end of the elementStartPart(end of elementEndPart for selfClosed el)
*/
function appendElement(el,domBuilder,parseStack){
var tagName = el.tagName;
var localNSMap = null;
var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
var i = el.length;
while(i--){
var a = el[i];
var qName = a.qName;
var value = a.value;
var nsp = qName.indexOf(':');
if(nsp>0){
var prefix = a.prefix = qName.slice(0,nsp);
var localName = qName.slice(nsp+1);
var nsPrefix = prefix === 'xmlns' && localName
}else{
localName = qName;
prefix = null
nsPrefix = qName === 'xmlns' && ''
}
//can not set prefix,because prefix !== ''
a.localName = localName ;
//prefix == null for no ns prefix attribute
if(nsPrefix !== false){//hack!!
if(localNSMap == null){
localNSMap = {}
_copy(currentNSMap,currentNSMap={})
}
currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
a.uri = 'http://www.w3.org/2000/xmlns/'
domBuilder.startPrefixMapping(nsPrefix, value)
}
}
var i = el.length;
while(i--){
a = el[i];
var prefix = a.prefix;
if(prefix){//no prefix attribute has no namespace
if(prefix === 'xml'){
a.uri = 'http://www.w3.org/XML/1998/namespace';
}if(prefix !== 'xmlns'){
a.uri = currentNSMap[prefix]
}
}
}
var nsp = tagName.indexOf(':');
if(nsp>0){
prefix = el.prefix = tagName.slice(0,nsp);
localName = el.localName = tagName.slice(nsp+1);
}else{
prefix = null;//important!!
localName = el.localName = tagName;
}
//no prefix element has default namespace
var ns = el.uri = currentNSMap[prefix || ''];
domBuilder.startElement(ns,localName,tagName,el);
//endPrefixMapping and startPrefixMapping have not any help for dom builder
//localNSMap = null
if(el.closed){
domBuilder.endElement(ns,localName,tagName);
if(localNSMap){
for(prefix in localNSMap){
domBuilder.endPrefixMapping(prefix)
}
}
}else{
el.currentNSMap = currentNSMap;
el.localNSMap = localNSMap;
parseStack.push(el);
}
}
function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){
if(/^(?:script|textarea)$/i.test(tagName)){
var elEndStart = source.indexOf('</'+tagName+'>',elStartEnd);
var text = source.substring(elStartEnd+1,elEndStart);
if(/[&<]/.test(text)){
if(/^script$/i.test(tagName)){
//if(!/\]\]>/.test(text)){
//lexHandler.startCDATA();
domBuilder.characters(text,0,text.length);
//lexHandler.endCDATA();
return elEndStart;
//}
}//}else{//text area
text = text.replace(/&#?\w+;/g,entityReplacer);
domBuilder.characters(text,0,text.length);
return elEndStart;
//}
}
}
return elStartEnd+1;
}
function fixSelfClosed(source,elStartEnd,tagName,closeMap){
//if(tagName in closeMap){
var pos = closeMap[tagName];
if(pos == null){
//console.log(tagName)
pos = closeMap[tagName] = source.lastIndexOf('</'+tagName+'>')
}
return pos<elStartEnd;
//}
}
function _copy(source,target){
for(var n in source){target[n] = source[n]}
}
function parseDCC(source,start,domBuilder){//sure start with '<!'
var next= source.charAt(start+2)
switch(next){
case '-':
if(source.charAt(start + 3) === '-'){
var end = source.indexOf('-->',start+4);
//append comment source.substring(4,end)//<!--
domBuilder.comment(source,start+4,end-start-4);
return end+3;
}else{
//error
return -1;
}
default:
if(source.substr(start+3,6) == 'CDATA['){
var end = source.indexOf(']]>',start+9);
domBuilder.startCDATA();
domBuilder.characters(source,start+9,end-start-9);
domBuilder.endCDATA()
return end+3;
}
//<!DOCTYPE
//startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId)
var matchs = split(source,start);
var len = matchs.length;
if(len>1 && /!doctype/i.test(matchs[0][0])){
var name = matchs[1][0];
var pubid = len>3 && /^public$/i.test(matchs[2][0]) && matchs[3][0]
var sysid = len>4 && matchs[4][0];
var lastMatch = matchs[len-1]
domBuilder.startDTD(name,pubid,sysid);
domBuilder.endDTD();
return lastMatch.index+lastMatch[0].length
}
}
return -1;
}
function parseInstruction(source,start,domBuilder){
var end = source.indexOf('?>',start);
if(end){
var match = source.substring(start,end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
if(match){
var len = match[0].length;
domBuilder.processingInstruction(match[1], match[2]) ;
return end+2;
}else{//error
return -1;
}
}
return -1;
}
/**
* @param source
*/
function ElementAttributes(source){
}
ElementAttributes.prototype = {
setTagName:function(tagName){
if(!tagNamePattern.test(tagName)){
throw new Error('invalid tagName:'+tagName)
}
this.tagName = tagName
},
add:function(qName,value,offset){
if(!tagNamePattern.test(qName)){
throw new Error('invalid attribute:'+qName)
}
this[this.length++] = {qName:qName,value:value,offset:offset}
},
length:0,
getLocalName:function(i){return this[i].localName},
getOffset:function(i){return this[i].offset},
getQName:function(i){return this[i].qName},
getURI:function(i){return this[i].uri},
getValue:function(i){return this[i].value}
// ,getIndex:function(uri, localName)){
// if(localName){
//
// }else{
// var qName = uri
// }
// },
// getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
// getType:function(uri,localName){}
// getType:function(i){},
}
function _set_proto_(thiz,parent){
thiz.__proto__ = parent;
return thiz;
}
if(!(_set_proto_({},_set_proto_.prototype) instanceof _set_proto_)){
_set_proto_ = function(thiz,parent){
function p(){};
p.prototype = parent;
p = new p();
for(parent in thiz){
p[parent] = thiz[parent];
}
return p;
}
}
function split(source,start){
var match;
var buf = [];
var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
reg.lastIndex = start;
reg.exec(source);//skip <
while(match = reg.exec(source)){
buf.push(match);
if(match[1])return buf;
}
}
if(typeof require == 'function'){
exports.XMLReader = XMLReader;
}
if(typeof require == 'function'){
exports.XMLReader=XMLReader;
}

View File

@ -0,0 +1,18 @@
#!/bin/sh
set -e
rm -rf coverage
count=1;
for file in $(find t -name \*.t.js); do
node_modules/.bin/istanbul cover -x 't/**' $file > /dev/null 2>&1
mv coverage/coverage.json coverage/coverage$count.json
count=$(expr $count + 1)
done
node_modules/.bin/istanbul report --root coverage --dir coverage > /dev/null
sed -i -e s,'^SF:'`pwd`/,SF:, coverage/lcov.info
exit 0

View File

@ -0,0 +1,5 @@
#!/usr/bin/env node
require('proof')(1, function (ok) {
ok(require('../..'), 'require');
});

View File

@ -0,0 +1,17 @@
#!/bin/sh
set -e
echo ""
(proof run t/*/*.t.js | tee .proof.out | proof progress) || (proof errors < .proof.out) || exit 1
if [ "$TRAVIS" = "true" ]; then
echo "running with coverage"
t/cover
echo "submitting to coveralls.io"
(cat coverage/lcov.info | node_modules/.bin/coveralls) > /dev/null 2>&1
fi
echo ""

View File

@ -0,0 +1 @@
require('./o3xml')

View File

@ -0,0 +1 @@
exports.test = 1;

View File

@ -0,0 +1,21 @@
var DOMParser = require('xmldom').DOMParser;
require('./mock')
//Compatibility
{
var doc = new DOMParser().parseFromString("<xml/>",'text/xml');
var np = doc.__proto__.__proto__.__proto__;
for(var n in np){
if(/_NODE$/.test(n)){
// console.log(n.replace(/_NODE$/,''),np[n])
np[n.replace(/_NODE$/,'')] = np[n];
}
}
}
require.cache[require.resolve('node-o3-xml')]
= require.cache[require.resolve('./mock')];
require('node-o3-xml').parseFromString = function(xml){
return new DOMParser().parseFromString(xml,'text/xml');
}
require('node-o3-xml/test/test')

View File

@ -0,0 +1,152 @@
var wows = require('vows');
var assert = require('assert');
var XMLSerializer = require('xmldom').XMLSerializer;
var DOMParser = require('xmldom').DOMParser;
var DomJS = require("dom-js").DomJS;
try{
var Libxml = require('libxmljs');
}catch(e){
}
function xmldom(data){
console.time('xmldom');
var doc = new DOMParser({locator:null,checkLater:true}).parseFromString(data);
console.timeEnd('xmldom');
doc.toString = function(){
return new XMLSerializer().serializeToString(doc);
}
return doc;
}
function libxml(data){
if(Libxml){
console.time('libxml');
var doc = Libxml.parseXmlString(data);
console.timeEnd('libxml');
var ToString=doc.toString ;
doc.toString = function(){
return ToString.apply(this,arguments).replace(/^\s+|\s+$/g,'');
}
return doc;
}else{
console.warn('libxml is not installed')
}
}
function domjs(data){
console.time('dom-js');
var doc;
new DomJS().parse(data, function(err, dom) {
doc = dom;
});
console.timeEnd('dom-js');
doc.toString = function(){
return doc.toXml();
}
return doc
}
var maxRandomAttr =parseInt(Math.random()*60);
console.log('maxRandomAttr',maxRandomAttr)
function addAttributes(el){
var c =parseInt(Math.random()*maxRandomAttr);
while(c--){
el.setAttribute('dynamic-attr'+c,c+new Array(c).join('.'));
}
var child = el.firstChild;
while(child){
if(child.nodeType == 1){
addAttributes(child)
}else if(child.nodeType == 4){//cdata
el.insertBefore(el.ownerDocument.createTextNode(child.data),child);
el.removeChild(child);
}
child = child.nextSibling;
}
}
// Create a Test Suite
wows.describe('XML Node Parse').addBatch({
"big file parse":function(){
var fs = require('fs');
var path = require('path')
var data = fs.readFileSync(path.resolve(__dirname,'./test.xml'), 'ascii');
//data = "<?xml version=\"1.0\"?><xml><child> ![CDATA[v]] d &amp;</child>\n</xml>"
console.log('test simple xml')
var t1 = new Date();
var doc1 = xmldom(data);
var t2 = new Date();
var doc2 = domjs(data);
var t3 = new Date();
var doc3 = libxml(data);
var t4 = new Date();
var xmldomTime = t2-t1;
var domjsTime = t3-t2;
console.assert(domjsTime>xmldomTime,'xmldom performance must more height!!')
doc1 = doc1.cloneNode(true);
addAttributes(doc1.documentElement);
data = doc1.toString();
console.log('test more attribute xml')
var t1 = new Date();
var doc1 = xmldom(data);
var t2 = new Date();
var doc2 = domjs(data);
var t3 = new Date();
var doc3 = libxml(data);
var t4 = new Date();
var xmldomTime = t2-t1;
var domjsTime = t3-t2;
console.assert(domjsTime>xmldomTime,'xmldom performance must more height!!')
function xmlReplace(a,v){
switch(v){
case '&':
return '&amp;'
case '<':
return '&lt;'
default:
if(v.length>1){
return v.replace(/([&<])/g,xmlReplace)
}
}
}
xmldomresult = (domjs(doc1+'')+'').replace(/^<\?.*?\?>\s*|<!\[CDATA\[([\s\S]*?)\]\]>/g,xmlReplace)
domjsresult = (doc2+'').replace(/^<\?.*?\?>\s*|<!\[CDATA\[([\s\S]*?)\]\]>/g,xmlReplace)
data = xmldomresult;
//console.log(data.substring(100,200))
console.log('test more attribute xml without cdata')
var t1 = new Date();
var doc1 = xmldom(data);
var t2 = new Date();
var doc2 = domjs(data);
var t3 = new Date();
var doc3 = libxml(data);
var t4 = new Date();
var xmldomTime = t2-t1;
var domjsTime = t3-t2;
console.assert(domjsTime>xmldomTime,'xmldom performance must more height!!')
//console.log(xmldomresult,domjsresult)
//assert.equal(xmldomresult,domjsresult);
//,xmldomresult,domjsresult)
if(xmldomresult !== domjsresult){
for(var i=0;i<xmldomresult.length;i++){
if(xmldomresult.charAt(i)!=domjsresult.charAt(i)){
console.log(xmldomresult.charAt(i))
var begin = i-50;
var len = 100;
xmldomresult = xmldomresult.substr(begin,len)
domjsresult = domjsresult.substr(begin,len)
//console.log(xmldomresult.length,domjsresult.length)
console.log('pos'+i,'\n',xmldomresult,'\n\n\n\n',domjsresult)
console.assert(xmldomresult == domjsresult)
break;
}
}
}
//console.assert(xmldomresult == domjsresult,xmldomresult.length,i)
}
}).run(); // Run it

View File

@ -0,0 +1,64 @@
var wows = require('vows');
var DOMParser = require('xmldom').DOMParser;
// Create a Test Suite
wows.describe('XML attrs').addBatch({
"set attribute":function(){
var root = new DOMParser().parseFromString("<xml/>",'text/xml').documentElement;
root.setAttribute('a','1');
console.assert(root.attributes[0].localName == 'a');
root.setAttribute('b',2);
root.setAttribute('a',1);
root.setAttribute('a',1);
root.setAttribute('a',1);
console.assert(root.attributes.length == 2);
try {
var c = root.ownerDocument.createElement('c');
c.setAttributeNode(root.attributes.item(0));
} catch (e) {
console.assert(e.code == 10);
return;
}
console.assert(false);
},
"set ns attribute":function(){
var root = new DOMParser().parseFromString("<xml xmlns:a='a' xmlns:b='b' xmlns='e'><child/></xml>",'text/xml').documentElement;
var child = root.firstChild
child.setAttributeNS('a','a:a','1');
child.setAttributeNS('b','b:b','2');
child.setAttributeNS('b','b:a','1');
console.assert(child.attributes.length == 3,child.attributes.length,child+'');
child.setAttribute('a',1);
child.setAttributeNS('b','b:b','2');
console.assert(child.attributes.length == 4,child.attributes.length);
try {
var c = root.ownerDocument.createElement('c');
c.setAttributeNodeNS(root.attributes.item(0));
} catch (e) {
console.assert(e.code == 10);
return;
}
console.assert(false);
},
"override attribute":function(){
var root = new DOMParser().parseFromString("<xml xmlns:a='a' xmlns:b='b' xmlns='e'><child/></xml>",'text/xml').documentElement;
root.setAttributeNS('a','a:a','1');
console.assert(root.attributes.length == 4,root.attributes.length);
//not standart
// root.firstChild.setAttributeNode(root.attributes[0]);
// console.assert(root.attributes.length == 0);
},
"attribute namespace":function(){
var root = new DOMParser().parseFromString("<xml xmlns:a='a' xmlns:b='b' a:b='e'></xml>",'text/xml').documentElement;
console.assert(root.getAttributeNS("a", "b"), "e");
},
"override ns attribute":function(){
},
"set existed attribute":function(){
},
"set document existed attribute":function(){
}
}).run(); // Run it

View File

@ -0,0 +1,22 @@
var wows = require('vows');
var XMLSerializer = require('xmldom').XMLSerializer;
var DOMParser = require('xmldom').DOMParser;
// Create a Test Suite
wows.describe('XML Namespace Parse').addBatch({
'clone': function () {
var doc1 = new DOMParser().parseFromString("<doc1 attr1='1' attr2='a2'>text1<child>text2</child></doc1>",'text/xml')
var n =doc1.cloneNode(true)
console.assert(n == new XMLSerializer().serializeToString(doc1))
},
'import': function () {
var doc1 = new DOMParser().parseFromString("<doc2 attr='2'/>")
var doc2 = new DOMParser().parseFromString("<doc1 attr1='1' attr2='a2'>text1<child>text2</child></doc1>",'text/xml')
var doc3 = new DOMParser().parseFromString("<doc2 attr='2'><doc1 attr1='1' attr2='a2'>text1<child>text2</child></doc1></doc2>")
var n =doc1.importNode(doc2.documentElement, true)
doc1.documentElement.appendChild(n)
console.assert(doc1 == doc3+'')
console.assert(doc2 != doc3+'')
}
}).run(); // Run it

View File

@ -0,0 +1,139 @@
var wows = require('vows');
var DOMParser = require('xmldom').DOMParser;
var XMLSerializer = require('xmldom').XMLSerializer;
// Create a Test Suite
wows.describe('XML Namespace Parse').addBatch({
// See: http://jsfiddle.net/bigeasy/ShcXP/1/
"Document_getElementsByTagName":function () {
var doc = new DOMParser().parseFromString('<a><b/></a>');
console.assert(doc.getElementsByTagName('*').length == 2);
console.assert(doc.documentElement.getElementsByTagName('*').length == 1);
},
'getElementsByTagName': function () {
var doc = new DOMParser().parseFromString('<xml xmlns="http://test.com" xmlns:t="http://test.com" xmlns:t2="http://test2.com">' +
'<t:test/><test/><t2:test/>'+
'<child attr="1"><test><child attr="2"/></test></child>' +
'<child attr="3"/></xml>','text/xml');
var childs = doc.documentElement.getElementsByTagName('child');
console.assert(childs.item(0).getAttribute('attr')=="1",childs.item(0)+'');
console.assert(childs.item(1).getAttribute('attr')=="2",childs.item(1)+'');
console.assert(childs.item(2).getAttribute('attr')=="3",childs.item(2)+'');
console.assert(childs.length==3,3,childs.length);
var childs = doc.getElementsByTagName('child');
console.assert(childs.item(0).getAttribute('attr')=="1",childs.item(0)+'');
console.assert(childs.item(1).getAttribute('attr')=="2",childs.item(1)+'');
console.assert(childs.item(2).getAttribute('attr')=="3",childs.item(2)+'');
console.assert(childs.length==3,3,childs.length);
var childs = doc.documentElement.getElementsByTagName('*');
for(var i=0,buf = [];i<childs.length;i++){
buf.push(childs[i].tagName)
}
console.assert(childs.length==7,childs.length,buf);
var feed = new DOMParser().parseFromString('<feed><entry>foo</entry></feed>');
var entries = feed.documentElement.getElementsByTagName('entry');
console.log(entries[0].nodeName);
console.log(feed.documentElement.childNodes.item(0).nodeName);
},
'getElementsByTagNameNS': function () {
var doc = new DOMParser().parseFromString('<xml xmlns="http://test.com" xmlns:t="http://test.com" xmlns:t2="http://test2.com">' +
'<t:test/><test/><t2:test/>'+
'<child attr="1"><test><child attr="2"/></test></child>' +
'<child attr="3"/></xml>','text/xml');
var childs = doc.documentElement.getElementsByTagNameNS("http://test.com",'*');
console.assert(childs.length==6,childs.length);
var childs = doc.getElementsByTagNameNS("http://test.com",'*');
console.assert(childs.length==7,childs.length);
var childs = doc.documentElement.getElementsByTagNameNS("http://test.com",'test');
console.assert(childs.length==3,childs.length);
var childs = doc.getElementsByTagNameNS("http://test.com",'test');
console.assert(childs.length==3,childs.length);
},
'getElementById': function () {
var doc = new DOMParser().parseFromString('<xml xmlns="http://test.com" id="root">' +
'<child id="a1" title="1"><child id="a2" title="2"/></child>' +
'<child id="a1" title="3"/></xml>','text/xml');
console.assert(doc.getElementById('root'))
console.assert(doc.getElementById('a1').getAttribute('title')=="1",doc.getElementById('a1'));
console.assert(doc.getElementById('a2').getAttribute('title')=="2",doc.getElementById('a2'));
console.assert(doc.getElementById('a2').getAttribute('title2')=="",doc.getElementById('a2'));
},
"append exist child":function(){
var doc = new DOMParser().parseFromString('<xml xmlns="http://test.com" id="root">' +
'<child1 id="a1" title="1"><child11 id="a2" title="2"/></child1>' +
'<child2 id="a1" title="3"/><child3 id="a1" title="3"/></xml>','text/xml');
var doc1 = doc;
var str1=new XMLSerializer().serializeToString(doc);
var doc2 = doc1.cloneNode(true);
var doc3 = doc1.cloneNode(true);
var doc4 = doc1.cloneNode(true);
doc3.documentElement.appendChild(doc3.documentElement.lastChild);
doc4.documentElement.appendChild(doc4.documentElement.firstChild);
var str2=new XMLSerializer().serializeToString(doc2);
var str3=new XMLSerializer().serializeToString(doc3);
var str4=new XMLSerializer().serializeToString(doc4);
console.assert(str1 == str2 && str2 == str3,str3,str1);
console.assert(str3 != str4 && str3.length == str4.length,str3);
},
"append exist other child":function(){
var doc = new DOMParser().parseFromString('<xml xmlns="http://test.com" id="root">' +
'<child1 id="a1" title="1"><child11 id="a2" title="2"><child/></child11></child1>' +
'<child2 id="a1" title="3"/><child3 id="a1" title="3"/></xml>','text/xml');
var doc1 = doc;
var str1=new XMLSerializer().serializeToString(doc);
var doc2 = doc1.cloneNode(true);
console.assert(doc2.documentElement.lastChild.childNodes.length == 0);
doc2.documentElement.appendChild(doc2.documentElement.firstChild.firstChild);
var str2=new XMLSerializer().serializeToString(doc2);
console.assert(doc2.documentElement.lastChild.childNodes.length == 1);
console.assert(str1 != str2 && str1.length != str2.length,str3);
var doc3 = new DOMParser().parseFromString(str2,'text/xml');
doc3.documentElement.firstChild.appendChild(doc3.documentElement.lastChild);
var str3 = new XMLSerializer().serializeToString(doc3);
console.assert(str1 == str3);
},
"set textContent":function() {
var doc = new DOMParser().parseFromString('<test><a/><b><c/></b></test>');
var a = doc.documentElement.firstChild;
var b = a.nextSibling;
a.textContent = 'hello';
console.assert(doc.documentElement.toString() == '<test><a>hello</a><b><c/></b></test>');
b.textContent = 'there';
console.assert(doc.documentElement.toString() == '<test><a>hello</a><b>there</b></test>');
b.textContent = '';
console.assert(doc.documentElement.toString() == '<test><a>hello</a><b/></test>');
doc.documentElement.textContent = 'bye';
console.assert(doc.documentElement.toString() == '<test>bye</test>');
},
"nested append failed":function(){
},
"self append failed":function(){
}
}).run(); // Run it

View File

@ -0,0 +1,15 @@
var wows = require('vows');
var DOMParser = require('xmldom').DOMParser;
var XMLSerializer = require('xmldom').XMLSerializer;
wows.describe('DOM DocumentFragment').addBatch({
// see: http://jsfiddle.net/9Wmh2/1/
"append empty fragment":function(){
var document = new DOMParser().parseFromString('<p id="p"/>');
var fragment = document.createDocumentFragment();
document.getElementById("p").insertBefore(fragment, null);
fragment.appendChild(document.createTextNode("a"));
document.getElementById("p").insertBefore(fragment, null);
console.assert(document.toString() == '<p id="p">a</p>', document.toString());
},
}).run();

View File

@ -0,0 +1,5 @@
require('./element');
require('./level3');
require('./clone');
require('./attr');
require('./serializer');

View File

@ -0,0 +1,8 @@
var wows = require('vows');
var DOMParser = require('xmldom').DOMParser;
// Create a Test Suite
wows.describe('XML Namespace Parse').addBatch({
"test":function(){}
//see namespace.js
}).run(); // Run it

View File

@ -0,0 +1,14 @@
var wows = require('vows');
var DOMParser = require('xmldom').DOMParser;
wows.describe('XML Serializer').addBatch({
'text node containing "]]>"': function() {
var doc = new DOMParser().parseFromString('<test/>', 'text/xml');
doc.documentElement.appendChild(doc.createTextNode('hello ]]> there'));
console.assert(doc.documentElement.firstChild.toString() == 'hello ]]> there',doc.documentElement.firstChild.toString());
},
'<script> element with no children': function() {
var doc = new DOMParser().parseFromString('<html><script></script></html>', 'text/html');
console.assert(doc.documentElement.firstChild.toString() == '<script></script>');
},
}).run();

View File

@ -0,0 +1,71 @@
var wows = require('vows');
var DOMParser = require('xmldom').DOMParser;
wows.describe('errorHandle').addBatch({
'only function two args': function() {
var error = {}
var parser = new DOMParser({
errorHandler:function(key,msg){error[key] = msg}
});
try{
var doc = parser.parseFromString('<html disabled><1 1="2"/></body></html>', 'text/xml');
console.assert(error.warning!=null ,'error.error:'+error.warning);
console.assert(error.error!=null ,'error.error:'+error.error);
console.assert(error.fatalError!=null ,'error.error:'+error.fatalError);
//console.log(doc+'')
}catch(e){
}
},
'only function': function() {
var error = []
var parser = new DOMParser({
errorHandler:function(msg){error.push(msg)}
});
try{
var doc = parser.parseFromString('<html disabled><1 1="2"/></body></html>', 'text/xml');
error.map(function(e){error[e.replace(/\:[\s\S]*/,'')]=e})
console.assert(error.warning!=null ,'error.error:'+error.warning);
console.assert(error.error!=null ,'error.error:'+error.error);
console.assert(error.fatalError!=null ,'error.error:'+error.fatalError);
//console.log(doc+'')
}catch(e){
}
},
'only function': function() {
var error = []
var errorMap = []
new DOMParser({
errorHandler:function(msg){error.push(msg)}
}).parseFromString('<html><body title="1<2">test</body></html>', 'text/xml');
'warn,warning,error,fatalError'.replace(/\w+/g,function(k){
var errorHandler = {};
errorMap[k] = [];
errorHandler[k] = function(msg){errorMap[k] .push(msg)}
new DOMParser({errorHandler:errorHandler}).parseFromString('<html><body title="1<2">test</body></html>', 'text/xml');
});
for(var n in errorMap){
console.assert(error.length == errorMap[n].length)
}
},
'error function': function() {
var error = []
var parser = new DOMParser({
locator:{},
errorHandler:{
error:function(msg){
error.push(msg);
throw new Error(msg)
}
}
});
try{
var doc = parser.parseFromString('<html><body title="1<2"><table>&lt;;test</body></body></html>', 'text/html');
}catch(e){
console.log(e);
console.assert(/\n@#\[line\:\d+,col\:\d+\]/.test(error.join(' ')),'line,col must record:'+error)
return;
}
console.assert(false,doc+' should be null');
}
}).run();

View File

@ -0,0 +1,89 @@
var wows = require('vows');
var assert = require('assert');
var DOMParser = require('xmldom').DOMParser;
var XMLSerializer = require('xmldom').XMLSerializer;
var parser = new DOMParser();
// Create a Test Suite
wows.describe('html normalizer').addBatch({
'text & <': function () {
var dom = new DOMParser().parseFromString('<div>&amp;&lt;123&456<789;&&</div>','text/html');
console.assert(dom == '<div>&amp;&lt;123&amp;456&lt;789;&amp;&amp;</div>',dom+'')
var dom = new DOMParser().parseFromString('<div><123e>&<a<br/></div>','text/html');
console.assert(dom == '<div>&lt;123e>&amp;&lt;a<br/></div>',dom+'')
var dom = new DOMParser().parseFromString('<div>&nbsp;&copy;&nbsp&copy</div>','text/html');
console.assert(dom == '<div>\u00a0\u00a9&amp;nbsp&amp;copy</div>',dom+'')
var dom = new DOMParser().parseFromString('<html xmlns:x="1"><body/></html>','text/html');
console.assert(dom == '<html xmlns:x="1"><body></body></html>',dom+'')
},
'attr': function () {
var dom = new DOMParser().parseFromString('<html test="a<b && a>b && \'&amp;&&\'"/>','text/html');
console.assert(dom == '<html test="a&lt;b &amp;&amp; a>b &amp;&amp; \'&amp;&amp;&amp;\'"></html>',dom+'')
var dom = new DOMParser().parseFromString('<div test="alert(\'<br/>\')"/>','text/html');
console.assert(dom == '<div test="alert(\'&lt;br/>\')"></div>',dom+'')
var dom = new DOMParser().parseFromString('<div test="a<b&&a< c && a>d"></div>','text/html');
console.assert(dom == '<div test="a&lt;b&amp;&amp;a&lt; c &amp;&amp; a>d"></div>',dom+'')
var dom = new DOMParser().parseFromString('<div a=& bb c d=123&&456/>','text/html');
console.assert(dom == '<div a="&amp;" bb="bb" c="c" d="123&amp;&amp;456"></div>',dom+'')
var dom = new DOMParser().parseFromString('<div a=& a="&\'\'" b/>','text/html');
console.assert(dom == '<div a="&amp;\'\'" b="b"></div>',dom+'')
},
'attrQute': function () {
var dom = new DOMParser().parseFromString('<html test="123"/>','text/html');
console.assert(dom == '<html test="123"></html>',dom+'')
// var dom = new DOMParser().parseFromString('<r><Label onClick="doClick..>Hello, World</Label></r>','text/html');
// console.assert(dom == '<r><Label onClick="doClick..">Hello, World</Label></r>',dom+'!!')
//
var dom = new DOMParser().parseFromString('<Label onClick=doClick..">Hello, World</Label>','text/html');
console.assert(dom == '<Label onClick="doClick..">Hello, World</Label>',dom+'')
},
"unclosed":function(){
var dom = new DOMParser().parseFromString('<html><meta><link><img><br><hr><input></html>','text/html');
console.assert(dom == '<html><meta/><link/><img/><br/><hr/><input/></html>',dom+'')
var dom = new DOMParser().parseFromString('<html title =1/2></html>','text/html');
console.assert(dom == '<html title="1/2"></html>',dom+'')
var dom = new DOMParser().parseFromString('<html title= 1/>','text/html');
console.assert(dom == '<html title="1"></html>',dom+'')
var dom = new DOMParser().parseFromString('<html title = 1/>','text/html');
console.assert(dom == '<html title="1"></html>',dom+'')
var dom = new DOMParser().parseFromString('<html title/>','text/html');
console.assert(dom == '<html title="title"></html>',dom+'')
var dom = new DOMParser().parseFromString('<html><meta><link><img><br><hr><input></html>','text/html');
console.assert(dom == '<html><meta/><link/><img/><br/><hr/><input/></html>',dom+'')
},
'script': function () {
var dom = new DOMParser().parseFromString('<script>alert(a<b&&c?"<br>":">>");</script>','text/html');
console.assert(dom == '<script>alert(a<b&&c?"<br>":">>");</script>',dom+'')
var dom = new DOMParser().parseFromString('<script>alert(a<b&&c?"<br>":">>");</script>','text/xml');
console.assert(dom == '<script>alert(a&lt;b&amp;&amp;c?"<br/>":">>");</script>',dom+'')
var dom = new DOMParser().parseFromString('<script>alert(a<b&&c?"<br/>":">>");</script>','text/html');
console.assert(dom == '<script>alert(a<b&&c?"<br/>":">>");</script>',dom+'')
},
'textarea': function () {
var dom = new DOMParser().parseFromString('<textarea>alert(a<b&&c?"<br>":">>");</textarea>','text/html');
console.assert(dom == '<textarea>alert(a&lt;b&amp;&amp;c?"&lt;br>":">>");</textarea>',dom+'')
var dom = new DOMParser().parseFromString('<textarea>alert(a<b&&c?"<br>":">>");</textarea>','text/xml');
console.assert(dom == '<textarea>alert(a&lt;b&amp;&amp;c?"<br/>":">>");</textarea>',dom+'')
}
}).run();

View File

@ -0,0 +1,63 @@
var XMLSerializer = require('xmldom').XMLSerializer;
var DOMParser = require('xmldom').DOMParser;
try{
var libxml = require('libxmljs');
}catch(e){
var DomJS = require("dom-js");
}
var assert = require('assert');
var oldParser = DOMParser.prototype.parseFromString ;
function format(s){
if(libxml){
var result = libxml.parseXmlString(s).toString().replace(/^\s+|\s+$/g,'');
//console.log(result.charCodeAt().toString(16),result)
}else{
var domjs = new DomJS.DomJS();
domjs.parse(s, function(err, dom) {
result = dom.toXml();
});
}
return result;
}
function check(data,doc){
var domjsresult = format(data);
var xmldomresult = new XMLSerializer().serializeToString(doc);
var xmldomresult2 = new XMLSerializer().serializeToString(doc.cloneNode(true));
assert.equal(xmldomresult,xmldomresult2);
xmldomresult = xmldomresult.replace(/^<\?.*?\?>\s*|<!\[CDATA\[\]\]>/g,'')
domjsresult = domjsresult.replace(/^<\?.*?\?>\s*|<!\[CDATA\[\]\]>/g,'')
//console.log('['+xmldomresult+'],['+domjsresult+']')
if(xmldomresult!=domjsresult){
assert.equal(format(xmldomresult),domjsresult);
}
}
DOMParser.prototype.parseFromString = function(data,mimeType){
var doc = oldParser.apply(this,arguments);
function ck(){
if(!/\/x?html?\b/.test(mimeType)){
try{
check(data,doc);
}catch(e){console.dir(e)}
}
}
if(this.options.checkLater){
setTimeout(ck,1);
}else{ck()}
return doc;
}
function include(){
for(var i=0;i<arguments.length;i++){
var file = arguments[i]
console.log('test ',file);
require(file);
}
}
include('./dom','./parse-element','./node','./namespace','./html/normalize'
,'./error','./locator'
,'./big-file-performance'
)

View File

@ -0,0 +1,50 @@
var wows = require('vows');
var DOMParser = require('xmldom').DOMParser;
function assertPosition(n, line, col) {
console.assert(n.lineNumber == line,'lineNumber:'+n.lineNumber+'/'+line);
console.assert(n.columnNumber == col,'columnNumber:'+n.columnNumber+'/'+col);
}
wows.describe('DOMLocator').addBatch({
'node positions': function() {
var parser = new DOMParser({locator:{}});
var doc = parser.parseFromString('<?xml version="1.0"?><!-- aaa -->\n<test>\n <a attr="value"><![CDATA[1]]>something\n</a>x</test>', 'text/xml');
var test = doc.documentElement;
var a = test.firstChild.nextSibling;
assertPosition(doc.firstChild, 1, 1);
assertPosition(doc.firstChild.nextSibling, 1, 1+'<?xml version="1.0"?>'.length);
assertPosition(test, 2, 1);
//assertPosition(test.firstChild, 1, 7);
assertPosition(a, 3, 3);
assertPosition(a.firstChild, 3, 19);
assertPosition(a.firstChild.nextSibling, 3, 19+'<![CDATA[1]]>'.length);
assertPosition(test.lastChild, 4, 5);
},
'error positions':function(){
var error = []
var parser = new DOMParser({
locator:{systemId:'c:/test/1.xml'},
errorHandler:function(msg){
error.push(msg);
}
});
var doc = parser.parseFromString('<html><body title="1<2"><table>&lt;;test</body></body></html>', 'text/html');
console.assert(/\n@c\:\/test\/1\.xml#\[line\:\d+,col\:\d+\]/.test(error.join(' ')),'line,col must record:'+error)
},
'error positions p':function(){
var error = []
var parser = new DOMParser({
locator:{},
errorHandler:function(msg){
error.push(msg);
}
});
var doc = parser.parseFromString('<root>\n\t<err</root>', 'text/html');
var root = doc.documentElement;
var textNode = root.firstChild;
console.log(root+'/'+textNode)
console.assert(/\n@#\[line\:2,col\:2\]/.test(error.join(' ')),'line,col must record:'+error);
console.log(textNode.lineNumber+'/'+textNode.columnNumber)
}
}).run();

View File

@ -0,0 +1,32 @@
var wows = require('vows');
var DOMParser = require('xmldom').DOMParser;
// Create a Test Suite
wows.describe('XML Namespace Parse').addBatch({
'default namespace': function () {
var dom = new DOMParser().parseFromString('<xml xmlns="http://test.com"><child attr="1"/></xml>','text/xml');
var root = dom.documentElement;
console.assert(root.namespaceURI=='http://test.com')
console.assert(root.lookupNamespaceURI('') == 'http://test.com')
console.assert(root.firstChild.namespaceURI=='http://test.com')
console.assert(root.firstChild.lookupNamespaceURI('') == 'http://test.com')
console.assert(root.firstChild.getAttributeNode('attr').namespaceURI==null)
},
'prefix namespace': function () {
var dom = new DOMParser().parseFromString('<xml xmlns:p1="http://p1.com" xmlns:p2="http://p2.com"><p1:child a="1" p1:attr="1" b="2"/><p2:child/></xml>','text/xml');
var root = dom.documentElement;
console.assert(root.firstChild.namespaceURI == 'http://p1.com')
console.assert(root.lookupNamespaceURI('p1') == 'http://p1.com')
console.assert(root.firstChild.getAttributeNode('attr') == null)
console.assert(root.firstChild.getAttributeNode('p1:attr').namespaceURI == 'http://p1.com')
console.assert(root.firstChild.nextSibling.namespaceURI == 'http://p2.com')
console.assert(root.firstChild.nextSibling.lookupNamespaceURI('p2') == 'http://p2.com')
},
'after prefix namespace': function () {
var dom = new DOMParser().parseFromString('<xml xmlns:p="http://test.com"><p:child xmlns:p="http://p.com"/><p:child/></xml>','text/xml');
var root = dom.documentElement;
console.assert(root.firstChild.namespaceURI=='http://p.com')
console.assert(root.lastChild.namespaceURI=='http://test.com')
console.assert(root.firstChild.nextSibling.lookupNamespaceURI('p') == 'http://test.com')
}
}).run(); // Run it

View File

@ -0,0 +1,102 @@
var wows = require('vows');
var assert = require('assert');
var DOMParser = require('xmldom').DOMParser;
var XMLSerializer = require('xmldom').XMLSerializer;
var parser = new DOMParser();
// Create a Test Suite
wows.describe('XML Node Parse').addBatch({
'element': function () {
var dom = new DOMParser().parseFromString('<xml><child/></xml>');
console.assert (dom.childNodes.length== 1,dom.childNodes.length, 1);
console.assert (dom.documentElement.childNodes.length== 1);
console.assert (dom.documentElement.tagName== 'xml');
console.assert (dom.documentElement.firstChild.tagName== 'child');
},
'text':function(){
var dom = new DOMParser().parseFromString('<xml>start center end</xml>');
var root = dom.documentElement;
console.assert( root.firstChild.data =='start center end');
console.assert( root.firstChild.nextSibling ==null);
},
'cdata': function () {
var dom = new DOMParser().parseFromString('<xml>start <![CDATA[<encoded>]]> end<![CDATA[[[[[[[[[]]]]]]]]]]></xml>');
var root = dom.documentElement;
console.assert ( root.firstChild.data =='start ');
console.assert ( root.firstChild.nextSibling.data =='<encoded>');
console.assert ( root.firstChild.nextSibling.nextSibling.nextSibling.data =='[[[[[[[[]]]]]]]]');
},
'cdata empty': function () {
var dom = new DOMParser().parseFromString('<xml><![CDATA[]]>start <![CDATA[]]> end</xml>');
var root = dom.documentElement;
console.assert ( root.textContent =='start end');
},
'comment': function(){
var dom = new DOMParser().parseFromString('<xml><!-- comment&>< --></xml>');
var root = dom.documentElement;
console.assert ( root.firstChild.nodeValue ==' comment&>< ');
},
'cdata comment': function(){
var dom = new DOMParser().parseFromString('<xml>start <![CDATA[<encoded>]]> <!-- comment -->end</xml>');
var root = dom.documentElement;
console.assert ( root.firstChild.nodeValue =='start ');
console.assert ( root.firstChild.nextSibling.nodeValue =='<encoded>');
console.assert ( root.firstChild.nextSibling.nextSibling.nextSibling.nodeValue ==' comment ');
console.assert ( root.firstChild.nextSibling.nextSibling.nextSibling.nextSibling.nodeValue =='end');
},
'append node': function () {
var dom = new DOMParser().parseFromString('<xml/>');
var child = dom.createElement("child");
console.assert ( child == dom.documentElement.appendChild(child));
console.assert ( child == dom.documentElement.firstChild);
var fragment = new dom.createDocumentFragment();
console.assert ( child == fragment.appendChild(child));
},
'insert node': function () {
var dom = new DOMParser().parseFromString('<xml><child/></xml>');
var node = dom.createElement("sibling");
var child = dom.documentElement.firstChild;
child.parentNode.insertBefore(node, child);
console.assert ( node == child.previousSibling);
console.assert ( node.nextSibling == child);
console.assert ( node.parentNode == child.parentNode);
},
'insert fragment': function () {
var dom = new DOMParser().parseFromString('<xml><child/></xml>');
var fragment = dom.createDocumentFragment();
assert(fragment.nodeType === 11);
var first = fragment.appendChild(dom.createElement("first"));
var last = fragment.appendChild(dom.createElement("last"));
console.assert ( fragment.firstChild == first);
console.assert ( fragment.lastChild == last);
console.assert ( last.previousSibling == first);
console.assert ( first.nextSibling == last);
var child = dom.documentElement.firstChild;
child.parentNode.insertBefore(fragment, child);
console.assert ( last.previousSibling == first);
console.assert ( first.nextSibling == last);
console.assert ( child.parentNode.firstChild == first);
console.assert ( last == child.previousSibling);
console.assert ( last.nextSibling == child);
console.assert ( first.parentNode == child.parentNode);
console.assert ( last.parentNode == child.parentNode);
}
}).addBatch({
"instruction":function(){
var source = '<?xml version="1.0"?><root><child>&amp;<!-- &amp; --></child></root>';
var doc = new DOMParser().parseFromString(source,"text/xml");
var source2 = new XMLSerializer().serializeToString(doc);
console.assert(source == source2,source2);
}
}).run(); // Run it
//var ELEMENT_NODE = NodeType.ELEMENT_NODE = 1;
//var ATTRIBUTE_NODE = NodeType.ATTRIBUTE_NODE = 2;
//var TEXT_NODE = NodeType.TEXT_NODE = 3;
//var CDATA_SECTION_NODE = NodeType.CDATA_SECTION_NODE = 4;
//var ENTITY_REFERENCE_NODE = NodeType.ENTITY_REFERENCE_NODE = 5;
//var ENTITY_NODE = NodeType.ENTITY_NODE = 6;
//var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
//var COMMENT_NODE = NodeType.COMMENT_NODE = 8;
//var DOCUMENT_NODE = NodeType.DOCUMENT_NODE = 9;
//var DOCUMENT_TYPE_NODE = NodeType.DOCUMENT_TYPE_NODE = 10;
//var DOCUMENT_FRAGMENT_NODE = NodeType.DOCUMENT_FRAGMENT_NODE = 11;
//var NOTATION_NODE = NodeType.NOTATION_NODE = 12;

View File

@ -0,0 +1,31 @@
var wows = require('vows');
var assert = require('assert');
var DOMParser = require('xmldom').DOMParser;
var XMLSerializer = require('xmldom').XMLSerializer;
var parser = new DOMParser();
// Create a Test Suite
wows.describe('XML Node Parse').addBatch({
'noAttribute': function () {
var dom = new DOMParser().parseFromString('<xml ></xml>','text/xml');
var dom = new DOMParser().parseFromString('<xml></xml>','text/xml');
var dom = new DOMParser().parseFromString('<xml />','text/xml');
var dom = new DOMParser().parseFromString('<xml/>','text/xml');
var dom = new DOMParser().parseFromString('<xml/>','text/xml');
},
'simpleAttribute': function () {
var dom = new DOMParser().parseFromString('<xml a="1" b="2"></xml>','text/xml');
var dom = new DOMParser().parseFromString('<xml a="1" b="2" ></xml>','text/xml');
var dom = new DOMParser().parseFromString('<xml a="1" b=\'\'></xml>','text/xml');
var dom = new DOMParser().parseFromString('<xml a="1" b=\'\' ></xml>','text/xml');
var dom = new DOMParser().parseFromString('<xml a="1" b="2/">','text/xml');
var dom = new DOMParser().parseFromString('<xml a="1" b="2" />','text/xml');
var dom = new DOMParser().parseFromString('<xml a="1" b=\'\'/>','text/xml');
var dom = new DOMParser().parseFromString('<xml a="1" b=\'\' />','text/xml');
},
'nsAttribute': function () {
var dom = new DOMParser().parseFromString('<xml xmlns="1" xmlns:a="2" a:test="3"></xml>','text/xml');
var dom = new DOMParser().parseFromString('<xml xmlns="1" xmlns:a="2" a:test="3" ></xml>','text/xml');
var dom = new DOMParser().parseFromString('<xml xmlns="1" xmlns:a="2" a:test="3/">','text/xml');
var dom = new DOMParser().parseFromString('<xml xmlns="1" xmlns:a="2" a:test="3" />','text/xml');
}
}).run();

View File

@ -0,0 +1,11 @@
var wows = require('vows');
var DOMParser = require('xmldom').DOMParser;
wows.describe('errorHandle').addBatch({
'simple': function() {
var parser = new DOMParser();
var doc = parser.parseFromString('<html><body title="1<2"></body></html>', 'text/html');
console.log(doc+'');
}
}).run();

View File

@ -0,0 +1,24 @@
var wows = require('vows');
var assert = require('assert');
var DOMParser = require('xmldom').DOMParser;
var XMLSerializer = require('xmldom').XMLSerializer;
var doc = new DOMParser().parseFromString('<xml xmlns="http://test.com" id="root">' +
'<child1 id="a1" title="1"><child11 id="a2" title="2"/></child1>' +
'<child2 id="a1" title="3"/><child3 id="a1" title="3"/></xml>','text/xml');
var doc1 = doc;
var str1=new XMLSerializer().serializeToString(doc);
var doc2 = doc1.cloneNode(true);
var doc3 = doc1.cloneNode(true);
var doc4 = doc1.cloneNode(true);
doc3.documentElement.appendChild(doc3.documentElement.lastChild);
//doc4.documentElement.appendChild(doc4.documentElement.firstChild);
var str2=new XMLSerializer().serializeToString(doc2);
var str3=new XMLSerializer().serializeToString(doc3);
var str4=new XMLSerializer().serializeToString(doc4);
console.assert(str1 == str3,str3,str1);
//console.assert(str3 != str4 && str3.length == str4.length,str3);

File diff suppressed because it is too large Load Diff

49
kitchenradio/node_modules/playlist-parser/package.json generated vendored Normal file
View File

@ -0,0 +1,49 @@
{
"name": "playlist-parser",
"version": "0.0.12",
"description": "Parse m3u, m3u extended, and pls",
"main": "lib/parser.min.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "grunt test"
},
"repository": {
"type": "git",
"url": "git://github.com/nickdesaulniers/javascript-playlist-parser.git"
},
"keywords": [
"javascript",
"playlist",
"parse",
"m3u",
"pls",
"asx"
],
"author": {
"name": "Nick Desaulniers"
},
"license": "Dual MIT & Beerware",
"bugs": {
"url": "https://github.com/nickdesaulniers/javascript-playlist-parser/issues"
},
"devDependencies": {
"chai": "1.7.2",
"grunt-contrib-coffee": "0.7.0",
"grunt-mocha-test": "0.6.3",
"grunt-contrib-uglify": "~0.2.4"
},
"dependencies": {
"xmldom": "0.1.16"
},
"readme": "#javascript-playlist-parser#\nParse m3u, m3u extended, pls, and asx in JavaScript.\n\n##Usage##\n###Browser###\nAdds `window.M3U.parse`, `window.PLS.parse`, and `window.ASX.parse` which take a\nstring and return a possibly empty array of objects.\n\n```html\n<script src=\"https://raw.github.com/nickdesaulniers/javascript-playlist-parser/master/lib/parser.min.js\"></script>\n```\n\n```javascript\n// Fetch the playlist file, using xhr for example\nvar xhr = new XMLHttpRequest();\nxhr.open(\"GET\", \"my_playlist.m3u\");\nxhr.overrideMimeType(\"audio/x-mpegurl\"); // Needed, see below.\nxhr.onload = parse;\nxhr.send();\n\n// Parse it\nfunction parse () {\n var playlist = M3U.parse(this.response);\n var audio = new Audio();\n next(audio, playlist, 0);\n};\n\n// Play each song after a song finishes\nfunction next (audio, playlist, i) {\n if (i < playlist.length) {\n audio.src = playlist[i++].file;\n audio.onended = next.bind(null, audio, playlist, i);\n audio.play();\n }\n};\n```\n\n[Demo](http://nickdesaulniers.github.io/javascript-playlist-parser/)\n\n###Node.js###\nAdds `require('playlist-parser').M3U.parse`,\n`require('playlist-parser').PLS.parse`,\nand `require('playlist-parser').ASX.parse`\nwhich take a string and return\na possibly empty array of objects.\n\n`npm install playlist-parser`\n```javascript\nvar parsers = require(\"playlist-parser\");\nvar M3U = parsers.M3U;\n\nvar fs = require(\"fs\");\nvar playlist = M3U.parse(fs.readFileSync(\"my_playlist.m3u\", { encoding: \"utf8\" }));\n```\n##Return Values##\nCalls to parse return an array of objects that look like:\n\n###M3U Simple or ASX###\n```javascript\n[{\n file: \"http://song.com/song.mp3\"\n}]\n```\n\n###M3U Extended###\n```javascript\n[{\n length: 1234,\n artist: \"Iron Maiden\",\n title: \"Rime of the Ancient Mariner\",\n file: \"http://song.com/song.mp3\"\n}]\n```\n\n###PLS###\n```javascript\n[{\n file: \"http://song.com/song.mp3\",\n title: \"My favorite song ever by my favorite artist\",\n length: 1234\n}]\n```\n\n##MIME Types##\n* m3u -> audio/x-mpegurl\n* pls -> audio/x-scpls\n* asx -> video/x-ms-asf\n\n##License##\n\nThis software is dual licensed under the MIT and Beerware license.\n\nThe MIT License (MIT)\n\nCopyright (c) 2013 Nick Desaulniers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\"THE BEER-WARE LICENSE\" (Revision 42):\n<nick@mozilla.com> wrote this file. As long as you retain this\nnotice you can do whatever you want with this stuff. If we meet some day,\nand you think this stuff is worth it, you can buy me a beer in return.\nNick Desaulniers\n\n",
"readmeFilename": "README.md",
"homepage": "https://github.com/nickdesaulniers/javascript-playlist-parser",
"_id": "playlist-parser@0.0.12",
"dist": {
"shasum": "4250e5b11771ad68213983bf9bb6ecab64ddf526"
},
"_from": "playlist-parser@*",
"_resolved": "https://registry.npmjs.org/playlist-parser/-/playlist-parser-0.0.12.tgz"
}

View File

@ -16,6 +16,8 @@
"dateformat": "*", "dateformat": "*",
"eyespect": "*", "eyespect": "*",
"interface-addresses": "*" "interface-addresses": "*",
"node-mplayer": "*",
"playlist-parser": "*"
} }
} }

View File

@ -30,6 +30,7 @@ var Radio = function() {
var channel = channels[idx]; var channel = channels[idx];
var $tile = $tileTemplate.clone(); var $tile = $tileTemplate.clone();
$tile.attr('data-id', idx);
fillTileWithChannel($tile, channel); fillTileWithChannel($tile, channel);
addClickToTile($tile); addClickToTile($tile);
@ -55,8 +56,29 @@ var Radio = function() {
$tile.click(function(e) { $tile.click(function(e) {
e.preventDefault(); e.preventDefault();
$navigation.find('.tile').removeClass('nowplaying');
var stream = $tile.attr('href'); var stream = $tile.attr('href');
var idx = $tile.attr('data-id');
console.log('Stream: ' + stream); console.log('Stream: ' + stream);
$.ajax({
url: '/action/play/'+idx+'/',
context: document.body,
statusCode: {
200: function() {
console.log('ok');
},
404: function() {
console.log('Resource not found');
},
500: function() {
console.log('Something went wrong');
}
}
}).done(function() {
$tile.addClass('nowplaying');
});
}); });
} }

View File

@ -21,3 +21,16 @@ exports.index = function(req, res, next) {
} }
); );
} }
exports.play = function(req, res, next) {
var id = req.params.id;
Log.trace('Router: ID ' + id + ' wanted');
if(Helper.isDefinedAndNotNull(Radio.getChannel(id))) {
Radio.play(id);
res.sendStatus(200);
} else {
res.sendStatus(400);
}
}