From 92417fc535c32d905957b4f5ef0fd2cfd8d78609 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Fri, 2 Dec 2011 21:17:55 +0100 Subject: First push with jQuery library --- mediagoblin/static/js/extlib/jquery.js | 1 + 1 file changed, 1 insertion(+) create mode 120000 mediagoblin/static/js/extlib/jquery.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/extlib/jquery.js b/mediagoblin/static/js/extlib/jquery.js new file mode 120000 index 00000000..d78f5cc3 --- /dev/null +++ b/mediagoblin/static/js/extlib/jquery.js @@ -0,0 +1 @@ +../../../../extlib/jquery/jquery.js \ No newline at end of file -- cgit v1.2.3 From 550d48d04059d94894573d93aed98f4faa63e3fb Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 29 Dec 2011 22:56:42 +0100 Subject: Forgot to include the newly created JS file --- mediagoblin/static/js/show_password.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 mediagoblin/static/js/show_password.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/show_password.js b/mediagoblin/static/js/show_password.js new file mode 100644 index 00000000..519b29c1 --- /dev/null +++ b/mediagoblin/static/js/show_password.js @@ -0,0 +1,19 @@ +$(document).ready(function(){ + $("#password").after(''); + $('#password_clear').hide(); + $('#password_boolean').click(function(){ + if($('#password_boolean').prop("checked")) { + $('#password_clear').val($('#password').val()); + $('#password').hide(); + $('#password_clear').show(); + } else { + $('#password').val($('#password_clear').val()); + $('#password_clear').hide(); + $('#password').show(); + }; + }); + $('#password,#password_clear').keyup(function(){ + $('#password').val($(this).val()); + $('#password_clear').val($(this).val()); + }); +}); -- cgit v1.2.3 From ada0642e5a619a3dce4050db535eb065e0cdc798 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 1 Jan 2012 22:58:32 +0100 Subject: Seperate jQuery bit that was still in media.html --- mediagoblin/static/js/comment_show.js | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 mediagoblin/static/js/comment_show.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/comment_show.js b/mediagoblin/static/js/comment_show.js new file mode 100644 index 00000000..2212b9ad --- /dev/null +++ b/mediagoblin/static/js/comment_show.js @@ -0,0 +1,9 @@ +$(document).ready(function(){ + $('#form_comment').hide(); + $('#button_addcomment').click(function(){ + $(this).fadeOut('fast'); + $('#form_comment').slideDown(function(){ + $('#comment_content').focus(); + }); + }); +}); -- cgit v1.2.3 From 7945cd21ba6aa7063fc54bc6f91457a3be65ecb3 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Thu, 5 Jan 2012 23:36:16 +0100 Subject: * Rename mediagoblin_header, mediagoblin_body, mediagoblin_footer, mediagoblin_header_right, mediagoblin_logo * Add html5shiv for older browsers * Small size fix (940px instead of 960pgx) --- mediagoblin/static/js/extlib/html5shiv.js | 1 + 1 file changed, 1 insertion(+) create mode 120000 mediagoblin/static/js/extlib/html5shiv.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/extlib/html5shiv.js b/mediagoblin/static/js/extlib/html5shiv.js new file mode 120000 index 00000000..ca7358c7 --- /dev/null +++ b/mediagoblin/static/js/extlib/html5shiv.js @@ -0,0 +1 @@ +../../../../extlib/html5shiv/html5shiv.js \ No newline at end of file -- cgit v1.2.3 From 836df45dbecbaa5c8156dbbdb93c1c23bee44be4 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 10 Jan 2012 02:53:46 +0100 Subject: Added code for leaflet geolocation map --- mediagoblin/static/js/extlib/leaflet | 1 + mediagoblin/static/js/geolocation-map.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 120000 mediagoblin/static/js/extlib/leaflet create mode 100644 mediagoblin/static/js/geolocation-map.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/extlib/leaflet b/mediagoblin/static/js/extlib/leaflet new file mode 120000 index 00000000..2fc302d7 --- /dev/null +++ b/mediagoblin/static/js/extlib/leaflet @@ -0,0 +1 @@ +../../../../extlib/leaflet/dist/ \ No newline at end of file diff --git a/mediagoblin/static/js/geolocation-map.js b/mediagoblin/static/js/geolocation-map.js new file mode 100644 index 00000000..22cbe2f3 --- /dev/null +++ b/mediagoblin/static/js/geolocation-map.js @@ -0,0 +1,29 @@ +$(document).ready(function () { + var longitude = Number( + $('#tile-map #gps-longitude').val()); + var latitude = Number( + $('#tile-map #gps-latitude').val()); + + console.log(longitude, latitude); + + var map = new L.Map('tile-map'); + + var mqtileUrl = 'http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg'; + var mqtileAttrib = 'Map data © ' + + String(new Date().getFullYear()) + + ' OpenStreetMap contributors, CC-BY-SA.' + + ' Imaging © ' + + String(new Date().getFullYear()) + + ' MapQuest.'; + var mqtile = new L.TileLayer( + mqtileUrl, + {maxZoom: 18, + attribution: mqtileAttrib, + subdomains: '1234'}); + + var location = new L.LatLng(latitude, longitude); // geographical point (longitude and latitude) + map.setView(location, 13).addLayer(mqtile); + + var marker = new L.Marker(location); + map.addLayer(marker); +}); -- cgit v1.2.3 From 9542a2ba076b7e00e79d7adb1a4e90a095427645 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 28 Jan 2012 01:31:56 +0100 Subject: JavaScript fixes - AGPL headers, etc - Added AGPL header to comment_show.js, show_password.js and geolocation-map.js - Removed console.log from geolocation-map.js --- mediagoblin/static/js/comment_show.js | 18 ++++++++++++++++++ mediagoblin/static/js/geolocation-map.js | 23 ++++++++++++++++++++--- mediagoblin/static/js/show_password.js | 18 ++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/comment_show.js b/mediagoblin/static/js/comment_show.js index 2212b9ad..71466a8d 100644 --- a/mediagoblin/static/js/comment_show.js +++ b/mediagoblin/static/js/comment_show.js @@ -1,3 +1,21 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + $(document).ready(function(){ $('#form_comment').hide(); $('#button_addcomment').click(function(){ diff --git a/mediagoblin/static/js/geolocation-map.js b/mediagoblin/static/js/geolocation-map.js index 22cbe2f3..35083d4f 100644 --- a/mediagoblin/static/js/geolocation-map.js +++ b/mediagoblin/static/js/geolocation-map.js @@ -1,11 +1,28 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + $(document).ready(function () { var longitude = Number( $('#tile-map #gps-longitude').val()); var latitude = Number( $('#tile-map #gps-latitude').val()); - console.log(longitude, latitude); - + // Get a new map instance attached and element with id="tile-map" var map = new L.Map('tile-map'); var mqtileUrl = 'http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg'; @@ -21,7 +38,7 @@ $(document).ready(function () { attribution: mqtileAttrib, subdomains: '1234'}); - var location = new L.LatLng(latitude, longitude); // geographical point (longitude and latitude) + var location = new L.LatLng(latitude, longitude); map.setView(location, 13).addLayer(mqtile); var marker = new L.Marker(location); diff --git a/mediagoblin/static/js/show_password.js b/mediagoblin/static/js/show_password.js index 519b29c1..513fe327 100644 --- a/mediagoblin/static/js/show_password.js +++ b/mediagoblin/static/js/show_password.js @@ -1,3 +1,21 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + $(document).ready(function(){ $("#password").after(''); $('#password_clear').hide(); -- cgit v1.2.3 From cf29e8a824e0ef4612f1144f079c80c1d20b89e5 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Thu, 2 Feb 2012 09:44:13 -0600 Subject: It's 2012 all up in here --- mediagoblin/static/js/comment_show.js | 2 +- mediagoblin/static/js/geolocation-map.js | 2 +- mediagoblin/static/js/show_password.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/comment_show.js b/mediagoblin/static/js/comment_show.js index 71466a8d..c5ccee66 100644 --- a/mediagoblin/static/js/comment_show.js +++ b/mediagoblin/static/js/comment_show.js @@ -1,6 +1,6 @@ /** * GNU MediaGoblin -- federated, autonomous media hosting - * Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. + * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/static/js/geolocation-map.js b/mediagoblin/static/js/geolocation-map.js index 35083d4f..a2c62045 100644 --- a/mediagoblin/static/js/geolocation-map.js +++ b/mediagoblin/static/js/geolocation-map.js @@ -1,6 +1,6 @@ /** * GNU MediaGoblin -- federated, autonomous media hosting - * Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. + * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/mediagoblin/static/js/show_password.js b/mediagoblin/static/js/show_password.js index 513fe327..e42d44ea 100644 --- a/mediagoblin/static/js/show_password.js +++ b/mediagoblin/static/js/show_password.js @@ -1,6 +1,6 @@ /** * GNU MediaGoblin -- federated, autonomous media hosting - * Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. + * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by -- cgit v1.2.3 From 643278243c3e68efdee579e9b92dd8ab7355391f Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Tue, 14 Feb 2012 16:59:31 +0100 Subject: Add left and right arrow keys navigation (add new JS file, link it from media.html; add new navigation_right class to right button) --- mediagoblin/static/js/keyboard_navigation.js | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 mediagoblin/static/js/keyboard_navigation.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/keyboard_navigation.js b/mediagoblin/static/js/keyboard_navigation.js new file mode 100644 index 00000000..83d339ff --- /dev/null +++ b/mediagoblin/static/js/keyboard_navigation.js @@ -0,0 +1,29 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +$(document).keydown(function(event){ + switch(event.which){ + case 37: + window.location = $('.navigation_left').attr('href'); + break; + case 39: + window.location = $('.navigation_right').attr('href'); + break; + } +}); + -- cgit v1.2.3 From 1213b8260ab4da97d465e7ef0e71fac2a2c20dbd Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Mon, 5 Mar 2012 19:27:26 +0100 Subject: Stop failing if there is no previous/next to go to --- mediagoblin/static/js/keyboard_navigation.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/keyboard_navigation.js b/mediagoblin/static/js/keyboard_navigation.js index 83d339ff..d4039a3c 100644 --- a/mediagoblin/static/js/keyboard_navigation.js +++ b/mediagoblin/static/js/keyboard_navigation.js @@ -19,10 +19,14 @@ $(document).keydown(function(event){ switch(event.which){ case 37: - window.location = $('.navigation_left').attr('href'); + if($('a.navigation_left').length) { + window.location = $('a.navigation_left').attr('href'); + } break; case 39: - window.location = $('.navigation_right').attr('href'); + if($('a.navigation_right').length) { + window.location = $('a.navigation_right').attr('href'); + } break; } }); -- cgit v1.2.3 From 560e22e7d27d8c2642c076ed8c30703b00e00c41 Mon Sep 17 00:00:00 2001 From: Sacha De'Angeli Date: Mon, 12 Mar 2012 19:44:55 -0500 Subject: adding the video.js wrapper --- mediagoblin/static/js/extlib/video-js | 1 + 1 file changed, 1 insertion(+) create mode 120000 mediagoblin/static/js/extlib/video-js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/extlib/video-js b/mediagoblin/static/js/extlib/video-js new file mode 120000 index 00000000..35da21ca --- /dev/null +++ b/mediagoblin/static/js/extlib/video-js @@ -0,0 +1 @@ +../../../../extlib/video-js \ No newline at end of file -- cgit v1.2.3 From a9d84d4cb79252549d472f9f2059b45bbce4f4f1 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 22 Mar 2012 01:27:19 +0100 Subject: Faster sniffing - Sniffing now goes through the old extension-based filter before doing it the bitsniffing way. - Refractored get_media_type_and_manager(filename). - Removed ogg extension from video accepted extensions, audio will take care of that. - Added custom audio player, still WIP,but working. - Added test for sniffing. This only tests for the mediagoblin.media_types.image type, as that is the only one enabled from start. --- mediagoblin/static/js/audio.js | 140 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 mediagoblin/static/js/audio.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/audio.js b/mediagoblin/static/js/audio.js new file mode 100644 index 00000000..8c91bd0b --- /dev/null +++ b/mediagoblin/static/js/audio.js @@ -0,0 +1,140 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +var audioPlayer = new Object(); + +(function (audioPlayer) { + audioPlayer.init = function (audioElement) { + audioPlayer.audioElement = audioElement; + console.log(audioElement); + attachEvents(); + $(audioElement).hide(); + }; + + function attachEvents () { + audioPlayer.audioElement.addEventListener('durationchange', audioPlayer.durationChange, true); + audioPlayer.audioElement.addEventListener('timeupdate', audioPlayer.timeUpdate, true); + audioPlayer.audioElement.addEventListener('progress', audioPlayer.onProgress, true); + $(document).ready( function () { + $('.audio-spectrogram').delegate('.seekbar', 'click', audioPlayer.onSeek); + $('.audio-spectrogram').delegate('.audio-control-play-pause', 'click', audioPlayer.playPause); + }); + } + + audioPlayer.onProgress = function(a, b, c) { + console.log(a, b, c); + buffered = audioPlayer.audioElement.buffered; + + ranges = new Array(); + + for (i = 0; i < buffered.length; i++) { + ranges[i] = new Array(); + ranges[i][0] = buffered.start(i); + ranges[i][1] = buffered.end(i); + } + console.log('ranges', ranges); + $('.audio-spectrogram .buffered').width( + (ranges[0][1] / audioPlayer.audioElement.duration) * audioPlayer.imageElement.width()); + }; + + audioPlayer.onSeek = function (e) { + console.log('onSeek', e); + im = audioPlayer.imageElement; + pos = e.offsetX / im.width(); + audioPlayer.audioElement.currentTime = pos * audioPlayer.audioElement.duration; + audioPlayer.audioElement.play(); + audioPlayer.setState(audioPlayer.PLAYING); + }; + + audioPlayer.playPause = function (e) { + console.log('playPause', e); + if (audioPlayer.audioElement.paused) { + audioPlayer.audioElement.play(); + audioPlayer.setState(audioPlayer.PLAYING); + } else { + audioPlayer.audioElement.pause(); + audioPlayer.setState(audioPlayer.PAUSED); + } + }; + + audioPlayer.NULL = null; + audioPlayer.PLAYING = 2; + audioPlayer.PAUSED = 4; + + audioPlayer.state = audioPlayer.NULL; + + audioPlayer.setState = function (state) { + if (state == audioPlayer.state) { + return; + } + + switch (state) { + case audioPlayer.PLAYING: + $('.audio-spectrogram .audio-control-play-pause') + .removeClass('paused').addClass('playing') + .text('■'); + break; + case audioPlayer.PAUSED: + $('.audio-spectrogram .audio-control-play-pause') + .removeClass('playing').addClass('paused') + .text('▶'); + break; + } + }; + + audioPlayer.durationChange = function () { + duration = audioPlayer.audioElement.duration; + }; + + audioPlayer.timeUpdate = function () { + currentTime = audioPlayer.audioElement.currentTime; + playhead = audioPlayer.imageElement.parent().find('.playhead'); + playhead.css('width', (currentTime / audioPlayer.audioElement.duration) * audioPlayer.imageElement.width()); + time = formatTime(currentTime); + duration = formatTime(audioPlayer.audioElement.duration); + audioPlayer.imageElement.parent().find('.audio-currentTime').text(time + '/' + duration); + }; + + function formatTime(seconds) { + var h = Math.floor(seconds / (60 * 60)); + var m = Math.floor((seconds - h * 60 * 60) / 60); + var s = Math.round(seconds - h * 60 * 60 - m * 60); + return '' + (h ? (h < 10 ? '0' + h : h) + ':' : '') + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s); + } + + audioPlayer.attachToImage = function (imageElement) { + /** + * Attach the player to an image element + */ + console.log(imageElement); + im = $(imageElement); + audioPlayer.imageElement = im; + $('
').appendTo(im.parent()); + $('
').appendTo(im.parent()); + $('
').appendTo(im.parent()); + $('
').appendTo(im.parent()); + $('
00:00
').appendTo(im.parent()); + }; +})(audioPlayer); + +$(document).ready(function () { + audioElements = $('.audio-media .audio-player'); + audioPlayer.init(audioElements[0]); + audioPlayer.attachToImage($('.audio-spectrogram img')[0]); +}); + -- cgit v1.2.3 From e8be1d7af550267ab8e5e4cd3aad7a2e28e65ce3 Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Sat, 24 Mar 2012 14:49:43 +0100 Subject: Allow arrow keys in input fields and textareas If you pressed an arrow key in a textarea before, the next/previous media was opened. --- mediagoblin/static/js/keyboard_navigation.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/keyboard_navigation.js b/mediagoblin/static/js/keyboard_navigation.js index d4039a3c..7401e4d8 100644 --- a/mediagoblin/static/js/keyboard_navigation.js +++ b/mediagoblin/static/js/keyboard_navigation.js @@ -16,6 +16,15 @@ * along with this program. If not, see . */ +/* It must be wrapped into a function and you also cannot use + * $(':not(textarea, input)') because of some reason. */ + +$(document).ready(function(){ + $('textarea, input').keydown(function(event){ + event.stopPropagation(); + }); +}); + $(document).keydown(function(event){ switch(event.which){ case 37: @@ -30,4 +39,3 @@ $(document).keydown(function(event){ break; } }); - -- cgit v1.2.3 From 6c49799deb6bf776d3765febeb9d7959e27af43d Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Sat, 24 Mar 2012 17:36:12 +0100 Subject: Fill username automatically in (Forget Password) Fill the username automatically in the "Forget Password" form if the user already entered his username on the login page --- mediagoblin/static/js/autofilledin_password.js | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 mediagoblin/static/js/autofilledin_password.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/autofilledin_password.js b/mediagoblin/static/js/autofilledin_password.js new file mode 100644 index 00000000..9513c273 --- /dev/null +++ b/mediagoblin/static/js/autofilledin_password.js @@ -0,0 +1,27 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2012 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +$(document).ready(function(){ + $('#forgot_password').click(function(event){ + event.preventDefault(); + window.location.pathname = $(this).attr('href') + '?username=' + + $('#username').val(); + }); + + $('#username').val(window.location.search.match(/username=(.*)/)[1]); +}); -- cgit v1.2.3 From 952b97d5a0671e1b4a68692a3b5f8a696cd2ca5f Mon Sep 17 00:00:00 2001 From: Jakob Kramer Date: Sun, 25 Mar 2012 21:51:09 +0200 Subject: set username default server-side --- mediagoblin/static/js/autofilledin_password.js | 2 -- 1 file changed, 2 deletions(-) (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/autofilledin_password.js b/mediagoblin/static/js/autofilledin_password.js index 9513c273..45e867fe 100644 --- a/mediagoblin/static/js/autofilledin_password.js +++ b/mediagoblin/static/js/autofilledin_password.js @@ -22,6 +22,4 @@ $(document).ready(function(){ window.location.pathname = $(this).attr('href') + '?username=' + $('#username').val(); }); - - $('#username').val(window.location.search.match(/username=(.*)/)[1]); }); -- cgit v1.2.3 From ebb24e4fd18fb53133755333314a23d22fc72707 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Mon, 26 Mar 2012 20:23:49 +0200 Subject: Add comment in JavaScript file about duplicating the password field --- mediagoblin/static/js/show_password.js | 1 + 1 file changed, 1 insertion(+) (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/show_password.js b/mediagoblin/static/js/show_password.js index e42d44ea..b3fbc862 100644 --- a/mediagoblin/static/js/show_password.js +++ b/mediagoblin/static/js/show_password.js @@ -17,6 +17,7 @@ */ $(document).ready(function(){ + //Create a duplicate password field. We could change the input type dynamically, but this angers the IE gods (not just IE6). $("#password").after(''); $('#password_clear').hide(); $('#password_boolean').click(function(){ -- cgit v1.2.3 From 97e40b52854a4177ac5da62ca567d4003867e08b Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 29 Mar 2012 16:06:36 +0200 Subject: Seeking works in firefox - Added support for indicating multiple buffered ranges (Firefox) - Added volume slider (Chromium) - Replaced stop button with faux pause button - Added 'ended' event handler --- mediagoblin/static/js/audio.js | 139 ++++++++++++++++++++++++++++++++--------- 1 file changed, 111 insertions(+), 28 deletions(-) (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/audio.js b/mediagoblin/static/js/audio.js index 91d52f96..f50908a1 100644 --- a/mediagoblin/static/js/audio.js +++ b/mediagoblin/static/js/audio.js @@ -21,46 +21,110 @@ var audioPlayer = new Object(); (function (audioPlayer) { audioPlayer.init = function (audioElement) { audioPlayer.audioElement = audioElement; + console.log(audioElement); + attachEvents(); + $(audioElement).hide(); }; function attachEvents () { - audioPlayer.audioElement.addEventListener('durationchange', audioPlayer.durationChange, true); - audioPlayer.audioElement.addEventListener('timeupdate', audioPlayer.timeUpdate, true); - audioPlayer.audioElement.addEventListener('progress', audioPlayer.onProgress, true); + audioPlayer.audioElement.addEventListener( + 'durationchange', audioPlayer.durationChange, true); + audioPlayer.audioElement.addEventListener( + 'timeupdate', audioPlayer.timeUpdate, true); + audioPlayer.audioElement.addEventListener( + 'progress', audioPlayer.onProgress, true); + audioPlayer.audioElement.addEventListener( + 'ended', audioPlayer.onEnded, true); + $(document).ready( function () { - $('.audio-spectrogram').delegate('.seekbar', 'click', audioPlayer.onSeek); - $('.audio-spectrogram').delegate('.audio-control-play-pause', 'click', audioPlayer.playPause); + $('.audio-spectrogram').delegate( + '.seekbar', 'click', audioPlayer.onSeek); + $('.audio-spectrogram').delegate( + '.audio-control-play-pause', 'click', audioPlayer.playPause); + $('.audio-spectrogram').delegate( + '.audio-volume', 'change', audioPlayer.onVolumeChange); + $('.audio-media').delegate( + '.audio-spectrogram', 'attachedControls', + audioPlayer.onControlsAttached); }); } - audioPlayer.onProgress = function(a, b, c) { - console.log(a, b, c); - buffered = audioPlayer.audioElement.buffered; + audioPlayer.onVolumeChange = function(e) { + console.log('volume change', e); + audioPlayer.audioElement.volume = e.target.value; + } + + audioPlayer.onControlsAttached = function(e) { + console.log('Controls attached', e); + $('.audio-spectrogram .audio-volume').val( + Math.round(audioPlayer.audioElement.volume, 2)); + } + + audioPlayer.onProgress = function(e) { + /** + * Handler for file download progress + */ + console.log(e); + + var buffered = audioPlayer.audioElement.buffered; ranges = new Array(); - for (i = 0; i < buffered.length; i++) { - ranges[i] = new Array(); - ranges[i][0] = buffered.start(i); - ranges[i][1] = buffered.end(i); + var indicators = $('.audio-spectrogram .buffered-indicators div'); + + for (var i = 0; i < buffered.length; i++) { + if (!(i in indicators)) { + $('
') + .appendTo($('.audio-spectrogram .buffered-indicators')) + .fadeIn(500); + indicators = $('.audio-spectrogram .buffered-indicators div'); + } + var posStart = ((buffered.start(i) / audioPlayer.audioElement.duration) + * audioPlayer.imageElement.width()); + var posStop = ((buffered.end(i) / audioPlayer.audioElement.duration) + * audioPlayer.imageElement.width()); + console.log('indicators', indicators); + + var indicator = $(indicators[i]); + + indicator.css('left', posStart); + indicator.css('width', posStop - posStart); + } + + /* + * Clean up unused indicators + */ + if (indicators.length > buffered.length) { + for (var i = buffered.length; i < indicators.length; i++) { + $(indicators[i]).fadeOut(500, function () { + this.remove(); + }); + } } - console.log('ranges', ranges); - $('.audio-spectrogram .buffered').width( - (ranges[0][1] / audioPlayer.audioElement.duration) * audioPlayer.imageElement.width()); }; audioPlayer.onSeek = function (e) { + /** + * Callback handler for seek event, which is a .click() event on the + * .seekbar element + */ console.log('onSeek', e); - im = audioPlayer.imageElement; - pos = e.offsetX / im.width(); + + var im = audioPlayer.imageElement; + var pos = (e.offsetX || e.originalEvent.layerX) / im.width(); + audioPlayer.audioElement.currentTime = pos * audioPlayer.audioElement.duration; audioPlayer.audioElement.play(); audioPlayer.setState(audioPlayer.PLAYING); }; + audioPlayer.onEnded = function (e) { + audioPlayer.setState(audioPlayer.PAUSED); + } + audioPlayer.playPause = function (e) { console.log('playPause', e); if (audioPlayer.audioElement.paused) { @@ -81,13 +145,15 @@ var audioPlayer = new Object(); audioPlayer.setState = function (state) { if (state == audioPlayer.state) { return; + } else { + audioPlayer.state = state; } switch (state) { case audioPlayer.PLAYING: $('.audio-spectrogram .audio-control-play-pause') .removeClass('paused').addClass('playing') - .text('■'); + .text('▮▮'); break; case audioPlayer.PAUSED: $('.audio-spectrogram .audio-control-play-pause') @@ -98,37 +164,55 @@ var audioPlayer = new Object(); }; audioPlayer.durationChange = function () { - duration = audioPlayer.audioElement.duration; + // ??? }; audioPlayer.timeUpdate = function () { - currentTime = audioPlayer.audioElement.currentTime; - playhead = audioPlayer.imageElement.parent().find('.playhead'); - playhead.css('width', (currentTime / audioPlayer.audioElement.duration) * audioPlayer.imageElement.width()); - time = formatTime(currentTime); - duration = formatTime(audioPlayer.audioElement.duration); - audioPlayer.imageElement.parent().find('.audio-currentTime').text(time + '/' + duration); + /** + * Callback handler for the timeupdate event, responsible for + * updating the playhead + */ + var currentTime = audioPlayer.audioElement.currentTime; + var playhead = audioPlayer.imageElement.parent().find('.playhead'); + playhead.css('width', (currentTime / audioPlayer.audioElement.duration) + * audioPlayer.imageElement.width()); + var time = formatTime(currentTime); + var duration = formatTime(audioPlayer.audioElement.duration); + audioPlayer.imageElement.parent() + .find('.audio-currentTime') + .text(time + '/' + duration); }; function formatTime(seconds) { + /** + * Format a time duration in (hh:)?mm:ss manner + */ var h = Math.floor(seconds / (60 * 60)); var m = Math.floor((seconds - h * 60 * 60) / 60); var s = Math.round(seconds - h * 60 * 60 - m * 60); return '' + (h ? (h < 10 ? '0' + h : h) + ':' : '') + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s); } + audioPlayer.formatTime = formatTime; + audioPlayer.attachToImage = function (imageElement) { /** * Attach the player to an image element */ console.log(imageElement); - im = $(imageElement); + + var im = $(imageElement); + audioPlayer.imageElement = im; + $('
').appendTo(im.parent()); - $('
').appendTo(im.parent()); + $('
').appendTo(im.parent()); $('
').appendTo(im.parent()); $('
').appendTo(im.parent()); $('
00:00
').appendTo(im.parent()); + $('').appendTo(im.parent()); + $('.audio-spectrogram').trigger('attachedControls'); }; })(audioPlayer); @@ -143,4 +227,3 @@ $(document).ready(function () { audioPlayer.init(audioElements[0]); audioPlayer.attachToImage($('.audio-spectrogram img')[0]); }); - -- cgit v1.2.3 From d297d8e834a03692b7a0f0e83d394f5413ed7abc Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 1 Apr 2012 16:02:23 +0200 Subject: Add dropdown to header --- mediagoblin/static/js/header_dropdown.js | 33 ++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 mediagoblin/static/js/header_dropdown.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/header_dropdown.js b/mediagoblin/static/js/header_dropdown.js new file mode 100644 index 00000000..57385203 --- /dev/null +++ b/mediagoblin/static/js/header_dropdown.js @@ -0,0 +1,33 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +$(document).ready(function() { + $(".dropdown_items").hide(); + $(".dropdown").click(function(e) { + e.preventDefault(); + $(".dropdown_items").toggle(); + }); + $(".dropdown_items").mouseup(function() { + return false + }); + $(document).mouseup(function(e) { + if($(e.target).not(".dropdown_items")) { + $(".dropdown_items").hide(); + } + }); +}); -- cgit v1.2.3 From 98853c63fde6e133dca6c723aaacfb1f368cad38 Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 1 Apr 2012 18:06:49 +0200 Subject: JS: fix first part of #422; make items in drop-down acutally work --- mediagoblin/static/js/header_dropdown.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/header_dropdown.js b/mediagoblin/static/js/header_dropdown.js index 57385203..643bafa4 100644 --- a/mediagoblin/static/js/header_dropdown.js +++ b/mediagoblin/static/js/header_dropdown.js @@ -18,15 +18,12 @@ $(document).ready(function() { $(".dropdown_items").hide(); - $(".dropdown").click(function(e) { - e.preventDefault(); - $(".dropdown_items").toggle(); - }); - $(".dropdown_items").mouseup(function() { - return false - }); $(document).mouseup(function(e) { - if($(e.target).not(".dropdown_items")) { + if($(e.target).is(".dropdown")) { + $(".dropdown_items").toggle(); + } else if($(e.target).is(".dropdown_items")) { + return; + } else { $(".dropdown_items").hide(); } }); -- cgit v1.2.3 From 196a5181327dd4e4a3493ccdc55337d4705b066f Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Mon, 9 Apr 2012 16:28:46 +0200 Subject: Media processing, transcoding, display fixes - Added configurable options - Video - vp8_quality - vp8_threads - vorbis_quality - Audio - spectrogram_fft_size - ASCII - thumbnail_font - Cleaned up ascii.asciitoimage - Cleaned up video.transcoders - Changed default video quality settings to better quality - Changed default audio spectrogram solution to the double. - Added a hacky notice for Firefox users instead of the broken range input. --- mediagoblin/static/js/audio.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/audio.js b/mediagoblin/static/js/audio.js index f50908a1..217a2160 100644 --- a/mediagoblin/static/js/audio.js +++ b/mediagoblin/static/js/audio.js @@ -210,8 +210,14 @@ var audioPlayer = new Object(); $('
').appendTo(im.parent()); $('
').appendTo(im.parent()); $('
00:00
').appendTo(im.parent()); - $('').appendTo(im.parent()); + if (navigator && /Firefox/.test(navigator.userAgent)) { + $('

Sorry, Firefox does not support the ' + + 'range input type, you won\'t be able to change the volume

') + .appendTo(im.parent().parent()); + } else { + $('').appendTo(im.parent()); + } $('.audio-spectrogram').trigger('attachedControls'); }; })(audioPlayer); -- cgit v1.2.3 From 1d83cf8a8156054a4e1f3d23f23dac7aa33e69e7 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Wed, 18 Apr 2012 12:06:10 +0200 Subject: Added html5slider to support range inputs in Firefox --- mediagoblin/static/js/audio.js | 10 ++-------- mediagoblin/static/js/extlib/html5slider.js | 1 + 2 files changed, 3 insertions(+), 8 deletions(-) create mode 120000 mediagoblin/static/js/extlib/html5slider.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/audio.js b/mediagoblin/static/js/audio.js index 217a2160..50d58cd9 100644 --- a/mediagoblin/static/js/audio.js +++ b/mediagoblin/static/js/audio.js @@ -210,14 +210,8 @@ var audioPlayer = new Object(); $('
').appendTo(im.parent()); $('
').appendTo(im.parent()); $('
00:00
').appendTo(im.parent()); - if (navigator && /Firefox/.test(navigator.userAgent)) { - $('

Sorry, Firefox does not support the ' - + 'range input type, you won\'t be able to change the volume

') - .appendTo(im.parent().parent()); - } else { - $('').appendTo(im.parent()); - } + $('').appendTo(im.parent()); $('.audio-spectrogram').trigger('attachedControls'); }; })(audioPlayer); diff --git a/mediagoblin/static/js/extlib/html5slider.js b/mediagoblin/static/js/extlib/html5slider.js new file mode 120000 index 00000000..feae2cb8 --- /dev/null +++ b/mediagoblin/static/js/extlib/html5slider.js @@ -0,0 +1 @@ +../../../../extlib/html5slider/html5slider.js \ No newline at end of file -- cgit v1.2.3 From a0fdc00fab0a76e4f994ba62ce6d24a65f09a532 Mon Sep 17 00:00:00 2001 From: Aaron Williamson Date: Fri, 17 Aug 2012 00:57:18 -0400 Subject: Added new files for collections --- mediagoblin/static/js/collection_form_show.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 mediagoblin/static/js/collection_form_show.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/collection_form_show.js b/mediagoblin/static/js/collection_form_show.js new file mode 100644 index 00000000..03a4906b --- /dev/null +++ b/mediagoblin/static/js/collection_form_show.js @@ -0,0 +1,26 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +$(document).ready(function(){ + $('#new_collection').hide(); + $('#button_addcollection').click(function(){ + $('#new_collection').slideToggle('fast', function(){ + $('#collection_title').focus(); + }); + }); +}); -- cgit v1.2.3 From 294979824c2eb651168c66f58e1d759a2ff56ada Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Sun, 21 Oct 2012 21:49:39 +0200 Subject: Replace dropdown in top right with regular links --- mediagoblin/static/js/header_dropdown.js | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 mediagoblin/static/js/header_dropdown.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/header_dropdown.js b/mediagoblin/static/js/header_dropdown.js deleted file mode 100644 index 643bafa4..00000000 --- a/mediagoblin/static/js/header_dropdown.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * GNU MediaGoblin -- federated, autonomous media hosting - * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -$(document).ready(function() { - $(".dropdown_items").hide(); - $(document).mouseup(function(e) { - if($(e.target).is(".dropdown")) { - $(".dropdown_items").toggle(); - } else if($(e.target).is(".dropdown_items")) { - return; - } else { - $(".dropdown_items").hide(); - } - }); -}); -- cgit v1.2.3 From fd79d33a877c97a26706931bdf0988469ad37504 Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Wed, 14 Nov 2012 10:12:58 +0100 Subject: Pop up OpenStreetMap license on demand (#410) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only a short blurb "see map license" in the small map which will pop up the full license text via jquery when clicked. Adapt the license text as recommended by OpenStreetMap http://www.openstreetmap.org/copyright and link there. The disadvantage is that this only works when Javascript is enabled, but as the map only works when Javascript is enabled in the first place, this should not be too much of a limitation. TODO: Our esteemed web designer needs to have a look at the desired color style for this. Right now, I simply placed it in the message_warning class. This might want fine-tuning. Signed-off-by: Sebastian Spaeth --- mediagoblin/static/js/geolocation-map.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/geolocation-map.js b/mediagoblin/static/js/geolocation-map.js index de49a37d..26d94c5d 100644 --- a/mediagoblin/static/js/geolocation-map.js +++ b/mediagoblin/static/js/geolocation-map.js @@ -31,19 +31,15 @@ $(document).ready(function () { var map = new L.Map('tile-map'); var mqtileUrl = 'http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg'; - var mqtileAttrib = 'Map data © ' - + String(new Date().getFullYear()) - + ' OpenStreetMap contributors, CC-BY-SA.' - + ' Imaging © ' - + String(new Date().getFullYear()) - + ' MapQuest.'; + var mqtileAttrib = 'see map license'; var mqtile = new L.TileLayer( mqtileUrl, {maxZoom: 18, attribution: mqtileAttrib, subdomains: '1234'}); - var location = new L.LatLng(latitude, longitude); + map.attributionControl.setPrefix(''); + var location = new L.LatLng(latitude, longitude); map.setView(location, 13).addLayer(mqtile); var marker = new L.Marker(location); -- cgit v1.2.3 From 47cd2f66b6a4e4caa078927738b89d68624c32a6 Mon Sep 17 00:00:00 2001 From: Aeva Ntsc Date: Mon, 15 Oct 2012 01:33:38 -0500 Subject: Added the thingiview.js library. --- mediagoblin/static/js/thingiview.js/Three.js | 202 +++++ .../static/js/thingiview.js/binaryReader.js | 126 +++ mediagoblin/static/js/thingiview.js/plane.js | 62 ++ mediagoblin/static/js/thingiview.js/stats.js | 2 + .../static/js/thingiview.js/thingiloader.js | 318 ++++++++ mediagoblin/static/js/thingiview.js/thingiview.js | 894 +++++++++++++++++++++ 6 files changed, 1604 insertions(+) create mode 100644 mediagoblin/static/js/thingiview.js/Three.js create mode 100644 mediagoblin/static/js/thingiview.js/binaryReader.js create mode 100644 mediagoblin/static/js/thingiview.js/plane.js create mode 100644 mediagoblin/static/js/thingiview.js/stats.js create mode 100644 mediagoblin/static/js/thingiview.js/thingiloader.js create mode 100644 mediagoblin/static/js/thingiview.js/thingiview.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/thingiview.js/Three.js b/mediagoblin/static/js/thingiview.js/Three.js new file mode 100644 index 00000000..5c21380c --- /dev/null +++ b/mediagoblin/static/js/thingiview.js/Three.js @@ -0,0 +1,202 @@ +// Three.js r32 - http://github.com/mrdoob/three.js +var THREE=THREE||{};THREE.Color=function(a){this.autoUpdate=true;this.setHex(a)}; +THREE.Color.prototype={setRGB:function(a,c,d){this.r=a;this.g=c;this.b=d;if(this.autoUpdate){this.updateHex();this.updateStyleString()}},setHex:function(a){this.hex=~~a&16777215;if(this.autoUpdate){this.updateRGBA();this.updateStyleString()}},updateHex:function(){this.hex=~~(this.r*255)<<16^~~(this.g*255)<<8^~~(this.b*255)},updateRGBA:function(){this.r=(this.hex>>16&255)/255;this.g=(this.hex>>8&255)/255;this.b=(this.hex&255)/255},updateStyleString:function(){this.__styleString="rgb("+~~(this.r*255)+ +","+~~(this.g*255)+","+~~(this.b*255)+")"},clone:function(){return new THREE.Color(this.hex)},toString:function(){return"THREE.Color ( r: "+this.r+", g: "+this.g+", b: "+this.b+", hex: "+this.hex+" )"}};THREE.Vector2=function(a,c){this.x=a||0;this.y=c||0}; +THREE.Vector2.prototype={set:function(a,c){this.x=a;this.y=c;return this},copy:function(a){this.x=a.x;this.y=a.y;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;return this},add:function(a,c){this.x=a.x+c.x;this.y=a.y+c.y;return this},subSelf:function(a){this.x-=a.x;this.y-=a.y;return this},sub:function(a,c){this.x=a.x-c.x;this.y=a.y-c.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},unit:function(){this.multiplyScalar(1/this.length());return this},length:function(){return Math.sqrt(this.x* +this.x+this.y*this.y)},lengthSq:function(){return this.x*this.x+this.y*this.y},negate:function(){this.x=-this.x;this.y=-this.y;return this},clone:function(){return new THREE.Vector2(this.x,this.y)},toString:function(){return"THREE.Vector2 ("+this.x+", "+this.y+")"}};THREE.Vector3=function(a,c,d){this.x=a||0;this.y=c||0;this.z=d||0}; +THREE.Vector3.prototype={set:function(a,c,d){this.x=a;this.y=c;this.z=d;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,c){this.x=a.x+c.x;this.y=a.y+c.y;this.z=a.z+c.z;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},sub:function(a,c){this.x=a.x-c.x;this.y=a.y-c.y;this.z=a.z-c.z;return this},subSelf:function(a){this.x-=a.x;this.y-=a.y;this.z-=a.z;return this}, +cross:function(a,c){this.x=a.y*c.z-a.z*c.y;this.y=a.z*c.x-a.x*c.z;this.z=a.x*c.y-a.y*c.x;return this},crossSelf:function(a){var c=this.x,d=this.y,e=this.z;this.x=d*a.z-e*a.y;this.y=e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},multiply:function(a,c){this.x=a.x*c.x;this.y=a.y*c.y;this.z=a.z*c.z;return this},multiplySelf:function(a){this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},divideSelf:function(a){this.x/=a.x;this.y/=a.y;this.z/= +a.z;return this},divideScalar:function(a){this.x/=a;this.y/=a;this.z/=a;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},distanceTo:function(a){var c=this.x-a.x,d=this.y-a.y;a=this.z-a.z;return Math.sqrt(c*c+d*d+a*a)},distanceToSquared:function(a){var c=this.x-a.x,d=this.y-a.y;a=this.z-a.z;return c*c+d*d+a*a},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},negate:function(){this.x= +-this.x;this.y=-this.y;this.z=-this.z;return this},normalize:function(){var a=Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z);a>0?this.multiplyScalar(1/a):this.set(0,0,0);return this},setLength:function(a){return this.normalize().multiplyScalar(a)},isZero:function(){return Math.abs(this.x)<1.0E-4&&Math.abs(this.y)<1.0E-4&&Math.abs(this.z)<1.0E-4},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)},toString:function(){return"THREE.Vector3 ( "+this.x+", "+this.y+", "+this.z+" )"}}; +THREE.Vector4=function(a,c,d,e){this.x=a||0;this.y=c||0;this.z=d||0;this.w=e||1}; +THREE.Vector4.prototype={set:function(a,c,d,e){this.x=a;this.y=c;this.z=d;this.w=e;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=a.w||1;return this},add:function(a,c){this.x=a.x+c.x;this.y=a.y+c.y;this.z=a.z+c.z;this.w=a.w+c.w;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},sub:function(a,c){this.x=a.x-c.x;this.y=a.y-c.y;this.z=a.z-c.z;this.w=a.w-c.w;return this},subSelf:function(a){this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w; +return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this},divideScalar:function(a){this.x/=a;this.y/=a;this.z/=a;this.w/=a;return this},lerpSelf:function(a,c){this.x+=(a.x-this.x)*c;this.y+=(a.y-this.y)*c;this.z+=(a.z-this.z)*c;this.w+=(a.w-this.w)*c},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)},toString:function(){return"THREE.Vector4 ("+this.x+", "+this.y+", "+this.z+", "+this.w+")"}}; +THREE.Ray=function(a,c){this.origin=a||new THREE.Vector3;this.direction=c||new THREE.Vector3}; +THREE.Ray.prototype={intersectScene:function(a){var c,d,e=a.objects,g=[];a=0;for(c=e.length;a0&&K>0&&j+K<1}var d,e,g,h,o,b,i,k,y,z, +u,x=a.geometry,H=x.vertices,J=[];d=0;for(e=x.faces.length;di?e:i;g=g>k? +g:k}a()};this.add3Points=function(i,k,y,z,u,x){if(b){b=false;c=iy?i>u?i:u:y>u?y:u;g=k>z?k>x?k:x:z>x?z:x}else{c=iy?i>u?i>e?i:e:u>e?u:e:y>u?y>e?y:e:u>e?u:e;g=k>z?k>x?k>g?k:g:x>g?x:g:z>x?z>g?z:g:x>g?x:g}a()};this.addRectangle=function(i){if(b){b=false;c=i.getLeft();d=i.getTop();e=i.getRight();g=i.getBottom()}else{c=ci.getRight()?e:i.getRight();g=g>i.getBottom()?g:i.getBottom()}a()};this.inflate=function(i){c-=i;d-=i;e+=i;g+=i;a()};this.minSelf=function(i){c=c>i.getLeft()?c:i.getLeft();d=d>i.getTop()?d:i.getTop();e=e=0&&Math.min(g,i.getBottom())-Math.max(d,i.getTop())>=0};this.empty=function(){b=true;g=e=d=c=0;a()};this.isEmpty=function(){return b};this.toString= +function(){return"THREE.Rectangle ( left: "+c+", right: "+e+", top: "+d+", bottom: "+g+", width: "+h+", height: "+o+" )"}};THREE.Matrix3=function(){this.m=[]};THREE.Matrix3.prototype={transpose:function(){var a,c=this.m;a=c[1];c[1]=c[3];c[3]=a;a=c[2];c[2]=c[6];c[6]=a;a=c[5];c[5]=c[7];c[7]=a;return this}}; +THREE.Matrix4=function(a,c,d,e,g,h,o,b,i,k,y,z,u,x,H,J){this.n11=a||1;this.n12=c||0;this.n13=d||0;this.n14=e||0;this.n21=g||0;this.n22=h||1;this.n23=o||0;this.n24=b||0;this.n31=i||0;this.n32=k||0;this.n33=y||1;this.n34=z||0;this.n41=u||0;this.n42=x||0;this.n43=H||0;this.n44=J||1;this.flat=Array(16);this.m33=new THREE.Matrix3}; +THREE.Matrix4.prototype={identity:function(){this.n11=1;this.n21=this.n14=this.n13=this.n12=0;this.n22=1;this.n32=this.n31=this.n24=this.n23=0;this.n33=1;this.n43=this.n42=this.n41=this.n34=0;this.n44=1;return this},set:function(a,c,d,e,g,h,o,b,i,k,y,z,u,x,H,J){this.n11=a;this.n12=c;this.n13=d;this.n14=e;this.n21=g;this.n22=h;this.n23=o;this.n24=b;this.n31=i;this.n32=k;this.n33=y;this.n34=z;this.n41=u;this.n42=x;this.n43=H;this.n44=J;return this},copy:function(a){this.n11=a.n11;this.n12=a.n12;this.n13= +a.n13;this.n14=a.n14;this.n21=a.n21;this.n22=a.n22;this.n23=a.n23;this.n24=a.n24;this.n31=a.n31;this.n32=a.n32;this.n33=a.n33;this.n34=a.n34;this.n41=a.n41;this.n42=a.n42;this.n43=a.n43;this.n44=a.n44;return this},lookAt:function(a,c,d){var e=THREE.Matrix4.__tmpVec1,g=THREE.Matrix4.__tmpVec2,h=THREE.Matrix4.__tmpVec3;h.sub(a,c).normalize();e.cross(d,h).normalize();g.cross(h,e).normalize();this.n11=e.x;this.n12=e.y;this.n13=e.z;this.n14=-e.dot(a);this.n21=g.x;this.n22=g.y;this.n23=g.z;this.n24=-g.dot(a); +this.n31=h.x;this.n32=h.y;this.n33=h.z;this.n34=-h.dot(a);this.n43=this.n42=this.n41=0;this.n44=1;return this},multiplyVector3:function(a){var c=a.x,d=a.y,e=a.z,g=1/(this.n41*c+this.n42*d+this.n43*e+this.n44);a.x=(this.n11*c+this.n12*d+this.n13*e+this.n14)*g;a.y=(this.n21*c+this.n22*d+this.n23*e+this.n24)*g;a.z=(this.n31*c+this.n32*d+this.n33*e+this.n34)*g;return a},multiplyVector4:function(a){var c=a.x,d=a.y,e=a.z,g=a.w;a.x=this.n11*c+this.n12*d+this.n13*e+this.n14*g;a.y=this.n21*c+this.n22*d+this.n23* +e+this.n24*g;a.z=this.n31*c+this.n32*d+this.n33*e+this.n34*g;a.w=this.n41*c+this.n42*d+this.n43*e+this.n44*g;return a},crossVector:function(a){var c=new THREE.Vector4;c.x=this.n11*a.x+this.n12*a.y+this.n13*a.z+this.n14*a.w;c.y=this.n21*a.x+this.n22*a.y+this.n23*a.z+this.n24*a.w;c.z=this.n31*a.x+this.n32*a.y+this.n33*a.z+this.n34*a.w;c.w=a.w?this.n41*a.x+this.n42*a.y+this.n43*a.z+this.n44*a.w:1;return c},multiply:function(a,c){var d=a.n11,e=a.n12,g=a.n13,h=a.n14,o=a.n21,b=a.n22,i=a.n23,k=a.n24,y=a.n31, +z=a.n32,u=a.n33,x=a.n34,H=a.n41,J=a.n42,K=a.n43,p=a.n44,U=c.n11,F=c.n12,f=c.n13,j=c.n14,q=c.n21,l=c.n22,r=c.n23,C=c.n24,m=c.n31,t=c.n32,v=c.n33,s=c.n34,n=c.n41,E=c.n42,A=c.n43,O=c.n44;this.n11=d*U+e*q+g*m+h*n;this.n12=d*F+e*l+g*t+h*E;this.n13=d*f+e*r+g*v+h*A;this.n14=d*j+e*C+g*s+h*O;this.n21=o*U+b*q+i*m+k*n;this.n22=o*F+b*l+i*t+k*E;this.n23=o*f+b*r+i*v+k*A;this.n24=o*j+b*C+i*s+k*O;this.n31=y*U+z*q+u*m+x*n;this.n32=y*F+z*l+u*t+x*E;this.n33=y*f+z*r+u*v+x*A;this.n34=y*j+z*C+u*s+x*O;this.n41=H*U+J*q+ +K*m+p*n;this.n42=H*F+J*l+K*t+p*E;this.n43=H*f+J*r+K*v+p*A;this.n44=H*j+J*C+K*s+p*O;return this},multiplySelf:function(a){var c=this.n11,d=this.n12,e=this.n13,g=this.n14,h=this.n21,o=this.n22,b=this.n23,i=this.n24,k=this.n31,y=this.n32,z=this.n33,u=this.n34,x=this.n41,H=this.n42,J=this.n43,K=this.n44,p=a.n11,U=a.n21,F=a.n31,f=a.n41,j=a.n12,q=a.n22,l=a.n32,r=a.n42,C=a.n13,m=a.n23,t=a.n33,v=a.n43,s=a.n14,n=a.n24,E=a.n34;a=a.n44;this.n11=c*p+d*U+e*F+g*f;this.n12=c*j+d*q+e*l+g*r;this.n13=c*C+d*m+e*t+g* +v;this.n14=c*s+d*n+e*E+g*a;this.n21=h*p+o*U+b*F+i*f;this.n22=h*j+o*q+b*l+i*r;this.n23=h*C+o*m+b*t+i*v;this.n24=h*s+o*n+b*E+i*a;this.n31=k*p+y*U+z*F+u*f;this.n32=k*j+y*q+z*l+u*r;this.n33=k*C+y*m+z*t+u*v;this.n34=k*s+y*n+z*E+u*a;this.n41=x*p+H*U+J*F+K*f;this.n42=x*j+H*q+J*l+K*r;this.n43=x*C+H*m+J*t+K*v;this.n44=x*s+H*n+J*E+K*a;return this},multiplyScalar:function(a){this.n11*=a;this.n12*=a;this.n13*=a;this.n14*=a;this.n21*=a;this.n22*=a;this.n23*=a;this.n24*=a;this.n31*=a;this.n32*=a;this.n33*=a;this.n34*= +a;this.n41*=a;this.n42*=a;this.n43*=a;this.n44*=a;return this},determinant:function(){var a=this.n11,c=this.n12,d=this.n13,e=this.n14,g=this.n21,h=this.n22,o=this.n23,b=this.n24,i=this.n31,k=this.n32,y=this.n33,z=this.n34,u=this.n41,x=this.n42,H=this.n43,J=this.n44;return e*o*k*u-d*b*k*u-e*h*y*u+c*b*y*u+d*h*z*u-c*o*z*u-e*o*i*x+d*b*i*x+e*g*y*x-a*b*y*x-d*g*z*x+a*o*z*x+e*h*i*H-c*b*i*H-e*g*k*H+a*b*k*H+c*g*z*H-a*h*z*H-d*h*i*J+c*o*i*J+d*g*k*J-a*o*k*J-c*g*y*J+a*h*y*J},transpose:function(){function a(c,d, +e){var g=c[d];c[d]=c[e];c[e]=g}a(this,"n21","n12");a(this,"n31","n13");a(this,"n32","n23");a(this,"n41","n14");a(this,"n42","n24");a(this,"n43","n34");return this},clone:function(){var a=new THREE.Matrix4;a.n11=this.n11;a.n12=this.n12;a.n13=this.n13;a.n14=this.n14;a.n21=this.n21;a.n22=this.n22;a.n23=this.n23;a.n24=this.n24;a.n31=this.n31;a.n32=this.n32;a.n33=this.n33;a.n34=this.n34;a.n41=this.n41;a.n42=this.n42;a.n43=this.n43;a.n44=this.n44;return a},flatten:function(){var a=this.flat;a[0]=this.n11; +a[1]=this.n21;a[2]=this.n31;a[3]=this.n41;a[4]=this.n12;a[5]=this.n22;a[6]=this.n32;a[7]=this.n42;a[8]=this.n13;a[9]=this.n23;a[10]=this.n33;a[11]=this.n43;a[12]=this.n14;a[13]=this.n24;a[14]=this.n34;a[15]=this.n44;return a},setTranslation:function(a,c,d){this.set(1,0,0,a,0,1,0,c,0,0,1,d,0,0,0,1);return this},setScale:function(a,c,d){this.set(a,0,0,0,0,c,0,0,0,0,d,0,0,0,0,1);return this},setRotX:function(a){var c=Math.cos(a);a=Math.sin(a);this.set(1,0,0,0,0,c,-a,0,0,a,c,0,0,0,0,1);return this},setRotY:function(a){var c= +Math.cos(a);a=Math.sin(a);this.set(c,0,a,0,0,1,0,0,-a,0,c,0,0,0,0,1);return this},setRotZ:function(a){var c=Math.cos(a);a=Math.sin(a);this.set(c,-a,0,0,a,c,0,0,0,0,1,0,0,0,0,1);return this},setRotAxis:function(a,c){var d=Math.cos(c),e=Math.sin(c),g=1-d,h=a.x,o=a.y,b=a.z,i=g*h,k=g*o;this.set(i*h+d,i*o-e*b,i*b+e*o,0,i*o+e*b,k*o+d,k*b-e*h,0,i*b-e*o,k*b+e*h,g*b*b+d,0,0,0,0,1);return this},toString:function(){return"| "+this.n11+" "+this.n12+" "+this.n13+" "+this.n14+" |\n| "+this.n21+" "+this.n22+" "+ +this.n23+" "+this.n24+" |\n| "+this.n31+" "+this.n32+" "+this.n33+" "+this.n34+" |\n| "+this.n41+" "+this.n42+" "+this.n43+" "+this.n44+" |"}};THREE.Matrix4.translationMatrix=function(a,c,d){var e=new THREE.Matrix4;e.setTranslation(a,c,d);return e};THREE.Matrix4.scaleMatrix=function(a,c,d){var e=new THREE.Matrix4;e.setScale(a,c,d);return e};THREE.Matrix4.rotationXMatrix=function(a){var c=new THREE.Matrix4;c.setRotX(a);return c}; +THREE.Matrix4.rotationYMatrix=function(a){var c=new THREE.Matrix4;c.setRotY(a);return c};THREE.Matrix4.rotationZMatrix=function(a){var c=new THREE.Matrix4;c.setRotZ(a);return c};THREE.Matrix4.rotationAxisAngleMatrix=function(a,c){var d=new THREE.Matrix4;d.setRotAxis(a,c);return d}; +THREE.Matrix4.makeInvert=function(a){var c=a.n11,d=a.n12,e=a.n13,g=a.n14,h=a.n21,o=a.n22,b=a.n23,i=a.n24,k=a.n31,y=a.n32,z=a.n33,u=a.n34,x=a.n41,H=a.n42,J=a.n43,K=a.n44,p=new THREE.Matrix4;p.n11=b*u*H-i*z*H+i*y*J-o*u*J-b*y*K+o*z*K;p.n12=g*z*H-e*u*H-g*y*J+d*u*J+e*y*K-d*z*K;p.n13=e*i*H-g*b*H+g*o*J-d*i*J-e*o*K+d*b*K;p.n14=g*b*y-e*i*y-g*o*z+d*i*z+e*o*u-d*b*u;p.n21=i*z*x-b*u*x-i*k*J+h*u*J+b*k*K-h*z*K;p.n22=e*u*x-g*z*x+g*k*J-c*u*J-e*k*K+c*z*K;p.n23=g*b*x-e*i*x-g*h*J+c*i*J+e*h*K-c*b*K;p.n24=e*i*k-g*b*k+ +g*h*z-c*i*z-e*h*u+c*b*u;p.n31=o*u*x-i*y*x+i*k*H-h*u*H-o*k*K+h*y*K;p.n32=g*y*x-d*u*x-g*k*H+c*u*H+d*k*K-c*y*K;p.n33=e*i*x-g*o*x+g*h*H-c*i*H-d*h*K+c*o*K;p.n34=g*o*k-d*i*k-g*h*y+c*i*y+d*h*u-c*o*u;p.n41=b*y*x-o*z*x-b*k*H+h*z*H+o*k*J-h*y*J;p.n42=d*z*x-e*y*x+e*k*H-c*z*H-d*k*J+c*y*J;p.n43=e*o*x-d*b*x-e*h*H+c*b*H+d*h*J-c*o*J;p.n44=d*b*k-e*o*k+e*h*y-c*b*y-d*h*z+c*o*z;p.multiplyScalar(1/a.determinant());return p}; +THREE.Matrix4.makeInvert3x3=function(a){var c=a.flatten();a=a.m33;var d=a.m,e=c[10]*c[5]-c[6]*c[9],g=-c[10]*c[1]+c[2]*c[9],h=c[6]*c[1]-c[2]*c[5],o=-c[10]*c[4]+c[6]*c[8],b=c[10]*c[0]-c[2]*c[8],i=-c[6]*c[0]+c[2]*c[4],k=c[9]*c[4]-c[5]*c[8],y=-c[9]*c[0]+c[1]*c[8],z=c[5]*c[0]-c[1]*c[4];c=c[0]*e+c[1]*o+c[2]*k;if(c==0)throw"matrix not invertible";c=1/c;d[0]=c*e;d[1]=c*g;d[2]=c*h;d[3]=c*o;d[4]=c*b;d[5]=c*i;d[6]=c*k;d[7]=c*y;d[8]=c*z;return a}; +THREE.Matrix4.makeFrustum=function(a,c,d,e,g,h){var o,b,i;o=new THREE.Matrix4;b=2*g/(c-a);i=2*g/(e-d);a=(c+a)/(c-a);d=(e+d)/(e-d);e=-(h+g)/(h-g);g=-2*h*g/(h-g);o.n11=b;o.n12=0;o.n13=a;o.n14=0;o.n21=0;o.n22=i;o.n23=d;o.n24=0;o.n31=0;o.n32=0;o.n33=e;o.n34=g;o.n41=0;o.n42=0;o.n43=-1;o.n44=0;return o};THREE.Matrix4.makePerspective=function(a,c,d,e){var g;a=d*Math.tan(a*Math.PI/360);g=-a;return THREE.Matrix4.makeFrustum(g*c,a*c,g,a,d,e)}; +THREE.Matrix4.makeOrtho=function(a,c,d,e,g,h){var o,b,i,k;o=new THREE.Matrix4;b=c-a;i=d-e;k=h-g;a=(c+a)/b;d=(d+e)/i;g=(h+g)/k;o.n11=2/b;o.n12=0;o.n13=0;o.n14=-a;o.n21=0;o.n22=2/i;o.n23=0;o.n24=-d;o.n31=0;o.n32=0;o.n33=-2/k;o.n34=-g;o.n41=0;o.n42=0;o.n43=0;o.n44=1;return o};THREE.Matrix4.__tmpVec1=new THREE.Vector3;THREE.Matrix4.__tmpVec2=new THREE.Vector3;THREE.Matrix4.__tmpVec3=new THREE.Vector3; +THREE.Vertex=function(a,c){this.position=a||new THREE.Vector3;this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.normal=c||new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.normalScreen=new THREE.Vector3;this.tangent=new THREE.Vector4;this.__visible=true};THREE.Vertex.prototype={toString:function(){return"THREE.Vertex ( position: "+this.position+", normal: "+this.normal+" )"}}; +THREE.Face3=function(a,c,d,e,g){this.a=a;this.b=c;this.c=d;this.centroid=new THREE.Vector3;this.normal=e instanceof THREE.Vector3?e:new THREE.Vector3;this.vertexNormals=e instanceof Array?e:[];this.materials=g instanceof Array?g:[g]};THREE.Face3.prototype={toString:function(){return"THREE.Face3 ( "+this.a+", "+this.b+", "+this.c+" )"}}; +THREE.Face4=function(a,c,d,e,g,h){this.a=a;this.b=c;this.c=d;this.d=e;this.centroid=new THREE.Vector3;this.normal=g instanceof THREE.Vector3?g:new THREE.Vector3;this.vertexNormals=g instanceof Array?g:[];this.materials=h instanceof Array?h:[h]};THREE.Face4.prototype={toString:function(){return"THREE.Face4 ( "+this.a+", "+this.b+", "+this.c+" "+this.d+" )"}};THREE.UV=function(a,c){this.u=a||0;this.v=c||0}; +THREE.UV.prototype={copy:function(a){this.u=a.u;this.v=a.v},toString:function(){return"THREE.UV ("+this.u+", "+this.v+")"}};THREE.Geometry=function(){this.vertices=[];this.faces=[];this.uvs=[];this.boundingSphere=this.boundingBox=null;this.geometryChunks={};this.hasTangents=false}; +THREE.Geometry.prototype={computeCentroids:function(){var a,c,d;a=0;for(c=this.faces.length;a0){this.boundingBox={x:[this.vertices[0].position.x,this.vertices[0].position.x],y:[this.vertices[0].position.y,this.vertices[0].position.y], +z:[this.vertices[0].position.z,this.vertices[0].position.z]};for(var c=1,d=this.vertices.length;cthis.boundingBox.x[1])this.boundingBox.x[1]=a.position.x;if(a.position.ythis.boundingBox.y[1])this.boundingBox.y[1]=a.position.y;if(a.position.z +this.boundingBox.z[1])this.boundingBox.z[1]=a.position.z}}},computeBoundingSphere:function(){for(var a=this.boundingSphere===null?0:this.boundingSphere.radius,c=0,d=this.vertices.length;c65535){k[b].counter+=1;i=k[b].hash+"_"+k[b].counter;if(this.geometryChunks[i]==undefined)this.geometryChunks[i]={faces:[],materials:o,vertices:0}}this.geometryChunks[i].faces.push(e);this.geometryChunks[i].vertices+=h}},toString:function(){return"THREE.Geometry ( vertices: "+ +this.vertices+", faces: "+this.faces+", uvs: "+this.uvs+" )"}}; +THREE.Camera=function(a,c,d,e){this.fov=a;this.aspect=c;this.near=d;this.far=e;this.position=new THREE.Vector3;this.target={position:new THREE.Vector3};this.autoUpdateMatrix=true;this.projectionMatrix=null;this.matrix=new THREE.Matrix4;this.up=new THREE.Vector3(0,1,0);this.tmpVec=new THREE.Vector3;this.translateX=function(g){this.tmpVec.sub(this.target.position,this.position).normalize().multiplyScalar(g);this.tmpVec.crossSelf(this.up);this.position.addSelf(this.tmpVec);this.target.position.addSelf(this.tmpVec)}; +this.translateZ=function(g){this.tmpVec.sub(this.target.position,this.position).normalize().multiplyScalar(g);this.position.subSelf(this.tmpVec);this.target.position.subSelf(this.tmpVec)};this.updateMatrix=function(){this.matrix.lookAt(this.position,this.target.position,this.up)};this.updateProjectionMatrix=function(){this.projectionMatrix=THREE.Matrix4.makePerspective(this.fov,this.aspect,this.near,this.far)};this.updateProjectionMatrix()}; +THREE.Camera.prototype={toString:function(){return"THREE.Camera ( "+this.position+", "+this.target.position+" )"}};THREE.Light=function(a){this.color=new THREE.Color(a)};THREE.AmbientLight=function(a){THREE.Light.call(this,a)};THREE.AmbientLight.prototype=new THREE.Light;THREE.AmbientLight.prototype.constructor=THREE.AmbientLight;THREE.DirectionalLight=function(a,c){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,1,0);this.intensity=c||1};THREE.DirectionalLight.prototype=new THREE.Light; +THREE.DirectionalLight.prototype.constructor=THREE.DirectionalLight;THREE.PointLight=function(a,c){THREE.Light.call(this,a);this.position=new THREE.Vector3;this.intensity=c||1};THREE.PointLight.prototype=new THREE.Light;THREE.PointLight.prototype.constructor=THREE.PointLight; +THREE.Object3D=function(){this.id=THREE.Object3DCounter.value++;this.position=new THREE.Vector3;this.rotation=new THREE.Vector3;this.scale=new THREE.Vector3(1,1,1);this.matrix=new THREE.Matrix4;this.rotationMatrix=new THREE.Matrix4;this.tmpMatrix=new THREE.Matrix4;this.screen=new THREE.Vector3;this.visible=this.autoUpdateMatrix=true}; +THREE.Object3D.prototype={updateMatrix:function(){var a=this.position,c=this.rotation,d=this.scale,e=this.tmpMatrix;this.matrix.setTranslation(a.x,a.y,a.z);this.rotationMatrix.setRotX(c.x);if(c.y!=0){e.setRotY(c.y);this.rotationMatrix.multiplySelf(e)}if(c.z!=0){e.setRotZ(c.z);this.rotationMatrix.multiplySelf(e)}this.matrix.multiplySelf(this.rotationMatrix);if(d.x!=0||d.y!=0||d.z!=0){e.setScale(d.x,d.y,d.z);this.matrix.multiplySelf(e)}}};THREE.Object3DCounter={value:0}; +THREE.Particle=function(a){THREE.Object3D.call(this);this.materials=a instanceof Array?a:[a];this.autoUpdateMatrix=false};THREE.Particle.prototype=new THREE.Object3D;THREE.Particle.prototype.constructor=THREE.Particle;THREE.ParticleSystem=function(a,c){THREE.Object3D.call(this);this.geometry=a;this.materials=c instanceof Array?c:[c];this.autoUpdateMatrix=false};THREE.ParticleSystem.prototype=new THREE.Object3D;THREE.ParticleSystem.prototype.constructor=THREE.ParticleSystem; +THREE.Line=function(a,c,d){THREE.Object3D.call(this);this.geometry=a;this.materials=c instanceof Array?c:[c];this.type=d!=undefined?d:THREE.LineStrip};THREE.LineStrip=0;THREE.LinePieces=1;THREE.Line.prototype=new THREE.Object3D;THREE.Line.prototype.constructor=THREE.Line;THREE.Mesh=function(a,c){THREE.Object3D.call(this);this.geometry=a;this.materials=c instanceof Array?c:[c];this.overdraw=this.doubleSided=this.flipSided=false;this.geometry.boundingSphere||this.geometry.computeBoundingSphere()}; +THREE.Mesh.prototype=new THREE.Object3D;THREE.Mesh.prototype.constructor=THREE.Mesh;THREE.FlatShading=0;THREE.SmoothShading=1;THREE.NormalBlending=0;THREE.AdditiveBlending=1;THREE.SubtractiveBlending=2; +THREE.LineBasicMaterial=function(a){this.color=new THREE.Color(16777215);this.opacity=1;this.blending=THREE.NormalBlending;this.linewidth=1;this.linejoin=this.linecap="round";if(a){a.color!==undefined&&this.color.setHex(a.color);if(a.opacity!==undefined)this.opacity=a.opacity;if(a.blending!==undefined)this.blending=a.blending;if(a.linewidth!==undefined)this.linewidth=a.linewidth;if(a.linecap!==undefined)this.linecap=a.linecap;if(a.linejoin!==undefined)this.linejoin=a.linejoin}}; +THREE.LineBasicMaterial.prototype={toString:function(){return"THREE.LineBasicMaterial (
color: "+this.color+"
opacity: "+this.opacity+"
blending: "+this.blending+"
linewidth: "+this.linewidth+"
linecap: "+this.linecap+"
linejoin: "+this.linejoin+"
)"}}; +THREE.MeshBasicMaterial=function(a){this.id=THREE.MeshBasicMaterialCounter.value++;this.color=new THREE.Color(16777215);this.env_map=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refraction_ratio=0.98;this.fog=true;this.opacity=1;this.shading=THREE.SmoothShading;this.blending=THREE.NormalBlending;this.wireframe=false;this.wireframe_linewidth=1;this.wireframe_linejoin=this.wireframe_linecap="round";if(a){a.color!==undefined&&this.color.setHex(a.color);if(a.map!==undefined)this.map= +a.map;if(a.env_map!==undefined)this.env_map=a.env_map;if(a.combine!==undefined)this.combine=a.combine;if(a.reflectivity!==undefined)this.reflectivity=a.reflectivity;if(a.refraction_ratio!==undefined)this.refraction_ratio=a.refraction_ratio;if(a.fog!==undefined)this.fog=a.fog;if(a.opacity!==undefined)this.opacity=a.opacity;if(a.shading!==undefined)this.shading=a.shading;if(a.blending!==undefined)this.blending=a.blending;if(a.wireframe!==undefined)this.wireframe=a.wireframe;if(a.wireframe_linewidth!== +undefined)this.wireframe_linewidth=a.wireframe_linewidth;if(a.wireframe_linecap!==undefined)this.wireframe_linecap=a.wireframe_linecap;if(a.wireframe_linejoin!==undefined)this.wireframe_linejoin=a.wireframe_linejoin}}; +THREE.MeshBasicMaterial.prototype={toString:function(){return"THREE.MeshBasicMaterial (
id: "+this.id+"
color: "+this.color+"
map: "+this.map+"
env_map: "+this.env_map+"
combine: "+this.combine+"
reflectivity: "+this.reflectivity+"
refraction_ratio: "+this.refraction_ratio+"
opacity: "+this.opacity+"
blending: "+this.blending+"
wireframe: "+this.wireframe+"
wireframe_linewidth: "+this.wireframe_linewidth+"
wireframe_linecap: "+this.wireframe_linecap+ +"
wireframe_linejoin: "+this.wireframe_linejoin+"
)"}};THREE.MeshBasicMaterialCounter={value:0}; +THREE.MeshLambertMaterial=function(a){this.id=THREE.MeshLambertMaterialCounter.value++;this.color=new THREE.Color(16777215);this.env_map=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refraction_ratio=0.98;this.fog=true;this.opacity=1;this.shading=THREE.SmoothShading;this.blending=THREE.NormalBlending;this.wireframe=false;this.wireframe_linewidth=1;this.wireframe_linejoin=this.wireframe_linecap="round";if(a){a.color!==undefined&&this.color.setHex(a.color);if(a.map!==undefined)this.map= +a.map;if(a.env_map!==undefined)this.env_map=a.env_map;if(a.combine!==undefined)this.combine=a.combine;if(a.reflectivity!==undefined)this.reflectivity=a.reflectivity;if(a.refraction_ratio!==undefined)this.refraction_ratio=a.refraction_ratio;if(a.fog!==undefined)this.fog=a.fog;if(a.opacity!==undefined)this.opacity=a.opacity;if(a.shading!==undefined)this.shading=a.shading;if(a.blending!==undefined)this.blending=a.blending;if(a.wireframe!==undefined)this.wireframe=a.wireframe;if(a.wireframe_linewidth!== +undefined)this.wireframe_linewidth=a.wireframe_linewidth;if(a.wireframe_linecap!==undefined)this.wireframe_linecap=a.wireframe_linecap;if(a.wireframe_linejoin!==undefined)this.wireframe_linejoin=a.wireframe_linejoin}}; +THREE.MeshLambertMaterial.prototype={toString:function(){return"THREE.MeshLambertMaterial (
id: "+this.id+"
color: "+this.color+"
map: "+this.map+"
env_map: "+this.env_map+"
combine: "+this.combine+"
reflectivity: "+this.reflectivity+"
refraction_ratio: "+this.refraction_ratio+"
opacity: "+this.opacity+"
shading: "+this.shading+"
blending: "+this.blending+"
wireframe: "+this.wireframe+"
wireframe_linewidth: "+this.wireframe_linewidth+"
wireframe_linecap: "+ +this.wireframe_linecap+"
wireframe_linejoin: "+this.wireframe_linejoin+"
)"}};THREE.MeshLambertMaterialCounter={value:0}; +THREE.MeshPhongMaterial=function(a){this.id=THREE.MeshPhongMaterialCounter.value++;this.color=new THREE.Color(16777215);this.ambient=new THREE.Color(328965);this.specular=new THREE.Color(1118481);this.shininess=30;this.env_map=this.specular_map=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refraction_ratio=0.98;this.fog=true;this.opacity=1;this.shading=THREE.SmoothShading;this.blending=THREE.NormalBlending;this.wireframe=false;this.wireframe_linewidth=1;this.wireframe_linejoin= +this.wireframe_linecap="round";if(a){if(a.color!==undefined)this.color=new THREE.Color(a.color);if(a.ambient!==undefined)this.ambient=new THREE.Color(a.ambient);if(a.specular!==undefined)this.specular=new THREE.Color(a.specular);if(a.shininess!==undefined)this.shininess=a.shininess;if(a.map!==undefined)this.map=a.map;if(a.specular_map!==undefined)this.specular_map=a.specular_map;if(a.env_map!==undefined)this.env_map=a.env_map;if(a.combine!==undefined)this.combine=a.combine;if(a.reflectivity!==undefined)this.reflectivity= +a.reflectivity;if(a.refraction_ratio!==undefined)this.refraction_ratio=a.refraction_ratio;if(a.fog!==undefined)this.fog=a.fog;if(a.opacity!==undefined)this.opacity=a.opacity;if(a.shading!==undefined)this.shading=a.shading;if(a.blending!==undefined)this.blending=a.blending;if(a.wireframe!==undefined)this.wireframe=a.wireframe;if(a.wireframe_linewidth!==undefined)this.wireframe_linewidth=a.wireframe_linewidth;if(a.wireframe_linecap!==undefined)this.wireframe_linecap=a.wireframe_linecap;if(a.wireframe_linejoin!== +undefined)this.wireframe_linejoin=a.wireframe_linejoin}}; +THREE.MeshPhongMaterial.prototype={toString:function(){return"THREE.MeshPhongMaterial (
id: "+this.id+"
color: "+this.color+"
ambient: "+this.ambient+"
specular: "+this.specular+"
shininess: "+this.shininess+"
map: "+this.map+"
specular_map: "+this.specular_map+"
env_map: "+this.env_map+"
combine: "+this.combine+"
reflectivity: "+this.reflectivity+"
refraction_ratio: "+this.refraction_ratio+"
opacity: "+this.opacity+"
shading: "+this.shading+"
wireframe: "+ +this.wireframe+"
wireframe_linewidth: "+this.wireframe_linewidth+"
wireframe_linecap: "+this.wireframe_linecap+"
wireframe_linejoin: "+this.wireframe_linejoin+"
)"}};THREE.MeshPhongMaterialCounter={value:0}; +THREE.MeshDepthMaterial=function(a){this.opacity=1;this.shading=THREE.SmoothShading;this.blending=THREE.NormalBlending;this.wireframe=false;this.wireframe_linewidth=1;this.wireframe_linejoin=this.wireframe_linecap="round";if(a){if(a.opacity!==undefined)this.opacity=a.opacity;if(a.blending!==undefined)this.blending=a.blending}};THREE.MeshDepthMaterial.prototype={toString:function(){return"THREE.MeshDepthMaterial"}}; +THREE.MeshNormalMaterial=function(a){this.opacity=1;this.shading=THREE.FlatShading;this.blending=THREE.NormalBlending;if(a){if(a.opacity!==undefined)this.opacity=a.opacity;if(a.shading!==undefined)this.shading=a.shading;if(a.blending!==undefined)this.blending=a.blending}};THREE.MeshNormalMaterial.prototype={toString:function(){return"THREE.MeshNormalMaterial"}};THREE.MeshFaceMaterial=function(){};THREE.MeshFaceMaterial.prototype={toString:function(){return"THREE.MeshFaceMaterial"}}; +THREE.MeshShaderMaterial=function(a){this.id=THREE.MeshShaderMaterialCounter.value++;this.vertex_shader=this.fragment_shader="void main() {}";this.uniforms={};this.opacity=1;this.shading=THREE.SmoothShading;this.blending=THREE.NormalBlending;this.wireframe=false;this.wireframe_linewidth=1;this.wireframe_linejoin=this.wireframe_linecap="round";if(a){if(a.fragment_shader!==undefined)this.fragment_shader=a.fragment_shader;if(a.vertex_shader!==undefined)this.vertex_shader=a.vertex_shader;if(a.uniforms!== +undefined)this.uniforms=a.uniforms;if(a.shading!==undefined)this.shading=a.shading;if(a.blending!==undefined)this.blending=a.blending;if(a.wireframe!==undefined)this.wireframe=a.wireframe;if(a.wireframe_linewidth!==undefined)this.wireframe_linewidth=a.wireframe_linewidth;if(a.wireframe_linecap!==undefined)this.wireframe_linecap=a.wireframe_linecap;if(a.wireframe_linejoin!==undefined)this.wireframe_linejoin=a.wireframe_linejoin}}; +THREE.MeshShaderMaterial.prototype={toString:function(){return"THREE.MeshShaderMaterial (
id: "+this.id+"
blending: "+this.blending+"
wireframe: "+this.wireframe+"
wireframe_linewidth: "+this.wireframe_linewidth+"
wireframe_linecap: "+this.wireframe_linecap+"
wireframe_linejoin: "+this.wireframe_linejoin+"
)"}};THREE.MeshShaderMaterialCounter={value:0}; +THREE.ParticleBasicMaterial=function(a){this.color=new THREE.Color(16777215);this.map=null;this.opacity=1;this.blending=THREE.NormalBlending;this.offset=new THREE.Vector2;if(a){a.color!==undefined&&this.color.setHex(a.color);if(a.map!==undefined)this.map=a.map;if(a.opacity!==undefined)this.opacity=a.opacity;if(a.blending!==undefined)this.blending=a.blending}}; +THREE.ParticleBasicMaterial.prototype={toString:function(){return"THREE.ParticleBasicMaterial (
color: "+this.color+"
map: "+this.map+"
opacity: "+this.opacity+"
blending: "+this.blending+"
)"}};THREE.ParticleCircleMaterial=function(a){this.color=new THREE.Color(16777215);this.opacity=1;this.blending=THREE.NormalBlending;if(a){a.color!==undefined&&this.color.setHex(a.color);if(a.opacity!==undefined)this.opacity=a.opacity;if(a.blending!==undefined)this.blending=a.blending}}; +THREE.ParticleCircleMaterial.prototype={toString:function(){return"THREE.ParticleCircleMaterial (
color: "+this.color+"
opacity: "+this.opacity+"
blending: "+this.blending+"
)"}};THREE.ParticleDOMMaterial=function(a){this.domElement=a};THREE.ParticleDOMMaterial.prototype={toString:function(){return"THREE.ParticleDOMMaterial ( domElement: "+this.domElement+" )"}}; +THREE.Texture=function(a,c,d,e,g,h){this.image=a;this.mapping=c!==undefined?c:new THREE.UVMapping;this.wrap_s=d!==undefined?d:THREE.ClampToEdgeWrapping;this.wrap_t=e!==undefined?e:THREE.ClampToEdgeWrapping;this.mag_filter=g!==undefined?g:THREE.LinearFilter;this.min_filter=h!==undefined?h:THREE.LinearMipMapLinearFilter}; +THREE.Texture.prototype={clone:function(){return new THREE.Texture(this.image,this.mapping,this.wrap_s,this.wrap_t,this.mag_filter,this.min_filter)},toString:function(){return"THREE.Texture (
image: "+this.image+"
wrap_s: "+this.wrap_s+"
wrap_t: "+this.wrap_t+"
mag_filter: "+this.mag_filter+"
min_filter: "+this.min_filter+"
)"}};THREE.MultiplyOperation=0;THREE.MixOperation=1;THREE.RepeatWrapping=0;THREE.ClampToEdgeWrapping=1;THREE.MirroredRepeatWrapping=2; +THREE.NearestFilter=3;THREE.NearestMipMapNearestFilter=4;THREE.NearestMipMapLinearFilter=5;THREE.LinearFilter=6;THREE.LinearMipMapNearestFilter=7;THREE.LinearMipMapLinearFilter=8;THREE.ByteType=9;THREE.UnsignedByteType=10;THREE.ShortType=11;THREE.UnsignedShortType=12;THREE.IntType=13;THREE.UnsignedIntType=14;THREE.FloatType=15;THREE.AlphaFormat=16;THREE.RGBFormat=17;THREE.RGBAFormat=18;THREE.LuminanceFormat=19;THREE.LuminanceAlphaFormat=20; +THREE.RenderTarget=function(a,c,d){this.width=a;this.height=c;d=d||{};this.wrap_s=d.wrap_s!==undefined?d.wrap_s:THREE.ClampToEdgeWrapping;this.wrap_t=d.wrap_t!==undefined?d.wrap_t:THREE.ClampToEdgeWrapping;this.mag_filter=d.mag_filter!==undefined?d.mag_filter:THREE.LinearFilter;this.min_filter=d.min_filter!==undefined?d.min_filter:THREE.LinearMipMapLinearFilter;this.format=d.format!==undefined?d.format:THREE.RGBFormat;this.type=d.type!==undefined?d.type:THREE.UnsignedByteType}; +var Uniforms={clone:function(a){var c,d,e,g={};for(c in a){g[c]={};for(d in a[c]){e=a[c][d];g[c][d]=e instanceof THREE.Color||e instanceof THREE.Vector3||e instanceof THREE.Texture?e.clone():e}}return g},merge:function(a){var c,d,e,g={};for(c=0;c=0&&v>=0&&s>=0&&n>=0)return true;else if(t<0&&v<0||s<0&&n<0)return false;else{if(t<0)C=Math.max(C,t/(t-v));else if(v<0)m=Math.min(m,t/(t-v));if(s<0)C=Math.max(C,s/(s-n));else if(n<0)m=Math.min(m,s/(s-n));if(mt&&A.z0&&K.z<1){u=H[x]=H[x]||new THREE.RenderableParticle;u.x=K.x/K.w;u.y=K.y/K.w;u.z=K.z;u.rotation=G.rotation.z;u.scale.x=G.scale.x*Math.abs(u.x-(K.x+r.projectionMatrix.n11)/(K.w+r.projectionMatrix.n14)); +u.scale.y=G.scale.y*Math.abs(u.y-(K.y+r.projectionMatrix.n22)/(K.w+r.projectionMatrix.n24));u.materials=G.materials;m.push(u);x++}}}}C&&m.sort(a);return m};this.unprojectVector=function(l,r){var C=THREE.Matrix4.makeInvert(r.matrix);C.multiplySelf(THREE.Matrix4.makeInvert(r.projectionMatrix));C.multiplyVector3(l);return l}}; +THREE.DOMRenderer=function(){THREE.Renderer.call(this);var a=null,c=new THREE.Projector,d,e,g,h;this.domElement=document.createElement("div");this.setSize=function(o,b){d=o;e=b;g=d/2;h=e/2};this.render=function(o,b){var i,k,y,z,u,x,H,J;a=c.projectScene(o,b);i=0;for(k=a.length;i0){D.r+=ca.r*$;D.g+=ca.g*$;D.b+=ca.b*$}}else if($ instanceof THREE.PointLight){Y.sub($.position,X);Y.normalize();$=T.dot(Y)*ga;if($>0){D.r+=ca.r*$;D.g+=ca.g*$;D.b+=ca.b*$}}}}function Na(B,X,T){if(T.opacity!=0){a(T.opacity);c(T.blending);var D, +R,$,ca,ga,ia;if(T instanceof THREE.ParticleBasicMaterial){if(T.map){ca=T.map;ga=ca.width>>1;ia=ca.height>>1;R=X.scale.x*b;$=X.scale.y*i;T=R*ga;D=$*ia;w.set(B.x-T,B.y-D,B.x+T,B.y+D);if(V.instersects(w)){k.save();k.translate(B.x,B.y);k.rotate(-X.rotation);k.scale(R,-$);k.translate(-ga,-ia);k.drawImage(ca,0,0);k.restore()}}}else if(T instanceof THREE.ParticleCircleMaterial){if(M){Q.r=da.r+ba.r+Z.r;Q.g=da.g+ba.g+Z.g;Q.b=da.b+ba.b+Z.b;m.r=T.color.r*Q.r;m.g=T.color.g*Q.g;m.b=T.color.b*Q.b;m.updateStyleString()}else m.__styleString= +T.color.__styleString;T=X.scale.x*b;D=X.scale.y*i;w.set(B.x-T,B.y-D,B.x+T,B.y+D);if(V.instersects(w)){R=m.__styleString;if(J!=R)k.fillStyle=J=R;k.save();k.translate(B.x,B.y);k.rotate(-X.rotation);k.scale(T,D);k.beginPath();k.arc(0,0,1,0,ja,true);k.closePath();k.fill();k.restore()}}}}function Oa(B,X,T,D){if(D.opacity!=0){a(D.opacity);c(D.blending);k.beginPath();k.moveTo(B.positionScreen.x,B.positionScreen.y);k.lineTo(X.positionScreen.x,X.positionScreen.y);k.closePath();if(D instanceof THREE.LineBasicMaterial){m.__styleString= +D.color.__styleString;B=D.linewidth;if(K!=B)k.lineWidth=K=B;B=m.__styleString;if(H!=B)k.strokeStyle=H=B;k.stroke();w.inflate(D.linewidth*2)}}}function Ia(B,X,T,D,R,$){if(R.opacity!=0){a(R.opacity);c(R.blending);f=B.positionScreen.x;j=B.positionScreen.y;q=X.positionScreen.x;l=X.positionScreen.y;r=T.positionScreen.x;C=T.positionScreen.y;k.beginPath();k.moveTo(f,j);k.lineTo(q,l);k.lineTo(r,C);k.lineTo(f,j);k.closePath();if(R instanceof THREE.MeshBasicMaterial)if(R.map)R.map.image.loaded&&R.map.mapping instanceof +THREE.UVMapping&&xa(f,j,q,l,r,C,R.map.image,D.uvs[0].u,D.uvs[0].v,D.uvs[1].u,D.uvs[1].v,D.uvs[2].u,D.uvs[2].v);else if(R.env_map){if(R.env_map.image.loaded)if(R.env_map.mapping instanceof THREE.SphericalReflectionMapping){B=ra.matrix;Y.copy(D.vertexNormalsWorld[0]);N=(Y.x*B.n11+Y.y*B.n12+Y.z*B.n13)*0.5+0.5;G=-(Y.x*B.n21+Y.y*B.n22+Y.z*B.n23)*0.5+0.5;Y.copy(D.vertexNormalsWorld[1]);W=(Y.x*B.n11+Y.y*B.n12+Y.z*B.n13)*0.5+0.5;P=-(Y.x*B.n21+Y.y*B.n22+Y.z*B.n23)*0.5+0.5;Y.copy(D.vertexNormalsWorld[2]);I= +(Y.x*B.n11+Y.y*B.n12+Y.z*B.n13)*0.5+0.5;L=-(Y.x*B.n21+Y.y*B.n22+Y.z*B.n23)*0.5+0.5;xa(f,j,q,l,r,C,R.env_map.image,N,G,W,P,I,L)}}else R.wireframe?Ba(R.color.__styleString,R.wireframe_linewidth):Ca(R.color.__styleString);else if(R instanceof THREE.MeshLambertMaterial){if(R.map&&!R.wireframe){R.map.mapping instanceof THREE.UVMapping&&xa(f,j,q,l,r,C,R.map.image,D.uvs[0].u,D.uvs[0].v,D.uvs[1].u,D.uvs[1].v,D.uvs[2].u,D.uvs[2].v);c(THREE.SubtractiveBlending)}if(M)if(!R.wireframe&&R.shading==THREE.SmoothShading&& +D.vertexNormalsWorld.length==3){t.r=v.r=s.r=da.r;t.g=v.g=s.g=da.g;t.b=v.b=s.b=da.b;Aa($,D.v1.positionWorld,D.vertexNormalsWorld[0],t);Aa($,D.v2.positionWorld,D.vertexNormalsWorld[1],v);Aa($,D.v3.positionWorld,D.vertexNormalsWorld[2],s);n.r=(v.r+s.r)*0.5;n.g=(v.g+s.g)*0.5;n.b=(v.b+s.b)*0.5;O=Ja(t,v,s,n);xa(f,j,q,l,r,C,O,0,0,1,0,0,1)}else{Q.r=da.r;Q.g=da.g;Q.b=da.b;Aa($,D.centroidWorld,D.normalWorld,Q);m.r=R.color.r*Q.r;m.g=R.color.g*Q.g;m.b=R.color.b*Q.b;m.updateStyleString();R.wireframe?Ba(m.__styleString, +R.wireframe_linewidth):Ca(m.__styleString)}else R.wireframe?Ba(R.color.__styleString,R.wireframe_linewidth):Ca(R.color.__styleString)}else if(R instanceof THREE.MeshDepthMaterial){E=ra.near;A=ra.far;t.r=t.g=t.b=1-Ea(B.positionScreen.z,E,A);v.r=v.g=v.b=1-Ea(X.positionScreen.z,E,A);s.r=s.g=s.b=1-Ea(T.positionScreen.z,E,A);n.r=(v.r+s.r)*0.5;n.g=(v.g+s.g)*0.5;n.b=(v.b+s.b)*0.5;O=Ja(t,v,s,n);xa(f,j,q,l,r,C,O,0,0,1,0,0,1)}else if(R instanceof THREE.MeshNormalMaterial){m.r=Fa(D.normalWorld.x);m.g=Fa(D.normalWorld.y); +m.b=Fa(D.normalWorld.z);m.updateStyleString();R.wireframe?Ba(m.__styleString,R.wireframe_linewidth):Ca(m.__styleString)}}}function Ba(B,X){if(H!=B)k.strokeStyle=H=B;if(K!=X)k.lineWidth=K=X;k.stroke();w.inflate(X*2)}function Ca(B){if(J!=B)k.fillStyle=J=B;k.fill()}function xa(B,X,T,D,R,$,ca,ga,ia,na,la,oa,ya){var ta,pa;ta=ca.width-1;pa=ca.height-1;ga*=ta;ia*=pa;na*=ta;la*=pa;oa*=ta;ya*=pa;T-=B;D-=X;R-=B;$-=X;na-=ga;la-=ia;oa-=ga;ya-=ia;pa=1/(na*ya-oa*la);ta=(ya*T-la*R)*pa;la=(ya*D-la*$)*pa;T=(na*R- +oa*T)*pa;D=(na*$-oa*D)*pa;B=B-ta*ga-T*ia;X=X-la*ga-D*ia;k.save();k.transform(ta,la,T,D,B,X);k.clip();k.drawImage(ca,0,0);k.restore()}function Ja(B,X,T,D){var R=~~(B.r*255),$=~~(B.g*255);B=~~(B.b*255);var ca=~~(X.r*255),ga=~~(X.g*255);X=~~(X.b*255);var ia=~~(T.r*255),na=~~(T.g*255);T=~~(T.b*255);var la=~~(D.r*255),oa=~~(D.g*255);D=~~(D.b*255);ha[0]=R<0?0:R>255?255:R;ha[1]=$<0?0:$>255?255:$;ha[2]=B<0?0:B>255?255:B;ha[4]=ca<0?0:ca>255?255:ca;ha[5]=ga<0?0:ga>255?255:ga;ha[6]=X<0?0:X>255?255:X;ha[8]=ia< +0?0:ia>255?255:ia;ha[9]=na<0?0:na>255?255:na;ha[10]=T<0?0:T>255?255:T;ha[12]=la<0?0:la>255?255:la;ha[13]=oa<0?0:oa>255?255:oa;ha[14]=D<0?0:D>255?255:D;ka.putImageData(fa,0,0);ua.drawImage(qa,0,0);return sa}function Ea(B,X,T){B=(B-X)/(T-X);return B*B*(3-2*B)}function Fa(B){B=(B+1)*0.5;return B<0?0:B>1?1:B}function Ga(B,X){var T=X.x-B.x,D=X.y-B.y,R=1/Math.sqrt(T*T+D*D);T*=R;D*=R;X.x+=T;X.y+=D;B.x-=T;B.y-=D}var Da,Ka,aa,ma,wa,Ha,La,za;k.setTransform(1,0,0,-1,b,i);this.autoClear&&this.clear();d=e.projectScene(ea, +ra,this.sortElements);(M=ea.lights.length>0)&&Ma(ea);Da=0;for(Ka=d.length;Da0){W.r+=L.color.r*V;W.g+=L.color.g*V;W.b+=L.color.b*V}}else if(L instanceof THREE.PointLight){C.sub(L.position,G.centroidWorld);C.normalize();V=G.normalWorld.dot(C)*L.intensity;if(V>0){W.r+=L.color.r*V;W.g+=L.color.g*V;W.b+=L.color.b*V}}}}function c(N,G,W,P,I,L){s=e(n++);s.setAttribute("d","M "+N.positionScreen.x+ +" "+N.positionScreen.y+" L "+G.positionScreen.x+" "+G.positionScreen.y+" L "+W.positionScreen.x+","+W.positionScreen.y+"z");if(I instanceof THREE.MeshBasicMaterial)F.__styleString=I.color.__styleString;else if(I instanceof THREE.MeshLambertMaterial)if(U){f.r=j.r;f.g=j.g;f.b=j.b;a(L,P,f);F.r=I.color.r*f.r;F.g=I.color.g*f.g;F.b=I.color.b*f.b;F.updateStyleString()}else F.__styleString=I.color.__styleString;else if(I instanceof THREE.MeshDepthMaterial){r=1-I.__2near/(I.__farPlusNear-P.z*I.__farMinusNear); +F.setRGB(r,r,r)}else I instanceof THREE.MeshNormalMaterial&&F.setRGB(g(P.normalWorld.x),g(P.normalWorld.y),g(P.normalWorld.z));I.wireframe?s.setAttribute("style","fill: none; stroke: "+F.__styleString+"; stroke-width: "+I.wireframe_linewidth+"; stroke-opacity: "+I.opacity+"; stroke-linecap: "+I.wireframe_linecap+"; stroke-linejoin: "+I.wireframe_linejoin):s.setAttribute("style","fill: "+F.__styleString+"; fill-opacity: "+I.opacity);b.appendChild(s)}function d(N,G,W,P,I,L,V){s=e(n++);s.setAttribute("d", +"M "+N.positionScreen.x+" "+N.positionScreen.y+" L "+G.positionScreen.x+" "+G.positionScreen.y+" L "+W.positionScreen.x+","+W.positionScreen.y+" L "+P.positionScreen.x+","+P.positionScreen.y+"z");if(L instanceof THREE.MeshBasicMaterial)F.__styleString=L.color.__styleString;else if(L instanceof THREE.MeshLambertMaterial)if(U){f.r=j.r;f.g=j.g;f.b=j.b;a(V,I,f);F.r=L.color.r*f.r;F.g=L.color.g*f.g;F.b=L.color.b*f.b;F.updateStyleString()}else F.__styleString=L.color.__styleString;else if(L instanceof THREE.MeshDepthMaterial){r= +1-L.__2near/(L.__farPlusNear-I.z*L.__farMinusNear);F.setRGB(r,r,r)}else L instanceof THREE.MeshNormalMaterial&&F.setRGB(g(I.normalWorld.x),g(I.normalWorld.y),g(I.normalWorld.z));L.wireframe?s.setAttribute("style","fill: none; stroke: "+F.__styleString+"; stroke-width: "+L.wireframe_linewidth+"; stroke-opacity: "+L.opacity+"; stroke-linecap: "+L.wireframe_linecap+"; stroke-linejoin: "+L.wireframe_linejoin):s.setAttribute("style","fill: "+F.__styleString+"; fill-opacity: "+L.opacity);b.appendChild(s)} +function e(N){if(m[N]==null){m[N]=document.createElementNS("http://www.w3.org/2000/svg","path");O==0&&m[N].setAttribute("shape-rendering","crispEdges");return m[N]}return m[N]}function g(N){return N<0?Math.min((1+N)*0.5,0.5):0.5+Math.min(N*0.5,0.5)}var h=null,o=new THREE.Projector,b=document.createElementNS("http://www.w3.org/2000/svg","svg"),i,k,y,z,u,x,H,J,K=new THREE.Rectangle,p=new THREE.Rectangle,U=false,F=new THREE.Color(16777215),f=new THREE.Color(16777215),j=new THREE.Color(0),q=new THREE.Color(0), +l=new THREE.Color(0),r,C=new THREE.Vector3,m=[],t=[],v=[],s,n,E,A,O=1;this.domElement=b;this.sortElements=this.sortObjects=this.autoClear=true;this.setQuality=function(N){switch(N){case "high":O=1;break;case "low":O=0}};this.setSize=function(N,G){i=N;k=G;y=i/2;z=k/2;b.setAttribute("viewBox",-y+" "+-z+" "+i+" "+k);b.setAttribute("width",i);b.setAttribute("height",k);K.set(-y,-z,y,z)};this.clear=function(){for(;b.childNodes.length>0;)b.removeChild(b.childNodes[0])};this.render=function(N,G){var W,P, +I,L,V,S,w,M;this.autoClear&&this.clear();h=o.projectScene(N,G,this.sortElements);A=E=n=0;if(U=N.lights.length>0){w=N.lights;j.setRGB(0,0,0);q.setRGB(0,0,0);l.setRGB(0,0,0);W=0;for(P=w.length;W0){b.bindBuffer(b.ARRAY_BUFFER,f.__webGLUVBuffer);b.bufferData(b.ARRAY_BUFFER,da,q)}if(r){b.bindBuffer(b.ELEMENT_ARRAY_BUFFER, +f.__webGLFaceBuffer);b.bufferData(b.ELEMENT_ARRAY_BUFFER,ja,q);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,f.__webGLLineBuffer);b.bufferData(b.ELEMENT_ARRAY_BUFFER,Y,q)}};this.setLineBuffers=function(f,j,q,l){var r,C,m=f.vertices,t=m.length,v=f.__vertexArray,s=f.__lineArray;if(q)for(q=0;q0?"#define VERTEX_TEXTURES":"","#define MAX_DIR_LIGHTS "+s.maxDirLights,"#define MAX_POINT_LIGHTS "+s.maxPointLights, +s.map?"#define USE_MAP":"",s.env_map?"#define USE_ENVMAP":"","uniform mat4 objectMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\n"].join("\n");b.attachShader(E,g("fragment",A+t));b.attachShader(E,g("vertex",s+n));b.linkProgram(E);b.getProgramParameter(E,b.LINK_STATUS)||alert("Could not initialise shaders\nVALIDATE_STATUS: "+ +b.getProgramParameter(E,b.VALIDATE_STATUS)+", gl error ["+b.getError()+"]");E.uniforms={};E.attributes={};l.program=E;t=["viewMatrix","modelViewMatrix","projectionMatrix","normalMatrix","objectMatrix","cameraPosition"];for(m in l.uniforms)t.push(m);m=l.program;n=0;for(E=t.length;n=0){b.bindBuffer(b.ARRAY_BUFFER,r.__webGLNormalBuffer);b.vertexAttribPointer(v.normal,3,b.FLOAT,false,0,0);b.enableVertexAttribArray(v.normal)}if(v.tangent>=0){b.bindBuffer(b.ARRAY_BUFFER,r.__webGLTangentBuffer); +b.vertexAttribPointer(v.tangent,4,b.FLOAT,false,0,0);b.enableVertexAttribArray(v.tangent)}if(v.uv>=0)if(r.__webGLUVBuffer){b.bindBuffer(b.ARRAY_BUFFER,r.__webGLUVBuffer);b.vertexAttribPointer(v.uv,2,b.FLOAT,false,0,0);b.enableVertexAttribArray(v.uv)}else b.disableVertexAttribArray(v.uv);if(l.wireframe||l instanceof THREE.LineBasicMaterial){v=l.wireframe_linewidth!==undefined?l.wireframe_linewidth:l.linewidth!==undefined?l.linewidth:1;l=l instanceof THREE.LineBasicMaterial&&C.type==THREE.LineStrip? +b.LINE_STRIP:b.LINES;b.lineWidth(v);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,r.__webGLLineBuffer);b.drawElements(l,r.__webGLLineCount,b.UNSIGNED_SHORT,0)}else{b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,r.__webGLFaceBuffer);b.drawElements(b.TRIANGLES,r.__webGLFaceCount,b.UNSIGNED_SHORT,0)}};this.renderPass=function(f,j,q,l,r,C,m){var t,v,s,n,E;s=0;for(n=l.materials.length;s=0;q--){l=f.__webGLObjects[q].object;j==l&&f.__webGLObjects.splice(q,1)}};this.setupMatrices=function(f,j){f.autoUpdateMatrix&& +f.updateMatrix();y.multiply(j.matrix,f.matrix);x.set(y.flatten());z=THREE.Matrix4.makeInvert3x3(y).transpose();J.set(z.m);K.set(f.matrix.flatten())};this.loadMatrices=function(f){b.uniformMatrix4fv(f.uniforms.viewMatrix,false,u);b.uniformMatrix4fv(f.uniforms.modelViewMatrix,false,x);b.uniformMatrix4fv(f.uniforms.projectionMatrix,false,H);b.uniformMatrix3fv(f.uniforms.normalMatrix,false,J);b.uniformMatrix4fv(f.uniforms.objectMatrix,false,K)};this.loadCamera=function(f,j){b.uniform3f(f.uniforms.cameraPosition, +j.position.x,j.position.y,j.position.z)};this.setBlending=function(f){switch(f){case THREE.AdditiveBlending:b.blendEquation(b.FUNC_ADD);b.blendFunc(b.ONE,b.ONE);break;case THREE.SubtractiveBlending:b.blendFunc(b.DST_COLOR,b.ZERO);break;default:b.blendEquation(b.FUNC_ADD);b.blendFunc(b.ONE,b.ONE_MINUS_SRC_ALPHA)}};this.setFaceCulling=function(f,j){if(f){!j||j=="ccw"?b.frontFace(b.CCW):b.frontFace(b.CW);if(f=="back")b.cullFace(b.BACK);else f=="front"?b.cullFace(b.FRONT):b.cullFace(b.FRONT_AND_BACK); +b.enable(b.CULL_FACE)}else b.disable(b.CULL_FACE)};this.supportsVertexTextures=function(){return b.getParameter(b.MAX_VERTEX_TEXTURE_IMAGE_UNITS)>0}}; +THREE.Snippets={fog_pars_fragment:"#ifdef USE_FOG\nuniform vec3 fogColor;\n#ifdef FOG_EXP2\nuniform float fogDensity;\n#else\nuniform float fogNear;\nuniform float fogFar;\n#endif\n#endif",fog_fragment:"#ifdef USE_FOG\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n#ifdef FOG_EXP2\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n#else\nfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n#endif\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, 1.0 ), fogFactor );\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\nvarying vec3 vReflect;\nuniform float reflectivity;\nuniform samplerCube env_map;\nuniform int combine;\n#endif", +envmap_fragment:"#ifdef USE_ENVMAP\ncubeColor = textureCube( env_map, vec3( -vReflect.x, vReflect.yz ) );\nif ( combine == 1 ) {\ngl_FragColor = mix( gl_FragColor, cubeColor, reflectivity );\n} else {\ngl_FragColor = gl_FragColor * cubeColor;\n}\n#endif",envmap_pars_vertex:"#ifdef USE_ENVMAP\nvarying vec3 vReflect;\nuniform float refraction_ratio;\nuniform bool useRefract;\n#endif",envmap_vertex:"#ifdef USE_ENVMAP\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvec3 nWorld = mat3( objectMatrix[0].xyz, objectMatrix[1].xyz, objectMatrix[2].xyz ) * normal;\nif ( useRefract ) {\nvReflect = refract( normalize( mPosition.xyz - cameraPosition ), normalize( nWorld.xyz ), refraction_ratio );\n} else {\nvReflect = reflect( normalize( mPosition.xyz - cameraPosition ), normalize( nWorld.xyz ) );\n}\n#endif", +map_pars_fragment:"#ifdef USE_MAP\nvarying vec2 vUv;\nuniform sampler2D map;\n#endif",map_pars_vertex:"#ifdef USE_MAP\nvarying vec2 vUv;\n#endif",map_fragment:"#ifdef USE_MAP\nmapColor = texture2D( map, vUv );\n#endif",map_vertex:"#ifdef USE_MAP\nvUv = uv;\n#endif",lights_pars_vertex:"uniform bool enableLighting;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n#ifdef PHONG\nvarying vec3 vPointLightVector[ MAX_POINT_LIGHTS ];\n#endif\n#endif", +lights_vertex:"if ( !enableLighting ) {\nvLightWeighting = vec3( 1.0 );\n} else {\nvLightWeighting = ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nfloat directionalLightWeighting = max( dot( transformedNormal, normalize( lDirection.xyz ) ), 0.0 );\nvLightWeighting += directionalLightColor[ i ] * directionalLightWeighting;\n}\n#endif\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 pointLightVector = normalize( lPosition.xyz - mvPosition.xyz );\nfloat pointLightWeighting = max( dot( transformedNormal, pointLightVector ), 0.0 );\nvLightWeighting += pointLightColor[ i ] * pointLightWeighting;\n#ifdef PHONG\nvPointLightVector[ i ] = pointLightVector;\n#endif\n}\n#endif\n}", +lights_pars_fragment:"#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nvarying vec3 vPointLightVector[ MAX_POINT_LIGHTS ];\n#endif\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;",lights_fragment:"vec3 normal = normalize( vNormal );\nvec3 viewPosition = normalize( vViewPosition );\nvec4 mSpecular = vec4( specular, opacity );\n#if MAX_POINT_LIGHTS > 0\nvec4 pointDiffuse = vec4( 0.0 );\nvec4 pointSpecular = vec4( 0.0 );\nfor( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {\nvec3 pointVector = normalize( vPointLightVector[ i ] );\nvec3 pointHalfVector = normalize( vPointLightVector[ i ] + vViewPosition );\nfloat pointDotNormalHalf = dot( normal, pointHalfVector );\nfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\nfloat pointSpecularWeight = 0.0;\nif ( pointDotNormalHalf >= 0.0 )\npointSpecularWeight = pow( pointDotNormalHalf, shininess );\npointDiffuse += mColor * pointDiffuseWeight;\npointSpecular += mSpecular * pointSpecularWeight;\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec4 dirDiffuse = vec4( 0.0 );\nvec4 dirSpecular = vec4( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nvec3 dirHalfVector = normalize( lDirection.xyz + vViewPosition );\nfloat dirDotNormalHalf = dot( normal, dirHalfVector );\nfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\nfloat dirSpecularWeight = 0.0;\nif ( dirDotNormalHalf >= 0.0 )\ndirSpecularWeight = pow( dirDotNormalHalf, shininess );\ndirDiffuse += mColor * dirDiffuseWeight;\ndirSpecular += mSpecular * dirSpecularWeight;\n}\n#endif\nvec4 totalLight = vec4( ambient, opacity );\n#if MAX_DIR_LIGHTS > 0\ntotalLight += dirDiffuse + dirSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalLight += pointDiffuse + pointSpecular;\n#endif"}; +THREE.UniformsLib={common:{color:{type:"c",value:new THREE.Color(15658734)},opacity:{type:"f",value:1},map:{type:"t",value:0,texture:null},env_map:{type:"t",value:1,texture:null},useRefract:{type:"i",value:0},reflectivity:{type:"f",value:1},refraction_ratio:{type:"f",value:0.98},combine:{type:"i",value:0},fogDensity:{type:"f",value:2.5E-4},fogNear:{type:"f",value:1},fogFar:{type:"f",value:2E3},fogColor:{type:"c",value:new THREE.Color(16777215)}},lights:{enableLighting:{type:"i",value:1},ambientLightColor:{type:"fv", +value:[]},directionalLightDirection:{type:"fv",value:[]},directionalLightColor:{type:"fv",value:[]},pointLightPosition:{type:"fv",value:[]},pointLightColor:{type:"fv",value:[]}}}; +THREE.ShaderLib={depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3}},fragment_shader:"uniform float mNear;\nuniform float mFar;\nvoid main() {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat color = 1.0 - smoothstep( mNear, mFar, depth );\ngl_FragColor = vec4( vec3( color ), 1.0 );\n}",vertex_shader:"void main() {\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"},normal:{uniforms:{},fragment_shader:"varying vec3 vNormal;\nvoid main() {\ngl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, 1.0 );\n}", +vertex_shader:"varying vec3 vNormal;\nvoid main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvNormal = normalize( normalMatrix * normal );\ngl_Position = projectionMatrix * mvPosition;\n}"},basic:{uniforms:THREE.UniformsLib.common,fragment_shader:["uniform vec3 color;\nuniform float opacity;",THREE.Snippets.map_pars_fragment,THREE.Snippets.envmap_pars_fragment,THREE.Snippets.fog_pars_fragment,"void main() {\nvec4 mColor = vec4( color, opacity );\nvec4 mapColor = vec4( 1.0 );\nvec4 cubeColor = vec4( 1.0 );", +THREE.Snippets.map_fragment,"gl_FragColor = mColor * mapColor;",THREE.Snippets.envmap_fragment,THREE.Snippets.fog_fragment,"}"].join("\n"),vertex_shader:[THREE.Snippets.map_pars_vertex,THREE.Snippets.envmap_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",THREE.Snippets.map_vertex,THREE.Snippets.envmap_vertex,"gl_Position = projectionMatrix * mvPosition;\n}"].join("\n")},lambert:{uniforms:Uniforms.merge([THREE.UniformsLib.common,THREE.UniformsLib.lights]),fragment_shader:["uniform vec3 color;\nuniform float opacity;\nvarying vec3 vLightWeighting;", +THREE.Snippets.map_pars_fragment,THREE.Snippets.envmap_pars_fragment,THREE.Snippets.fog_pars_fragment,"void main() {\nvec4 mColor = vec4( color, opacity );\nvec4 mapColor = vec4( 1.0 );\nvec4 cubeColor = vec4( 1.0 );",THREE.Snippets.map_fragment,"gl_FragColor = mColor * mapColor * vec4( vLightWeighting, 1.0 );",THREE.Snippets.envmap_fragment,THREE.Snippets.fog_fragment,"}"].join("\n"),vertex_shader:["varying vec3 vLightWeighting;",THREE.Snippets.map_pars_vertex,THREE.Snippets.envmap_pars_vertex, +THREE.Snippets.lights_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",THREE.Snippets.map_vertex,THREE.Snippets.envmap_vertex,"vec3 transformedNormal = normalize( normalMatrix * normal );",THREE.Snippets.lights_vertex,"gl_Position = projectionMatrix * mvPosition;\n}"].join("\n")},phong:{uniforms:Uniforms.merge([THREE.UniformsLib.common,THREE.UniformsLib.lights,{ambient:{type:"c",value:new THREE.Color(328965)},specular:{type:"c",value:new THREE.Color(1118481)}, +shininess:{type:"f",value:30}}]),fragment_shader:["uniform vec3 color;\nuniform float opacity;\nuniform vec3 ambient;\nuniform vec3 specular;\nuniform float shininess;\nvarying vec3 vLightWeighting;",THREE.Snippets.map_pars_fragment,THREE.Snippets.envmap_pars_fragment,THREE.Snippets.fog_pars_fragment,THREE.Snippets.lights_pars_fragment,"void main() {\nvec4 mColor = vec4( color, opacity );\nvec4 mapColor = vec4( 1.0 );\nvec4 cubeColor = vec4( 1.0 );",THREE.Snippets.map_fragment,THREE.Snippets.lights_fragment, +"gl_FragColor = mapColor * totalLight * vec4( vLightWeighting, 1.0 );",THREE.Snippets.envmap_fragment,THREE.Snippets.fog_fragment,"}"].join("\n"),vertex_shader:["#define PHONG\nvarying vec3 vLightWeighting;\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;",THREE.Snippets.map_pars_vertex,THREE.Snippets.envmap_pars_vertex,THREE.Snippets.lights_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",THREE.Snippets.map_vertex,THREE.Snippets.envmap_vertex,"#ifndef USE_ENVMAP\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\n#endif\nvViewPosition = cameraPosition - mPosition.xyz;\nvec3 transformedNormal = normalize( normalMatrix * normal );\nvNormal = transformedNormal;", +THREE.Snippets.lights_vertex,"gl_Position = projectionMatrix * mvPosition;\n}"].join("\n")}};THREE.RenderableObject=function(){this.z=this.object=null};THREE.RenderableFace3=function(){this.z=null;this.v1=new THREE.Vertex;this.v2=new THREE.Vertex;this.v3=new THREE.Vertex;this.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[];this.faceMaterials=this.meshMaterials=null;this.overdraw=false;this.uvs=[null,null,null]}; +THREE.RenderableParticle=function(){this.rotation=this.z=this.y=this.x=null;this.scale=new THREE.Vector2;this.materials=null};THREE.RenderableLine=function(){this.z=null;this.v1=new THREE.Vertex;this.v2=new THREE.Vertex;this.materials=null}; diff --git a/mediagoblin/static/js/thingiview.js/binaryReader.js b/mediagoblin/static/js/thingiview.js/binaryReader.js new file mode 100644 index 00000000..f99a2379 --- /dev/null +++ b/mediagoblin/static/js/thingiview.js/binaryReader.js @@ -0,0 +1,126 @@ +// BinaryReader +// Refactored by Vjeux +// http://blog.vjeux.com/2010/javascript/javascript-binary-reader.html + +// Original +//+ Jonas Raoni Soares Silva +//@ http://jsfromhell.com/classes/binary-parser [rev. #1] + +BinaryReader = function (data) { + this._buffer = data; + this._pos = 0; +}; + +BinaryReader.prototype = { + + /* Public */ + + readInt8: function (){ return this._decodeInt(8, true); }, + readUInt8: function (){ return this._decodeInt(8, false); }, + readInt16: function (){ return this._decodeInt(16, true); }, + readUInt16: function (){ return this._decodeInt(16, false); }, + readInt32: function (){ return this._decodeInt(32, true); }, + readUInt32: function (){ return this._decodeInt(32, false); }, + + readFloat: function (){ return this._decodeFloat(23, 8); }, + readDouble: function (){ return this._decodeFloat(52, 11); }, + + readChar: function () { return this.readString(1); }, + readString: function (length) { + this._checkSize(length * 8); + var result = this._buffer.substr(this._pos, length); + this._pos += length; + return result; + }, + + seek: function (pos) { + this._pos = pos; + this._checkSize(0); + }, + + getPosition: function () { + return this._pos; + }, + + getSize: function () { + return this._buffer.length; + }, + + + /* Private */ + + _decodeFloat: function(precisionBits, exponentBits){ + var length = precisionBits + exponentBits + 1; + var size = length >> 3; + this._checkSize(length); + + var bias = Math.pow(2, exponentBits - 1) - 1; + var signal = this._readBits(precisionBits + exponentBits, 1, size); + var exponent = this._readBits(precisionBits, exponentBits, size); + var significand = 0; + var divisor = 2; + // var curByte = length + (-precisionBits >> 3) - 1; + var curByte = 0; + do { + var byteValue = this._readByte(++curByte, size); + var startBit = precisionBits % 8 || 8; + var mask = 1 << startBit; + while (mask >>= 1) { + if (byteValue & mask) { + significand += 1 / divisor; + } + divisor *= 2; + } + } while (precisionBits -= startBit); + + this._pos += size; + + return exponent == (bias << 1) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity + : (1 + signal * -2) * (exponent || significand ? !exponent ? Math.pow(2, -bias + 1) * significand + : Math.pow(2, exponent - bias) * (1 + significand) : 0); + }, + + _decodeInt: function(bits, signed){ + var x = this._readBits(0, bits, bits / 8), max = Math.pow(2, bits); + var result = signed && x >= max / 2 ? x - max : x; + + this._pos += bits / 8; + return result; + }, + + //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni) + _shl: function (a, b){ + for (++b; --b; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1); + return a; + }, + + _readByte: function (i, size) { + return this._buffer.charCodeAt(this._pos + size - i - 1) & 0xff; + }, + + _readBits: function (start, length, size) { + var offsetLeft = (start + length) % 8; + var offsetRight = start % 8; + var curByte = size - (start >> 3) - 1; + var lastByte = size + (-(start + length) >> 3); + var diff = curByte - lastByte; + + var sum = (this._readByte(curByte, size) >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1); + + if (diff && offsetLeft) { + sum += (this._readByte(lastByte++, size) & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight; + } + + while (diff) { + sum += this._shl(this._readByte(lastByte++, size), (diff-- << 3) - offsetRight); + } + + return sum; + }, + + _checkSize: function (neededBits) { + if (!(this._pos + Math.ceil(neededBits / 8) < this._buffer.length)) { + throw new Error("Index out of bound"); + } + } +}; \ No newline at end of file diff --git a/mediagoblin/static/js/thingiview.js/plane.js b/mediagoblin/static/js/thingiview.js/plane.js new file mode 100644 index 00000000..9f970be0 --- /dev/null +++ b/mediagoblin/static/js/thingiview.js/plane.js @@ -0,0 +1,62 @@ +/** + * @author mr.doob / http://mrdoob.com/ + * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as + */ + +var Plane = function ( width, height, segments_width, segments_height ) { + + THREE.Geometry.call( this ); + + var ix, iy, + width_half = width / 2, + height_half = height / 2, + gridX = segments_width || 1, + gridY = segments_height || 1, + gridX1 = gridX + 1, + gridY1 = gridY + 1, + segment_width = width / gridX, + segment_height = height / gridY; + + + for( iy = 0; iy < gridY1; iy++ ) { + + for( ix = 0; ix < gridX1; ix++ ) { + + var x = ix * segment_width - width_half; + var y = iy * segment_height - height_half; + + this.vertices.push( new THREE.Vertex( new THREE.Vector3( x, - y, 0 ) ) ); + + } + + } + + for( iy = 0; iy < gridY; iy++ ) { + + for( ix = 0; ix < gridX; ix++ ) { + + var a = ix + gridX1 * iy; + var b = ix + gridX1 * ( iy + 1 ); + var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); + var d = ( ix + 1 ) + gridX1 * iy; + + this.faces.push( new THREE.Face4( a, b, c, d ) ); + this.uvs.push( [ + new THREE.UV( ix / gridX, iy / gridY ), + new THREE.UV( ix / gridX, ( iy + 1 ) / gridY ), + new THREE.UV( ( ix + 1 ) / gridX, ( iy + 1 ) / gridY ), + new THREE.UV( ( ix + 1 ) / gridX, iy / gridY ) + ] ); + + } + + } + + this.computeCentroids(); + this.computeFaceNormals(); + this.sortFacesByMaterial(); + +}; + +Plane.prototype = new THREE.Geometry(); +Plane.prototype.constructor = Plane; diff --git a/mediagoblin/static/js/thingiview.js/stats.js b/mediagoblin/static/js/thingiview.js/stats.js new file mode 100644 index 00000000..270d1ce3 --- /dev/null +++ b/mediagoblin/static/js/thingiview.js/stats.js @@ -0,0 +1,2 @@ +// stats.js r5 - http://github.com/mrdoob/stats.js +var Stats=function(){var j=0,u=2,r,C=0,E=new Date().getTime(),w=E,f=E,m=0,e=1000,i=0,F,q,c,d,B,k=0,G=1000,a=0,A,t,p,D,l,v=0,o=1000,s=0,h,n,z,g,b,y={fps:{bg:{r:16,g:16,b:48},fg:{r:0,g:255,b:255}},ms:{bg:{r:16,g:48,b:16},fg:{r:0,g:255,b:0}},mem:{bg:{r:48,g:16,b:26},fg:{r:255,g:0,b:128}}};r=document.createElement("div");r.style.fontFamily="Helvetica, Arial, sans-serif";r.style.textAlign="left";r.style.fontSize="9px";r.style.opacity="0.9";r.style.width="80px";r.style.cursor="pointer";r.addEventListener("click",H,false);F=document.createElement("div");F.style.backgroundColor="rgb("+Math.floor(y.fps.bg.r/2)+","+Math.floor(y.fps.bg.g/2)+","+Math.floor(y.fps.bg.b/2)+")";F.style.padding="2px 0px 3px 0px";r.appendChild(F);q=document.createElement("div");q.innerHTML="FPS";q.style.color="rgb("+y.fps.fg.r+","+y.fps.fg.g+","+y.fps.fg.b+")";q.style.margin="0px 0px 1px 3px";F.appendChild(q);c=document.createElement("canvas");c.width=74;c.height=30;c.style.display="block";c.style.marginLeft="3px";F.appendChild(c);d=c.getContext("2d");d.fillStyle="rgb("+y.fps.bg.r+","+y.fps.bg.g+","+y.fps.bg.b+")";d.fillRect(0,0,c.width,c.height);B=d.getImageData(0,0,c.width,c.height);A=document.createElement("div");A.style.backgroundColor="rgb("+Math.floor(y.ms.bg.r/2)+","+Math.floor(y.ms.bg.g/2)+","+Math.floor(y.ms.bg.b/2)+")";A.style.padding="2px 0px 3px 0px";A.style.display="none";r.appendChild(A);t=document.createElement("div");t.innerHTML="MS";t.style.color="rgb("+y.ms.fg.r+","+y.ms.fg.g+","+y.ms.fg.b+")";t.style.margin="0px 0px 1px 3px";A.appendChild(t);p=document.createElement("canvas");p.width=74;p.height=30;p.style.display="block";p.style.marginLeft="3px";A.appendChild(p);D=p.getContext("2d");D.fillStyle="rgb("+y.ms.bg.r+","+y.ms.bg.g+","+y.ms.bg.b+")";D.fillRect(0,0,p.width,p.height);l=D.getImageData(0,0,p.width,p.height);try{if(webkitPerformance&&webkitPerformance.memory.totalJSHeapSize){u=3}}catch(x){}h=document.createElement("div");h.style.backgroundColor="rgb("+Math.floor(y.mem.bg.r/2)+","+Math.floor(y.mem.bg.g/2)+","+Math.floor(y.mem.bg.b/2)+")";h.style.padding="2px 0px 3px 0px";h.style.display="none";r.appendChild(h);n=document.createElement("div");n.innerHTML="MEM";n.style.color="rgb("+y.mem.fg.r+","+y.mem.fg.g+","+y.mem.fg.b+")";n.style.margin="0px 0px 1px 3px";h.appendChild(n);z=document.createElement("canvas");z.width=74;z.height=30;z.style.display="block";z.style.marginLeft="3px";h.appendChild(z);g=z.getContext("2d");g.fillStyle="#301010";g.fillRect(0,0,z.width,z.height);b=g.getImageData(0,0,z.width,z.height);function I(N,M,K){var J,O,L;for(O=0;O<30;O++){for(J=0;J<73;J++){L=(J+O*74)*4;N[L]=N[L+4];N[L+1]=N[L+5];N[L+2]=N[L+6]}}for(O=0;O<30;O++){L=(73+O*74)*4;if(O"+k+" MS ("+G+"-"+a+")";D.putImageData(l,0,0);w=E;if(E>f+1000){m=Math.round((C*1000)/(E-f));e=Math.min(e,m);i=Math.max(i,m);I(B.data,Math.min(30,30-(m/100)*30),"fps");q.innerHTML=""+m+" FPS ("+e+"-"+i+")";d.putImageData(B,0,0);if(u==3){v=webkitPerformance.memory.usedJSHeapSize*9.54e-7;o=Math.min(o,v);s=Math.max(s,v);I(b.data,Math.min(30,30-(v/2)),"mem");n.innerHTML=""+Math.round(v)+" MEM ("+Math.round(o)+"-"+Math.round(s)+")";g.putImageData(b,0,0)}f=E;C=0}}}}; \ No newline at end of file diff --git a/mediagoblin/static/js/thingiview.js/thingiloader.js b/mediagoblin/static/js/thingiview.js/thingiloader.js new file mode 100644 index 00000000..3791a49c --- /dev/null +++ b/mediagoblin/static/js/thingiview.js/thingiloader.js @@ -0,0 +1,318 @@ +Thingiloader = function(event) { + // Code from https://developer.mozilla.org/En/Using_XMLHttpRequest#Receiving_binary_data + this.load_binary_resource = function(url) { + var req = new XMLHttpRequest(); + req.open('GET', url, false); + // The following line says we want to receive data as Binary and not as Unicode + req.overrideMimeType('text/plain; charset=x-user-defined'); + req.send(null); + if (req.status != 200) return ''; + + return req.responseText; + }; + + this.loadSTL = function(url) { + var looksLikeBinary = function(reader) { + // STL files don't specify a way to distinguish ASCII from binary. + // The usual way is checking for "solid" at the start of the file -- + // but Thingiverse has seen at least one binary STL file in the wild + // that breaks this. + + // The approach here is different: binary STL files contain a triangle + // count early in the file. If this correctly predicts the file's length, + // it is most probably a binary STL file. + + reader.seek(80); // skip the header + var count = reader.readUInt32(); + + var predictedSize = 80 /* header */ + 4 /* count */ + 50 * count; + return reader.getSize() == predictedSize; + }; + + workerFacadeMessage({'status':'message', 'content':'Downloading ' + url}); + var file = this.load_binary_resource(url); + var reader = new BinaryReader(file); + + if (looksLikeBinary(reader)) { + this.loadSTLBinary(reader); + } else { + this.loadSTLString(file); + } + }; + + this.loadOBJ = function(url) { + workerFacadeMessage({'status':'message', 'content':'Downloading ' + url}); + var file = this.load_binary_resource(url); + this.loadOBJString(file); + }; + + this.loadJSON = function(url) { + workerFacadeMessage({'status':'message', 'content':'Downloading ' + url}); + var file = this.load_binary_resource(url); + this.loadJSONString(file); + }; + + this.loadPLY = function(url) { + workerFacadeMessage({'status':'message', 'content':'Downloading ' + url}); + + var file = this.load_binary_resource(url); + + if (file.match(/format ascii/i)) { + this.loadPLYString(file); + } else { + this.loadPLYBinary(file); + } + }; + + this.loadSTLString = function(STLString) { + workerFacadeMessage({'status':'message', 'content':'Parsing STL String...'}); + workerFacadeMessage({'status':'complete', 'content':this.ParseSTLString(STLString)}); + }; + + this.loadSTLBinary = function(STLBinary) { + workerFacadeMessage({'status':'message', 'content':'Parsing STL Binary...'}); + workerFacadeMessage({'status':'complete', 'content':this.ParseSTLBinary(STLBinary)}); + }; + + this.loadOBJString = function(OBJString) { + workerFacadeMessage({'status':'message', 'content':'Parsing OBJ String...'}); + workerFacadeMessage({'status':'complete', 'content':this.ParseOBJString(OBJString)}); + }; + + this.loadJSONString = function(JSONString) { + workerFacadeMessage({'status':'message', 'content':'Parsing JSON String...'}); + workerFacadeMessage({'status':'complete', 'content':eval(JSONString)}); + }; + + this.loadPLYString = function(PLYString) { + workerFacadeMessage({'status':'message', 'content':'Parsing PLY String...'}); + workerFacadeMessage({'status':'complete_points', 'content':this.ParsePLYString(PLYString)}); + }; + + this.loadPLYBinary = function(PLYBinary) { + workerFacadeMessage({'status':'message', 'content':'Parsing PLY Binary...'}); + workerFacadeMessage({'status':'complete_points', 'content':this.ParsePLYBinary(PLYBinary)}); + }; + + this.ParsePLYString = function(input) { + var properties = []; + var vertices = []; + var colors = []; + + var vertex_count = 0; + + var header = /ply\n([\s\S]+)\nend_header/ig.exec(input)[1]; + var data = /end_header\n([\s\S]+)$/ig.exec(input)[1]; + + // workerFacadeMessage({'status':'message', 'content':'header:\n' + header}); + // workerFacadeMessage({'status':'message', 'content':'data:\n' + data}); + + header_parts = header.split("\n"); + + for (i in header_parts) { + if (/element vertex/i.test(header_parts[i])) { + vertex_count = /element vertex (\d+)/i.exec(header_parts[i])[1]; + } else if (/property/i.test(header_parts[i])) { + properties.push(/property (.*) (.*)/i.exec(header_parts[i])[2]); + } + } + + // workerFacadeMessage({'status':'message', 'content':'properties: ' + properties}); + + data_parts = data.split("\n"); + + for (i in data_parts) { + data_line = data_parts[i]; + data_line_parts = data_line.split(" "); + + vertices.push([ + parseFloat(data_line_parts[properties.indexOf("x")]), + parseFloat(data_line_parts[properties.indexOf("y")]), + parseFloat(data_line_parts[properties.indexOf("z")]) + ]); + + colors.push([ + parseInt(data_line_parts[properties.indexOf("red")]), + parseInt(data_line_parts[properties.indexOf("green")]), + parseInt(data_line_parts[properties.indexOf("blue")]) + ]); + } + + // workerFacadeMessage({'status':'message', 'content':'vertices: ' + vertices}); + + return [vertices, colors]; + }; + + this.ParsePLYBinary = function(input) { + return false; + }; + + this.ParseSTLBinary = function(input) { + // Skip the header. + input.seek(80); + + // Load the number of vertices. + var count = input.readUInt32(); + + // During the parse loop we maintain the following data structures: + var vertices = []; // Append-only list of all unique vertices. + var vert_hash = {}; // Mapping from vertex to index in 'vertices', above. + var faces = []; // List of triangle descriptions, each a three-element + // list of indices in 'vertices', above. + + for (var i = 0; i < count; i++) { + if (i % 100 == 0) { + workerFacadeMessage({ + 'status':'message', + 'content':'Parsing ' + (i+1) + ' of ' + count + ' polygons...' + }); + workerFacadeMessage({ + 'status':'progress', + 'content':parseInt(i / count * 100) + '%' + }); + } + + // Skip the normal (3 single-precision floats) + input.seek(input.getPosition() + 12); + + var face_indices = []; + for (var x = 0; x < 3; x++) { + var vertex = [input.readFloat(), input.readFloat(), input.readFloat()]; + + var vertexIndex = vert_hash[vertex]; + if (vertexIndex == null) { + vertexIndex = vertices.length; + vertices.push(vertex); + vert_hash[vertex] = vertexIndex; + } + + face_indices.push(vertexIndex); + } + faces.push(face_indices); + + // Skip the "attribute" field (unused in common models) + input.readUInt16(); + } + + return [vertices, faces]; + }; + + // build stl's vertex and face arrays + this.ParseSTLString = function(STLString) { + var vertexes = []; + var faces = []; + + var face_vertexes = []; + var vert_hash = {} + + // console.log(STLString); + + // strip out extraneous stuff + STLString = STLString.replace(/\r/, "\n"); + STLString = STLString.replace(/^solid[^\n]*/, ""); + STLString = STLString.replace(/\n/g, " "); + STLString = STLString.replace(/facet normal /g,""); + STLString = STLString.replace(/outer loop/g,""); + STLString = STLString.replace(/vertex /g,""); + STLString = STLString.replace(/endloop/g,""); + STLString = STLString.replace(/endfacet/g,""); + STLString = STLString.replace(/endsolid[^\n]*/, ""); + STLString = STLString.replace(/\s+/g, " "); + STLString = STLString.replace(/^\s+/, ""); + + // console.log(STLString); + + var facet_count = 0; + var block_start = 0; + + var points = STLString.split(" "); + + workerFacadeMessage({'status':'message', 'content':'Parsing vertices...'}); + for (var i=0; i 0) { + // up + scope.setCameraZoom(+10); + } else { + // down + scope.setCameraZoom(-10); + } + } + + onRendererGestureChange = function(event) { + event.preventDefault(); + + if (event.scale > 1) { + scope.setCameraZoom(+5); + } else { + scope.setCameraZoom(-5); + } + } + + onRendererMouseOver = function(event) { + mouseOver = true; + // targetRotation = object.rotation.z; + if (timer == null) { + // log('starting loop'); + timer = setInterval(sceneLoop, 1000/60); + } + } + + onRendererMouseDown = function(event) { + // log("down"); + + event.preventDefault(); + mouseDown = true; + + if(scope.getRotation()){ + wasRotating = true; + scope.setRotation(false); + } else { + wasRotating = false; + } + + mouseXOnMouseDown = event.clientX - windowHalfX; + mouseYOnMouseDown = event.clientY - windowHalfY; + + targetXRotationOnMouseDown = targetXRotation; + targetYRotationOnMouseDown = targetYRotation; + } + + onRendererMouseMove = function(event) { + // log("move"); + + if (mouseDown) { + mouseX = event.clientX - windowHalfX; + // targetXRotation = targetXRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02; + xrot = targetXRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02; + + mouseY = event.clientY - windowHalfY; + // targetYRotation = targetYRotationOnMouseDown + (mouseY - mouseYOnMouseDown) * 0.02; + yrot = targetYRotationOnMouseDown + (mouseY - mouseYOnMouseDown) * 0.02; + + targetXRotation = xrot; + targetYRotation = yrot; + } + } + + onRendererMouseUp = function(event) { + // log("up"); + if (mouseDown) { + mouseDown = false; + if (!mouseOver) { + clearInterval(timer); + timer = null; + } + if (wasRotating) { + scope.setRotation(true); + } + } + } + + onRendererMouseOut = function(event) { + if (!mouseDown) { + clearInterval(timer); + timer = null; + } + mouseOver = false; + } + + onRendererTouchStart = function(event) { + targetXRotation = object.rotation.z; + targetYRotation = object.rotation.x; + + timer = setInterval(sceneLoop, 1000/60); + + if (event.touches.length == 1) { + event.preventDefault(); + + mouseXOnMouseDown = event.touches[0].pageX - windowHalfX; + targetXRotationOnMouseDown = targetXRotation; + + mouseYOnMouseDown = event.touches[0].pageY - windowHalfY; + targetYRotationOnMouseDown = targetYRotation; + } + } + + onRendererTouchEnd = function(event) { + clearInterval(timer); + timer = null; + // targetXRotation = object.rotation.z; + // targetYRotation = object.rotation.x; + } + + onRendererTouchMove = function(event) { + if (event.touches.length == 1) { + event.preventDefault(); + + mouseX = event.touches[0].pageX - windowHalfX; + targetXRotation = targetXRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05; + + mouseY = event.touches[0].pageY - windowHalfY; + targetYRotation = targetYRotationOnMouseDown + (mouseY - mouseYOnMouseDown) * 0.05; + } + } + + sceneLoop = function() { + if (object) { + // if (view == 'bottom') { + // if (showPlane) { + // plane.rotation.z = object.rotation.z -= (targetRotation + object.rotation.z) * 0.05; + // } else { + // object.rotation.z -= (targetRotation + object.rotation.z) * 0.05; + // } + // } else { + // if (showPlane) { + // plane.rotation.z = object.rotation.z += (targetRotation - object.rotation.z) * 0.05; + // } else { + // object.rotation.z += (targetRotation - object.rotation.z) * 0.05; + // } + // } + + if (showPlane) { + plane.rotation.z = object.rotation.z = (targetXRotation - object.rotation.z) * 0.2; + plane.rotation.x = object.rotation.x = (targetYRotation - object.rotation.x) * 0.2; + } else { + object.rotation.z = (targetXRotation - object.rotation.z) * 0.2; + object.rotation.x = (targetYRotation - object.rotation.x) * 0.2; + } + + // log(object.rotation.x); + + camera.updateMatrix(); + object.updateMatrix(); + + if (showPlane) { + plane.updateMatrix(); + } + + renderer.render(scene, camera); + // stats.update(); + } + } + + rotateLoop = function() { + // targetRotation += 0.01; + targetXRotation += 0.05; + sceneLoop(); + } + + this.getShowPlane = function(){ + return showPlane; + } + + this.setShowPlane = function(show) { + showPlane = show; + + if (show) { + if (scene && !plane) { + loadPlaneGeometry(); + } + plane.material[0].opacity = 1; + // plane.updateMatrix(); + } else { + if (scene && plane) { + // alert(plane.material[0].opacity); + plane.material[0].opacity = 0; + // plane.updateMatrix(); + } + } + + sceneLoop(); + } + + this.getRotation = function() { + return rotateTimer !== null; + } + + this.setRotation = function(rotate) { + rotation = rotate; + + if (rotate) { + rotateTimer = setInterval(rotateLoop, 1000/60); + } else { + clearInterval(rotateTimer); + rotateTimer = null; + } + + scope.onSetRotation(); + } + + this.onSetRotation = function(callback) { + if(callback === undefined){ + if(rotateListener !== null){ + try{ + rotateListener(scope.getRotation()); + } catch(ignored) {} + } + } else { + rotateListener = callback; + } + } + + this.setCameraView = function(dir) { + cameraView = dir; + + targetXRotation = 0; + targetYRotation = 0; + + if (object) { + object.rotation.x = 0; + object.rotation.y = 0; + object.rotation.z = 0; + } + + if (showPlane && object) { + plane.rotation.x = object.rotation.x; + plane.rotation.y = object.rotation.y; + plane.rotation.z = object.rotation.z; + } + + if (dir == 'top') { + // camera.position.y = 0; + // camera.position.z = 100; + // camera.target.position.z = 0; + if (showPlane) { + plane.flipSided = false; + } + } else if (dir == 'side') { + // camera.position.y = -70; + // camera.position.z = 70; + // camera.target.position.z = 0; + targetYRotation = -4.5; + if (showPlane) { + plane.flipSided = false; + } + } else if (dir == 'bottom') { + // camera.position.y = 0; + // camera.position.z = -100; + // camera.target.position.z = 0; + if (showPlane) { + plane.flipSided = true; + } + } else { + // camera.position.y = -70; + // camera.position.z = 70; + // camera.target.position.z = 0; + if (showPlane) { + plane.flipSided = false; + } + } + + mouseX = targetXRotation; + mouseXOnMouseDown = targetXRotation; + + mouseY = targetYRotation; + mouseYOnMouseDown = targetYRotation; + + scope.centerCamera(); + + sceneLoop(); + } + + this.setCameraZoom = function(factor) { + cameraZoom = factor; + + if (cameraView == 'bottom') { + if (camera.position.z + factor > 0) { + factor = 0; + } + } else { + if (camera.position.z - factor < 0) { + factor = 0; + } + } + + if (cameraView == 'top') { + camera.position.z -= factor; + } else if (cameraView == 'bottom') { + camera.position.z += factor; + } else if (cameraView == 'side') { + camera.position.y += factor; + camera.position.z -= factor; + } else { + camera.position.y += factor; + camera.position.z -= factor; + } + + sceneLoop(); + } + + this.getObjectMaterial = function() { + return objectMaterial; + } + + this.setObjectMaterial = function(type) { + objectMaterial = type; + + loadObjectGeometry(); + } + + this.setBackgroundColor = function(color) { + backgroundColor = color + + if (renderer) { + renderer.domElement.style.backgroundColor = color; + } + } + + this.setObjectColor = function(color) { + objectColor = parseInt(color.replace(/\#/g, ''), 16); + + loadObjectGeometry(); + } + + this.loadSTL = function(url) { + scope.newWorker('loadSTL', url); + } + + this.loadOBJ = function(url) { + scope.newWorker('loadOBJ', url); + } + + this.loadSTLString = function(STLString) { + scope.newWorker('loadSTLString', STLString); + } + + this.loadSTLBinary = function(STLBinary) { + scope.newWorker('loadSTLBinary', STLBinary); + } + + this.loadOBJString = function(OBJString) { + scope.newWorker('loadOBJString', OBJString); + } + + this.loadJSON = function(url) { + scope.newWorker('loadJSON', url); + } + + this.loadPLY = function(url) { + scope.newWorker('loadPLY', url); + } + + this.loadPLYString = function(PLYString) { + scope.newWorker('loadPLYString', PLYString); + } + + this.loadPLYBinary = function(PLYBinary) { + scope.newWorker('loadPLYBinary', PLYBinary); + } + + this.centerCamera = function() { + if (geometry) { + // Using method from http://msdn.microsoft.com/en-us/library/bb197900(v=xnagamestudio.10).aspx + // log("bounding sphere radius = " + geometry.boundingSphere.radius); + + // look at the center of the object + camera.target.position.x = geometry.center_x; + camera.target.position.y = geometry.center_y; + camera.target.position.z = geometry.center_z; + + // set camera position to center of sphere + camera.position.x = geometry.center_x; + camera.position.y = geometry.center_y; + camera.position.z = geometry.center_z; + + // find distance to center + distance = geometry.boundingSphere.radius / Math.sin((camera.fov/2) * (Math.PI / 180)); + + // zoom backwards about half that distance, I don't think I'm doing the math or backwards vector calculation correctly? + // scope.setCameraZoom(-distance/1.8); + // scope.setCameraZoom(-distance/1.5); + scope.setCameraZoom(-distance/1.9); + + directionalLight.position.x = geometry.min_y * 2; + directionalLight.position.y = geometry.min_y * 2; + directionalLight.position.z = geometry.max_z * 2; + + pointLight.position.x = geometry.center_y; + pointLight.position.y = geometry.center_y; + pointLight.position.z = geometry.max_z * 2; + } else { + // set to any valid position so it doesn't fail before geometry is available + camera.position.y = -70; + camera.position.z = 70; + camera.target.position.z = 0; + } + } + + this.loadArray = function(array) { + log("loading array..."); + geometry = new STLGeometry(array); + loadObjectGeometry(); + scope.setRotation(false); + scope.setRotation(true); + scope.centerCamera(); + log("finished loading " + geometry.faces.length + " faces."); + } + + this.newWorker = function(cmd, param) { + scope.setRotation(false); + + var worker = new WorkerFacade(thingiurlbase + '/thingiloader.js'); + + worker.onmessage = function(event) { + if (event.data.status == "complete") { + progressBar.innerHTML = 'Initializing geometry...'; + // scene.removeObject(object); + geometry = new STLGeometry(event.data.content); + loadObjectGeometry(); + progressBar.innerHTML = ''; + progressBar.style.display = 'none'; + + scope.setRotation(false); + scope.setRotation(true); + log("finished loading " + geometry.faces.length + " faces."); + scope.centerCamera(); + } else if (event.data.status == "complete_points") { + progressBar.innerHTML = 'Initializing points...'; + + geometry = new THREE.Geometry(); + + var material = new THREE.ParticleBasicMaterial( { color: 0xff0000, opacity: 1 } ); + + // material = new THREE.ParticleBasicMaterial( { size: 35, sizeAttenuation: false} ); + // material.color.setHSV( 1.0, 0.2, 0.8 ); + + for (i in event.data.content[0]) { + // for (var i=0; i<10; i++) { + vector = new THREE.Vector3( event.data.content[0][i][0], event.data.content[0][i][1], event.data.content[0][i][2] ); + geometry.vertices.push( new THREE.Vertex( vector ) ); + } + + particles = new THREE.ParticleSystem( geometry, material ); + particles.sortParticles = true; + particles.updateMatrix(); + scene.addObject( particles ); + + camera.updateMatrix(); + renderer.render(scene, camera); + + progressBar.innerHTML = ''; + progressBar.style.display = 'none'; + + scope.setRotation(false); + scope.setRotation(true); + log("finished loading " + event.data.content[0].length + " points."); + // scope.centerCamera(); + } else if (event.data.status == "progress") { + progressBar.style.display = 'block'; + progressBar.style.width = event.data.content; + // log(event.data.content); + } else if (event.data.status == "message") { + progressBar.style.display = 'block'; + progressBar.innerHTML = event.data.content; + log(event.data.content); + } else if (event.data.status == "alert") { + scope.displayAlert(event.data.content); + } else { + alert('Error: ' + event.data); + log('Unknown Worker Message: ' + event.data); + } + } + + worker.onerror = function(error) { + log(error); + error.preventDefault(); + } + + worker.postMessage({'cmd':cmd, 'param':param}); + } + + this.displayAlert = function(msg) { + msg = msg + "

" + + alertBox.innerHTML = msg; + alertBox.style.display = 'block'; + + // log(msg); + } + + function loadPlaneGeometry() { + // TODO: switch to lines instead of the Plane object so we can get rid of the horizontal lines in canvas renderer... + plane = new THREE.Mesh(new Plane(100, 100, 10, 10), new THREE.MeshBasicMaterial({color:0xafafaf,wireframe:true})); + scene.addObject(plane); + } + + function loadObjectGeometry() { + if (scene && geometry) { + if (objectMaterial == 'wireframe') { + // material = new THREE.MeshColorStrokeMaterial(objectColor, 1, 1); + material = new THREE.MeshBasicMaterial({color:objectColor,wireframe:true}); + } else { + if (isWebGl) { + // material = new THREE.MeshPhongMaterial(objectColor, objectColor, 0xffffff, 50, 1.0); + // material = new THREE.MeshColorFillMaterial(objectColor); + // material = new THREE.MeshLambertMaterial({color:objectColor}); + material = new THREE.MeshLambertMaterial({color:objectColor, shading: THREE.FlatShading}); + } else { + // material = new THREE.MeshColorFillMaterial(objectColor); + material = new THREE.MeshLambertMaterial({color:objectColor, shading: THREE.FlatShading}); + } + } + + // scene.removeObject(object); + + if (object) { + // shouldn't be needed, but this fixes a bug with webgl not removing previous object when loading a new one dynamically + object.materials = [new THREE.MeshBasicMaterial({color:0xffffff, opacity:0})]; + scene.removeObject(object); + // object.geometry = geometry; + // object.materials = [material]; + } + + object = new THREE.Mesh(geometry, material); + scene.addObject(object); + + if (objectMaterial != 'wireframe') { + object.overdraw = true; + object.doubleSided = true; + } + + object.updateMatrix(); + + targetXRotation = 0; + targetYRotation = 0; + + sceneLoop(); + } + } + +}; + +var STLGeometry = function(stlArray) { + // log("building geometry..."); + THREE.Geometry.call(this); + + var scope = this; + + // var vertexes = stlArray[0]; + // var normals = stlArray[1]; + // var faces = stlArray[2]; + + for (var i=0; i 0){ + theworker.postToWorkerFunction(callings[0]); + callings.shift(); + } + }; + document.body.appendChild(scr); + + var binaryscr = document.createElement("SCRIPT"); + binaryscr.src = thingiurlbase + '/binaryReader.js'; + binaryscr.type = "text/javascript"; + document.body.appendChild(binaryscr); + + return theworker; + }; + that.fake = true; + that.add = function(pth, worker){ + workers[pth] = worker; + return function(param){ + masters[pth].onmessage({"data": param}); + }; + }; + that.toString = function(){ + return "FakeWorker('"+path+"')"; + }; + return that; + }()); +} + +/* Then just use WorkerFacade instead of Worker (or alias it) + +The Worker code must should use a custom function (name it how you want) instead of postMessage. +Put this at the end of the Worker: + +if(typeof(window) === "undefined"){ + onmessage = nameOfWorkerFunction; + customPostMessage = postMessage; +} else { + customPostMessage = WorkerFacade.add("path/to/thisworker.js", nameOfWorkerFunction); +} + +*/ -- cgit v1.2.3 From 2b19fd5135bbc28ffc73db69cabc169e8747015a Mon Sep 17 00:00:00 2001 From: Aeva Ntsc Date: Mon, 15 Oct 2012 01:34:11 -0500 Subject: Added the thingiview.js library. --- mediagoblin/static/js/thingiview.js/LICENSE | 165 ++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 mediagoblin/static/js/thingiview.js/LICENSE (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/thingiview.js/LICENSE b/mediagoblin/static/js/thingiview.js/LICENSE new file mode 100644 index 00000000..65c5ca88 --- /dev/null +++ b/mediagoblin/static/js/thingiview.js/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. -- cgit v1.2.3 From 171dcbe3a80e13f4114a969f271dae1a1a5b3d7e Mon Sep 17 00:00:00 2001 From: Aeva Ntsc Date: Mon, 15 Oct 2012 10:10:04 -0500 Subject: disabled auto rotate --- mediagoblin/static/js/thingiview.js/thingiview.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/thingiview.js/thingiview.js b/mediagoblin/static/js/thingiview.js/thingiview.js index 71511eb2..5eb30335 100644 --- a/mediagoblin/static/js/thingiview.js/thingiview.js +++ b/mediagoblin/static/js/thingiview.js/thingiview.js @@ -391,6 +391,13 @@ Thingiview = function(containerId) { return rotateTimer !== null; } + this.resetRotation = function () { + if (rotate) { + this.setRotation(false); + this.setRotation(true); + } + } + this.setRotation = function(rotate) { rotation = rotate; @@ -606,8 +613,7 @@ Thingiview = function(containerId) { log("loading array..."); geometry = new STLGeometry(array); loadObjectGeometry(); - scope.setRotation(false); - scope.setRotation(true); + scope.resetRotation(); scope.centerCamera(); log("finished loading " + geometry.faces.length + " faces."); } @@ -626,8 +632,7 @@ Thingiview = function(containerId) { progressBar.innerHTML = ''; progressBar.style.display = 'none'; - scope.setRotation(false); - scope.setRotation(true); + scope.resetRotation(); log("finished loading " + geometry.faces.length + " faces."); scope.centerCamera(); } else if (event.data.status == "complete_points") { @@ -657,8 +662,7 @@ Thingiview = function(containerId) { progressBar.innerHTML = ''; progressBar.style.display = 'none'; - scope.setRotation(false); - scope.setRotation(true); + scope.resetRotation(); log("finished loading " + event.data.content[0].length + " points."); // scope.centerCamera(); } else if (event.data.status == "progress") { -- cgit v1.2.3 From 78d932e7928a39311309e4e89a47fb3d992feac7 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Mon, 3 Dec 2012 14:57:52 -0600 Subject: Moving thingiview.js into extlib/ --- mediagoblin/static/js/thingiview.js/LICENSE | 165 ---- mediagoblin/static/js/thingiview.js/Three.js | 202 ----- .../static/js/thingiview.js/binaryReader.js | 126 --- mediagoblin/static/js/thingiview.js/plane.js | 62 -- mediagoblin/static/js/thingiview.js/stats.js | 2 - .../static/js/thingiview.js/thingiloader.js | 318 -------- mediagoblin/static/js/thingiview.js/thingiview.js | 898 --------------------- 7 files changed, 1773 deletions(-) delete mode 100644 mediagoblin/static/js/thingiview.js/LICENSE delete mode 100644 mediagoblin/static/js/thingiview.js/Three.js delete mode 100644 mediagoblin/static/js/thingiview.js/binaryReader.js delete mode 100644 mediagoblin/static/js/thingiview.js/plane.js delete mode 100644 mediagoblin/static/js/thingiview.js/stats.js delete mode 100644 mediagoblin/static/js/thingiview.js/thingiloader.js delete mode 100644 mediagoblin/static/js/thingiview.js/thingiview.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/thingiview.js/LICENSE b/mediagoblin/static/js/thingiview.js/LICENSE deleted file mode 100644 index 65c5ca88..00000000 --- a/mediagoblin/static/js/thingiview.js/LICENSE +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. diff --git a/mediagoblin/static/js/thingiview.js/Three.js b/mediagoblin/static/js/thingiview.js/Three.js deleted file mode 100644 index 5c21380c..00000000 --- a/mediagoblin/static/js/thingiview.js/Three.js +++ /dev/null @@ -1,202 +0,0 @@ -// Three.js r32 - http://github.com/mrdoob/three.js -var THREE=THREE||{};THREE.Color=function(a){this.autoUpdate=true;this.setHex(a)}; -THREE.Color.prototype={setRGB:function(a,c,d){this.r=a;this.g=c;this.b=d;if(this.autoUpdate){this.updateHex();this.updateStyleString()}},setHex:function(a){this.hex=~~a&16777215;if(this.autoUpdate){this.updateRGBA();this.updateStyleString()}},updateHex:function(){this.hex=~~(this.r*255)<<16^~~(this.g*255)<<8^~~(this.b*255)},updateRGBA:function(){this.r=(this.hex>>16&255)/255;this.g=(this.hex>>8&255)/255;this.b=(this.hex&255)/255},updateStyleString:function(){this.__styleString="rgb("+~~(this.r*255)+ -","+~~(this.g*255)+","+~~(this.b*255)+")"},clone:function(){return new THREE.Color(this.hex)},toString:function(){return"THREE.Color ( r: "+this.r+", g: "+this.g+", b: "+this.b+", hex: "+this.hex+" )"}};THREE.Vector2=function(a,c){this.x=a||0;this.y=c||0}; -THREE.Vector2.prototype={set:function(a,c){this.x=a;this.y=c;return this},copy:function(a){this.x=a.x;this.y=a.y;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;return this},add:function(a,c){this.x=a.x+c.x;this.y=a.y+c.y;return this},subSelf:function(a){this.x-=a.x;this.y-=a.y;return this},sub:function(a,c){this.x=a.x-c.x;this.y=a.y-c.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},unit:function(){this.multiplyScalar(1/this.length());return this},length:function(){return Math.sqrt(this.x* -this.x+this.y*this.y)},lengthSq:function(){return this.x*this.x+this.y*this.y},negate:function(){this.x=-this.x;this.y=-this.y;return this},clone:function(){return new THREE.Vector2(this.x,this.y)},toString:function(){return"THREE.Vector2 ("+this.x+", "+this.y+")"}};THREE.Vector3=function(a,c,d){this.x=a||0;this.y=c||0;this.z=d||0}; -THREE.Vector3.prototype={set:function(a,c,d){this.x=a;this.y=c;this.z=d;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,c){this.x=a.x+c.x;this.y=a.y+c.y;this.z=a.z+c.z;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},sub:function(a,c){this.x=a.x-c.x;this.y=a.y-c.y;this.z=a.z-c.z;return this},subSelf:function(a){this.x-=a.x;this.y-=a.y;this.z-=a.z;return this}, -cross:function(a,c){this.x=a.y*c.z-a.z*c.y;this.y=a.z*c.x-a.x*c.z;this.z=a.x*c.y-a.y*c.x;return this},crossSelf:function(a){var c=this.x,d=this.y,e=this.z;this.x=d*a.z-e*a.y;this.y=e*a.x-c*a.z;this.z=c*a.y-d*a.x;return this},multiply:function(a,c){this.x=a.x*c.x;this.y=a.y*c.y;this.z=a.z*c.z;return this},multiplySelf:function(a){this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},divideSelf:function(a){this.x/=a.x;this.y/=a.y;this.z/= -a.z;return this},divideScalar:function(a){this.x/=a;this.y/=a;this.z/=a;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.z},distanceTo:function(a){var c=this.x-a.x,d=this.y-a.y;a=this.z-a.z;return Math.sqrt(c*c+d*d+a*a)},distanceToSquared:function(a){var c=this.x-a.x,d=this.y-a.y;a=this.z-a.z;return c*c+d*d+a*a},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},negate:function(){this.x= --this.x;this.y=-this.y;this.z=-this.z;return this},normalize:function(){var a=Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z);a>0?this.multiplyScalar(1/a):this.set(0,0,0);return this},setLength:function(a){return this.normalize().multiplyScalar(a)},isZero:function(){return Math.abs(this.x)<1.0E-4&&Math.abs(this.y)<1.0E-4&&Math.abs(this.z)<1.0E-4},clone:function(){return new THREE.Vector3(this.x,this.y,this.z)},toString:function(){return"THREE.Vector3 ( "+this.x+", "+this.y+", "+this.z+" )"}}; -THREE.Vector4=function(a,c,d,e){this.x=a||0;this.y=c||0;this.z=d||0;this.w=e||1}; -THREE.Vector4.prototype={set:function(a,c,d,e){this.x=a;this.y=c;this.z=d;this.w=e;return this},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=a.w||1;return this},add:function(a,c){this.x=a.x+c.x;this.y=a.y+c.y;this.z=a.z+c.z;this.w=a.w+c.w;return this},addSelf:function(a){this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this},sub:function(a,c){this.x=a.x-c.x;this.y=a.y-c.y;this.z=a.z-c.z;this.w=a.w-c.w;return this},subSelf:function(a){this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w; -return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this},divideScalar:function(a){this.x/=a;this.y/=a;this.z/=a;this.w/=a;return this},lerpSelf:function(a,c){this.x+=(a.x-this.x)*c;this.y+=(a.y-this.y)*c;this.z+=(a.z-this.z)*c;this.w+=(a.w-this.w)*c},clone:function(){return new THREE.Vector4(this.x,this.y,this.z,this.w)},toString:function(){return"THREE.Vector4 ("+this.x+", "+this.y+", "+this.z+", "+this.w+")"}}; -THREE.Ray=function(a,c){this.origin=a||new THREE.Vector3;this.direction=c||new THREE.Vector3}; -THREE.Ray.prototype={intersectScene:function(a){var c,d,e=a.objects,g=[];a=0;for(c=e.length;a0&&K>0&&j+K<1}var d,e,g,h,o,b,i,k,y,z, -u,x=a.geometry,H=x.vertices,J=[];d=0;for(e=x.faces.length;di?e:i;g=g>k? -g:k}a()};this.add3Points=function(i,k,y,z,u,x){if(b){b=false;c=iy?i>u?i:u:y>u?y:u;g=k>z?k>x?k:x:z>x?z:x}else{c=iy?i>u?i>e?i:e:u>e?u:e:y>u?y>e?y:e:u>e?u:e;g=k>z?k>x?k>g?k:g:x>g?x:g:z>x?z>g?z:g:x>g?x:g}a()};this.addRectangle=function(i){if(b){b=false;c=i.getLeft();d=i.getTop();e=i.getRight();g=i.getBottom()}else{c=ci.getRight()?e:i.getRight();g=g>i.getBottom()?g:i.getBottom()}a()};this.inflate=function(i){c-=i;d-=i;e+=i;g+=i;a()};this.minSelf=function(i){c=c>i.getLeft()?c:i.getLeft();d=d>i.getTop()?d:i.getTop();e=e=0&&Math.min(g,i.getBottom())-Math.max(d,i.getTop())>=0};this.empty=function(){b=true;g=e=d=c=0;a()};this.isEmpty=function(){return b};this.toString= -function(){return"THREE.Rectangle ( left: "+c+", right: "+e+", top: "+d+", bottom: "+g+", width: "+h+", height: "+o+" )"}};THREE.Matrix3=function(){this.m=[]};THREE.Matrix3.prototype={transpose:function(){var a,c=this.m;a=c[1];c[1]=c[3];c[3]=a;a=c[2];c[2]=c[6];c[6]=a;a=c[5];c[5]=c[7];c[7]=a;return this}}; -THREE.Matrix4=function(a,c,d,e,g,h,o,b,i,k,y,z,u,x,H,J){this.n11=a||1;this.n12=c||0;this.n13=d||0;this.n14=e||0;this.n21=g||0;this.n22=h||1;this.n23=o||0;this.n24=b||0;this.n31=i||0;this.n32=k||0;this.n33=y||1;this.n34=z||0;this.n41=u||0;this.n42=x||0;this.n43=H||0;this.n44=J||1;this.flat=Array(16);this.m33=new THREE.Matrix3}; -THREE.Matrix4.prototype={identity:function(){this.n11=1;this.n21=this.n14=this.n13=this.n12=0;this.n22=1;this.n32=this.n31=this.n24=this.n23=0;this.n33=1;this.n43=this.n42=this.n41=this.n34=0;this.n44=1;return this},set:function(a,c,d,e,g,h,o,b,i,k,y,z,u,x,H,J){this.n11=a;this.n12=c;this.n13=d;this.n14=e;this.n21=g;this.n22=h;this.n23=o;this.n24=b;this.n31=i;this.n32=k;this.n33=y;this.n34=z;this.n41=u;this.n42=x;this.n43=H;this.n44=J;return this},copy:function(a){this.n11=a.n11;this.n12=a.n12;this.n13= -a.n13;this.n14=a.n14;this.n21=a.n21;this.n22=a.n22;this.n23=a.n23;this.n24=a.n24;this.n31=a.n31;this.n32=a.n32;this.n33=a.n33;this.n34=a.n34;this.n41=a.n41;this.n42=a.n42;this.n43=a.n43;this.n44=a.n44;return this},lookAt:function(a,c,d){var e=THREE.Matrix4.__tmpVec1,g=THREE.Matrix4.__tmpVec2,h=THREE.Matrix4.__tmpVec3;h.sub(a,c).normalize();e.cross(d,h).normalize();g.cross(h,e).normalize();this.n11=e.x;this.n12=e.y;this.n13=e.z;this.n14=-e.dot(a);this.n21=g.x;this.n22=g.y;this.n23=g.z;this.n24=-g.dot(a); -this.n31=h.x;this.n32=h.y;this.n33=h.z;this.n34=-h.dot(a);this.n43=this.n42=this.n41=0;this.n44=1;return this},multiplyVector3:function(a){var c=a.x,d=a.y,e=a.z,g=1/(this.n41*c+this.n42*d+this.n43*e+this.n44);a.x=(this.n11*c+this.n12*d+this.n13*e+this.n14)*g;a.y=(this.n21*c+this.n22*d+this.n23*e+this.n24)*g;a.z=(this.n31*c+this.n32*d+this.n33*e+this.n34)*g;return a},multiplyVector4:function(a){var c=a.x,d=a.y,e=a.z,g=a.w;a.x=this.n11*c+this.n12*d+this.n13*e+this.n14*g;a.y=this.n21*c+this.n22*d+this.n23* -e+this.n24*g;a.z=this.n31*c+this.n32*d+this.n33*e+this.n34*g;a.w=this.n41*c+this.n42*d+this.n43*e+this.n44*g;return a},crossVector:function(a){var c=new THREE.Vector4;c.x=this.n11*a.x+this.n12*a.y+this.n13*a.z+this.n14*a.w;c.y=this.n21*a.x+this.n22*a.y+this.n23*a.z+this.n24*a.w;c.z=this.n31*a.x+this.n32*a.y+this.n33*a.z+this.n34*a.w;c.w=a.w?this.n41*a.x+this.n42*a.y+this.n43*a.z+this.n44*a.w:1;return c},multiply:function(a,c){var d=a.n11,e=a.n12,g=a.n13,h=a.n14,o=a.n21,b=a.n22,i=a.n23,k=a.n24,y=a.n31, -z=a.n32,u=a.n33,x=a.n34,H=a.n41,J=a.n42,K=a.n43,p=a.n44,U=c.n11,F=c.n12,f=c.n13,j=c.n14,q=c.n21,l=c.n22,r=c.n23,C=c.n24,m=c.n31,t=c.n32,v=c.n33,s=c.n34,n=c.n41,E=c.n42,A=c.n43,O=c.n44;this.n11=d*U+e*q+g*m+h*n;this.n12=d*F+e*l+g*t+h*E;this.n13=d*f+e*r+g*v+h*A;this.n14=d*j+e*C+g*s+h*O;this.n21=o*U+b*q+i*m+k*n;this.n22=o*F+b*l+i*t+k*E;this.n23=o*f+b*r+i*v+k*A;this.n24=o*j+b*C+i*s+k*O;this.n31=y*U+z*q+u*m+x*n;this.n32=y*F+z*l+u*t+x*E;this.n33=y*f+z*r+u*v+x*A;this.n34=y*j+z*C+u*s+x*O;this.n41=H*U+J*q+ -K*m+p*n;this.n42=H*F+J*l+K*t+p*E;this.n43=H*f+J*r+K*v+p*A;this.n44=H*j+J*C+K*s+p*O;return this},multiplySelf:function(a){var c=this.n11,d=this.n12,e=this.n13,g=this.n14,h=this.n21,o=this.n22,b=this.n23,i=this.n24,k=this.n31,y=this.n32,z=this.n33,u=this.n34,x=this.n41,H=this.n42,J=this.n43,K=this.n44,p=a.n11,U=a.n21,F=a.n31,f=a.n41,j=a.n12,q=a.n22,l=a.n32,r=a.n42,C=a.n13,m=a.n23,t=a.n33,v=a.n43,s=a.n14,n=a.n24,E=a.n34;a=a.n44;this.n11=c*p+d*U+e*F+g*f;this.n12=c*j+d*q+e*l+g*r;this.n13=c*C+d*m+e*t+g* -v;this.n14=c*s+d*n+e*E+g*a;this.n21=h*p+o*U+b*F+i*f;this.n22=h*j+o*q+b*l+i*r;this.n23=h*C+o*m+b*t+i*v;this.n24=h*s+o*n+b*E+i*a;this.n31=k*p+y*U+z*F+u*f;this.n32=k*j+y*q+z*l+u*r;this.n33=k*C+y*m+z*t+u*v;this.n34=k*s+y*n+z*E+u*a;this.n41=x*p+H*U+J*F+K*f;this.n42=x*j+H*q+J*l+K*r;this.n43=x*C+H*m+J*t+K*v;this.n44=x*s+H*n+J*E+K*a;return this},multiplyScalar:function(a){this.n11*=a;this.n12*=a;this.n13*=a;this.n14*=a;this.n21*=a;this.n22*=a;this.n23*=a;this.n24*=a;this.n31*=a;this.n32*=a;this.n33*=a;this.n34*= -a;this.n41*=a;this.n42*=a;this.n43*=a;this.n44*=a;return this},determinant:function(){var a=this.n11,c=this.n12,d=this.n13,e=this.n14,g=this.n21,h=this.n22,o=this.n23,b=this.n24,i=this.n31,k=this.n32,y=this.n33,z=this.n34,u=this.n41,x=this.n42,H=this.n43,J=this.n44;return e*o*k*u-d*b*k*u-e*h*y*u+c*b*y*u+d*h*z*u-c*o*z*u-e*o*i*x+d*b*i*x+e*g*y*x-a*b*y*x-d*g*z*x+a*o*z*x+e*h*i*H-c*b*i*H-e*g*k*H+a*b*k*H+c*g*z*H-a*h*z*H-d*h*i*J+c*o*i*J+d*g*k*J-a*o*k*J-c*g*y*J+a*h*y*J},transpose:function(){function a(c,d, -e){var g=c[d];c[d]=c[e];c[e]=g}a(this,"n21","n12");a(this,"n31","n13");a(this,"n32","n23");a(this,"n41","n14");a(this,"n42","n24");a(this,"n43","n34");return this},clone:function(){var a=new THREE.Matrix4;a.n11=this.n11;a.n12=this.n12;a.n13=this.n13;a.n14=this.n14;a.n21=this.n21;a.n22=this.n22;a.n23=this.n23;a.n24=this.n24;a.n31=this.n31;a.n32=this.n32;a.n33=this.n33;a.n34=this.n34;a.n41=this.n41;a.n42=this.n42;a.n43=this.n43;a.n44=this.n44;return a},flatten:function(){var a=this.flat;a[0]=this.n11; -a[1]=this.n21;a[2]=this.n31;a[3]=this.n41;a[4]=this.n12;a[5]=this.n22;a[6]=this.n32;a[7]=this.n42;a[8]=this.n13;a[9]=this.n23;a[10]=this.n33;a[11]=this.n43;a[12]=this.n14;a[13]=this.n24;a[14]=this.n34;a[15]=this.n44;return a},setTranslation:function(a,c,d){this.set(1,0,0,a,0,1,0,c,0,0,1,d,0,0,0,1);return this},setScale:function(a,c,d){this.set(a,0,0,0,0,c,0,0,0,0,d,0,0,0,0,1);return this},setRotX:function(a){var c=Math.cos(a);a=Math.sin(a);this.set(1,0,0,0,0,c,-a,0,0,a,c,0,0,0,0,1);return this},setRotY:function(a){var c= -Math.cos(a);a=Math.sin(a);this.set(c,0,a,0,0,1,0,0,-a,0,c,0,0,0,0,1);return this},setRotZ:function(a){var c=Math.cos(a);a=Math.sin(a);this.set(c,-a,0,0,a,c,0,0,0,0,1,0,0,0,0,1);return this},setRotAxis:function(a,c){var d=Math.cos(c),e=Math.sin(c),g=1-d,h=a.x,o=a.y,b=a.z,i=g*h,k=g*o;this.set(i*h+d,i*o-e*b,i*b+e*o,0,i*o+e*b,k*o+d,k*b-e*h,0,i*b-e*o,k*b+e*h,g*b*b+d,0,0,0,0,1);return this},toString:function(){return"| "+this.n11+" "+this.n12+" "+this.n13+" "+this.n14+" |\n| "+this.n21+" "+this.n22+" "+ -this.n23+" "+this.n24+" |\n| "+this.n31+" "+this.n32+" "+this.n33+" "+this.n34+" |\n| "+this.n41+" "+this.n42+" "+this.n43+" "+this.n44+" |"}};THREE.Matrix4.translationMatrix=function(a,c,d){var e=new THREE.Matrix4;e.setTranslation(a,c,d);return e};THREE.Matrix4.scaleMatrix=function(a,c,d){var e=new THREE.Matrix4;e.setScale(a,c,d);return e};THREE.Matrix4.rotationXMatrix=function(a){var c=new THREE.Matrix4;c.setRotX(a);return c}; -THREE.Matrix4.rotationYMatrix=function(a){var c=new THREE.Matrix4;c.setRotY(a);return c};THREE.Matrix4.rotationZMatrix=function(a){var c=new THREE.Matrix4;c.setRotZ(a);return c};THREE.Matrix4.rotationAxisAngleMatrix=function(a,c){var d=new THREE.Matrix4;d.setRotAxis(a,c);return d}; -THREE.Matrix4.makeInvert=function(a){var c=a.n11,d=a.n12,e=a.n13,g=a.n14,h=a.n21,o=a.n22,b=a.n23,i=a.n24,k=a.n31,y=a.n32,z=a.n33,u=a.n34,x=a.n41,H=a.n42,J=a.n43,K=a.n44,p=new THREE.Matrix4;p.n11=b*u*H-i*z*H+i*y*J-o*u*J-b*y*K+o*z*K;p.n12=g*z*H-e*u*H-g*y*J+d*u*J+e*y*K-d*z*K;p.n13=e*i*H-g*b*H+g*o*J-d*i*J-e*o*K+d*b*K;p.n14=g*b*y-e*i*y-g*o*z+d*i*z+e*o*u-d*b*u;p.n21=i*z*x-b*u*x-i*k*J+h*u*J+b*k*K-h*z*K;p.n22=e*u*x-g*z*x+g*k*J-c*u*J-e*k*K+c*z*K;p.n23=g*b*x-e*i*x-g*h*J+c*i*J+e*h*K-c*b*K;p.n24=e*i*k-g*b*k+ -g*h*z-c*i*z-e*h*u+c*b*u;p.n31=o*u*x-i*y*x+i*k*H-h*u*H-o*k*K+h*y*K;p.n32=g*y*x-d*u*x-g*k*H+c*u*H+d*k*K-c*y*K;p.n33=e*i*x-g*o*x+g*h*H-c*i*H-d*h*K+c*o*K;p.n34=g*o*k-d*i*k-g*h*y+c*i*y+d*h*u-c*o*u;p.n41=b*y*x-o*z*x-b*k*H+h*z*H+o*k*J-h*y*J;p.n42=d*z*x-e*y*x+e*k*H-c*z*H-d*k*J+c*y*J;p.n43=e*o*x-d*b*x-e*h*H+c*b*H+d*h*J-c*o*J;p.n44=d*b*k-e*o*k+e*h*y-c*b*y-d*h*z+c*o*z;p.multiplyScalar(1/a.determinant());return p}; -THREE.Matrix4.makeInvert3x3=function(a){var c=a.flatten();a=a.m33;var d=a.m,e=c[10]*c[5]-c[6]*c[9],g=-c[10]*c[1]+c[2]*c[9],h=c[6]*c[1]-c[2]*c[5],o=-c[10]*c[4]+c[6]*c[8],b=c[10]*c[0]-c[2]*c[8],i=-c[6]*c[0]+c[2]*c[4],k=c[9]*c[4]-c[5]*c[8],y=-c[9]*c[0]+c[1]*c[8],z=c[5]*c[0]-c[1]*c[4];c=c[0]*e+c[1]*o+c[2]*k;if(c==0)throw"matrix not invertible";c=1/c;d[0]=c*e;d[1]=c*g;d[2]=c*h;d[3]=c*o;d[4]=c*b;d[5]=c*i;d[6]=c*k;d[7]=c*y;d[8]=c*z;return a}; -THREE.Matrix4.makeFrustum=function(a,c,d,e,g,h){var o,b,i;o=new THREE.Matrix4;b=2*g/(c-a);i=2*g/(e-d);a=(c+a)/(c-a);d=(e+d)/(e-d);e=-(h+g)/(h-g);g=-2*h*g/(h-g);o.n11=b;o.n12=0;o.n13=a;o.n14=0;o.n21=0;o.n22=i;o.n23=d;o.n24=0;o.n31=0;o.n32=0;o.n33=e;o.n34=g;o.n41=0;o.n42=0;o.n43=-1;o.n44=0;return o};THREE.Matrix4.makePerspective=function(a,c,d,e){var g;a=d*Math.tan(a*Math.PI/360);g=-a;return THREE.Matrix4.makeFrustum(g*c,a*c,g,a,d,e)}; -THREE.Matrix4.makeOrtho=function(a,c,d,e,g,h){var o,b,i,k;o=new THREE.Matrix4;b=c-a;i=d-e;k=h-g;a=(c+a)/b;d=(d+e)/i;g=(h+g)/k;o.n11=2/b;o.n12=0;o.n13=0;o.n14=-a;o.n21=0;o.n22=2/i;o.n23=0;o.n24=-d;o.n31=0;o.n32=0;o.n33=-2/k;o.n34=-g;o.n41=0;o.n42=0;o.n43=0;o.n44=1;return o};THREE.Matrix4.__tmpVec1=new THREE.Vector3;THREE.Matrix4.__tmpVec2=new THREE.Vector3;THREE.Matrix4.__tmpVec3=new THREE.Vector3; -THREE.Vertex=function(a,c){this.position=a||new THREE.Vector3;this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.normal=c||new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.normalScreen=new THREE.Vector3;this.tangent=new THREE.Vector4;this.__visible=true};THREE.Vertex.prototype={toString:function(){return"THREE.Vertex ( position: "+this.position+", normal: "+this.normal+" )"}}; -THREE.Face3=function(a,c,d,e,g){this.a=a;this.b=c;this.c=d;this.centroid=new THREE.Vector3;this.normal=e instanceof THREE.Vector3?e:new THREE.Vector3;this.vertexNormals=e instanceof Array?e:[];this.materials=g instanceof Array?g:[g]};THREE.Face3.prototype={toString:function(){return"THREE.Face3 ( "+this.a+", "+this.b+", "+this.c+" )"}}; -THREE.Face4=function(a,c,d,e,g,h){this.a=a;this.b=c;this.c=d;this.d=e;this.centroid=new THREE.Vector3;this.normal=g instanceof THREE.Vector3?g:new THREE.Vector3;this.vertexNormals=g instanceof Array?g:[];this.materials=h instanceof Array?h:[h]};THREE.Face4.prototype={toString:function(){return"THREE.Face4 ( "+this.a+", "+this.b+", "+this.c+" "+this.d+" )"}};THREE.UV=function(a,c){this.u=a||0;this.v=c||0}; -THREE.UV.prototype={copy:function(a){this.u=a.u;this.v=a.v},toString:function(){return"THREE.UV ("+this.u+", "+this.v+")"}};THREE.Geometry=function(){this.vertices=[];this.faces=[];this.uvs=[];this.boundingSphere=this.boundingBox=null;this.geometryChunks={};this.hasTangents=false}; -THREE.Geometry.prototype={computeCentroids:function(){var a,c,d;a=0;for(c=this.faces.length;a0){this.boundingBox={x:[this.vertices[0].position.x,this.vertices[0].position.x],y:[this.vertices[0].position.y,this.vertices[0].position.y], -z:[this.vertices[0].position.z,this.vertices[0].position.z]};for(var c=1,d=this.vertices.length;cthis.boundingBox.x[1])this.boundingBox.x[1]=a.position.x;if(a.position.ythis.boundingBox.y[1])this.boundingBox.y[1]=a.position.y;if(a.position.z -this.boundingBox.z[1])this.boundingBox.z[1]=a.position.z}}},computeBoundingSphere:function(){for(var a=this.boundingSphere===null?0:this.boundingSphere.radius,c=0,d=this.vertices.length;c65535){k[b].counter+=1;i=k[b].hash+"_"+k[b].counter;if(this.geometryChunks[i]==undefined)this.geometryChunks[i]={faces:[],materials:o,vertices:0}}this.geometryChunks[i].faces.push(e);this.geometryChunks[i].vertices+=h}},toString:function(){return"THREE.Geometry ( vertices: "+ -this.vertices+", faces: "+this.faces+", uvs: "+this.uvs+" )"}}; -THREE.Camera=function(a,c,d,e){this.fov=a;this.aspect=c;this.near=d;this.far=e;this.position=new THREE.Vector3;this.target={position:new THREE.Vector3};this.autoUpdateMatrix=true;this.projectionMatrix=null;this.matrix=new THREE.Matrix4;this.up=new THREE.Vector3(0,1,0);this.tmpVec=new THREE.Vector3;this.translateX=function(g){this.tmpVec.sub(this.target.position,this.position).normalize().multiplyScalar(g);this.tmpVec.crossSelf(this.up);this.position.addSelf(this.tmpVec);this.target.position.addSelf(this.tmpVec)}; -this.translateZ=function(g){this.tmpVec.sub(this.target.position,this.position).normalize().multiplyScalar(g);this.position.subSelf(this.tmpVec);this.target.position.subSelf(this.tmpVec)};this.updateMatrix=function(){this.matrix.lookAt(this.position,this.target.position,this.up)};this.updateProjectionMatrix=function(){this.projectionMatrix=THREE.Matrix4.makePerspective(this.fov,this.aspect,this.near,this.far)};this.updateProjectionMatrix()}; -THREE.Camera.prototype={toString:function(){return"THREE.Camera ( "+this.position+", "+this.target.position+" )"}};THREE.Light=function(a){this.color=new THREE.Color(a)};THREE.AmbientLight=function(a){THREE.Light.call(this,a)};THREE.AmbientLight.prototype=new THREE.Light;THREE.AmbientLight.prototype.constructor=THREE.AmbientLight;THREE.DirectionalLight=function(a,c){THREE.Light.call(this,a);this.position=new THREE.Vector3(0,1,0);this.intensity=c||1};THREE.DirectionalLight.prototype=new THREE.Light; -THREE.DirectionalLight.prototype.constructor=THREE.DirectionalLight;THREE.PointLight=function(a,c){THREE.Light.call(this,a);this.position=new THREE.Vector3;this.intensity=c||1};THREE.PointLight.prototype=new THREE.Light;THREE.PointLight.prototype.constructor=THREE.PointLight; -THREE.Object3D=function(){this.id=THREE.Object3DCounter.value++;this.position=new THREE.Vector3;this.rotation=new THREE.Vector3;this.scale=new THREE.Vector3(1,1,1);this.matrix=new THREE.Matrix4;this.rotationMatrix=new THREE.Matrix4;this.tmpMatrix=new THREE.Matrix4;this.screen=new THREE.Vector3;this.visible=this.autoUpdateMatrix=true}; -THREE.Object3D.prototype={updateMatrix:function(){var a=this.position,c=this.rotation,d=this.scale,e=this.tmpMatrix;this.matrix.setTranslation(a.x,a.y,a.z);this.rotationMatrix.setRotX(c.x);if(c.y!=0){e.setRotY(c.y);this.rotationMatrix.multiplySelf(e)}if(c.z!=0){e.setRotZ(c.z);this.rotationMatrix.multiplySelf(e)}this.matrix.multiplySelf(this.rotationMatrix);if(d.x!=0||d.y!=0||d.z!=0){e.setScale(d.x,d.y,d.z);this.matrix.multiplySelf(e)}}};THREE.Object3DCounter={value:0}; -THREE.Particle=function(a){THREE.Object3D.call(this);this.materials=a instanceof Array?a:[a];this.autoUpdateMatrix=false};THREE.Particle.prototype=new THREE.Object3D;THREE.Particle.prototype.constructor=THREE.Particle;THREE.ParticleSystem=function(a,c){THREE.Object3D.call(this);this.geometry=a;this.materials=c instanceof Array?c:[c];this.autoUpdateMatrix=false};THREE.ParticleSystem.prototype=new THREE.Object3D;THREE.ParticleSystem.prototype.constructor=THREE.ParticleSystem; -THREE.Line=function(a,c,d){THREE.Object3D.call(this);this.geometry=a;this.materials=c instanceof Array?c:[c];this.type=d!=undefined?d:THREE.LineStrip};THREE.LineStrip=0;THREE.LinePieces=1;THREE.Line.prototype=new THREE.Object3D;THREE.Line.prototype.constructor=THREE.Line;THREE.Mesh=function(a,c){THREE.Object3D.call(this);this.geometry=a;this.materials=c instanceof Array?c:[c];this.overdraw=this.doubleSided=this.flipSided=false;this.geometry.boundingSphere||this.geometry.computeBoundingSphere()}; -THREE.Mesh.prototype=new THREE.Object3D;THREE.Mesh.prototype.constructor=THREE.Mesh;THREE.FlatShading=0;THREE.SmoothShading=1;THREE.NormalBlending=0;THREE.AdditiveBlending=1;THREE.SubtractiveBlending=2; -THREE.LineBasicMaterial=function(a){this.color=new THREE.Color(16777215);this.opacity=1;this.blending=THREE.NormalBlending;this.linewidth=1;this.linejoin=this.linecap="round";if(a){a.color!==undefined&&this.color.setHex(a.color);if(a.opacity!==undefined)this.opacity=a.opacity;if(a.blending!==undefined)this.blending=a.blending;if(a.linewidth!==undefined)this.linewidth=a.linewidth;if(a.linecap!==undefined)this.linecap=a.linecap;if(a.linejoin!==undefined)this.linejoin=a.linejoin}}; -THREE.LineBasicMaterial.prototype={toString:function(){return"THREE.LineBasicMaterial (
color: "+this.color+"
opacity: "+this.opacity+"
blending: "+this.blending+"
linewidth: "+this.linewidth+"
linecap: "+this.linecap+"
linejoin: "+this.linejoin+"
)"}}; -THREE.MeshBasicMaterial=function(a){this.id=THREE.MeshBasicMaterialCounter.value++;this.color=new THREE.Color(16777215);this.env_map=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refraction_ratio=0.98;this.fog=true;this.opacity=1;this.shading=THREE.SmoothShading;this.blending=THREE.NormalBlending;this.wireframe=false;this.wireframe_linewidth=1;this.wireframe_linejoin=this.wireframe_linecap="round";if(a){a.color!==undefined&&this.color.setHex(a.color);if(a.map!==undefined)this.map= -a.map;if(a.env_map!==undefined)this.env_map=a.env_map;if(a.combine!==undefined)this.combine=a.combine;if(a.reflectivity!==undefined)this.reflectivity=a.reflectivity;if(a.refraction_ratio!==undefined)this.refraction_ratio=a.refraction_ratio;if(a.fog!==undefined)this.fog=a.fog;if(a.opacity!==undefined)this.opacity=a.opacity;if(a.shading!==undefined)this.shading=a.shading;if(a.blending!==undefined)this.blending=a.blending;if(a.wireframe!==undefined)this.wireframe=a.wireframe;if(a.wireframe_linewidth!== -undefined)this.wireframe_linewidth=a.wireframe_linewidth;if(a.wireframe_linecap!==undefined)this.wireframe_linecap=a.wireframe_linecap;if(a.wireframe_linejoin!==undefined)this.wireframe_linejoin=a.wireframe_linejoin}}; -THREE.MeshBasicMaterial.prototype={toString:function(){return"THREE.MeshBasicMaterial (
id: "+this.id+"
color: "+this.color+"
map: "+this.map+"
env_map: "+this.env_map+"
combine: "+this.combine+"
reflectivity: "+this.reflectivity+"
refraction_ratio: "+this.refraction_ratio+"
opacity: "+this.opacity+"
blending: "+this.blending+"
wireframe: "+this.wireframe+"
wireframe_linewidth: "+this.wireframe_linewidth+"
wireframe_linecap: "+this.wireframe_linecap+ -"
wireframe_linejoin: "+this.wireframe_linejoin+"
)"}};THREE.MeshBasicMaterialCounter={value:0}; -THREE.MeshLambertMaterial=function(a){this.id=THREE.MeshLambertMaterialCounter.value++;this.color=new THREE.Color(16777215);this.env_map=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refraction_ratio=0.98;this.fog=true;this.opacity=1;this.shading=THREE.SmoothShading;this.blending=THREE.NormalBlending;this.wireframe=false;this.wireframe_linewidth=1;this.wireframe_linejoin=this.wireframe_linecap="round";if(a){a.color!==undefined&&this.color.setHex(a.color);if(a.map!==undefined)this.map= -a.map;if(a.env_map!==undefined)this.env_map=a.env_map;if(a.combine!==undefined)this.combine=a.combine;if(a.reflectivity!==undefined)this.reflectivity=a.reflectivity;if(a.refraction_ratio!==undefined)this.refraction_ratio=a.refraction_ratio;if(a.fog!==undefined)this.fog=a.fog;if(a.opacity!==undefined)this.opacity=a.opacity;if(a.shading!==undefined)this.shading=a.shading;if(a.blending!==undefined)this.blending=a.blending;if(a.wireframe!==undefined)this.wireframe=a.wireframe;if(a.wireframe_linewidth!== -undefined)this.wireframe_linewidth=a.wireframe_linewidth;if(a.wireframe_linecap!==undefined)this.wireframe_linecap=a.wireframe_linecap;if(a.wireframe_linejoin!==undefined)this.wireframe_linejoin=a.wireframe_linejoin}}; -THREE.MeshLambertMaterial.prototype={toString:function(){return"THREE.MeshLambertMaterial (
id: "+this.id+"
color: "+this.color+"
map: "+this.map+"
env_map: "+this.env_map+"
combine: "+this.combine+"
reflectivity: "+this.reflectivity+"
refraction_ratio: "+this.refraction_ratio+"
opacity: "+this.opacity+"
shading: "+this.shading+"
blending: "+this.blending+"
wireframe: "+this.wireframe+"
wireframe_linewidth: "+this.wireframe_linewidth+"
wireframe_linecap: "+ -this.wireframe_linecap+"
wireframe_linejoin: "+this.wireframe_linejoin+"
)"}};THREE.MeshLambertMaterialCounter={value:0}; -THREE.MeshPhongMaterial=function(a){this.id=THREE.MeshPhongMaterialCounter.value++;this.color=new THREE.Color(16777215);this.ambient=new THREE.Color(328965);this.specular=new THREE.Color(1118481);this.shininess=30;this.env_map=this.specular_map=this.map=null;this.combine=THREE.MultiplyOperation;this.reflectivity=1;this.refraction_ratio=0.98;this.fog=true;this.opacity=1;this.shading=THREE.SmoothShading;this.blending=THREE.NormalBlending;this.wireframe=false;this.wireframe_linewidth=1;this.wireframe_linejoin= -this.wireframe_linecap="round";if(a){if(a.color!==undefined)this.color=new THREE.Color(a.color);if(a.ambient!==undefined)this.ambient=new THREE.Color(a.ambient);if(a.specular!==undefined)this.specular=new THREE.Color(a.specular);if(a.shininess!==undefined)this.shininess=a.shininess;if(a.map!==undefined)this.map=a.map;if(a.specular_map!==undefined)this.specular_map=a.specular_map;if(a.env_map!==undefined)this.env_map=a.env_map;if(a.combine!==undefined)this.combine=a.combine;if(a.reflectivity!==undefined)this.reflectivity= -a.reflectivity;if(a.refraction_ratio!==undefined)this.refraction_ratio=a.refraction_ratio;if(a.fog!==undefined)this.fog=a.fog;if(a.opacity!==undefined)this.opacity=a.opacity;if(a.shading!==undefined)this.shading=a.shading;if(a.blending!==undefined)this.blending=a.blending;if(a.wireframe!==undefined)this.wireframe=a.wireframe;if(a.wireframe_linewidth!==undefined)this.wireframe_linewidth=a.wireframe_linewidth;if(a.wireframe_linecap!==undefined)this.wireframe_linecap=a.wireframe_linecap;if(a.wireframe_linejoin!== -undefined)this.wireframe_linejoin=a.wireframe_linejoin}}; -THREE.MeshPhongMaterial.prototype={toString:function(){return"THREE.MeshPhongMaterial (
id: "+this.id+"
color: "+this.color+"
ambient: "+this.ambient+"
specular: "+this.specular+"
shininess: "+this.shininess+"
map: "+this.map+"
specular_map: "+this.specular_map+"
env_map: "+this.env_map+"
combine: "+this.combine+"
reflectivity: "+this.reflectivity+"
refraction_ratio: "+this.refraction_ratio+"
opacity: "+this.opacity+"
shading: "+this.shading+"
wireframe: "+ -this.wireframe+"
wireframe_linewidth: "+this.wireframe_linewidth+"
wireframe_linecap: "+this.wireframe_linecap+"
wireframe_linejoin: "+this.wireframe_linejoin+"
)"}};THREE.MeshPhongMaterialCounter={value:0}; -THREE.MeshDepthMaterial=function(a){this.opacity=1;this.shading=THREE.SmoothShading;this.blending=THREE.NormalBlending;this.wireframe=false;this.wireframe_linewidth=1;this.wireframe_linejoin=this.wireframe_linecap="round";if(a){if(a.opacity!==undefined)this.opacity=a.opacity;if(a.blending!==undefined)this.blending=a.blending}};THREE.MeshDepthMaterial.prototype={toString:function(){return"THREE.MeshDepthMaterial"}}; -THREE.MeshNormalMaterial=function(a){this.opacity=1;this.shading=THREE.FlatShading;this.blending=THREE.NormalBlending;if(a){if(a.opacity!==undefined)this.opacity=a.opacity;if(a.shading!==undefined)this.shading=a.shading;if(a.blending!==undefined)this.blending=a.blending}};THREE.MeshNormalMaterial.prototype={toString:function(){return"THREE.MeshNormalMaterial"}};THREE.MeshFaceMaterial=function(){};THREE.MeshFaceMaterial.prototype={toString:function(){return"THREE.MeshFaceMaterial"}}; -THREE.MeshShaderMaterial=function(a){this.id=THREE.MeshShaderMaterialCounter.value++;this.vertex_shader=this.fragment_shader="void main() {}";this.uniforms={};this.opacity=1;this.shading=THREE.SmoothShading;this.blending=THREE.NormalBlending;this.wireframe=false;this.wireframe_linewidth=1;this.wireframe_linejoin=this.wireframe_linecap="round";if(a){if(a.fragment_shader!==undefined)this.fragment_shader=a.fragment_shader;if(a.vertex_shader!==undefined)this.vertex_shader=a.vertex_shader;if(a.uniforms!== -undefined)this.uniforms=a.uniforms;if(a.shading!==undefined)this.shading=a.shading;if(a.blending!==undefined)this.blending=a.blending;if(a.wireframe!==undefined)this.wireframe=a.wireframe;if(a.wireframe_linewidth!==undefined)this.wireframe_linewidth=a.wireframe_linewidth;if(a.wireframe_linecap!==undefined)this.wireframe_linecap=a.wireframe_linecap;if(a.wireframe_linejoin!==undefined)this.wireframe_linejoin=a.wireframe_linejoin}}; -THREE.MeshShaderMaterial.prototype={toString:function(){return"THREE.MeshShaderMaterial (
id: "+this.id+"
blending: "+this.blending+"
wireframe: "+this.wireframe+"
wireframe_linewidth: "+this.wireframe_linewidth+"
wireframe_linecap: "+this.wireframe_linecap+"
wireframe_linejoin: "+this.wireframe_linejoin+"
)"}};THREE.MeshShaderMaterialCounter={value:0}; -THREE.ParticleBasicMaterial=function(a){this.color=new THREE.Color(16777215);this.map=null;this.opacity=1;this.blending=THREE.NormalBlending;this.offset=new THREE.Vector2;if(a){a.color!==undefined&&this.color.setHex(a.color);if(a.map!==undefined)this.map=a.map;if(a.opacity!==undefined)this.opacity=a.opacity;if(a.blending!==undefined)this.blending=a.blending}}; -THREE.ParticleBasicMaterial.prototype={toString:function(){return"THREE.ParticleBasicMaterial (
color: "+this.color+"
map: "+this.map+"
opacity: "+this.opacity+"
blending: "+this.blending+"
)"}};THREE.ParticleCircleMaterial=function(a){this.color=new THREE.Color(16777215);this.opacity=1;this.blending=THREE.NormalBlending;if(a){a.color!==undefined&&this.color.setHex(a.color);if(a.opacity!==undefined)this.opacity=a.opacity;if(a.blending!==undefined)this.blending=a.blending}}; -THREE.ParticleCircleMaterial.prototype={toString:function(){return"THREE.ParticleCircleMaterial (
color: "+this.color+"
opacity: "+this.opacity+"
blending: "+this.blending+"
)"}};THREE.ParticleDOMMaterial=function(a){this.domElement=a};THREE.ParticleDOMMaterial.prototype={toString:function(){return"THREE.ParticleDOMMaterial ( domElement: "+this.domElement+" )"}}; -THREE.Texture=function(a,c,d,e,g,h){this.image=a;this.mapping=c!==undefined?c:new THREE.UVMapping;this.wrap_s=d!==undefined?d:THREE.ClampToEdgeWrapping;this.wrap_t=e!==undefined?e:THREE.ClampToEdgeWrapping;this.mag_filter=g!==undefined?g:THREE.LinearFilter;this.min_filter=h!==undefined?h:THREE.LinearMipMapLinearFilter}; -THREE.Texture.prototype={clone:function(){return new THREE.Texture(this.image,this.mapping,this.wrap_s,this.wrap_t,this.mag_filter,this.min_filter)},toString:function(){return"THREE.Texture (
image: "+this.image+"
wrap_s: "+this.wrap_s+"
wrap_t: "+this.wrap_t+"
mag_filter: "+this.mag_filter+"
min_filter: "+this.min_filter+"
)"}};THREE.MultiplyOperation=0;THREE.MixOperation=1;THREE.RepeatWrapping=0;THREE.ClampToEdgeWrapping=1;THREE.MirroredRepeatWrapping=2; -THREE.NearestFilter=3;THREE.NearestMipMapNearestFilter=4;THREE.NearestMipMapLinearFilter=5;THREE.LinearFilter=6;THREE.LinearMipMapNearestFilter=7;THREE.LinearMipMapLinearFilter=8;THREE.ByteType=9;THREE.UnsignedByteType=10;THREE.ShortType=11;THREE.UnsignedShortType=12;THREE.IntType=13;THREE.UnsignedIntType=14;THREE.FloatType=15;THREE.AlphaFormat=16;THREE.RGBFormat=17;THREE.RGBAFormat=18;THREE.LuminanceFormat=19;THREE.LuminanceAlphaFormat=20; -THREE.RenderTarget=function(a,c,d){this.width=a;this.height=c;d=d||{};this.wrap_s=d.wrap_s!==undefined?d.wrap_s:THREE.ClampToEdgeWrapping;this.wrap_t=d.wrap_t!==undefined?d.wrap_t:THREE.ClampToEdgeWrapping;this.mag_filter=d.mag_filter!==undefined?d.mag_filter:THREE.LinearFilter;this.min_filter=d.min_filter!==undefined?d.min_filter:THREE.LinearMipMapLinearFilter;this.format=d.format!==undefined?d.format:THREE.RGBFormat;this.type=d.type!==undefined?d.type:THREE.UnsignedByteType}; -var Uniforms={clone:function(a){var c,d,e,g={};for(c in a){g[c]={};for(d in a[c]){e=a[c][d];g[c][d]=e instanceof THREE.Color||e instanceof THREE.Vector3||e instanceof THREE.Texture?e.clone():e}}return g},merge:function(a){var c,d,e,g={};for(c=0;c=0&&v>=0&&s>=0&&n>=0)return true;else if(t<0&&v<0||s<0&&n<0)return false;else{if(t<0)C=Math.max(C,t/(t-v));else if(v<0)m=Math.min(m,t/(t-v));if(s<0)C=Math.max(C,s/(s-n));else if(n<0)m=Math.min(m,s/(s-n));if(mt&&A.z0&&K.z<1){u=H[x]=H[x]||new THREE.RenderableParticle;u.x=K.x/K.w;u.y=K.y/K.w;u.z=K.z;u.rotation=G.rotation.z;u.scale.x=G.scale.x*Math.abs(u.x-(K.x+r.projectionMatrix.n11)/(K.w+r.projectionMatrix.n14)); -u.scale.y=G.scale.y*Math.abs(u.y-(K.y+r.projectionMatrix.n22)/(K.w+r.projectionMatrix.n24));u.materials=G.materials;m.push(u);x++}}}}C&&m.sort(a);return m};this.unprojectVector=function(l,r){var C=THREE.Matrix4.makeInvert(r.matrix);C.multiplySelf(THREE.Matrix4.makeInvert(r.projectionMatrix));C.multiplyVector3(l);return l}}; -THREE.DOMRenderer=function(){THREE.Renderer.call(this);var a=null,c=new THREE.Projector,d,e,g,h;this.domElement=document.createElement("div");this.setSize=function(o,b){d=o;e=b;g=d/2;h=e/2};this.render=function(o,b){var i,k,y,z,u,x,H,J;a=c.projectScene(o,b);i=0;for(k=a.length;i0){D.r+=ca.r*$;D.g+=ca.g*$;D.b+=ca.b*$}}else if($ instanceof THREE.PointLight){Y.sub($.position,X);Y.normalize();$=T.dot(Y)*ga;if($>0){D.r+=ca.r*$;D.g+=ca.g*$;D.b+=ca.b*$}}}}function Na(B,X,T){if(T.opacity!=0){a(T.opacity);c(T.blending);var D, -R,$,ca,ga,ia;if(T instanceof THREE.ParticleBasicMaterial){if(T.map){ca=T.map;ga=ca.width>>1;ia=ca.height>>1;R=X.scale.x*b;$=X.scale.y*i;T=R*ga;D=$*ia;w.set(B.x-T,B.y-D,B.x+T,B.y+D);if(V.instersects(w)){k.save();k.translate(B.x,B.y);k.rotate(-X.rotation);k.scale(R,-$);k.translate(-ga,-ia);k.drawImage(ca,0,0);k.restore()}}}else if(T instanceof THREE.ParticleCircleMaterial){if(M){Q.r=da.r+ba.r+Z.r;Q.g=da.g+ba.g+Z.g;Q.b=da.b+ba.b+Z.b;m.r=T.color.r*Q.r;m.g=T.color.g*Q.g;m.b=T.color.b*Q.b;m.updateStyleString()}else m.__styleString= -T.color.__styleString;T=X.scale.x*b;D=X.scale.y*i;w.set(B.x-T,B.y-D,B.x+T,B.y+D);if(V.instersects(w)){R=m.__styleString;if(J!=R)k.fillStyle=J=R;k.save();k.translate(B.x,B.y);k.rotate(-X.rotation);k.scale(T,D);k.beginPath();k.arc(0,0,1,0,ja,true);k.closePath();k.fill();k.restore()}}}}function Oa(B,X,T,D){if(D.opacity!=0){a(D.opacity);c(D.blending);k.beginPath();k.moveTo(B.positionScreen.x,B.positionScreen.y);k.lineTo(X.positionScreen.x,X.positionScreen.y);k.closePath();if(D instanceof THREE.LineBasicMaterial){m.__styleString= -D.color.__styleString;B=D.linewidth;if(K!=B)k.lineWidth=K=B;B=m.__styleString;if(H!=B)k.strokeStyle=H=B;k.stroke();w.inflate(D.linewidth*2)}}}function Ia(B,X,T,D,R,$){if(R.opacity!=0){a(R.opacity);c(R.blending);f=B.positionScreen.x;j=B.positionScreen.y;q=X.positionScreen.x;l=X.positionScreen.y;r=T.positionScreen.x;C=T.positionScreen.y;k.beginPath();k.moveTo(f,j);k.lineTo(q,l);k.lineTo(r,C);k.lineTo(f,j);k.closePath();if(R instanceof THREE.MeshBasicMaterial)if(R.map)R.map.image.loaded&&R.map.mapping instanceof -THREE.UVMapping&&xa(f,j,q,l,r,C,R.map.image,D.uvs[0].u,D.uvs[0].v,D.uvs[1].u,D.uvs[1].v,D.uvs[2].u,D.uvs[2].v);else if(R.env_map){if(R.env_map.image.loaded)if(R.env_map.mapping instanceof THREE.SphericalReflectionMapping){B=ra.matrix;Y.copy(D.vertexNormalsWorld[0]);N=(Y.x*B.n11+Y.y*B.n12+Y.z*B.n13)*0.5+0.5;G=-(Y.x*B.n21+Y.y*B.n22+Y.z*B.n23)*0.5+0.5;Y.copy(D.vertexNormalsWorld[1]);W=(Y.x*B.n11+Y.y*B.n12+Y.z*B.n13)*0.5+0.5;P=-(Y.x*B.n21+Y.y*B.n22+Y.z*B.n23)*0.5+0.5;Y.copy(D.vertexNormalsWorld[2]);I= -(Y.x*B.n11+Y.y*B.n12+Y.z*B.n13)*0.5+0.5;L=-(Y.x*B.n21+Y.y*B.n22+Y.z*B.n23)*0.5+0.5;xa(f,j,q,l,r,C,R.env_map.image,N,G,W,P,I,L)}}else R.wireframe?Ba(R.color.__styleString,R.wireframe_linewidth):Ca(R.color.__styleString);else if(R instanceof THREE.MeshLambertMaterial){if(R.map&&!R.wireframe){R.map.mapping instanceof THREE.UVMapping&&xa(f,j,q,l,r,C,R.map.image,D.uvs[0].u,D.uvs[0].v,D.uvs[1].u,D.uvs[1].v,D.uvs[2].u,D.uvs[2].v);c(THREE.SubtractiveBlending)}if(M)if(!R.wireframe&&R.shading==THREE.SmoothShading&& -D.vertexNormalsWorld.length==3){t.r=v.r=s.r=da.r;t.g=v.g=s.g=da.g;t.b=v.b=s.b=da.b;Aa($,D.v1.positionWorld,D.vertexNormalsWorld[0],t);Aa($,D.v2.positionWorld,D.vertexNormalsWorld[1],v);Aa($,D.v3.positionWorld,D.vertexNormalsWorld[2],s);n.r=(v.r+s.r)*0.5;n.g=(v.g+s.g)*0.5;n.b=(v.b+s.b)*0.5;O=Ja(t,v,s,n);xa(f,j,q,l,r,C,O,0,0,1,0,0,1)}else{Q.r=da.r;Q.g=da.g;Q.b=da.b;Aa($,D.centroidWorld,D.normalWorld,Q);m.r=R.color.r*Q.r;m.g=R.color.g*Q.g;m.b=R.color.b*Q.b;m.updateStyleString();R.wireframe?Ba(m.__styleString, -R.wireframe_linewidth):Ca(m.__styleString)}else R.wireframe?Ba(R.color.__styleString,R.wireframe_linewidth):Ca(R.color.__styleString)}else if(R instanceof THREE.MeshDepthMaterial){E=ra.near;A=ra.far;t.r=t.g=t.b=1-Ea(B.positionScreen.z,E,A);v.r=v.g=v.b=1-Ea(X.positionScreen.z,E,A);s.r=s.g=s.b=1-Ea(T.positionScreen.z,E,A);n.r=(v.r+s.r)*0.5;n.g=(v.g+s.g)*0.5;n.b=(v.b+s.b)*0.5;O=Ja(t,v,s,n);xa(f,j,q,l,r,C,O,0,0,1,0,0,1)}else if(R instanceof THREE.MeshNormalMaterial){m.r=Fa(D.normalWorld.x);m.g=Fa(D.normalWorld.y); -m.b=Fa(D.normalWorld.z);m.updateStyleString();R.wireframe?Ba(m.__styleString,R.wireframe_linewidth):Ca(m.__styleString)}}}function Ba(B,X){if(H!=B)k.strokeStyle=H=B;if(K!=X)k.lineWidth=K=X;k.stroke();w.inflate(X*2)}function Ca(B){if(J!=B)k.fillStyle=J=B;k.fill()}function xa(B,X,T,D,R,$,ca,ga,ia,na,la,oa,ya){var ta,pa;ta=ca.width-1;pa=ca.height-1;ga*=ta;ia*=pa;na*=ta;la*=pa;oa*=ta;ya*=pa;T-=B;D-=X;R-=B;$-=X;na-=ga;la-=ia;oa-=ga;ya-=ia;pa=1/(na*ya-oa*la);ta=(ya*T-la*R)*pa;la=(ya*D-la*$)*pa;T=(na*R- -oa*T)*pa;D=(na*$-oa*D)*pa;B=B-ta*ga-T*ia;X=X-la*ga-D*ia;k.save();k.transform(ta,la,T,D,B,X);k.clip();k.drawImage(ca,0,0);k.restore()}function Ja(B,X,T,D){var R=~~(B.r*255),$=~~(B.g*255);B=~~(B.b*255);var ca=~~(X.r*255),ga=~~(X.g*255);X=~~(X.b*255);var ia=~~(T.r*255),na=~~(T.g*255);T=~~(T.b*255);var la=~~(D.r*255),oa=~~(D.g*255);D=~~(D.b*255);ha[0]=R<0?0:R>255?255:R;ha[1]=$<0?0:$>255?255:$;ha[2]=B<0?0:B>255?255:B;ha[4]=ca<0?0:ca>255?255:ca;ha[5]=ga<0?0:ga>255?255:ga;ha[6]=X<0?0:X>255?255:X;ha[8]=ia< -0?0:ia>255?255:ia;ha[9]=na<0?0:na>255?255:na;ha[10]=T<0?0:T>255?255:T;ha[12]=la<0?0:la>255?255:la;ha[13]=oa<0?0:oa>255?255:oa;ha[14]=D<0?0:D>255?255:D;ka.putImageData(fa,0,0);ua.drawImage(qa,0,0);return sa}function Ea(B,X,T){B=(B-X)/(T-X);return B*B*(3-2*B)}function Fa(B){B=(B+1)*0.5;return B<0?0:B>1?1:B}function Ga(B,X){var T=X.x-B.x,D=X.y-B.y,R=1/Math.sqrt(T*T+D*D);T*=R;D*=R;X.x+=T;X.y+=D;B.x-=T;B.y-=D}var Da,Ka,aa,ma,wa,Ha,La,za;k.setTransform(1,0,0,-1,b,i);this.autoClear&&this.clear();d=e.projectScene(ea, -ra,this.sortElements);(M=ea.lights.length>0)&&Ma(ea);Da=0;for(Ka=d.length;Da0){W.r+=L.color.r*V;W.g+=L.color.g*V;W.b+=L.color.b*V}}else if(L instanceof THREE.PointLight){C.sub(L.position,G.centroidWorld);C.normalize();V=G.normalWorld.dot(C)*L.intensity;if(V>0){W.r+=L.color.r*V;W.g+=L.color.g*V;W.b+=L.color.b*V}}}}function c(N,G,W,P,I,L){s=e(n++);s.setAttribute("d","M "+N.positionScreen.x+ -" "+N.positionScreen.y+" L "+G.positionScreen.x+" "+G.positionScreen.y+" L "+W.positionScreen.x+","+W.positionScreen.y+"z");if(I instanceof THREE.MeshBasicMaterial)F.__styleString=I.color.__styleString;else if(I instanceof THREE.MeshLambertMaterial)if(U){f.r=j.r;f.g=j.g;f.b=j.b;a(L,P,f);F.r=I.color.r*f.r;F.g=I.color.g*f.g;F.b=I.color.b*f.b;F.updateStyleString()}else F.__styleString=I.color.__styleString;else if(I instanceof THREE.MeshDepthMaterial){r=1-I.__2near/(I.__farPlusNear-P.z*I.__farMinusNear); -F.setRGB(r,r,r)}else I instanceof THREE.MeshNormalMaterial&&F.setRGB(g(P.normalWorld.x),g(P.normalWorld.y),g(P.normalWorld.z));I.wireframe?s.setAttribute("style","fill: none; stroke: "+F.__styleString+"; stroke-width: "+I.wireframe_linewidth+"; stroke-opacity: "+I.opacity+"; stroke-linecap: "+I.wireframe_linecap+"; stroke-linejoin: "+I.wireframe_linejoin):s.setAttribute("style","fill: "+F.__styleString+"; fill-opacity: "+I.opacity);b.appendChild(s)}function d(N,G,W,P,I,L,V){s=e(n++);s.setAttribute("d", -"M "+N.positionScreen.x+" "+N.positionScreen.y+" L "+G.positionScreen.x+" "+G.positionScreen.y+" L "+W.positionScreen.x+","+W.positionScreen.y+" L "+P.positionScreen.x+","+P.positionScreen.y+"z");if(L instanceof THREE.MeshBasicMaterial)F.__styleString=L.color.__styleString;else if(L instanceof THREE.MeshLambertMaterial)if(U){f.r=j.r;f.g=j.g;f.b=j.b;a(V,I,f);F.r=L.color.r*f.r;F.g=L.color.g*f.g;F.b=L.color.b*f.b;F.updateStyleString()}else F.__styleString=L.color.__styleString;else if(L instanceof THREE.MeshDepthMaterial){r= -1-L.__2near/(L.__farPlusNear-I.z*L.__farMinusNear);F.setRGB(r,r,r)}else L instanceof THREE.MeshNormalMaterial&&F.setRGB(g(I.normalWorld.x),g(I.normalWorld.y),g(I.normalWorld.z));L.wireframe?s.setAttribute("style","fill: none; stroke: "+F.__styleString+"; stroke-width: "+L.wireframe_linewidth+"; stroke-opacity: "+L.opacity+"; stroke-linecap: "+L.wireframe_linecap+"; stroke-linejoin: "+L.wireframe_linejoin):s.setAttribute("style","fill: "+F.__styleString+"; fill-opacity: "+L.opacity);b.appendChild(s)} -function e(N){if(m[N]==null){m[N]=document.createElementNS("http://www.w3.org/2000/svg","path");O==0&&m[N].setAttribute("shape-rendering","crispEdges");return m[N]}return m[N]}function g(N){return N<0?Math.min((1+N)*0.5,0.5):0.5+Math.min(N*0.5,0.5)}var h=null,o=new THREE.Projector,b=document.createElementNS("http://www.w3.org/2000/svg","svg"),i,k,y,z,u,x,H,J,K=new THREE.Rectangle,p=new THREE.Rectangle,U=false,F=new THREE.Color(16777215),f=new THREE.Color(16777215),j=new THREE.Color(0),q=new THREE.Color(0), -l=new THREE.Color(0),r,C=new THREE.Vector3,m=[],t=[],v=[],s,n,E,A,O=1;this.domElement=b;this.sortElements=this.sortObjects=this.autoClear=true;this.setQuality=function(N){switch(N){case "high":O=1;break;case "low":O=0}};this.setSize=function(N,G){i=N;k=G;y=i/2;z=k/2;b.setAttribute("viewBox",-y+" "+-z+" "+i+" "+k);b.setAttribute("width",i);b.setAttribute("height",k);K.set(-y,-z,y,z)};this.clear=function(){for(;b.childNodes.length>0;)b.removeChild(b.childNodes[0])};this.render=function(N,G){var W,P, -I,L,V,S,w,M;this.autoClear&&this.clear();h=o.projectScene(N,G,this.sortElements);A=E=n=0;if(U=N.lights.length>0){w=N.lights;j.setRGB(0,0,0);q.setRGB(0,0,0);l.setRGB(0,0,0);W=0;for(P=w.length;W0){b.bindBuffer(b.ARRAY_BUFFER,f.__webGLUVBuffer);b.bufferData(b.ARRAY_BUFFER,da,q)}if(r){b.bindBuffer(b.ELEMENT_ARRAY_BUFFER, -f.__webGLFaceBuffer);b.bufferData(b.ELEMENT_ARRAY_BUFFER,ja,q);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,f.__webGLLineBuffer);b.bufferData(b.ELEMENT_ARRAY_BUFFER,Y,q)}};this.setLineBuffers=function(f,j,q,l){var r,C,m=f.vertices,t=m.length,v=f.__vertexArray,s=f.__lineArray;if(q)for(q=0;q0?"#define VERTEX_TEXTURES":"","#define MAX_DIR_LIGHTS "+s.maxDirLights,"#define MAX_POINT_LIGHTS "+s.maxPointLights, -s.map?"#define USE_MAP":"",s.env_map?"#define USE_ENVMAP":"","uniform mat4 objectMatrix;\nuniform mat4 modelViewMatrix;\nuniform mat4 projectionMatrix;\nuniform mat4 viewMatrix;\nuniform mat3 normalMatrix;\nuniform vec3 cameraPosition;\nattribute vec3 position;\nattribute vec3 normal;\nattribute vec2 uv;\n"].join("\n");b.attachShader(E,g("fragment",A+t));b.attachShader(E,g("vertex",s+n));b.linkProgram(E);b.getProgramParameter(E,b.LINK_STATUS)||alert("Could not initialise shaders\nVALIDATE_STATUS: "+ -b.getProgramParameter(E,b.VALIDATE_STATUS)+", gl error ["+b.getError()+"]");E.uniforms={};E.attributes={};l.program=E;t=["viewMatrix","modelViewMatrix","projectionMatrix","normalMatrix","objectMatrix","cameraPosition"];for(m in l.uniforms)t.push(m);m=l.program;n=0;for(E=t.length;n=0){b.bindBuffer(b.ARRAY_BUFFER,r.__webGLNormalBuffer);b.vertexAttribPointer(v.normal,3,b.FLOAT,false,0,0);b.enableVertexAttribArray(v.normal)}if(v.tangent>=0){b.bindBuffer(b.ARRAY_BUFFER,r.__webGLTangentBuffer); -b.vertexAttribPointer(v.tangent,4,b.FLOAT,false,0,0);b.enableVertexAttribArray(v.tangent)}if(v.uv>=0)if(r.__webGLUVBuffer){b.bindBuffer(b.ARRAY_BUFFER,r.__webGLUVBuffer);b.vertexAttribPointer(v.uv,2,b.FLOAT,false,0,0);b.enableVertexAttribArray(v.uv)}else b.disableVertexAttribArray(v.uv);if(l.wireframe||l instanceof THREE.LineBasicMaterial){v=l.wireframe_linewidth!==undefined?l.wireframe_linewidth:l.linewidth!==undefined?l.linewidth:1;l=l instanceof THREE.LineBasicMaterial&&C.type==THREE.LineStrip? -b.LINE_STRIP:b.LINES;b.lineWidth(v);b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,r.__webGLLineBuffer);b.drawElements(l,r.__webGLLineCount,b.UNSIGNED_SHORT,0)}else{b.bindBuffer(b.ELEMENT_ARRAY_BUFFER,r.__webGLFaceBuffer);b.drawElements(b.TRIANGLES,r.__webGLFaceCount,b.UNSIGNED_SHORT,0)}};this.renderPass=function(f,j,q,l,r,C,m){var t,v,s,n,E;s=0;for(n=l.materials.length;s=0;q--){l=f.__webGLObjects[q].object;j==l&&f.__webGLObjects.splice(q,1)}};this.setupMatrices=function(f,j){f.autoUpdateMatrix&& -f.updateMatrix();y.multiply(j.matrix,f.matrix);x.set(y.flatten());z=THREE.Matrix4.makeInvert3x3(y).transpose();J.set(z.m);K.set(f.matrix.flatten())};this.loadMatrices=function(f){b.uniformMatrix4fv(f.uniforms.viewMatrix,false,u);b.uniformMatrix4fv(f.uniforms.modelViewMatrix,false,x);b.uniformMatrix4fv(f.uniforms.projectionMatrix,false,H);b.uniformMatrix3fv(f.uniforms.normalMatrix,false,J);b.uniformMatrix4fv(f.uniforms.objectMatrix,false,K)};this.loadCamera=function(f,j){b.uniform3f(f.uniforms.cameraPosition, -j.position.x,j.position.y,j.position.z)};this.setBlending=function(f){switch(f){case THREE.AdditiveBlending:b.blendEquation(b.FUNC_ADD);b.blendFunc(b.ONE,b.ONE);break;case THREE.SubtractiveBlending:b.blendFunc(b.DST_COLOR,b.ZERO);break;default:b.blendEquation(b.FUNC_ADD);b.blendFunc(b.ONE,b.ONE_MINUS_SRC_ALPHA)}};this.setFaceCulling=function(f,j){if(f){!j||j=="ccw"?b.frontFace(b.CCW):b.frontFace(b.CW);if(f=="back")b.cullFace(b.BACK);else f=="front"?b.cullFace(b.FRONT):b.cullFace(b.FRONT_AND_BACK); -b.enable(b.CULL_FACE)}else b.disable(b.CULL_FACE)};this.supportsVertexTextures=function(){return b.getParameter(b.MAX_VERTEX_TEXTURE_IMAGE_UNITS)>0}}; -THREE.Snippets={fog_pars_fragment:"#ifdef USE_FOG\nuniform vec3 fogColor;\n#ifdef FOG_EXP2\nuniform float fogDensity;\n#else\nuniform float fogNear;\nuniform float fogFar;\n#endif\n#endif",fog_fragment:"#ifdef USE_FOG\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\n#ifdef FOG_EXP2\nconst float LOG2 = 1.442695;\nfloat fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );\nfogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );\n#else\nfloat fogFactor = smoothstep( fogNear, fogFar, depth );\n#endif\ngl_FragColor = mix( gl_FragColor, vec4( fogColor, 1.0 ), fogFactor );\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\nvarying vec3 vReflect;\nuniform float reflectivity;\nuniform samplerCube env_map;\nuniform int combine;\n#endif", -envmap_fragment:"#ifdef USE_ENVMAP\ncubeColor = textureCube( env_map, vec3( -vReflect.x, vReflect.yz ) );\nif ( combine == 1 ) {\ngl_FragColor = mix( gl_FragColor, cubeColor, reflectivity );\n} else {\ngl_FragColor = gl_FragColor * cubeColor;\n}\n#endif",envmap_pars_vertex:"#ifdef USE_ENVMAP\nvarying vec3 vReflect;\nuniform float refraction_ratio;\nuniform bool useRefract;\n#endif",envmap_vertex:"#ifdef USE_ENVMAP\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\nvec3 nWorld = mat3( objectMatrix[0].xyz, objectMatrix[1].xyz, objectMatrix[2].xyz ) * normal;\nif ( useRefract ) {\nvReflect = refract( normalize( mPosition.xyz - cameraPosition ), normalize( nWorld.xyz ), refraction_ratio );\n} else {\nvReflect = reflect( normalize( mPosition.xyz - cameraPosition ), normalize( nWorld.xyz ) );\n}\n#endif", -map_pars_fragment:"#ifdef USE_MAP\nvarying vec2 vUv;\nuniform sampler2D map;\n#endif",map_pars_vertex:"#ifdef USE_MAP\nvarying vec2 vUv;\n#endif",map_fragment:"#ifdef USE_MAP\nmapColor = texture2D( map, vUv );\n#endif",map_vertex:"#ifdef USE_MAP\nvUv = uv;\n#endif",lights_pars_vertex:"uniform bool enableLighting;\nuniform vec3 ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nuniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];\nuniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];\n#ifdef PHONG\nvarying vec3 vPointLightVector[ MAX_POINT_LIGHTS ];\n#endif\n#endif", -lights_vertex:"if ( !enableLighting ) {\nvLightWeighting = vec3( 1.0 );\n} else {\nvLightWeighting = ambientLightColor;\n#if MAX_DIR_LIGHTS > 0\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nfloat directionalLightWeighting = max( dot( transformedNormal, normalize( lDirection.xyz ) ), 0.0 );\nvLightWeighting += directionalLightColor[ i ] * directionalLightWeighting;\n}\n#endif\n#if MAX_POINT_LIGHTS > 0\nfor( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {\nvec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );\nvec3 pointLightVector = normalize( lPosition.xyz - mvPosition.xyz );\nfloat pointLightWeighting = max( dot( transformedNormal, pointLightVector ), 0.0 );\nvLightWeighting += pointLightColor[ i ] * pointLightWeighting;\n#ifdef PHONG\nvPointLightVector[ i ] = pointLightVector;\n#endif\n}\n#endif\n}", -lights_pars_fragment:"#if MAX_DIR_LIGHTS > 0\nuniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];\n#endif\n#if MAX_POINT_LIGHTS > 0\nvarying vec3 vPointLightVector[ MAX_POINT_LIGHTS ];\n#endif\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;",lights_fragment:"vec3 normal = normalize( vNormal );\nvec3 viewPosition = normalize( vViewPosition );\nvec4 mSpecular = vec4( specular, opacity );\n#if MAX_POINT_LIGHTS > 0\nvec4 pointDiffuse = vec4( 0.0 );\nvec4 pointSpecular = vec4( 0.0 );\nfor( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {\nvec3 pointVector = normalize( vPointLightVector[ i ] );\nvec3 pointHalfVector = normalize( vPointLightVector[ i ] + vViewPosition );\nfloat pointDotNormalHalf = dot( normal, pointHalfVector );\nfloat pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );\nfloat pointSpecularWeight = 0.0;\nif ( pointDotNormalHalf >= 0.0 )\npointSpecularWeight = pow( pointDotNormalHalf, shininess );\npointDiffuse += mColor * pointDiffuseWeight;\npointSpecular += mSpecular * pointSpecularWeight;\n}\n#endif\n#if MAX_DIR_LIGHTS > 0\nvec4 dirDiffuse = vec4( 0.0 );\nvec4 dirSpecular = vec4( 0.0 );\nfor( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {\nvec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );\nvec3 dirVector = normalize( lDirection.xyz );\nvec3 dirHalfVector = normalize( lDirection.xyz + vViewPosition );\nfloat dirDotNormalHalf = dot( normal, dirHalfVector );\nfloat dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );\nfloat dirSpecularWeight = 0.0;\nif ( dirDotNormalHalf >= 0.0 )\ndirSpecularWeight = pow( dirDotNormalHalf, shininess );\ndirDiffuse += mColor * dirDiffuseWeight;\ndirSpecular += mSpecular * dirSpecularWeight;\n}\n#endif\nvec4 totalLight = vec4( ambient, opacity );\n#if MAX_DIR_LIGHTS > 0\ntotalLight += dirDiffuse + dirSpecular;\n#endif\n#if MAX_POINT_LIGHTS > 0\ntotalLight += pointDiffuse + pointSpecular;\n#endif"}; -THREE.UniformsLib={common:{color:{type:"c",value:new THREE.Color(15658734)},opacity:{type:"f",value:1},map:{type:"t",value:0,texture:null},env_map:{type:"t",value:1,texture:null},useRefract:{type:"i",value:0},reflectivity:{type:"f",value:1},refraction_ratio:{type:"f",value:0.98},combine:{type:"i",value:0},fogDensity:{type:"f",value:2.5E-4},fogNear:{type:"f",value:1},fogFar:{type:"f",value:2E3},fogColor:{type:"c",value:new THREE.Color(16777215)}},lights:{enableLighting:{type:"i",value:1},ambientLightColor:{type:"fv", -value:[]},directionalLightDirection:{type:"fv",value:[]},directionalLightColor:{type:"fv",value:[]},pointLightPosition:{type:"fv",value:[]},pointLightColor:{type:"fv",value:[]}}}; -THREE.ShaderLib={depth:{uniforms:{mNear:{type:"f",value:1},mFar:{type:"f",value:2E3}},fragment_shader:"uniform float mNear;\nuniform float mFar;\nvoid main() {\nfloat depth = gl_FragCoord.z / gl_FragCoord.w;\nfloat color = 1.0 - smoothstep( mNear, mFar, depth );\ngl_FragColor = vec4( vec3( color ), 1.0 );\n}",vertex_shader:"void main() {\ngl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"},normal:{uniforms:{},fragment_shader:"varying vec3 vNormal;\nvoid main() {\ngl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, 1.0 );\n}", -vertex_shader:"varying vec3 vNormal;\nvoid main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\nvNormal = normalize( normalMatrix * normal );\ngl_Position = projectionMatrix * mvPosition;\n}"},basic:{uniforms:THREE.UniformsLib.common,fragment_shader:["uniform vec3 color;\nuniform float opacity;",THREE.Snippets.map_pars_fragment,THREE.Snippets.envmap_pars_fragment,THREE.Snippets.fog_pars_fragment,"void main() {\nvec4 mColor = vec4( color, opacity );\nvec4 mapColor = vec4( 1.0 );\nvec4 cubeColor = vec4( 1.0 );", -THREE.Snippets.map_fragment,"gl_FragColor = mColor * mapColor;",THREE.Snippets.envmap_fragment,THREE.Snippets.fog_fragment,"}"].join("\n"),vertex_shader:[THREE.Snippets.map_pars_vertex,THREE.Snippets.envmap_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",THREE.Snippets.map_vertex,THREE.Snippets.envmap_vertex,"gl_Position = projectionMatrix * mvPosition;\n}"].join("\n")},lambert:{uniforms:Uniforms.merge([THREE.UniformsLib.common,THREE.UniformsLib.lights]),fragment_shader:["uniform vec3 color;\nuniform float opacity;\nvarying vec3 vLightWeighting;", -THREE.Snippets.map_pars_fragment,THREE.Snippets.envmap_pars_fragment,THREE.Snippets.fog_pars_fragment,"void main() {\nvec4 mColor = vec4( color, opacity );\nvec4 mapColor = vec4( 1.0 );\nvec4 cubeColor = vec4( 1.0 );",THREE.Snippets.map_fragment,"gl_FragColor = mColor * mapColor * vec4( vLightWeighting, 1.0 );",THREE.Snippets.envmap_fragment,THREE.Snippets.fog_fragment,"}"].join("\n"),vertex_shader:["varying vec3 vLightWeighting;",THREE.Snippets.map_pars_vertex,THREE.Snippets.envmap_pars_vertex, -THREE.Snippets.lights_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",THREE.Snippets.map_vertex,THREE.Snippets.envmap_vertex,"vec3 transformedNormal = normalize( normalMatrix * normal );",THREE.Snippets.lights_vertex,"gl_Position = projectionMatrix * mvPosition;\n}"].join("\n")},phong:{uniforms:Uniforms.merge([THREE.UniformsLib.common,THREE.UniformsLib.lights,{ambient:{type:"c",value:new THREE.Color(328965)},specular:{type:"c",value:new THREE.Color(1118481)}, -shininess:{type:"f",value:30}}]),fragment_shader:["uniform vec3 color;\nuniform float opacity;\nuniform vec3 ambient;\nuniform vec3 specular;\nuniform float shininess;\nvarying vec3 vLightWeighting;",THREE.Snippets.map_pars_fragment,THREE.Snippets.envmap_pars_fragment,THREE.Snippets.fog_pars_fragment,THREE.Snippets.lights_pars_fragment,"void main() {\nvec4 mColor = vec4( color, opacity );\nvec4 mapColor = vec4( 1.0 );\nvec4 cubeColor = vec4( 1.0 );",THREE.Snippets.map_fragment,THREE.Snippets.lights_fragment, -"gl_FragColor = mapColor * totalLight * vec4( vLightWeighting, 1.0 );",THREE.Snippets.envmap_fragment,THREE.Snippets.fog_fragment,"}"].join("\n"),vertex_shader:["#define PHONG\nvarying vec3 vLightWeighting;\nvarying vec3 vViewPosition;\nvarying vec3 vNormal;",THREE.Snippets.map_pars_vertex,THREE.Snippets.envmap_pars_vertex,THREE.Snippets.lights_pars_vertex,"void main() {\nvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",THREE.Snippets.map_vertex,THREE.Snippets.envmap_vertex,"#ifndef USE_ENVMAP\nvec4 mPosition = objectMatrix * vec4( position, 1.0 );\n#endif\nvViewPosition = cameraPosition - mPosition.xyz;\nvec3 transformedNormal = normalize( normalMatrix * normal );\nvNormal = transformedNormal;", -THREE.Snippets.lights_vertex,"gl_Position = projectionMatrix * mvPosition;\n}"].join("\n")}};THREE.RenderableObject=function(){this.z=this.object=null};THREE.RenderableFace3=function(){this.z=null;this.v1=new THREE.Vertex;this.v2=new THREE.Vertex;this.v3=new THREE.Vertex;this.centroidWorld=new THREE.Vector3;this.centroidScreen=new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.vertexNormalsWorld=[];this.faceMaterials=this.meshMaterials=null;this.overdraw=false;this.uvs=[null,null,null]}; -THREE.RenderableParticle=function(){this.rotation=this.z=this.y=this.x=null;this.scale=new THREE.Vector2;this.materials=null};THREE.RenderableLine=function(){this.z=null;this.v1=new THREE.Vertex;this.v2=new THREE.Vertex;this.materials=null}; diff --git a/mediagoblin/static/js/thingiview.js/binaryReader.js b/mediagoblin/static/js/thingiview.js/binaryReader.js deleted file mode 100644 index f99a2379..00000000 --- a/mediagoblin/static/js/thingiview.js/binaryReader.js +++ /dev/null @@ -1,126 +0,0 @@ -// BinaryReader -// Refactored by Vjeux -// http://blog.vjeux.com/2010/javascript/javascript-binary-reader.html - -// Original -//+ Jonas Raoni Soares Silva -//@ http://jsfromhell.com/classes/binary-parser [rev. #1] - -BinaryReader = function (data) { - this._buffer = data; - this._pos = 0; -}; - -BinaryReader.prototype = { - - /* Public */ - - readInt8: function (){ return this._decodeInt(8, true); }, - readUInt8: function (){ return this._decodeInt(8, false); }, - readInt16: function (){ return this._decodeInt(16, true); }, - readUInt16: function (){ return this._decodeInt(16, false); }, - readInt32: function (){ return this._decodeInt(32, true); }, - readUInt32: function (){ return this._decodeInt(32, false); }, - - readFloat: function (){ return this._decodeFloat(23, 8); }, - readDouble: function (){ return this._decodeFloat(52, 11); }, - - readChar: function () { return this.readString(1); }, - readString: function (length) { - this._checkSize(length * 8); - var result = this._buffer.substr(this._pos, length); - this._pos += length; - return result; - }, - - seek: function (pos) { - this._pos = pos; - this._checkSize(0); - }, - - getPosition: function () { - return this._pos; - }, - - getSize: function () { - return this._buffer.length; - }, - - - /* Private */ - - _decodeFloat: function(precisionBits, exponentBits){ - var length = precisionBits + exponentBits + 1; - var size = length >> 3; - this._checkSize(length); - - var bias = Math.pow(2, exponentBits - 1) - 1; - var signal = this._readBits(precisionBits + exponentBits, 1, size); - var exponent = this._readBits(precisionBits, exponentBits, size); - var significand = 0; - var divisor = 2; - // var curByte = length + (-precisionBits >> 3) - 1; - var curByte = 0; - do { - var byteValue = this._readByte(++curByte, size); - var startBit = precisionBits % 8 || 8; - var mask = 1 << startBit; - while (mask >>= 1) { - if (byteValue & mask) { - significand += 1 / divisor; - } - divisor *= 2; - } - } while (precisionBits -= startBit); - - this._pos += size; - - return exponent == (bias << 1) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity - : (1 + signal * -2) * (exponent || significand ? !exponent ? Math.pow(2, -bias + 1) * significand - : Math.pow(2, exponent - bias) * (1 + significand) : 0); - }, - - _decodeInt: function(bits, signed){ - var x = this._readBits(0, bits, bits / 8), max = Math.pow(2, bits); - var result = signed && x >= max / 2 ? x - max : x; - - this._pos += bits / 8; - return result; - }, - - //shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni) - _shl: function (a, b){ - for (++b; --b; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1); - return a; - }, - - _readByte: function (i, size) { - return this._buffer.charCodeAt(this._pos + size - i - 1) & 0xff; - }, - - _readBits: function (start, length, size) { - var offsetLeft = (start + length) % 8; - var offsetRight = start % 8; - var curByte = size - (start >> 3) - 1; - var lastByte = size + (-(start + length) >> 3); - var diff = curByte - lastByte; - - var sum = (this._readByte(curByte, size) >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1); - - if (diff && offsetLeft) { - sum += (this._readByte(lastByte++, size) & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight; - } - - while (diff) { - sum += this._shl(this._readByte(lastByte++, size), (diff-- << 3) - offsetRight); - } - - return sum; - }, - - _checkSize: function (neededBits) { - if (!(this._pos + Math.ceil(neededBits / 8) < this._buffer.length)) { - throw new Error("Index out of bound"); - } - } -}; \ No newline at end of file diff --git a/mediagoblin/static/js/thingiview.js/plane.js b/mediagoblin/static/js/thingiview.js/plane.js deleted file mode 100644 index 9f970be0..00000000 --- a/mediagoblin/static/js/thingiview.js/plane.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @author mr.doob / http://mrdoob.com/ - * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as - */ - -var Plane = function ( width, height, segments_width, segments_height ) { - - THREE.Geometry.call( this ); - - var ix, iy, - width_half = width / 2, - height_half = height / 2, - gridX = segments_width || 1, - gridY = segments_height || 1, - gridX1 = gridX + 1, - gridY1 = gridY + 1, - segment_width = width / gridX, - segment_height = height / gridY; - - - for( iy = 0; iy < gridY1; iy++ ) { - - for( ix = 0; ix < gridX1; ix++ ) { - - var x = ix * segment_width - width_half; - var y = iy * segment_height - height_half; - - this.vertices.push( new THREE.Vertex( new THREE.Vector3( x, - y, 0 ) ) ); - - } - - } - - for( iy = 0; iy < gridY; iy++ ) { - - for( ix = 0; ix < gridX; ix++ ) { - - var a = ix + gridX1 * iy; - var b = ix + gridX1 * ( iy + 1 ); - var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); - var d = ( ix + 1 ) + gridX1 * iy; - - this.faces.push( new THREE.Face4( a, b, c, d ) ); - this.uvs.push( [ - new THREE.UV( ix / gridX, iy / gridY ), - new THREE.UV( ix / gridX, ( iy + 1 ) / gridY ), - new THREE.UV( ( ix + 1 ) / gridX, ( iy + 1 ) / gridY ), - new THREE.UV( ( ix + 1 ) / gridX, iy / gridY ) - ] ); - - } - - } - - this.computeCentroids(); - this.computeFaceNormals(); - this.sortFacesByMaterial(); - -}; - -Plane.prototype = new THREE.Geometry(); -Plane.prototype.constructor = Plane; diff --git a/mediagoblin/static/js/thingiview.js/stats.js b/mediagoblin/static/js/thingiview.js/stats.js deleted file mode 100644 index 270d1ce3..00000000 --- a/mediagoblin/static/js/thingiview.js/stats.js +++ /dev/null @@ -1,2 +0,0 @@ -// stats.js r5 - http://github.com/mrdoob/stats.js -var Stats=function(){var j=0,u=2,r,C=0,E=new Date().getTime(),w=E,f=E,m=0,e=1000,i=0,F,q,c,d,B,k=0,G=1000,a=0,A,t,p,D,l,v=0,o=1000,s=0,h,n,z,g,b,y={fps:{bg:{r:16,g:16,b:48},fg:{r:0,g:255,b:255}},ms:{bg:{r:16,g:48,b:16},fg:{r:0,g:255,b:0}},mem:{bg:{r:48,g:16,b:26},fg:{r:255,g:0,b:128}}};r=document.createElement("div");r.style.fontFamily="Helvetica, Arial, sans-serif";r.style.textAlign="left";r.style.fontSize="9px";r.style.opacity="0.9";r.style.width="80px";r.style.cursor="pointer";r.addEventListener("click",H,false);F=document.createElement("div");F.style.backgroundColor="rgb("+Math.floor(y.fps.bg.r/2)+","+Math.floor(y.fps.bg.g/2)+","+Math.floor(y.fps.bg.b/2)+")";F.style.padding="2px 0px 3px 0px";r.appendChild(F);q=document.createElement("div");q.innerHTML="FPS";q.style.color="rgb("+y.fps.fg.r+","+y.fps.fg.g+","+y.fps.fg.b+")";q.style.margin="0px 0px 1px 3px";F.appendChild(q);c=document.createElement("canvas");c.width=74;c.height=30;c.style.display="block";c.style.marginLeft="3px";F.appendChild(c);d=c.getContext("2d");d.fillStyle="rgb("+y.fps.bg.r+","+y.fps.bg.g+","+y.fps.bg.b+")";d.fillRect(0,0,c.width,c.height);B=d.getImageData(0,0,c.width,c.height);A=document.createElement("div");A.style.backgroundColor="rgb("+Math.floor(y.ms.bg.r/2)+","+Math.floor(y.ms.bg.g/2)+","+Math.floor(y.ms.bg.b/2)+")";A.style.padding="2px 0px 3px 0px";A.style.display="none";r.appendChild(A);t=document.createElement("div");t.innerHTML="MS";t.style.color="rgb("+y.ms.fg.r+","+y.ms.fg.g+","+y.ms.fg.b+")";t.style.margin="0px 0px 1px 3px";A.appendChild(t);p=document.createElement("canvas");p.width=74;p.height=30;p.style.display="block";p.style.marginLeft="3px";A.appendChild(p);D=p.getContext("2d");D.fillStyle="rgb("+y.ms.bg.r+","+y.ms.bg.g+","+y.ms.bg.b+")";D.fillRect(0,0,p.width,p.height);l=D.getImageData(0,0,p.width,p.height);try{if(webkitPerformance&&webkitPerformance.memory.totalJSHeapSize){u=3}}catch(x){}h=document.createElement("div");h.style.backgroundColor="rgb("+Math.floor(y.mem.bg.r/2)+","+Math.floor(y.mem.bg.g/2)+","+Math.floor(y.mem.bg.b/2)+")";h.style.padding="2px 0px 3px 0px";h.style.display="none";r.appendChild(h);n=document.createElement("div");n.innerHTML="MEM";n.style.color="rgb("+y.mem.fg.r+","+y.mem.fg.g+","+y.mem.fg.b+")";n.style.margin="0px 0px 1px 3px";h.appendChild(n);z=document.createElement("canvas");z.width=74;z.height=30;z.style.display="block";z.style.marginLeft="3px";h.appendChild(z);g=z.getContext("2d");g.fillStyle="#301010";g.fillRect(0,0,z.width,z.height);b=g.getImageData(0,0,z.width,z.height);function I(N,M,K){var J,O,L;for(O=0;O<30;O++){for(J=0;J<73;J++){L=(J+O*74)*4;N[L]=N[L+4];N[L+1]=N[L+5];N[L+2]=N[L+6]}}for(O=0;O<30;O++){L=(73+O*74)*4;if(O"+k+" MS ("+G+"-"+a+")";D.putImageData(l,0,0);w=E;if(E>f+1000){m=Math.round((C*1000)/(E-f));e=Math.min(e,m);i=Math.max(i,m);I(B.data,Math.min(30,30-(m/100)*30),"fps");q.innerHTML=""+m+" FPS ("+e+"-"+i+")";d.putImageData(B,0,0);if(u==3){v=webkitPerformance.memory.usedJSHeapSize*9.54e-7;o=Math.min(o,v);s=Math.max(s,v);I(b.data,Math.min(30,30-(v/2)),"mem");n.innerHTML=""+Math.round(v)+" MEM ("+Math.round(o)+"-"+Math.round(s)+")";g.putImageData(b,0,0)}f=E;C=0}}}}; \ No newline at end of file diff --git a/mediagoblin/static/js/thingiview.js/thingiloader.js b/mediagoblin/static/js/thingiview.js/thingiloader.js deleted file mode 100644 index 3791a49c..00000000 --- a/mediagoblin/static/js/thingiview.js/thingiloader.js +++ /dev/null @@ -1,318 +0,0 @@ -Thingiloader = function(event) { - // Code from https://developer.mozilla.org/En/Using_XMLHttpRequest#Receiving_binary_data - this.load_binary_resource = function(url) { - var req = new XMLHttpRequest(); - req.open('GET', url, false); - // The following line says we want to receive data as Binary and not as Unicode - req.overrideMimeType('text/plain; charset=x-user-defined'); - req.send(null); - if (req.status != 200) return ''; - - return req.responseText; - }; - - this.loadSTL = function(url) { - var looksLikeBinary = function(reader) { - // STL files don't specify a way to distinguish ASCII from binary. - // The usual way is checking for "solid" at the start of the file -- - // but Thingiverse has seen at least one binary STL file in the wild - // that breaks this. - - // The approach here is different: binary STL files contain a triangle - // count early in the file. If this correctly predicts the file's length, - // it is most probably a binary STL file. - - reader.seek(80); // skip the header - var count = reader.readUInt32(); - - var predictedSize = 80 /* header */ + 4 /* count */ + 50 * count; - return reader.getSize() == predictedSize; - }; - - workerFacadeMessage({'status':'message', 'content':'Downloading ' + url}); - var file = this.load_binary_resource(url); - var reader = new BinaryReader(file); - - if (looksLikeBinary(reader)) { - this.loadSTLBinary(reader); - } else { - this.loadSTLString(file); - } - }; - - this.loadOBJ = function(url) { - workerFacadeMessage({'status':'message', 'content':'Downloading ' + url}); - var file = this.load_binary_resource(url); - this.loadOBJString(file); - }; - - this.loadJSON = function(url) { - workerFacadeMessage({'status':'message', 'content':'Downloading ' + url}); - var file = this.load_binary_resource(url); - this.loadJSONString(file); - }; - - this.loadPLY = function(url) { - workerFacadeMessage({'status':'message', 'content':'Downloading ' + url}); - - var file = this.load_binary_resource(url); - - if (file.match(/format ascii/i)) { - this.loadPLYString(file); - } else { - this.loadPLYBinary(file); - } - }; - - this.loadSTLString = function(STLString) { - workerFacadeMessage({'status':'message', 'content':'Parsing STL String...'}); - workerFacadeMessage({'status':'complete', 'content':this.ParseSTLString(STLString)}); - }; - - this.loadSTLBinary = function(STLBinary) { - workerFacadeMessage({'status':'message', 'content':'Parsing STL Binary...'}); - workerFacadeMessage({'status':'complete', 'content':this.ParseSTLBinary(STLBinary)}); - }; - - this.loadOBJString = function(OBJString) { - workerFacadeMessage({'status':'message', 'content':'Parsing OBJ String...'}); - workerFacadeMessage({'status':'complete', 'content':this.ParseOBJString(OBJString)}); - }; - - this.loadJSONString = function(JSONString) { - workerFacadeMessage({'status':'message', 'content':'Parsing JSON String...'}); - workerFacadeMessage({'status':'complete', 'content':eval(JSONString)}); - }; - - this.loadPLYString = function(PLYString) { - workerFacadeMessage({'status':'message', 'content':'Parsing PLY String...'}); - workerFacadeMessage({'status':'complete_points', 'content':this.ParsePLYString(PLYString)}); - }; - - this.loadPLYBinary = function(PLYBinary) { - workerFacadeMessage({'status':'message', 'content':'Parsing PLY Binary...'}); - workerFacadeMessage({'status':'complete_points', 'content':this.ParsePLYBinary(PLYBinary)}); - }; - - this.ParsePLYString = function(input) { - var properties = []; - var vertices = []; - var colors = []; - - var vertex_count = 0; - - var header = /ply\n([\s\S]+)\nend_header/ig.exec(input)[1]; - var data = /end_header\n([\s\S]+)$/ig.exec(input)[1]; - - // workerFacadeMessage({'status':'message', 'content':'header:\n' + header}); - // workerFacadeMessage({'status':'message', 'content':'data:\n' + data}); - - header_parts = header.split("\n"); - - for (i in header_parts) { - if (/element vertex/i.test(header_parts[i])) { - vertex_count = /element vertex (\d+)/i.exec(header_parts[i])[1]; - } else if (/property/i.test(header_parts[i])) { - properties.push(/property (.*) (.*)/i.exec(header_parts[i])[2]); - } - } - - // workerFacadeMessage({'status':'message', 'content':'properties: ' + properties}); - - data_parts = data.split("\n"); - - for (i in data_parts) { - data_line = data_parts[i]; - data_line_parts = data_line.split(" "); - - vertices.push([ - parseFloat(data_line_parts[properties.indexOf("x")]), - parseFloat(data_line_parts[properties.indexOf("y")]), - parseFloat(data_line_parts[properties.indexOf("z")]) - ]); - - colors.push([ - parseInt(data_line_parts[properties.indexOf("red")]), - parseInt(data_line_parts[properties.indexOf("green")]), - parseInt(data_line_parts[properties.indexOf("blue")]) - ]); - } - - // workerFacadeMessage({'status':'message', 'content':'vertices: ' + vertices}); - - return [vertices, colors]; - }; - - this.ParsePLYBinary = function(input) { - return false; - }; - - this.ParseSTLBinary = function(input) { - // Skip the header. - input.seek(80); - - // Load the number of vertices. - var count = input.readUInt32(); - - // During the parse loop we maintain the following data structures: - var vertices = []; // Append-only list of all unique vertices. - var vert_hash = {}; // Mapping from vertex to index in 'vertices', above. - var faces = []; // List of triangle descriptions, each a three-element - // list of indices in 'vertices', above. - - for (var i = 0; i < count; i++) { - if (i % 100 == 0) { - workerFacadeMessage({ - 'status':'message', - 'content':'Parsing ' + (i+1) + ' of ' + count + ' polygons...' - }); - workerFacadeMessage({ - 'status':'progress', - 'content':parseInt(i / count * 100) + '%' - }); - } - - // Skip the normal (3 single-precision floats) - input.seek(input.getPosition() + 12); - - var face_indices = []; - for (var x = 0; x < 3; x++) { - var vertex = [input.readFloat(), input.readFloat(), input.readFloat()]; - - var vertexIndex = vert_hash[vertex]; - if (vertexIndex == null) { - vertexIndex = vertices.length; - vertices.push(vertex); - vert_hash[vertex] = vertexIndex; - } - - face_indices.push(vertexIndex); - } - faces.push(face_indices); - - // Skip the "attribute" field (unused in common models) - input.readUInt16(); - } - - return [vertices, faces]; - }; - - // build stl's vertex and face arrays - this.ParseSTLString = function(STLString) { - var vertexes = []; - var faces = []; - - var face_vertexes = []; - var vert_hash = {} - - // console.log(STLString); - - // strip out extraneous stuff - STLString = STLString.replace(/\r/, "\n"); - STLString = STLString.replace(/^solid[^\n]*/, ""); - STLString = STLString.replace(/\n/g, " "); - STLString = STLString.replace(/facet normal /g,""); - STLString = STLString.replace(/outer loop/g,""); - STLString = STLString.replace(/vertex /g,""); - STLString = STLString.replace(/endloop/g,""); - STLString = STLString.replace(/endfacet/g,""); - STLString = STLString.replace(/endsolid[^\n]*/, ""); - STLString = STLString.replace(/\s+/g, " "); - STLString = STLString.replace(/^\s+/, ""); - - // console.log(STLString); - - var facet_count = 0; - var block_start = 0; - - var points = STLString.split(" "); - - workerFacadeMessage({'status':'message', 'content':'Parsing vertices...'}); - for (var i=0; i 0) { - // up - scope.setCameraZoom(+10); - } else { - // down - scope.setCameraZoom(-10); - } - } - - onRendererGestureChange = function(event) { - event.preventDefault(); - - if (event.scale > 1) { - scope.setCameraZoom(+5); - } else { - scope.setCameraZoom(-5); - } - } - - onRendererMouseOver = function(event) { - mouseOver = true; - // targetRotation = object.rotation.z; - if (timer == null) { - // log('starting loop'); - timer = setInterval(sceneLoop, 1000/60); - } - } - - onRendererMouseDown = function(event) { - // log("down"); - - event.preventDefault(); - mouseDown = true; - - if(scope.getRotation()){ - wasRotating = true; - scope.setRotation(false); - } else { - wasRotating = false; - } - - mouseXOnMouseDown = event.clientX - windowHalfX; - mouseYOnMouseDown = event.clientY - windowHalfY; - - targetXRotationOnMouseDown = targetXRotation; - targetYRotationOnMouseDown = targetYRotation; - } - - onRendererMouseMove = function(event) { - // log("move"); - - if (mouseDown) { - mouseX = event.clientX - windowHalfX; - // targetXRotation = targetXRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02; - xrot = targetXRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02; - - mouseY = event.clientY - windowHalfY; - // targetYRotation = targetYRotationOnMouseDown + (mouseY - mouseYOnMouseDown) * 0.02; - yrot = targetYRotationOnMouseDown + (mouseY - mouseYOnMouseDown) * 0.02; - - targetXRotation = xrot; - targetYRotation = yrot; - } - } - - onRendererMouseUp = function(event) { - // log("up"); - if (mouseDown) { - mouseDown = false; - if (!mouseOver) { - clearInterval(timer); - timer = null; - } - if (wasRotating) { - scope.setRotation(true); - } - } - } - - onRendererMouseOut = function(event) { - if (!mouseDown) { - clearInterval(timer); - timer = null; - } - mouseOver = false; - } - - onRendererTouchStart = function(event) { - targetXRotation = object.rotation.z; - targetYRotation = object.rotation.x; - - timer = setInterval(sceneLoop, 1000/60); - - if (event.touches.length == 1) { - event.preventDefault(); - - mouseXOnMouseDown = event.touches[0].pageX - windowHalfX; - targetXRotationOnMouseDown = targetXRotation; - - mouseYOnMouseDown = event.touches[0].pageY - windowHalfY; - targetYRotationOnMouseDown = targetYRotation; - } - } - - onRendererTouchEnd = function(event) { - clearInterval(timer); - timer = null; - // targetXRotation = object.rotation.z; - // targetYRotation = object.rotation.x; - } - - onRendererTouchMove = function(event) { - if (event.touches.length == 1) { - event.preventDefault(); - - mouseX = event.touches[0].pageX - windowHalfX; - targetXRotation = targetXRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05; - - mouseY = event.touches[0].pageY - windowHalfY; - targetYRotation = targetYRotationOnMouseDown + (mouseY - mouseYOnMouseDown) * 0.05; - } - } - - sceneLoop = function() { - if (object) { - // if (view == 'bottom') { - // if (showPlane) { - // plane.rotation.z = object.rotation.z -= (targetRotation + object.rotation.z) * 0.05; - // } else { - // object.rotation.z -= (targetRotation + object.rotation.z) * 0.05; - // } - // } else { - // if (showPlane) { - // plane.rotation.z = object.rotation.z += (targetRotation - object.rotation.z) * 0.05; - // } else { - // object.rotation.z += (targetRotation - object.rotation.z) * 0.05; - // } - // } - - if (showPlane) { - plane.rotation.z = object.rotation.z = (targetXRotation - object.rotation.z) * 0.2; - plane.rotation.x = object.rotation.x = (targetYRotation - object.rotation.x) * 0.2; - } else { - object.rotation.z = (targetXRotation - object.rotation.z) * 0.2; - object.rotation.x = (targetYRotation - object.rotation.x) * 0.2; - } - - // log(object.rotation.x); - - camera.updateMatrix(); - object.updateMatrix(); - - if (showPlane) { - plane.updateMatrix(); - } - - renderer.render(scene, camera); - // stats.update(); - } - } - - rotateLoop = function() { - // targetRotation += 0.01; - targetXRotation += 0.05; - sceneLoop(); - } - - this.getShowPlane = function(){ - return showPlane; - } - - this.setShowPlane = function(show) { - showPlane = show; - - if (show) { - if (scene && !plane) { - loadPlaneGeometry(); - } - plane.material[0].opacity = 1; - // plane.updateMatrix(); - } else { - if (scene && plane) { - // alert(plane.material[0].opacity); - plane.material[0].opacity = 0; - // plane.updateMatrix(); - } - } - - sceneLoop(); - } - - this.getRotation = function() { - return rotateTimer !== null; - } - - this.resetRotation = function () { - if (rotate) { - this.setRotation(false); - this.setRotation(true); - } - } - - this.setRotation = function(rotate) { - rotation = rotate; - - if (rotate) { - rotateTimer = setInterval(rotateLoop, 1000/60); - } else { - clearInterval(rotateTimer); - rotateTimer = null; - } - - scope.onSetRotation(); - } - - this.onSetRotation = function(callback) { - if(callback === undefined){ - if(rotateListener !== null){ - try{ - rotateListener(scope.getRotation()); - } catch(ignored) {} - } - } else { - rotateListener = callback; - } - } - - this.setCameraView = function(dir) { - cameraView = dir; - - targetXRotation = 0; - targetYRotation = 0; - - if (object) { - object.rotation.x = 0; - object.rotation.y = 0; - object.rotation.z = 0; - } - - if (showPlane && object) { - plane.rotation.x = object.rotation.x; - plane.rotation.y = object.rotation.y; - plane.rotation.z = object.rotation.z; - } - - if (dir == 'top') { - // camera.position.y = 0; - // camera.position.z = 100; - // camera.target.position.z = 0; - if (showPlane) { - plane.flipSided = false; - } - } else if (dir == 'side') { - // camera.position.y = -70; - // camera.position.z = 70; - // camera.target.position.z = 0; - targetYRotation = -4.5; - if (showPlane) { - plane.flipSided = false; - } - } else if (dir == 'bottom') { - // camera.position.y = 0; - // camera.position.z = -100; - // camera.target.position.z = 0; - if (showPlane) { - plane.flipSided = true; - } - } else { - // camera.position.y = -70; - // camera.position.z = 70; - // camera.target.position.z = 0; - if (showPlane) { - plane.flipSided = false; - } - } - - mouseX = targetXRotation; - mouseXOnMouseDown = targetXRotation; - - mouseY = targetYRotation; - mouseYOnMouseDown = targetYRotation; - - scope.centerCamera(); - - sceneLoop(); - } - - this.setCameraZoom = function(factor) { - cameraZoom = factor; - - if (cameraView == 'bottom') { - if (camera.position.z + factor > 0) { - factor = 0; - } - } else { - if (camera.position.z - factor < 0) { - factor = 0; - } - } - - if (cameraView == 'top') { - camera.position.z -= factor; - } else if (cameraView == 'bottom') { - camera.position.z += factor; - } else if (cameraView == 'side') { - camera.position.y += factor; - camera.position.z -= factor; - } else { - camera.position.y += factor; - camera.position.z -= factor; - } - - sceneLoop(); - } - - this.getObjectMaterial = function() { - return objectMaterial; - } - - this.setObjectMaterial = function(type) { - objectMaterial = type; - - loadObjectGeometry(); - } - - this.setBackgroundColor = function(color) { - backgroundColor = color - - if (renderer) { - renderer.domElement.style.backgroundColor = color; - } - } - - this.setObjectColor = function(color) { - objectColor = parseInt(color.replace(/\#/g, ''), 16); - - loadObjectGeometry(); - } - - this.loadSTL = function(url) { - scope.newWorker('loadSTL', url); - } - - this.loadOBJ = function(url) { - scope.newWorker('loadOBJ', url); - } - - this.loadSTLString = function(STLString) { - scope.newWorker('loadSTLString', STLString); - } - - this.loadSTLBinary = function(STLBinary) { - scope.newWorker('loadSTLBinary', STLBinary); - } - - this.loadOBJString = function(OBJString) { - scope.newWorker('loadOBJString', OBJString); - } - - this.loadJSON = function(url) { - scope.newWorker('loadJSON', url); - } - - this.loadPLY = function(url) { - scope.newWorker('loadPLY', url); - } - - this.loadPLYString = function(PLYString) { - scope.newWorker('loadPLYString', PLYString); - } - - this.loadPLYBinary = function(PLYBinary) { - scope.newWorker('loadPLYBinary', PLYBinary); - } - - this.centerCamera = function() { - if (geometry) { - // Using method from http://msdn.microsoft.com/en-us/library/bb197900(v=xnagamestudio.10).aspx - // log("bounding sphere radius = " + geometry.boundingSphere.radius); - - // look at the center of the object - camera.target.position.x = geometry.center_x; - camera.target.position.y = geometry.center_y; - camera.target.position.z = geometry.center_z; - - // set camera position to center of sphere - camera.position.x = geometry.center_x; - camera.position.y = geometry.center_y; - camera.position.z = geometry.center_z; - - // find distance to center - distance = geometry.boundingSphere.radius / Math.sin((camera.fov/2) * (Math.PI / 180)); - - // zoom backwards about half that distance, I don't think I'm doing the math or backwards vector calculation correctly? - // scope.setCameraZoom(-distance/1.8); - // scope.setCameraZoom(-distance/1.5); - scope.setCameraZoom(-distance/1.9); - - directionalLight.position.x = geometry.min_y * 2; - directionalLight.position.y = geometry.min_y * 2; - directionalLight.position.z = geometry.max_z * 2; - - pointLight.position.x = geometry.center_y; - pointLight.position.y = geometry.center_y; - pointLight.position.z = geometry.max_z * 2; - } else { - // set to any valid position so it doesn't fail before geometry is available - camera.position.y = -70; - camera.position.z = 70; - camera.target.position.z = 0; - } - } - - this.loadArray = function(array) { - log("loading array..."); - geometry = new STLGeometry(array); - loadObjectGeometry(); - scope.resetRotation(); - scope.centerCamera(); - log("finished loading " + geometry.faces.length + " faces."); - } - - this.newWorker = function(cmd, param) { - scope.setRotation(false); - - var worker = new WorkerFacade(thingiurlbase + '/thingiloader.js'); - - worker.onmessage = function(event) { - if (event.data.status == "complete") { - progressBar.innerHTML = 'Initializing geometry...'; - // scene.removeObject(object); - geometry = new STLGeometry(event.data.content); - loadObjectGeometry(); - progressBar.innerHTML = ''; - progressBar.style.display = 'none'; - - scope.resetRotation(); - log("finished loading " + geometry.faces.length + " faces."); - scope.centerCamera(); - } else if (event.data.status == "complete_points") { - progressBar.innerHTML = 'Initializing points...'; - - geometry = new THREE.Geometry(); - - var material = new THREE.ParticleBasicMaterial( { color: 0xff0000, opacity: 1 } ); - - // material = new THREE.ParticleBasicMaterial( { size: 35, sizeAttenuation: false} ); - // material.color.setHSV( 1.0, 0.2, 0.8 ); - - for (i in event.data.content[0]) { - // for (var i=0; i<10; i++) { - vector = new THREE.Vector3( event.data.content[0][i][0], event.data.content[0][i][1], event.data.content[0][i][2] ); - geometry.vertices.push( new THREE.Vertex( vector ) ); - } - - particles = new THREE.ParticleSystem( geometry, material ); - particles.sortParticles = true; - particles.updateMatrix(); - scene.addObject( particles ); - - camera.updateMatrix(); - renderer.render(scene, camera); - - progressBar.innerHTML = ''; - progressBar.style.display = 'none'; - - scope.resetRotation(); - log("finished loading " + event.data.content[0].length + " points."); - // scope.centerCamera(); - } else if (event.data.status == "progress") { - progressBar.style.display = 'block'; - progressBar.style.width = event.data.content; - // log(event.data.content); - } else if (event.data.status == "message") { - progressBar.style.display = 'block'; - progressBar.innerHTML = event.data.content; - log(event.data.content); - } else if (event.data.status == "alert") { - scope.displayAlert(event.data.content); - } else { - alert('Error: ' + event.data); - log('Unknown Worker Message: ' + event.data); - } - } - - worker.onerror = function(error) { - log(error); - error.preventDefault(); - } - - worker.postMessage({'cmd':cmd, 'param':param}); - } - - this.displayAlert = function(msg) { - msg = msg + "

" - - alertBox.innerHTML = msg; - alertBox.style.display = 'block'; - - // log(msg); - } - - function loadPlaneGeometry() { - // TODO: switch to lines instead of the Plane object so we can get rid of the horizontal lines in canvas renderer... - plane = new THREE.Mesh(new Plane(100, 100, 10, 10), new THREE.MeshBasicMaterial({color:0xafafaf,wireframe:true})); - scene.addObject(plane); - } - - function loadObjectGeometry() { - if (scene && geometry) { - if (objectMaterial == 'wireframe') { - // material = new THREE.MeshColorStrokeMaterial(objectColor, 1, 1); - material = new THREE.MeshBasicMaterial({color:objectColor,wireframe:true}); - } else { - if (isWebGl) { - // material = new THREE.MeshPhongMaterial(objectColor, objectColor, 0xffffff, 50, 1.0); - // material = new THREE.MeshColorFillMaterial(objectColor); - // material = new THREE.MeshLambertMaterial({color:objectColor}); - material = new THREE.MeshLambertMaterial({color:objectColor, shading: THREE.FlatShading}); - } else { - // material = new THREE.MeshColorFillMaterial(objectColor); - material = new THREE.MeshLambertMaterial({color:objectColor, shading: THREE.FlatShading}); - } - } - - // scene.removeObject(object); - - if (object) { - // shouldn't be needed, but this fixes a bug with webgl not removing previous object when loading a new one dynamically - object.materials = [new THREE.MeshBasicMaterial({color:0xffffff, opacity:0})]; - scene.removeObject(object); - // object.geometry = geometry; - // object.materials = [material]; - } - - object = new THREE.Mesh(geometry, material); - scene.addObject(object); - - if (objectMaterial != 'wireframe') { - object.overdraw = true; - object.doubleSided = true; - } - - object.updateMatrix(); - - targetXRotation = 0; - targetYRotation = 0; - - sceneLoop(); - } - } - -}; - -var STLGeometry = function(stlArray) { - // log("building geometry..."); - THREE.Geometry.call(this); - - var scope = this; - - // var vertexes = stlArray[0]; - // var normals = stlArray[1]; - // var faces = stlArray[2]; - - for (var i=0; i 0){ - theworker.postToWorkerFunction(callings[0]); - callings.shift(); - } - }; - document.body.appendChild(scr); - - var binaryscr = document.createElement("SCRIPT"); - binaryscr.src = thingiurlbase + '/binaryReader.js'; - binaryscr.type = "text/javascript"; - document.body.appendChild(binaryscr); - - return theworker; - }; - that.fake = true; - that.add = function(pth, worker){ - workers[pth] = worker; - return function(param){ - masters[pth].onmessage({"data": param}); - }; - }; - that.toString = function(){ - return "FakeWorker('"+path+"')"; - }; - return that; - }()); -} - -/* Then just use WorkerFacade instead of Worker (or alias it) - -The Worker code must should use a custom function (name it how you want) instead of postMessage. -Put this at the end of the Worker: - -if(typeof(window) === "undefined"){ - onmessage = nameOfWorkerFunction; - customPostMessage = postMessage; -} else { - customPostMessage = WorkerFacade.add("path/to/thisworker.js", nameOfWorkerFunction); -} - -*/ -- cgit v1.2.3 From 75a086dafaf59a45a995f84a37951e6553566dfc Mon Sep 17 00:00:00 2001 From: Jef van Schendel Date: Tue, 4 Dec 2012 21:12:00 +0100 Subject: Add header_dropdown.js --- mediagoblin/static/js/header_dropdown.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 mediagoblin/static/js/header_dropdown.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/header_dropdown.js b/mediagoblin/static/js/header_dropdown.js new file mode 100644 index 00000000..1b2fb00f --- /dev/null +++ b/mediagoblin/static/js/header_dropdown.js @@ -0,0 +1,27 @@ +/** + * GNU MediaGoblin -- federated, autonomous media hosting + * Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +$(document).ready(function(){ + $(".header_dropdown").hide(); + $(".header_dropdown_up").hide(); + $(".header_dropdown_down,.header_dropdown_up").click(function() { + $(".header_dropdown_down").toggle(); + $(".header_dropdown_up").toggle(); + $(".header_dropdown").slideToggle(); + }); +}); -- cgit v1.2.3 From 565d01a09a58bb1f60b6562e949ea322f6e01cc0 Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Thu, 20 Dec 2012 09:07:59 +0100 Subject: Bump bundled video.js to v3.2.3 (#512) There is nothing inherently wrong with the currently bundled version, but the last one was uploaded in March 2012 and there have been upstream releases since. So bump to the latest available release 3.2.3. Might help with the reported issue 512 of an unresponsive video player. Do note that the Flash fallback option is removed. If we decide this should be added it is easy to add it back. We still use our own customized theme. Signed-off-by: Sebastian Spaeth --- mediagoblin/static/js/extlib/video-js | 1 - 1 file changed, 1 deletion(-) delete mode 120000 mediagoblin/static/js/extlib/video-js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/extlib/video-js b/mediagoblin/static/js/extlib/video-js deleted file mode 120000 index 35da21ca..00000000 --- a/mediagoblin/static/js/extlib/video-js +++ /dev/null @@ -1 +0,0 @@ -../../../../extlib/video-js \ No newline at end of file -- cgit v1.2.3 From 8db7eed3bcba5c0527befc48a9d2b84cf5be62a8 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Tue, 26 Feb 2013 17:49:53 -0600 Subject: Removing html5shiv for not complying with its own licenses and racism Issues of racism seem to have been resolved and removed from upstream, but make having this as a dependency somewhat uncomfortable: https://github.com/aFarkas/html5shiv/issues/91 Regardless, at the time of writing the project doesn't comply with its own license... it states to be dual licensed under MIT and GPLv2 but distributes neither of these licenses with its source. --- mediagoblin/static/js/extlib/html5shiv.js | 1 - 1 file changed, 1 deletion(-) delete mode 120000 mediagoblin/static/js/extlib/html5shiv.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/extlib/html5shiv.js b/mediagoblin/static/js/extlib/html5shiv.js deleted file mode 120000 index ca7358c7..00000000 --- a/mediagoblin/static/js/extlib/html5shiv.js +++ /dev/null @@ -1 +0,0 @@ -../../../../extlib/html5shiv/html5shiv.js \ No newline at end of file -- cgit v1.2.3 From 0151060a5ba42c1543fb4cd89cfbf7b68002e8e4 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sun, 10 Mar 2013 23:08:53 +0100 Subject: Added thingiview.js symlink, fixes webgl view --- mediagoblin/static/js/extlib/thingiview.js | 1 + 1 file changed, 1 insertion(+) create mode 120000 mediagoblin/static/js/extlib/thingiview.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/extlib/thingiview.js b/mediagoblin/static/js/extlib/thingiview.js new file mode 120000 index 00000000..b7c842ba --- /dev/null +++ b/mediagoblin/static/js/extlib/thingiview.js @@ -0,0 +1 @@ +../../../../extlib/thingiview.js/ \ No newline at end of file -- cgit v1.2.3 From a80ebf3b64dce807d84ab3993984c211f55b47db Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Wed, 27 Mar 2013 12:21:10 +0200 Subject: add pdf media type The new media type supports pdf and a subset of media recognized by libreoffice via unoconv. Every document added goes through: * conversion to pdf with unoconv if not already a pdf * creation of thumbnail and medium sized image, and pdfinfo generates some information (even for unoconv produces docs - should fix this) Poppler (pdftocairo, pdfinfo) is used. http://poppler.freedesktop.org/ A working but uglified pdf.js integration exists, which is enabled by setting pdf.pdf_js=true mediagoblin_local.ini (disabled in mediagoblin.ini) Adds one test to the test_submission test suite, and another separate test_pdf suite. The tests are only run if media_types.pdf.processing.check_prerequisites passes, so the test suite will not require any extra package. TODO: make test suite say 'skipped' in that case instead of just 'ok' Signed-off-by: Alon Levy --- mediagoblin/static/js/pdf_viewer.js | 3615 +++++++++++++++++++++++++++++++++++ 1 file changed, 3615 insertions(+) create mode 100644 mediagoblin/static/js/pdf_viewer.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/pdf_viewer.js b/mediagoblin/static/js/pdf_viewer.js new file mode 100644 index 00000000..79c1e708 --- /dev/null +++ b/mediagoblin/static/js/pdf_viewer.js @@ -0,0 +1,3615 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ +/* Copyright 2012 Mozilla Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* globals PDFJS, PDFBug, FirefoxCom, Stats */ + +'use strict'; + +var DEFAULT_SCALE = 'auto'; +var DEFAULT_SCALE_DELTA = 1.1; +var UNKNOWN_SCALE = 0; +var CACHE_SIZE = 20; +var CSS_UNITS = 96.0 / 72.0; +var SCROLLBAR_PADDING = 40; +var VERTICAL_PADDING = 5; +var MIN_SCALE = 0.25; +var MAX_SCALE = 4.0; +var IMAGE_DIR = './images/'; +var SETTINGS_MEMORY = 20; +var ANNOT_MIN_SIZE = 10; +var RenderingStates = { + INITIAL: 0, + RUNNING: 1, + PAUSED: 2, + FINISHED: 3 +}; +var FindStates = { + FIND_FOUND: 0, + FIND_NOTFOUND: 1, + FIND_WRAPPED: 2, + FIND_PENDING: 3 +}; + +//#if (FIREFOX || MOZCENTRAL || B2G || GENERIC || CHROME) +//PDFJS.workerSrc = '../build/pdf.js'; +//#endif + +var mozL10n = document.mozL10n || document.webL10n; + +function getFileName(url) { + var anchor = url.indexOf('#'); + var query = url.indexOf('?'); + var end = Math.min( + anchor > 0 ? anchor : url.length, + query > 0 ? query : url.length); + return url.substring(url.lastIndexOf('/', end) + 1, end); +} + +function scrollIntoView(element, spot) { + // Assuming offsetParent is available (it's not available when viewer is in + // hidden iframe or object). We have to scroll: if the offsetParent is not set + // producing the error. See also animationStartedClosure. + var parent = element.offsetParent; + var offsetY = element.offsetTop + element.clientTop; + if (!parent) { + console.error('offsetParent is not set -- cannot scroll'); + return; + } + while (parent.clientHeight == parent.scrollHeight) { + offsetY += parent.offsetTop; + parent = parent.offsetParent; + if (!parent) + return; // no need to scroll + } + if (spot) + offsetY += spot.top; + parent.scrollTop = offsetY; +} + +var Cache = function cacheCache(size) { + var data = []; + this.push = function cachePush(view) { + var i = data.indexOf(view); + if (i >= 0) + data.splice(i); + data.push(view); + if (data.length > size) + data.shift().destroy(); + }; +}; + +var ProgressBar = (function ProgressBarClosure() { + + function clamp(v, min, max) { + return Math.min(Math.max(v, min), max); + } + + function ProgressBar(id, opts) { + + // Fetch the sub-elements for later + this.div = document.querySelector(id + ' .progress'); + + // Get options, with sensible defaults + this.height = opts.height || 100; + this.width = opts.width || 100; + this.units = opts.units || '%'; + + // Initialize heights + this.div.style.height = this.height + this.units; + } + + ProgressBar.prototype = { + + updateBar: function ProgressBar_updateBar() { + if (this._indeterminate) { + this.div.classList.add('indeterminate'); + return; + } + + var progressSize = this.width * this._percent / 100; + + if (this._percent > 95) + this.div.classList.add('full'); + else + this.div.classList.remove('full'); + this.div.classList.remove('indeterminate'); + + this.div.style.width = progressSize + this.units; + }, + + get percent() { + return this._percent; + }, + + set percent(val) { + this._indeterminate = isNaN(val); + this._percent = clamp(val, 0, 100); + this.updateBar(); + } + }; + + return ProgressBar; +})(); + +//#if FIREFOX || MOZCENTRAL +//#include firefoxcom.js +//#endif + +// Settings Manager - This is a utility for saving settings +// First we see if localStorage is available +// If not, we use FUEL in FF +// Use asyncStorage for B2G +var Settings = (function SettingsClosure() { +//#if !(FIREFOX || MOZCENTRAL || B2G) + var isLocalStorageEnabled = (function localStorageEnabledTest() { + // Feature test as per http://diveintohtml5.info/storage.html + // The additional localStorage call is to get around a FF quirk, see + // bug #495747 in bugzilla + try { + return 'localStorage' in window && window['localStorage'] !== null && + localStorage; + } catch (e) { + return false; + } + })(); +//#endif + + function Settings(fingerprint) { + this.fingerprint = fingerprint; + this.initializedPromise = new PDFJS.Promise(); + + var resolvePromise = (function settingsResolvePromise(db) { + this.initialize(db || '{}'); + this.initializedPromise.resolve(); + }).bind(this); + +//#if B2G +// asyncStorage.getItem('database', resolvePromise); +//#endif + +//#if FIREFOX || MOZCENTRAL +// resolvePromise(FirefoxCom.requestSync('getDatabase', null)); +//#endif + +//#if !(FIREFOX || MOZCENTRAL || B2G) + if (isLocalStorageEnabled) + resolvePromise(localStorage.getItem('database')); +//#endif + } + + Settings.prototype = { + initialize: function settingsInitialize(database) { + database = JSON.parse(database); + if (!('files' in database)) + database.files = []; + if (database.files.length >= SETTINGS_MEMORY) + database.files.shift(); + var index; + for (var i = 0, length = database.files.length; i < length; i++) { + var branch = database.files[i]; + if (branch.fingerprint == this.fingerprint) { + index = i; + break; + } + } + if (typeof index != 'number') + index = database.files.push({fingerprint: this.fingerprint}) - 1; + this.file = database.files[index]; + this.database = database; + }, + + set: function settingsSet(name, val) { + if (!this.initializedPromise.isResolved) + return; + + var file = this.file; + file[name] = val; + var database = JSON.stringify(this.database); + +//#if B2G +// asyncStorage.setItem('database', database); +//#endif + +//#if FIREFOX || MOZCENTRAL +// FirefoxCom.requestSync('setDatabase', database); +//#endif + +//#if !(FIREFOX || MOZCENTRAL || B2G) + if (isLocalStorageEnabled) + localStorage.setItem('database', database); +//#endif + }, + + get: function settingsGet(name, defaultValue) { + if (!this.initializedPromise.isResolved) + return defaultValue; + + return this.file[name] || defaultValue; + } + }; + + return Settings; +})(); + +var cache = new Cache(CACHE_SIZE); +var currentPageNumber = 1; + +var PDFFindController = { + startedTextExtraction: false, + + extractTextPromises: [], + + // If active, find results will be highlighted. + active: false, + + // Stores the text for each page. + pageContents: [], + + pageMatches: [], + + // Currently selected match. + selected: { + pageIdx: -1, + matchIdx: -1 + }, + + // Where find algorithm currently is in the document. + offset: { + pageIdx: null, + matchIdx: null + }, + + resumePageIdx: null, + + resumeCallback: null, + + state: null, + + dirtyMatch: false, + + findTimeout: null, + + initialize: function() { + var events = [ + 'find', + 'findagain', + 'findhighlightallchange', + 'findcasesensitivitychange' + ]; + + this.handleEvent = this.handleEvent.bind(this); + + for (var i = 0; i < events.length; i++) { + window.addEventListener(events[i], this.handleEvent); + } + }, + + calcFindMatch: function(pageIndex) { + var pageContent = this.pageContents[pageIndex]; + var query = this.state.query; + var caseSensitive = this.state.caseSensitive; + var queryLen = query.length; + + if (queryLen === 0) { + // Do nothing the matches should be wiped out already. + return; + } + + if (!caseSensitive) { + pageContent = pageContent.toLowerCase(); + query = query.toLowerCase(); + } + + var matches = []; + + var matchIdx = -queryLen; + while (true) { + matchIdx = pageContent.indexOf(query, matchIdx + queryLen); + if (matchIdx === -1) { + break; + } + + matches.push(matchIdx); + } + this.pageMatches[pageIndex] = matches; + this.updatePage(pageIndex); + if (this.resumePageIdx === pageIndex) { + var callback = this.resumeCallback; + this.resumePageIdx = null; + this.resumeCallback = null; + callback(); + } + }, + + extractText: function() { + if (this.startedTextExtraction) { + return; + } + this.startedTextExtraction = true; + + this.pageContents = []; + for (var i = 0, ii = PDFView.pdfDocument.numPages; i < ii; i++) { + this.extractTextPromises.push(new PDFJS.Promise()); + } + + var self = this; + function extractPageText(pageIndex) { + PDFView.pages[pageIndex].getTextContent().then( + function textContentResolved(data) { + // Build the find string. + var bidiTexts = data.bidiTexts; + var str = ''; + + for (var i = 0; i < bidiTexts.length; i++) { + str += bidiTexts[i].str; + } + + // Store the pageContent as a string. + self.pageContents.push(str); + + self.extractTextPromises[pageIndex].resolve(pageIndex); + if ((pageIndex + 1) < PDFView.pages.length) + extractPageText(pageIndex + 1); + } + ); + } + extractPageText(0); + return this.extractTextPromise; + }, + + handleEvent: function(e) { + if (this.state === null || e.type !== 'findagain') { + this.dirtyMatch = true; + } + this.state = e.detail; + this.updateUIState(FindStates.FIND_PENDING); + + this.extractText(); + + clearTimeout(this.findTimeout); + if (e.type === 'find') { + // Only trigger the find action after 250ms of silence. + this.findTimeout = setTimeout(this.nextMatch.bind(this), 250); + } else { + this.nextMatch(); + } + }, + + updatePage: function(idx) { + var page = PDFView.pages[idx]; + + if (this.selected.pageIdx === idx) { + // If the page is selected, scroll the page into view, which triggers + // rendering the page, which adds the textLayer. Once the textLayer is + // build, it will scroll onto the selected match. + page.scrollIntoView(); + } + + if (page.textLayer) { + page.textLayer.updateMatches(); + } + }, + + nextMatch: function() { + var pages = PDFView.pages; + var previous = this.state.findPrevious; + var numPages = PDFView.pages.length; + + this.active = true; + + if (this.dirtyMatch) { + // Need to recalculate the matches, reset everything. + this.dirtyMatch = false; + this.selected.pageIdx = this.selected.matchIdx = -1; + this.offset.pageIdx = previous ? numPages - 1 : 0; + this.offset.matchIdx = null; + this.hadMatch = false; + this.resumeCallback = null; + this.resumePageIdx = null; + this.pageMatches = []; + var self = this; + + for (var i = 0; i < numPages; i++) { + // Wipe out any previous highlighted matches. + this.updatePage(i); + + // As soon as the text is extracted start finding the matches. + this.extractTextPromises[i].onData(function(pageIdx) { + // Use a timeout since all the pages may already be extracted and we + // want to start highlighting before finding all the matches. + setTimeout(function() { + self.calcFindMatch(pageIdx); + }); + }); + } + } + + // If there's no query there's no point in searching. + if (this.state.query === '') { + this.updateUIState(FindStates.FIND_FOUND); + return; + } + + // If we're waiting on a page, we return since we can't do anything else. + if (this.resumeCallback) { + return; + } + + var offset = this.offset; + // If there's already a matchIdx that means we are iterating through a + // page's matches. + if (offset.matchIdx !== null) { + var numPageMatches = this.pageMatches[offset.pageIdx].length; + if ((!previous && offset.matchIdx + 1 < numPageMatches) || + (previous && offset.matchIdx > 0)) { + // The simple case, we just have advance the matchIdx to select the next + // match on the page. + this.hadMatch = true; + offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1; + this.updateMatch(true); + return; + } + // We went beyond the current page's matches, so we advance to the next + // page. + this.advanceOffsetPage(previous); + } + // Start searching through the page. + this.nextPageMatch(); + }, + + nextPageMatch: function() { + if (this.resumePageIdx !== null) + console.error('There can only be one pending page.'); + + var matchesReady = function(matches) { + var offset = this.offset; + var numMatches = matches.length; + var previous = this.state.findPrevious; + if (numMatches) { + // There were matches for the page, so initialize the matchIdx. + this.hadMatch = true; + offset.matchIdx = previous ? numMatches - 1 : 0; + this.updateMatch(true); + } else { + // No matches attempt to search the next page. + this.advanceOffsetPage(previous); + if (offset.wrapped) { + offset.matchIdx = null; + if (!this.hadMatch) { + // No point in wrapping there were no matches. + this.updateMatch(false); + return; + } + } + // Search the next page. + this.nextPageMatch(); + } + }.bind(this); + + var pageIdx = this.offset.pageIdx; + var pageMatches = this.pageMatches; + if (!pageMatches[pageIdx]) { + // The matches aren't ready setup a callback so we can be notified, + // when they are ready. + this.resumeCallback = function() { + matchesReady(pageMatches[pageIdx]); + }; + this.resumePageIdx = pageIdx; + return; + } + // The matches are finished already. + matchesReady(pageMatches[pageIdx]); + }, + + advanceOffsetPage: function(previous) { + var offset = this.offset; + var numPages = this.extractTextPromises.length; + offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1; + offset.matchIdx = null; + if (offset.pageIdx >= numPages || offset.pageIdx < 0) { + offset.pageIdx = previous ? numPages - 1 : 0; + offset.wrapped = true; + return; + } + }, + + updateMatch: function(found) { + var state = FindStates.FIND_NOTFOUND; + var wrapped = this.offset.wrapped; + this.offset.wrapped = false; + if (found) { + var previousPage = this.selected.pageIdx; + this.selected.pageIdx = this.offset.pageIdx; + this.selected.matchIdx = this.offset.matchIdx; + state = wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND; + // Update the currently selected page to wipe out any selected matches. + if (previousPage !== -1 && previousPage !== this.selected.pageIdx) { + this.updatePage(previousPage); + } + } + this.updateUIState(state, this.state.findPrevious); + if (this.selected.pageIdx !== -1) { + this.updatePage(this.selected.pageIdx, true); + } + }, + + updateUIState: function(state, previous) { + if (PDFView.supportsIntegratedFind) { + FirefoxCom.request('updateFindControlState', + {result: state, findPrevious: previous}); + return; + } + PDFFindBar.updateUIState(state, previous); + } +}; + +var PDFFindBar = { + // TODO: Enable the FindBar *AFTER* the pagesPromise in the load function + // got resolved + + opened: false, + + initialize: function() { + this.bar = document.getElementById('findbar'); + this.toggleButton = document.getElementById('viewFind'); + this.findField = document.getElementById('findInput'); + this.highlightAll = document.getElementById('findHighlightAll'); + this.caseSensitive = document.getElementById('findMatchCase'); + this.findMsg = document.getElementById('findMsg'); + this.findStatusIcon = document.getElementById('findStatusIcon'); + + var self = this; + this.toggleButton.addEventListener('click', function() { + self.toggle(); + }); + + this.findField.addEventListener('input', function() { + self.dispatchEvent(''); + }); + + this.bar.addEventListener('keydown', function(evt) { + switch (evt.keyCode) { + case 13: // Enter + if (evt.target === self.findField) { + self.dispatchEvent('again', evt.shiftKey); + } + break; + case 27: // Escape + self.close(); + break; + } + }); + + document.getElementById('findPrevious').addEventListener('click', + function() { self.dispatchEvent('again', true); } + ); + + document.getElementById('findNext').addEventListener('click', function() { + self.dispatchEvent('again', false); + }); + + this.highlightAll.addEventListener('click', function() { + self.dispatchEvent('highlightallchange'); + }); + + this.caseSensitive.addEventListener('click', function() { + self.dispatchEvent('casesensitivitychange'); + }); + }, + + dispatchEvent: function(aType, aFindPrevious) { + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('find' + aType, true, true, { + query: this.findField.value, + caseSensitive: this.caseSensitive.checked, + highlightAll: this.highlightAll.checked, + findPrevious: aFindPrevious + }); + return window.dispatchEvent(event); + }, + + updateUIState: function(state, previous) { + var notFound = false; + var findMsg = ''; + var status = ''; + + switch (state) { + case FindStates.FIND_FOUND: + break; + + case FindStates.FIND_PENDING: + status = 'pending'; + break; + + case FindStates.FIND_NOTFOUND: + findMsg = mozL10n.get('find_not_found', null, 'Phrase not found'); + notFound = true; + break; + + case FindStates.FIND_WRAPPED: + if (previous) { + findMsg = mozL10n.get('find_reached_top', null, + 'Reached top of document, continued from bottom'); + } else { + findMsg = mozL10n.get('find_reached_bottom', null, + 'Reached end of document, continued from top'); + } + break; + } + + if (notFound) { + this.findField.classList.add('notFound'); + } else { + this.findField.classList.remove('notFound'); + } + + this.findField.setAttribute('data-status', status); + this.findMsg.textContent = findMsg; + }, + + open: function() { + if (this.opened) return; + + this.opened = true; + this.toggleButton.classList.add('toggled'); + this.bar.classList.remove('hidden'); + this.findField.select(); + this.findField.focus(); + }, + + close: function() { + if (!this.opened) return; + + this.opened = false; + this.toggleButton.classList.remove('toggled'); + this.bar.classList.add('hidden'); + + PDFFindController.active = false; + }, + + toggle: function() { + if (this.opened) { + this.close(); + } else { + this.open(); + } + } +}; + +var PDFView = { + pages: [], + thumbnails: [], + currentScale: UNKNOWN_SCALE, + currentScaleValue: null, + initialBookmark: document.location.hash.substring(1), + startedTextExtraction: false, + pageText: [], + container: null, + thumbnailContainer: null, + initialized: false, + fellback: false, + pdfDocument: null, + sidebarOpen: false, + pageViewScroll: null, + thumbnailViewScroll: null, + isFullscreen: false, + previousScale: null, + pageRotation: 0, + mouseScrollTimeStamp: 0, + mouseScrollDelta: 0, + lastScroll: 0, + previousPageNumber: 1, + + // called once when the document is loaded + initialize: function pdfViewInitialize() { + var self = this; + var container = this.container = document.getElementById('viewerContainer'); + this.pageViewScroll = {}; + this.watchScroll(container, this.pageViewScroll, updateViewarea); + + var thumbnailContainer = this.thumbnailContainer = + document.getElementById('thumbnailView'); + this.thumbnailViewScroll = {}; + this.watchScroll(thumbnailContainer, this.thumbnailViewScroll, + this.renderHighestPriority.bind(this)); + + PDFFindBar.initialize(); + PDFFindController.initialize(); + + this.initialized = true; + container.addEventListener('scroll', function() { + self.lastScroll = Date.now(); + }, false); + }, + + getPage: function pdfViewGetPage(n) { + return this.pdfDocument.getPage(n); + }, + + // Helper function to keep track whether a div was scrolled up or down and + // then call a callback. + watchScroll: function pdfViewWatchScroll(viewAreaElement, state, callback) { + state.down = true; + state.lastY = viewAreaElement.scrollTop; + viewAreaElement.addEventListener('scroll', function webViewerScroll(evt) { + var currentY = viewAreaElement.scrollTop; + var lastY = state.lastY; + if (currentY > lastY) + state.down = true; + else if (currentY < lastY) + state.down = false; + // else do nothing and use previous value + state.lastY = currentY; + callback(); + }, true); + }, + + setScale: function pdfViewSetScale(val, resetAutoSettings, noScroll) { + if (val == this.currentScale) + return; + + var pages = this.pages; + for (var i = 0; i < pages.length; i++) + pages[i].update(val * CSS_UNITS); + + if (!noScroll && this.currentScale != val) + this.pages[this.page - 1].scrollIntoView(); + this.currentScale = val; + + var event = document.createEvent('UIEvents'); + event.initUIEvent('scalechange', false, false, window, 0); + event.scale = val; + event.resetAutoSettings = resetAutoSettings; + window.dispatchEvent(event); + }, + + parseScale: function pdfViewParseScale(value, resetAutoSettings, noScroll) { + if ('custom' == value) + return; + + var scale = parseFloat(value); + this.currentScaleValue = value; + if (scale) { + this.setScale(scale, true, noScroll); + return; + } + + var container = this.container; + var currentPage = this.pages[this.page - 1]; + if (!currentPage) { + return; + } + + var pageWidthScale = (container.clientWidth - SCROLLBAR_PADDING) / + currentPage.width * currentPage.scale / CSS_UNITS; + var pageHeightScale = (container.clientHeight - VERTICAL_PADDING) / + currentPage.height * currentPage.scale / CSS_UNITS; + switch (value) { + case 'page-actual': + scale = 1; + break; + case 'page-width': + scale = pageWidthScale; + break; + case 'page-height': + scale = pageHeightScale; + break; + case 'page-fit': + scale = Math.min(pageWidthScale, pageHeightScale); + break; + case 'auto': + scale = Math.min(1.0, pageWidthScale); + break; + } + this.setScale(scale, resetAutoSettings, noScroll); + + selectScaleOption(value); + }, + + zoomIn: function pdfViewZoomIn() { + var newScale = (this.currentScale * DEFAULT_SCALE_DELTA).toFixed(2); + newScale = Math.ceil(newScale * 10) / 10; + newScale = Math.min(MAX_SCALE, newScale); + this.parseScale(newScale, true); + }, + + zoomOut: function pdfViewZoomOut() { + var newScale = (this.currentScale / DEFAULT_SCALE_DELTA).toFixed(2); + newScale = Math.floor(newScale * 10) / 10; + newScale = Math.max(MIN_SCALE, newScale); + this.parseScale(newScale, true); + }, + + set page(val) { + var pages = this.pages; + var input = document.getElementById('pageNumber'); + var event = document.createEvent('UIEvents'); + event.initUIEvent('pagechange', false, false, window, 0); + + if (!(0 < val && val <= pages.length)) { + this.previousPageNumber = val; + event.pageNumber = this.page; + window.dispatchEvent(event); + return; + } + + pages[val - 1].updateStats(); + this.previousPageNumber = currentPageNumber; + currentPageNumber = val; + event.pageNumber = val; + window.dispatchEvent(event); + + // checking if the this.page was called from the updateViewarea function: + // avoiding the creation of two "set page" method (internal and public) + if (updateViewarea.inProgress) + return; + + // Avoid scrolling the first page during loading + if (this.loading && val == 1) + return; + + pages[val - 1].scrollIntoView(); + }, + + get page() { + return currentPageNumber; + }, + + get supportsPrinting() { + var canvas = document.createElement('canvas'); + var value = 'mozPrintCallback' in canvas; + // shadow + Object.defineProperty(this, 'supportsPrinting', { value: value, + enumerable: true, + configurable: true, + writable: false }); + return value; + }, + + get supportsFullscreen() { + var doc = document.documentElement; + var support = doc.requestFullscreen || doc.mozRequestFullScreen || + doc.webkitRequestFullScreen; + + // Disable fullscreen button if we're in an iframe + if (!!window.frameElement) + support = false; + + Object.defineProperty(this, 'supportsFullScreen', { value: support, + enumerable: true, + configurable: true, + writable: false }); + return support; + }, + + get supportsIntegratedFind() { + var support = false; +//#if !(FIREFOX || MOZCENTRAL) +//#else +// support = FirefoxCom.requestSync('supportsIntegratedFind'); +//#endif + Object.defineProperty(this, 'supportsIntegratedFind', { value: support, + enumerable: true, + configurable: true, + writable: false }); + return support; + }, + + get supportsDocumentFonts() { + var support = true; +//#if !(FIREFOX || MOZCENTRAL) +//#else +// support = FirefoxCom.requestSync('supportsDocumentFonts'); +//#endif + Object.defineProperty(this, 'supportsDocumentFonts', { value: support, + enumerable: true, + configurable: true, + writable: false }); + return support; + }, + + get isHorizontalScrollbarEnabled() { + var div = document.getElementById('viewerContainer'); + return div.scrollWidth > div.clientWidth; + }, + + initPassiveLoading: function pdfViewInitPassiveLoading() { + if (!PDFView.loadingBar) { + PDFView.loadingBar = new ProgressBar('#loadingBar', {}); + } + + window.addEventListener('message', function window_message(e) { + var args = e.data; + + if (typeof args !== 'object' || !('pdfjsLoadAction' in args)) + return; + switch (args.pdfjsLoadAction) { + case 'progress': + PDFView.progress(args.loaded / args.total); + break; + case 'complete': + if (!args.data) { + PDFView.error(mozL10n.get('loading_error', null, + 'An error occurred while loading the PDF.'), e); + break; + } + PDFView.open(args.data, 0); + break; + } + }); + FirefoxCom.requestSync('initPassiveLoading', null); + }, + + setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) { + this.url = url; + try { + this.setTitle(decodeURIComponent(getFileName(url)) || url); + } catch (e) { + // decodeURIComponent may throw URIError, + // fall back to using the unprocessed url in that case + this.setTitle(url); + } + }, + + setTitle: function pdfViewSetTitle(title) { + document.title = title; +//#if B2G +// document.getElementById('activityTitle').textContent = title; +//#endif + }, + + open: function pdfViewOpen(url, scale, password) { + var parameters = {password: password}; + if (typeof url === 'string') { // URL + this.setTitleUsingUrl(url); + parameters.url = url; + } else if (url && 'byteLength' in url) { // ArrayBuffer + parameters.data = url; + } + + if (!PDFView.loadingBar) { + PDFView.loadingBar = new ProgressBar('#loadingBar', {}); + } + + this.pdfDocument = null; + var self = this; + self.loading = true; + PDFJS.getDocument(parameters).then( + function getDocumentCallback(pdfDocument) { + self.load(pdfDocument, scale); + self.loading = false; + }, + function getDocumentError(message, exception) { + if (exception && exception.name === 'PasswordException') { + if (exception.code === 'needpassword') { + var promptString = mozL10n.get('request_password', null, + 'PDF is protected by a password:'); + password = prompt(promptString); + if (password && password.length > 0) { + return PDFView.open(url, scale, password); + } + } + } + + var loadingErrorMessage = mozL10n.get('loading_error', null, + 'An error occurred while loading the PDF.'); + + if (exception && exception.name === 'InvalidPDFException') { + // change error message also for other builds + var loadingErrorMessage = mozL10n.get('invalid_file_error', null, + 'Invalid or corrupted PDF file.'); +//#if B2G +// window.alert(loadingErrorMessage); +// return window.close(); +//#endif + } + + if (exception && exception.name === 'MissingPDFException') { + // special message for missing PDF's + var loadingErrorMessage = mozL10n.get('missing_file_error', null, + 'Missing PDF file.'); + +//#if B2G +// window.alert(loadingErrorMessage); +// return window.close(); +//#endif + } + + var loadingIndicator = document.getElementById('loading'); + loadingIndicator.textContent = mozL10n.get('loading_error_indicator', + null, 'Error'); + var moreInfo = { + message: message + }; + self.error(loadingErrorMessage, moreInfo); + self.loading = false; + }, + function getDocumentProgress(progressData) { + self.progress(progressData.loaded / progressData.total); + } + ); + }, + + download: function pdfViewDownload() { + function noData() { + FirefoxCom.request('download', { originalUrl: url }); + } + var url = this.url.split('#')[0]; +//#if !(FIREFOX || MOZCENTRAL) + url += '#pdfjs.action=download'; + window.open(url, '_parent'); +//#else +// // Document isn't ready just try to download with the url. +// if (!this.pdfDocument) { +// noData(); +// return; +// } +// this.pdfDocument.getData().then( +// function getDataSuccess(data) { +// var blob = PDFJS.createBlob(data.buffer, 'application/pdf'); +// var blobUrl = window.URL.createObjectURL(blob); +// +// FirefoxCom.request('download', { blobUrl: blobUrl, originalUrl: url }, +// function response(err) { +// if (err) { +// // This error won't really be helpful because it's likely the +// // fallback won't work either (or is already open). +// PDFView.error('PDF failed to download.'); +// } +// window.URL.revokeObjectURL(blobUrl); +// } +// ); +// }, +// noData // Error occurred try downloading with just the url. +// ); +//#endif + }, + + fallback: function pdfViewFallback() { +//#if !(FIREFOX || MOZCENTRAL) +// return; +//#else +// // Only trigger the fallback once so we don't spam the user with messages +// // for one PDF. +// if (this.fellback) +// return; +// this.fellback = true; +// var url = this.url.split('#')[0]; +// FirefoxCom.request('fallback', url, function response(download) { +// if (!download) +// return; +// PDFView.download(); +// }); +//#endif + }, + + navigateTo: function pdfViewNavigateTo(dest) { + if (typeof dest === 'string') + dest = this.destinations[dest]; + if (!(dest instanceof Array)) + return; // invalid destination + // dest array looks like that: + var destRef = dest[0]; + var pageNumber = destRef instanceof Object ? + this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] : (destRef + 1); + if (pageNumber > this.pages.length) + pageNumber = this.pages.length; + if (pageNumber) { + this.page = pageNumber; + var currentPage = this.pages[pageNumber - 1]; + if (!this.isFullscreen) { // Avoid breaking fullscreen mode. + currentPage.scrollIntoView(dest); + } + } + }, + + getDestinationHash: function pdfViewGetDestinationHash(dest) { + if (typeof dest === 'string') + return PDFView.getAnchorUrl('#' + escape(dest)); + if (dest instanceof Array) { + var destRef = dest[0]; // see navigateTo method for dest format + var pageNumber = destRef instanceof Object ? + this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] : + (destRef + 1); + if (pageNumber) { + var pdfOpenParams = PDFView.getAnchorUrl('#page=' + pageNumber); + var destKind = dest[1]; + if (typeof destKind === 'object' && 'name' in destKind && + destKind.name == 'XYZ') { + var scale = (dest[4] || this.currentScale); + pdfOpenParams += '&zoom=' + (scale * 100); + if (dest[2] || dest[3]) { + pdfOpenParams += ',' + (dest[2] || 0) + ',' + (dest[3] || 0); + } + } + return pdfOpenParams; + } + } + return ''; + }, + + /** + * For the firefox extension we prefix the full url on anchor links so they + * don't come up as resource:// urls and so open in new tab/window works. + * @param {String} anchor The anchor hash include the #. + */ + getAnchorUrl: function getAnchorUrl(anchor) { +//#if !(FIREFOX || MOZCENTRAL) + return anchor; +//#else +// return this.url.split('#')[0] + anchor; +//#endif + }, + + /** + * Returns scale factor for the canvas. It makes sense for the HiDPI displays. + * @return {Object} The object with horizontal (sx) and vertical (sy) + scales. The scaled property is set to false if scaling is + not required, true otherwise. + */ + getOutputScale: function pdfViewGetOutputDPI() { + var pixelRatio = 'devicePixelRatio' in window ? window.devicePixelRatio : 1; + return { + sx: pixelRatio, + sy: pixelRatio, + scaled: pixelRatio != 1 + }; + }, + + /** + * Show the error box. + * @param {String} message A message that is human readable. + * @param {Object} moreInfo (optional) Further information about the error + * that is more technical. Should have a 'message' + * and optionally a 'stack' property. + */ + error: function pdfViewError(message, moreInfo) { + var moreInfoText = mozL10n.get('error_version_info', + {version: PDFJS.version || '?', build: PDFJS.build || '?'}, + 'PDF.js v{{version}} (build: {{build}})') + '\n'; + if (moreInfo) { + moreInfoText += + mozL10n.get('error_message', {message: moreInfo.message}, + 'Message: {{message}}'); + if (moreInfo.stack) { + moreInfoText += '\n' + + mozL10n.get('error_stack', {stack: moreInfo.stack}, + 'Stack: {{stack}}'); + } else { + if (moreInfo.filename) { + moreInfoText += '\n' + + mozL10n.get('error_file', {file: moreInfo.filename}, + 'File: {{file}}'); + } + if (moreInfo.lineNumber) { + moreInfoText += '\n' + + mozL10n.get('error_line', {line: moreInfo.lineNumber}, + 'Line: {{line}}'); + } + } + } + + var loadingBox = document.getElementById('loadingBox'); + loadingBox.setAttribute('hidden', 'true'); + +//#if !(FIREFOX || MOZCENTRAL) + var errorWrapper = document.getElementById('errorWrapper'); + errorWrapper.removeAttribute('hidden'); + + var errorMessage = document.getElementById('errorMessage'); + errorMessage.textContent = message; + + var closeButton = document.getElementById('errorClose'); + closeButton.onclick = function() { + errorWrapper.setAttribute('hidden', 'true'); + }; + + var errorMoreInfo = document.getElementById('errorMoreInfo'); + var moreInfoButton = document.getElementById('errorShowMore'); + var lessInfoButton = document.getElementById('errorShowLess'); + moreInfoButton.onclick = function() { + errorMoreInfo.removeAttribute('hidden'); + moreInfoButton.setAttribute('hidden', 'true'); + lessInfoButton.removeAttribute('hidden'); + }; + lessInfoButton.onclick = function() { + errorMoreInfo.setAttribute('hidden', 'true'); + moreInfoButton.removeAttribute('hidden'); + lessInfoButton.setAttribute('hidden', 'true'); + }; + moreInfoButton.removeAttribute('hidden'); + lessInfoButton.setAttribute('hidden', 'true'); + errorMoreInfo.value = moreInfoText; + + errorMoreInfo.rows = moreInfoText.split('\n').length - 1; +//#else +// console.error(message + '\n' + moreInfoText); +// this.fallback(); +//#endif + }, + + progress: function pdfViewProgress(level) { + var percent = Math.round(level * 100); + PDFView.loadingBar.percent = percent; + }, + + load: function pdfViewLoad(pdfDocument, scale) { + function bindOnAfterDraw(pageView, thumbnailView) { + // when page is painted, using the image as thumbnail base + pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() { + thumbnailView.setImage(pageView.canvas); + }; + } + + this.pdfDocument = pdfDocument; + + var errorWrapper = document.getElementById('errorWrapper'); + errorWrapper.setAttribute('hidden', 'true'); + + var loadingBox = document.getElementById('loadingBox'); + loadingBox.setAttribute('hidden', 'true'); + var loadingIndicator = document.getElementById('loading'); + loadingIndicator.textContent = ''; + + var thumbsView = document.getElementById('thumbnailView'); + thumbsView.parentNode.scrollTop = 0; + + while (thumbsView.hasChildNodes()) + thumbsView.removeChild(thumbsView.lastChild); + + if ('_loadingInterval' in thumbsView) + clearInterval(thumbsView._loadingInterval); + + var container = document.getElementById('viewer'); + while (container.hasChildNodes()) + container.removeChild(container.lastChild); + + var pagesCount = pdfDocument.numPages; + var id = pdfDocument.fingerprint; + document.getElementById('numPages').textContent = + mozL10n.get('page_of', {pageCount: pagesCount}, 'of {{pageCount}}'); + document.getElementById('pageNumber').max = pagesCount; + + PDFView.documentFingerprint = id; + var store = PDFView.store = new Settings(id); + + this.pageRotation = 0; + + var pages = this.pages = []; + this.pageText = []; + this.startedTextExtraction = false; + var pagesRefMap = this.pagesRefMap = {}; + var thumbnails = this.thumbnails = []; + + var pagesPromise = new PDFJS.Promise(); + var self = this; + + var firstPagePromise = pdfDocument.getPage(1); + + // Fetch a single page so we can get a viewport that will be the default + // viewport for all pages + firstPagePromise.then(function(pdfPage) { + var viewport = pdfPage.getViewport(scale || 1.0); + var pagePromises = []; + for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { + var viewportClone = viewport.clone(); + var pageView = new PageView(container, pageNum, scale, + self.navigateTo.bind(self), + viewportClone); + var thumbnailView = new ThumbnailView(thumbsView, pageNum, + viewportClone); + bindOnAfterDraw(pageView, thumbnailView); + pages.push(pageView); + thumbnails.push(thumbnailView); + } + + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('documentload', true, true, {}); + window.dispatchEvent(event); + + for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { + var pagePromise = pdfDocument.getPage(pageNum); + pagePromise.then(function(pdfPage) { + var pageNum = pdfPage.pageNumber; + var pageView = pages[pageNum - 1]; + if (!pageView.pdfPage) { + // The pdfPage might already be set if we've already entered + // pageView.draw() + pageView.setPdfPage(pdfPage); + } + var thumbnailView = thumbnails[pageNum - 1]; + if (!thumbnailView.pdfPage) { + thumbnailView.setPdfPage(pdfPage); + } + + var pageRef = pdfPage.ref; + var refStr = pageRef.num + ' ' + pageRef.gen + ' R'; + pagesRefMap[refStr] = pdfPage.pageNumber; + }); + pagePromises.push(pagePromise); + } + + PDFJS.Promise.all(pagePromises).then(function(pages) { + pagesPromise.resolve(pages); + }); + }); + + var storePromise = store.initializedPromise; + PDFJS.Promise.all([firstPagePromise, storePromise]).then(function() { + var storedHash = null; + if (store.get('exists', false)) { + var pageNum = store.get('page', '1'); + var zoom = store.get('zoom', PDFView.currentScale); + var left = store.get('scrollLeft', '0'); + var top = store.get('scrollTop', '0'); + + storedHash = 'page=' + pageNum + '&zoom=' + zoom + ',' + + left + ',' + top; + } + self.setInitialView(storedHash, scale); + }); + + pagesPromise.then(function() { + if (PDFView.supportsPrinting) { + pdfDocument.getJavaScript().then(function(javaScript) { + if (javaScript.length) { + console.warn('Warning: JavaScript is not supported'); + PDFView.fallback(); + } + // Hack to support auto printing. + var regex = /\bprint\s*\(/g; + for (var i = 0, ii = javaScript.length; i < ii; i++) { + var js = javaScript[i]; + if (js && regex.test(js)) { + setTimeout(function() { + window.print(); + }); + return; + } + } + }); + } + }); + + var destinationsPromise = pdfDocument.getDestinations(); + destinationsPromise.then(function(destinations) { + self.destinations = destinations; + }); + + // outline depends on destinations and pagesRefMap + var promises = [pagesPromise, destinationsPromise, + PDFView.animationStartedPromise]; + PDFJS.Promise.all(promises).then(function() { + pdfDocument.getOutline().then(function(outline) { + self.outline = new DocumentOutlineView(outline); + }); + + // Make all navigation keys work on document load, + // unless the viewer is embedded in another page. + if (window.parent.location === window.location) { + PDFView.container.focus(); + } + }); + + pdfDocument.getMetadata().then(function(data) { + var info = data.info, metadata = data.metadata; + self.documentInfo = info; + self.metadata = metadata; + + // Provides some basic debug information + console.log('PDF ' + pdfDocument.fingerprint + ' [' + + info.PDFFormatVersion + ' ' + (info.Producer || '-') + + ' / ' + (info.Creator || '-') + ']' + + (PDFJS.version ? ' (PDF.js: ' + PDFJS.version + ')' : '')); + + var pdfTitle; + if (metadata) { + if (metadata.has('dc:title')) + pdfTitle = metadata.get('dc:title'); + } + + if (!pdfTitle && info && info['Title']) + pdfTitle = info['Title']; + + if (pdfTitle) + self.setTitle(pdfTitle + ' - ' + document.title); + + if (info.IsAcroFormPresent) { + console.warn('Warning: AcroForm/XFA is not supported'); + PDFView.fallback(); + } + }); + }, + + setInitialView: function pdfViewSetInitialView(storedHash, scale) { + // Reset the current scale, as otherwise the page's scale might not get + // updated if the zoom level stayed the same. + this.currentScale = 0; + this.currentScaleValue = null; + if (this.initialBookmark) { + this.setHash(this.initialBookmark); + this.initialBookmark = null; + } + else if (storedHash) + this.setHash(storedHash); + else if (scale) { + this.parseScale(scale, true); + this.page = 1; + } + + if (PDFView.currentScale === UNKNOWN_SCALE) { + // Scale was not initialized: invalid bookmark or scale was not specified. + // Setting the default one. + this.parseScale(DEFAULT_SCALE, true); + } + }, + + renderHighestPriority: function pdfViewRenderHighestPriority() { + // Pages have a higher priority than thumbnails, so check them first. + var visiblePages = this.getVisiblePages(); + var pageView = this.getHighestPriority(visiblePages, this.pages, + this.pageViewScroll.down); + if (pageView) { + this.renderView(pageView, 'page'); + return; + } + // No pages needed rendering so check thumbnails. + if (this.sidebarOpen) { + var visibleThumbs = this.getVisibleThumbs(); + var thumbView = this.getHighestPriority(visibleThumbs, + this.thumbnails, + this.thumbnailViewScroll.down); + if (thumbView) + this.renderView(thumbView, 'thumbnail'); + } + }, + + getHighestPriority: function pdfViewGetHighestPriority(visible, views, + scrolledDown) { + // The state has changed figure out which page has the highest priority to + // render next (if any). + // Priority: + // 1 visible pages + // 2 if last scrolled down page after the visible pages + // 2 if last scrolled up page before the visible pages + var visibleViews = visible.views; + + var numVisible = visibleViews.length; + if (numVisible === 0) { + return false; + } + for (var i = 0; i < numVisible; ++i) { + var view = visibleViews[i].view; + if (!this.isViewFinished(view)) + return view; + } + + // All the visible views have rendered, try to render next/previous pages. + if (scrolledDown) { + var nextPageIndex = visible.last.id; + // ID's start at 1 so no need to add 1. + if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) + return views[nextPageIndex]; + } else { + var previousPageIndex = visible.first.id - 2; + if (views[previousPageIndex] && + !this.isViewFinished(views[previousPageIndex])) + return views[previousPageIndex]; + } + // Everything that needs to be rendered has been. + return false; + }, + + isViewFinished: function pdfViewNeedsRendering(view) { + return view.renderingState === RenderingStates.FINISHED; + }, + + // Render a page or thumbnail view. This calls the appropriate function based + // on the views state. If the view is already rendered it will return false. + renderView: function pdfViewRender(view, type) { + var state = view.renderingState; + switch (state) { + case RenderingStates.FINISHED: + return false; + case RenderingStates.PAUSED: + PDFView.highestPriorityPage = type + view.id; + view.resume(); + break; + case RenderingStates.RUNNING: + PDFView.highestPriorityPage = type + view.id; + break; + case RenderingStates.INITIAL: + PDFView.highestPriorityPage = type + view.id; + view.draw(this.renderHighestPriority.bind(this)); + break; + } + return true; + }, + + setHash: function pdfViewSetHash(hash) { + if (!hash) + return; + + if (hash.indexOf('=') >= 0) { + var params = PDFView.parseQueryString(hash); + // borrowing syntax from "Parameters for Opening PDF Files" + if ('nameddest' in params) { + PDFView.navigateTo(params.nameddest); + return; + } + if ('page' in params) { + var pageNumber = (params.page | 0) || 1; + if ('zoom' in params) { + var zoomArgs = params.zoom.split(','); // scale,left,top + // building destination array + + // If the zoom value, it has to get divided by 100. If it is a string, + // it should stay as it is. + var zoomArg = zoomArgs[0]; + var zoomArgNumber = parseFloat(zoomArg); + if (zoomArgNumber) + zoomArg = zoomArgNumber / 100; + + var dest = [null, {name: 'XYZ'}, + zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null, + zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null, + zoomArg]; + var currentPage = this.pages[pageNumber - 1]; + currentPage.scrollIntoView(dest); + } else { + this.page = pageNumber; // simple page + } + } + if ('pagemode' in params) { + var toggle = document.getElementById('sidebarToggle'); + if (params.pagemode === 'thumbs' || params.pagemode === 'bookmarks') { + if (!this.sidebarOpen) { + toggle.click(); + } + this.switchSidebarView(params.pagemode === 'thumbs' ? + 'thumbs' : 'outline'); + } else if (params.pagemode === 'none' && this.sidebarOpen) { + toggle.click(); + } + } + } else if (/^\d+$/.test(hash)) // page number + this.page = hash; + else // named destination + PDFView.navigateTo(unescape(hash)); + }, + + switchSidebarView: function pdfViewSwitchSidebarView(view) { + var thumbsView = document.getElementById('thumbnailView'); + var outlineView = document.getElementById('outlineView'); + + var thumbsButton = document.getElementById('viewThumbnail'); + var outlineButton = document.getElementById('viewOutline'); + + switch (view) { + case 'thumbs': + var wasOutlineViewVisible = thumbsView.classList.contains('hidden'); + + thumbsButton.classList.add('toggled'); + outlineButton.classList.remove('toggled'); + thumbsView.classList.remove('hidden'); + outlineView.classList.add('hidden'); + + PDFView.renderHighestPriority(); + + if (wasOutlineViewVisible) { + // Ensure that the thumbnail of the current page is visible + // when switching from the outline view. + scrollIntoView(document.getElementById('thumbnailContainer' + + this.page)); + } + break; + + case 'outline': + thumbsButton.classList.remove('toggled'); + outlineButton.classList.add('toggled'); + thumbsView.classList.add('hidden'); + outlineView.classList.remove('hidden'); + + if (outlineButton.getAttribute('disabled')) + return; + break; + } + }, + + getVisiblePages: function pdfViewGetVisiblePages() { + if (!this.isFullscreen) { + return this.getVisibleElements(this.container, this.pages, true); + } else { + // The algorithm in getVisibleElements is broken in fullscreen mode. + var visible = [], page = this.page; + var currentPage = this.pages[page - 1]; + visible.push({ id: currentPage.id, view: currentPage }); + + return { first: currentPage, last: currentPage, views: visible}; + } + }, + + getVisibleThumbs: function pdfViewGetVisibleThumbs() { + return this.getVisibleElements(this.thumbnailContainer, this.thumbnails); + }, + + // Generic helper to find out what elements are visible within a scroll pane. + getVisibleElements: function pdfViewGetVisibleElements( + scrollEl, views, sortByVisibility) { + var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight; + var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth; + + var visible = [], view; + var currentHeight, viewHeight, hiddenHeight, percentHeight; + var currentWidth, viewWidth; + for (var i = 0, ii = views.length; i < ii; ++i) { + view = views[i]; + currentHeight = view.el.offsetTop + view.el.clientTop; + viewHeight = view.el.clientHeight; + if ((currentHeight + viewHeight) < top) { + continue; + } + if (currentHeight > bottom) { + break; + } + currentWidth = view.el.offsetLeft + view.el.clientLeft; + viewWidth = view.el.clientWidth; + if ((currentWidth + viewWidth) < left || currentWidth > right) { + continue; + } + hiddenHeight = Math.max(0, top - currentHeight) + + Math.max(0, currentHeight + viewHeight - bottom); + percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0; + + visible.push({ id: view.id, y: currentHeight, + view: view, percent: percentHeight }); + } + + var first = visible[0]; + var last = visible[visible.length - 1]; + + if (sortByVisibility) { + visible.sort(function(a, b) { + var pc = a.percent - b.percent; + if (Math.abs(pc) > 0.001) { + return -pc; + } + return a.id - b.id; // ensure stability + }); + } + return {first: first, last: last, views: visible}; + }, + + // Helper function to parse query string (e.g. ?param1=value&parm2=...). + parseQueryString: function pdfViewParseQueryString(query) { + var parts = query.split('&'); + var params = {}; + for (var i = 0, ii = parts.length; i < parts.length; ++i) { + var param = parts[i].split('='); + var key = param[0]; + var value = param.length > 1 ? param[1] : null; + params[unescape(key)] = unescape(value); + } + return params; + }, + + beforePrint: function pdfViewSetupBeforePrint() { + if (!this.supportsPrinting) { + var printMessage = mozL10n.get('printing_not_supported', null, + 'Warning: Printing is not fully supported by this browser.'); + this.error(printMessage); + return; + } + + var alertNotReady = false; + if (!this.pages.length) { + alertNotReady = true; + } else { + for (var i = 0, ii = this.pages.length; i < ii; ++i) { + if (!this.pages[i].pdfPage) { + alertNotReady = true; + break; + } + } + } + if (alertNotReady) { + var notReadyMessage = mozL10n.get('printing_not_ready', null, + 'Warning: The PDF is not fully loaded for printing.'); + window.alert(notReadyMessage); + return; + } + + var body = document.querySelector('body'); + body.setAttribute('data-mozPrintCallback', true); + for (var i = 0, ii = this.pages.length; i < ii; ++i) { + this.pages[i].beforePrint(); + } + }, + + afterPrint: function pdfViewSetupAfterPrint() { + var div = document.getElementById('printContainer'); + while (div.hasChildNodes()) + div.removeChild(div.lastChild); + }, + + fullscreen: function pdfViewFullscreen() { + var isFullscreen = document.fullscreenElement || document.mozFullScreen || + document.webkitIsFullScreen; + + if (isFullscreen) { + return false; + } + + var wrapper = document.getElementById('viewerContainer'); + if (document.documentElement.requestFullscreen) { + wrapper.requestFullscreen(); + } else if (document.documentElement.mozRequestFullScreen) { + wrapper.mozRequestFullScreen(); + } else if (document.documentElement.webkitRequestFullScreen) { + wrapper.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); + } else { + return false; + } + + this.isFullscreen = true; + var currentPage = this.pages[this.page - 1]; + this.previousScale = this.currentScaleValue; + this.parseScale('page-fit', true); + + // Wait for fullscreen to take effect + setTimeout(function() { + currentPage.scrollIntoView(); + }, 0); + + this.showPresentationControls(); + return true; + }, + + exitFullscreen: function pdfViewExitFullscreen() { + this.isFullscreen = false; + this.parseScale(this.previousScale); + this.page = this.page; + this.clearMouseScrollState(); + this.hidePresentationControls(); + + // Ensure that the thumbnail of the current page is visible + // when exiting fullscreen mode. + scrollIntoView(document.getElementById('thumbnailContainer' + this.page)); + }, + + showPresentationControls: function pdfViewShowPresentationControls() { + var DELAY_BEFORE_HIDING_CONTROLS = 3000; + var wrapper = document.getElementById('viewerContainer'); + if (this.presentationControlsTimeout) { + clearTimeout(this.presentationControlsTimeout); + } else { + wrapper.classList.add('presentationControls'); + } + this.presentationControlsTimeout = setTimeout(function hideControls() { + wrapper.classList.remove('presentationControls'); + delete PDFView.presentationControlsTimeout; + }, DELAY_BEFORE_HIDING_CONTROLS); + }, + + hidePresentationControls: function pdfViewShowPresentationControls() { + if (!this.presentationControlsTimeout) { + return; + } + clearTimeout(this.presentationControlsTimeout); + delete this.presentationControlsTimeout; + + var wrapper = document.getElementById('viewerContainer'); + wrapper.classList.remove('presentationControls'); + }, + + rotatePages: function pdfViewPageRotation(delta) { + + this.pageRotation = (this.pageRotation + 360 + delta) % 360; + + for (var i = 0, l = this.pages.length; i < l; i++) { + var page = this.pages[i]; + page.update(page.scale, this.pageRotation); + } + + for (var i = 0, l = this.thumbnails.length; i < l; i++) { + var thumb = this.thumbnails[i]; + thumb.update(this.pageRotation); + } + + this.parseScale(this.currentScaleValue, true); + + this.renderHighestPriority(); + + var currentPage = this.pages[this.page - 1]; + if (!currentPage) { + return; + } + + // Wait for fullscreen to take effect + setTimeout(function() { + currentPage.scrollIntoView(); + }, 0); + }, + + /** + * This function flips the page in presentation mode if the user scrolls up + * or down with large enough motion and prevents page flipping too often. + * + * @this {PDFView} + * @param {number} mouseScrollDelta The delta value from the mouse event. + */ + mouseScroll: function pdfViewMouseScroll(mouseScrollDelta) { + var MOUSE_SCROLL_COOLDOWN_TIME = 50; + + var currentTime = (new Date()).getTime(); + var storedTime = this.mouseScrollTimeStamp; + + // In case one page has already been flipped there is a cooldown time + // which has to expire before next page can be scrolled on to. + if (currentTime > storedTime && + currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) + return; + + // In case the user decides to scroll to the opposite direction than before + // clear the accumulated delta. + if ((this.mouseScrollDelta > 0 && mouseScrollDelta < 0) || + (this.mouseScrollDelta < 0 && mouseScrollDelta > 0)) + this.clearMouseScrollState(); + + this.mouseScrollDelta += mouseScrollDelta; + + var PAGE_FLIP_THRESHOLD = 120; + if (Math.abs(this.mouseScrollDelta) >= PAGE_FLIP_THRESHOLD) { + + var PageFlipDirection = { + UP: -1, + DOWN: 1 + }; + + // In fullscreen mode scroll one page at a time. + var pageFlipDirection = (this.mouseScrollDelta > 0) ? + PageFlipDirection.UP : + PageFlipDirection.DOWN; + this.clearMouseScrollState(); + var currentPage = this.page; + + // In case we are already on the first or the last page there is no need + // to do anything. + if ((currentPage == 1 && pageFlipDirection == PageFlipDirection.UP) || + (currentPage == this.pages.length && + pageFlipDirection == PageFlipDirection.DOWN)) + return; + + this.page += pageFlipDirection; + this.mouseScrollTimeStamp = currentTime; + } + }, + + /** + * This function clears the member attributes used with mouse scrolling in + * presentation mode. + * + * @this {PDFView} + */ + clearMouseScrollState: function pdfViewClearMouseScrollState() { + this.mouseScrollTimeStamp = 0; + this.mouseScrollDelta = 0; + } +}; + +var PageView = function pageView(container, id, scale, + navigateTo, defaultViewport) { + this.id = id; + + this.rotation = 0; + this.scale = scale || 1.0; + this.viewport = defaultViewport; + this.pdfPageRotate = defaultViewport.rotate; + + this.renderingState = RenderingStates.INITIAL; + this.resume = null; + + this.textContent = null; + this.textLayer = null; + + var anchor = document.createElement('a'); + anchor.name = '' + this.id; + + var div = this.el = document.createElement('div'); + div.id = 'pageContainer' + this.id; + div.className = 'page'; + div.style.width = Math.floor(this.viewport.width) + 'px'; + div.style.height = Math.floor(this.viewport.height) + 'px'; + + container.appendChild(anchor); + container.appendChild(div); + + this.setPdfPage = function pageViewSetPdfPage(pdfPage) { + this.pdfPage = pdfPage; + this.pdfPageRotate = pdfPage.rotate; + this.viewport = pdfPage.getViewport(this.scale); + this.stats = pdfPage.stats; + this.update(); + }; + + this.destroy = function pageViewDestroy() { + this.update(); + if (this.pdfPage) { + this.pdfPage.destroy(); + } + }; + + this.update = function pageViewUpdate(scale, rotation) { + this.renderingState = RenderingStates.INITIAL; + this.resume = null; + + if (typeof rotation !== 'undefined') { + this.rotation = rotation; + } + + this.scale = scale || this.scale; + + var totalRotation = (this.rotation + this.pdfPageRotate) % 360; + this.viewport = this.viewport.clone({ + scale: this.scale, + rotation: totalRotation + }); + + div.style.width = Math.floor(this.viewport.width) + 'px'; + div.style.height = Math.floor(this.viewport.height) + 'px'; + + while (div.hasChildNodes()) + div.removeChild(div.lastChild); + div.removeAttribute('data-loaded'); + + delete this.canvas; + + this.loadingIconDiv = document.createElement('div'); + this.loadingIconDiv.className = 'loadingIcon'; + div.appendChild(this.loadingIconDiv); + }; + + Object.defineProperty(this, 'width', { + get: function PageView_getWidth() { + return this.viewport.width; + }, + enumerable: true + }); + + Object.defineProperty(this, 'height', { + get: function PageView_getHeight() { + return this.viewport.height; + }, + enumerable: true + }); + + function setupAnnotations(pdfPage, viewport) { + function bindLink(link, dest) { + link.href = PDFView.getDestinationHash(dest); + link.onclick = function pageViewSetupLinksOnclick() { + if (dest) + PDFView.navigateTo(dest); + return false; + }; + } + function createElementWithStyle(tagName, item, rect) { + if (!rect) { + rect = viewport.convertToViewportRectangle(item.rect); + rect = PDFJS.Util.normalizeRect(rect); + } + var element = document.createElement(tagName); + element.style.left = Math.floor(rect[0]) + 'px'; + element.style.top = Math.floor(rect[1]) + 'px'; + element.style.width = Math.ceil(rect[2] - rect[0]) + 'px'; + element.style.height = Math.ceil(rect[3] - rect[1]) + 'px'; + return element; + } + function createTextAnnotation(item) { + var container = document.createElement('section'); + container.className = 'annotText'; + + var rect = viewport.convertToViewportRectangle(item.rect); + rect = PDFJS.Util.normalizeRect(rect); + // sanity check because of OOo-generated PDFs + if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) { + rect[3] = rect[1] + ANNOT_MIN_SIZE; + } + if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) { + rect[2] = rect[0] + (rect[3] - rect[1]); // make it square + } + var image = createElementWithStyle('img', item, rect); + var iconName = item.name; + image.src = IMAGE_DIR + 'annotation-' + + iconName.toLowerCase() + '.svg'; + image.alt = mozL10n.get('text_annotation_type', {type: iconName}, + '[{{type}} Annotation]'); + var content = document.createElement('div'); + content.setAttribute('hidden', true); + var title = document.createElement('h1'); + var text = document.createElement('p'); + content.style.left = Math.floor(rect[2]) + 'px'; + content.style.top = Math.floor(rect[1]) + 'px'; + title.textContent = item.title; + + if (!item.content && !item.title) { + content.setAttribute('hidden', true); + } else { + var e = document.createElement('span'); + var lines = item.content.split(/(?:\r\n?|\n)/); + for (var i = 0, ii = lines.length; i < ii; ++i) { + var line = lines[i]; + e.appendChild(document.createTextNode(line)); + if (i < (ii - 1)) + e.appendChild(document.createElement('br')); + } + text.appendChild(e); + image.addEventListener('mouseover', function annotationImageOver() { + content.removeAttribute('hidden'); + }, false); + + image.addEventListener('mouseout', function annotationImageOut() { + content.setAttribute('hidden', true); + }, false); + } + + content.appendChild(title); + content.appendChild(text); + container.appendChild(image); + container.appendChild(content); + + return container; + } + + pdfPage.getAnnotations().then(function(items) { + for (var i = 0; i < items.length; i++) { + var item = items[i]; + switch (item.type) { + case 'Link': + var link = createElementWithStyle('a', item); + link.href = item.url || ''; + if (!item.url) + bindLink(link, ('dest' in item) ? item.dest : null); + div.appendChild(link); + break; + case 'Text': + var textAnnotation = createTextAnnotation(item); + if (textAnnotation) + div.appendChild(textAnnotation); + break; + } + } + }); + } + + this.getPagePoint = function pageViewGetPagePoint(x, y) { + return this.viewport.convertToPdfPoint(x, y); + }; + + this.scrollIntoView = function pageViewScrollIntoView(dest) { + if (!dest) { + scrollIntoView(div); + return; + } + + var x = 0, y = 0; + var width = 0, height = 0, widthScale, heightScale; + var scale = 0; + switch (dest[1].name) { + case 'XYZ': + x = dest[2]; + y = dest[3]; + scale = dest[4]; + // If x and/or y coordinates are not supplied, default to + // _top_ left of the page (not the obvious bottom left, + // since aligning the bottom of the intended page with the + // top of the window is rarely helpful). + x = x !== null ? x : 0; + y = y !== null ? y : this.height / this.scale; + break; + case 'Fit': + case 'FitB': + scale = 'page-fit'; + break; + case 'FitH': + case 'FitBH': + y = dest[2]; + scale = 'page-width'; + break; + case 'FitV': + case 'FitBV': + x = dest[2]; + scale = 'page-height'; + break; + case 'FitR': + x = dest[2]; + y = dest[3]; + width = dest[4] - x; + height = dest[5] - y; + widthScale = (this.container.clientWidth - SCROLLBAR_PADDING) / + width / CSS_UNITS; + heightScale = (this.container.clientHeight - SCROLLBAR_PADDING) / + height / CSS_UNITS; + scale = Math.min(widthScale, heightScale); + break; + default: + return; + } + + if (scale && scale !== PDFView.currentScale) + PDFView.parseScale(scale, true, true); + else if (PDFView.currentScale === UNKNOWN_SCALE) + PDFView.parseScale(DEFAULT_SCALE, true, true); + + var boundingRect = [ + this.viewport.convertToViewportPoint(x, y), + this.viewport.convertToViewportPoint(x + width, y + height) + ]; + setTimeout(function pageViewScrollIntoViewRelayout() { + // letting page to re-layout before scrolling + var scale = PDFView.currentScale; + var x = Math.min(boundingRect[0][0], boundingRect[1][0]); + var y = Math.min(boundingRect[0][1], boundingRect[1][1]); + var width = Math.abs(boundingRect[0][0] - boundingRect[1][0]); + var height = Math.abs(boundingRect[0][1] - boundingRect[1][1]); + + scrollIntoView(div, {left: x, top: y, width: width, height: height}); + }, 0); + }; + + this.getTextContent = function pageviewGetTextContent() { + if (!this.textContent) { + this.textContent = this.pdfPage.getTextContent(); + } + return this.textContent; + }; + + this.draw = function pageviewDraw(callback) { + var pdfPage = this.pdfPage; + + if (!pdfPage) { + var promise = PDFView.getPage(this.id); + promise.then(function(pdfPage) { + this.setPdfPage(pdfPage); + this.draw(callback); + }.bind(this)); + return; + } + + if (this.renderingState !== RenderingStates.INITIAL) { + console.error('Must be in new state before drawing'); + } + + this.renderingState = RenderingStates.RUNNING; + + var canvas = document.createElement('canvas'); + canvas.id = 'page' + this.id; + div.appendChild(canvas); + this.canvas = canvas; + + var scale = this.scale, viewport = this.viewport; + var outputScale = PDFView.getOutputScale(); + canvas.width = Math.floor(viewport.width) * outputScale.sx; + canvas.height = Math.floor(viewport.height) * outputScale.sy; + + var textLayerDiv = null; + if (!PDFJS.disableTextLayer) { + textLayerDiv = document.createElement('div'); + textLayerDiv.className = 'textLayer'; + textLayerDiv.style.width = canvas.width + 'px'; + textLayerDiv.style.height = canvas.height + 'px'; + div.appendChild(textLayerDiv); + } + var textLayer = this.textLayer = + textLayerDiv ? new TextLayerBuilder(textLayerDiv, this.id - 1) : null; + + if (outputScale.scaled) { + var cssScale = 'scale(' + (1 / outputScale.sx) + ', ' + + (1 / outputScale.sy) + ')'; + CustomStyle.setProp('transform' , canvas, cssScale); + CustomStyle.setProp('transformOrigin' , canvas, '0% 0%'); + if (textLayerDiv) { + CustomStyle.setProp('transform' , textLayerDiv, cssScale); + CustomStyle.setProp('transformOrigin' , textLayerDiv, '0% 0%'); + } + } + + var ctx = canvas.getContext('2d'); + ctx.clearRect(0, 0, canvas.width, canvas.height); + // TODO(mack): use data attributes to store these + ctx._scaleX = outputScale.sx; + ctx._scaleY = outputScale.sy; + if (outputScale.scaled) { + ctx.scale(outputScale.sx, outputScale.sy); + } +//#if (FIREFOX || MOZCENTRAL) +// // Checking if document fonts are used only once +// var checkIfDocumentFontsUsed = !PDFView.pdfDocument.embeddedFontsUsed; +//#endif + + // Rendering area + + var self = this; + var renderingWasReset = false; + function pageViewDrawCallback(error) { + if (renderingWasReset) { + return; + } + + self.renderingState = RenderingStates.FINISHED; + + if (self.loadingIconDiv) { + div.removeChild(self.loadingIconDiv); + delete self.loadingIconDiv; + } + +//#if (FIREFOX || MOZCENTRAL) +// if (checkIfDocumentFontsUsed && PDFView.pdfDocument.embeddedFontsUsed && +// !PDFView.supportsDocumentFonts) { +// console.error(mozL10n.get('web_fonts_disabled', null, +// 'Web fonts are disabled: unable to use embedded PDF fonts.')); +// PDFView.fallback(); +// } +//#endif + if (error) { + PDFView.error(mozL10n.get('rendering_error', null, + 'An error occurred while rendering the page.'), error); + } + + self.stats = pdfPage.stats; + self.updateStats(); + if (self.onAfterDraw) + self.onAfterDraw(); + + cache.push(self); + + var event = document.createEvent('CustomEvent'); + event.initCustomEvent('pagerender', true, true, { + pageNumber: pdfPage.pageNumber + }); + div.dispatchEvent(event); + + callback(); + } + + var renderContext = { + canvasContext: ctx, + viewport: this.viewport, + textLayer: textLayer, + continueCallback: function pdfViewcContinueCallback(cont) { + if (self.renderingState === RenderingStates.INITIAL) { + // The page update() was called, we just need to abort any rendering. + renderingWasReset = true; + return; + } + + if (PDFView.highestPriorityPage !== 'page' + self.id) { + self.renderingState = RenderingStates.PAUSED; + self.resume = function resumeCallback() { + self.renderingState = RenderingStates.RUNNING; + cont(); + }; + return; + } + cont(); + } + }; + this.pdfPage.render(renderContext).then( + function pdfPageRenderCallback() { + pageViewDrawCallback(null); + }, + function pdfPageRenderError(error) { + pageViewDrawCallback(error); + } + ); + + if (textLayer) { + this.getTextContent().then( + function textContentResolved(textContent) { + textLayer.setTextContent(textContent); + } + ); + } + + setupAnnotations(this.pdfPage, this.viewport); + div.setAttribute('data-loaded', true); + }; + + this.beforePrint = function pageViewBeforePrint() { + var pdfPage = this.pdfPage; + + var viewport = pdfPage.getViewport(1); + // Use the same hack we use for high dpi displays for printing to get better + // output until bug 811002 is fixed in FF. + var PRINT_OUTPUT_SCALE = 2; + var canvas = this.canvas = document.createElement('canvas'); + canvas.width = Math.floor(viewport.width) * PRINT_OUTPUT_SCALE; + canvas.height = Math.floor(viewport.height) * PRINT_OUTPUT_SCALE; + canvas.style.width = (PRINT_OUTPUT_SCALE * viewport.width) + 'pt'; + canvas.style.height = (PRINT_OUTPUT_SCALE * viewport.height) + 'pt'; + var cssScale = 'scale(' + (1 / PRINT_OUTPUT_SCALE) + ', ' + + (1 / PRINT_OUTPUT_SCALE) + ')'; + CustomStyle.setProp('transform' , canvas, cssScale); + CustomStyle.setProp('transformOrigin' , canvas, '0% 0%'); + + var printContainer = document.getElementById('printContainer'); + printContainer.appendChild(canvas); + + var self = this; + canvas.mozPrintCallback = function(obj) { + var ctx = obj.context; + + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.restore(); + ctx.scale(PRINT_OUTPUT_SCALE, PRINT_OUTPUT_SCALE); + + var renderContext = { + canvasContext: ctx, + viewport: viewport + }; + + pdfPage.render(renderContext).then(function() { + // Tell the printEngine that rendering this canvas/page has finished. + obj.done(); + self.pdfPage.destroy(); + }, function(error) { + console.error(error); + // Tell the printEngine that rendering this canvas/page has failed. + // This will make the print proces stop. + if ('abort' in obj) + obj.abort(); + else + obj.done(); + self.pdfPage.destroy(); + }); + }; + }; + + this.updateStats = function pageViewUpdateStats() { + if (!this.stats) { + return; + } + + if (PDFJS.pdfBug && Stats.enabled) { + var stats = this.stats; + Stats.add(this.id, stats); + } + }; +}; + +var ThumbnailView = function thumbnailView(container, id, defaultViewport) { + var anchor = document.createElement('a'); + anchor.href = PDFView.getAnchorUrl('#page=' + id); + anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}'); + anchor.onclick = function stopNavigation() { + PDFView.page = id; + return false; + }; + + + this.pdfPage = undefined; + this.viewport = defaultViewport; + this.pdfPageRotate = defaultViewport.rotate; + + this.rotation = 0; + this.pageWidth = this.viewport.width; + this.pageHeight = this.viewport.height; + this.pageRatio = this.pageWidth / this.pageHeight; + this.id = id; + + this.canvasWidth = 98; + this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight; + this.scale = (this.canvasWidth / this.pageWidth); + + var div = this.el = document.createElement('div'); + div.id = 'thumbnailContainer' + id; + div.className = 'thumbnail'; + + if (id === 1) { + // Highlight the thumbnail of the first page when no page number is + // specified (or exists in cache) when the document is loaded. + div.classList.add('selected'); + } + + var ring = document.createElement('div'); + ring.className = 'thumbnailSelectionRing'; + ring.style.width = this.canvasWidth + 'px'; + ring.style.height = this.canvasHeight + 'px'; + + div.appendChild(ring); + anchor.appendChild(div); + container.appendChild(anchor); + + this.hasImage = false; + this.renderingState = RenderingStates.INITIAL; + + this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) { + this.pdfPage = pdfPage; + this.pdfPageRotate = pdfPage.rotate; + this.viewport = pdfPage.getViewport(1); + this.update(); + }; + + this.update = function thumbnailViewUpdate(rot) { + if (!this.pdfPage) { + return; + } + + if (rot !== undefined) { + this.rotation = rot; + } + + var totalRotation = (this.rotation + this.pdfPage.rotate) % 360; + this.viewport = this.viewport.clone({ + scale: 1, + rotation: totalRotation + }); + this.pageWidth = this.viewport.width; + this.pageHeight = this.viewport.height; + this.pageRatio = this.pageWidth / this.pageHeight; + + this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight; + this.scale = (this.canvasWidth / this.pageWidth); + + div.removeAttribute('data-loaded'); + ring.textContent = ''; + ring.style.width = this.canvasWidth + 'px'; + ring.style.height = this.canvasHeight + 'px'; + + this.hasImage = false; + this.renderingState = RenderingStates.INITIAL; + this.resume = null; + }; + + this.getPageDrawContext = function thumbnailViewGetPageDrawContext() { + var canvas = document.createElement('canvas'); + canvas.id = 'thumbnail' + id; + + canvas.width = this.canvasWidth; + canvas.height = this.canvasHeight; + canvas.className = 'thumbnailImage'; + canvas.setAttribute('aria-label', mozL10n.get('thumb_page_canvas', + {page: id}, 'Thumbnail of Page {{page}}')); + + div.setAttribute('data-loaded', true); + + ring.appendChild(canvas); + + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight); + ctx.restore(); + return ctx; + }; + + this.drawingRequired = function thumbnailViewDrawingRequired() { + return !this.hasImage; + }; + + this.draw = function thumbnailViewDraw(callback) { + if (!this.pdfPage) { + var promise = PDFView.getPage(this.id); + promise.then(function(pdfPage) { + this.setPdfPage(pdfPage); + this.draw(callback); + }.bind(this)); + return; + } + + if (this.renderingState !== RenderingStates.INITIAL) { + console.error('Must be in new state before drawing'); + } + + this.renderingState = RenderingStates.RUNNING; + if (this.hasImage) { + callback(); + return; + } + + var self = this; + var ctx = this.getPageDrawContext(); + var drawViewport = this.viewport.clone({ scale: this.scale }); + var renderContext = { + canvasContext: ctx, + viewport: drawViewport, + continueCallback: function(cont) { + if (PDFView.highestPriorityPage !== 'thumbnail' + self.id) { + self.renderingState = RenderingStates.PAUSED; + self.resume = function() { + self.renderingState = RenderingStates.RUNNING; + cont(); + }; + return; + } + cont(); + } + }; + this.pdfPage.render(renderContext).then( + function pdfPageRenderCallback() { + self.renderingState = RenderingStates.FINISHED; + callback(); + }, + function pdfPageRenderError(error) { + self.renderingState = RenderingStates.FINISHED; + callback(); + } + ); + this.hasImage = true; + }; + + this.setImage = function thumbnailViewSetImage(img) { + if (this.hasImage || !img) + return; + this.renderingState = RenderingStates.FINISHED; + var ctx = this.getPageDrawContext(); + ctx.drawImage(img, 0, 0, img.width, img.height, + 0, 0, ctx.canvas.width, ctx.canvas.height); + + this.hasImage = true; + }; +}; + +var DocumentOutlineView = function documentOutlineView(outline) { + var outlineView = document.getElementById('outlineView'); + while (outlineView.firstChild) + outlineView.removeChild(outlineView.firstChild); + + function bindItemLink(domObj, item) { + domObj.href = PDFView.getDestinationHash(item.dest); + domObj.onclick = function documentOutlineViewOnclick(e) { + PDFView.navigateTo(item.dest); + return false; + }; + } + + if (!outline) { + var noOutline = document.createElement('div'); + noOutline.classList.add('noOutline'); + noOutline.textContent = mozL10n.get('no_outline', null, + 'No Outline Available'); + outlineView.appendChild(noOutline); + return; + } + + var queue = [{parent: outlineView, items: outline}]; + while (queue.length > 0) { + var levelData = queue.shift(); + var i, n = levelData.items.length; + for (i = 0; i < n; i++) { + var item = levelData.items[i]; + var div = document.createElement('div'); + div.className = 'outlineItem'; + var a = document.createElement('a'); + bindItemLink(a, item); + a.textContent = item.title; + div.appendChild(a); + + if (item.items.length > 0) { + var itemsDiv = document.createElement('div'); + itemsDiv.className = 'outlineItems'; + div.appendChild(itemsDiv); + queue.push({parent: itemsDiv, items: item.items}); + } + + levelData.parent.appendChild(div); + } + } +}; + +// optimised CSS custom property getter/setter +var CustomStyle = (function CustomStyleClosure() { + + // As noted on: http://www.zachstronaut.com/posts/2009/02/17/ + // animate-css-transforms-firefox-webkit.html + // in some versions of IE9 it is critical that ms appear in this list + // before Moz + var prefixes = ['ms', 'Moz', 'Webkit', 'O']; + var _cache = { }; + + function CustomStyle() { + } + + CustomStyle.getProp = function get(propName, element) { + // check cache only when no element is given + if (arguments.length == 1 && typeof _cache[propName] == 'string') { + return _cache[propName]; + } + + element = element || document.documentElement; + var style = element.style, prefixed, uPropName; + + // test standard property first + if (typeof style[propName] == 'string') { + return (_cache[propName] = propName); + } + + // capitalize + uPropName = propName.charAt(0).toUpperCase() + propName.slice(1); + + // test vendor specific properties + for (var i = 0, l = prefixes.length; i < l; i++) { + prefixed = prefixes[i] + uPropName; + if (typeof style[prefixed] == 'string') { + return (_cache[propName] = prefixed); + } + } + + //if all fails then set to undefined + return (_cache[propName] = 'undefined'); + }; + + CustomStyle.setProp = function set(propName, element, str) { + var prop = this.getProp(propName); + if (prop != 'undefined') + element.style[prop] = str; + }; + + return CustomStyle; +})(); + +var TextLayerBuilder = function textLayerBuilder(textLayerDiv, pageIdx) { + var textLayerFrag = document.createDocumentFragment(); + + this.textLayerDiv = textLayerDiv; + this.layoutDone = false; + this.divContentDone = false; + this.pageIdx = pageIdx; + this.matches = []; + + this.beginLayout = function textLayerBuilderBeginLayout() { + this.textDivs = []; + this.textLayerQueue = []; + this.renderingDone = false; + }; + + this.endLayout = function textLayerBuilderEndLayout() { + this.layoutDone = true; + this.insertDivContent(); + }; + + this.renderLayer = function textLayerBuilderRenderLayer() { + var self = this; + var textDivs = this.textDivs; + var bidiTexts = this.textContent.bidiTexts; + var textLayerDiv = this.textLayerDiv; + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + + // No point in rendering so many divs as it'd make the browser unusable + // even after the divs are rendered + var MAX_TEXT_DIVS_TO_RENDER = 100000; + if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER) + return; + + for (var i = 0, ii = textDivs.length; i < ii; i++) { + var textDiv = textDivs[i]; + if ('isWhitespace' in textDiv.dataset) { + continue; + } + textLayerFrag.appendChild(textDiv); + + ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily; + var width = ctx.measureText(textDiv.textContent).width; + + if (width > 0) { + var textScale = textDiv.dataset.canvasWidth / width; + + var transform = 'scale(' + textScale + ', 1)'; + if (bidiTexts[i].dir === 'ttb') { + transform = 'rotate(90deg) ' + transform; + } + CustomStyle.setProp('transform' , textDiv, transform); + CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%'); + + textLayerDiv.appendChild(textDiv); + } + } + + this.renderingDone = true; + this.updateMatches(); + + textLayerDiv.appendChild(textLayerFrag); + }; + + this.setupRenderLayoutTimer = function textLayerSetupRenderLayoutTimer() { + // Schedule renderLayout() if user has been scrolling, otherwise + // run it right away + var RENDER_DELAY = 200; // in ms + var self = this; + if (Date.now() - PDFView.lastScroll > RENDER_DELAY) { + // Render right away + this.renderLayer(); + } else { + // Schedule + if (this.renderTimer) + clearTimeout(this.renderTimer); + this.renderTimer = setTimeout(function() { + self.setupRenderLayoutTimer(); + }, RENDER_DELAY); + } + }; + + this.appendText = function textLayerBuilderAppendText(geom) { + var textDiv = document.createElement('div'); + + // vScale and hScale already contain the scaling to pixel units + var fontHeight = geom.fontSize * Math.abs(geom.vScale); + textDiv.dataset.canvasWidth = geom.canvasWidth * geom.hScale; + textDiv.dataset.fontName = geom.fontName; + + textDiv.style.fontSize = fontHeight + 'px'; + textDiv.style.fontFamily = geom.fontFamily; + textDiv.style.left = geom.x + 'px'; + textDiv.style.top = (geom.y - fontHeight) + 'px'; + + // The content of the div is set in the `setTextContent` function. + + this.textDivs.push(textDiv); + }; + + this.insertDivContent = function textLayerUpdateTextContent() { + // Only set the content of the divs once layout has finished, the content + // for the divs is available and content is not yet set on the divs. + if (!this.layoutDone || this.divContentDone || !this.textContent) + return; + + this.divContentDone = true; + + var textDivs = this.textDivs; + var bidiTexts = this.textContent.bidiTexts; + + for (var i = 0; i < bidiTexts.length; i++) { + var bidiText = bidiTexts[i]; + var textDiv = textDivs[i]; + if (!/\S/.test(bidiText.str)) { + textDiv.dataset.isWhitespace = true; + continue; + } + + textDiv.textContent = bidiText.str; + // bidiText.dir may be 'ttb' for vertical texts. + textDiv.dir = bidiText.dir === 'rtl' ? 'rtl' : 'ltr'; + } + + this.setupRenderLayoutTimer(); + }; + + this.setTextContent = function textLayerBuilderSetTextContent(textContent) { + this.textContent = textContent; + this.insertDivContent(); + }; + + this.convertMatches = function textLayerBuilderConvertMatches(matches) { + var i = 0; + var iIndex = 0; + var bidiTexts = this.textContent.bidiTexts; + var end = bidiTexts.length - 1; + var queryLen = PDFFindController.state.query.length; + + var lastDivIdx = -1; + var pos; + + var ret = []; + + // Loop over all the matches. + for (var m = 0; m < matches.length; m++) { + var matchIdx = matches[m]; + // # Calculate the begin position. + + // Loop over the divIdxs. + while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) { + iIndex += bidiTexts[i].str.length; + i++; + } + + // TODO: Do proper handling here if something goes wrong. + if (i == bidiTexts.length) { + console.error('Could not find matching mapping'); + } + + var match = { + begin: { + divIdx: i, + offset: matchIdx - iIndex + } + }; + + // # Calculate the end position. + matchIdx += queryLen; + + // Somewhat same array as above, but use a > instead of >= to get the end + // position right. + while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) { + iIndex += bidiTexts[i].str.length; + i++; + } + + match.end = { + divIdx: i, + offset: matchIdx - iIndex + }; + ret.push(match); + } + + return ret; + }; + + this.renderMatches = function textLayerBuilder_renderMatches(matches) { + // Early exit if there is nothing to render. + if (matches.length === 0) { + return; + } + + var bidiTexts = this.textContent.bidiTexts; + var textDivs = this.textDivs; + var prevEnd = null; + var isSelectedPage = this.pageIdx === PDFFindController.selected.pageIdx; + var selectedMatchIdx = PDFFindController.selected.matchIdx; + var highlightAll = PDFFindController.state.highlightAll; + + var infty = { + divIdx: -1, + offset: undefined + }; + + function beginText(begin, className) { + var divIdx = begin.divIdx; + var div = textDivs[divIdx]; + div.textContent = ''; + + var content = bidiTexts[divIdx].str.substring(0, begin.offset); + var node = document.createTextNode(content); + if (className) { + var isSelected = isSelectedPage && + divIdx === selectedMatchIdx; + var span = document.createElement('span'); + span.className = className + (isSelected ? ' selected' : ''); + span.appendChild(node); + div.appendChild(span); + return; + } + div.appendChild(node); + } + + function appendText(from, to, className) { + var divIdx = from.divIdx; + var div = textDivs[divIdx]; + + var content = bidiTexts[divIdx].str.substring(from.offset, to.offset); + var node = document.createTextNode(content); + if (className) { + var span = document.createElement('span'); + span.className = className; + span.appendChild(node); + div.appendChild(span); + return; + } + div.appendChild(node); + } + + function highlightDiv(divIdx, className) { + textDivs[divIdx].className = className; + } + + var i0 = selectedMatchIdx, i1 = i0 + 1, i; + + if (highlightAll) { + i0 = 0; + i1 = matches.length; + } else if (!isSelectedPage) { + // Not highlighting all and this isn't the selected page, so do nothing. + return; + } + + for (i = i0; i < i1; i++) { + var match = matches[i]; + var begin = match.begin; + var end = match.end; + + var isSelected = isSelectedPage && i === selectedMatchIdx; + var highlightSuffix = (isSelected ? ' selected' : ''); + if (isSelected) + scrollIntoView(textDivs[begin.divIdx], {top: -50}); + + // Match inside new div. + if (!prevEnd || begin.divIdx !== prevEnd.divIdx) { + // If there was a previous div, then add the text at the end + if (prevEnd !== null) { + appendText(prevEnd, infty); + } + // clears the divs and set the content until the begin point. + beginText(begin); + } else { + appendText(prevEnd, begin); + } + + if (begin.divIdx === end.divIdx) { + appendText(begin, end, 'highlight' + highlightSuffix); + } else { + appendText(begin, infty, 'highlight begin' + highlightSuffix); + for (var n = begin.divIdx + 1; n < end.divIdx; n++) { + highlightDiv(n, 'highlight middle' + highlightSuffix); + } + beginText(end, 'highlight end' + highlightSuffix); + } + prevEnd = end; + } + + if (prevEnd) { + appendText(prevEnd, infty); + } + }; + + this.updateMatches = function textLayerUpdateMatches() { + // Only show matches, once all rendering is done. + if (!this.renderingDone) + return; + + // Clear out all matches. + var matches = this.matches; + var textDivs = this.textDivs; + var bidiTexts = this.textContent.bidiTexts; + var clearedUntilDivIdx = -1; + + // Clear out all current matches. + for (var i = 0; i < matches.length; i++) { + var match = matches[i]; + var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx); + for (var n = begin; n <= match.end.divIdx; n++) { + var div = textDivs[n]; + div.textContent = bidiTexts[n].str; + div.className = ''; + } + clearedUntilDivIdx = match.end.divIdx + 1; + } + + if (!PDFFindController.active) + return; + + // Convert the matches on the page controller into the match format used + // for the textLayer. + this.matches = matches = + this.convertMatches(PDFFindController.pageMatches[this.pageIdx] || []); + + this.renderMatches(this.matches); + }; +}; + +document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) { + PDFView.initialize(); + var params = PDFView.parseQueryString(document.location.search.substring(1)); + +//#if !(FIREFOX || MOZCENTRAL) + var file = params.file || DEFAULT_URL; +//#else +//var file = window.location.toString() +//#endif + +//#if !(FIREFOX || MOZCENTRAL) + if (!window.File || !window.FileReader || !window.FileList || !window.Blob) { + document.getElementById('openFile').setAttribute('hidden', 'true'); + } else { + document.getElementById('fileInput').value = null; + } +//#else +//document.getElementById('openFile').setAttribute('hidden', 'true'); +//#endif + + // Special debugging flags in the hash section of the URL. + var hash = document.location.hash.substring(1); + var hashParams = PDFView.parseQueryString(hash); + + if ('disableWorker' in hashParams) + PDFJS.disableWorker = (hashParams['disableWorker'] === 'true'); + +//#if !(FIREFOX || MOZCENTRAL) + var locale = navigator.language; + if ('locale' in hashParams) + locale = hashParams['locale']; + mozL10n.setLanguage(locale); +//#endif + + if ('textLayer' in hashParams) { + switch (hashParams['textLayer']) { + case 'off': + PDFJS.disableTextLayer = true; + break; + case 'visible': + case 'shadow': + case 'hover': + var viewer = document.getElementById('viewer'); + viewer.classList.add('textLayer-' + hashParams['textLayer']); + break; + } + } + +//#if !(FIREFOX || MOZCENTRAL) + if ('pdfBug' in hashParams) { +//#else +//if ('pdfBug' in hashParams && FirefoxCom.requestSync('pdfBugEnabled')) { +//#endif + PDFJS.pdfBug = true; + var pdfBug = hashParams['pdfBug']; + var enabled = pdfBug.split(','); + PDFBug.enable(enabled); + PDFBug.init(); + } + + if (!PDFView.supportsPrinting) { + document.getElementById('print').classList.add('hidden'); + } + + if (!PDFView.supportsFullscreen) { + document.getElementById('fullscreen').classList.add('hidden'); + } + + if (PDFView.supportsIntegratedFind) { + document.querySelector('#viewFind').classList.add('hidden'); + } + + // Listen for warnings to trigger the fallback UI. Errors should be caught + // and call PDFView.error() so we don't need to listen for those. + PDFJS.LogManager.addLogger({ + warn: function() { + PDFView.fallback(); + } + }); + + var mainContainer = document.getElementById('mainContainer'); + var outerContainer = document.getElementById('outerContainer'); + mainContainer.addEventListener('transitionend', function(e) { + if (e.target == mainContainer) { + var event = document.createEvent('UIEvents'); + event.initUIEvent('resize', false, false, window, 0); + window.dispatchEvent(event); + outerContainer.classList.remove('sidebarMoving'); + } + }, true); + + document.getElementById('sidebarToggle').addEventListener('click', + function() { + this.classList.toggle('toggled'); + outerContainer.classList.add('sidebarMoving'); + outerContainer.classList.toggle('sidebarOpen'); + PDFView.sidebarOpen = outerContainer.classList.contains('sidebarOpen'); + PDFView.renderHighestPriority(); + }); + + document.getElementById('viewThumbnail').addEventListener('click', + function() { + PDFView.switchSidebarView('thumbs'); + }); + + document.getElementById('viewOutline').addEventListener('click', + function() { + PDFView.switchSidebarView('outline'); + }); + + document.getElementById('previous').addEventListener('click', + function() { + PDFView.page--; + }); + + document.getElementById('next').addEventListener('click', + function() { + PDFView.page++; + }); + + document.querySelector('.zoomIn').addEventListener('click', + function() { + PDFView.zoomIn(); + }); + + document.querySelector('.zoomOut').addEventListener('click', + function() { + PDFView.zoomOut(); + }); + + document.getElementById('fullscreen').addEventListener('click', + function() { + PDFView.fullscreen(); + }); + + document.getElementById('openFile').addEventListener('click', + function() { + document.getElementById('fileInput').click(); + }); + + document.getElementById('print').addEventListener('click', + function() { + window.print(); + }); + + document.getElementById('download').addEventListener('click', + function() { + PDFView.download(); + }); + + document.getElementById('pageNumber').addEventListener('click', + function() { + this.select(); + }); + + document.getElementById('pageNumber').addEventListener('change', + function() { + // Handle the user inputting a floating point number. + PDFView.page = (this.value | 0); + + if (this.value !== (this.value | 0).toString()) { + this.value = PDFView.page; + } + }); + + document.getElementById('scaleSelect').addEventListener('change', + function() { + PDFView.parseScale(this.value); + }); + + document.getElementById('first_page').addEventListener('click', + function() { + PDFView.page = 1; + }); + + document.getElementById('last_page').addEventListener('click', + function() { + PDFView.page = PDFView.pdfDocument.numPages; + }); + + document.getElementById('page_rotate_ccw').addEventListener('click', + function() { + PDFView.rotatePages(-90); + }); + + document.getElementById('page_rotate_cw').addEventListener('click', + function() { + PDFView.rotatePages(90); + }); + +//#if (FIREFOX || MOZCENTRAL) +//if (FirefoxCom.requestSync('getLoadingType') == 'passive') { +// PDFView.setTitleUsingUrl(file); +// PDFView.initPassiveLoading(); +// return; +//} +//#endif + +//#if !B2G + PDFView.open(file, 0); +//#endif +}, true); + +function updateViewarea() { + + if (!PDFView.initialized) + return; + var visible = PDFView.getVisiblePages(); + var visiblePages = visible.views; + if (visiblePages.length === 0) { + return; + } + + PDFView.renderHighestPriority(); + + var currentId = PDFView.page; + var firstPage = visible.first; + + for (var i = 0, ii = visiblePages.length, stillFullyVisible = false; + i < ii; ++i) { + var page = visiblePages[i]; + + if (page.percent < 100) + break; + + if (page.id === PDFView.page) { + stillFullyVisible = true; + break; + } + } + + if (!stillFullyVisible) { + currentId = visiblePages[0].id; + } + + if (!PDFView.isFullscreen) { + updateViewarea.inProgress = true; // used in "set page" + PDFView.page = currentId; + updateViewarea.inProgress = false; + } + + var currentScale = PDFView.currentScale; + var currentScaleValue = PDFView.currentScaleValue; + var normalizedScaleValue = currentScaleValue == currentScale ? + currentScale * 100 : currentScaleValue; + + var pageNumber = firstPage.id; + var pdfOpenParams = '#page=' + pageNumber; + pdfOpenParams += '&zoom=' + normalizedScaleValue; + var currentPage = PDFView.pages[pageNumber - 1]; + var topLeft = currentPage.getPagePoint(PDFView.container.scrollLeft, + (PDFView.container.scrollTop - firstPage.y)); + pdfOpenParams += ',' + Math.round(topLeft[0]) + ',' + Math.round(topLeft[1]); + + var store = PDFView.store; + store.initializedPromise.then(function() { + store.set('exists', true); + store.set('page', pageNumber); + store.set('zoom', normalizedScaleValue); + store.set('scrollLeft', Math.round(topLeft[0])); + store.set('scrollTop', Math.round(topLeft[1])); + }); + var href = PDFView.getAnchorUrl(pdfOpenParams); + document.getElementById('viewBookmark').href = href; +} + +window.addEventListener('resize', function webViewerResize(evt) { + if (PDFView.initialized && + (document.getElementById('pageWidthOption').selected || + document.getElementById('pageFitOption').selected || + document.getElementById('pageAutoOption').selected)) + PDFView.parseScale(document.getElementById('scaleSelect').value); + updateViewarea(); +}); + +window.addEventListener('hashchange', function webViewerHashchange(evt) { + PDFView.setHash(document.location.hash.substring(1)); +}); + +window.addEventListener('change', function webViewerChange(evt) { + var files = evt.target.files; + if (!files || files.length === 0) + return; + + // Read the local file into a Uint8Array. + var fileReader = new FileReader(); + fileReader.onload = function webViewerChangeFileReaderOnload(evt) { + var buffer = evt.target.result; + var uint8Array = new Uint8Array(buffer); + PDFView.open(uint8Array, 0); + }; + + var file = files[0]; + fileReader.readAsArrayBuffer(file); + PDFView.setTitleUsingUrl(file.name); + + // URL does not reflect proper document location - hiding some icons. + document.getElementById('viewBookmark').setAttribute('hidden', 'true'); + document.getElementById('download').setAttribute('hidden', 'true'); +}, true); + +function selectScaleOption(value) { + var options = document.getElementById('scaleSelect').options; + var predefinedValueFound = false; + for (var i = 0; i < options.length; i++) { + var option = options[i]; + if (option.value != value) { + option.selected = false; + continue; + } + option.selected = true; + predefinedValueFound = true; + } + return predefinedValueFound; +} + +window.addEventListener('localized', function localized(evt) { + document.getElementsByTagName('html')[0].dir = mozL10n.getDirection(); + + // Adjust the width of the zoom box to fit the content. + PDFView.animationStartedPromise.then( + function() { + var container = document.getElementById('scaleSelectContainer'); + var select = document.getElementById('scaleSelect'); + select.setAttribute('style', 'min-width: inherit;'); + var width = select.clientWidth + 8; + select.setAttribute('style', 'min-width: ' + (width + 20) + 'px;'); + container.setAttribute('style', 'min-width: ' + width + 'px; ' + + 'max-width: ' + width + 'px;'); + }); +}, true); + +window.addEventListener('scalechange', function scalechange(evt) { + var customScaleOption = document.getElementById('customScaleOption'); + customScaleOption.selected = false; + + if (!evt.resetAutoSettings && + (document.getElementById('pageWidthOption').selected || + document.getElementById('pageFitOption').selected || + document.getElementById('pageAutoOption').selected)) { + updateViewarea(); + return; + } + + var predefinedValueFound = selectScaleOption('' + evt.scale); + if (!predefinedValueFound) { + customScaleOption.textContent = Math.round(evt.scale * 10000) / 100 + '%'; + customScaleOption.selected = true; + } + + document.getElementById('zoom_out').disabled = (evt.scale === MIN_SCALE); + document.getElementById('zoom_in').disabled = (evt.scale === MAX_SCALE); + + updateViewarea(); +}, true); + +window.addEventListener('pagechange', function pagechange(evt) { + var page = evt.pageNumber; + if (PDFView.previousPageNumber !== page) { + document.getElementById('pageNumber').value = page; + var selected = document.querySelector('.thumbnail.selected'); + if (selected) + selected.classList.remove('selected'); + var thumbnail = document.getElementById('thumbnailContainer' + page); + thumbnail.classList.add('selected'); + var visibleThumbs = PDFView.getVisibleThumbs(); + var numVisibleThumbs = visibleThumbs.views.length; + // If the thumbnail isn't currently visible scroll it into view. + if (numVisibleThumbs > 0) { + var first = visibleThumbs.first.id; + // Account for only one thumbnail being visible. + var last = numVisibleThumbs > 1 ? + visibleThumbs.last.id : first; + if (page <= first || page >= last) + scrollIntoView(thumbnail); + } + + } + document.getElementById('previous').disabled = (page <= 1); + document.getElementById('next').disabled = (page >= PDFView.pages.length); +}, true); + +// Firefox specific event, so that we can prevent browser from zooming +window.addEventListener('DOMMouseScroll', function(evt) { + if (evt.ctrlKey) { + evt.preventDefault(); + + var ticks = evt.detail; + var direction = (ticks > 0) ? 'zoomOut' : 'zoomIn'; + for (var i = 0, length = Math.abs(ticks); i < length; i++) + PDFView[direction](); + } else if (PDFView.isFullscreen) { + var FIREFOX_DELTA_FACTOR = -40; + PDFView.mouseScroll(evt.detail * FIREFOX_DELTA_FACTOR); + } +}, false); + +window.addEventListener('mousemove', function mousemove(evt) { + if (PDFView.isFullscreen) { + PDFView.showPresentationControls(); + } +}, false); + +window.addEventListener('mousedown', function mousedown(evt) { + if (PDFView.isFullscreen && evt.button === 0) { + // Enable clicking of links in fullscreen mode. + // Note: Only links that point to the currently loaded PDF document works. + var targetHref = evt.target.href; + var internalLink = targetHref && (targetHref.replace(/#.*$/, '') === + window.location.href.replace(/#.*$/, '')); + if (!internalLink) { + // Unless an internal link was clicked, advance a page in fullscreen mode. + evt.preventDefault(); + PDFView.page++; + } + } +}, false); + +window.addEventListener('click', function click(evt) { + if (PDFView.isFullscreen && evt.button === 0) { + // Necessary since preventDefault() in 'mousedown' won't stop + // the event propagation in all circumstances. + evt.preventDefault(); + } +}, false); + +window.addEventListener('keydown', function keydown(evt) { + var handled = false; + var cmd = (evt.ctrlKey ? 1 : 0) | + (evt.altKey ? 2 : 0) | + (evt.shiftKey ? 4 : 0) | + (evt.metaKey ? 8 : 0); + + // First, handle the key bindings that are independent whether an input + // control is selected or not. + if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) { + // either CTRL or META key with optional SHIFT. + switch (evt.keyCode) { + case 70: + if (!PDFView.supportsIntegratedFind) { + PDFFindBar.toggle(); + handled = true; + } + break; + case 61: // FF/Mac '=' + case 107: // FF '+' and '=' + case 187: // Chrome '+' + case 171: // FF with German keyboard + PDFView.zoomIn(); + handled = true; + break; + case 173: // FF/Mac '-' + case 109: // FF '-' + case 189: // Chrome '-' + PDFView.zoomOut(); + handled = true; + break; + case 48: // '0' + case 96: // '0' on Numpad of Swedish keyboard + PDFView.parseScale(DEFAULT_SCALE, true); + handled = false; // keeping it unhandled (to restore page zoom to 100%) + break; + } + } + + // CTRL or META with or without SHIFT. + if (cmd == 1 || cmd == 8 || cmd == 5 || cmd == 12) { + switch (evt.keyCode) { + case 71: // g + if (!PDFView.supportsIntegratedFind) { + PDFFindBar.dispatchEvent('again', cmd == 5 || cmd == 12); + handled = true; + } + break; + } + } + + if (handled) { + evt.preventDefault(); + return; + } + + // Some shortcuts should not get handled if a control/input element + // is selected. + var curElement = document.activeElement; + if (curElement && (curElement.tagName == 'INPUT' || + curElement.tagName == 'SELECT')) { + return; + } + var controlsElement = document.getElementById('toolbar'); + while (curElement) { + if (curElement === controlsElement && !PDFView.isFullscreen) + return; // ignoring if the 'toolbar' element is focused + curElement = curElement.parentNode; + } + + if (cmd === 0) { // no control key pressed at all. + switch (evt.keyCode) { + case 38: // up arrow + case 33: // pg up + case 8: // backspace + if (!PDFView.isFullscreen && PDFView.currentScaleValue !== 'page-fit') { + break; + } + /* in fullscreen mode */ + /* falls through */ + case 37: // left arrow + // horizontal scrolling using arrow keys + if (PDFView.isHorizontalScrollbarEnabled) { + break; + } + /* falls through */ + case 75: // 'k' + case 80: // 'p' + PDFView.page--; + handled = true; + break; + case 27: // esc key + if (!PDFView.supportsIntegratedFind && PDFFindBar.opened) { + PDFFindBar.close(); + handled = true; + } + break; + case 40: // down arrow + case 34: // pg down + case 32: // spacebar + if (!PDFView.isFullscreen && PDFView.currentScaleValue !== 'page-fit') { + break; + } + /* falls through */ + case 39: // right arrow + // horizontal scrolling using arrow keys + if (PDFView.isHorizontalScrollbarEnabled) { + break; + } + /* falls through */ + case 74: // 'j' + case 78: // 'n' + PDFView.page++; + handled = true; + break; + + case 36: // home + if (PDFView.isFullscreen) { + PDFView.page = 1; + handled = true; + } + break; + case 35: // end + if (PDFView.isFullscreen) { + PDFView.page = PDFView.pdfDocument.numPages; + handled = true; + } + break; + + case 82: // 'r' + PDFView.rotatePages(90); + break; + } + } + + if (cmd == 4) { // shift-key + switch (evt.keyCode) { + case 82: // 'r' + PDFView.rotatePages(-90); + break; + } + } + + if (handled) { + evt.preventDefault(); + PDFView.clearMouseScrollState(); + } +}); + +window.addEventListener('beforeprint', function beforePrint(evt) { + PDFView.beforePrint(); +}); + +window.addEventListener('afterprint', function afterPrint(evt) { + PDFView.afterPrint(); +}); + +(function fullscreenClosure() { + function fullscreenChange(e) { + var isFullscreen = document.fullscreenElement || document.mozFullScreen || + document.webkitIsFullScreen; + + if (!isFullscreen) { + PDFView.exitFullscreen(); + } + } + + window.addEventListener('fullscreenchange', fullscreenChange, false); + window.addEventListener('mozfullscreenchange', fullscreenChange, false); + window.addEventListener('webkitfullscreenchange', fullscreenChange, false); +})(); + +(function animationStartedClosure() { + // The offsetParent is not set until the pdf.js iframe or object is visible. + // Waiting for first animation. + var requestAnimationFrame = window.requestAnimationFrame || + window.mozRequestAnimationFrame || + window.webkitRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function startAtOnce(callback) { callback(); }; + PDFView.animationStartedPromise = new PDFJS.Promise(); + requestAnimationFrame(function onAnimationFrame() { + PDFView.animationStartedPromise.resolve(); + }); +})(); + +//#if B2G +//window.navigator.mozSetMessageHandler('activity', function(activity) { +// var url = activity.source.data.url; +// PDFView.open(url); +// var cancelButton = document.getElementById('activityClose'); +// cancelButton.addEventListener('click', function() { +// activity.postResult('close'); +// }); +//}); +//#endif -- cgit v1.2.3 From 0c6ae5ab08f72138dd47912eade4438b4f9e2eea Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Fri, 21 Jun 2013 01:51:47 +0300 Subject: pdf: remove two unused files (we use pdf.js in an iframe, no need for our own bastard copy) Signed-off-by: Alon Levy --- mediagoblin/static/js/pdf_viewer.js | 3615 ----------------------------------- 1 file changed, 3615 deletions(-) delete mode 100644 mediagoblin/static/js/pdf_viewer.js (limited to 'mediagoblin/static/js') diff --git a/mediagoblin/static/js/pdf_viewer.js b/mediagoblin/static/js/pdf_viewer.js deleted file mode 100644 index 79c1e708..00000000 --- a/mediagoblin/static/js/pdf_viewer.js +++ /dev/null @@ -1,3615 +0,0 @@ -/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* Copyright 2012 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* globals PDFJS, PDFBug, FirefoxCom, Stats */ - -'use strict'; - -var DEFAULT_SCALE = 'auto'; -var DEFAULT_SCALE_DELTA = 1.1; -var UNKNOWN_SCALE = 0; -var CACHE_SIZE = 20; -var CSS_UNITS = 96.0 / 72.0; -var SCROLLBAR_PADDING = 40; -var VERTICAL_PADDING = 5; -var MIN_SCALE = 0.25; -var MAX_SCALE = 4.0; -var IMAGE_DIR = './images/'; -var SETTINGS_MEMORY = 20; -var ANNOT_MIN_SIZE = 10; -var RenderingStates = { - INITIAL: 0, - RUNNING: 1, - PAUSED: 2, - FINISHED: 3 -}; -var FindStates = { - FIND_FOUND: 0, - FIND_NOTFOUND: 1, - FIND_WRAPPED: 2, - FIND_PENDING: 3 -}; - -//#if (FIREFOX || MOZCENTRAL || B2G || GENERIC || CHROME) -//PDFJS.workerSrc = '../build/pdf.js'; -//#endif - -var mozL10n = document.mozL10n || document.webL10n; - -function getFileName(url) { - var anchor = url.indexOf('#'); - var query = url.indexOf('?'); - var end = Math.min( - anchor > 0 ? anchor : url.length, - query > 0 ? query : url.length); - return url.substring(url.lastIndexOf('/', end) + 1, end); -} - -function scrollIntoView(element, spot) { - // Assuming offsetParent is available (it's not available when viewer is in - // hidden iframe or object). We have to scroll: if the offsetParent is not set - // producing the error. See also animationStartedClosure. - var parent = element.offsetParent; - var offsetY = element.offsetTop + element.clientTop; - if (!parent) { - console.error('offsetParent is not set -- cannot scroll'); - return; - } - while (parent.clientHeight == parent.scrollHeight) { - offsetY += parent.offsetTop; - parent = parent.offsetParent; - if (!parent) - return; // no need to scroll - } - if (spot) - offsetY += spot.top; - parent.scrollTop = offsetY; -} - -var Cache = function cacheCache(size) { - var data = []; - this.push = function cachePush(view) { - var i = data.indexOf(view); - if (i >= 0) - data.splice(i); - data.push(view); - if (data.length > size) - data.shift().destroy(); - }; -}; - -var ProgressBar = (function ProgressBarClosure() { - - function clamp(v, min, max) { - return Math.min(Math.max(v, min), max); - } - - function ProgressBar(id, opts) { - - // Fetch the sub-elements for later - this.div = document.querySelector(id + ' .progress'); - - // Get options, with sensible defaults - this.height = opts.height || 100; - this.width = opts.width || 100; - this.units = opts.units || '%'; - - // Initialize heights - this.div.style.height = this.height + this.units; - } - - ProgressBar.prototype = { - - updateBar: function ProgressBar_updateBar() { - if (this._indeterminate) { - this.div.classList.add('indeterminate'); - return; - } - - var progressSize = this.width * this._percent / 100; - - if (this._percent > 95) - this.div.classList.add('full'); - else - this.div.classList.remove('full'); - this.div.classList.remove('indeterminate'); - - this.div.style.width = progressSize + this.units; - }, - - get percent() { - return this._percent; - }, - - set percent(val) { - this._indeterminate = isNaN(val); - this._percent = clamp(val, 0, 100); - this.updateBar(); - } - }; - - return ProgressBar; -})(); - -//#if FIREFOX || MOZCENTRAL -//#include firefoxcom.js -//#endif - -// Settings Manager - This is a utility for saving settings -// First we see if localStorage is available -// If not, we use FUEL in FF -// Use asyncStorage for B2G -var Settings = (function SettingsClosure() { -//#if !(FIREFOX || MOZCENTRAL || B2G) - var isLocalStorageEnabled = (function localStorageEnabledTest() { - // Feature test as per http://diveintohtml5.info/storage.html - // The additional localStorage call is to get around a FF quirk, see - // bug #495747 in bugzilla - try { - return 'localStorage' in window && window['localStorage'] !== null && - localStorage; - } catch (e) { - return false; - } - })(); -//#endif - - function Settings(fingerprint) { - this.fingerprint = fingerprint; - this.initializedPromise = new PDFJS.Promise(); - - var resolvePromise = (function settingsResolvePromise(db) { - this.initialize(db || '{}'); - this.initializedPromise.resolve(); - }).bind(this); - -//#if B2G -// asyncStorage.getItem('database', resolvePromise); -//#endif - -//#if FIREFOX || MOZCENTRAL -// resolvePromise(FirefoxCom.requestSync('getDatabase', null)); -//#endif - -//#if !(FIREFOX || MOZCENTRAL || B2G) - if (isLocalStorageEnabled) - resolvePromise(localStorage.getItem('database')); -//#endif - } - - Settings.prototype = { - initialize: function settingsInitialize(database) { - database = JSON.parse(database); - if (!('files' in database)) - database.files = []; - if (database.files.length >= SETTINGS_MEMORY) - database.files.shift(); - var index; - for (var i = 0, length = database.files.length; i < length; i++) { - var branch = database.files[i]; - if (branch.fingerprint == this.fingerprint) { - index = i; - break; - } - } - if (typeof index != 'number') - index = database.files.push({fingerprint: this.fingerprint}) - 1; - this.file = database.files[index]; - this.database = database; - }, - - set: function settingsSet(name, val) { - if (!this.initializedPromise.isResolved) - return; - - var file = this.file; - file[name] = val; - var database = JSON.stringify(this.database); - -//#if B2G -// asyncStorage.setItem('database', database); -//#endif - -//#if FIREFOX || MOZCENTRAL -// FirefoxCom.requestSync('setDatabase', database); -//#endif - -//#if !(FIREFOX || MOZCENTRAL || B2G) - if (isLocalStorageEnabled) - localStorage.setItem('database', database); -//#endif - }, - - get: function settingsGet(name, defaultValue) { - if (!this.initializedPromise.isResolved) - return defaultValue; - - return this.file[name] || defaultValue; - } - }; - - return Settings; -})(); - -var cache = new Cache(CACHE_SIZE); -var currentPageNumber = 1; - -var PDFFindController = { - startedTextExtraction: false, - - extractTextPromises: [], - - // If active, find results will be highlighted. - active: false, - - // Stores the text for each page. - pageContents: [], - - pageMatches: [], - - // Currently selected match. - selected: { - pageIdx: -1, - matchIdx: -1 - }, - - // Where find algorithm currently is in the document. - offset: { - pageIdx: null, - matchIdx: null - }, - - resumePageIdx: null, - - resumeCallback: null, - - state: null, - - dirtyMatch: false, - - findTimeout: null, - - initialize: function() { - var events = [ - 'find', - 'findagain', - 'findhighlightallchange', - 'findcasesensitivitychange' - ]; - - this.handleEvent = this.handleEvent.bind(this); - - for (var i = 0; i < events.length; i++) { - window.addEventListener(events[i], this.handleEvent); - } - }, - - calcFindMatch: function(pageIndex) { - var pageContent = this.pageContents[pageIndex]; - var query = this.state.query; - var caseSensitive = this.state.caseSensitive; - var queryLen = query.length; - - if (queryLen === 0) { - // Do nothing the matches should be wiped out already. - return; - } - - if (!caseSensitive) { - pageContent = pageContent.toLowerCase(); - query = query.toLowerCase(); - } - - var matches = []; - - var matchIdx = -queryLen; - while (true) { - matchIdx = pageContent.indexOf(query, matchIdx + queryLen); - if (matchIdx === -1) { - break; - } - - matches.push(matchIdx); - } - this.pageMatches[pageIndex] = matches; - this.updatePage(pageIndex); - if (this.resumePageIdx === pageIndex) { - var callback = this.resumeCallback; - this.resumePageIdx = null; - this.resumeCallback = null; - callback(); - } - }, - - extractText: function() { - if (this.startedTextExtraction) { - return; - } - this.startedTextExtraction = true; - - this.pageContents = []; - for (var i = 0, ii = PDFView.pdfDocument.numPages; i < ii; i++) { - this.extractTextPromises.push(new PDFJS.Promise()); - } - - var self = this; - function extractPageText(pageIndex) { - PDFView.pages[pageIndex].getTextContent().then( - function textContentResolved(data) { - // Build the find string. - var bidiTexts = data.bidiTexts; - var str = ''; - - for (var i = 0; i < bidiTexts.length; i++) { - str += bidiTexts[i].str; - } - - // Store the pageContent as a string. - self.pageContents.push(str); - - self.extractTextPromises[pageIndex].resolve(pageIndex); - if ((pageIndex + 1) < PDFView.pages.length) - extractPageText(pageIndex + 1); - } - ); - } - extractPageText(0); - return this.extractTextPromise; - }, - - handleEvent: function(e) { - if (this.state === null || e.type !== 'findagain') { - this.dirtyMatch = true; - } - this.state = e.detail; - this.updateUIState(FindStates.FIND_PENDING); - - this.extractText(); - - clearTimeout(this.findTimeout); - if (e.type === 'find') { - // Only trigger the find action after 250ms of silence. - this.findTimeout = setTimeout(this.nextMatch.bind(this), 250); - } else { - this.nextMatch(); - } - }, - - updatePage: function(idx) { - var page = PDFView.pages[idx]; - - if (this.selected.pageIdx === idx) { - // If the page is selected, scroll the page into view, which triggers - // rendering the page, which adds the textLayer. Once the textLayer is - // build, it will scroll onto the selected match. - page.scrollIntoView(); - } - - if (page.textLayer) { - page.textLayer.updateMatches(); - } - }, - - nextMatch: function() { - var pages = PDFView.pages; - var previous = this.state.findPrevious; - var numPages = PDFView.pages.length; - - this.active = true; - - if (this.dirtyMatch) { - // Need to recalculate the matches, reset everything. - this.dirtyMatch = false; - this.selected.pageIdx = this.selected.matchIdx = -1; - this.offset.pageIdx = previous ? numPages - 1 : 0; - this.offset.matchIdx = null; - this.hadMatch = false; - this.resumeCallback = null; - this.resumePageIdx = null; - this.pageMatches = []; - var self = this; - - for (var i = 0; i < numPages; i++) { - // Wipe out any previous highlighted matches. - this.updatePage(i); - - // As soon as the text is extracted start finding the matches. - this.extractTextPromises[i].onData(function(pageIdx) { - // Use a timeout since all the pages may already be extracted and we - // want to start highlighting before finding all the matches. - setTimeout(function() { - self.calcFindMatch(pageIdx); - }); - }); - } - } - - // If there's no query there's no point in searching. - if (this.state.query === '') { - this.updateUIState(FindStates.FIND_FOUND); - return; - } - - // If we're waiting on a page, we return since we can't do anything else. - if (this.resumeCallback) { - return; - } - - var offset = this.offset; - // If there's already a matchIdx that means we are iterating through a - // page's matches. - if (offset.matchIdx !== null) { - var numPageMatches = this.pageMatches[offset.pageIdx].length; - if ((!previous && offset.matchIdx + 1 < numPageMatches) || - (previous && offset.matchIdx > 0)) { - // The simple case, we just have advance the matchIdx to select the next - // match on the page. - this.hadMatch = true; - offset.matchIdx = previous ? offset.matchIdx - 1 : offset.matchIdx + 1; - this.updateMatch(true); - return; - } - // We went beyond the current page's matches, so we advance to the next - // page. - this.advanceOffsetPage(previous); - } - // Start searching through the page. - this.nextPageMatch(); - }, - - nextPageMatch: function() { - if (this.resumePageIdx !== null) - console.error('There can only be one pending page.'); - - var matchesReady = function(matches) { - var offset = this.offset; - var numMatches = matches.length; - var previous = this.state.findPrevious; - if (numMatches) { - // There were matches for the page, so initialize the matchIdx. - this.hadMatch = true; - offset.matchIdx = previous ? numMatches - 1 : 0; - this.updateMatch(true); - } else { - // No matches attempt to search the next page. - this.advanceOffsetPage(previous); - if (offset.wrapped) { - offset.matchIdx = null; - if (!this.hadMatch) { - // No point in wrapping there were no matches. - this.updateMatch(false); - return; - } - } - // Search the next page. - this.nextPageMatch(); - } - }.bind(this); - - var pageIdx = this.offset.pageIdx; - var pageMatches = this.pageMatches; - if (!pageMatches[pageIdx]) { - // The matches aren't ready setup a callback so we can be notified, - // when they are ready. - this.resumeCallback = function() { - matchesReady(pageMatches[pageIdx]); - }; - this.resumePageIdx = pageIdx; - return; - } - // The matches are finished already. - matchesReady(pageMatches[pageIdx]); - }, - - advanceOffsetPage: function(previous) { - var offset = this.offset; - var numPages = this.extractTextPromises.length; - offset.pageIdx = previous ? offset.pageIdx - 1 : offset.pageIdx + 1; - offset.matchIdx = null; - if (offset.pageIdx >= numPages || offset.pageIdx < 0) { - offset.pageIdx = previous ? numPages - 1 : 0; - offset.wrapped = true; - return; - } - }, - - updateMatch: function(found) { - var state = FindStates.FIND_NOTFOUND; - var wrapped = this.offset.wrapped; - this.offset.wrapped = false; - if (found) { - var previousPage = this.selected.pageIdx; - this.selected.pageIdx = this.offset.pageIdx; - this.selected.matchIdx = this.offset.matchIdx; - state = wrapped ? FindStates.FIND_WRAPPED : FindStates.FIND_FOUND; - // Update the currently selected page to wipe out any selected matches. - if (previousPage !== -1 && previousPage !== this.selected.pageIdx) { - this.updatePage(previousPage); - } - } - this.updateUIState(state, this.state.findPrevious); - if (this.selected.pageIdx !== -1) { - this.updatePage(this.selected.pageIdx, true); - } - }, - - updateUIState: function(state, previous) { - if (PDFView.supportsIntegratedFind) { - FirefoxCom.request('updateFindControlState', - {result: state, findPrevious: previous}); - return; - } - PDFFindBar.updateUIState(state, previous); - } -}; - -var PDFFindBar = { - // TODO: Enable the FindBar *AFTER* the pagesPromise in the load function - // got resolved - - opened: false, - - initialize: function() { - this.bar = document.getElementById('findbar'); - this.toggleButton = document.getElementById('viewFind'); - this.findField = document.getElementById('findInput'); - this.highlightAll = document.getElementById('findHighlightAll'); - this.caseSensitive = document.getElementById('findMatchCase'); - this.findMsg = document.getElementById('findMsg'); - this.findStatusIcon = document.getElementById('findStatusIcon'); - - var self = this; - this.toggleButton.addEventListener('click', function() { - self.toggle(); - }); - - this.findField.addEventListener('input', function() { - self.dispatchEvent(''); - }); - - this.bar.addEventListener('keydown', function(evt) { - switch (evt.keyCode) { - case 13: // Enter - if (evt.target === self.findField) { - self.dispatchEvent('again', evt.shiftKey); - } - break; - case 27: // Escape - self.close(); - break; - } - }); - - document.getElementById('findPrevious').addEventListener('click', - function() { self.dispatchEvent('again', true); } - ); - - document.getElementById('findNext').addEventListener('click', function() { - self.dispatchEvent('again', false); - }); - - this.highlightAll.addEventListener('click', function() { - self.dispatchEvent('highlightallchange'); - }); - - this.caseSensitive.addEventListener('click', function() { - self.dispatchEvent('casesensitivitychange'); - }); - }, - - dispatchEvent: function(aType, aFindPrevious) { - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('find' + aType, true, true, { - query: this.findField.value, - caseSensitive: this.caseSensitive.checked, - highlightAll: this.highlightAll.checked, - findPrevious: aFindPrevious - }); - return window.dispatchEvent(event); - }, - - updateUIState: function(state, previous) { - var notFound = false; - var findMsg = ''; - var status = ''; - - switch (state) { - case FindStates.FIND_FOUND: - break; - - case FindStates.FIND_PENDING: - status = 'pending'; - break; - - case FindStates.FIND_NOTFOUND: - findMsg = mozL10n.get('find_not_found', null, 'Phrase not found'); - notFound = true; - break; - - case FindStates.FIND_WRAPPED: - if (previous) { - findMsg = mozL10n.get('find_reached_top', null, - 'Reached top of document, continued from bottom'); - } else { - findMsg = mozL10n.get('find_reached_bottom', null, - 'Reached end of document, continued from top'); - } - break; - } - - if (notFound) { - this.findField.classList.add('notFound'); - } else { - this.findField.classList.remove('notFound'); - } - - this.findField.setAttribute('data-status', status); - this.findMsg.textContent = findMsg; - }, - - open: function() { - if (this.opened) return; - - this.opened = true; - this.toggleButton.classList.add('toggled'); - this.bar.classList.remove('hidden'); - this.findField.select(); - this.findField.focus(); - }, - - close: function() { - if (!this.opened) return; - - this.opened = false; - this.toggleButton.classList.remove('toggled'); - this.bar.classList.add('hidden'); - - PDFFindController.active = false; - }, - - toggle: function() { - if (this.opened) { - this.close(); - } else { - this.open(); - } - } -}; - -var PDFView = { - pages: [], - thumbnails: [], - currentScale: UNKNOWN_SCALE, - currentScaleValue: null, - initialBookmark: document.location.hash.substring(1), - startedTextExtraction: false, - pageText: [], - container: null, - thumbnailContainer: null, - initialized: false, - fellback: false, - pdfDocument: null, - sidebarOpen: false, - pageViewScroll: null, - thumbnailViewScroll: null, - isFullscreen: false, - previousScale: null, - pageRotation: 0, - mouseScrollTimeStamp: 0, - mouseScrollDelta: 0, - lastScroll: 0, - previousPageNumber: 1, - - // called once when the document is loaded - initialize: function pdfViewInitialize() { - var self = this; - var container = this.container = document.getElementById('viewerContainer'); - this.pageViewScroll = {}; - this.watchScroll(container, this.pageViewScroll, updateViewarea); - - var thumbnailContainer = this.thumbnailContainer = - document.getElementById('thumbnailView'); - this.thumbnailViewScroll = {}; - this.watchScroll(thumbnailContainer, this.thumbnailViewScroll, - this.renderHighestPriority.bind(this)); - - PDFFindBar.initialize(); - PDFFindController.initialize(); - - this.initialized = true; - container.addEventListener('scroll', function() { - self.lastScroll = Date.now(); - }, false); - }, - - getPage: function pdfViewGetPage(n) { - return this.pdfDocument.getPage(n); - }, - - // Helper function to keep track whether a div was scrolled up or down and - // then call a callback. - watchScroll: function pdfViewWatchScroll(viewAreaElement, state, callback) { - state.down = true; - state.lastY = viewAreaElement.scrollTop; - viewAreaElement.addEventListener('scroll', function webViewerScroll(evt) { - var currentY = viewAreaElement.scrollTop; - var lastY = state.lastY; - if (currentY > lastY) - state.down = true; - else if (currentY < lastY) - state.down = false; - // else do nothing and use previous value - state.lastY = currentY; - callback(); - }, true); - }, - - setScale: function pdfViewSetScale(val, resetAutoSettings, noScroll) { - if (val == this.currentScale) - return; - - var pages = this.pages; - for (var i = 0; i < pages.length; i++) - pages[i].update(val * CSS_UNITS); - - if (!noScroll && this.currentScale != val) - this.pages[this.page - 1].scrollIntoView(); - this.currentScale = val; - - var event = document.createEvent('UIEvents'); - event.initUIEvent('scalechange', false, false, window, 0); - event.scale = val; - event.resetAutoSettings = resetAutoSettings; - window.dispatchEvent(event); - }, - - parseScale: function pdfViewParseScale(value, resetAutoSettings, noScroll) { - if ('custom' == value) - return; - - var scale = parseFloat(value); - this.currentScaleValue = value; - if (scale) { - this.setScale(scale, true, noScroll); - return; - } - - var container = this.container; - var currentPage = this.pages[this.page - 1]; - if (!currentPage) { - return; - } - - var pageWidthScale = (container.clientWidth - SCROLLBAR_PADDING) / - currentPage.width * currentPage.scale / CSS_UNITS; - var pageHeightScale = (container.clientHeight - VERTICAL_PADDING) / - currentPage.height * currentPage.scale / CSS_UNITS; - switch (value) { - case 'page-actual': - scale = 1; - break; - case 'page-width': - scale = pageWidthScale; - break; - case 'page-height': - scale = pageHeightScale; - break; - case 'page-fit': - scale = Math.min(pageWidthScale, pageHeightScale); - break; - case 'auto': - scale = Math.min(1.0, pageWidthScale); - break; - } - this.setScale(scale, resetAutoSettings, noScroll); - - selectScaleOption(value); - }, - - zoomIn: function pdfViewZoomIn() { - var newScale = (this.currentScale * DEFAULT_SCALE_DELTA).toFixed(2); - newScale = Math.ceil(newScale * 10) / 10; - newScale = Math.min(MAX_SCALE, newScale); - this.parseScale(newScale, true); - }, - - zoomOut: function pdfViewZoomOut() { - var newScale = (this.currentScale / DEFAULT_SCALE_DELTA).toFixed(2); - newScale = Math.floor(newScale * 10) / 10; - newScale = Math.max(MIN_SCALE, newScale); - this.parseScale(newScale, true); - }, - - set page(val) { - var pages = this.pages; - var input = document.getElementById('pageNumber'); - var event = document.createEvent('UIEvents'); - event.initUIEvent('pagechange', false, false, window, 0); - - if (!(0 < val && val <= pages.length)) { - this.previousPageNumber = val; - event.pageNumber = this.page; - window.dispatchEvent(event); - return; - } - - pages[val - 1].updateStats(); - this.previousPageNumber = currentPageNumber; - currentPageNumber = val; - event.pageNumber = val; - window.dispatchEvent(event); - - // checking if the this.page was called from the updateViewarea function: - // avoiding the creation of two "set page" method (internal and public) - if (updateViewarea.inProgress) - return; - - // Avoid scrolling the first page during loading - if (this.loading && val == 1) - return; - - pages[val - 1].scrollIntoView(); - }, - - get page() { - return currentPageNumber; - }, - - get supportsPrinting() { - var canvas = document.createElement('canvas'); - var value = 'mozPrintCallback' in canvas; - // shadow - Object.defineProperty(this, 'supportsPrinting', { value: value, - enumerable: true, - configurable: true, - writable: false }); - return value; - }, - - get supportsFullscreen() { - var doc = document.documentElement; - var support = doc.requestFullscreen || doc.mozRequestFullScreen || - doc.webkitRequestFullScreen; - - // Disable fullscreen button if we're in an iframe - if (!!window.frameElement) - support = false; - - Object.defineProperty(this, 'supportsFullScreen', { value: support, - enumerable: true, - configurable: true, - writable: false }); - return support; - }, - - get supportsIntegratedFind() { - var support = false; -//#if !(FIREFOX || MOZCENTRAL) -//#else -// support = FirefoxCom.requestSync('supportsIntegratedFind'); -//#endif - Object.defineProperty(this, 'supportsIntegratedFind', { value: support, - enumerable: true, - configurable: true, - writable: false }); - return support; - }, - - get supportsDocumentFonts() { - var support = true; -//#if !(FIREFOX || MOZCENTRAL) -//#else -// support = FirefoxCom.requestSync('supportsDocumentFonts'); -//#endif - Object.defineProperty(this, 'supportsDocumentFonts', { value: support, - enumerable: true, - configurable: true, - writable: false }); - return support; - }, - - get isHorizontalScrollbarEnabled() { - var div = document.getElementById('viewerContainer'); - return div.scrollWidth > div.clientWidth; - }, - - initPassiveLoading: function pdfViewInitPassiveLoading() { - if (!PDFView.loadingBar) { - PDFView.loadingBar = new ProgressBar('#loadingBar', {}); - } - - window.addEventListener('message', function window_message(e) { - var args = e.data; - - if (typeof args !== 'object' || !('pdfjsLoadAction' in args)) - return; - switch (args.pdfjsLoadAction) { - case 'progress': - PDFView.progress(args.loaded / args.total); - break; - case 'complete': - if (!args.data) { - PDFView.error(mozL10n.get('loading_error', null, - 'An error occurred while loading the PDF.'), e); - break; - } - PDFView.open(args.data, 0); - break; - } - }); - FirefoxCom.requestSync('initPassiveLoading', null); - }, - - setTitleUsingUrl: function pdfViewSetTitleUsingUrl(url) { - this.url = url; - try { - this.setTitle(decodeURIComponent(getFileName(url)) || url); - } catch (e) { - // decodeURIComponent may throw URIError, - // fall back to using the unprocessed url in that case - this.setTitle(url); - } - }, - - setTitle: function pdfViewSetTitle(title) { - document.title = title; -//#if B2G -// document.getElementById('activityTitle').textContent = title; -//#endif - }, - - open: function pdfViewOpen(url, scale, password) { - var parameters = {password: password}; - if (typeof url === 'string') { // URL - this.setTitleUsingUrl(url); - parameters.url = url; - } else if (url && 'byteLength' in url) { // ArrayBuffer - parameters.data = url; - } - - if (!PDFView.loadingBar) { - PDFView.loadingBar = new ProgressBar('#loadingBar', {}); - } - - this.pdfDocument = null; - var self = this; - self.loading = true; - PDFJS.getDocument(parameters).then( - function getDocumentCallback(pdfDocument) { - self.load(pdfDocument, scale); - self.loading = false; - }, - function getDocumentError(message, exception) { - if (exception && exception.name === 'PasswordException') { - if (exception.code === 'needpassword') { - var promptString = mozL10n.get('request_password', null, - 'PDF is protected by a password:'); - password = prompt(promptString); - if (password && password.length > 0) { - return PDFView.open(url, scale, password); - } - } - } - - var loadingErrorMessage = mozL10n.get('loading_error', null, - 'An error occurred while loading the PDF.'); - - if (exception && exception.name === 'InvalidPDFException') { - // change error message also for other builds - var loadingErrorMessage = mozL10n.get('invalid_file_error', null, - 'Invalid or corrupted PDF file.'); -//#if B2G -// window.alert(loadingErrorMessage); -// return window.close(); -//#endif - } - - if (exception && exception.name === 'MissingPDFException') { - // special message for missing PDF's - var loadingErrorMessage = mozL10n.get('missing_file_error', null, - 'Missing PDF file.'); - -//#if B2G -// window.alert(loadingErrorMessage); -// return window.close(); -//#endif - } - - var loadingIndicator = document.getElementById('loading'); - loadingIndicator.textContent = mozL10n.get('loading_error_indicator', - null, 'Error'); - var moreInfo = { - message: message - }; - self.error(loadingErrorMessage, moreInfo); - self.loading = false; - }, - function getDocumentProgress(progressData) { - self.progress(progressData.loaded / progressData.total); - } - ); - }, - - download: function pdfViewDownload() { - function noData() { - FirefoxCom.request('download', { originalUrl: url }); - } - var url = this.url.split('#')[0]; -//#if !(FIREFOX || MOZCENTRAL) - url += '#pdfjs.action=download'; - window.open(url, '_parent'); -//#else -// // Document isn't ready just try to download with the url. -// if (!this.pdfDocument) { -// noData(); -// return; -// } -// this.pdfDocument.getData().then( -// function getDataSuccess(data) { -// var blob = PDFJS.createBlob(data.buffer, 'application/pdf'); -// var blobUrl = window.URL.createObjectURL(blob); -// -// FirefoxCom.request('download', { blobUrl: blobUrl, originalUrl: url }, -// function response(err) { -// if (err) { -// // This error won't really be helpful because it's likely the -// // fallback won't work either (or is already open). -// PDFView.error('PDF failed to download.'); -// } -// window.URL.revokeObjectURL(blobUrl); -// } -// ); -// }, -// noData // Error occurred try downloading with just the url. -// ); -//#endif - }, - - fallback: function pdfViewFallback() { -//#if !(FIREFOX || MOZCENTRAL) -// return; -//#else -// // Only trigger the fallback once so we don't spam the user with messages -// // for one PDF. -// if (this.fellback) -// return; -// this.fellback = true; -// var url = this.url.split('#')[0]; -// FirefoxCom.request('fallback', url, function response(download) { -// if (!download) -// return; -// PDFView.download(); -// }); -//#endif - }, - - navigateTo: function pdfViewNavigateTo(dest) { - if (typeof dest === 'string') - dest = this.destinations[dest]; - if (!(dest instanceof Array)) - return; // invalid destination - // dest array looks like that: - var destRef = dest[0]; - var pageNumber = destRef instanceof Object ? - this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] : (destRef + 1); - if (pageNumber > this.pages.length) - pageNumber = this.pages.length; - if (pageNumber) { - this.page = pageNumber; - var currentPage = this.pages[pageNumber - 1]; - if (!this.isFullscreen) { // Avoid breaking fullscreen mode. - currentPage.scrollIntoView(dest); - } - } - }, - - getDestinationHash: function pdfViewGetDestinationHash(dest) { - if (typeof dest === 'string') - return PDFView.getAnchorUrl('#' + escape(dest)); - if (dest instanceof Array) { - var destRef = dest[0]; // see navigateTo method for dest format - var pageNumber = destRef instanceof Object ? - this.pagesRefMap[destRef.num + ' ' + destRef.gen + ' R'] : - (destRef + 1); - if (pageNumber) { - var pdfOpenParams = PDFView.getAnchorUrl('#page=' + pageNumber); - var destKind = dest[1]; - if (typeof destKind === 'object' && 'name' in destKind && - destKind.name == 'XYZ') { - var scale = (dest[4] || this.currentScale); - pdfOpenParams += '&zoom=' + (scale * 100); - if (dest[2] || dest[3]) { - pdfOpenParams += ',' + (dest[2] || 0) + ',' + (dest[3] || 0); - } - } - return pdfOpenParams; - } - } - return ''; - }, - - /** - * For the firefox extension we prefix the full url on anchor links so they - * don't come up as resource:// urls and so open in new tab/window works. - * @param {String} anchor The anchor hash include the #. - */ - getAnchorUrl: function getAnchorUrl(anchor) { -//#if !(FIREFOX || MOZCENTRAL) - return anchor; -//#else -// return this.url.split('#')[0] + anchor; -//#endif - }, - - /** - * Returns scale factor for the canvas. It makes sense for the HiDPI displays. - * @return {Object} The object with horizontal (sx) and vertical (sy) - scales. The scaled property is set to false if scaling is - not required, true otherwise. - */ - getOutputScale: function pdfViewGetOutputDPI() { - var pixelRatio = 'devicePixelRatio' in window ? window.devicePixelRatio : 1; - return { - sx: pixelRatio, - sy: pixelRatio, - scaled: pixelRatio != 1 - }; - }, - - /** - * Show the error box. - * @param {String} message A message that is human readable. - * @param {Object} moreInfo (optional) Further information about the error - * that is more technical. Should have a 'message' - * and optionally a 'stack' property. - */ - error: function pdfViewError(message, moreInfo) { - var moreInfoText = mozL10n.get('error_version_info', - {version: PDFJS.version || '?', build: PDFJS.build || '?'}, - 'PDF.js v{{version}} (build: {{build}})') + '\n'; - if (moreInfo) { - moreInfoText += - mozL10n.get('error_message', {message: moreInfo.message}, - 'Message: {{message}}'); - if (moreInfo.stack) { - moreInfoText += '\n' + - mozL10n.get('error_stack', {stack: moreInfo.stack}, - 'Stack: {{stack}}'); - } else { - if (moreInfo.filename) { - moreInfoText += '\n' + - mozL10n.get('error_file', {file: moreInfo.filename}, - 'File: {{file}}'); - } - if (moreInfo.lineNumber) { - moreInfoText += '\n' + - mozL10n.get('error_line', {line: moreInfo.lineNumber}, - 'Line: {{line}}'); - } - } - } - - var loadingBox = document.getElementById('loadingBox'); - loadingBox.setAttribute('hidden', 'true'); - -//#if !(FIREFOX || MOZCENTRAL) - var errorWrapper = document.getElementById('errorWrapper'); - errorWrapper.removeAttribute('hidden'); - - var errorMessage = document.getElementById('errorMessage'); - errorMessage.textContent = message; - - var closeButton = document.getElementById('errorClose'); - closeButton.onclick = function() { - errorWrapper.setAttribute('hidden', 'true'); - }; - - var errorMoreInfo = document.getElementById('errorMoreInfo'); - var moreInfoButton = document.getElementById('errorShowMore'); - var lessInfoButton = document.getElementById('errorShowLess'); - moreInfoButton.onclick = function() { - errorMoreInfo.removeAttribute('hidden'); - moreInfoButton.setAttribute('hidden', 'true'); - lessInfoButton.removeAttribute('hidden'); - }; - lessInfoButton.onclick = function() { - errorMoreInfo.setAttribute('hidden', 'true'); - moreInfoButton.removeAttribute('hidden'); - lessInfoButton.setAttribute('hidden', 'true'); - }; - moreInfoButton.removeAttribute('hidden'); - lessInfoButton.setAttribute('hidden', 'true'); - errorMoreInfo.value = moreInfoText; - - errorMoreInfo.rows = moreInfoText.split('\n').length - 1; -//#else -// console.error(message + '\n' + moreInfoText); -// this.fallback(); -//#endif - }, - - progress: function pdfViewProgress(level) { - var percent = Math.round(level * 100); - PDFView.loadingBar.percent = percent; - }, - - load: function pdfViewLoad(pdfDocument, scale) { - function bindOnAfterDraw(pageView, thumbnailView) { - // when page is painted, using the image as thumbnail base - pageView.onAfterDraw = function pdfViewLoadOnAfterDraw() { - thumbnailView.setImage(pageView.canvas); - }; - } - - this.pdfDocument = pdfDocument; - - var errorWrapper = document.getElementById('errorWrapper'); - errorWrapper.setAttribute('hidden', 'true'); - - var loadingBox = document.getElementById('loadingBox'); - loadingBox.setAttribute('hidden', 'true'); - var loadingIndicator = document.getElementById('loading'); - loadingIndicator.textContent = ''; - - var thumbsView = document.getElementById('thumbnailView'); - thumbsView.parentNode.scrollTop = 0; - - while (thumbsView.hasChildNodes()) - thumbsView.removeChild(thumbsView.lastChild); - - if ('_loadingInterval' in thumbsView) - clearInterval(thumbsView._loadingInterval); - - var container = document.getElementById('viewer'); - while (container.hasChildNodes()) - container.removeChild(container.lastChild); - - var pagesCount = pdfDocument.numPages; - var id = pdfDocument.fingerprint; - document.getElementById('numPages').textContent = - mozL10n.get('page_of', {pageCount: pagesCount}, 'of {{pageCount}}'); - document.getElementById('pageNumber').max = pagesCount; - - PDFView.documentFingerprint = id; - var store = PDFView.store = new Settings(id); - - this.pageRotation = 0; - - var pages = this.pages = []; - this.pageText = []; - this.startedTextExtraction = false; - var pagesRefMap = this.pagesRefMap = {}; - var thumbnails = this.thumbnails = []; - - var pagesPromise = new PDFJS.Promise(); - var self = this; - - var firstPagePromise = pdfDocument.getPage(1); - - // Fetch a single page so we can get a viewport that will be the default - // viewport for all pages - firstPagePromise.then(function(pdfPage) { - var viewport = pdfPage.getViewport(scale || 1.0); - var pagePromises = []; - for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { - var viewportClone = viewport.clone(); - var pageView = new PageView(container, pageNum, scale, - self.navigateTo.bind(self), - viewportClone); - var thumbnailView = new ThumbnailView(thumbsView, pageNum, - viewportClone); - bindOnAfterDraw(pageView, thumbnailView); - pages.push(pageView); - thumbnails.push(thumbnailView); - } - - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('documentload', true, true, {}); - window.dispatchEvent(event); - - for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) { - var pagePromise = pdfDocument.getPage(pageNum); - pagePromise.then(function(pdfPage) { - var pageNum = pdfPage.pageNumber; - var pageView = pages[pageNum - 1]; - if (!pageView.pdfPage) { - // The pdfPage might already be set if we've already entered - // pageView.draw() - pageView.setPdfPage(pdfPage); - } - var thumbnailView = thumbnails[pageNum - 1]; - if (!thumbnailView.pdfPage) { - thumbnailView.setPdfPage(pdfPage); - } - - var pageRef = pdfPage.ref; - var refStr = pageRef.num + ' ' + pageRef.gen + ' R'; - pagesRefMap[refStr] = pdfPage.pageNumber; - }); - pagePromises.push(pagePromise); - } - - PDFJS.Promise.all(pagePromises).then(function(pages) { - pagesPromise.resolve(pages); - }); - }); - - var storePromise = store.initializedPromise; - PDFJS.Promise.all([firstPagePromise, storePromise]).then(function() { - var storedHash = null; - if (store.get('exists', false)) { - var pageNum = store.get('page', '1'); - var zoom = store.get('zoom', PDFView.currentScale); - var left = store.get('scrollLeft', '0'); - var top = store.get('scrollTop', '0'); - - storedHash = 'page=' + pageNum + '&zoom=' + zoom + ',' + - left + ',' + top; - } - self.setInitialView(storedHash, scale); - }); - - pagesPromise.then(function() { - if (PDFView.supportsPrinting) { - pdfDocument.getJavaScript().then(function(javaScript) { - if (javaScript.length) { - console.warn('Warning: JavaScript is not supported'); - PDFView.fallback(); - } - // Hack to support auto printing. - var regex = /\bprint\s*\(/g; - for (var i = 0, ii = javaScript.length; i < ii; i++) { - var js = javaScript[i]; - if (js && regex.test(js)) { - setTimeout(function() { - window.print(); - }); - return; - } - } - }); - } - }); - - var destinationsPromise = pdfDocument.getDestinations(); - destinationsPromise.then(function(destinations) { - self.destinations = destinations; - }); - - // outline depends on destinations and pagesRefMap - var promises = [pagesPromise, destinationsPromise, - PDFView.animationStartedPromise]; - PDFJS.Promise.all(promises).then(function() { - pdfDocument.getOutline().then(function(outline) { - self.outline = new DocumentOutlineView(outline); - }); - - // Make all navigation keys work on document load, - // unless the viewer is embedded in another page. - if (window.parent.location === window.location) { - PDFView.container.focus(); - } - }); - - pdfDocument.getMetadata().then(function(data) { - var info = data.info, metadata = data.metadata; - self.documentInfo = info; - self.metadata = metadata; - - // Provides some basic debug information - console.log('PDF ' + pdfDocument.fingerprint + ' [' + - info.PDFFormatVersion + ' ' + (info.Producer || '-') + - ' / ' + (info.Creator || '-') + ']' + - (PDFJS.version ? ' (PDF.js: ' + PDFJS.version + ')' : '')); - - var pdfTitle; - if (metadata) { - if (metadata.has('dc:title')) - pdfTitle = metadata.get('dc:title'); - } - - if (!pdfTitle && info && info['Title']) - pdfTitle = info['Title']; - - if (pdfTitle) - self.setTitle(pdfTitle + ' - ' + document.title); - - if (info.IsAcroFormPresent) { - console.warn('Warning: AcroForm/XFA is not supported'); - PDFView.fallback(); - } - }); - }, - - setInitialView: function pdfViewSetInitialView(storedHash, scale) { - // Reset the current scale, as otherwise the page's scale might not get - // updated if the zoom level stayed the same. - this.currentScale = 0; - this.currentScaleValue = null; - if (this.initialBookmark) { - this.setHash(this.initialBookmark); - this.initialBookmark = null; - } - else if (storedHash) - this.setHash(storedHash); - else if (scale) { - this.parseScale(scale, true); - this.page = 1; - } - - if (PDFView.currentScale === UNKNOWN_SCALE) { - // Scale was not initialized: invalid bookmark or scale was not specified. - // Setting the default one. - this.parseScale(DEFAULT_SCALE, true); - } - }, - - renderHighestPriority: function pdfViewRenderHighestPriority() { - // Pages have a higher priority than thumbnails, so check them first. - var visiblePages = this.getVisiblePages(); - var pageView = this.getHighestPriority(visiblePages, this.pages, - this.pageViewScroll.down); - if (pageView) { - this.renderView(pageView, 'page'); - return; - } - // No pages needed rendering so check thumbnails. - if (this.sidebarOpen) { - var visibleThumbs = this.getVisibleThumbs(); - var thumbView = this.getHighestPriority(visibleThumbs, - this.thumbnails, - this.thumbnailViewScroll.down); - if (thumbView) - this.renderView(thumbView, 'thumbnail'); - } - }, - - getHighestPriority: function pdfViewGetHighestPriority(visible, views, - scrolledDown) { - // The state has changed figure out which page has the highest priority to - // render next (if any). - // Priority: - // 1 visible pages - // 2 if last scrolled down page after the visible pages - // 2 if last scrolled up page before the visible pages - var visibleViews = visible.views; - - var numVisible = visibleViews.length; - if (numVisible === 0) { - return false; - } - for (var i = 0; i < numVisible; ++i) { - var view = visibleViews[i].view; - if (!this.isViewFinished(view)) - return view; - } - - // All the visible views have rendered, try to render next/previous pages. - if (scrolledDown) { - var nextPageIndex = visible.last.id; - // ID's start at 1 so no need to add 1. - if (views[nextPageIndex] && !this.isViewFinished(views[nextPageIndex])) - return views[nextPageIndex]; - } else { - var previousPageIndex = visible.first.id - 2; - if (views[previousPageIndex] && - !this.isViewFinished(views[previousPageIndex])) - return views[previousPageIndex]; - } - // Everything that needs to be rendered has been. - return false; - }, - - isViewFinished: function pdfViewNeedsRendering(view) { - return view.renderingState === RenderingStates.FINISHED; - }, - - // Render a page or thumbnail view. This calls the appropriate function based - // on the views state. If the view is already rendered it will return false. - renderView: function pdfViewRender(view, type) { - var state = view.renderingState; - switch (state) { - case RenderingStates.FINISHED: - return false; - case RenderingStates.PAUSED: - PDFView.highestPriorityPage = type + view.id; - view.resume(); - break; - case RenderingStates.RUNNING: - PDFView.highestPriorityPage = type + view.id; - break; - case RenderingStates.INITIAL: - PDFView.highestPriorityPage = type + view.id; - view.draw(this.renderHighestPriority.bind(this)); - break; - } - return true; - }, - - setHash: function pdfViewSetHash(hash) { - if (!hash) - return; - - if (hash.indexOf('=') >= 0) { - var params = PDFView.parseQueryString(hash); - // borrowing syntax from "Parameters for Opening PDF Files" - if ('nameddest' in params) { - PDFView.navigateTo(params.nameddest); - return; - } - if ('page' in params) { - var pageNumber = (params.page | 0) || 1; - if ('zoom' in params) { - var zoomArgs = params.zoom.split(','); // scale,left,top - // building destination array - - // If the zoom value, it has to get divided by 100. If it is a string, - // it should stay as it is. - var zoomArg = zoomArgs[0]; - var zoomArgNumber = parseFloat(zoomArg); - if (zoomArgNumber) - zoomArg = zoomArgNumber / 100; - - var dest = [null, {name: 'XYZ'}, - zoomArgs.length > 1 ? (zoomArgs[1] | 0) : null, - zoomArgs.length > 2 ? (zoomArgs[2] | 0) : null, - zoomArg]; - var currentPage = this.pages[pageNumber - 1]; - currentPage.scrollIntoView(dest); - } else { - this.page = pageNumber; // simple page - } - } - if ('pagemode' in params) { - var toggle = document.getElementById('sidebarToggle'); - if (params.pagemode === 'thumbs' || params.pagemode === 'bookmarks') { - if (!this.sidebarOpen) { - toggle.click(); - } - this.switchSidebarView(params.pagemode === 'thumbs' ? - 'thumbs' : 'outline'); - } else if (params.pagemode === 'none' && this.sidebarOpen) { - toggle.click(); - } - } - } else if (/^\d+$/.test(hash)) // page number - this.page = hash; - else // named destination - PDFView.navigateTo(unescape(hash)); - }, - - switchSidebarView: function pdfViewSwitchSidebarView(view) { - var thumbsView = document.getElementById('thumbnailView'); - var outlineView = document.getElementById('outlineView'); - - var thumbsButton = document.getElementById('viewThumbnail'); - var outlineButton = document.getElementById('viewOutline'); - - switch (view) { - case 'thumbs': - var wasOutlineViewVisible = thumbsView.classList.contains('hidden'); - - thumbsButton.classList.add('toggled'); - outlineButton.classList.remove('toggled'); - thumbsView.classList.remove('hidden'); - outlineView.classList.add('hidden'); - - PDFView.renderHighestPriority(); - - if (wasOutlineViewVisible) { - // Ensure that the thumbnail of the current page is visible - // when switching from the outline view. - scrollIntoView(document.getElementById('thumbnailContainer' + - this.page)); - } - break; - - case 'outline': - thumbsButton.classList.remove('toggled'); - outlineButton.classList.add('toggled'); - thumbsView.classList.add('hidden'); - outlineView.classList.remove('hidden'); - - if (outlineButton.getAttribute('disabled')) - return; - break; - } - }, - - getVisiblePages: function pdfViewGetVisiblePages() { - if (!this.isFullscreen) { - return this.getVisibleElements(this.container, this.pages, true); - } else { - // The algorithm in getVisibleElements is broken in fullscreen mode. - var visible = [], page = this.page; - var currentPage = this.pages[page - 1]; - visible.push({ id: currentPage.id, view: currentPage }); - - return { first: currentPage, last: currentPage, views: visible}; - } - }, - - getVisibleThumbs: function pdfViewGetVisibleThumbs() { - return this.getVisibleElements(this.thumbnailContainer, this.thumbnails); - }, - - // Generic helper to find out what elements are visible within a scroll pane. - getVisibleElements: function pdfViewGetVisibleElements( - scrollEl, views, sortByVisibility) { - var top = scrollEl.scrollTop, bottom = top + scrollEl.clientHeight; - var left = scrollEl.scrollLeft, right = left + scrollEl.clientWidth; - - var visible = [], view; - var currentHeight, viewHeight, hiddenHeight, percentHeight; - var currentWidth, viewWidth; - for (var i = 0, ii = views.length; i < ii; ++i) { - view = views[i]; - currentHeight = view.el.offsetTop + view.el.clientTop; - viewHeight = view.el.clientHeight; - if ((currentHeight + viewHeight) < top) { - continue; - } - if (currentHeight > bottom) { - break; - } - currentWidth = view.el.offsetLeft + view.el.clientLeft; - viewWidth = view.el.clientWidth; - if ((currentWidth + viewWidth) < left || currentWidth > right) { - continue; - } - hiddenHeight = Math.max(0, top - currentHeight) + - Math.max(0, currentHeight + viewHeight - bottom); - percentHeight = ((viewHeight - hiddenHeight) * 100 / viewHeight) | 0; - - visible.push({ id: view.id, y: currentHeight, - view: view, percent: percentHeight }); - } - - var first = visible[0]; - var last = visible[visible.length - 1]; - - if (sortByVisibility) { - visible.sort(function(a, b) { - var pc = a.percent - b.percent; - if (Math.abs(pc) > 0.001) { - return -pc; - } - return a.id - b.id; // ensure stability - }); - } - return {first: first, last: last, views: visible}; - }, - - // Helper function to parse query string (e.g. ?param1=value&parm2=...). - parseQueryString: function pdfViewParseQueryString(query) { - var parts = query.split('&'); - var params = {}; - for (var i = 0, ii = parts.length; i < parts.length; ++i) { - var param = parts[i].split('='); - var key = param[0]; - var value = param.length > 1 ? param[1] : null; - params[unescape(key)] = unescape(value); - } - return params; - }, - - beforePrint: function pdfViewSetupBeforePrint() { - if (!this.supportsPrinting) { - var printMessage = mozL10n.get('printing_not_supported', null, - 'Warning: Printing is not fully supported by this browser.'); - this.error(printMessage); - return; - } - - var alertNotReady = false; - if (!this.pages.length) { - alertNotReady = true; - } else { - for (var i = 0, ii = this.pages.length; i < ii; ++i) { - if (!this.pages[i].pdfPage) { - alertNotReady = true; - break; - } - } - } - if (alertNotReady) { - var notReadyMessage = mozL10n.get('printing_not_ready', null, - 'Warning: The PDF is not fully loaded for printing.'); - window.alert(notReadyMessage); - return; - } - - var body = document.querySelector('body'); - body.setAttribute('data-mozPrintCallback', true); - for (var i = 0, ii = this.pages.length; i < ii; ++i) { - this.pages[i].beforePrint(); - } - }, - - afterPrint: function pdfViewSetupAfterPrint() { - var div = document.getElementById('printContainer'); - while (div.hasChildNodes()) - div.removeChild(div.lastChild); - }, - - fullscreen: function pdfViewFullscreen() { - var isFullscreen = document.fullscreenElement || document.mozFullScreen || - document.webkitIsFullScreen; - - if (isFullscreen) { - return false; - } - - var wrapper = document.getElementById('viewerContainer'); - if (document.documentElement.requestFullscreen) { - wrapper.requestFullscreen(); - } else if (document.documentElement.mozRequestFullScreen) { - wrapper.mozRequestFullScreen(); - } else if (document.documentElement.webkitRequestFullScreen) { - wrapper.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); - } else { - return false; - } - - this.isFullscreen = true; - var currentPage = this.pages[this.page - 1]; - this.previousScale = this.currentScaleValue; - this.parseScale('page-fit', true); - - // Wait for fullscreen to take effect - setTimeout(function() { - currentPage.scrollIntoView(); - }, 0); - - this.showPresentationControls(); - return true; - }, - - exitFullscreen: function pdfViewExitFullscreen() { - this.isFullscreen = false; - this.parseScale(this.previousScale); - this.page = this.page; - this.clearMouseScrollState(); - this.hidePresentationControls(); - - // Ensure that the thumbnail of the current page is visible - // when exiting fullscreen mode. - scrollIntoView(document.getElementById('thumbnailContainer' + this.page)); - }, - - showPresentationControls: function pdfViewShowPresentationControls() { - var DELAY_BEFORE_HIDING_CONTROLS = 3000; - var wrapper = document.getElementById('viewerContainer'); - if (this.presentationControlsTimeout) { - clearTimeout(this.presentationControlsTimeout); - } else { - wrapper.classList.add('presentationControls'); - } - this.presentationControlsTimeout = setTimeout(function hideControls() { - wrapper.classList.remove('presentationControls'); - delete PDFView.presentationControlsTimeout; - }, DELAY_BEFORE_HIDING_CONTROLS); - }, - - hidePresentationControls: function pdfViewShowPresentationControls() { - if (!this.presentationControlsTimeout) { - return; - } - clearTimeout(this.presentationControlsTimeout); - delete this.presentationControlsTimeout; - - var wrapper = document.getElementById('viewerContainer'); - wrapper.classList.remove('presentationControls'); - }, - - rotatePages: function pdfViewPageRotation(delta) { - - this.pageRotation = (this.pageRotation + 360 + delta) % 360; - - for (var i = 0, l = this.pages.length; i < l; i++) { - var page = this.pages[i]; - page.update(page.scale, this.pageRotation); - } - - for (var i = 0, l = this.thumbnails.length; i < l; i++) { - var thumb = this.thumbnails[i]; - thumb.update(this.pageRotation); - } - - this.parseScale(this.currentScaleValue, true); - - this.renderHighestPriority(); - - var currentPage = this.pages[this.page - 1]; - if (!currentPage) { - return; - } - - // Wait for fullscreen to take effect - setTimeout(function() { - currentPage.scrollIntoView(); - }, 0); - }, - - /** - * This function flips the page in presentation mode if the user scrolls up - * or down with large enough motion and prevents page flipping too often. - * - * @this {PDFView} - * @param {number} mouseScrollDelta The delta value from the mouse event. - */ - mouseScroll: function pdfViewMouseScroll(mouseScrollDelta) { - var MOUSE_SCROLL_COOLDOWN_TIME = 50; - - var currentTime = (new Date()).getTime(); - var storedTime = this.mouseScrollTimeStamp; - - // In case one page has already been flipped there is a cooldown time - // which has to expire before next page can be scrolled on to. - if (currentTime > storedTime && - currentTime - storedTime < MOUSE_SCROLL_COOLDOWN_TIME) - return; - - // In case the user decides to scroll to the opposite direction than before - // clear the accumulated delta. - if ((this.mouseScrollDelta > 0 && mouseScrollDelta < 0) || - (this.mouseScrollDelta < 0 && mouseScrollDelta > 0)) - this.clearMouseScrollState(); - - this.mouseScrollDelta += mouseScrollDelta; - - var PAGE_FLIP_THRESHOLD = 120; - if (Math.abs(this.mouseScrollDelta) >= PAGE_FLIP_THRESHOLD) { - - var PageFlipDirection = { - UP: -1, - DOWN: 1 - }; - - // In fullscreen mode scroll one page at a time. - var pageFlipDirection = (this.mouseScrollDelta > 0) ? - PageFlipDirection.UP : - PageFlipDirection.DOWN; - this.clearMouseScrollState(); - var currentPage = this.page; - - // In case we are already on the first or the last page there is no need - // to do anything. - if ((currentPage == 1 && pageFlipDirection == PageFlipDirection.UP) || - (currentPage == this.pages.length && - pageFlipDirection == PageFlipDirection.DOWN)) - return; - - this.page += pageFlipDirection; - this.mouseScrollTimeStamp = currentTime; - } - }, - - /** - * This function clears the member attributes used with mouse scrolling in - * presentation mode. - * - * @this {PDFView} - */ - clearMouseScrollState: function pdfViewClearMouseScrollState() { - this.mouseScrollTimeStamp = 0; - this.mouseScrollDelta = 0; - } -}; - -var PageView = function pageView(container, id, scale, - navigateTo, defaultViewport) { - this.id = id; - - this.rotation = 0; - this.scale = scale || 1.0; - this.viewport = defaultViewport; - this.pdfPageRotate = defaultViewport.rotate; - - this.renderingState = RenderingStates.INITIAL; - this.resume = null; - - this.textContent = null; - this.textLayer = null; - - var anchor = document.createElement('a'); - anchor.name = '' + this.id; - - var div = this.el = document.createElement('div'); - div.id = 'pageContainer' + this.id; - div.className = 'page'; - div.style.width = Math.floor(this.viewport.width) + 'px'; - div.style.height = Math.floor(this.viewport.height) + 'px'; - - container.appendChild(anchor); - container.appendChild(div); - - this.setPdfPage = function pageViewSetPdfPage(pdfPage) { - this.pdfPage = pdfPage; - this.pdfPageRotate = pdfPage.rotate; - this.viewport = pdfPage.getViewport(this.scale); - this.stats = pdfPage.stats; - this.update(); - }; - - this.destroy = function pageViewDestroy() { - this.update(); - if (this.pdfPage) { - this.pdfPage.destroy(); - } - }; - - this.update = function pageViewUpdate(scale, rotation) { - this.renderingState = RenderingStates.INITIAL; - this.resume = null; - - if (typeof rotation !== 'undefined') { - this.rotation = rotation; - } - - this.scale = scale || this.scale; - - var totalRotation = (this.rotation + this.pdfPageRotate) % 360; - this.viewport = this.viewport.clone({ - scale: this.scale, - rotation: totalRotation - }); - - div.style.width = Math.floor(this.viewport.width) + 'px'; - div.style.height = Math.floor(this.viewport.height) + 'px'; - - while (div.hasChildNodes()) - div.removeChild(div.lastChild); - div.removeAttribute('data-loaded'); - - delete this.canvas; - - this.loadingIconDiv = document.createElement('div'); - this.loadingIconDiv.className = 'loadingIcon'; - div.appendChild(this.loadingIconDiv); - }; - - Object.defineProperty(this, 'width', { - get: function PageView_getWidth() { - return this.viewport.width; - }, - enumerable: true - }); - - Object.defineProperty(this, 'height', { - get: function PageView_getHeight() { - return this.viewport.height; - }, - enumerable: true - }); - - function setupAnnotations(pdfPage, viewport) { - function bindLink(link, dest) { - link.href = PDFView.getDestinationHash(dest); - link.onclick = function pageViewSetupLinksOnclick() { - if (dest) - PDFView.navigateTo(dest); - return false; - }; - } - function createElementWithStyle(tagName, item, rect) { - if (!rect) { - rect = viewport.convertToViewportRectangle(item.rect); - rect = PDFJS.Util.normalizeRect(rect); - } - var element = document.createElement(tagName); - element.style.left = Math.floor(rect[0]) + 'px'; - element.style.top = Math.floor(rect[1]) + 'px'; - element.style.width = Math.ceil(rect[2] - rect[0]) + 'px'; - element.style.height = Math.ceil(rect[3] - rect[1]) + 'px'; - return element; - } - function createTextAnnotation(item) { - var container = document.createElement('section'); - container.className = 'annotText'; - - var rect = viewport.convertToViewportRectangle(item.rect); - rect = PDFJS.Util.normalizeRect(rect); - // sanity check because of OOo-generated PDFs - if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) { - rect[3] = rect[1] + ANNOT_MIN_SIZE; - } - if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) { - rect[2] = rect[0] + (rect[3] - rect[1]); // make it square - } - var image = createElementWithStyle('img', item, rect); - var iconName = item.name; - image.src = IMAGE_DIR + 'annotation-' + - iconName.toLowerCase() + '.svg'; - image.alt = mozL10n.get('text_annotation_type', {type: iconName}, - '[{{type}} Annotation]'); - var content = document.createElement('div'); - content.setAttribute('hidden', true); - var title = document.createElement('h1'); - var text = document.createElement('p'); - content.style.left = Math.floor(rect[2]) + 'px'; - content.style.top = Math.floor(rect[1]) + 'px'; - title.textContent = item.title; - - if (!item.content && !item.title) { - content.setAttribute('hidden', true); - } else { - var e = document.createElement('span'); - var lines = item.content.split(/(?:\r\n?|\n)/); - for (var i = 0, ii = lines.length; i < ii; ++i) { - var line = lines[i]; - e.appendChild(document.createTextNode(line)); - if (i < (ii - 1)) - e.appendChild(document.createElement('br')); - } - text.appendChild(e); - image.addEventListener('mouseover', function annotationImageOver() { - content.removeAttribute('hidden'); - }, false); - - image.addEventListener('mouseout', function annotationImageOut() { - content.setAttribute('hidden', true); - }, false); - } - - content.appendChild(title); - content.appendChild(text); - container.appendChild(image); - container.appendChild(content); - - return container; - } - - pdfPage.getAnnotations().then(function(items) { - for (var i = 0; i < items.length; i++) { - var item = items[i]; - switch (item.type) { - case 'Link': - var link = createElementWithStyle('a', item); - link.href = item.url || ''; - if (!item.url) - bindLink(link, ('dest' in item) ? item.dest : null); - div.appendChild(link); - break; - case 'Text': - var textAnnotation = createTextAnnotation(item); - if (textAnnotation) - div.appendChild(textAnnotation); - break; - } - } - }); - } - - this.getPagePoint = function pageViewGetPagePoint(x, y) { - return this.viewport.convertToPdfPoint(x, y); - }; - - this.scrollIntoView = function pageViewScrollIntoView(dest) { - if (!dest) { - scrollIntoView(div); - return; - } - - var x = 0, y = 0; - var width = 0, height = 0, widthScale, heightScale; - var scale = 0; - switch (dest[1].name) { - case 'XYZ': - x = dest[2]; - y = dest[3]; - scale = dest[4]; - // If x and/or y coordinates are not supplied, default to - // _top_ left of the page (not the obvious bottom left, - // since aligning the bottom of the intended page with the - // top of the window is rarely helpful). - x = x !== null ? x : 0; - y = y !== null ? y : this.height / this.scale; - break; - case 'Fit': - case 'FitB': - scale = 'page-fit'; - break; - case 'FitH': - case 'FitBH': - y = dest[2]; - scale = 'page-width'; - break; - case 'FitV': - case 'FitBV': - x = dest[2]; - scale = 'page-height'; - break; - case 'FitR': - x = dest[2]; - y = dest[3]; - width = dest[4] - x; - height = dest[5] - y; - widthScale = (this.container.clientWidth - SCROLLBAR_PADDING) / - width / CSS_UNITS; - heightScale = (this.container.clientHeight - SCROLLBAR_PADDING) / - height / CSS_UNITS; - scale = Math.min(widthScale, heightScale); - break; - default: - return; - } - - if (scale && scale !== PDFView.currentScale) - PDFView.parseScale(scale, true, true); - else if (PDFView.currentScale === UNKNOWN_SCALE) - PDFView.parseScale(DEFAULT_SCALE, true, true); - - var boundingRect = [ - this.viewport.convertToViewportPoint(x, y), - this.viewport.convertToViewportPoint(x + width, y + height) - ]; - setTimeout(function pageViewScrollIntoViewRelayout() { - // letting page to re-layout before scrolling - var scale = PDFView.currentScale; - var x = Math.min(boundingRect[0][0], boundingRect[1][0]); - var y = Math.min(boundingRect[0][1], boundingRect[1][1]); - var width = Math.abs(boundingRect[0][0] - boundingRect[1][0]); - var height = Math.abs(boundingRect[0][1] - boundingRect[1][1]); - - scrollIntoView(div, {left: x, top: y, width: width, height: height}); - }, 0); - }; - - this.getTextContent = function pageviewGetTextContent() { - if (!this.textContent) { - this.textContent = this.pdfPage.getTextContent(); - } - return this.textContent; - }; - - this.draw = function pageviewDraw(callback) { - var pdfPage = this.pdfPage; - - if (!pdfPage) { - var promise = PDFView.getPage(this.id); - promise.then(function(pdfPage) { - this.setPdfPage(pdfPage); - this.draw(callback); - }.bind(this)); - return; - } - - if (this.renderingState !== RenderingStates.INITIAL) { - console.error('Must be in new state before drawing'); - } - - this.renderingState = RenderingStates.RUNNING; - - var canvas = document.createElement('canvas'); - canvas.id = 'page' + this.id; - div.appendChild(canvas); - this.canvas = canvas; - - var scale = this.scale, viewport = this.viewport; - var outputScale = PDFView.getOutputScale(); - canvas.width = Math.floor(viewport.width) * outputScale.sx; - canvas.height = Math.floor(viewport.height) * outputScale.sy; - - var textLayerDiv = null; - if (!PDFJS.disableTextLayer) { - textLayerDiv = document.createElement('div'); - textLayerDiv.className = 'textLayer'; - textLayerDiv.style.width = canvas.width + 'px'; - textLayerDiv.style.height = canvas.height + 'px'; - div.appendChild(textLayerDiv); - } - var textLayer = this.textLayer = - textLayerDiv ? new TextLayerBuilder(textLayerDiv, this.id - 1) : null; - - if (outputScale.scaled) { - var cssScale = 'scale(' + (1 / outputScale.sx) + ', ' + - (1 / outputScale.sy) + ')'; - CustomStyle.setProp('transform' , canvas, cssScale); - CustomStyle.setProp('transformOrigin' , canvas, '0% 0%'); - if (textLayerDiv) { - CustomStyle.setProp('transform' , textLayerDiv, cssScale); - CustomStyle.setProp('transformOrigin' , textLayerDiv, '0% 0%'); - } - } - - var ctx = canvas.getContext('2d'); - ctx.clearRect(0, 0, canvas.width, canvas.height); - // TODO(mack): use data attributes to store these - ctx._scaleX = outputScale.sx; - ctx._scaleY = outputScale.sy; - if (outputScale.scaled) { - ctx.scale(outputScale.sx, outputScale.sy); - } -//#if (FIREFOX || MOZCENTRAL) -// // Checking if document fonts are used only once -// var checkIfDocumentFontsUsed = !PDFView.pdfDocument.embeddedFontsUsed; -//#endif - - // Rendering area - - var self = this; - var renderingWasReset = false; - function pageViewDrawCallback(error) { - if (renderingWasReset) { - return; - } - - self.renderingState = RenderingStates.FINISHED; - - if (self.loadingIconDiv) { - div.removeChild(self.loadingIconDiv); - delete self.loadingIconDiv; - } - -//#if (FIREFOX || MOZCENTRAL) -// if (checkIfDocumentFontsUsed && PDFView.pdfDocument.embeddedFontsUsed && -// !PDFView.supportsDocumentFonts) { -// console.error(mozL10n.get('web_fonts_disabled', null, -// 'Web fonts are disabled: unable to use embedded PDF fonts.')); -// PDFView.fallback(); -// } -//#endif - if (error) { - PDFView.error(mozL10n.get('rendering_error', null, - 'An error occurred while rendering the page.'), error); - } - - self.stats = pdfPage.stats; - self.updateStats(); - if (self.onAfterDraw) - self.onAfterDraw(); - - cache.push(self); - - var event = document.createEvent('CustomEvent'); - event.initCustomEvent('pagerender', true, true, { - pageNumber: pdfPage.pageNumber - }); - div.dispatchEvent(event); - - callback(); - } - - var renderContext = { - canvasContext: ctx, - viewport: this.viewport, - textLayer: textLayer, - continueCallback: function pdfViewcContinueCallback(cont) { - if (self.renderingState === RenderingStates.INITIAL) { - // The page update() was called, we just need to abort any rendering. - renderingWasReset = true; - return; - } - - if (PDFView.highestPriorityPage !== 'page' + self.id) { - self.renderingState = RenderingStates.PAUSED; - self.resume = function resumeCallback() { - self.renderingState = RenderingStates.RUNNING; - cont(); - }; - return; - } - cont(); - } - }; - this.pdfPage.render(renderContext).then( - function pdfPageRenderCallback() { - pageViewDrawCallback(null); - }, - function pdfPageRenderError(error) { - pageViewDrawCallback(error); - } - ); - - if (textLayer) { - this.getTextContent().then( - function textContentResolved(textContent) { - textLayer.setTextContent(textContent); - } - ); - } - - setupAnnotations(this.pdfPage, this.viewport); - div.setAttribute('data-loaded', true); - }; - - this.beforePrint = function pageViewBeforePrint() { - var pdfPage = this.pdfPage; - - var viewport = pdfPage.getViewport(1); - // Use the same hack we use for high dpi displays for printing to get better - // output until bug 811002 is fixed in FF. - var PRINT_OUTPUT_SCALE = 2; - var canvas = this.canvas = document.createElement('canvas'); - canvas.width = Math.floor(viewport.width) * PRINT_OUTPUT_SCALE; - canvas.height = Math.floor(viewport.height) * PRINT_OUTPUT_SCALE; - canvas.style.width = (PRINT_OUTPUT_SCALE * viewport.width) + 'pt'; - canvas.style.height = (PRINT_OUTPUT_SCALE * viewport.height) + 'pt'; - var cssScale = 'scale(' + (1 / PRINT_OUTPUT_SCALE) + ', ' + - (1 / PRINT_OUTPUT_SCALE) + ')'; - CustomStyle.setProp('transform' , canvas, cssScale); - CustomStyle.setProp('transformOrigin' , canvas, '0% 0%'); - - var printContainer = document.getElementById('printContainer'); - printContainer.appendChild(canvas); - - var self = this; - canvas.mozPrintCallback = function(obj) { - var ctx = obj.context; - - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.restore(); - ctx.scale(PRINT_OUTPUT_SCALE, PRINT_OUTPUT_SCALE); - - var renderContext = { - canvasContext: ctx, - viewport: viewport - }; - - pdfPage.render(renderContext).then(function() { - // Tell the printEngine that rendering this canvas/page has finished. - obj.done(); - self.pdfPage.destroy(); - }, function(error) { - console.error(error); - // Tell the printEngine that rendering this canvas/page has failed. - // This will make the print proces stop. - if ('abort' in obj) - obj.abort(); - else - obj.done(); - self.pdfPage.destroy(); - }); - }; - }; - - this.updateStats = function pageViewUpdateStats() { - if (!this.stats) { - return; - } - - if (PDFJS.pdfBug && Stats.enabled) { - var stats = this.stats; - Stats.add(this.id, stats); - } - }; -}; - -var ThumbnailView = function thumbnailView(container, id, defaultViewport) { - var anchor = document.createElement('a'); - anchor.href = PDFView.getAnchorUrl('#page=' + id); - anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}'); - anchor.onclick = function stopNavigation() { - PDFView.page = id; - return false; - }; - - - this.pdfPage = undefined; - this.viewport = defaultViewport; - this.pdfPageRotate = defaultViewport.rotate; - - this.rotation = 0; - this.pageWidth = this.viewport.width; - this.pageHeight = this.viewport.height; - this.pageRatio = this.pageWidth / this.pageHeight; - this.id = id; - - this.canvasWidth = 98; - this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight; - this.scale = (this.canvasWidth / this.pageWidth); - - var div = this.el = document.createElement('div'); - div.id = 'thumbnailContainer' + id; - div.className = 'thumbnail'; - - if (id === 1) { - // Highlight the thumbnail of the first page when no page number is - // specified (or exists in cache) when the document is loaded. - div.classList.add('selected'); - } - - var ring = document.createElement('div'); - ring.className = 'thumbnailSelectionRing'; - ring.style.width = this.canvasWidth + 'px'; - ring.style.height = this.canvasHeight + 'px'; - - div.appendChild(ring); - anchor.appendChild(div); - container.appendChild(anchor); - - this.hasImage = false; - this.renderingState = RenderingStates.INITIAL; - - this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) { - this.pdfPage = pdfPage; - this.pdfPageRotate = pdfPage.rotate; - this.viewport = pdfPage.getViewport(1); - this.update(); - }; - - this.update = function thumbnailViewUpdate(rot) { - if (!this.pdfPage) { - return; - } - - if (rot !== undefined) { - this.rotation = rot; - } - - var totalRotation = (this.rotation + this.pdfPage.rotate) % 360; - this.viewport = this.viewport.clone({ - scale: 1, - rotation: totalRotation - }); - this.pageWidth = this.viewport.width; - this.pageHeight = this.viewport.height; - this.pageRatio = this.pageWidth / this.pageHeight; - - this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight; - this.scale = (this.canvasWidth / this.pageWidth); - - div.removeAttribute('data-loaded'); - ring.textContent = ''; - ring.style.width = this.canvasWidth + 'px'; - ring.style.height = this.canvasHeight + 'px'; - - this.hasImage = false; - this.renderingState = RenderingStates.INITIAL; - this.resume = null; - }; - - this.getPageDrawContext = function thumbnailViewGetPageDrawContext() { - var canvas = document.createElement('canvas'); - canvas.id = 'thumbnail' + id; - - canvas.width = this.canvasWidth; - canvas.height = this.canvasHeight; - canvas.className = 'thumbnailImage'; - canvas.setAttribute('aria-label', mozL10n.get('thumb_page_canvas', - {page: id}, 'Thumbnail of Page {{page}}')); - - div.setAttribute('data-loaded', true); - - ring.appendChild(canvas); - - var ctx = canvas.getContext('2d'); - ctx.save(); - ctx.fillStyle = 'rgb(255, 255, 255)'; - ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight); - ctx.restore(); - return ctx; - }; - - this.drawingRequired = function thumbnailViewDrawingRequired() { - return !this.hasImage; - }; - - this.draw = function thumbnailViewDraw(callback) { - if (!this.pdfPage) { - var promise = PDFView.getPage(this.id); - promise.then(function(pdfPage) { - this.setPdfPage(pdfPage); - this.draw(callback); - }.bind(this)); - return; - } - - if (this.renderingState !== RenderingStates.INITIAL) { - console.error('Must be in new state before drawing'); - } - - this.renderingState = RenderingStates.RUNNING; - if (this.hasImage) { - callback(); - return; - } - - var self = this; - var ctx = this.getPageDrawContext(); - var drawViewport = this.viewport.clone({ scale: this.scale }); - var renderContext = { - canvasContext: ctx, - viewport: drawViewport, - continueCallback: function(cont) { - if (PDFView.highestPriorityPage !== 'thumbnail' + self.id) { - self.renderingState = RenderingStates.PAUSED; - self.resume = function() { - self.renderingState = RenderingStates.RUNNING; - cont(); - }; - return; - } - cont(); - } - }; - this.pdfPage.render(renderContext).then( - function pdfPageRenderCallback() { - self.renderingState = RenderingStates.FINISHED; - callback(); - }, - function pdfPageRenderError(error) { - self.renderingState = RenderingStates.FINISHED; - callback(); - } - ); - this.hasImage = true; - }; - - this.setImage = function thumbnailViewSetImage(img) { - if (this.hasImage || !img) - return; - this.renderingState = RenderingStates.FINISHED; - var ctx = this.getPageDrawContext(); - ctx.drawImage(img, 0, 0, img.width, img.height, - 0, 0, ctx.canvas.width, ctx.canvas.height); - - this.hasImage = true; - }; -}; - -var DocumentOutlineView = function documentOutlineView(outline) { - var outlineView = document.getElementById('outlineView'); - while (outlineView.firstChild) - outlineView.removeChild(outlineView.firstChild); - - function bindItemLink(domObj, item) { - domObj.href = PDFView.getDestinationHash(item.dest); - domObj.onclick = function documentOutlineViewOnclick(e) { - PDFView.navigateTo(item.dest); - return false; - }; - } - - if (!outline) { - var noOutline = document.createElement('div'); - noOutline.classList.add('noOutline'); - noOutline.textContent = mozL10n.get('no_outline', null, - 'No Outline Available'); - outlineView.appendChild(noOutline); - return; - } - - var queue = [{parent: outlineView, items: outline}]; - while (queue.length > 0) { - var levelData = queue.shift(); - var i, n = levelData.items.length; - for (i = 0; i < n; i++) { - var item = levelData.items[i]; - var div = document.createElement('div'); - div.className = 'outlineItem'; - var a = document.createElement('a'); - bindItemLink(a, item); - a.textContent = item.title; - div.appendChild(a); - - if (item.items.length > 0) { - var itemsDiv = document.createElement('div'); - itemsDiv.className = 'outlineItems'; - div.appendChild(itemsDiv); - queue.push({parent: itemsDiv, items: item.items}); - } - - levelData.parent.appendChild(div); - } - } -}; - -// optimised CSS custom property getter/setter -var CustomStyle = (function CustomStyleClosure() { - - // As noted on: http://www.zachstronaut.com/posts/2009/02/17/ - // animate-css-transforms-firefox-webkit.html - // in some versions of IE9 it is critical that ms appear in this list - // before Moz - var prefixes = ['ms', 'Moz', 'Webkit', 'O']; - var _cache = { }; - - function CustomStyle() { - } - - CustomStyle.getProp = function get(propName, element) { - // check cache only when no element is given - if (arguments.length == 1 && typeof _cache[propName] == 'string') { - return _cache[propName]; - } - - element = element || document.documentElement; - var style = element.style, prefixed, uPropName; - - // test standard property first - if (typeof style[propName] == 'string') { - return (_cache[propName] = propName); - } - - // capitalize - uPropName = propName.charAt(0).toUpperCase() + propName.slice(1); - - // test vendor specific properties - for (var i = 0, l = prefixes.length; i < l; i++) { - prefixed = prefixes[i] + uPropName; - if (typeof style[prefixed] == 'string') { - return (_cache[propName] = prefixed); - } - } - - //if all fails then set to undefined - return (_cache[propName] = 'undefined'); - }; - - CustomStyle.setProp = function set(propName, element, str) { - var prop = this.getProp(propName); - if (prop != 'undefined') - element.style[prop] = str; - }; - - return CustomStyle; -})(); - -var TextLayerBuilder = function textLayerBuilder(textLayerDiv, pageIdx) { - var textLayerFrag = document.createDocumentFragment(); - - this.textLayerDiv = textLayerDiv; - this.layoutDone = false; - this.divContentDone = false; - this.pageIdx = pageIdx; - this.matches = []; - - this.beginLayout = function textLayerBuilderBeginLayout() { - this.textDivs = []; - this.textLayerQueue = []; - this.renderingDone = false; - }; - - this.endLayout = function textLayerBuilderEndLayout() { - this.layoutDone = true; - this.insertDivContent(); - }; - - this.renderLayer = function textLayerBuilderRenderLayer() { - var self = this; - var textDivs = this.textDivs; - var bidiTexts = this.textContent.bidiTexts; - var textLayerDiv = this.textLayerDiv; - var canvas = document.createElement('canvas'); - var ctx = canvas.getContext('2d'); - - // No point in rendering so many divs as it'd make the browser unusable - // even after the divs are rendered - var MAX_TEXT_DIVS_TO_RENDER = 100000; - if (textDivs.length > MAX_TEXT_DIVS_TO_RENDER) - return; - - for (var i = 0, ii = textDivs.length; i < ii; i++) { - var textDiv = textDivs[i]; - if ('isWhitespace' in textDiv.dataset) { - continue; - } - textLayerFrag.appendChild(textDiv); - - ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily; - var width = ctx.measureText(textDiv.textContent).width; - - if (width > 0) { - var textScale = textDiv.dataset.canvasWidth / width; - - var transform = 'scale(' + textScale + ', 1)'; - if (bidiTexts[i].dir === 'ttb') { - transform = 'rotate(90deg) ' + transform; - } - CustomStyle.setProp('transform' , textDiv, transform); - CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%'); - - textLayerDiv.appendChild(textDiv); - } - } - - this.renderingDone = true; - this.updateMatches(); - - textLayerDiv.appendChild(textLayerFrag); - }; - - this.setupRenderLayoutTimer = function textLayerSetupRenderLayoutTimer() { - // Schedule renderLayout() if user has been scrolling, otherwise - // run it right away - var RENDER_DELAY = 200; // in ms - var self = this; - if (Date.now() - PDFView.lastScroll > RENDER_DELAY) { - // Render right away - this.renderLayer(); - } else { - // Schedule - if (this.renderTimer) - clearTimeout(this.renderTimer); - this.renderTimer = setTimeout(function() { - self.setupRenderLayoutTimer(); - }, RENDER_DELAY); - } - }; - - this.appendText = function textLayerBuilderAppendText(geom) { - var textDiv = document.createElement('div'); - - // vScale and hScale already contain the scaling to pixel units - var fontHeight = geom.fontSize * Math.abs(geom.vScale); - textDiv.dataset.canvasWidth = geom.canvasWidth * geom.hScale; - textDiv.dataset.fontName = geom.fontName; - - textDiv.style.fontSize = fontHeight + 'px'; - textDiv.style.fontFamily = geom.fontFamily; - textDiv.style.left = geom.x + 'px'; - textDiv.style.top = (geom.y - fontHeight) + 'px'; - - // The content of the div is set in the `setTextContent` function. - - this.textDivs.push(textDiv); - }; - - this.insertDivContent = function textLayerUpdateTextContent() { - // Only set the content of the divs once layout has finished, the content - // for the divs is available and content is not yet set on the divs. - if (!this.layoutDone || this.divContentDone || !this.textContent) - return; - - this.divContentDone = true; - - var textDivs = this.textDivs; - var bidiTexts = this.textContent.bidiTexts; - - for (var i = 0; i < bidiTexts.length; i++) { - var bidiText = bidiTexts[i]; - var textDiv = textDivs[i]; - if (!/\S/.test(bidiText.str)) { - textDiv.dataset.isWhitespace = true; - continue; - } - - textDiv.textContent = bidiText.str; - // bidiText.dir may be 'ttb' for vertical texts. - textDiv.dir = bidiText.dir === 'rtl' ? 'rtl' : 'ltr'; - } - - this.setupRenderLayoutTimer(); - }; - - this.setTextContent = function textLayerBuilderSetTextContent(textContent) { - this.textContent = textContent; - this.insertDivContent(); - }; - - this.convertMatches = function textLayerBuilderConvertMatches(matches) { - var i = 0; - var iIndex = 0; - var bidiTexts = this.textContent.bidiTexts; - var end = bidiTexts.length - 1; - var queryLen = PDFFindController.state.query.length; - - var lastDivIdx = -1; - var pos; - - var ret = []; - - // Loop over all the matches. - for (var m = 0; m < matches.length; m++) { - var matchIdx = matches[m]; - // # Calculate the begin position. - - // Loop over the divIdxs. - while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) { - iIndex += bidiTexts[i].str.length; - i++; - } - - // TODO: Do proper handling here if something goes wrong. - if (i == bidiTexts.length) { - console.error('Could not find matching mapping'); - } - - var match = { - begin: { - divIdx: i, - offset: matchIdx - iIndex - } - }; - - // # Calculate the end position. - matchIdx += queryLen; - - // Somewhat same array as above, but use a > instead of >= to get the end - // position right. - while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) { - iIndex += bidiTexts[i].str.length; - i++; - } - - match.end = { - divIdx: i, - offset: matchIdx - iIndex - }; - ret.push(match); - } - - return ret; - }; - - this.renderMatches = function textLayerBuilder_renderMatches(matches) { - // Early exit if there is nothing to render. - if (matches.length === 0) { - return; - } - - var bidiTexts = this.textContent.bidiTexts; - var textDivs = this.textDivs; - var prevEnd = null; - var isSelectedPage = this.pageIdx === PDFFindController.selected.pageIdx; - var selectedMatchIdx = PDFFindController.selected.matchIdx; - var highlightAll = PDFFindController.state.highlightAll; - - var infty = { - divIdx: -1, - offset: undefined - }; - - function beginText(begin, className) { - var divIdx = begin.divIdx; - var div = textDivs[divIdx]; - div.textContent = ''; - - var content = bidiTexts[divIdx].str.substring(0, begin.offset); - var node = document.createTextNode(content); - if (className) { - var isSelected = isSelectedPage && - divIdx === selectedMatchIdx; - var span = document.createElement('span'); - span.className = className + (isSelected ? ' selected' : ''); - span.appendChild(node); - div.appendChild(span); - return; - } - div.appendChild(node); - } - - function appendText(from, to, className) { - var divIdx = from.divIdx; - var div = textDivs[divIdx]; - - var content = bidiTexts[divIdx].str.substring(from.offset, to.offset); - var node = document.createTextNode(content); - if (className) { - var span = document.createElement('span'); - span.className = className; - span.appendChild(node); - div.appendChild(span); - return; - } - div.appendChild(node); - } - - function highlightDiv(divIdx, className) { - textDivs[divIdx].className = className; - } - - var i0 = selectedMatchIdx, i1 = i0 + 1, i; - - if (highlightAll) { - i0 = 0; - i1 = matches.length; - } else if (!isSelectedPage) { - // Not highlighting all and this isn't the selected page, so do nothing. - return; - } - - for (i = i0; i < i1; i++) { - var match = matches[i]; - var begin = match.begin; - var end = match.end; - - var isSelected = isSelectedPage && i === selectedMatchIdx; - var highlightSuffix = (isSelected ? ' selected' : ''); - if (isSelected) - scrollIntoView(textDivs[begin.divIdx], {top: -50}); - - // Match inside new div. - if (!prevEnd || begin.divIdx !== prevEnd.divIdx) { - // If there was a previous div, then add the text at the end - if (prevEnd !== null) { - appendText(prevEnd, infty); - } - // clears the divs and set the content until the begin point. - beginText(begin); - } else { - appendText(prevEnd, begin); - } - - if (begin.divIdx === end.divIdx) { - appendText(begin, end, 'highlight' + highlightSuffix); - } else { - appendText(begin, infty, 'highlight begin' + highlightSuffix); - for (var n = begin.divIdx + 1; n < end.divIdx; n++) { - highlightDiv(n, 'highlight middle' + highlightSuffix); - } - beginText(end, 'highlight end' + highlightSuffix); - } - prevEnd = end; - } - - if (prevEnd) { - appendText(prevEnd, infty); - } - }; - - this.updateMatches = function textLayerUpdateMatches() { - // Only show matches, once all rendering is done. - if (!this.renderingDone) - return; - - // Clear out all matches. - var matches = this.matches; - var textDivs = this.textDivs; - var bidiTexts = this.textContent.bidiTexts; - var clearedUntilDivIdx = -1; - - // Clear out all current matches. - for (var i = 0; i < matches.length; i++) { - var match = matches[i]; - var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx); - for (var n = begin; n <= match.end.divIdx; n++) { - var div = textDivs[n]; - div.textContent = bidiTexts[n].str; - div.className = ''; - } - clearedUntilDivIdx = match.end.divIdx + 1; - } - - if (!PDFFindController.active) - return; - - // Convert the matches on the page controller into the match format used - // for the textLayer. - this.matches = matches = - this.convertMatches(PDFFindController.pageMatches[this.pageIdx] || []); - - this.renderMatches(this.matches); - }; -}; - -document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) { - PDFView.initialize(); - var params = PDFView.parseQueryString(document.location.search.substring(1)); - -//#if !(FIREFOX || MOZCENTRAL) - var file = params.file || DEFAULT_URL; -//#else -//var file = window.location.toString() -//#endif - -//#if !(FIREFOX || MOZCENTRAL) - if (!window.File || !window.FileReader || !window.FileList || !window.Blob) { - document.getElementById('openFile').setAttribute('hidden', 'true'); - } else { - document.getElementById('fileInput').value = null; - } -//#else -//document.getElementById('openFile').setAttribute('hidden', 'true'); -//#endif - - // Special debugging flags in the hash section of the URL. - var hash = document.location.hash.substring(1); - var hashParams = PDFView.parseQueryString(hash); - - if ('disableWorker' in hashParams) - PDFJS.disableWorker = (hashParams['disableWorker'] === 'true'); - -//#if !(FIREFOX || MOZCENTRAL) - var locale = navigator.language; - if ('locale' in hashParams) - locale = hashParams['locale']; - mozL10n.setLanguage(locale); -//#endif - - if ('textLayer' in hashParams) { - switch (hashParams['textLayer']) { - case 'off': - PDFJS.disableTextLayer = true; - break; - case 'visible': - case 'shadow': - case 'hover': - var viewer = document.getElementById('viewer'); - viewer.classList.add('textLayer-' + hashParams['textLayer']); - break; - } - } - -//#if !(FIREFOX || MOZCENTRAL) - if ('pdfBug' in hashParams) { -//#else -//if ('pdfBug' in hashParams && FirefoxCom.requestSync('pdfBugEnabled')) { -//#endif - PDFJS.pdfBug = true; - var pdfBug = hashParams['pdfBug']; - var enabled = pdfBug.split(','); - PDFBug.enable(enabled); - PDFBug.init(); - } - - if (!PDFView.supportsPrinting) { - document.getElementById('print').classList.add('hidden'); - } - - if (!PDFView.supportsFullscreen) { - document.getElementById('fullscreen').classList.add('hidden'); - } - - if (PDFView.supportsIntegratedFind) { - document.querySelector('#viewFind').classList.add('hidden'); - } - - // Listen for warnings to trigger the fallback UI. Errors should be caught - // and call PDFView.error() so we don't need to listen for those. - PDFJS.LogManager.addLogger({ - warn: function() { - PDFView.fallback(); - } - }); - - var mainContainer = document.getElementById('mainContainer'); - var outerContainer = document.getElementById('outerContainer'); - mainContainer.addEventListener('transitionend', function(e) { - if (e.target == mainContainer) { - var event = document.createEvent('UIEvents'); - event.initUIEvent('resize', false, false, window, 0); - window.dispatchEvent(event); - outerContainer.classList.remove('sidebarMoving'); - } - }, true); - - document.getElementById('sidebarToggle').addEventListener('click', - function() { - this.classList.toggle('toggled'); - outerContainer.classList.add('sidebarMoving'); - outerContainer.classList.toggle('sidebarOpen'); - PDFView.sidebarOpen = outerContainer.classList.contains('sidebarOpen'); - PDFView.renderHighestPriority(); - }); - - document.getElementById('viewThumbnail').addEventListener('click', - function() { - PDFView.switchSidebarView('thumbs'); - }); - - document.getElementById('viewOutline').addEventListener('click', - function() { - PDFView.switchSidebarView('outline'); - }); - - document.getElementById('previous').addEventListener('click', - function() { - PDFView.page--; - }); - - document.getElementById('next').addEventListener('click', - function() { - PDFView.page++; - }); - - document.querySelector('.zoomIn').addEventListener('click', - function() { - PDFView.zoomIn(); - }); - - document.querySelector('.zoomOut').addEventListener('click', - function() { - PDFView.zoomOut(); - }); - - document.getElementById('fullscreen').addEventListener('click', - function() { - PDFView.fullscreen(); - }); - - document.getElementById('openFile').addEventListener('click', - function() { - document.getElementById('fileInput').click(); - }); - - document.getElementById('print').addEventListener('click', - function() { - window.print(); - }); - - document.getElementById('download').addEventListener('click', - function() { - PDFView.download(); - }); - - document.getElementById('pageNumber').addEventListener('click', - function() { - this.select(); - }); - - document.getElementById('pageNumber').addEventListener('change', - function() { - // Handle the user inputting a floating point number. - PDFView.page = (this.value | 0); - - if (this.value !== (this.value | 0).toString()) { - this.value = PDFView.page; - } - }); - - document.getElementById('scaleSelect').addEventListener('change', - function() { - PDFView.parseScale(this.value); - }); - - document.getElementById('first_page').addEventListener('click', - function() { - PDFView.page = 1; - }); - - document.getElementById('last_page').addEventListener('click', - function() { - PDFView.page = PDFView.pdfDocument.numPages; - }); - - document.getElementById('page_rotate_ccw').addEventListener('click', - function() { - PDFView.rotatePages(-90); - }); - - document.getElementById('page_rotate_cw').addEventListener('click', - function() { - PDFView.rotatePages(90); - }); - -//#if (FIREFOX || MOZCENTRAL) -//if (FirefoxCom.requestSync('getLoadingType') == 'passive') { -// PDFView.setTitleUsingUrl(file); -// PDFView.initPassiveLoading(); -// return; -//} -//#endif - -//#if !B2G - PDFView.open(file, 0); -//#endif -}, true); - -function updateViewarea() { - - if (!PDFView.initialized) - return; - var visible = PDFView.getVisiblePages(); - var visiblePages = visible.views; - if (visiblePages.length === 0) { - return; - } - - PDFView.renderHighestPriority(); - - var currentId = PDFView.page; - var firstPage = visible.first; - - for (var i = 0, ii = visiblePages.length, stillFullyVisible = false; - i < ii; ++i) { - var page = visiblePages[i]; - - if (page.percent < 100) - break; - - if (page.id === PDFView.page) { - stillFullyVisible = true; - break; - } - } - - if (!stillFullyVisible) { - currentId = visiblePages[0].id; - } - - if (!PDFView.isFullscreen) { - updateViewarea.inProgress = true; // used in "set page" - PDFView.page = currentId; - updateViewarea.inProgress = false; - } - - var currentScale = PDFView.currentScale; - var currentScaleValue = PDFView.currentScaleValue; - var normalizedScaleValue = currentScaleValue == currentScale ? - currentScale * 100 : currentScaleValue; - - var pageNumber = firstPage.id; - var pdfOpenParams = '#page=' + pageNumber; - pdfOpenParams += '&zoom=' + normalizedScaleValue; - var currentPage = PDFView.pages[pageNumber - 1]; - var topLeft = currentPage.getPagePoint(PDFView.container.scrollLeft, - (PDFView.container.scrollTop - firstPage.y)); - pdfOpenParams += ',' + Math.round(topLeft[0]) + ',' + Math.round(topLeft[1]); - - var store = PDFView.store; - store.initializedPromise.then(function() { - store.set('exists', true); - store.set('page', pageNumber); - store.set('zoom', normalizedScaleValue); - store.set('scrollLeft', Math.round(topLeft[0])); - store.set('scrollTop', Math.round(topLeft[1])); - }); - var href = PDFView.getAnchorUrl(pdfOpenParams); - document.getElementById('viewBookmark').href = href; -} - -window.addEventListener('resize', function webViewerResize(evt) { - if (PDFView.initialized && - (document.getElementById('pageWidthOption').selected || - document.getElementById('pageFitOption').selected || - document.getElementById('pageAutoOption').selected)) - PDFView.parseScale(document.getElementById('scaleSelect').value); - updateViewarea(); -}); - -window.addEventListener('hashchange', function webViewerHashchange(evt) { - PDFView.setHash(document.location.hash.substring(1)); -}); - -window.addEventListener('change', function webViewerChange(evt) { - var files = evt.target.files; - if (!files || files.length === 0) - return; - - // Read the local file into a Uint8Array. - var fileReader = new FileReader(); - fileReader.onload = function webViewerChangeFileReaderOnload(evt) { - var buffer = evt.target.result; - var uint8Array = new Uint8Array(buffer); - PDFView.open(uint8Array, 0); - }; - - var file = files[0]; - fileReader.readAsArrayBuffer(file); - PDFView.setTitleUsingUrl(file.name); - - // URL does not reflect proper document location - hiding some icons. - document.getElementById('viewBookmark').setAttribute('hidden', 'true'); - document.getElementById('download').setAttribute('hidden', 'true'); -}, true); - -function selectScaleOption(value) { - var options = document.getElementById('scaleSelect').options; - var predefinedValueFound = false; - for (var i = 0; i < options.length; i++) { - var option = options[i]; - if (option.value != value) { - option.selected = false; - continue; - } - option.selected = true; - predefinedValueFound = true; - } - return predefinedValueFound; -} - -window.addEventListener('localized', function localized(evt) { - document.getElementsByTagName('html')[0].dir = mozL10n.getDirection(); - - // Adjust the width of the zoom box to fit the content. - PDFView.animationStartedPromise.then( - function() { - var container = document.getElementById('scaleSelectContainer'); - var select = document.getElementById('scaleSelect'); - select.setAttribute('style', 'min-width: inherit;'); - var width = select.clientWidth + 8; - select.setAttribute('style', 'min-width: ' + (width + 20) + 'px;'); - container.setAttribute('style', 'min-width: ' + width + 'px; ' + - 'max-width: ' + width + 'px;'); - }); -}, true); - -window.addEventListener('scalechange', function scalechange(evt) { - var customScaleOption = document.getElementById('customScaleOption'); - customScaleOption.selected = false; - - if (!evt.resetAutoSettings && - (document.getElementById('pageWidthOption').selected || - document.getElementById('pageFitOption').selected || - document.getElementById('pageAutoOption').selected)) { - updateViewarea(); - return; - } - - var predefinedValueFound = selectScaleOption('' + evt.scale); - if (!predefinedValueFound) { - customScaleOption.textContent = Math.round(evt.scale * 10000) / 100 + '%'; - customScaleOption.selected = true; - } - - document.getElementById('zoom_out').disabled = (evt.scale === MIN_SCALE); - document.getElementById('zoom_in').disabled = (evt.scale === MAX_SCALE); - - updateViewarea(); -}, true); - -window.addEventListener('pagechange', function pagechange(evt) { - var page = evt.pageNumber; - if (PDFView.previousPageNumber !== page) { - document.getElementById('pageNumber').value = page; - var selected = document.querySelector('.thumbnail.selected'); - if (selected) - selected.classList.remove('selected'); - var thumbnail = document.getElementById('thumbnailContainer' + page); - thumbnail.classList.add('selected'); - var visibleThumbs = PDFView.getVisibleThumbs(); - var numVisibleThumbs = visibleThumbs.views.length; - // If the thumbnail isn't currently visible scroll it into view. - if (numVisibleThumbs > 0) { - var first = visibleThumbs.first.id; - // Account for only one thumbnail being visible. - var last = numVisibleThumbs > 1 ? - visibleThumbs.last.id : first; - if (page <= first || page >= last) - scrollIntoView(thumbnail); - } - - } - document.getElementById('previous').disabled = (page <= 1); - document.getElementById('next').disabled = (page >= PDFView.pages.length); -}, true); - -// Firefox specific event, so that we can prevent browser from zooming -window.addEventListener('DOMMouseScroll', function(evt) { - if (evt.ctrlKey) { - evt.preventDefault(); - - var ticks = evt.detail; - var direction = (ticks > 0) ? 'zoomOut' : 'zoomIn'; - for (var i = 0, length = Math.abs(ticks); i < length; i++) - PDFView[direction](); - } else if (PDFView.isFullscreen) { - var FIREFOX_DELTA_FACTOR = -40; - PDFView.mouseScroll(evt.detail * FIREFOX_DELTA_FACTOR); - } -}, false); - -window.addEventListener('mousemove', function mousemove(evt) { - if (PDFView.isFullscreen) { - PDFView.showPresentationControls(); - } -}, false); - -window.addEventListener('mousedown', function mousedown(evt) { - if (PDFView.isFullscreen && evt.button === 0) { - // Enable clicking of links in fullscreen mode. - // Note: Only links that point to the currently loaded PDF document works. - var targetHref = evt.target.href; - var internalLink = targetHref && (targetHref.replace(/#.*$/, '') === - window.location.href.replace(/#.*$/, '')); - if (!internalLink) { - // Unless an internal link was clicked, advance a page in fullscreen mode. - evt.preventDefault(); - PDFView.page++; - } - } -}, false); - -window.addEventListener('click', function click(evt) { - if (PDFView.isFullscreen && evt.button === 0) { - // Necessary since preventDefault() in 'mousedown' won't stop - // the event propagation in all circumstances. - evt.preventDefault(); - } -}, false); - -window.addEventListener('keydown', function keydown(evt) { - var handled = false; - var cmd = (evt.ctrlKey ? 1 : 0) | - (evt.altKey ? 2 : 0) | - (evt.shiftKey ? 4 : 0) | - (evt.metaKey ? 8 : 0); - - // First, handle the key bindings that are independent whether an input - // control is selected or not. - if (cmd === 1 || cmd === 8 || cmd === 5 || cmd === 12) { - // either CTRL or META key with optional SHIFT. - switch (evt.keyCode) { - case 70: - if (!PDFView.supportsIntegratedFind) { - PDFFindBar.toggle(); - handled = true; - } - break; - case 61: // FF/Mac '=' - case 107: // FF '+' and '=' - case 187: // Chrome '+' - case 171: // FF with German keyboard - PDFView.zoomIn(); - handled = true; - break; - case 173: // FF/Mac '-' - case 109: // FF '-' - case 189: // Chrome '-' - PDFView.zoomOut(); - handled = true; - break; - case 48: // '0' - case 96: // '0' on Numpad of Swedish keyboard - PDFView.parseScale(DEFAULT_SCALE, true); - handled = false; // keeping it unhandled (to restore page zoom to 100%) - break; - } - } - - // CTRL or META with or without SHIFT. - if (cmd == 1 || cmd == 8 || cmd == 5 || cmd == 12) { - switch (evt.keyCode) { - case 71: // g - if (!PDFView.supportsIntegratedFind) { - PDFFindBar.dispatchEvent('again', cmd == 5 || cmd == 12); - handled = true; - } - break; - } - } - - if (handled) { - evt.preventDefault(); - return; - } - - // Some shortcuts should not get handled if a control/input element - // is selected. - var curElement = document.activeElement; - if (curElement && (curElement.tagName == 'INPUT' || - curElement.tagName == 'SELECT')) { - return; - } - var controlsElement = document.getElementById('toolbar'); - while (curElement) { - if (curElement === controlsElement && !PDFView.isFullscreen) - return; // ignoring if the 'toolbar' element is focused - curElement = curElement.parentNode; - } - - if (cmd === 0) { // no control key pressed at all. - switch (evt.keyCode) { - case 38: // up arrow - case 33: // pg up - case 8: // backspace - if (!PDFView.isFullscreen && PDFView.currentScaleValue !== 'page-fit') { - break; - } - /* in fullscreen mode */ - /* falls through */ - case 37: // left arrow - // horizontal scrolling using arrow keys - if (PDFView.isHorizontalScrollbarEnabled) { - break; - } - /* falls through */ - case 75: // 'k' - case 80: // 'p' - PDFView.page--; - handled = true; - break; - case 27: // esc key - if (!PDFView.supportsIntegratedFind && PDFFindBar.opened) { - PDFFindBar.close(); - handled = true; - } - break; - case 40: // down arrow - case 34: // pg down - case 32: // spacebar - if (!PDFView.isFullscreen && PDFView.currentScaleValue !== 'page-fit') { - break; - } - /* falls through */ - case 39: // right arrow - // horizontal scrolling using arrow keys - if (PDFView.isHorizontalScrollbarEnabled) { - break; - } - /* falls through */ - case 74: // 'j' - case 78: // 'n' - PDFView.page++; - handled = true; - break; - - case 36: // home - if (PDFView.isFullscreen) { - PDFView.page = 1; - handled = true; - } - break; - case 35: // end - if (PDFView.isFullscreen) { - PDFView.page = PDFView.pdfDocument.numPages; - handled = true; - } - break; - - case 82: // 'r' - PDFView.rotatePages(90); - break; - } - } - - if (cmd == 4) { // shift-key - switch (evt.keyCode) { - case 82: // 'r' - PDFView.rotatePages(-90); - break; - } - } - - if (handled) { - evt.preventDefault(); - PDFView.clearMouseScrollState(); - } -}); - -window.addEventListener('beforeprint', function beforePrint(evt) { - PDFView.beforePrint(); -}); - -window.addEventListener('afterprint', function afterPrint(evt) { - PDFView.afterPrint(); -}); - -(function fullscreenClosure() { - function fullscreenChange(e) { - var isFullscreen = document.fullscreenElement || document.mozFullScreen || - document.webkitIsFullScreen; - - if (!isFullscreen) { - PDFView.exitFullscreen(); - } - } - - window.addEventListener('fullscreenchange', fullscreenChange, false); - window.addEventListener('mozfullscreenchange', fullscreenChange, false); - window.addEventListener('webkitfullscreenchange', fullscreenChange, false); -})(); - -(function animationStartedClosure() { - // The offsetParent is not set until the pdf.js iframe or object is visible. - // Waiting for first animation. - var requestAnimationFrame = window.requestAnimationFrame || - window.mozRequestAnimationFrame || - window.webkitRequestAnimationFrame || - window.oRequestAnimationFrame || - window.msRequestAnimationFrame || - function startAtOnce(callback) { callback(); }; - PDFView.animationStartedPromise = new PDFJS.Promise(); - requestAnimationFrame(function onAnimationFrame() { - PDFView.animationStartedPromise.resolve(); - }); -})(); - -//#if B2G -//window.navigator.mozSetMessageHandler('activity', function(activity) { -// var url = activity.source.data.url; -// PDFView.open(url); -// var cancelButton = document.getElementById('activityClose'); -// cancelButton.addEventListener('click', function() { -// activity.postResult('close'); -// }); -//}); -//#endif -- cgit v1.2.3