mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 09:07:32 -04:00 
			
		
		
		
	
						commit
						2bda5683cf
					
				| @ -6,9 +6,10 @@ | ||||
| <!-- | ||||
| <link href="{{ asset('vendor/bootstrap/dist/css/bootstrap.min.css') }}" rel="stylesheet" type="text/css"/>  | ||||
| <link href="{{ asset('css/bootstrap.splash.css') }}" rel="stylesheet" type="text/css"/>  | ||||
| <link href="{{ asset('css/splash.css') }}" rel="stylesheet" type="text/css"/>     | ||||
| --> | ||||
| <link href="{{ asset('css/splash.css') }}" rel="stylesheet" type="text/css"/>     | ||||
| 
 | ||||
| <!-- | ||||
| <link href="{{ asset('images/apple-touch-icon-114x114-precomposed.png') }}" rel="apple-touch-icon-precomposed" sizes="114x114"> | ||||
| <link href="{{ asset('images/apple-touch-icon-72x72-precomposed.png') }}" rel="apple-touch-icon-precomposed" sizes="72x72"> | ||||
| <link href="{{ asset('images/apple-touch-icon-57x57-precomposed.png') }}" rel="apple-touch-icon-precomposed"> | ||||
|  | ||||
| @ -2,12 +2,6 @@ | ||||
| 
 | ||||
| @section('content') | ||||
| 
 | ||||
|   <style> | ||||
|   section.body { | ||||
|     background-color: #f8f8f8 !important;
 | ||||
|   } | ||||
|   </style> | ||||
| 
 | ||||
|   <section class="hero background hero3" data-speed="2" data-type="background"> | ||||
|   <div class="caption-side"></div> | ||||
|   <div class="container"> | ||||
| @ -21,28 +15,85 @@ | ||||
|       </div> | ||||
|     </section> | ||||
| 
 | ||||
|  <section class="center" style="background-color:#f8f8f8"> | ||||
|  <section class="plans center"> | ||||
|   <div class="container"> | ||||
|     <div class="row"> | ||||
|       <div class="col-md-8 col-md-offset-2"> | ||||
|          <p/> | ||||
|         <h2>Go Pro to Unlock Premium Invoice Ninja Features</h2> | ||||
|         <p>We believe that the free version of Invoice Ninja is a truly awesome product loaded  | ||||
|           with the key features you need to bill your clients electronically. But for those who  | ||||
|           crave still more Ninja awesomeness, we've unmasked the Invoice Ninja Pro plan, which  | ||||
|           offers more versatility, power and customization options for just $50 per year. </p> | ||||
|           <br/> <br/> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </section> | ||||
|  <div class="container"> | ||||
|       <div class="row"> | ||||
|         <div class="plans-table col-md-9"> | ||||
|         <div class="col-md-4 desc hide-mobile"> | ||||
|             <div class="cell"></div> | ||||
|             <div class="cell">Number of clients per account</div> | ||||
|             <div class="cell">Remove "Created by Invoice Ninja"</div> | ||||
|             <div class="cell">Custom invoice fields</div> | ||||
|             <div class="cell">Unlimited client invoices</div> | ||||
|             <div class="cell">Add your company logo</div> | ||||
|             <div class="cell">Live .PDF invoice creation </div> | ||||
|             <div class="cell">4 beatiful invoice templates</div> | ||||
|             <div class="cell">Accept credit card payments</div> | ||||
|             <div class="cell">Multiple currency & language support</div> | ||||
|             <div class="cell">Open source platform</div> | ||||
|             <div class="cell">Self-hosting available</div> | ||||
|             <div class="cell">Customize payment terms</div> | ||||
|                         <div class="cell">Pricing</div> | ||||
| 
 | ||||
| <div style="background-color:#f8f8f8"> | ||||
|   <center><img src="{{ asset('images/pro-plan-chart.png') }}"/></center> | ||||
| </div>       | ||||
|              | ||||
|             </div> | ||||
|         <div class="free col-md-4"> | ||||
|             <div class="cell">Free</div> | ||||
|             <div class="cell"><div class="hide-desktop">Number of clients per account</div><span>1000</span></div> | ||||
|             <div class="cell"><div class="hide-desktop">Remove "Created by Invoice Ninja"</div><span class="glyphicon glyphicon-remove"></div> | ||||
|             <div class="cell"><div class="hide-desktop">Custom invoice fields</div><span class="glyphicon glyphicon-remove"></div> | ||||
|             <div class="cell"><div class="hide-desktop">Unlimited client invoices</div><span class="glyphicon glyphicon-ok"></div> | ||||
|             <div class="cell"><div class="hide-desktop">Add your company logo</div><span class="glyphicon glyphicon-ok"></div> | ||||
|             <div class="cell"><div class="hide-desktop">Live .PDF invoice creation</div><span class="glyphicon glyphicon-ok"></div> | ||||
|             <div class="cell"><div class="hide-desktop">4 beatiful invoice templates</div><span class="glyphicon glyphicon-ok"></div> | ||||
|             <div class="cell"><div class="hide-desktop">Accept credit card payments</div><span class="glyphicon glyphicon-ok"></div> | ||||
|             <div class="cell"><div class="hide-desktop">Multiple currency & language support</div><span class="glyphicon glyphicon-ok"></div> | ||||
|             <div class="cell"><div class="hide-desktop">Open source platform</div><span class="glyphicon glyphicon-ok"></div> | ||||
|             <div class="cell"><div class="hide-desktop">Self-hosting available</div><span class="glyphicon glyphicon-ok"></div> | ||||
|             <div class="cell"><div class="hide-desktop">Customize payment terms</div><span class="glyphicon glyphicon-ok"></div> | ||||
|             <div class="cell price"><div class="hide-desktop">Pricing</div><p>Free<span> /Always!</span></p></div> | ||||
|             </div> | ||||
|         <div class="pro col-md-4"> | ||||
|              | ||||
|             <div class="cell">Pro Plan<span class="glyphicon glyphicon-star"></div> | ||||
|             <div class="cell"><div class="hide-desktop">Number of clients per account</div><span style="color: #2299c0; font-size: 16px;">5000</span></div> | ||||
|             <div class="cell"><div class="hide-desktop">Remove "Created by Invoice Ninja"</div><span class="glyphicon glyphicon-ok"></div> | ||||
|                 <div class="cell"><div class="hide-desktop">Custom invoice fields</div><span class="glyphicon glyphicon-ok"></div> | ||||
|                     <div class="cell"><div class="hide-desktop">Unlimited client invoices</div><span class="glyphicon glyphicon-ok"></div> | ||||
|               <div class="cell"><div class="hide-desktop">Add your company logo</div><span class="glyphicon glyphicon-ok"></div> | ||||
|               <div class="cell"><div class="hide-desktop">Live .PDF invoice creation</div><span class="glyphicon glyphicon-ok"></div> | ||||
|               <div class="cell"><div class="hide-desktop">4 beatiful invoice templates</div><span class="glyphicon glyphicon-ok"></div> | ||||
|               <div class="cell"><div class="hide-desktop">Accept credit card payments</div><span class="glyphicon glyphicon-ok"></div> | ||||
|               <div class="cell"><div class="hide-desktop">Multiple currency & language support</div><span class="glyphicon glyphicon-ok"></div> | ||||
|               <div class="cell"><div class="hide-desktop">Open source platform</div><span class="glyphicon glyphicon-ok"></div> | ||||
|               <div class="cell"><div class="hide-desktop">Self-hosting available</div><span class="glyphicon glyphicon-ok"></div> | ||||
|               <div class="cell"><div class="hide-desktop">Customize payment terms</div><span class="glyphicon glyphicon-ok"></div> | ||||
|               <div class="cell price"><div class="hide-desktop">Pricing</div><p>$50<span> /Year</span></p></div> | ||||
|               <div class="cell"> | ||||
|               <a href="#"> | ||||
|         <div class="cta"> | ||||
|           <h2 onclick="return getStarted()">GO PRO <span>+</span></h2> | ||||
|         </div> | ||||
|       </a> | ||||
|             </div> | ||||
|           </div> | ||||
|      </div> | ||||
|                       </div> | ||||
|      </div> | ||||
|                 </section> | ||||
| 
 | ||||
| 
 | ||||
| <section style="background-color:#f8f8f8;padding-top:80px;padding-bottom:80px;"> | ||||
| <section class="upper-footer white-bg"> | ||||
|  <div class="container"> | ||||
|   <div class="row"> | ||||
|     <div class="col-md-3 center-block"> | ||||
|  | ||||
| @ -282,11 +282,11 @@ section.blue .col-md-6 h1 span { | ||||
|     text-transform: lowercase; | ||||
| } | ||||
| 
 | ||||
| section.about, section.team { | ||||
| section.about, section.team, section.plans { | ||||
|     padding: 70px 0; | ||||
| } | ||||
| 
 | ||||
| section.about h2, section.team h2 { | ||||
| section.about h2, section.team h2, section.plans h2 { | ||||
|     font-size: 25px; | ||||
|     margin: 0 0 25px; | ||||
|     text-transform: none; | ||||
| @ -748,4 +748,68 @@ div.fb_iframe_widget > span { | ||||
| ::-moz-selection { | ||||
|     color: #fff; | ||||
|     background: #2e2b2b; | ||||
| } | ||||
| } | ||||
| 
 | ||||
| .plans-table {text-align:center; margin: 0 auto; float: none; margin-top: 60px; } | ||||
| .plans-table .free, .plans-table .desc { padding: 0; } | ||||
| .plans-table .free .cell { padding-right: 15px; } | ||||
| 
 | ||||
| .plans-table .desc .cell { text-align: right; padding-right: 15px; border-left: 1px solid #dfe0e1; font-size: 13px; font-weight: 800; } | ||||
| .plans-table .pro .cell { border-left: 1px solid #cccccc; border-right: 1px solid #cccccc;} | ||||
| 
 | ||||
| .plans-table .cell {background-color: #fff; border-top: 1px solid #dfe0e1;padding: 18px 0; font-family: Roboto, sans-serif; height: 60px;} | ||||
| .plans-table .cell:nth-child(odd){background-color: #fbfbfb;} | ||||
| .plans-table .pro .cell:nth-child(odd){background-color: #f4f4f4;} | ||||
| .plans-table .pro { | ||||
|     background-color: #2299c0; | ||||
|      overflow:hidden; | ||||
|     padding: 0; | ||||
| -webkit-box-shadow: 0px 0px 15px 0px rgba(0, 5, 5, 0.2); | ||||
| -moz-box-shadow:    0px 0px 15px 0px rgba(0, 5, 5, 0.2); | ||||
| box-shadow:         0px 0px 15px 0px rgba(0, 5, 5, 0.2); | ||||
| } | ||||
| .plans-table .free .cell:first-child, .plans-table .pro .cell:first-child {color: #fff; text-transform: uppercase; font-size: 24px; font-weight:800; line-height: 60px; padding: 0; position: relative; bottom: -1px; border: none;} | ||||
| .plans-table .free .cell:first-child {background-color: #9b9b9b; margin-right: 15px; padding-right: 0;} | ||||
| .plans-table .free, .plans-table .desc {border-bottom: 1px solid #dfe0e1;} | ||||
| .plans-table .pro .cell:first-child {background-color: #2299c0;} | ||||
| .plans-table .pro .cell:last-child {padding: 0; border: none;} | ||||
| .plans-table .desc .cell:first-child {background-color: transparent; border: none;} | ||||
| 
 | ||||
| .plans-table .glyphicon {color: #fff; border-radius: 50px; padding: 5px; font-size: 10px;} | ||||
| .plans-table .glyphicon-remove {background-color: #da4830;} | ||||
| .plans-table .glyphicon-ok {background-color: #35c156;} | ||||
| .plans-table .glyphicon-star {border-radius: 0; background-color: #2e2b2b; | ||||
|     display: block;   | ||||
|     width: 60px;   | ||||
|     height: 30px;   | ||||
|     position: absolute;   | ||||
|     top: -5px;   | ||||
|     right: -20px;   | ||||
|     -webkit-transform: rotate(45deg); | ||||
|     -moz-transform: rotate(45deg); | ||||
|     -o-transform: rotate(45deg); | ||||
|     transform: rotate(45deg); | ||||
|     padding: 13px 0 0 1px; | ||||
| } | ||||
| 
 | ||||
| .plans-table .price {padding: 0; } | ||||
| .plans-table .free .price p {color: #35c156;} | ||||
| .plans-table .pro .price p {color: #2299c0;} | ||||
| .plans-table .price p {font-size: 40px; text-transform: uppercase; font-weight: 800; margin: 0; line-height: 55px;} | ||||
| .plans-table .price p span {font-size: 16px; text-transform: none; font-weight: 400;} | ||||
| 
 | ||||
| .plans-table a .cta h2 {background: #2299c0; color:#fff; margin: 0;} | ||||
| .plans-table a .cta h2 span {background: #1e84a5;} | ||||
| 
 | ||||
| @media screen and (min-width: 769px) { | ||||
|    .hide-desktop {display: none;} | ||||
| } | ||||
| @media screen and (max-width: 769px) { | ||||
|    .hide-mobile {display: none;} | ||||
|     .plans-table .cell {height: auto; padding: 14px 0; } | ||||
|     .plans-table .free .cell { padding-right: 0; } | ||||
|     .plans-table .free .cell:first-child {margin-right: 0;} | ||||
|        .plans-table .cell div:first-child {margin-bottom: 5px;} | ||||
|        .plans-table .cell .cta {margin-bottom: 0 !important;} | ||||
|        .plans-table .pro {margin-top: 40px;} | ||||
| }  | ||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										135
									
								
								public/vendor/pdfjs/extensions/firefox/components/PdfRedirector.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								public/vendor/pdfjs/extensions/firefox/components/PdfRedirector.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,135 @@ | ||||
| /* -*- 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. | ||||
|  */ | ||||
| /* jshint esnext:true */ | ||||
| /* globals Components, Services, XPCOMUtils, NetUtil, dump */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| var EXPORTED_SYMBOLS = ['PdfRedirector']; | ||||
| 
 | ||||
| const Cc = Components.classes; | ||||
| const Ci = Components.interfaces; | ||||
| const Cr = Components.results; | ||||
| const Cu = Components.utils; | ||||
| 
 | ||||
| const PDF_CONTENT_TYPE = 'application/pdf'; | ||||
| const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}'; | ||||
| 
 | ||||
| Cu.import('resource://gre/modules/XPCOMUtils.jsm'); | ||||
| Cu.import('resource://gre/modules/Services.jsm'); | ||||
| Cu.import('resource://gre/modules/NetUtil.jsm'); | ||||
| 
 | ||||
| 
 | ||||
| function getDOMWindow(aChannel) { | ||||
|   var requestor = aChannel.notificationCallbacks ? | ||||
|                   aChannel.notificationCallbacks : | ||||
|                   aChannel.loadGroup.notificationCallbacks; | ||||
|   var win = requestor.getInterface(Components.interfaces.nsIDOMWindow); | ||||
|   return win; | ||||
| } | ||||
| 
 | ||||
| function getObjectUrl(window) { | ||||
|   // PlayPreview overlay "belongs" to the embed/object tag and consists of DIV
 | ||||
|   // and IFRAME. Starting from IFRAME and looking for first object tag.
 | ||||
|   var element = window.frameElement, containerElement; | ||||
|   if (!element) { | ||||
|     return null; // iframe tag
 | ||||
|   } | ||||
|   var tagName = element.nodeName; | ||||
|   while (tagName !== 'EMBED' && tagName !== 'OBJECT') { | ||||
|     containerElement = element; | ||||
|     element = element.parentNode; | ||||
|     if (!element) { | ||||
|       return null; // object tag was not found
 | ||||
|     } | ||||
|     tagName = element.nodeName; | ||||
|   } | ||||
| 
 | ||||
|   // Checking if overlay is a proper PlayPreview overlay.
 | ||||
|   for (var i = 0; i < element.children.length; i++) { | ||||
|     if (element.children[i] === containerElement) { | ||||
|       return null; // invalid plugin element overlay
 | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return element.srcURI.spec; | ||||
| } | ||||
| 
 | ||||
| function PdfRedirector() { | ||||
| } | ||||
| 
 | ||||
| PdfRedirector.prototype = { | ||||
| 
 | ||||
|   // properties required for XPCOM registration:
 | ||||
|   classID: Components.ID('{8cbfd8d0-2042-4976-b3ef-d9dee1efb975}'), | ||||
|   classDescription: 'pdf.js Redirector', | ||||
|   contractID: | ||||
|     '@mozilla.org/streamconv;1?from=application/x-moz-playpreview-pdfjs&to=*/*', | ||||
| 
 | ||||
|   QueryInterface: XPCOMUtils.generateQI([ | ||||
|       Ci.nsIStreamConverter, | ||||
|       Ci.nsIStreamListener, | ||||
|       Ci.nsIRequestObserver | ||||
|   ]), | ||||
| 
 | ||||
|   // nsIStreamConverter::convert
 | ||||
|   convert: function(aFromStream, aFromType, aToType, aCtxt) { | ||||
|     throw Cr.NS_ERROR_NOT_IMPLEMENTED; | ||||
|   }, | ||||
| 
 | ||||
|   // nsIStreamConverter::asyncConvertData
 | ||||
|   asyncConvertData: function(aFromType, aToType, aListener, aCtxt) { | ||||
|     // Store the listener passed to us
 | ||||
|     this.listener = aListener; | ||||
|   }, | ||||
| 
 | ||||
|   // nsIStreamListener::onDataAvailable
 | ||||
|   onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) { | ||||
|     // Do nothing since all the data loading is handled by the viewer.
 | ||||
|   }, | ||||
| 
 | ||||
|   // nsIRequestObserver::onStartRequest
 | ||||
|   onStartRequest: function(aRequest, aContext) { | ||||
|     // Setup the request so we can use it below.
 | ||||
|     aRequest.QueryInterface(Ci.nsIChannel); | ||||
|     // Cancel the request so the viewer can handle it.
 | ||||
|     aRequest.cancel(Cr.NS_BINDING_ABORTED); | ||||
| 
 | ||||
|     var domWindow = getDOMWindow(aRequest); | ||||
|     var pdfUrl = getObjectUrl(domWindow); | ||||
|     if (!pdfUrl) { | ||||
|       Services.console.logStringMessage( | ||||
|         'PdfRedirector.js: PDF location is not specified for OBJECT/EMBED tag'); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     // Create a new channel that is viewer loaded as a resource.
 | ||||
|     var ioService = Services.io; | ||||
|     var channel = ioService.newChannel(pdfUrl, null, null); | ||||
| 
 | ||||
|     channel.loadGroup = aRequest.loadGroup; | ||||
| 
 | ||||
|     channel.asyncOpen(this.listener, aContext); | ||||
|   }, | ||||
| 
 | ||||
|   // nsIRequestObserver::onStopRequest
 | ||||
|   onStopRequest: function(aRequest, aContext, aStatusCode) { | ||||
|     // Do nothing
 | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| var NSGetFactory = XPCOMUtils.generateNSGetFactory([PdfRedirector]); | ||||
							
								
								
									
										963
									
								
								public/vendor/pdfjs/extensions/firefox/components/PdfStreamConverter.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										963
									
								
								public/vendor/pdfjs/extensions/firefox/components/PdfStreamConverter.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,963 @@ | ||||
| /* -*- 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. | ||||
|  */ | ||||
| /* jshint esnext:true */ | ||||
| /* globals Components, Services, XPCOMUtils, NetUtil, PrivateBrowsingUtils, | ||||
|            dump, NetworkManager, PdfJsTelemetry, DEFAULT_PREFERENCES */ | ||||
| 
 | ||||
| 'use strict'; | ||||
| 
 | ||||
| var EXPORTED_SYMBOLS = ['PdfStreamConverter']; | ||||
| 
 | ||||
| const Cc = Components.classes; | ||||
| const Ci = Components.interfaces; | ||||
| const Cr = Components.results; | ||||
| const Cu = Components.utils; | ||||
| // True only if this is the version of pdf.js that is included with firefox.
 | ||||
| const MOZ_CENTRAL = JSON.parse('PDFJSSCRIPT_MOZ_CENTRAL'); | ||||
| const PDFJS_EVENT_ID = 'pdf.js.message'; | ||||
| const PDF_CONTENT_TYPE = 'application/pdf'; | ||||
| const PREF_PREFIX = 'PDFJSSCRIPT_PREF_PREFIX'; | ||||
| const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html'; | ||||
| const MAX_DATABASE_LENGTH = 4096; | ||||
| const MAX_STRING_PREF_LENGTH = 4096; | ||||
| 
 | ||||
| Cu.import('resource://gre/modules/XPCOMUtils.jsm'); | ||||
| Cu.import('resource://gre/modules/Services.jsm'); | ||||
| Cu.import('resource://gre/modules/NetUtil.jsm'); | ||||
| Cu.import('resource://pdf.js/network.js'); | ||||
| 
 | ||||
| // Load the default preferences.
 | ||||
| Cu.import('resource://pdf.js/default_preferences.js'); | ||||
| 
 | ||||
| XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils', | ||||
|   'resource://gre/modules/PrivateBrowsingUtils.jsm'); | ||||
| 
 | ||||
| XPCOMUtils.defineLazyModuleGetter(this, 'PdfJsTelemetry', | ||||
|   'resource://pdf.js/PdfJsTelemetry.jsm'); | ||||
| 
 | ||||
| var Svc = {}; | ||||
| XPCOMUtils.defineLazyServiceGetter(Svc, 'mime', | ||||
|                                    '@mozilla.org/mime;1', | ||||
|                                    'nsIMIMEService'); | ||||
| 
 | ||||
| function getChromeWindow(domWindow) { | ||||
|   var containingBrowser = domWindow.QueryInterface(Ci.nsIInterfaceRequestor) | ||||
|                                    .getInterface(Ci.nsIWebNavigation) | ||||
|                                    .QueryInterface(Ci.nsIDocShell) | ||||
|                                    .chromeEventHandler; | ||||
|   return containingBrowser.ownerDocument.defaultView; | ||||
| } | ||||
| 
 | ||||
| function setBoolPref(pref, value) { | ||||
|   Services.prefs.setBoolPref(pref, value); | ||||
| } | ||||
| 
 | ||||
| function getBoolPref(pref, def) { | ||||
|   try { | ||||
|     return Services.prefs.getBoolPref(pref); | ||||
|   } catch (ex) { | ||||
|     return def; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function setIntPref(pref, value) { | ||||
|   Services.prefs.setIntPref(pref, value); | ||||
| } | ||||
| 
 | ||||
| function getIntPref(pref, def) { | ||||
|   try { | ||||
|     return Services.prefs.getIntPref(pref); | ||||
|   } catch (ex) { | ||||
|     return def; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function setStringPref(pref, value) { | ||||
|   var str = Cc['@mozilla.org/supports-string;1'] | ||||
|               .createInstance(Ci.nsISupportsString); | ||||
|   str.data = value; | ||||
|   Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str); | ||||
| } | ||||
| 
 | ||||
| function getStringPref(pref, def) { | ||||
|   try { | ||||
|     return Services.prefs.getComplexValue(pref, Ci.nsISupportsString).data; | ||||
|   } catch (ex) { | ||||
|     return def; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function log(aMsg) { | ||||
|   if (!getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false)) | ||||
|     return; | ||||
|   var msg = 'PdfStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg); | ||||
|   Services.console.logStringMessage(msg); | ||||
|   dump(msg + '\n'); | ||||
| } | ||||
| 
 | ||||
| function getDOMWindow(aChannel) { | ||||
|   var requestor = aChannel.notificationCallbacks ? | ||||
|                   aChannel.notificationCallbacks : | ||||
|                   aChannel.loadGroup.notificationCallbacks; | ||||
|   var win = requestor.getInterface(Components.interfaces.nsIDOMWindow); | ||||
|   return win; | ||||
| } | ||||
| 
 | ||||
| function getLocalizedStrings(path) { | ||||
|   var stringBundle = Cc['@mozilla.org/intl/stringbundle;1']. | ||||
|       getService(Ci.nsIStringBundleService). | ||||
|       createBundle('chrome://pdf.js/locale/' + path); | ||||
| 
 | ||||
|   var map = {}; | ||||
|   var enumerator = stringBundle.getSimpleEnumeration(); | ||||
|   while (enumerator.hasMoreElements()) { | ||||
|     var string = enumerator.getNext().QueryInterface(Ci.nsIPropertyElement); | ||||
|     var key = string.key, property = 'textContent'; | ||||
|     var i = key.lastIndexOf('.'); | ||||
|     if (i >= 0) { | ||||
|       property = key.substring(i + 1); | ||||
|       key = key.substring(0, i); | ||||
|     } | ||||
|     if (!(key in map)) | ||||
|       map[key] = {}; | ||||
|     map[key][property] = string.value; | ||||
|   } | ||||
|   return map; | ||||
| } | ||||
| function getLocalizedString(strings, id, property) { | ||||
|   property = property || 'textContent'; | ||||
|   if (id in strings) | ||||
|     return strings[id][property]; | ||||
|   return id; | ||||
| } | ||||
| 
 | ||||
| // PDF data storage
 | ||||
| function PdfDataListener(length) { | ||||
|   this.length = length; // less than 0, if length is unknown
 | ||||
|   this.data = new Uint8Array(length >= 0 ? length : 0x10000); | ||||
|   this.loaded = 0; | ||||
| } | ||||
| 
 | ||||
| PdfDataListener.prototype = { | ||||
|   append: function PdfDataListener_append(chunk) { | ||||
|     var willBeLoaded = this.loaded + chunk.length; | ||||
|     if (this.length >= 0 && this.length < willBeLoaded) { | ||||
|       this.length = -1; // reset the length, server is giving incorrect one
 | ||||
|     } | ||||
|     if (this.length < 0 && this.data.length < willBeLoaded) { | ||||
|       // data length is unknown and new chunk will not fit in the existing
 | ||||
|       // buffer, resizing the buffer by doubling the its last length
 | ||||
|       var newLength = this.data.length; | ||||
|       for (; newLength < willBeLoaded; newLength *= 2) {} | ||||
|       var newData = new Uint8Array(newLength); | ||||
|       newData.set(this.data); | ||||
|       this.data = newData; | ||||
|     } | ||||
|     this.data.set(chunk, this.loaded); | ||||
|     this.loaded = willBeLoaded; | ||||
|     this.onprogress(this.loaded, this.length >= 0 ? this.length : void(0)); | ||||
|   }, | ||||
|   getData: function PdfDataListener_getData() { | ||||
|     var data = this.data; | ||||
|     if (this.loaded != data.length) | ||||
|       data = data.subarray(0, this.loaded); | ||||
|     delete this.data; // releasing temporary storage
 | ||||
|     return data; | ||||
|   }, | ||||
|   finish: function PdfDataListener_finish() { | ||||
|     this.isDataReady = true; | ||||
|     if (this.oncompleteCallback) { | ||||
|       this.oncompleteCallback(this.getData()); | ||||
|     } | ||||
|   }, | ||||
|   error: function PdfDataListener_error(errorCode) { | ||||
|     this.errorCode = errorCode; | ||||
|     if (this.oncompleteCallback) { | ||||
|       this.oncompleteCallback(null, errorCode); | ||||
|     } | ||||
|   }, | ||||
|   onprogress: function() {}, | ||||
|   get oncomplete() { | ||||
|     return this.oncompleteCallback; | ||||
|   }, | ||||
|   set oncomplete(value) { | ||||
|     this.oncompleteCallback = value; | ||||
|     if (this.isDataReady) { | ||||
|       value(this.getData()); | ||||
|     } | ||||
|     if (this.errorCode) { | ||||
|       value(null, this.errorCode); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // All the priviledged actions.
 | ||||
| function ChromeActions(domWindow, contentDispositionFilename) { | ||||
|   this.domWindow = domWindow; | ||||
|   this.contentDispositionFilename = contentDispositionFilename; | ||||
|   this.telemetryState = { | ||||
|     documentInfo: false, | ||||
|     firstPageInfo: false, | ||||
|     streamTypesUsed: [], | ||||
|     startAt: Date.now() | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| ChromeActions.prototype = { | ||||
|   isInPrivateBrowsing: function() { | ||||
|     return PrivateBrowsingUtils.isWindowPrivate(this.domWindow); | ||||
|   }, | ||||
|   download: function(data, sendResponse) { | ||||
|     var self = this; | ||||
|     var originalUrl = data.originalUrl; | ||||
|     // The data may not be downloaded so we need just retry getting the pdf with
 | ||||
|     // the original url.
 | ||||
|     var originalUri = NetUtil.newURI(data.originalUrl); | ||||
|     var filename = data.filename; | ||||
|     if (typeof filename !== 'string' || !/\.pdf$/i.test(filename)) { | ||||
|       filename = 'document.pdf'; | ||||
|     } | ||||
|     var blobUri = data.blobUrl ? NetUtil.newURI(data.blobUrl) : originalUri; | ||||
|     var extHelperAppSvc = | ||||
|           Cc['@mozilla.org/uriloader/external-helper-app-service;1']. | ||||
|              getService(Ci.nsIExternalHelperAppService); | ||||
|     var frontWindow = Cc['@mozilla.org/embedcomp/window-watcher;1']. | ||||
|                          getService(Ci.nsIWindowWatcher).activeWindow; | ||||
| 
 | ||||
|     var docIsPrivate = this.isInPrivateBrowsing(); | ||||
|     var netChannel = NetUtil.newChannel(blobUri); | ||||
|     if ('nsIPrivateBrowsingChannel' in Ci && | ||||
|         netChannel instanceof Ci.nsIPrivateBrowsingChannel) { | ||||
|       netChannel.setPrivate(docIsPrivate); | ||||
|     } | ||||
|     NetUtil.asyncFetch(netChannel, function(aInputStream, aResult) { | ||||
|       if (!Components.isSuccessCode(aResult)) { | ||||
|         if (sendResponse) | ||||
|           sendResponse(true); | ||||
|         return; | ||||
|       } | ||||
|       // Create a nsIInputStreamChannel so we can set the url on the channel
 | ||||
|       // so the filename will be correct.
 | ||||
|       var channel = Cc['@mozilla.org/network/input-stream-channel;1']. | ||||
|                        createInstance(Ci.nsIInputStreamChannel); | ||||
|       channel.QueryInterface(Ci.nsIChannel); | ||||
|       try { | ||||
|         // contentDisposition/contentDispositionFilename is readonly before FF18
 | ||||
|         channel.contentDisposition = Ci.nsIChannel.DISPOSITION_ATTACHMENT; | ||||
|         if (self.contentDispositionFilename) { | ||||
|           channel.contentDispositionFilename = self.contentDispositionFilename; | ||||
|         } else { | ||||
|           channel.contentDispositionFilename = filename; | ||||
|         } | ||||
|       } catch (e) {} | ||||
|       channel.setURI(originalUri); | ||||
|       channel.contentStream = aInputStream; | ||||
|       if ('nsIPrivateBrowsingChannel' in Ci && | ||||
|           channel instanceof Ci.nsIPrivateBrowsingChannel) { | ||||
|         channel.setPrivate(docIsPrivate); | ||||
|       } | ||||
| 
 | ||||
|       var listener = { | ||||
|         extListener: null, | ||||
|         onStartRequest: function(aRequest, aContext) { | ||||
|           this.extListener = extHelperAppSvc.doContent('application/pdf', | ||||
|                                 aRequest, frontWindow, false); | ||||
|           this.extListener.onStartRequest(aRequest, aContext); | ||||
|         }, | ||||
|         onStopRequest: function(aRequest, aContext, aStatusCode) { | ||||
|           if (this.extListener) | ||||
|             this.extListener.onStopRequest(aRequest, aContext, aStatusCode); | ||||
|           // Notify the content code we're done downloading.
 | ||||
|           if (sendResponse) | ||||
|             sendResponse(false); | ||||
|         }, | ||||
|         onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, | ||||
|                                   aCount) { | ||||
|           this.extListener.onDataAvailable(aRequest, aContext, aInputStream, | ||||
|                                            aOffset, aCount); | ||||
|         } | ||||
|       }; | ||||
| 
 | ||||
|       channel.asyncOpen(listener, null); | ||||
|     }); | ||||
|   }, | ||||
|   setDatabase: function(data) { | ||||
|     if (this.isInPrivateBrowsing()) | ||||
|       return; | ||||
|     // Protect against something sending tons of data to setDatabase.
 | ||||
|     if (data.length > MAX_DATABASE_LENGTH) | ||||
|       return; | ||||
|     setStringPref(PREF_PREFIX + '.database', data); | ||||
|   }, | ||||
|   getDatabase: function() { | ||||
|     if (this.isInPrivateBrowsing()) | ||||
|       return '{}'; | ||||
|     return getStringPref(PREF_PREFIX + '.database', '{}'); | ||||
|   }, | ||||
|   getLocale: function() { | ||||
|     return getStringPref('general.useragent.locale', 'en-US'); | ||||
|   }, | ||||
|   getStrings: function(data) { | ||||
|     try { | ||||
|       // Lazy initialization of localizedStrings
 | ||||
|       if (!('localizedStrings' in this)) | ||||
|         this.localizedStrings = getLocalizedStrings('viewer.properties'); | ||||
| 
 | ||||
|       var result = this.localizedStrings[data]; | ||||
|       return JSON.stringify(result || null); | ||||
|     } catch (e) { | ||||
|       log('Unable to retrive localized strings: ' + e); | ||||
|       return 'null'; | ||||
|     } | ||||
|   }, | ||||
|   pdfBugEnabled: function() { | ||||
|     return getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false); | ||||
|   }, | ||||
|   supportsIntegratedFind: function() { | ||||
|     // Integrated find is only supported when we're not in a frame and when the
 | ||||
|     // new find events code exists.
 | ||||
|     return this.domWindow.frameElement === null && | ||||
|            getChromeWindow(this.domWindow).gFindBar && | ||||
|            'updateControlState' in getChromeWindow(this.domWindow).gFindBar; | ||||
|   }, | ||||
|   supportsDocumentFonts: function() { | ||||
|     var prefBrowser = getIntPref('browser.display.use_document_fonts', 1); | ||||
|     var prefGfx = getBoolPref('gfx.downloadable_fonts.enabled', true); | ||||
|     return (!!prefBrowser && prefGfx); | ||||
|   }, | ||||
|   supportsDocumentColors: function() { | ||||
|     return getBoolPref('browser.display.use_document_colors', true); | ||||
|   }, | ||||
|   reportTelemetry: function (data) { | ||||
|     var probeInfo = JSON.parse(data); | ||||
|     switch (probeInfo.type) { | ||||
|       case 'documentInfo': | ||||
|         if (!this.telemetryState.documentInfo) { | ||||
|           PdfJsTelemetry.onDocumentVersion(probeInfo.version | 0); | ||||
|           PdfJsTelemetry.onDocumentGenerator(probeInfo.generator | 0); | ||||
|           if (probeInfo.formType) { | ||||
|             PdfJsTelemetry.onForm(probeInfo.formType === 'acroform'); | ||||
|           } | ||||
|           this.telemetryState.documentInfo = true; | ||||
|         } | ||||
|         break; | ||||
|       case 'pageInfo': | ||||
|         if (!this.telemetryState.firstPageInfo) { | ||||
|           var duration = Date.now() - this.telemetryState.startAt; | ||||
|           PdfJsTelemetry.onTimeToView(duration); | ||||
|           this.telemetryState.firstPageInfo = true; | ||||
|         } | ||||
|         break; | ||||
|       case 'streamInfo': | ||||
|         if (!Array.isArray(probeInfo.streamTypes)) { | ||||
|           break; | ||||
|         } | ||||
|         for (var i = 0; i < probeInfo.streamTypes.length; i++) { | ||||
|           var streamTypeId = probeInfo.streamTypes[i] | 0; | ||||
|           if (streamTypeId >= 0 && streamTypeId < 10 && | ||||
|               !this.telemetryState.streamTypesUsed[streamTypeId]) { | ||||
|             PdfJsTelemetry.onStreamType(streamTypeId); | ||||
|             this.telemetryState.streamTypesUsed[streamTypeId] = true; | ||||
|           } | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|   }, | ||||
|   fallback: function(args, sendResponse) { | ||||
|     var featureId = args.featureId; | ||||
|     var url = args.url; | ||||
| 
 | ||||
|     var self = this; | ||||
|     var domWindow = this.domWindow; | ||||
|     var strings = getLocalizedStrings('chrome.properties'); | ||||
|     var message; | ||||
|     if (featureId === 'forms') { | ||||
|       message = getLocalizedString(strings, 'unsupported_feature_forms'); | ||||
|     } else { | ||||
|       message = getLocalizedString(strings, 'unsupported_feature'); | ||||
|     } | ||||
| 
 | ||||
|     PdfJsTelemetry.onFallback(); | ||||
| 
 | ||||
|     var notificationBox = null; | ||||
|     try { | ||||
|       // Based on MDN's "Working with windows in chrome code"
 | ||||
|       var mainWindow = domWindow | ||||
|         .QueryInterface(Components.interfaces.nsIInterfaceRequestor) | ||||
|         .getInterface(Components.interfaces.nsIWebNavigation) | ||||
|         .QueryInterface(Components.interfaces.nsIDocShellTreeItem) | ||||
|         .rootTreeItem | ||||
|         .QueryInterface(Components.interfaces.nsIInterfaceRequestor) | ||||
|         .getInterface(Components.interfaces.nsIDOMWindow); | ||||
|       var browser = mainWindow.gBrowser | ||||
|                               .getBrowserForDocument(domWindow.top.document); | ||||
|       notificationBox = mainWindow.gBrowser.getNotificationBox(browser); | ||||
|     } catch (e) { | ||||
|       log('Unable to get a notification box for the fallback message'); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     // Flag so we don't call the response callback twice, since if the user
 | ||||
|     // clicks open with different viewer both the button callback and
 | ||||
|     // eventCallback will be called.
 | ||||
|     var sentResponse = false; | ||||
|     var buttons = [{ | ||||
|       label: getLocalizedString(strings, 'open_with_different_viewer'), | ||||
|       accessKey: getLocalizedString(strings, 'open_with_different_viewer', | ||||
|                                     'accessKey'), | ||||
|       callback: function() { | ||||
|         sentResponse = true; | ||||
|         sendResponse(true); | ||||
|       } | ||||
|     }]; | ||||
|     notificationBox.appendNotification(message, 'pdfjs-fallback', null, | ||||
|                                        notificationBox.PRIORITY_INFO_LOW, | ||||
|                                        buttons, | ||||
|                                        function eventsCallback(eventType) { | ||||
|       // Currently there is only one event "removed" but if there are any other
 | ||||
|       // added in the future we still only care about removed at the moment.
 | ||||
|       if (eventType !== 'removed') | ||||
|         return; | ||||
|       // Don't send a response again if we already responded when the button was
 | ||||
|       // clicked.
 | ||||
|       if (!sentResponse) | ||||
|         sendResponse(false); | ||||
|     }); | ||||
|   }, | ||||
|   updateFindControlState: function(data) { | ||||
|     if (!this.supportsIntegratedFind()) | ||||
|       return; | ||||
|     // Verify what we're sending to the findbar.
 | ||||
|     var result = data.result; | ||||
|     var findPrevious = data.findPrevious; | ||||
|     var findPreviousType = typeof findPrevious; | ||||
|     if ((typeof result !== 'number' || result < 0 || result > 3) || | ||||
|         (findPreviousType !== 'undefined' && findPreviousType !== 'boolean')) { | ||||
|       return; | ||||
|     } | ||||
|     getChromeWindow(this.domWindow).gFindBar | ||||
|                                    .updateControlState(result, findPrevious); | ||||
|   }, | ||||
|   setPreferences: function(prefs) { | ||||
|     var prefValue, defaultValue, prefName, prefType, defaultType; | ||||
| 
 | ||||
|     for (var key in DEFAULT_PREFERENCES) { | ||||
|       prefValue = prefs[key]; | ||||
|       defaultValue = DEFAULT_PREFERENCES[key]; | ||||
|       prefName = (PREF_PREFIX + '.' + key); | ||||
| 
 | ||||
|       if (prefValue === undefined || prefValue === defaultValue) { | ||||
|         Services.prefs.clearUserPref(prefName); | ||||
|       } else { | ||||
|         prefType = typeof prefValue; | ||||
|         defaultType = typeof defaultValue; | ||||
| 
 | ||||
|         if (prefType !== defaultType) { | ||||
|           continue; | ||||
|         } | ||||
|         switch (defaultType) { | ||||
|           case 'boolean': | ||||
|             setBoolPref(prefName, prefValue); | ||||
|             break; | ||||
|           case 'number': | ||||
|             setIntPref(prefName, prefValue); | ||||
|             break; | ||||
|           case 'string': | ||||
|             // Protect against adding arbitrarily long strings in about:config.
 | ||||
|             if (prefValue.length <= MAX_STRING_PREF_LENGTH) { | ||||
|               setStringPref(prefName, prefValue); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   getPreferences: function() { | ||||
|     var currentPrefs = {}; | ||||
|     var defaultValue, prefName; | ||||
| 
 | ||||
|     for (var key in DEFAULT_PREFERENCES) { | ||||
|       defaultValue = DEFAULT_PREFERENCES[key]; | ||||
|       prefName = (PREF_PREFIX + '.' + key); | ||||
| 
 | ||||
|       switch (typeof defaultValue) { | ||||
|         case 'boolean': | ||||
|           currentPrefs[key] = getBoolPref(prefName, defaultValue); | ||||
|           break; | ||||
|         case 'number': | ||||
|           currentPrefs[key] = getIntPref(prefName, defaultValue); | ||||
|           break; | ||||
|         case 'string': | ||||
|           currentPrefs[key] = getStringPref(prefName, defaultValue); | ||||
|           break; | ||||
|       } | ||||
|     } | ||||
|     return JSON.stringify(currentPrefs); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| var RangedChromeActions = (function RangedChromeActionsClosure() { | ||||
|   /** | ||||
|    * This is for range requests | ||||
|    */ | ||||
|   function RangedChromeActions( | ||||
|               domWindow, contentDispositionFilename, originalRequest, | ||||
|               dataListener) { | ||||
| 
 | ||||
|     ChromeActions.call(this, domWindow, contentDispositionFilename); | ||||
|     this.dataListener = dataListener; | ||||
|     this.originalRequest = originalRequest; | ||||
| 
 | ||||
|     this.pdfUrl = originalRequest.URI.spec; | ||||
|     this.contentLength = originalRequest.contentLength; | ||||
| 
 | ||||
|     // Pass all the headers from the original request through
 | ||||
|     var httpHeaderVisitor = { | ||||
|       headers: {}, | ||||
|       visitHeader: function(aHeader, aValue) { | ||||
|         if (aHeader === 'Range') { | ||||
|           // When loading the PDF from cache, firefox seems to set the Range
 | ||||
|           // request header to fetch only the unfetched portions of the file
 | ||||
|           // (e.g. 'Range: bytes=1024-'). However, we want to set this header
 | ||||
|           // manually to fetch the PDF in chunks.
 | ||||
|           return; | ||||
|         } | ||||
|         this.headers[aHeader] = aValue; | ||||
|       } | ||||
|     }; | ||||
|     originalRequest.visitRequestHeaders(httpHeaderVisitor); | ||||
| 
 | ||||
|     var self = this; | ||||
|     var xhr_onreadystatechange = function xhr_onreadystatechange() { | ||||
|       if (this.readyState === 1) { // LOADING
 | ||||
|         var netChannel = this.channel; | ||||
|         if ('nsIPrivateBrowsingChannel' in Ci && | ||||
|             netChannel instanceof Ci.nsIPrivateBrowsingChannel) { | ||||
|           var docIsPrivate = self.isInPrivateBrowsing(); | ||||
|           netChannel.setPrivate(docIsPrivate); | ||||
|         } | ||||
|       } | ||||
|     }; | ||||
|     var getXhr = function getXhr() { | ||||
|       const XMLHttpRequest = Components.Constructor( | ||||
|           '@mozilla.org/xmlextras/xmlhttprequest;1'); | ||||
|       var xhr = new XMLHttpRequest(); | ||||
|       xhr.addEventListener('readystatechange', xhr_onreadystatechange); | ||||
|       return xhr; | ||||
|     }; | ||||
| 
 | ||||
|     this.networkManager = new NetworkManager(this.pdfUrl, { | ||||
|       httpHeaders: httpHeaderVisitor.headers, | ||||
|       getXhr: getXhr | ||||
|     }); | ||||
| 
 | ||||
|     // If we are in range request mode, this means we manually issued xhr
 | ||||
|     // requests, which we need to abort when we leave the page
 | ||||
|     domWindow.addEventListener('unload', function unload(e) { | ||||
|       self.networkManager.abortAllRequests(); | ||||
|       domWindow.removeEventListener(e.type, unload); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   RangedChromeActions.prototype = Object.create(ChromeActions.prototype); | ||||
|   var proto = RangedChromeActions.prototype; | ||||
|   proto.constructor = RangedChromeActions; | ||||
| 
 | ||||
|   proto.initPassiveLoading = function RangedChromeActions_initPassiveLoading() { | ||||
|     this.originalRequest.cancel(Cr.NS_BINDING_ABORTED); | ||||
|     this.originalRequest = null; | ||||
|     this.domWindow.postMessage({ | ||||
|       pdfjsLoadAction: 'supportsRangedLoading', | ||||
|       pdfUrl: this.pdfUrl, | ||||
|       length: this.contentLength, | ||||
|       data: this.dataListener.getData() | ||||
|     }, '*'); | ||||
|     this.dataListener = null; | ||||
| 
 | ||||
|     return true; | ||||
|   }; | ||||
| 
 | ||||
|   proto.requestDataRange = function RangedChromeActions_requestDataRange(args) { | ||||
|     var begin = args.begin; | ||||
|     var end = args.end; | ||||
|     var domWindow = this.domWindow; | ||||
|     // TODO(mack): Support error handler. We're not currently not handling
 | ||||
|     // errors from chrome code for non-range requests, so this doesn't
 | ||||
|     // seem high-pri
 | ||||
|     this.networkManager.requestRange(begin, end, { | ||||
|       onDone: function RangedChromeActions_onDone(args) { | ||||
|         domWindow.postMessage({ | ||||
|           pdfjsLoadAction: 'range', | ||||
|           begin: args.begin, | ||||
|           chunk: args.chunk | ||||
|         }, '*'); | ||||
|       }, | ||||
|       onProgress: function RangedChromeActions_onProgress(evt) { | ||||
|         domWindow.postMessage({ | ||||
|           pdfjsLoadAction: 'rangeProgress', | ||||
|           loaded: evt.loaded, | ||||
|         }, '*'); | ||||
|       } | ||||
|     }); | ||||
|   }; | ||||
| 
 | ||||
|   return RangedChromeActions; | ||||
| })(); | ||||
| 
 | ||||
| var StandardChromeActions = (function StandardChromeActionsClosure() { | ||||
| 
 | ||||
|   /** | ||||
|    * This is for a single network stream | ||||
|    */ | ||||
|   function StandardChromeActions(domWindow, contentDispositionFilename, | ||||
|                                  dataListener) { | ||||
| 
 | ||||
|     ChromeActions.call(this, domWindow, contentDispositionFilename); | ||||
|     this.dataListener = dataListener; | ||||
|   } | ||||
| 
 | ||||
|   StandardChromeActions.prototype = Object.create(ChromeActions.prototype); | ||||
|   var proto = StandardChromeActions.prototype; | ||||
|   proto.constructor = StandardChromeActions; | ||||
| 
 | ||||
|   proto.initPassiveLoading = | ||||
|       function StandardChromeActions_initPassiveLoading() { | ||||
| 
 | ||||
|     if (!this.dataListener) { | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|     var self = this; | ||||
| 
 | ||||
|     this.dataListener.onprogress = function ChromeActions_dataListenerProgress( | ||||
|                                       loaded, total) { | ||||
|       self.domWindow.postMessage({ | ||||
|         pdfjsLoadAction: 'progress', | ||||
|         loaded: loaded, | ||||
|         total: total | ||||
|       }, '*'); | ||||
|     }; | ||||
| 
 | ||||
|     this.dataListener.oncomplete = function ChromeActions_dataListenerComplete( | ||||
|                                       data, errorCode) { | ||||
|       self.domWindow.postMessage({ | ||||
|         pdfjsLoadAction: 'complete', | ||||
|         data: data, | ||||
|         errorCode: errorCode | ||||
|       }, '*'); | ||||
| 
 | ||||
|       delete self.dataListener; | ||||
|     }; | ||||
| 
 | ||||
|     return true; | ||||
|   }; | ||||
| 
 | ||||
|   return StandardChromeActions; | ||||
| })(); | ||||
| 
 | ||||
| // Event listener to trigger chrome privedged code.
 | ||||
| function RequestListener(actions) { | ||||
|   this.actions = actions; | ||||
| } | ||||
| // Receive an event and synchronously or asynchronously responds.
 | ||||
| RequestListener.prototype.receive = function(event) { | ||||
|   var message = event.target; | ||||
|   var doc = message.ownerDocument; | ||||
|   var action = event.detail.action; | ||||
|   var data = event.detail.data; | ||||
|   var sync = event.detail.sync; | ||||
|   var actions = this.actions; | ||||
|   if (!(action in actions)) { | ||||
|     log('Unknown action: ' + action); | ||||
|     return; | ||||
|   } | ||||
|   if (sync) { | ||||
|     var response = actions[action].call(this.actions, data); | ||||
|     var detail = event.detail; | ||||
|     detail.__exposedProps__ = {response: 'r'}; | ||||
|     detail.response = response; | ||||
|   } else { | ||||
|     var response; | ||||
|     if (!event.detail.callback) { | ||||
|       doc.documentElement.removeChild(message); | ||||
|       response = null; | ||||
|     } else { | ||||
|       response = function sendResponse(response) { | ||||
|         try { | ||||
|           var listener = doc.createEvent('CustomEvent'); | ||||
|           listener.initCustomEvent('pdf.js.response', true, false, | ||||
|                                    {response: response, | ||||
|                                     __exposedProps__: {response: 'r'}}); | ||||
|           return message.dispatchEvent(listener); | ||||
|         } catch (e) { | ||||
|           // doc is no longer accessible because the requestor is already
 | ||||
|           // gone. unloaded content cannot receive the response anyway.
 | ||||
|           return false; | ||||
|         } | ||||
|       }; | ||||
|     } | ||||
|     actions[action].call(this.actions, data, response); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // Forwards events from the eventElement to the contentWindow only if the
 | ||||
| // content window matches the currently selected browser window.
 | ||||
| function FindEventManager(eventElement, contentWindow, chromeWindow) { | ||||
|   this.types = ['find', | ||||
|                 'findagain', | ||||
|                 'findhighlightallchange', | ||||
|                 'findcasesensitivitychange']; | ||||
|   this.chromeWindow = chromeWindow; | ||||
|   this.contentWindow = contentWindow; | ||||
|   this.eventElement = eventElement; | ||||
| } | ||||
| 
 | ||||
| FindEventManager.prototype.bind = function() { | ||||
|   var unload = function(e) { | ||||
|     this.unbind(); | ||||
|     this.contentWindow.removeEventListener(e.type, unload); | ||||
|   }.bind(this); | ||||
|   this.contentWindow.addEventListener('unload', unload); | ||||
| 
 | ||||
|   for (var i = 0; i < this.types.length; i++) { | ||||
|     var type = this.types[i]; | ||||
|     this.eventElement.addEventListener(type, this, true); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| FindEventManager.prototype.handleEvent = function(e) { | ||||
|   var chromeWindow = this.chromeWindow; | ||||
|   var contentWindow = this.contentWindow; | ||||
|   // Only forward the events if they are for our dom window.
 | ||||
|   if (chromeWindow.gBrowser.selectedBrowser.contentWindow === contentWindow) { | ||||
|     var detail = e.detail; | ||||
|     detail.__exposedProps__ = { | ||||
|       query: 'r', | ||||
|       caseSensitive: 'r', | ||||
|       highlightAll: 'r', | ||||
|       findPrevious: 'r' | ||||
|     }; | ||||
|     var forward = contentWindow.document.createEvent('CustomEvent'); | ||||
|     forward.initCustomEvent(e.type, true, true, detail); | ||||
|     contentWindow.dispatchEvent(forward); | ||||
|     e.preventDefault(); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| FindEventManager.prototype.unbind = function() { | ||||
|   for (var i = 0; i < this.types.length; i++) { | ||||
|     var type = this.types[i]; | ||||
|     this.eventElement.removeEventListener(type, this, true); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| function PdfStreamConverter() { | ||||
| } | ||||
| 
 | ||||
| PdfStreamConverter.prototype = { | ||||
| 
 | ||||
|   // properties required for XPCOM registration:
 | ||||
|   classID: Components.ID('{PDFJSSCRIPT_STREAM_CONVERTER_ID}'), | ||||
|   classDescription: 'pdf.js Component', | ||||
|   contractID: '@mozilla.org/streamconv;1?from=application/pdf&to=*/*', | ||||
| 
 | ||||
|   QueryInterface: XPCOMUtils.generateQI([ | ||||
|       Ci.nsISupports, | ||||
|       Ci.nsIStreamConverter, | ||||
|       Ci.nsIStreamListener, | ||||
|       Ci.nsIRequestObserver | ||||
|   ]), | ||||
| 
 | ||||
|   /* | ||||
|    * This component works as such: | ||||
|    * 1. asyncConvertData stores the listener | ||||
|    * 2. onStartRequest creates a new channel, streams the viewer | ||||
|    * 3. If range requests are supported: | ||||
|    *      3.1. Leave the request open until the viewer is ready to switch to | ||||
|    *           range requests. | ||||
|    * | ||||
|    *    If range rquests are not supported: | ||||
|    *      3.1. Read the stream as it's loaded in onDataAvailable to send | ||||
|    *           to the viewer | ||||
|    * | ||||
|    * The convert function just returns the stream, it's just the synchronous | ||||
|    * version of asyncConvertData. | ||||
|    */ | ||||
| 
 | ||||
|   // nsIStreamConverter::convert
 | ||||
|   convert: function(aFromStream, aFromType, aToType, aCtxt) { | ||||
|     throw Cr.NS_ERROR_NOT_IMPLEMENTED; | ||||
|   }, | ||||
| 
 | ||||
|   // nsIStreamConverter::asyncConvertData
 | ||||
|   asyncConvertData: function(aFromType, aToType, aListener, aCtxt) { | ||||
|     // Store the listener passed to us
 | ||||
|     this.listener = aListener; | ||||
|   }, | ||||
| 
 | ||||
|   // nsIStreamListener::onDataAvailable
 | ||||
|   onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) { | ||||
|     if (!this.dataListener) { | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     var binaryStream = this.binaryStream; | ||||
|     binaryStream.setInputStream(aInputStream); | ||||
|     var chunk = binaryStream.readByteArray(aCount); | ||||
|     this.dataListener.append(chunk); | ||||
|   }, | ||||
| 
 | ||||
|   // nsIRequestObserver::onStartRequest
 | ||||
|   onStartRequest: function(aRequest, aContext) { | ||||
|     // Setup the request so we can use it below.
 | ||||
|     var isHttpRequest = false; | ||||
|     try { | ||||
|       aRequest.QueryInterface(Ci.nsIHttpChannel); | ||||
|       isHttpRequest = true; | ||||
|     } catch (e) {} | ||||
| 
 | ||||
|     var rangeRequest = false; | ||||
|     if (isHttpRequest) { | ||||
|       var contentEncoding = 'identity'; | ||||
|       try { | ||||
|         contentEncoding = aRequest.getResponseHeader('Content-Encoding'); | ||||
|       } catch (e) {} | ||||
| 
 | ||||
|       var acceptRanges; | ||||
|       try { | ||||
|         acceptRanges = aRequest.getResponseHeader('Accept-Ranges'); | ||||
|       } catch (e) {} | ||||
| 
 | ||||
|       var hash = aRequest.URI.ref; | ||||
|       rangeRequest = contentEncoding === 'identity' && | ||||
|                      acceptRanges === 'bytes' && | ||||
|                      aRequest.contentLength >= 0 && | ||||
|                      hash.indexOf('disableRange=true') < 0; | ||||
|     } | ||||
| 
 | ||||
|     aRequest.QueryInterface(Ci.nsIChannel); | ||||
| 
 | ||||
|     aRequest.QueryInterface(Ci.nsIWritablePropertyBag); | ||||
| 
 | ||||
|     var contentDispositionFilename; | ||||
|     try { | ||||
|       contentDispositionFilename = aRequest.contentDispositionFilename; | ||||
|     } catch (e) {} | ||||
| 
 | ||||
|     // Change the content type so we don't get stuck in a loop.
 | ||||
|     aRequest.setProperty('contentType', aRequest.contentType); | ||||
|     aRequest.contentType = 'text/html'; | ||||
|     if (isHttpRequest) { | ||||
|       // We trust PDF viewer, using no CSP
 | ||||
|       aRequest.setResponseHeader('Content-Security-Policy', '', false); | ||||
|       aRequest.setResponseHeader('Content-Security-Policy-Report-Only', '', | ||||
|                                  false); | ||||
|       aRequest.setResponseHeader('X-Content-Security-Policy', '', false); | ||||
|       aRequest.setResponseHeader('X-Content-Security-Policy-Report-Only', '', | ||||
|                                  false); | ||||
|     } | ||||
| 
 | ||||
|     PdfJsTelemetry.onViewerIsUsed(); | ||||
|     PdfJsTelemetry.onDocumentSize(aRequest.contentLength); | ||||
| 
 | ||||
| 
 | ||||
|     // Creating storage for PDF data
 | ||||
|     var contentLength = aRequest.contentLength; | ||||
|     this.dataListener = new PdfDataListener(contentLength); | ||||
|     this.binaryStream = Cc['@mozilla.org/binaryinputstream;1'] | ||||
|                         .createInstance(Ci.nsIBinaryInputStream); | ||||
| 
 | ||||
|     // Create a new channel that is viewer loaded as a resource.
 | ||||
|     var ioService = Services.io; | ||||
|     var channel = ioService.newChannel( | ||||
|                     PDF_VIEWER_WEB_PAGE, null, null); | ||||
| 
 | ||||
|     var listener = this.listener; | ||||
|     var dataListener = this.dataListener; | ||||
|     // Proxy all the request observer calls, when it gets to onStopRequest
 | ||||
|     // we can get the dom window.  We also intentionally pass on the original
 | ||||
|     // request(aRequest) below so we don't overwrite the original channel and
 | ||||
|     // trigger an assertion.
 | ||||
|     var proxy = { | ||||
|       onStartRequest: function(request, context) { | ||||
|         listener.onStartRequest(aRequest, context); | ||||
|       }, | ||||
|       onDataAvailable: function(request, context, inputStream, offset, count) { | ||||
|         listener.onDataAvailable(aRequest, context, inputStream, offset, count); | ||||
|       }, | ||||
|       onStopRequest: function(request, context, statusCode) { | ||||
|         // We get the DOM window here instead of before the request since it
 | ||||
|         // may have changed during a redirect.
 | ||||
|         var domWindow = getDOMWindow(channel); | ||||
|         var actions; | ||||
|         if (rangeRequest) { | ||||
|           actions = new RangedChromeActions( | ||||
|               domWindow, contentDispositionFilename, aRequest, dataListener); | ||||
|         } else { | ||||
|           actions = new StandardChromeActions( | ||||
|               domWindow, contentDispositionFilename, dataListener); | ||||
|         } | ||||
|         var requestListener = new RequestListener(actions); | ||||
|         domWindow.addEventListener(PDFJS_EVENT_ID, function(event) { | ||||
|           requestListener.receive(event); | ||||
|         }, false, true); | ||||
|         if (actions.supportsIntegratedFind()) { | ||||
|           var chromeWindow = getChromeWindow(domWindow); | ||||
|           var findEventManager = new FindEventManager(chromeWindow.gFindBar, | ||||
|                                                       domWindow, | ||||
|                                                       chromeWindow); | ||||
|           findEventManager.bind(); | ||||
|         } | ||||
|         listener.onStopRequest(aRequest, context, statusCode); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     // Keep the URL the same so the browser sees it as the same.
 | ||||
|     channel.originalURI = aRequest.URI; | ||||
|     channel.loadGroup = aRequest.loadGroup; | ||||
| 
 | ||||
|     // We can use resource principal when data is fetched by the chrome
 | ||||
|     // e.g. useful for NoScript
 | ||||
|     var securityManager = Cc['@mozilla.org/scriptsecuritymanager;1'] | ||||
|                           .getService(Ci.nsIScriptSecurityManager); | ||||
|     var uri = ioService.newURI(PDF_VIEWER_WEB_PAGE, null, null); | ||||
|     // FF16 and below had getCodebasePrincipal, it was replaced by
 | ||||
|     // getNoAppCodebasePrincipal (bug 758258).
 | ||||
|     var resourcePrincipal = 'getNoAppCodebasePrincipal' in securityManager ? | ||||
|                             securityManager.getNoAppCodebasePrincipal(uri) : | ||||
|                             securityManager.getCodebasePrincipal(uri); | ||||
|     aRequest.owner = resourcePrincipal; | ||||
|     channel.asyncOpen(proxy, aContext); | ||||
|   }, | ||||
| 
 | ||||
|   // nsIRequestObserver::onStopRequest
 | ||||
|   onStopRequest: function(aRequest, aContext, aStatusCode) { | ||||
|     if (!this.dataListener) { | ||||
|       // Do nothing
 | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     if (Components.isSuccessCode(aStatusCode)) | ||||
|       this.dataListener.finish(); | ||||
|     else | ||||
|       this.dataListener.error(aStatusCode); | ||||
|     delete this.dataListener; | ||||
|     delete this.binaryStream; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| var NSGetFactory = XPCOMUtils.generateNSGetFactory([PdfStreamConverter]); | ||||
							
								
								
									
										18
									
								
								public/vendor/pdfjs/l10n/es/chrome.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								public/vendor/pdfjs/l10n/es/chrome.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| # 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. | ||||
| 
 | ||||
| # Chrome notification bar messages and buttons | ||||
| unsupported_feature=Es posible que este documento PDF no se muestre correctamente. | ||||
| open_with_different_viewer=Abrir con un visor diferente | ||||
| open_with_different_viewer.accessKey=a | ||||
							
								
								
									
										8
									
								
								public/vendor/pdfjs/l10n/es/metadata.inc
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								public/vendor/pdfjs/l10n/es/metadata.inc
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
|     <em:localized> | ||||
|       <Description> | ||||
|         <em:locale>es</em:locale> | ||||
|         <em:name>Visor de PDF</em:name> | ||||
|         <em:description>Usa HTML5 para mostrar archivos PDF directamente en Firefox.</em:description> | ||||
|       </Description> | ||||
|     </em:localized> | ||||
| 
 | ||||
							
								
								
									
										141
									
								
								public/vendor/pdfjs/l10n/es/viewer.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								public/vendor/pdfjs/l10n/es/viewer.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,141 @@ | ||||
| # 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. | ||||
| 
 | ||||
| # Main toolbar buttons (tooltips and alt text for images) | ||||
| previous.title=Página anterior | ||||
| previous_label=Anterior | ||||
| next.title=Página siguiente | ||||
| next_label=Siguiente | ||||
| 
 | ||||
| # LOCALIZATION NOTE (page_label, page_of): | ||||
| # These strings are concatenated to form the "Page: X of Y" string. | ||||
| # Do not translate "{{pageCount}}", it will be substituted with a number | ||||
| # representing the total number of pages. | ||||
| page_label=Página: | ||||
| page_of=de {{pageCount}} | ||||
| 
 | ||||
| zoom_out.title=Reducir | ||||
| zoom_out_label=Reducir | ||||
| zoom_in.title=Aumentar | ||||
| zoom_in_label=Aumentar | ||||
| zoom.title=Ampliación | ||||
| presentation_mode.title=Cambiar al modo de presentación | ||||
| presentation_mode_label=Modo de presentación | ||||
| open_file.title=Abrir un archivo | ||||
| open_file_label=Abrir | ||||
| print.title=Imprimir | ||||
| print_label=Imprimir | ||||
| download.title=Descargar | ||||
| download_label=Descargar | ||||
| bookmark.title=Vista actual (para copiar o abrir en otra ventana) | ||||
| bookmark_label=Vista actual | ||||
| 
 | ||||
| # Secondary toolbar and context menu | ||||
| tools.title=Herramientas | ||||
| tools_label=Herramientas | ||||
| first_page.title=Ir a la primera página | ||||
| first_page.label=Ir a la primera página | ||||
| first_page_label=Ir a la primera página | ||||
| last_page.title=Ir a la última página | ||||
| last_page.label=Ir a la última página | ||||
| last_page_label=Ir a la última página | ||||
| page_rotate_cw.title=Girar a la derecha | ||||
| page_rotate_cw.label=Girar a la derecha | ||||
| page_rotate_cw_label=Girar a la derecha | ||||
| page_rotate_ccw.title=Girar a la izquierda | ||||
| page_rotate_ccw.label=Girar a la izquierda | ||||
| page_rotate_ccw_label=Girar a la izquierda | ||||
| 
 | ||||
| hand_tool_enable.title=Activar la herramienta Mano | ||||
| hand_tool_enable_label=Activar la herramienta Mano | ||||
| hand_tool_disable.title=Desactivar la herramienta Mano | ||||
| hand_tool_disable_label=Desactivar la herramienta Mano | ||||
| 
 | ||||
| # Tooltips and alt text for side panel toolbar buttons | ||||
| # (the _label strings are alt text for the buttons, the .title strings are | ||||
| # tooltips) | ||||
| toggle_sidebar.title=Mostrar u ocultar la barra lateral | ||||
| toggle_sidebar_label=Conmutar la barra lateral | ||||
| outline.title=Mostrar el esquema del documento | ||||
| outline_label=Esquema del documento | ||||
| thumbs.title=Mostrar las miniaturas | ||||
| thumbs_label=Miniaturas | ||||
| findbar.title=Buscar en el documento | ||||
| findbar_label=Buscar | ||||
| 
 | ||||
| # Thumbnails panel item (tooltip and alt text for images) | ||||
| # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page | ||||
| # number. | ||||
| thumb_page_title=Página {{page}} | ||||
| # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page | ||||
| # number. | ||||
| thumb_page_canvas=Miniatura de la página {{page}} | ||||
| 
 | ||||
| # Find panel button title and messages | ||||
| find_label=Buscar: | ||||
| find_previous.title=Ir a la frase encontrada anterior | ||||
| find_previous_label=Anterior | ||||
| find_next.title=Ir a la frase encontrada siguiente | ||||
| find_next_label=Siguiente | ||||
| find_highlight=Resaltar todo | ||||
| find_match_case_label=Coincidir mayúsculas y minúsculas | ||||
| find_reached_top=Se alcanzó el inicio del documento, se continúa desde el final | ||||
| find_reached_bottom=Se alcanzó el final del documento, se continúa desde el inicio | ||||
| find_not_found=No se encontró la frase | ||||
| 
 | ||||
| # Error panel labels | ||||
| error_more_info=Más información | ||||
| error_less_info=Menos información | ||||
| error_close=Cerrar | ||||
| # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be | ||||
| # replaced by the PDF.JS version and build ID. | ||||
| error_version_info=PDF.js v{{version}} (compilación: {{build}}) | ||||
| # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an | ||||
| # english string describing the error. | ||||
| error_message=Mensaje: {{message}} | ||||
| # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack | ||||
| # trace. | ||||
| error_stack=Pila: {{stack}} | ||||
| # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename | ||||
| error_file=Archivo: {{file}} | ||||
| # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number | ||||
| error_line=Línea: {{line}} | ||||
| rendering_error=Ocurrió un error al renderizar la página. | ||||
| 
 | ||||
| # Predefined zoom values | ||||
| page_scale_width=Anchura de la página | ||||
| page_scale_fit=Ajustar a la página | ||||
| page_scale_auto=Ampliación automática | ||||
| page_scale_actual=Tamaño real | ||||
| 
 | ||||
| # Loading indicator messages | ||||
| loading_error_indicator=Error | ||||
| loading_error=Ocurrió un error al cargar el PDF. | ||||
| invalid_file_error=El archivo PDF no es válido o está dañado. | ||||
| missing_file_error=Falta el archivo PDF. | ||||
| 
 | ||||
| # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. | ||||
| # "{{type}}" will be replaced with an annotation type from a list defined in | ||||
| # the PDF spec (32000-1:2008 Table 169 – Annotation types). | ||||
| # Some common types are e.g.: "Check", "Text", "Comment", "Note" | ||||
| text_annotation_type.alt=[Anotación {{type}}] | ||||
| password_label=Escriba la contraseña para abrir este archivo PDF. | ||||
| password_invalid=La contraseña no es válida. Inténtelo de nuevo. | ||||
| password_ok=Aceptar | ||||
| password_cancel=Cancelar | ||||
| 
 | ||||
| printing_not_supported=Aviso: Este navegador no es compatible completamente con la impresión. | ||||
| printing_not_ready=Aviso: El PDF no se ha cargado completamente para su impresión. | ||||
| web_fonts_disabled=Se han desactivado los tipos de letra web: no se pueden usar los tipos de letra incrustados en el PDF. | ||||
| document_colors_disabled=No se permite que los documentos PDF usen sus propios colores: la opción «Permitir que las páginas elijan sus propios colores» está desactivada en el navegador. | ||||
							
								
								
									
										19
									
								
								public/vendor/pdfjs/l10n/no/chrome.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								public/vendor/pdfjs/l10n/no/chrome.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| # 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. | ||||
| 
 | ||||
| # Chrome notification bar messages and buttons | ||||
| unsupported_feature=Dette PDF-dokumentet vert kanskje ikkje vist rett. | ||||
| open_with_different_viewer=Opne med eit anna visingsprogram | ||||
| open_with_different_viewer.accessKey=o | ||||
| 
 | ||||
							
								
								
									
										8
									
								
								public/vendor/pdfjs/l10n/no/metadata.inc
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								public/vendor/pdfjs/l10n/no/metadata.inc
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
|     <em:localized> | ||||
|       <Description> | ||||
|         <em:locale>no</em:locale> | ||||
|         <em:name>PDF Viewer</em:name> | ||||
|         <em:description>Bruker HTML5 for å vise PDF-filer direkte i Firefox.</em:description> | ||||
|       </Description> | ||||
|     </em:localized> | ||||
| 
 | ||||
							
								
								
									
										134
									
								
								public/vendor/pdfjs/l10n/no/viewer.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								public/vendor/pdfjs/l10n/no/viewer.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | ||||
| # 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. | ||||
| 
 | ||||
| # Main toolbar buttons (tooltips and alt text for images) | ||||
| previous.title=Førre Side | ||||
| previous_label=Førre | ||||
| next.title=Neste side | ||||
| next_label=Neste | ||||
| 
 | ||||
| # LOCALIZATION NOTE (page_label, page_of): | ||||
| # These strings are concatenated to form the "Page: X of Y" string. | ||||
| # Do not translate "{{pageCount}}", it will be substituted with a number | ||||
| # representing the total number of pages. | ||||
| page_label=Side: | ||||
| page_of=av {{pageCount}} | ||||
| 
 | ||||
| zoom_out.title=Zoom ut | ||||
| zoom_out_label=Zoom ut | ||||
| zoom_in.title=Zoom inn | ||||
| zoom_in_label=Zoom inn | ||||
| zoom.title=Zoom | ||||
| presentation_mode.title=Bytt til presentasjonsmodus | ||||
| presentation_mode_label=Presentasjonsmodus | ||||
| open_file.title=Opne fil | ||||
| open_file_label=Opne | ||||
| print.title=Skriv ut | ||||
| print_label=Skriv ut | ||||
| download.title=Last ned | ||||
| download_label=Last ned | ||||
| bookmark.title=Gjeldande visning (kopier eller opne i nytt vindauge) | ||||
| bookmark_label=Gjeldende visning | ||||
| 
 | ||||
| # Secondary toolbar and context menu | ||||
| tools.title=Verktøy | ||||
| tools_label=Verktøy | ||||
| first_page.title=Gå til første side | ||||
| first_page.label=Gå til første side | ||||
| first_page_label=Gå til første side | ||||
| last_page.title=Gå til siste side | ||||
| last_page.label=Gå til siste side | ||||
| last_page_label=Gå til siste side | ||||
| page_rotate_cw.title=Roter med klokka | ||||
| page_rotate_cw.label=Roter med klokka | ||||
| page_rotate_cw_label=Roter med klokka | ||||
| page_rotate_ccw.title=Roter mot klokka | ||||
| page_rotate_ccw.label=Roter mot klokka | ||||
| page_rotate_ccw_label=Roter mot klokka | ||||
| 
 | ||||
| # Tooltips and alt text for side panel toolbar buttons | ||||
| # (the _label strings are alt text for the buttons, the .title strings are | ||||
| # tooltips) | ||||
| toggle_sidebar.title=Veksle Sidebar | ||||
| toggle_sidebar_label=Veksle Sidebar | ||||
| outline.title=Vis Document Outline | ||||
| outline_label=Document Outline | ||||
| thumbs.title=Vis miniatyrbilder | ||||
| thumbs_label=Miniatyrbilder | ||||
| findbar.title=Finne i Dokument | ||||
| findbar_label=Finn | ||||
| 
 | ||||
| # Thumbnails panel item (tooltip and alt text for images) | ||||
| # LOCALIZATION NOTE (thumb_page_title): "{{page}}" will be replaced by the page | ||||
| # number. | ||||
| thumb_page_title=Side {{page}} | ||||
| # LOCALIZATION NOTE (thumb_page_canvas): "{{page}}" will be replaced by the page | ||||
| # number. | ||||
| thumb_page_canvas=Thumbnail av siden {{page}} | ||||
| 
 | ||||
| # Find panel button title and messages | ||||
| find_label=Finn: | ||||
| find_previous.title=Finn tidlegare førekomst av frasa | ||||
| find_previous_label=Førre | ||||
| find_next.title=Finn neste førekomst av frasa | ||||
| find_next_label=Neste | ||||
| find_highlight=Uthev alle | ||||
| find_match_case_label=Skil store/små bokstavar | ||||
| find_reached_top=Nådde toppen av dokumentet, held fram frå botnen | ||||
| find_reached_bottom=Nådde botnen av dokumentet, held fram frå toppen | ||||
| find_not_found=Fann ikkje teksten | ||||
| 
 | ||||
| # Error panel labels | ||||
| error_more_info=Meir info | ||||
| error_less_info=Mindre info | ||||
| error_close=Lukk | ||||
| # LOCALIZATION NOTE (error_version_info): "{{version}}" and "{{build}}" will be | ||||
| # replaced by the PDF.JS version and build ID. | ||||
| error_version_info=PDF.js v {{version}} (build: {{build}}) | ||||
| # LOCALIZATION NOTE (error_message): "{{message}}" will be replaced by an | ||||
| # english string describing the error. | ||||
| error_message=Melding: {{message}} | ||||
| # LOCALIZATION NOTE (error_stack): "{{stack}}" will be replaced with a stack | ||||
| # trace. | ||||
| error_stack=Stakk: {{stack}} | ||||
| # LOCALIZATION NOTE (error_file): "{{file}}" will be replaced with a filename | ||||
| error_file=Fil: {{file}} | ||||
| # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number | ||||
| error_line=Linje: {{line}} | ||||
| rendering_error=Ein feil oppstod ved oppteikning av sida. | ||||
| 
 | ||||
| # Predefined zoom values | ||||
| page_scale_width=Sidebreidde | ||||
| page_scale_fit=Tilpass til sida | ||||
| page_scale_auto=Automatisk zoom | ||||
| page_scale_actual=Verkeleg størrelse | ||||
| 
 | ||||
| # Loading indicator messages | ||||
| loading_error_indicator=Feil | ||||
| loading_error=Ein feil oppstod ved lasting av PDF. | ||||
| invalid_file_error=Ugyldig eller korrupt PDF fil. | ||||
| missing_file_error=Manglande PDF-fil. | ||||
| 
 | ||||
| # LOCALIZATION NOTE (text_annotation_type.alt): This is used as a tooltip. | ||||
| # "{{type}}" will be replaced with an annotation type from a list defined in | ||||
| # the PDF spec (32000-1:2008 Table 169 – Annotation types). | ||||
| # Some common types are e.g.: "Check", "Text", "Comment", "Note" | ||||
| text_annotation_type.alt=[{{type}} annotasjon] | ||||
| request_password=PDF er beskytta av eit passord: | ||||
| invalid_password=Ugyldig passord. | ||||
| 
 | ||||
| printing_not_supported=Åtvaring: Utskrift er ikkje fullstendig støtta av denne nettlesaren. | ||||
| printing_not_ready=Åtvaring: PDF ikkje fullstendig innlasta for utskrift. | ||||
| web_fonts_disabled=Web-fontar er avslått: Kan ikkje bruke innbundne PDF-fontar. | ||||
| document_colors_disabled=PDF-dokument har ikkje løyve til å nytte eigne fargar: \'Tillat sider å velje eigne fargar\' er slått av i nettlesaren. | ||||
							
								
								
									
										640
									
								
								public/vendor/pdfjs/test/resources/reftest-analyzer.xhtml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										640
									
								
								public/vendor/pdfjs/test/resources/reftest-analyzer.xhtml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,640 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!-- vim: set shiftwidth=4 tabstop=4 autoindent noexpandtab: --> | ||||
| <!-- ***** BEGIN LICENSE BLOCK ***** | ||||
|    - Version: MPL 1.1/GPL 2.0/LGPL 2.1 | ||||
|    - | ||||
|    - The contents of this file are subject to the Mozilla Public License Version | ||||
|    - 1.1 (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.mozilla.org/MPL/ | ||||
|    - | ||||
|    - Software distributed under the License is distributed on an "AS IS" basis, | ||||
|    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | ||||
|    - for the specific language governing rights and limitations under the | ||||
|    - License. | ||||
|    - | ||||
|    - The Original Code is reftest-analyzer.html. | ||||
|    - | ||||
|    - The Initial Developer of the Original Code is the Mozilla Foundation. | ||||
|    - Portions created by the Initial Developer are Copyright (C) 2008 | ||||
|    - the Initial Developer. All Rights Reserved. | ||||
|    - | ||||
|    - Contributor(s): | ||||
|    -   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation (original author) | ||||
|    - | ||||
|    - Alternatively, the contents of this file may be used under the terms of | ||||
|    - either the GNU General Public License Version 2 or later (the "GPL"), or | ||||
|    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), | ||||
|    - in which case the provisions of the GPL or the LGPL are applicable instead | ||||
|    - of those above. If you wish to allow use of your version of this file only | ||||
|    - under the terms of either the GPL or the LGPL, and not to allow others to | ||||
|    - use your version of this file under the terms of the MPL, indicate your | ||||
|    - decision by deleting the provisions above and replace them with the notice | ||||
|    - and other provisions required by the LGPL or the GPL. If you do not delete | ||||
|    - the provisions above, a recipient may use your version of this file under | ||||
|    - the terms of any one of the MPL, the GPL or the LGPL. | ||||
|    - | ||||
|    - ***** END LICENSE BLOCK ***** --> | ||||
| <!-- | ||||
| 
 | ||||
| Features to add: | ||||
| * make the left and right parts of the viewer independently scrollable | ||||
| * make the test list filterable | ||||
| ** default to only showing unexpecteds | ||||
| * add other ways to highlight differences other than circling? | ||||
| * add zoom/pan to images | ||||
| * Add ability to load log via XMLHttpRequest (also triggered via URL param) | ||||
| * color the test list based on pass/fail and expected/unexpected/random/skip | ||||
| * ability to load multiple logs ? | ||||
| ** rename them by clicking on the name and editing | ||||
| ** turn the test list into a collapsing tree view | ||||
| ** move log loading into popup from viewer UI | ||||
| 
 | ||||
| --> | ||||
| <html lang="en-US" xml:lang="en-US" xmlns="http://www.w3.org/1999/xhtml"> | ||||
| <head> | ||||
|   <title>Reftest analyzer</title> | ||||
|   <style type="text/css"><![CDATA[ | ||||
| 
 | ||||
|   html, body { margin: 0; } | ||||
|   html { padding: 0; } | ||||
|   body { padding: 4px; } | ||||
| 
 | ||||
|   #pixelarea, #itemlist, #images { position: absolute; } | ||||
|   #itemlist, #images { overflow: auto; } | ||||
|   #pixelarea { top: 0; left: 0; width: 320px; height: 84px; overflow: visible } | ||||
|   #itemlist { top: 84px; left: 0; width: 320px; bottom: 0; } | ||||
|   #images { top: 0; bottom: 0; left: 320px; right: 0; } | ||||
| 
 | ||||
|   #leftpane { width: 320px; } | ||||
|   #images { position: fixed; top: 10px; left: 340px; } | ||||
| 
 | ||||
|   form#imgcontrols { margin: 0; display: block; } | ||||
| 
 | ||||
|   #itemlist > table { border-collapse: collapse; } | ||||
|   #itemlist > table > tbody > tr > td { border: 1px solid; padding: 1px; } | ||||
| 
 | ||||
|   .selected { background-color: lightsteelblue; } | ||||
| 
 | ||||
|   /* | ||||
|   #itemlist > table > tbody > tr.pass > td.url { background: lime; } | ||||
|   #itemlist > table > tbody > tr.fail > td.url { background: red; } | ||||
|   */ | ||||
| 
 | ||||
|   #magnification > svg { display: block; width: 84px; height: 84px; } | ||||
| 
 | ||||
|   #pixelinfo { font: small sans-serif; position: absolute; width: 200px; left: 84px; } | ||||
|   #pixelinfo table { border-collapse: collapse; } | ||||
|   #pixelinfo table th { white-space: nowrap; text-align: left; padding: 0; } | ||||
|   #pixelinfo table td { font-family: monospace; padding: 0 0 0 0.25em; } | ||||
| 
 | ||||
|   #pixelhint { display: inline; color: #88f; cursor: help; } | ||||
|   #pixelhint > * { display: none; position: absolute; margin: 8px 0 0 8px; padding: 4px; width: 400px; background: #ffa; color: black; box-shadow: 3px 3px 2px #888; z-index: 1; } | ||||
|   #pixelhint:hover { color: #000; } | ||||
|   #pixelhint:hover > * { display: block; } | ||||
|   #pixelhint p { margin: 0; } | ||||
|   #pixelhint p + p { margin-top: 1em; } | ||||
| 
 | ||||
|   ]]></style> | ||||
|   <script type="text/javascript"><![CDATA[ | ||||
| 
 | ||||
| var XLINK_NS = "http://www.w3.org/1999/xlink"; | ||||
| var SVG_NS = "http://www.w3.org/2000/svg"; | ||||
| 
 | ||||
| var gPhases = null; | ||||
| 
 | ||||
| var gIDCache = {}; | ||||
| 
 | ||||
| var gMagPixPaths = [];     // 2D array of array-of-two <path> objects used in the pixel magnifier | ||||
| var gMagWidth = 5;         // number of zoomed in pixels to show horizontally | ||||
| var gMagHeight = 5;        // number of zoomed in pixels to show vertically | ||||
| var gMagZoom = 16;         // size of the zoomed in pixels | ||||
| var gImage1Data;           // ImageData object for the test output image | ||||
| var gImage2Data;           // ImageData object for the reference image | ||||
| var gFlashingPixels = [];  // array of <path> objects that should be flashed due to pixel color mismatch | ||||
| var gPath = '';            // path taken from #web= and prepended to ref/snp urls | ||||
| var gSelected = null;      // currently selected comparison | ||||
| 
 | ||||
| function ID(id) { | ||||
|   if (!(id in gIDCache)) | ||||
|     gIDCache[id] = document.getElementById(id); | ||||
|   return gIDCache[id]; | ||||
| } | ||||
| 
 | ||||
| function hash_parameters() { | ||||
|   var result = { }; | ||||
|   var params = window.location.hash.substr(1).split(/[&;]/); | ||||
|   for (var i = 0; i < params.length; i++) { | ||||
|     var parts = params[i].split("="); | ||||
|     result[parts[0]] = unescape(unescape(parts[1])); | ||||
|   } | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| function load() { | ||||
|   gPhases = [ ID("entry"), ID("loading"), ID("viewer") ]; | ||||
|   build_mag(); | ||||
|   var params = hash_parameters(); | ||||
|   if (params.log) { | ||||
|     ID("logentry").value = params.log; | ||||
|     log_pasted(); | ||||
|   } else if (params.web) { | ||||
|     loadFromWeb(params.web);  | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function build_mag() { | ||||
|   var mag = ID("mag"); | ||||
| 
 | ||||
|   var r = document.createElementNS(SVG_NS, "rect"); | ||||
|   r.setAttribute("x", gMagZoom * -gMagWidth / 2); | ||||
|   r.setAttribute("y", gMagZoom * -gMagHeight / 2); | ||||
|   r.setAttribute("width", gMagZoom * gMagWidth); | ||||
|   r.setAttribute("height", gMagZoom * gMagHeight); | ||||
|   mag.appendChild(r); | ||||
| 
 | ||||
|   mag.setAttribute("transform", "translate(" + (gMagZoom * (gMagWidth / 2) + 1) + "," + (gMagZoom * (gMagHeight / 2) + 1) + ")"); | ||||
| 
 | ||||
|   for (var x = 0; x < gMagWidth; x++) { | ||||
|     gMagPixPaths[x] = []; | ||||
|     for (var y = 0; y < gMagHeight; y++) { | ||||
|       var p1 = document.createElementNS(SVG_NS, "path"); | ||||
|       p1.setAttribute("d", "M" + ((x - gMagWidth / 2) + 1) * gMagZoom + "," + (y - gMagHeight / 2) * gMagZoom + "h" + -gMagZoom + "v" + gMagZoom); | ||||
|       p1.setAttribute("stroke", "black"); | ||||
|       p1.setAttribute("stroke-width", "1px"); | ||||
|       p1.setAttribute("fill", "#aaa"); | ||||
| 
 | ||||
|       var p2 = document.createElementNS(SVG_NS, "path"); | ||||
|       p2.setAttribute("d", "M" + ((x - gMagWidth / 2) + 1) * gMagZoom + "," + (y - gMagHeight / 2) * gMagZoom + "v" + gMagZoom + "h" + -gMagZoom); | ||||
|       p2.setAttribute("stroke", "black"); | ||||
|       p2.setAttribute("stroke-width", "1px"); | ||||
|       p2.setAttribute("fill", "#888"); | ||||
| 
 | ||||
|       mag.appendChild(p1); | ||||
|       mag.appendChild(p2); | ||||
|       gMagPixPaths[x][y] = [p1, p2]; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   var flashedOn = false; | ||||
|   setInterval(function() { | ||||
|     flashedOn = !flashedOn; | ||||
|     flash_pixels(flashedOn); | ||||
|   }, 500); | ||||
| } | ||||
| 
 | ||||
| function show_phase(phaseid) { | ||||
|   for (var i in gPhases) { | ||||
|     var phase = gPhases[i]; | ||||
|     phase.style.display = (phase.id == phaseid) ? "" : "none"; | ||||
|   } | ||||
| 
 | ||||
|   if (phase == "viewer") | ||||
|     ID("images").style.display = "none"; | ||||
| } | ||||
| 
 | ||||
| function loadFromWeb(url) { | ||||
|   var lastSlash = url.lastIndexOf('/'); | ||||
|   if (lastSlash) { | ||||
|     gPath = url.substring(0, lastSlash + 1); | ||||
|   } | ||||
| 
 | ||||
|   var r = new XMLHttpRequest(); | ||||
|   r.open("GET", url); | ||||
|   r.onreadystatechange = function() { | ||||
|     if (r.readyState == 4) { | ||||
|       process_log(r.response); | ||||
|     } | ||||
|   } | ||||
|   r.send(null); | ||||
| } | ||||
| 
 | ||||
| function fileentry_changed() { | ||||
|   show_phase("loading"); | ||||
|   var input = ID("fileentry"); | ||||
|   var files = input.files; | ||||
|   if (files.length > 0) { | ||||
|     // Only handle the first file; don't handle multiple selection. | ||||
|     // The parts of the log we care about are ASCII-only.  Since we | ||||
|     // can ignore lines we don't care about, best to read in as | ||||
|     // iso-8859-1, which guarantees we don't get decoding errors. | ||||
|     var fileReader = new FileReader(); | ||||
|     fileReader.onload = function(e) { | ||||
|       var log = null; | ||||
| 
 | ||||
|       log = e.target.result; | ||||
|        | ||||
|       if (log) | ||||
|         process_log(log); | ||||
|       else | ||||
|         show_phase("entry"); | ||||
|     } | ||||
|     fileReader.readAsText(files[0], "iso-8859-1"); | ||||
|   } | ||||
|   // So the user can process the same filename again (after | ||||
|   // overwriting the log), clear the value on the form input so we | ||||
|   // will always get an onchange event. | ||||
|   input.value = ""; | ||||
| } | ||||
| 
 | ||||
| function log_pasted() { | ||||
|   show_phase("loading"); | ||||
|   var entry = ID("logentry"); | ||||
|   var log = entry.value; | ||||
|   entry.value = ""; | ||||
|   process_log(log); | ||||
| } | ||||
| 
 | ||||
| var gTestItems; | ||||
| 
 | ||||
| function process_log(contents) { | ||||
|   var lines = contents.split(/[\r\n]+/); | ||||
|   gTestItems = []; | ||||
|   for (var j in lines) { | ||||
|     var line = lines[j]; | ||||
|     var match = line.match(/^(?:NEXT ERROR )?REFTEST (.*)$/); | ||||
|     if (!match) | ||||
|       continue; | ||||
|     line = match[1]; | ||||
|     match = line.match(/^(TEST-PASS|TEST-UNEXPECTED-PASS|TEST-KNOWN-FAIL|TEST-UNEXPECTED-FAIL)(\(EXPECTED RANDOM\)|) \| ([^\|]+) \|(.*)/); | ||||
|     if (match) { | ||||
|       var state = match[1]; | ||||
|       var random = match[2]; | ||||
|       var url = match[3]; | ||||
|                         var extra = match[4]; | ||||
|       gTestItems.push( | ||||
|         { | ||||
|           pass: !state.match(/FAIL$/), | ||||
|           // only one of the following three should ever be true | ||||
|           unexpected: !!state.match(/^TEST-UNEXPECTED/), | ||||
|           random: (random == "(EXPECTED RANDOM)"), | ||||
|           skip: (extra == " (SKIP)"), | ||||
|           url: url, | ||||
|           images: [] | ||||
|         }); | ||||
|       continue; | ||||
|     } | ||||
|     match = line.match(/^  IMAGE[^:]*: (.*)$/); | ||||
|     if (match) { | ||||
|       var item = gTestItems[gTestItems.length - 1]; | ||||
|       item.images.push(match[1]); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   build_viewer(); | ||||
| } | ||||
| 
 | ||||
| function build_viewer() { | ||||
|   if (gTestItems.length == 0) { | ||||
|     show_phase("entry"); | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   var cell = ID("itemlist"); | ||||
|   while (cell.childNodes.length > 0) | ||||
|     cell.removeChild(cell.childNodes[cell.childNodes.length - 1]); | ||||
| 
 | ||||
|   var table = document.createElement("table"); | ||||
|   var tbody = document.createElement("tbody"); | ||||
|   table.appendChild(tbody); | ||||
| 
 | ||||
|   for (var i in gTestItems) { | ||||
|     var item = gTestItems[i]; | ||||
| 
 | ||||
|     // XXX skip expected pass items until we have filtering UI | ||||
|     if (item.pass && !item.unexpected) | ||||
|       continue; | ||||
| 
 | ||||
|     var tr = document.createElement("tr"); | ||||
|     var rowclass = item.pass ? "pass" : "fail"; | ||||
|     var td; | ||||
|     var text; | ||||
| 
 | ||||
|     td = document.createElement("td"); | ||||
|     text = ""; | ||||
|     if (item.unexpected) { text += "!"; rowclass += " unexpected"; } | ||||
|     if (item.random) { text += "R"; rowclass += " random"; } | ||||
|     if (item.skip) { text += "S"; rowclass += " skip"; } | ||||
|     td.appendChild(document.createTextNode(text)); | ||||
|     tr.appendChild(td); | ||||
| 
 | ||||
|     td = document.createElement("td"); | ||||
|     td.id = "url" + i; | ||||
|     td.className = "url"; | ||||
|     // Only display part of URL after "/mozilla/". | ||||
|     var match = item.url.match(/\/mozilla\/(.*)/); | ||||
|     text = document.createTextNode(match ? match[1] : item.url); | ||||
|     if (item.images.length > 0) { | ||||
|       var a = document.createElement("a"); | ||||
|       a.href = "javascript:show_images(" + i + ")"; | ||||
|       a.appendChild(text); | ||||
|       td.appendChild(a); | ||||
|     } else { | ||||
|       td.appendChild(text); | ||||
|     } | ||||
|     tr.appendChild(td); | ||||
| 
 | ||||
|     tbody.appendChild(tr); | ||||
|   } | ||||
| 
 | ||||
|   cell.appendChild(table); | ||||
| 
 | ||||
|   show_phase("viewer"); | ||||
| } | ||||
| 
 | ||||
| function get_image_data(src, whenReady) { | ||||
|   var img = new Image(); | ||||
|   img.onload = function() { | ||||
|     var canvas = document.createElement("canvas"); | ||||
|     canvas.width = 800; | ||||
|     canvas.height = 1000; | ||||
| 
 | ||||
|     var ctx = canvas.getContext("2d"); | ||||
|     ctx.drawImage(img, 0, 0); | ||||
| 
 | ||||
|     whenReady(ctx.getImageData(0, 0, 800, 1000)); | ||||
|   }; | ||||
|   img.src = gPath + src; | ||||
| } | ||||
| 
 | ||||
| function show_images(i) { | ||||
|   if (gSelected !== null) { | ||||
|     ID('url' + gSelected).classList.remove('selected'); | ||||
|   } | ||||
|   gSelected = i; | ||||
|   ID('url' + gSelected).classList.add('selected'); | ||||
|   var item = gTestItems[i]; | ||||
|   var cell = ID("images"); | ||||
| 
 | ||||
|   ID("image1").style.display = ""; | ||||
|   ID("image2").style.display = "none"; | ||||
|   ID("diffrect").style.display = "none"; | ||||
|   ID("imgcontrols").reset(); | ||||
| 
 | ||||
|   ID("image1").setAttributeNS(XLINK_NS, "xlink:href", gPath + item.images[0]); | ||||
|   // Making the href be #image1 doesn't seem to work | ||||
|   ID("feimage1").setAttributeNS(XLINK_NS, "xlink:href", gPath + item.images[0]); | ||||
|   if (item.images.length == 1) { | ||||
|     ID("imgcontrols").style.display = "none"; | ||||
|   } else { | ||||
|     ID("imgcontrols").style.display = ""; | ||||
| 
 | ||||
|     ID("image2").setAttributeNS(XLINK_NS, "xlink:href", gPath + item.images[1]); | ||||
|     // Making the href be #image2 doesn't seem to work | ||||
|     ID("feimage2").setAttributeNS(XLINK_NS, "xlink:href", gPath + item.images[1]); | ||||
|   } | ||||
| 
 | ||||
|   cell.style.display = ""; | ||||
| 
 | ||||
|   get_image_data(item.images[0], function(data) { gImage1Data = data }); | ||||
|   get_image_data(item.images[1], function(data) { gImage2Data = data }); | ||||
| } | ||||
| 
 | ||||
| function show_image(i) { | ||||
|   if (i == 1) { | ||||
|     ID("image1").style.display = ""; | ||||
|     ID("image2").style.display = "none"; | ||||
|   } else { | ||||
|     ID("image1").style.display = "none"; | ||||
|     ID("image2").style.display = ""; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function show_differences(cb) { | ||||
|   ID("diffrect").style.display = cb.checked ? "" : "none"; | ||||
| } | ||||
| 
 | ||||
| function flash_pixels(on) { | ||||
|   var stroke = on ? "red" : "black"; | ||||
|   var strokeWidth = on ? "2px" : "1px"; | ||||
|   for (var i = 0; i < gFlashingPixels.length; i++) { | ||||
|     gFlashingPixels[i].setAttribute("stroke", stroke); | ||||
|     gFlashingPixels[i].setAttribute("stroke-width", strokeWidth); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| function cursor_point(evt) { | ||||
|   var m = evt.target.getScreenCTM().inverse(); | ||||
|   var p = ID("svg").createSVGPoint(); | ||||
|   p.x = evt.clientX; | ||||
|   p.y = evt.clientY; | ||||
|   p = p.matrixTransform(m); | ||||
|   return { x: Math.floor(p.x), y: Math.floor(p.y) }; | ||||
| } | ||||
| 
 | ||||
| function hex2(i) { | ||||
|   return (i < 16 ? "0" : "") + i.toString(16); | ||||
| } | ||||
| 
 | ||||
| function canvas_pixel_as_hex(data, x, y) { | ||||
|   var offset = (y * data.width + x) * 4; | ||||
|   var r = data.data[offset]; | ||||
|   var g = data.data[offset + 1]; | ||||
|   var b = data.data[offset + 2]; | ||||
|   return "#" + hex2(r) + hex2(g) + hex2(b); | ||||
| } | ||||
| 
 | ||||
| function hex_as_rgb(hex) { | ||||
|   return "rgb(" + [parseInt(hex.substring(1, 3), 16), parseInt(hex.substring(3, 5), 16), parseInt(hex.substring(5, 7), 16)] + ")"; | ||||
| } | ||||
| 
 | ||||
| function magnify(evt) { | ||||
|   var { x: x, y: y } = cursor_point(evt); | ||||
|   var centerPixelColor1, centerPixelColor2; | ||||
| 
 | ||||
|   var dx_lo = -Math.floor(gMagWidth / 2); | ||||
|   var dx_hi = Math.floor(gMagWidth / 2); | ||||
|   var dy_lo = -Math.floor(gMagHeight / 2); | ||||
|   var dy_hi = Math.floor(gMagHeight / 2); | ||||
| 
 | ||||
|   flash_pixels(false); | ||||
|   gFlashingPixels = []; | ||||
|   for (var j = dy_lo; j <= dy_hi; j++) { | ||||
|     for (var i = dx_lo; i <= dx_hi; i++) { | ||||
|       var px = x + i; | ||||
|       var py = y + j; | ||||
|       var p1 = gMagPixPaths[i + dx_hi][j + dy_hi][0]; | ||||
|       var p2 = gMagPixPaths[i + dx_hi][j + dy_hi][1]; | ||||
|       if (px < 0 || py < 0 || px >= 800 || py >= 1000) { | ||||
|         p1.setAttribute("fill", "#aaa"); | ||||
|         p2.setAttribute("fill", "#888"); | ||||
|       } else { | ||||
|         var color1 = canvas_pixel_as_hex(gImage1Data, x + i, y + j); | ||||
|         var color2 = canvas_pixel_as_hex(gImage2Data, x + i, y + j); | ||||
|         p1.setAttribute("fill", color1); | ||||
|         p2.setAttribute("fill", color2); | ||||
|         if (color1 != color2) { | ||||
|           gFlashingPixels.push(p1, p2); | ||||
|           p1.parentNode.appendChild(p1); | ||||
|           p2.parentNode.appendChild(p2); | ||||
|         } | ||||
|         if (i == 0 && j == 0) { | ||||
|           centerPixelColor1 = color1; | ||||
|           centerPixelColor2 = color2; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   flash_pixels(true); | ||||
|   show_pixelinfo(x, y, centerPixelColor1, hex_as_rgb(centerPixelColor1), centerPixelColor2, hex_as_rgb(centerPixelColor2)); | ||||
| } | ||||
| 
 | ||||
| function show_pixelinfo(x, y, pix1rgb, pix1hex, pix2rgb, pix2hex) { | ||||
|   var pixelinfo = ID("pixelinfo"); | ||||
|   ID("coords").textContent = [x, y]; | ||||
|   ID("pix1hex").textContent = pix1hex; | ||||
|   ID("pix1rgb").textContent = pix1rgb; | ||||
|   ID("pix2hex").textContent = pix2hex; | ||||
|   ID("pix2rgb").textContent = pix2rgb; | ||||
| } | ||||
| 
 | ||||
| window.addEventListener('keydown', function keydown(event) { | ||||
|   if (event.which === 84) { | ||||
|     // 't' switch test/ref images | ||||
|     var val = 0; | ||||
|     if (document.querySelector('input[name="which"][value="0"]:checked')) { | ||||
|       val = 1; | ||||
|     } | ||||
|     document.querySelector('input[name="which"][value="' + val + '"]').click(); | ||||
|   } else if (event.which === 78 || event.which === 80) { | ||||
|     // 'n' next image, 'p' previous image | ||||
|     var select = gSelected; | ||||
|     if (gSelected === null) { | ||||
|       select = 0; | ||||
|     } else if (event.which === 78) { | ||||
|       select++; | ||||
|     } else { | ||||
|       select--; | ||||
|     } | ||||
|     var length = gTestItems.length; | ||||
|     select = select < 0 ? length - 1 : select >= length ? 0 : select; | ||||
|     show_images(select); | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
|   ]]></script> | ||||
| 
 | ||||
| </head> | ||||
| <body onload="load()"> | ||||
| 
 | ||||
| <div id="entry"> | ||||
| 
 | ||||
| <h1>Reftest analyzer: load reftest log</h1> | ||||
| 
 | ||||
| <p>Either paste your log into this textarea:<br /> | ||||
| <textarea cols="80" rows="10" id="logentry"/><br/> | ||||
| <input type="button" value="Process pasted log" onclick="log_pasted()" /></p> | ||||
| 
 | ||||
| <p>... or load it from a file:<br/> | ||||
| <input type="file" id="fileentry" onchange="fileentry_changed()" /> | ||||
| </p> | ||||
| </div> | ||||
| 
 | ||||
| <div id="loading" style="display:none">Loading log...</div> | ||||
| 
 | ||||
| <div id="viewer" style="display:none"> | ||||
|   <div id="pixelarea"> | ||||
|     <div id="pixelinfo"> | ||||
|       <table> | ||||
|         <tbody> | ||||
|           <tr><th>Pixel at:</th><td colspan="2" id="coords"/></tr> | ||||
|           <tr><th>Test:</th><td id="pix1rgb"></td><td id="pix1hex"></td></tr> | ||||
|           <tr><th>Reference:</th><td id="pix2rgb"></td><td id="pix2hex"></td></tr> | ||||
|         </tbody> | ||||
|       </table> | ||||
|       <div> | ||||
|         <div id="pixelhint">★ | ||||
|           <div> | ||||
|             <p>Move the mouse over the reftest image on the right to show | ||||
|             magnified pixels on the left.  The color information above is for | ||||
|             the pixel centered in the magnified view.</p> | ||||
|             <p>Image 1 is shown in the upper triangle of each pixel and Image 2 | ||||
|             is shown in the lower triangle.</p> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div id="magnification"> | ||||
|       <svg xmlns="http://www.w3.org/2000/svg" width="84" height="84" shape-rendering="optimizeSpeed"> | ||||
|         <g id="mag"/> | ||||
|       </svg> | ||||
|     </div> | ||||
|   </div> | ||||
|   <div id="itemlist"></div> | ||||
|   <div id="images" style="display:none"> | ||||
|     <form id="imgcontrols"> | ||||
|     <label><input type="radio" name="which" value="0" onchange="show_image(1)" checked="checked" />Test</label> | ||||
|     <label><input type="radio" name="which" value="1" onchange="show_image(2)" />Reference</label> | ||||
|     <label><input type="checkbox" onchange="show_differences(this)" />Circle differences</label> | ||||
|     </form> | ||||
|     <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800px" height="1000px" viewbox="0 0 800 1000" id="svg"> | ||||
|       <defs> | ||||
|         <!-- use sRGB to avoid loss of data --> | ||||
|         <filter id="showDifferences" x="0%" y="0%" width="100%" height="100%" | ||||
|                 style="color-interpolation-filters: sRGB"> | ||||
|           <feImage id="feimage1" result="img1" xlink:href="#image1" /> | ||||
|           <feImage id="feimage2" result="img2" xlink:href="#image2" /> | ||||
|           <!-- inv1 and inv2 are the images with RGB inverted --> | ||||
|           <feComponentTransfer result="inv1" in="img1"> | ||||
|             <feFuncR type="linear" slope="-1" intercept="1" /> | ||||
|             <feFuncG type="linear" slope="-1" intercept="1" /> | ||||
|             <feFuncB type="linear" slope="-1" intercept="1" /> | ||||
|           </feComponentTransfer> | ||||
|           <feComponentTransfer result="inv2" in="img2"> | ||||
|             <feFuncR type="linear" slope="-1" intercept="1" /> | ||||
|             <feFuncG type="linear" slope="-1" intercept="1" /> | ||||
|             <feFuncB type="linear" slope="-1" intercept="1" /> | ||||
|           </feComponentTransfer> | ||||
|           <!-- w1 will have non-white pixels anywhere that img2 | ||||
|                is brighter than img1, and w2 for the reverse. | ||||
|                It would be nice not to have to go through these | ||||
|                intermediate states, but feComposite | ||||
|                type="arithmetic" can't transform the RGB channels | ||||
|                and leave the alpha channel untouched. --> | ||||
|           <feComposite result="w1" in="img1" in2="inv2" operator="arithmetic" k2="1" k3="1" /> | ||||
|           <feComposite result="w2" in="img2" in2="inv1" operator="arithmetic" k2="1" k3="1" /> | ||||
|           <!-- c1 will have non-black pixels anywhere that img2 | ||||
|                is brighter than img1, and c2 for the reverse --> | ||||
|           <feComponentTransfer result="c1" in="w1"> | ||||
|             <feFuncR type="linear" slope="-1" intercept="1" /> | ||||
|             <feFuncG type="linear" slope="-1" intercept="1" /> | ||||
|             <feFuncB type="linear" slope="-1" intercept="1" /> | ||||
|           </feComponentTransfer> | ||||
|           <feComponentTransfer result="c2" in="w2"> | ||||
|             <feFuncR type="linear" slope="-1" intercept="1" /> | ||||
|             <feFuncG type="linear" slope="-1" intercept="1" /> | ||||
|             <feFuncB type="linear" slope="-1" intercept="1" /> | ||||
|           </feComponentTransfer> | ||||
|           <!-- c will be nonblack (and fully on) for every pixel+component where there are differences --> | ||||
|           <feComposite result="c" in="c1" in2="c2" operator="arithmetic" k2="255" k3="255" /> | ||||
|           <!-- a will be opaque for every pixel with differences and transparent for all others --> | ||||
|           <feColorMatrix result="a" type="matrix" values="0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  1 1 1 0 0" /> | ||||
|            | ||||
|           <!-- a, dilated by 4 pixels --> | ||||
|           <feMorphology result="dila4" in="a" operator="dilate" radius="4" /> | ||||
|           <!-- a, dilated by 1 pixel --> | ||||
|           <feMorphology result="dila1" in="a" operator="dilate" radius="1" /> | ||||
|            | ||||
|           <!-- all the pixels in the 3-pixel dilation of a but not in the 1-pixel dilation of a, to highlight the diffs --> | ||||
|           <feComposite result="highlight" in="dila4" in2="dila1" operator="out" /> | ||||
| 
 | ||||
|           <feFlood result="red" flood-color="red" /> | ||||
|           <feComposite result="redhighlight" in="red" in2="highlight" operator="in" /> | ||||
|           <feFlood result="black" flood-color="black" flood-opacity="0.5" /> | ||||
|           <feMerge> | ||||
|             <feMergeNode in="black" /> | ||||
|             <feMergeNode in="redhighlight" /> | ||||
|           </feMerge> | ||||
|         </filter> | ||||
|       </defs> | ||||
|       <g onmousemove="magnify(evt)"> | ||||
|         <image x="0" y="0" width="100%" height="100%" id="image1" /> | ||||
|         <image x="0" y="0" width="100%" height="100%" id="image2" /> | ||||
|       </g> | ||||
|       <rect id="diffrect" filter="url(#showDifferences)" pointer-events="none" x="0" y="0" width="100%" height="100%" /> | ||||
|     </svg> | ||||
|   </div> | ||||
| </div> | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										954
									
								
								public/vendor/pdfjs/test/test.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										954
									
								
								public/vendor/pdfjs/test/test.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,954 @@ | ||||
| # 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. | ||||
| 
 | ||||
| import json, platform, os, shutil, sys, subprocess, tempfile, threading | ||||
| import time, urllib, urllib2, hashlib, re, base64, uuid, socket, errno | ||||
| import traceback | ||||
| from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer | ||||
| from SocketServer import ThreadingMixIn | ||||
| from optparse import OptionParser | ||||
| from urlparse import urlparse, parse_qs | ||||
| from threading import Lock | ||||
| 
 | ||||
| USAGE_EXAMPLE = "%prog" | ||||
| 
 | ||||
| # The local web server uses the git repo as the document root. | ||||
| DOC_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__),"..")) | ||||
| 
 | ||||
| GIT_CLONE_CHECK = True | ||||
| DEFAULT_MANIFEST_FILE = 'test_manifest.json' | ||||
| EQLOG_FILE = 'eq.log' | ||||
| BROWSERLOG_FILE = 'browser.log' | ||||
| REFDIR = 'ref' | ||||
| TEST_SNAPSHOTS = 'test_snapshots' | ||||
| TMPDIR = 'tmp' | ||||
| VERBOSE = False | ||||
| BROWSER_TIMEOUT = 120 | ||||
| 
 | ||||
| SERVER_HOST = "localhost" | ||||
| 
 | ||||
| lock = Lock() | ||||
| 
 | ||||
| class TestOptions(OptionParser): | ||||
|     def __init__(self, **kwargs): | ||||
|         OptionParser.__init__(self, **kwargs) | ||||
|         self.add_option("-m", "--masterMode", action="store_true", dest="masterMode", | ||||
|                         help="Run the script in master mode.", default=False) | ||||
|         self.add_option("--noPrompts", action="store_true", dest="noPrompts", | ||||
|                         help="Uses default answers (intended for CLOUD TESTS only!).", default=False) | ||||
|         self.add_option("--manifestFile", action="store", type="string", dest="manifestFile", | ||||
|                         help="A JSON file in the form of test_manifest.json (the default).") | ||||
|         self.add_option("-b", "--browser", action="store", type="string", dest="browser", | ||||
|                         help="The path to a single browser (right now, only Firefox is supported).") | ||||
|         self.add_option("--browserManifestFile", action="store", type="string", | ||||
|                         dest="browserManifestFile", | ||||
|                         help="A JSON file in the form of those found in resources/browser_manifests") | ||||
|         self.add_option("--reftest", action="store_true", dest="reftest", | ||||
|                         help="Automatically start reftest showing comparison test failures, if there are any.", | ||||
|                         default=False) | ||||
|         self.add_option("--port", action="store", dest="port", type="int", | ||||
|                         help="The port the HTTP server should listen on.", default=8080) | ||||
|         self.add_option("--unitTest", action="store_true", dest="unitTest", | ||||
|                         help="Run the unit tests.", default=False) | ||||
|         self.add_option("--fontTest", action="store_true", dest="fontTest", | ||||
|                         help="Run the font tests.", default=False) | ||||
|         self.add_option("--noDownload", action="store_true", dest="noDownload", | ||||
|                         help="Skips test PDFs downloading.", default=False) | ||||
|         self.add_option("--statsFile", action="store", dest="statsFile", type="string", | ||||
|                         help="The file where to store stats.", default=None) | ||||
|         self.add_option("--statsDelay", action="store", dest="statsDelay", type="int", | ||||
|                         help="The amount of time in milliseconds the browser should wait before starting stats.", default=10000) | ||||
|         self.set_usage(USAGE_EXAMPLE) | ||||
| 
 | ||||
|     def verifyOptions(self, options): | ||||
|         if options.reftest and (options.unitTest or options.fontTest): | ||||
|             self.error("--reftest and --unitTest/--fontTest must not be specified at the same time.") | ||||
|         if options.masterMode and options.manifestFile: | ||||
|             self.error("--masterMode and --manifestFile must not be specified at the same time.") | ||||
|         if not options.manifestFile: | ||||
|             options.manifestFile = DEFAULT_MANIFEST_FILE | ||||
|         if options.browser and options.browserManifestFile: | ||||
|             print "Warning: ignoring browser argument since manifest file was also supplied" | ||||
|         if not options.browser and not options.browserManifestFile: | ||||
|             print "Starting server on port %s." % options.port | ||||
|         if not options.statsFile: | ||||
|             options.statsDelay = 0 | ||||
| 
 | ||||
|         return options | ||||
|          | ||||
| 
 | ||||
| def prompt(question): | ||||
|     '''Return True iff the user answered "yes" to |question|.''' | ||||
|     inp = raw_input(question +' [yes/no] > ') | ||||
|     return inp == 'yes' | ||||
| 
 | ||||
| MIMEs = { | ||||
|     '.css': 'text/css', | ||||
|     '.html': 'text/html', | ||||
|     '.js': 'application/javascript', | ||||
|     '.json': 'application/json', | ||||
|     '.svg': 'image/svg+xml', | ||||
|     '.pdf': 'application/pdf', | ||||
|     '.xhtml': 'application/xhtml+xml', | ||||
|     '.gif': 'image/gif', | ||||
|     '.ico': 'image/x-icon', | ||||
|     '.png': 'image/png', | ||||
|     '.log': 'text/plain', | ||||
|     '.properties': 'text/plain' | ||||
| } | ||||
| 
 | ||||
| class State: | ||||
|     browsers = [ ] | ||||
|     manifest = { } | ||||
|     taskResults = { } | ||||
|     remaining = { } | ||||
|     results = { } | ||||
|     done = False | ||||
|     numErrors = 0 | ||||
|     numEqFailures = 0 | ||||
|     numEqNoSnapshot = 0 | ||||
|     numFBFFailures = 0 | ||||
|     numLoadFailures = 0 | ||||
|     eqLog = None | ||||
|     saveStats = False | ||||
|     stats = [ ] | ||||
|     lastPost = { } | ||||
| 
 | ||||
| class UnitTestState: | ||||
|     browsers = [ ] | ||||
|     browsersRunning = 0 | ||||
|     lastPost = { } | ||||
|     numErrors = 0 | ||||
|     numRun = 0 | ||||
| 
 | ||||
| class Result: | ||||
|     def __init__(self, snapshot, failure, page): | ||||
|         self.snapshot = snapshot | ||||
|         self.failure = failure | ||||
|         self.page = page | ||||
| 
 | ||||
| class TestServer(ThreadingMixIn, HTTPServer): | ||||
|     pass | ||||
| 
 | ||||
| class TestHandlerBase(BaseHTTPRequestHandler): | ||||
|     # Disable annoying noise by default | ||||
|     def log_request(code=0, size=0): | ||||
|         if VERBOSE: | ||||
|             BaseHTTPRequestHandler.log_request(code, size) | ||||
| 
 | ||||
|     def handle_one_request(self): | ||||
|         try: | ||||
|             BaseHTTPRequestHandler.handle_one_request(self) | ||||
|         except socket.error, v: | ||||
|             if v[0] == errno.ECONNRESET: | ||||
|                 # Ignoring connection reset by peer exceptions | ||||
|                 if VERBOSE: | ||||
|                     print 'Detected connection reset' | ||||
|             elif v[0] == errno.EPIPE: | ||||
|                 if VERBOSE: | ||||
|                     print 'Detected remote peer disconnected' | ||||
|             elif v[0] == 10053: | ||||
|                 if VERBOSE: | ||||
|                     print 'An established connection was aborted by the' \ | ||||
|                           ' software in your host machine' | ||||
|             else: | ||||
|                 raise | ||||
| 
 | ||||
|     def finish(self,*args,**kw): | ||||
|         # From http://stackoverflow.com/a/14355079/1834797 | ||||
|         try: | ||||
|             if not self.wfile.closed: | ||||
|                 self.wfile.flush() | ||||
|                 self.wfile.close() | ||||
|         except socket.error: | ||||
|             pass | ||||
|         self.rfile.close() | ||||
| 
 | ||||
|     def sendFile(self, path, ext): | ||||
|         self.send_response(200) | ||||
|         self.send_header("Accept-Ranges", "bytes") | ||||
|         self.send_header("Content-Type", MIMEs[ext]) | ||||
|         self.send_header("Content-Length", os.path.getsize(path)) | ||||
|         self.end_headers() | ||||
|         with open(path, "rb") as f: | ||||
|             self.wfile.write(f.read()) | ||||
| 
 | ||||
|     def sendFileRange(self, path, ext, start, end): | ||||
|         file_len = os.path.getsize(path) | ||||
|         if (end is None) or (file_len < end): | ||||
|           end = file_len | ||||
|         if (file_len < start) or (end <= start): | ||||
|           self.send_error(416) | ||||
|           return | ||||
|         chunk_len = end - start | ||||
|         time.sleep(chunk_len / 1000000.0) | ||||
|         self.send_response(206) | ||||
|         self.send_header("Accept-Ranges", "bytes") | ||||
|         self.send_header("Content-Type", MIMEs[ext]) | ||||
|         self.send_header("Content-Length", chunk_len) | ||||
|         self.send_header("Content-Range", 'bytes ' + str(start) + '-' + str(end - 1) + '/' + str(file_len)) | ||||
|         self.end_headers() | ||||
|         with open(path, "rb") as f: | ||||
|             f.seek(start) | ||||
|             self.wfile.write(f.read(chunk_len)) | ||||
| 
 | ||||
|     def do_GET(self): | ||||
|         url = urlparse(self.path) | ||||
| 
 | ||||
|         # Ignore query string | ||||
|         path, _ = urllib.unquote_plus(url.path), url.query | ||||
|         path = os.path.abspath(os.path.realpath(DOC_ROOT + os.sep + path)) | ||||
|         prefix = os.path.commonprefix(( path, DOC_ROOT )) | ||||
|         _, ext = os.path.splitext(path.lower()) | ||||
| 
 | ||||
|         if url.path == "/favicon.ico": | ||||
|             self.sendFile(os.path.join(DOC_ROOT, "test", "resources", "favicon.ico"), ext) | ||||
|             return | ||||
| 
 | ||||
|         if os.path.isdir(path): | ||||
|             self.sendIndex(url.path, url.query) | ||||
|             return | ||||
| 
 | ||||
|         if not (prefix == DOC_ROOT | ||||
|                 and os.path.isfile(path) | ||||
|                 and ext in MIMEs): | ||||
|             print path | ||||
|             self.send_error(404) | ||||
|             return | ||||
| 
 | ||||
|         if 'Range' in self.headers: | ||||
|             range_re = re.compile(r"^bytes=(\d+)\-(\d+)?") | ||||
|             parsed_range = range_re.search(self.headers.getheader("Range")) | ||||
|             if parsed_range is None: | ||||
|                 self.send_error(501) | ||||
|                 return | ||||
|             if VERBOSE: | ||||
|                 print 'Range requested %s - %s: %s' % ( | ||||
|                     parsed_range.group(1), parsed_range.group(2)) | ||||
|             start = int(parsed_range.group(1)) | ||||
|             if parsed_range.group(2) is None: | ||||
|                 self.sendFileRange(path, ext, start, None) | ||||
|             else: | ||||
|                 end = int(parsed_range.group(2)) + 1 | ||||
|                 self.sendFileRange(path, ext, start, end) | ||||
|             return | ||||
| 
 | ||||
|         self.sendFile(path, ext) | ||||
| 
 | ||||
| class UnitTestHandler(TestHandlerBase): | ||||
|     def sendIndex(self, path, query): | ||||
|         print "send index" | ||||
| 
 | ||||
|     def translateFont(self, base64Data): | ||||
|         self.send_response(200) | ||||
|         self.send_header("Content-Type", "text/xml") | ||||
|         self.end_headers() | ||||
| 
 | ||||
|         data = base64.b64decode(base64Data) | ||||
|         taskId = str(uuid.uuid4()) | ||||
|         fontPath = 'ttx/' + taskId + '.otf' | ||||
|         resultPath = 'ttx/' + taskId + '.ttx' | ||||
|         with open(fontPath, "wb") as f: | ||||
|             f.write(data) | ||||
| 
 | ||||
|         # When fontTools used directly, we need to snif ttx file | ||||
|         # to check what version of python is used | ||||
|         ttxPath = '' | ||||
|         for path in os.environ["PATH"].split(os.pathsep): | ||||
|             if os.path.isfile(path + os.sep + "ttx"): | ||||
|                 ttxPath = path + os.sep + "ttx" | ||||
|                 break | ||||
|         if ttxPath == '': | ||||
|             self.wfile.write("<error>TTX was not found</error>") | ||||
|             return | ||||
| 
 | ||||
|         ttxRunner = '' | ||||
|         with open(ttxPath, "r") as f: | ||||
|             firstLine = f.readline() | ||||
|             if firstLine[:2] == '#!' and firstLine.find('python') > -1: | ||||
|               ttxRunner = firstLine[2:].strip() | ||||
| 
 | ||||
|         with open(os.devnull, "w") as fnull: | ||||
|             if ttxRunner != '': | ||||
|                 result = subprocess.call([ttxRunner, ttxPath, fontPath], stdout = fnull) | ||||
|             else: | ||||
|                 result = subprocess.call([ttxPath, fontPath], stdout = fnull) | ||||
| 
 | ||||
|         os.remove(fontPath) | ||||
| 
 | ||||
|         if not os.path.isfile(resultPath): | ||||
|             self.wfile.write("<error>Output was not generated</error>") | ||||
|             return | ||||
| 
 | ||||
|         with open(resultPath, "rb") as f: | ||||
|             self.wfile.write(f.read()) | ||||
| 
 | ||||
|         os.remove(resultPath) | ||||
| 
 | ||||
|         return | ||||
| 
 | ||||
|     def do_POST(self): | ||||
|         with lock: | ||||
|             url = urlparse(self.path) | ||||
|             numBytes = int(self.headers['Content-Length']) | ||||
|             content = self.rfile.read(numBytes) | ||||
| 
 | ||||
|             # Process special utility requests | ||||
|             if url.path == '/ttx': | ||||
|                 self.translateFont(content) | ||||
|                 return | ||||
| 
 | ||||
|             self.send_response(200) | ||||
|             self.send_header('Content-Type', 'text/plain') | ||||
|             self.end_headers() | ||||
| 
 | ||||
|             result = json.loads(content) | ||||
|             browser = result['browser'] | ||||
|             UnitTestState.lastPost[browser] = int(time.time()) | ||||
|             if url.path == "/tellMeToQuit": | ||||
|                 tellAppToQuit(url.path, url.query) | ||||
|                 UnitTestState.browsersRunning -= 1 | ||||
|                 UnitTestState.lastPost[browser] = None | ||||
|                 return | ||||
|             elif url.path == '/info': | ||||
|                 print result['message'] | ||||
|             elif url.path == '/submit_task_results': | ||||
|                 status, description = result['status'], result['description'] | ||||
|                 UnitTestState.numRun += 1 | ||||
|                 if status == 'TEST-UNEXPECTED-FAIL': | ||||
|                     UnitTestState.numErrors += 1 | ||||
|                 message = status + ' | ' + description + ' | in ' + browser | ||||
|                 if 'error' in result: | ||||
|                     message += ' | ' + result['error'] | ||||
|                 print message | ||||
|             else: | ||||
|                 print 'Error: uknown action' + url.path | ||||
| 
 | ||||
| class PDFTestHandler(TestHandlerBase): | ||||
| 
 | ||||
|     def sendIndex(self, path, query): | ||||
|         if not path.endswith("/"): | ||||
|           # we need trailing slash | ||||
|           self.send_response(301) | ||||
|           redirectLocation = path + "/" | ||||
|           if query: | ||||
|             redirectLocation += "?" + query | ||||
|           self.send_header("Location",  redirectLocation) | ||||
|           self.end_headers() | ||||
|           return | ||||
| 
 | ||||
|         self.send_response(200) | ||||
|         self.send_header("Content-Type", "text/html") | ||||
|         self.end_headers() | ||||
|         if query == "frame": | ||||
|           self.wfile.write("<html><frameset cols=*,200><frame name=pdf>" + | ||||
|             "<frame src='" + path + "'></frameset></html>") | ||||
|           return | ||||
| 
 | ||||
|         location = os.path.abspath(os.path.realpath(DOC_ROOT + os.sep + path)) | ||||
|         self.wfile.write("<html><body><h1>PDFs of " + path + "</h1>\n") | ||||
|         for filename in os.listdir(location): | ||||
|           if filename.lower().endswith('.pdf'): | ||||
|             self.wfile.write("<a href='/web/viewer.html?file=" + | ||||
|               urllib.quote_plus(path + filename, '/') + "' target=pdf>" + | ||||
|               filename + "</a><br>\n") | ||||
|         self.wfile.write("</body></html>") | ||||
| 
 | ||||
| 
 | ||||
|     def do_POST(self): | ||||
|         with lock: | ||||
|             numBytes = int(self.headers['Content-Length']) | ||||
| 
 | ||||
|             self.send_response(200) | ||||
|             self.send_header('Content-Type', 'text/plain') | ||||
|             self.end_headers() | ||||
| 
 | ||||
|             url = urlparse(self.path) | ||||
|             if url.path == "/tellMeToQuit": | ||||
|                 tellAppToQuit(url.path, url.query) | ||||
|                 return | ||||
| 
 | ||||
|             result = json.loads(self.rfile.read(numBytes)) | ||||
|             browser = result['browser'] | ||||
|             State.lastPost[browser] = int(time.time()) | ||||
|             if url.path == "/info": | ||||
|                 print result['message'] | ||||
|                 return | ||||
| 
 | ||||
|             id = result['id'] | ||||
|             failure = result['failure'] | ||||
|             round = result['round'] | ||||
|             page = result['page'] | ||||
|             snapshot = result['snapshot'] | ||||
| 
 | ||||
|             taskResults = State.taskResults[browser][id] | ||||
|             taskResults[round].append(Result(snapshot, failure, page)) | ||||
|             if State.saveStats: | ||||
|                 stat = { | ||||
|                     'browser': browser, | ||||
|                     'pdf': id, | ||||
|                     'page': page, | ||||
|                     'round': round, | ||||
|                     'stats': result['stats'] | ||||
|                 } | ||||
|                 State.stats.append(stat) | ||||
| 
 | ||||
|             def isTaskDone(): | ||||
|                 last_page_num = result['lastPageNum'] | ||||
|                 rounds = State.manifest[id]['rounds'] | ||||
|                 for round in range(0,rounds): | ||||
|                     if not taskResults[round]: | ||||
|                         return False | ||||
|                     latest_page = taskResults[round][-1] | ||||
|                     if not latest_page.page == last_page_num: | ||||
|                         return False | ||||
|                 return True | ||||
| 
 | ||||
|             if isTaskDone(): | ||||
|                 # sort the results since they sometimes come in out of order | ||||
|                 for results in taskResults: | ||||
|                     results.sort(key=lambda result: result.page) | ||||
|                 check(State.manifest[id], taskResults, browser, | ||||
|                     self.server.masterMode) | ||||
|                 # Please oh please GC this ... | ||||
|                 del State.taskResults[browser][id] | ||||
|                 State.remaining[browser] -= 1 | ||||
| 
 | ||||
|                 checkIfDone() | ||||
| 
 | ||||
| def checkIfDone(): | ||||
|     State.done = True | ||||
|     for key in State.remaining: | ||||
|         if State.remaining[key] != 0: | ||||
|             State.done = False | ||||
|             return | ||||
| 
 | ||||
| # Applescript hack to quit Chrome on Mac | ||||
| def tellAppToQuit(path, query): | ||||
|     if platform.system() != "Darwin": | ||||
|         return | ||||
|     d = parse_qs(query) | ||||
|     path = d['path'][0] | ||||
|     cmd = """osascript<<END | ||||
| tell application "%s" | ||||
| quit | ||||
| end tell | ||||
| END""" % path | ||||
|     os.system(cmd) | ||||
| 
 | ||||
| class BaseBrowserCommand(object): | ||||
|     def __init__(self, browserRecord): | ||||
|         self.name = browserRecord["name"] | ||||
|         self.path = browserRecord["path"] | ||||
|         self.tempDir = None | ||||
|         self.process = None | ||||
| 
 | ||||
|         if platform.system() == "Darwin" and (self.path.endswith(".app") or self.path.endswith(".app/")): | ||||
|             self._fixupMacPath() | ||||
| 
 | ||||
|         if not os.path.exists(self.path): | ||||
|             raise Exception("Path to browser '%s' does not exist." % self.path) | ||||
| 
 | ||||
|     def setup(self): | ||||
|         self.tempDir = tempfile.mkdtemp() | ||||
|         self.profileDir = os.path.join(self.tempDir, "profile") | ||||
|         self.browserLog = open(BROWSERLOG_FILE, "w") | ||||
| 
 | ||||
|     def teardown(self): | ||||
|         self.process.terminate() | ||||
| 
 | ||||
|         # If the browser is still running, wait up to ten seconds for it to quit | ||||
|         if self.process and self.process.poll() is None: | ||||
|             checks = 0 | ||||
|             while self.process.poll() is None and checks < 20: | ||||
|                 checks += 1 | ||||
|                 time.sleep(.5) | ||||
|             # If it's still not dead, try to kill it | ||||
|             if self.process.poll() is None: | ||||
|                 print "Process %s is still running. Killing." % self.name | ||||
|                 self.process.kill() | ||||
|                 self.process.wait() | ||||
|              | ||||
|         if self.tempDir is not None and os.path.exists(self.tempDir): | ||||
|             shutil.rmtree(self.tempDir) | ||||
| 
 | ||||
|         self.browserLog.close() | ||||
| 
 | ||||
|     def start(self, url): | ||||
|         raise Exception("Can't start BaseBrowserCommand") | ||||
| 
 | ||||
| class FirefoxBrowserCommand(BaseBrowserCommand): | ||||
|     def _fixupMacPath(self): | ||||
|         self.path = os.path.join(self.path, "Contents", "MacOS", "firefox-bin") | ||||
| 
 | ||||
|     def setup(self): | ||||
|         super(FirefoxBrowserCommand, self).setup() | ||||
|         shutil.copytree(os.path.join(DOC_ROOT, "test", "resources", "firefox"), | ||||
|                         self.profileDir) | ||||
| 
 | ||||
|     def start(self, url): | ||||
|         cmds = [self.path] | ||||
|         if platform.system() == "Darwin": | ||||
|             cmds.append("-foreground") | ||||
|         cmds.extend(["-no-remote", "-profile", self.profileDir, url]) | ||||
|         self.process = subprocess.Popen(cmds, stdout = self.browserLog, stderr = self.browserLog) | ||||
| 
 | ||||
| class ChromeBrowserCommand(BaseBrowserCommand): | ||||
|     def _fixupMacPath(self): | ||||
|         self.path = os.path.join(self.path, "Contents", "MacOS", "Google Chrome") | ||||
| 
 | ||||
|     def start(self, url): | ||||
|         cmds = [self.path] | ||||
|         cmds.extend(["--user-data-dir=%s" % self.profileDir, | ||||
|                      "--no-first-run", "--disable-sync", url]) | ||||
|         self.process = subprocess.Popen(cmds, stdout = self.browserLog, stderr = self.browserLog) | ||||
| 
 | ||||
| def makeBrowserCommand(browser): | ||||
|     path = browser["path"].lower() | ||||
|     name = browser["name"] | ||||
|     if name is not None: | ||||
|         name = name.lower() | ||||
| 
 | ||||
|     types = {"firefox": FirefoxBrowserCommand, | ||||
|              "chrome": ChromeBrowserCommand } | ||||
|     command = None | ||||
|     for key in types.keys(): | ||||
|         if (name and name.find(key) > -1) or path.find(key) > -1: | ||||
|             command = types[key](browser) | ||||
|             command.name = command.name or key | ||||
|             break | ||||
| 
 | ||||
|     if command is None: | ||||
|         raise Exception("Unrecognized browser: %s" % browser) | ||||
| 
 | ||||
|     return command  | ||||
| 
 | ||||
| def makeBrowserCommands(browserManifestFile): | ||||
|     with open(browserManifestFile) as bmf: | ||||
|         browsers = [makeBrowserCommand(browser) for browser in json.load(bmf)] | ||||
|     return browsers | ||||
| 
 | ||||
| def downloadLinkedPDF(f): | ||||
|     linkFile = open(f +'.link') | ||||
|     link = linkFile.read() | ||||
|     linkFile.close() | ||||
| 
 | ||||
|     sys.stdout.write('Downloading '+ link +' to '+ f +' ...') | ||||
|     sys.stdout.flush() | ||||
|     response = urllib2.urlopen(link) | ||||
| 
 | ||||
|     with open(f, 'wb') as out: | ||||
|         out.write(response.read()) | ||||
| 
 | ||||
|     print 'done' | ||||
| 
 | ||||
| def downloadLinkedPDFs(manifestList): | ||||
|     for item in manifestList: | ||||
|         f, isLink = item['file'], item.get('link', False) | ||||
|         if isLink and not os.access(f, os.R_OK): | ||||
|             try: | ||||
|                 downloadLinkedPDF(f) | ||||
|             except: | ||||
|                 exc_type, exc_value, exc_traceback = sys.exc_info() | ||||
|                 print 'ERROR: Unable to download file "' + f + '".' | ||||
|                 open(f, 'wb').close() | ||||
|                 with open(f + '.error', 'w') as out: | ||||
|                   out.write('\n'.join(traceback.format_exception(exc_type, | ||||
|                                                                  exc_value, | ||||
|                                                                  exc_traceback))) | ||||
| 
 | ||||
| def verifyPDFs(manifestList): | ||||
|     error = False | ||||
|     for item in manifestList: | ||||
|         f = item['file'] | ||||
|         if os.path.isfile(f + '.error'): | ||||
|             print 'WARNING: File was not downloaded. See "' + f + '.error" file.' | ||||
|             error = True | ||||
|         elif os.access(f, os.R_OK): | ||||
|             fileMd5 = hashlib.md5(open(f, 'rb').read()).hexdigest() | ||||
|             if 'md5' not in item: | ||||
|                 print 'WARNING: Missing md5 for file "' + f + '".', | ||||
|                 print 'Hash for current file is "' + fileMd5 + '"' | ||||
|                 error = True | ||||
|                 continue | ||||
|             md5 = item['md5'] | ||||
|             if fileMd5 != md5: | ||||
|                 print 'WARNING: MD5 of file "' + f + '" does not match file.', | ||||
|                 print 'Expected "' + md5 + '" computed "' + fileMd5 + '"' | ||||
|                 error = True | ||||
|                 continue | ||||
|         else: | ||||
|             print 'WARNING: Unable to open file for reading "' + f + '".' | ||||
|             error = True | ||||
|     return not error | ||||
| 
 | ||||
| def getTestBrowsers(options): | ||||
|     testBrowsers = [] | ||||
|     if options.browserManifestFile: | ||||
|         testBrowsers = makeBrowserCommands(options.browserManifestFile) | ||||
|     elif options.browser: | ||||
|         testBrowsers = [makeBrowserCommand({"path":options.browser, "name":None})] | ||||
| 
 | ||||
|     if options.browserManifestFile or options.browser: | ||||
|         assert len(testBrowsers) > 0 | ||||
|     return testBrowsers | ||||
| 
 | ||||
| def setUp(options): | ||||
|     # Only serve files from a pdf.js clone | ||||
|     assert not GIT_CLONE_CHECK or os.path.isfile('../src/pdf.js') and os.path.isdir('../.git') | ||||
| 
 | ||||
|     if options.masterMode and os.path.isdir(TMPDIR): | ||||
|         print 'Temporary snapshot dir tmp/ is still around.' | ||||
|         print 'tmp/ can be removed if it has nothing you need.' | ||||
|         if options.noPrompts or prompt('SHOULD THIS SCRIPT REMOVE tmp/?  THINK CAREFULLY'): | ||||
|             subprocess.call(( 'rm', '-rf', 'tmp' )) | ||||
| 
 | ||||
|     assert not os.path.isdir(TMPDIR) | ||||
| 
 | ||||
|     testBrowsers = getTestBrowsers(options) | ||||
| 
 | ||||
|     with open(options.manifestFile) as mf: | ||||
|         manifestList = json.load(mf) | ||||
| 
 | ||||
|     if not options.noDownload: | ||||
|         downloadLinkedPDFs(manifestList) | ||||
| 
 | ||||
|         if not verifyPDFs(manifestList): | ||||
|           print 'Unable to verify the checksum for the files that are used for testing.' | ||||
|           print 'Please re-download the files, or adjust the MD5 checksum in the manifest for the files listed above.\n' | ||||
| 
 | ||||
|     for b in testBrowsers: | ||||
|         State.taskResults[b.name] = { } | ||||
|         State.remaining[b.name] = len(manifestList) | ||||
|         State.lastPost[b.name] = int(time.time()) | ||||
|         for item in manifestList: | ||||
|             id, rounds = item['id'], int(item['rounds']) | ||||
|             State.manifest[id] = item | ||||
|             taskResults = [ ] | ||||
|             for r in xrange(rounds): | ||||
|                 taskResults.append([ ]) | ||||
|             State.taskResults[b.name][id] = taskResults | ||||
| 
 | ||||
|     if options.statsFile != None: | ||||
|         State.saveStats = True | ||||
|     return testBrowsers | ||||
| 
 | ||||
| def setUpUnitTests(options): | ||||
|     # Only serve files from a pdf.js clone | ||||
|     assert not GIT_CLONE_CHECK or os.path.isfile('../src/pdf.js') and os.path.isdir('../.git') | ||||
| 
 | ||||
|     testBrowsers = getTestBrowsers(options) | ||||
| 
 | ||||
|     UnitTestState.browsersRunning = len(testBrowsers) | ||||
|     for b in testBrowsers: | ||||
|         UnitTestState.lastPost[b.name] = int(time.time()) | ||||
|     return testBrowsers | ||||
| 
 | ||||
| def startBrowsers(browsers, options, path): | ||||
|     for b in browsers: | ||||
|         b.setup() | ||||
|         print 'Launching', b.name | ||||
|         host = 'http://%s:%s' % (SERVER_HOST, options.port)  | ||||
|         qs = '?browser='+ urllib.quote(b.name) +'&manifestFile='+ urllib.quote(options.manifestFile) | ||||
|         qs += '&path=' + b.path | ||||
|         qs += '&delay=' + str(options.statsDelay) | ||||
|         qs += '&masterMode=' + str(options.masterMode) | ||||
|         b.start(host + path + qs) | ||||
| 
 | ||||
| def teardownBrowsers(browsers): | ||||
|     for b in browsers: | ||||
|         try: | ||||
|             b.teardown() | ||||
|         except: | ||||
|             print "Error cleaning up after browser at ", b.path | ||||
|             print "Temp dir was ", b.tempDir | ||||
|             print "Error:", sys.exc_info()[0] | ||||
| 
 | ||||
| def check(task, results, browser, masterMode): | ||||
|     failed = False | ||||
|     for r in xrange(len(results)): | ||||
|         pageResults = results[r] | ||||
|         for p in xrange(len(pageResults)): | ||||
|             pageResult = pageResults[p] | ||||
|             if pageResult is None: | ||||
|                 continue | ||||
|             failure = pageResult.failure | ||||
|             if failure: | ||||
|                 failed = True | ||||
|                 if os.path.isfile(task['file'] + '.error'): | ||||
|                   print 'TEST-SKIPPED | PDF was not downloaded', task['id'], '| in', browser, '| page', p + 1, 'round', r, '|', failure | ||||
|                 else: | ||||
|                   State.numErrors += 1 | ||||
|                   print 'TEST-UNEXPECTED-FAIL | test failed', task['id'], '| in', browser, '| page', p + 1, 'round', r, '|', failure | ||||
| 
 | ||||
|     if failed: | ||||
|         return | ||||
| 
 | ||||
|     kind = task['type'] | ||||
|     if 'eq' == kind or 'text' == kind: | ||||
|         checkEq(task, results, browser, masterMode) | ||||
|     elif 'fbf' == kind: | ||||
|         checkFBF(task, results, browser) | ||||
|     elif 'load' == kind: | ||||
|         checkLoad(task, results, browser) | ||||
|     else: | ||||
|         assert 0 and 'Unknown test type' | ||||
| 
 | ||||
| def createDir(dir): | ||||
|     try: | ||||
|         os.makedirs(dir) | ||||
|     except OSError, e: | ||||
|         if e.errno != 17: # file exists | ||||
|             print >>sys.stderr, 'Creating', dir, 'failed!' | ||||
| 
 | ||||
| 
 | ||||
| def readDataUri(data): | ||||
|     metadata, encoded = data.rsplit(",", 1) | ||||
|     return base64.b64decode(encoded) | ||||
| 
 | ||||
| def checkEq(task, results, browser, masterMode): | ||||
|     pfx = os.path.join(REFDIR, sys.platform, browser, task['id']) | ||||
|     testSnapshotDir = os.path.join(TEST_SNAPSHOTS, sys.platform, browser, task['id']) | ||||
|     results = results[0] | ||||
|     taskId = task['id'] | ||||
|     taskType = task['type'] | ||||
| 
 | ||||
|     passed = True | ||||
|     for result in results: | ||||
|         page = result.page | ||||
|         snapshot = readDataUri(result.snapshot) | ||||
|         ref = None | ||||
|         eq = True | ||||
| 
 | ||||
|         path = os.path.join(pfx, str(page) + '.png') | ||||
|         if not os.access(path, os.R_OK): | ||||
|             State.numEqNoSnapshot += 1 | ||||
|             if not masterMode: | ||||
|                 print 'WARNING: no reference snapshot', path | ||||
|         else: | ||||
|             f = open(path, 'rb') | ||||
|             ref = f.read() | ||||
|             f.close() | ||||
| 
 | ||||
|             eq = (ref == snapshot) | ||||
|             if not eq: | ||||
|                 print 'TEST-UNEXPECTED-FAIL |', taskType, taskId, '| in', browser, '| rendering of page', page, '!= reference rendering' | ||||
| 
 | ||||
|                 if not State.eqLog: | ||||
|                     State.eqLog = open(EQLOG_FILE, 'w') | ||||
|                 eqLog = State.eqLog | ||||
| 
 | ||||
|                 createDir(testSnapshotDir) | ||||
|                 testSnapshotPath = os.path.join(testSnapshotDir, str(page) + '.png') | ||||
|                 handle = open(testSnapshotPath, 'wb') | ||||
|                 handle.write(snapshot) | ||||
|                 handle.close() | ||||
| 
 | ||||
|                 refSnapshotPath = os.path.join(testSnapshotDir, str(page) + '_ref.png') | ||||
|                 handle = open(refSnapshotPath, 'wb') | ||||
|                 handle.write(ref) | ||||
|                 handle.close() | ||||
| 
 | ||||
|                 # NB: this follows the format of Mozilla reftest | ||||
|                 # output so that we can reuse its reftest-analyzer | ||||
|                 # script | ||||
|                 eqLog.write('REFTEST TEST-UNEXPECTED-FAIL | ' + browser +'-'+ taskId +'-page'+ str(page) + ' | image comparison (==)\n') | ||||
|                 eqLog.write('REFTEST   IMAGE 1 (TEST): ' + testSnapshotPath + '\n') | ||||
|                 eqLog.write('REFTEST   IMAGE 2 (REFERENCE): ' + refSnapshotPath + '\n') | ||||
| 
 | ||||
|                 passed = False | ||||
|                 State.numEqFailures += 1 | ||||
| 
 | ||||
|         if masterMode and (ref is None or not eq): | ||||
|             tmpTaskDir = os.path.join(TMPDIR, sys.platform, browser, task['id']) | ||||
|             createDir(tmpTaskDir) | ||||
| 
 | ||||
|             handle = open(os.path.join(tmpTaskDir, str(page)) + '.png', 'wb') | ||||
|             handle.write(snapshot) | ||||
|             handle.close() | ||||
| 
 | ||||
|     if passed: | ||||
|         print 'TEST-PASS |', taskType, 'test', task['id'], '| in', browser | ||||
| 
 | ||||
| def checkFBF(task, results, browser): | ||||
|     round0, round1 = results[0], results[1] | ||||
|     assert len(round0) == len(round1) | ||||
| 
 | ||||
|     passed = True | ||||
|     for page in xrange(len(round1)): | ||||
|         r0Page, r1Page = round0[page], round1[page] | ||||
|         if r0Page is None: | ||||
|             break | ||||
|         if r0Page.snapshot != r1Page.snapshot: | ||||
|             print 'TEST-UNEXPECTED-FAIL | forward-back-forward test', task['id'], '| in', browser, '| first rendering of page', page + 1, '!= second' | ||||
|             passed = False | ||||
|             State.numFBFFailures += 1 | ||||
|     if passed: | ||||
|         print 'TEST-PASS | forward-back-forward test', task['id'], '| in', browser | ||||
| 
 | ||||
| 
 | ||||
| def checkLoad(task, results, browser): | ||||
|     # Load just checks for absence of failure, so if we got here the | ||||
|     # test has passed | ||||
|     print 'TEST-PASS | load test', task['id'], '| in', browser | ||||
| 
 | ||||
| 
 | ||||
| def processResults(options): | ||||
|     print '' | ||||
|     numFatalFailures = (State.numErrors + State.numFBFFailures) | ||||
|     if 0 == State.numEqFailures and 0 == numFatalFailures: | ||||
|         print 'All regression tests passed.' | ||||
|     else: | ||||
|         print 'OHNOES!  Some tests failed!' | ||||
|         if 0 < State.numErrors: | ||||
|             print '  errors:', State.numErrors | ||||
|         if 0 < State.numEqFailures: | ||||
|             print '  different ref/snapshot:', State.numEqFailures | ||||
|         if 0 < State.numFBFFailures: | ||||
|             print '  different first/second rendering:', State.numFBFFailures | ||||
|     if options.statsFile != None: | ||||
|         with open(options.statsFile, 'w') as sf: | ||||
|             sf.write(json.dumps(State.stats, sort_keys=True, indent=4)) | ||||
|         print 'Wrote stats file: ' + options.statsFile | ||||
| 
 | ||||
| 
 | ||||
| def maybeUpdateRefImages(options, browser): | ||||
|     if options.masterMode and (0 < State.numEqFailures or 0 < State.numEqNoSnapshot):  | ||||
|         print "Some eq tests failed or didn't have snapshots." | ||||
|         print 'Checking to see if master references can be updated...' | ||||
|         numFatalFailures = (State.numErrors + State.numFBFFailures) | ||||
|         if 0 < numFatalFailures: | ||||
|             print '  No.  Some non-eq tests failed.' | ||||
|         else: | ||||
|             print '  Yes!  The references in tmp/ can be synced with ref/.' | ||||
|             if options.reftest:                                                                                                               | ||||
|                 startReftest(browser, options) | ||||
|             if options.noPrompts or prompt('Would you like to update the master copy in ref/?'): | ||||
|                 sys.stdout.write('  Updating ref/ ... ') | ||||
| 
 | ||||
|                 if not os.path.exists('ref'): | ||||
|                     subprocess.check_call('mkdir ref', shell = True) | ||||
|                 subprocess.check_call('cp -Rf tmp/* ref/', shell = True) | ||||
| 
 | ||||
|                 print 'done' | ||||
|             else: | ||||
|                 print '  OK, not updating.' | ||||
| 
 | ||||
| def startReftest(browser, options): | ||||
|     url = "http://%s:%s" % (SERVER_HOST, options.port) | ||||
|     url += "/test/resources/reftest-analyzer.xhtml" | ||||
|     url += "#web=/test/eq.log" | ||||
|     try: | ||||
|         browser.setup() | ||||
|         browser.start(url) | ||||
|         print "Waiting for browser..." | ||||
|         browser.process.wait() | ||||
|     finally: | ||||
|         teardownBrowsers([browser]) | ||||
|     print "Completed reftest usage." | ||||
| 
 | ||||
| def runTests(options, browsers): | ||||
|     try: | ||||
|         shutil.rmtree(TEST_SNAPSHOTS); | ||||
|     except OSError, e: | ||||
|         if e.errno != 2: # folder doesn't exist | ||||
|             print >>sys.stderr, 'Deleting', dir, 'failed!' | ||||
|     t1 = time.time() | ||||
|     try: | ||||
|         startBrowsers(browsers, options, '/test/test_slave.html') | ||||
|         while not State.done: | ||||
|             for b in State.lastPost: | ||||
|                 if State.remaining[b] > 0 and int(time.time()) - State.lastPost[b] > BROWSER_TIMEOUT: | ||||
|                     print 'TEST-UNEXPECTED-FAIL | test failed', b, "has not responded in", BROWSER_TIMEOUT, "s" | ||||
|                     State.numErrors += State.remaining[b] | ||||
|                     State.remaining[b] = 0 | ||||
|                     checkIfDone() | ||||
|             time.sleep(1) | ||||
|         processResults(options) | ||||
|     finally: | ||||
|         teardownBrowsers(browsers) | ||||
|     t2 = time.time() | ||||
|     print "Runtime was", int(t2 - t1), "seconds" | ||||
|     if State.eqLog: | ||||
|         State.eqLog.close(); | ||||
|     if options.masterMode: | ||||
|         maybeUpdateRefImages(options, browsers[0]) | ||||
|     elif options.reftest and State.numEqFailures > 0: | ||||
|         print "\nStarting reftest harness to examine %d eq test failures." % State.numEqFailures | ||||
|         startReftest(browsers[0], options) | ||||
| 
 | ||||
| def runUnitTests(options, browsers, url, name): | ||||
|     t1 = time.time() | ||||
|     try: | ||||
|         startBrowsers(browsers, options, url) | ||||
|         while UnitTestState.browsersRunning > 0: | ||||
|             for b in UnitTestState.lastPost: | ||||
|                 if UnitTestState.lastPost[b] != None and int(time.time()) - UnitTestState.lastPost[b] > BROWSER_TIMEOUT: | ||||
|                     print 'TEST-UNEXPECTED-FAIL | test failed', b, "has not responded in", BROWSER_TIMEOUT, "s" | ||||
|                     UnitTestState.lastPost[b] = None | ||||
|                     UnitTestState.browsersRunning -= 1 | ||||
|                     UnitTestState.numErrors += 1 | ||||
|             time.sleep(1) | ||||
|         print '' | ||||
|         print 'Ran', UnitTestState.numRun, 'tests' | ||||
|         if UnitTestState.numErrors > 0: | ||||
|             print 'OHNOES!  Some', name, 'tests failed!' | ||||
|             print '  ', UnitTestState.numErrors, 'of', UnitTestState.numRun, 'failed' | ||||
|         else: | ||||
|             print 'All', name, 'tests passed.' | ||||
|     finally: | ||||
|         teardownBrowsers(browsers) | ||||
|     t2 = time.time() | ||||
|     print '', name, 'tests runtime was', int(t2 - t1), 'seconds' | ||||
| 
 | ||||
| def main(): | ||||
|     optionParser = TestOptions() | ||||
|     options, args = optionParser.parse_args() | ||||
|     options = optionParser.verifyOptions(options) | ||||
|     if options == None: | ||||
|         sys.exit(1) | ||||
| 
 | ||||
|     if options.unitTest or options.fontTest: | ||||
|         httpd = TestServer((SERVER_HOST, options.port), UnitTestHandler) | ||||
|         httpd_thread = threading.Thread(target=httpd.serve_forever) | ||||
|         httpd_thread.setDaemon(True) | ||||
|         httpd_thread.start() | ||||
| 
 | ||||
|         browsers = setUpUnitTests(options) | ||||
|         if len(browsers) > 0: | ||||
|             if options.unitTest: | ||||
|               runUnitTests(options, browsers, '/test/unit/unit_test.html', 'unit') | ||||
|             if options.fontTest: | ||||
|               runUnitTests(options, browsers, '/test/font/font_test.html', 'font') | ||||
|     else: | ||||
|         httpd = TestServer((SERVER_HOST, options.port), PDFTestHandler) | ||||
|         httpd.masterMode = options.masterMode | ||||
|         httpd_thread = threading.Thread(target=httpd.serve_forever) | ||||
|         httpd_thread.setDaemon(True) | ||||
|         httpd_thread.start() | ||||
| 
 | ||||
|         browsers = setUp(options) | ||||
|         if len(browsers) > 0: | ||||
|             runTests(options, browsers) | ||||
|         else: | ||||
|             # just run the server | ||||
|             print "Running HTTP server. Press Ctrl-C to quit." | ||||
|             try: | ||||
|                 while True: | ||||
|                     time.sleep(1) | ||||
|             except (KeyboardInterrupt): | ||||
|                 print "\nExiting." | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
							
								
								
									
										
											BIN
										
									
								
								public/vendor/pdfjs/web/images/Thumbs.db
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/vendor/pdfjs/web/images/Thumbs.db
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										33
									
								
								public/vendor/sizzle/.bower.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								public/vendor/sizzle/.bower.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| { | ||||
|   "name": "sizzle", | ||||
|   "version": "1.10.16", | ||||
|   "main": "./dist/sizzle.js", | ||||
|   "devDependencies": { | ||||
|     "qunit": "~1.12.0", | ||||
|     "benchmark": "~1.0.0", | ||||
|     "requirejs": "~2.1.8", | ||||
|     "requirejs-domready": "~2.0.1", | ||||
|     "requirejs-text": "~2.0.10" | ||||
|   }, | ||||
|   "ignore": [ | ||||
|     "**/.*", | ||||
|     "package.json", | ||||
|     "bower.json", | ||||
|     "speed", | ||||
|     "Makefile", | ||||
|     "*.md", | ||||
|     "*.txt", | ||||
|     "src", | ||||
|     "Gruntfile.js" | ||||
|   ], | ||||
|   "homepage": "https://github.com/jquery/sizzle", | ||||
|   "_release": "1.10.16", | ||||
|   "_resolution": { | ||||
|     "type": "version", | ||||
|     "tag": "1.10.16", | ||||
|     "commit": "0fd151739d05648118002914c7a638411bbd0dbe" | ||||
|   }, | ||||
|   "_source": "git://github.com/jquery/sizzle.git", | ||||
|   "_target": "1.10.16", | ||||
|   "_originalSource": "sizzle" | ||||
| } | ||||
							
								
								
									
										2015
									
								
								public/vendor/sizzle/dist/sizzle.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2015
									
								
								public/vendor/sizzle/dist/sizzle.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3
									
								
								public/vendor/sizzle/dist/sizzle.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								public/vendor/sizzle/dist/sizzle.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/vendor/sizzle/dist/sizzle.min.map
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/vendor/sizzle/dist/sizzle.min.map
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										10
									
								
								public/vendor/sizzle/tasks/commit.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								public/vendor/sizzle/tasks/commit.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| var exec = require( "child_process" ).exec; | ||||
| 
 | ||||
| module.exports = function( grunt ) { | ||||
| 	grunt.registerTask( "commit", "Add and commit changes", function( message ) { | ||||
| 		// Always add dist directory
 | ||||
| 		exec( "git add dist && git commit -m " + message, this.async() ); | ||||
| 	}); | ||||
| }; | ||||
							
								
								
									
										34
									
								
								public/vendor/sizzle/tasks/compile.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								public/vendor/sizzle/tasks/compile.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| module.exports = function( grunt ) { | ||||
| 	grunt.registerMultiTask( | ||||
| 		"compile", | ||||
| 		"Compile sizzle.js to the dist directory. Embed date/version.", | ||||
| 		function() { | ||||
| 			var data = this.data, | ||||
| 				dest = data.dest, | ||||
| 				src = data.src, | ||||
| 				version = grunt.config( "pkg.version" ), | ||||
| 				compiled = grunt.file.read( src ); | ||||
| 
 | ||||
| 			// Embed version and date
 | ||||
| 			compiled = compiled | ||||
| 				.replace( /@VERSION/g, version ) | ||||
| 				.replace( "@DATE", function() { | ||||
| 					var date = new Date(); | ||||
| 
 | ||||
| 					// YYYY-MM-DD
 | ||||
| 					return [ | ||||
| 						date.getFullYear(), | ||||
| 						( "0" + ( date.getMonth() + 1 ) ).slice( -2 ), | ||||
| 						( "0" + date.getDate() ).slice( -2 ) | ||||
| 					].join( "-" ); | ||||
| 				}); | ||||
| 
 | ||||
| 			// Write source to file
 | ||||
| 			grunt.file.write( dest, compiled ); | ||||
| 
 | ||||
| 			grunt.log.ok( "File written to " + dest ); | ||||
| 		} | ||||
| 	); | ||||
| }; | ||||
							
								
								
									
										35
									
								
								public/vendor/sizzle/tasks/dist.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								public/vendor/sizzle/tasks/dist.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| var fs = require( "fs" ); | ||||
| 
 | ||||
| module.exports = function( grunt ) { | ||||
| 	grunt.registerTask( "dist", "Process files for distribution", function() { | ||||
| 		var files = grunt.file.expand( { filter: "isFile" }, "dist/*" ); | ||||
| 
 | ||||
| 		files.forEach(function( filename ) { | ||||
| 			var map, | ||||
| 				text = fs.readFileSync( filename, "utf8" ); | ||||
| 
 | ||||
| 			// Modify map/min so that it points to files in the same folder;
 | ||||
| 			// see https://github.com/mishoo/UglifyJS2/issues/47
 | ||||
| 			if ( /\.map$/.test( filename ) ) { | ||||
| 				text = text.replace( /"dist\//g, "\"" ); | ||||
| 				fs.writeFileSync( filename, text, "utf-8" ); | ||||
| 			} else if ( /\.min\.js$/.test( filename ) ) { | ||||
| 				// Wrap sourceMap directive in multiline comments (#13274)
 | ||||
| 				text = text.replace( /\n?(\/\/@\s*sourceMappingURL=)(.*)/, | ||||
| 					function( _, directive, path ) { | ||||
| 						map = "\n" + directive + path.replace( /^dist\//, "" ); | ||||
| 						return ""; | ||||
| 					}); | ||||
| 				if ( map ) { | ||||
| 					text = text.replace( /(^\/\*[\w\W]*?)\s*\*\/|$/, | ||||
| 						function( _, comment ) { | ||||
| 							return ( comment || "\n/*" ) + map + "\n*/"; | ||||
| 						}); | ||||
| 				} | ||||
| 				fs.writeFileSync( filename, text, "utf-8" ); | ||||
| 			} | ||||
| 		}); | ||||
| 	}); | ||||
| }; | ||||
							
								
								
									
										43
									
								
								public/vendor/sizzle/tasks/release.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								public/vendor/sizzle/tasks/release.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| var exec = require( "child_process" ).exec; | ||||
| 
 | ||||
| module.exports = function( grunt ) { | ||||
| 	var rpreversion = /(\d\.\d+\.\d+)-pre/; | ||||
| 
 | ||||
| 	grunt.registerTask( "release", | ||||
| 		"Release a version of sizzle, updates a pre version to released, " + | ||||
| 		"inserts `next` as the new pre version", function( next ) { | ||||
| 		 | ||||
| 		if ( !rpreversion.test( next ) ) { | ||||
| 			grunt.fatal( "Next version should be a -pre version (x.x.x-pre): " + next ); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		var done, | ||||
| 			version = grunt.config( "pkg.version" ); | ||||
| 		if ( !rpreversion.test( version ) ) { | ||||
| 			grunt.fatal( "Existing version is not a pre version: " + version ); | ||||
| 			return; | ||||
| 		} | ||||
| 		version = version.replace( rpreversion, "$1" ); | ||||
| 
 | ||||
| 		done = this.async(); | ||||
| 		exec( "git diff --quiet HEAD", function( err ) { | ||||
| 			if ( err ) { | ||||
| 				grunt.fatal( "The working directory should be clean when releasing. Commit or stash changes." ); | ||||
| 				return; | ||||
| 			} | ||||
| 			// Build to dist directories along with a map and tag the release
 | ||||
| 			grunt.task.run([ | ||||
| 				// Commit new version
 | ||||
| 				"version:" + version, | ||||
| 				// Tag new version
 | ||||
| 				"tag:" + version, | ||||
| 				// Commit next version
 | ||||
| 				"version:" + next | ||||
| 			]); | ||||
| 			done(); | ||||
| 		}); | ||||
| 	}); | ||||
| }; | ||||
							
								
								
									
										9
									
								
								public/vendor/sizzle/tasks/tag.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								public/vendor/sizzle/tasks/tag.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| var exec = require( "child_process" ).exec; | ||||
| 
 | ||||
| module.exports = function( grunt ) { | ||||
| 	grunt.registerTask( "tag", "Tag the specified version", function( version ) { | ||||
| 		exec( "git tag " + version, this.async() ); | ||||
| 	}); | ||||
| }; | ||||
							
								
								
									
										35
									
								
								public/vendor/sizzle/tasks/version.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								public/vendor/sizzle/tasks/version.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| "use strict"; | ||||
| 
 | ||||
| var exec = require( "child_process" ).exec; | ||||
| 
 | ||||
| module.exports = function( grunt ) { | ||||
| 	grunt.registerTask( "version", "Commit a new version", function( version ) { | ||||
| 		if ( !/\d\.\d+\.\d+(?:-pre)?/.test( version ) ) { | ||||
| 			grunt.fatal( "Version must follow semver release format: " + version ); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		var done = this.async(), | ||||
| 			files = grunt.config( "version.files" ), | ||||
| 			rversion = /("version":\s*")[^"]+/; | ||||
| 
 | ||||
| 		// Update version in specified files
 | ||||
| 		files.forEach(function( filename ) { | ||||
| 			var text = grunt.file.read( filename ); | ||||
| 			text = text.replace( rversion, "$1" + version ); | ||||
| 			grunt.file.write( filename, text ); | ||||
| 		}); | ||||
| 
 | ||||
| 		// Add files to git index
 | ||||
| 		exec( "git add -A", function( err ) { | ||||
| 			if ( err ) { | ||||
| 				grunt.fatal( err ); | ||||
| 				return; | ||||
| 			} | ||||
| 			// Commit next pre version
 | ||||
| 			grunt.config( "pkg.version", version ); | ||||
| 			grunt.task.run([ "build", "uglify", "dist", "commit:'Update version to " + version + "'" ]); | ||||
| 			done(); | ||||
| 		}); | ||||
| 	}); | ||||
| }; | ||||
							
								
								
									
										0
									
								
								public/vendor/sizzle/test/data/empty.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								public/vendor/sizzle/test/data/empty.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
									
										22
									
								
								public/vendor/sizzle/test/data/mixed_sort.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								public/vendor/sizzle/test/data/mixed_sort.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="en"> | ||||
| <head> | ||||
| 	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||||
| 	<script>var QUnit = parent.QUnit</script> | ||||
| 	<script src="testinit.js"></script> | ||||
| 	<script src="../../dist/sizzle.js"></script> | ||||
| </head> | ||||
| <body> | ||||
| 	<script> | ||||
| 		var doc = parent.document, | ||||
| 			unframed = [ doc.getElementById( "qunit-fixture" ), doc.body, doc.documentElement ], | ||||
| 			framed = Sizzle( "*" ); | ||||
| 
 | ||||
| 		window.parent.iframeCallback( | ||||
| 			Sizzle.uniqueSort( unframed.concat( framed ) ), | ||||
| 			framed.concat( unframed.reverse() ), | ||||
| 			"Mixed array was sorted correctly" | ||||
| 		); | ||||
| 	</script> | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										136
									
								
								public/vendor/sizzle/test/data/testinit.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								public/vendor/sizzle/test/data/testinit.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,136 @@ | ||||
| var fireNative, | ||||
| 	jQuery = this.jQuery || "jQuery", // For testing .noConflict()
 | ||||
| 	$ = this.$ || "$", | ||||
| 	originaljQuery = jQuery, | ||||
| 	original$ = $; | ||||
| 
 | ||||
| (function() { | ||||
| 	// Config parameter to force basic code paths
 | ||||
| 	QUnit.config.urlConfig.push({ | ||||
| 		id: "basic", | ||||
| 		label: "Bypass optimizations", | ||||
| 		tooltip: "Force use of the most basic code by disabling native querySelectorAll; contains; compareDocumentPosition" | ||||
| 	}); | ||||
| 	if ( QUnit.urlParams.basic ) { | ||||
| 		document.querySelectorAll = null; | ||||
| 		document.documentElement.contains = null; | ||||
| 		document.documentElement.compareDocumentPosition = null; | ||||
| 		// Return array of length two to pass assertion
 | ||||
| 		// But support should be false as its not native
 | ||||
| 		document.getElementsByClassName = function() { return [ 0, 1 ]; }; | ||||
| 	} | ||||
| })(); | ||||
| 
 | ||||
| /** | ||||
|  * Returns an array of elements with the given IDs | ||||
|  * @example q("main", "foo", "bar") | ||||
|  * @result [<div id="main">, <span id="foo">, <input id="bar">] | ||||
|  */ | ||||
| function q() { | ||||
| 	var r = [], | ||||
| 		i = 0; | ||||
| 
 | ||||
| 	for ( ; i < arguments.length; i++ ) { | ||||
| 		r.push( document.getElementById( arguments[i] ) ); | ||||
| 	} | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Asserts that a select matches the given IDs | ||||
|  * @param {String} a - Assertion name | ||||
|  * @param {String} b - Sizzle selector | ||||
|  * @param {String} c - Array of ids to construct what is expected | ||||
|  * @example t("Check for something", "//[a]", ["foo", "baar"]); | ||||
|  * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar' | ||||
|  */ | ||||
| function t( a, b, c ) { | ||||
| 	var f = Sizzle(b), | ||||
| 		s = "", | ||||
| 		i = 0; | ||||
| 
 | ||||
| 	for ( ; i < f.length; i++ ) { | ||||
| 		s += ( s && "," ) + '"' + f[ i ].id + '"'; | ||||
| 	} | ||||
| 
 | ||||
| 	deepEqual(f, q.apply( q, c ), a + " (" + b + ")"); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Add random number to url to stop caching | ||||
|  * | ||||
|  * @example url("data/test.html") | ||||
|  * @result "data/test.html?10538358428943" | ||||
|  * | ||||
|  * @example url("data/test.php?foo=bar") | ||||
|  * @result "data/test.php?foo=bar&10538358345554" | ||||
|  */ | ||||
| function url( value ) { | ||||
| 	return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000); | ||||
| } | ||||
| 
 | ||||
| var createWithFriesXML = function() { | ||||
| 	var string = '<?xml version="1.0" encoding="UTF-8"?> \ | ||||
| 	<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" \ | ||||
| 		xmlns:xsd="http://www.w3.org/2001/XMLSchema" \ | ||||
| 		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> \ | ||||
| 		<soap:Body> \ | ||||
| 			<jsconf xmlns="http://www.example.com/ns1"> \ | ||||
| 				<response xmlns:ab="http://www.example.com/ns2"> \ | ||||
| 					<meta> \ | ||||
| 						<component id="seite1" class="component"> \ | ||||
| 							<properties xmlns:cd="http://www.example.com/ns3"> \ | ||||
| 								<property name="prop1"> \ | ||||
| 									<thing /> \ | ||||
| 									<value>1</value> \ | ||||
| 								</property> \ | ||||
| 								<property name="prop2"> \ | ||||
| 									<thing att="something" /> \ | ||||
| 								</property> \ | ||||
| 								<foo_bar>foo</foo_bar> \ | ||||
| 							</properties> \ | ||||
| 						</component> \ | ||||
| 					</meta> \ | ||||
| 				</response> \ | ||||
| 			</jsconf> \ | ||||
| 		</soap:Body> \ | ||||
| 	</soap:Envelope>'; | ||||
| 
 | ||||
| 	return jQuery.parseXML( string ); | ||||
| }; | ||||
| 
 | ||||
| fireNative = document.createEvent ? | ||||
| 	function( node, type ) { | ||||
| 		var event = document.createEvent("HTMLEvents"); | ||||
| 		event.initEvent( type, true, true ); | ||||
| 		node.dispatchEvent( event ); | ||||
| 	} : | ||||
| 	function( node, type ) { | ||||
| 		var event = document.createEventObject(); | ||||
| 		node.fireEvent( "on" + type, event ); | ||||
| 	}; | ||||
| 
 | ||||
| function testIframeWithCallback( title, fileName, func ) { | ||||
| 	test( title, function() { | ||||
| 		var iframe; | ||||
| 
 | ||||
| 		stop(); | ||||
| 		window.iframeCallback = function() { | ||||
| 			var self = this, | ||||
| 				args = arguments; | ||||
| 			setTimeout(function() { | ||||
| 				window.iframeCallback = undefined; | ||||
| 				iframe.remove(); | ||||
| 				func.apply( self, args ); | ||||
| 				func = function() {}; | ||||
| 				start(); | ||||
| 			}, 0 ); | ||||
| 		}; | ||||
| 		iframe = jQuery( "<div/>" ).css({ position: "absolute", width: "500px", left: "-600px" }) | ||||
| 			.append( jQuery( "<iframe/>" ).attr( "src", url( "./data/" + fileName ) ) ) | ||||
| 			.appendTo( "#qunit-fixture" ); | ||||
| 	}); | ||||
| }; | ||||
| window.iframeCallback = undefined; | ||||
| 
 | ||||
| function moduleTeardown() {} | ||||
							
								
								
									
										242
									
								
								public/vendor/sizzle/test/index.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										242
									
								
								public/vendor/sizzle/test/index.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,242 @@ | ||||
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||||
| <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr" id="html"> | ||||
| <head> | ||||
| 	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | ||||
| 	<title>Sizzle Test Suite</title> | ||||
| 	<link rel="Stylesheet" media="screen" href="libs/qunit/qunit.css" /> | ||||
| 	<script type="text/javascript" src="libs/qunit/qunit.js"></script> | ||||
| 	<script type="text/javascript" src="data/testinit.js"></script> | ||||
| 	<script type="text/javascript" src="jquery.js"></script> | ||||
| 	<script type="text/javascript" src="../dist/sizzle.js"></script> | ||||
| 	<script type="text/javascript" src="unit/selector.js"></script> | ||||
| 	<script type="text/javascript" src="unit/utilities.js"></script> | ||||
| 	<script type="text/javascript" src="unit/extending.js"></script> | ||||
| </head> | ||||
| 
 | ||||
| <body id="body"> | ||||
| 	<div id="qunit"></div> | ||||
| 
 | ||||
| 	<!-- Test HTML --> | ||||
| 	<dl id="dl" style="position:absolute;top:-32767px;left:-32767px;width:1px"> | ||||
| 	<div id="qunit-fixture"> | ||||
| 		<p id="firstp">See <a id="simon1" href="http://simon.incutio.com/archive/2003/03/25/#getElementsBySelector" rel="bookmark">this blog entry</a> for more information.</p> | ||||
| 		<p id="ap"> | ||||
| 			Here are some [links] in a normal paragraph: <a id="google" href="http://www.google.com/" title="Google!">Google</a>, | ||||
| 			<a id="groups" href="http://groups.google.com/" class="GROUPS">Google Groups (Link)</a>. | ||||
| 			This link has <code id="code1"><a href="http://smin" id="anchor1">class="blog"</a></code>: | ||||
| 			<a href="http://diveintomark.org/" class="blog" hreflang="en" id="mark">diveintomark</a> | ||||
| 
 | ||||
| 		</p> | ||||
| 		<div id="foo"> | ||||
| 			<p id="sndp">Everything inside the red border is inside a div with <code>id="foo"</code>.</p> | ||||
| 			<p lang="en" id="en">This is a normal link: <a id="yahoo" href="http://www.yahoo.com/" class="blogTest">Yahoo</a></p> | ||||
| 			<p id="sap">This link has <code><a href="#2" id="anchor2">class="blog"</a></code>: <a href="http://simon.incutio.com/" class="blog link" id="simon">Simon Willison's Weblog</a></p> | ||||
| 
 | ||||
| 		</div> | ||||
| 		<div id="nothiddendiv" style="height:1px;background:white;" class="nothiddendiv"> | ||||
| 			<div id="nothiddendivchild"></div> | ||||
| 		</div> | ||||
| 		<span id="name+value"></span> | ||||
| 		<p id="first">Try them out:</p> | ||||
| 		<ul id="firstUL"></ul> | ||||
| 		<ol id="empty"><!-- comment --></ol> | ||||
| 		<form id="form" action="formaction"> | ||||
| 			<label for="action" id="label-for">Action:</label> | ||||
| 			<input type="text" name="action" value="Test" id="text1" maxlength="30"/> | ||||
| 			<input type="text" name="text2" value="Test" id="text2" disabled="disabled"/> | ||||
| 			<input type="radio" name="radio1" id="radio1" value="on"/> | ||||
| 
 | ||||
| 			<input type="radio" name="radio2" id="radio2" checked="checked"/> | ||||
| 			<input type="checkbox" name="check" id="check1" checked="checked"/> | ||||
| 			<input type="checkbox" id="check2" value="on"/> | ||||
| 
 | ||||
| 			<input type="hidden" name="hidden" id="hidden1"/> | ||||
| 			<input type="text" style="display:none;" name="foo[bar]" id="hidden2"/> | ||||
| 
 | ||||
| 			<input type="text" id="name" name="name" value="name" /> | ||||
| 			<input type="search" id="search" name="search" value="search" /> | ||||
| 
 | ||||
| 			<button id="button" name="button" type="button">Button</button> | ||||
| 
 | ||||
| 			<textarea id="area1" maxlength="30">foobar</textarea> | ||||
| 
 | ||||
| 			<select name="select1" id="select1"> | ||||
| 				<option id="option1a" class="emptyopt" value="">Nothing</option> | ||||
| 				<option id="option1b" value="1">1</option> | ||||
| 				<option id="option1c" value="2">2</option> | ||||
| 				<option id="option1d" value="3">3</option> | ||||
| 			</select> | ||||
| 			<select name="select2" id="select2"> | ||||
| 				<option id="option2a" class="emptyopt" value="">Nothing</option> | ||||
| 				<option id="option2b" value="1">1</option> | ||||
| 				<option id="option2c" value="2">2</option> | ||||
| 				<option id="option2d" selected="selected" value="3">3</option> | ||||
| 			</select> | ||||
| 			<select name="select3" id="select3" multiple="multiple"> | ||||
| 				<option id="option3a" class="emptyopt" value="">Nothing</option> | ||||
| 				<option id="option3b" selected="selected" value="1">1</option> | ||||
| 				<option id="option3c" selected="selected" value="2">2</option> | ||||
| 				<option id="option3d" value="3">3</option> | ||||
| 				<option id="option3e">no value</option> | ||||
| 			</select> | ||||
| 			<select name="select4" id="select4" multiple="multiple"> | ||||
| 				<optgroup disabled="disabled"> | ||||
| 					<option id="option4a" class="emptyopt" value="">Nothing</option> | ||||
| 					<option id="option4b" disabled="disabled" selected="selected" value="1">1</option> | ||||
| 					<option id="option4c" selected="selected" value="2">2</option> | ||||
| 				</optgroup> | ||||
| 				<option selected="selected" disabled="disabled" id="option4d" value="3">3</option> | ||||
| 				<option id="option4e">no value</option> | ||||
| 			</select> | ||||
| 			<select name="select5" id="select5"> | ||||
| 				<option id="option5a" value="3">1</option> | ||||
| 				<option id="option5b" value="2">2</option> | ||||
| 				<option id="option5c" value="1">3</option> | ||||
| 			</select> | ||||
| 
 | ||||
| 			<object id="object1" codebase="stupid"> | ||||
| 				<param name="p1" value="x1" /> | ||||
| 				<param name="p2" value="x2" /> | ||||
| 			</object> | ||||
| 
 | ||||
| 			<span id="台北Táiběi"></span> | ||||
| 			<span id="台北" lang="中文"></span> | ||||
| 			<span id="utf8class1" class="台北Táiběi 台北"></span> | ||||
| 			<span id="utf8class2" class="台北"></span> | ||||
| 			<span id="foo:bar" class="foo:bar"><span id="foo_descendent"></span></span> | ||||
| 			<span id="test.foo[5]bar" class="test.foo[5]bar"></span> | ||||
| 
 | ||||
| 			<foo_bar id="foobar">test element</foo_bar> | ||||
| 		</form> | ||||
| 		<b id="floatTest">Float test.</b> | ||||
| 		<iframe id="iframe" name="iframe"></iframe> | ||||
| 		<form id="lengthtest"> | ||||
| 			<input type="text" id="length" name="test"/> | ||||
| 			<input type="text" id="idTest" name="id"/> | ||||
| 		</form> | ||||
| 		<table id="table"></table> | ||||
| 
 | ||||
| 		<form id="name-tests"> | ||||
| 			<!-- Inputs with a grouped name attribute. --> | ||||
| 			<input name="types[]" id="types_all" type="checkbox" value="all" /> | ||||
| 			<input name="types[]" id="types_anime" type="checkbox" value="anime" /> | ||||
| 			<input name="types[]" id="types_movie" type="checkbox" value="movie" /> | ||||
| 		</form> | ||||
| 
 | ||||
| 		<form id="testForm" action="#" method="get"> | ||||
| 			<textarea name="T3" rows="2" cols="15">? | ||||
| Z</textarea> | ||||
| 			<input type="hidden" name="H1" value="x" /> | ||||
| 			<input type="hidden" name="H2" /> | ||||
| 			<input name="PWD" type="password" value="" /> | ||||
| 			<input name="T1" type="text" /> | ||||
| 			<input name="T2" type="text" value="YES" readonly="readonly" /> | ||||
| 			<input type="checkbox" name="C1" value="1" /> | ||||
| 			<input type="checkbox" name="C2" /> | ||||
| 			<input type="radio" name="R1" value="1" /> | ||||
| 			<input type="radio" name="R1" value="2" /> | ||||
| 			<input type="text" name="My Name" value="me" /> | ||||
| 			<input type="reset" name="reset" value="NO" /> | ||||
| 			<select name="S1"> | ||||
| 				<option value="abc">ABC</option> | ||||
| 				<option value="abc">ABC</option> | ||||
| 				<option value="abc">ABC</option> | ||||
| 			</select> | ||||
| 			<select name="S2" multiple="multiple" size="3"> | ||||
| 				<option value="abc">ABC</option> | ||||
| 				<option value="abc">ABC</option> | ||||
| 				<option value="abc">ABC</option> | ||||
| 			</select> | ||||
| 			<select name="S3"> | ||||
| 				<option selected="selected">YES</option> | ||||
| 			</select> | ||||
| 			<select name="S4"> | ||||
| 				<option value="" selected="selected">NO</option> | ||||
| 			</select> | ||||
| 			<input type="submit" name="sub1" value="NO" /> | ||||
| 			<input type="submit" name="sub2" value="NO" /> | ||||
| 			<input type="image" name="sub3" value="NO" /> | ||||
| 			<button name="sub4" type="submit" value="NO">NO</button> | ||||
| 			<input name="D1" type="text" value="NO" disabled="disabled" /> | ||||
| 			<input type="checkbox" checked="checked" disabled="disabled" name="D2" value="NO" /> | ||||
| 			<input type="radio" name="D3" value="NO" checked="checked" disabled="disabled" /> | ||||
| 			<select name="D4" disabled="disabled"> | ||||
| 				<option selected="selected" value="NO">NO</option> | ||||
| 			</select> | ||||
| 			<input id="list-test" type="text" /> | ||||
| 			<datalist id="datalist"> | ||||
| 				<option value="option"></option> | ||||
| 			</datalist> | ||||
| 		</form> | ||||
| 		<div id="moretests"> | ||||
| 			<form> | ||||
| 				<div id="checkedtest" style="display:none;"> | ||||
| 					<input type="radio" name="checkedtestradios" checked="checked"/> | ||||
| 					<input type="radio" name="checkedtestradios" value="on"/> | ||||
| 					<input type="checkbox" name="checkedtestcheckboxes" checked="checked"/> | ||||
| 					<input type="checkbox" name="checkedtestcheckboxes" /> | ||||
| 				</div> | ||||
| 			</form> | ||||
| 			<div id="nonnodes"><span>hi</span> there <!-- mon ami --></div> | ||||
| 			<div id="t2037"> | ||||
| 				<div><div class="hidden">hidden</div></div> | ||||
| 			</div> | ||||
| 			<div id="t6652"> | ||||
| 				<div></div> | ||||
| 			</div> | ||||
| 			<div id="t12087"> | ||||
| 				<input type="hidden" id="el12087" data-comma="0,1"/> | ||||
| 			</div> | ||||
| 			<div id="no-clone-exception"><object><embed></embed></object></div> | ||||
| 			<div id="names-group"> | ||||
| 				<span id="name-is-example" name="example"></span> | ||||
| 				<span id="name-is-div" name="div"></span> | ||||
| 			</div> | ||||
| 			<script id="script-no-src"></script> | ||||
| 			<script id="script-src" src="data/empty.js"></script> | ||||
| 			<div id="id-name-tests"> | ||||
| 				<a id="tName1ID" name="tName1"><span></span></a> | ||||
| 				<a id="tName2ID" name="tName2"><span></span></a> | ||||
| 				<div id="tName1"><span id="tName1-span">C</span></div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<div id="tabindex-tests"> | ||||
| 			<ol id="listWithTabIndex" tabindex="5"> | ||||
| 				<li id="foodWithNegativeTabIndex" tabindex="-1">Rice</li> | ||||
| 				<li id="foodNoTabIndex">Beans</li> | ||||
| 				<li>Blinis</li> | ||||
| 				<li>Tofu</li> | ||||
| 			</ol> | ||||
| 
 | ||||
| 			<div id="divWithNoTabIndex">I'm hungry. I should...</div> | ||||
| 			<span>...</span><a href="#" id="linkWithNoTabIndex">Eat lots of food</a><span>...</span> | | ||||
| 			<span>...</span><a href="#" id="linkWithTabIndex" tabindex="2">Eat a little food</a><span>...</span> | | ||||
| 			<span>...</span><a href="#" id="linkWithNegativeTabIndex" tabindex="-1">Eat no food</a><span>...</span> | ||||
| 			<span>...</span><a id="linkWithNoHrefWithNoTabIndex">Eat a burger</a><span>...</span> | ||||
| 			<span>...</span><a id="linkWithNoHrefWithTabIndex" tabindex="1">Eat some funyuns</a><span>...</span> | ||||
| 			<span>...</span><a id="linkWithNoHrefWithNegativeTabIndex" tabindex="-1">Eat some funyuns</a><span>...</span> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<div id="liveHandlerOrder"> | ||||
| 			<span id="liveSpan1"><a href="#" id="liveLink1"></a></span> | ||||
| 			<span id="liveSpan2"><a href="#" id="liveLink2"></a></span> | ||||
| 		</div> | ||||
| 
 | ||||
| 		<div id="siblingTest"> | ||||
| 			<em id="siblingfirst">1</em> | ||||
| 			<em id="siblingnext">2</em> | ||||
| 			<em id="siblingthird"> | ||||
| 				<em id="siblingchild"> | ||||
| 					<em id="siblinggrandchild"> | ||||
| 						<em id="siblinggreatgrandchild"></em> | ||||
| 					</em> | ||||
| 				</em> | ||||
| 			</em> | ||||
| 			<span id="siblingspan"></span> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 	</dl> | ||||
| 	<br id="last"/> | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										9597
									
								
								public/vendor/sizzle/test/jquery.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9597
									
								
								public/vendor/sizzle/test/jquery.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										244
									
								
								public/vendor/sizzle/test/libs/qunit/qunit.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								public/vendor/sizzle/test/libs/qunit/qunit.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,244 @@ | ||||
| /** | ||||
|  * QUnit v1.12.0 - A JavaScript Unit Testing Framework | ||||
|  * | ||||
|  * http://qunitjs.com | ||||
|  * | ||||
|  * Copyright 2012 jQuery Foundation and other contributors | ||||
|  * Released under the MIT license. | ||||
|  * http://jquery.org/license | ||||
|  */ | ||||
| 
 | ||||
| /** Font Family and Sizes */ | ||||
| 
 | ||||
| #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { | ||||
| 	font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; | ||||
| } | ||||
| 
 | ||||
| #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } | ||||
| #qunit-tests { font-size: smaller; } | ||||
| 
 | ||||
| 
 | ||||
| /** Resets */ | ||||
| 
 | ||||
| #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { | ||||
| 	margin: 0; | ||||
| 	padding: 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** Header */ | ||||
| 
 | ||||
| #qunit-header { | ||||
| 	padding: 0.5em 0 0.5em 1em; | ||||
| 
 | ||||
| 	color: #8699a4; | ||||
| 	background-color: #0d3349; | ||||
| 
 | ||||
| 	font-size: 1.5em; | ||||
| 	line-height: 1em; | ||||
| 	font-weight: normal; | ||||
| 
 | ||||
| 	border-radius: 5px 5px 0 0; | ||||
| 	-moz-border-radius: 5px 5px 0 0; | ||||
| 	-webkit-border-top-right-radius: 5px; | ||||
| 	-webkit-border-top-left-radius: 5px; | ||||
| } | ||||
| 
 | ||||
| #qunit-header a { | ||||
| 	text-decoration: none; | ||||
| 	color: #c2ccd1; | ||||
| } | ||||
| 
 | ||||
| #qunit-header a:hover, | ||||
| #qunit-header a:focus { | ||||
| 	color: #fff; | ||||
| } | ||||
| 
 | ||||
| #qunit-testrunner-toolbar label { | ||||
| 	display: inline-block; | ||||
| 	padding: 0 .5em 0 .1em; | ||||
| } | ||||
| 
 | ||||
| #qunit-banner { | ||||
| 	height: 5px; | ||||
| } | ||||
| 
 | ||||
| #qunit-testrunner-toolbar { | ||||
| 	padding: 0.5em 0 0.5em 2em; | ||||
| 	color: #5E740B; | ||||
| 	background-color: #eee; | ||||
| 	overflow: hidden; | ||||
| } | ||||
| 
 | ||||
| #qunit-userAgent { | ||||
| 	padding: 0.5em 0 0.5em 2.5em; | ||||
| 	background-color: #2b81af; | ||||
| 	color: #fff; | ||||
| 	text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; | ||||
| } | ||||
| 
 | ||||
| #qunit-modulefilter-container { | ||||
| 	float: right; | ||||
| } | ||||
| 
 | ||||
| /** Tests: Pass/Fail */ | ||||
| 
 | ||||
| #qunit-tests { | ||||
| 	list-style-position: inside; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests li { | ||||
| 	padding: 0.4em 0.5em 0.4em 2.5em; | ||||
| 	border-bottom: 1px solid #fff; | ||||
| 	list-style-position: inside; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running  { | ||||
| 	display: none; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests li strong { | ||||
| 	cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests li a { | ||||
| 	padding: 0.5em; | ||||
| 	color: #c2ccd1; | ||||
| 	text-decoration: none; | ||||
| } | ||||
| #qunit-tests li a:hover, | ||||
| #qunit-tests li a:focus { | ||||
| 	color: #000; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests li .runtime { | ||||
| 	float: right; | ||||
| 	font-size: smaller; | ||||
| } | ||||
| 
 | ||||
| .qunit-assert-list { | ||||
| 	margin-top: 0.5em; | ||||
| 	padding: 0.5em; | ||||
| 
 | ||||
| 	background-color: #fff; | ||||
| 
 | ||||
| 	border-radius: 5px; | ||||
| 	-moz-border-radius: 5px; | ||||
| 	-webkit-border-radius: 5px; | ||||
| } | ||||
| 
 | ||||
| .qunit-collapsed { | ||||
| 	display: none; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests table { | ||||
| 	border-collapse: collapse; | ||||
| 	margin-top: .2em; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests th { | ||||
| 	text-align: right; | ||||
| 	vertical-align: top; | ||||
| 	padding: 0 .5em 0 0; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests td { | ||||
| 	vertical-align: top; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests pre { | ||||
| 	margin: 0; | ||||
| 	white-space: pre-wrap; | ||||
| 	word-wrap: break-word; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests del { | ||||
| 	background-color: #e0f2be; | ||||
| 	color: #374e0c; | ||||
| 	text-decoration: none; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests ins { | ||||
| 	background-color: #ffcaca; | ||||
| 	color: #500; | ||||
| 	text-decoration: none; | ||||
| } | ||||
| 
 | ||||
| /*** Test Counts */ | ||||
| 
 | ||||
| #qunit-tests b.counts                       { color: black; } | ||||
| #qunit-tests b.passed                       { color: #5E740B; } | ||||
| #qunit-tests b.failed                       { color: #710909; } | ||||
| 
 | ||||
| #qunit-tests li li { | ||||
| 	padding: 5px; | ||||
| 	background-color: #fff; | ||||
| 	border-bottom: none; | ||||
| 	list-style-position: inside; | ||||
| } | ||||
| 
 | ||||
| /*** Passing Styles */ | ||||
| 
 | ||||
| #qunit-tests li li.pass { | ||||
| 	color: #3c510c; | ||||
| 	background-color: #fff; | ||||
| 	border-left: 10px solid #C6E746; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests .pass                          { color: #528CE0; background-color: #D2E0E6; } | ||||
| #qunit-tests .pass .test-name               { color: #366097; } | ||||
| 
 | ||||
| #qunit-tests .pass .test-actual, | ||||
| #qunit-tests .pass .test-expected           { color: #999999; } | ||||
| 
 | ||||
| #qunit-banner.qunit-pass                    { background-color: #C6E746; } | ||||
| 
 | ||||
| /*** Failing Styles */ | ||||
| 
 | ||||
| #qunit-tests li li.fail { | ||||
| 	color: #710909; | ||||
| 	background-color: #fff; | ||||
| 	border-left: 10px solid #EE5757; | ||||
| 	white-space: pre; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests > li:last-child { | ||||
| 	border-radius: 0 0 5px 5px; | ||||
| 	-moz-border-radius: 0 0 5px 5px; | ||||
| 	-webkit-border-bottom-right-radius: 5px; | ||||
| 	-webkit-border-bottom-left-radius: 5px; | ||||
| } | ||||
| 
 | ||||
| #qunit-tests .fail                          { color: #000000; background-color: #EE5757; } | ||||
| #qunit-tests .fail .test-name, | ||||
| #qunit-tests .fail .module-name             { color: #000000; } | ||||
| 
 | ||||
| #qunit-tests .fail .test-actual             { color: #EE5757; } | ||||
| #qunit-tests .fail .test-expected           { color: green;   } | ||||
| 
 | ||||
| #qunit-banner.qunit-fail                    { background-color: #EE5757; } | ||||
| 
 | ||||
| 
 | ||||
| /** Result */ | ||||
| 
 | ||||
| #qunit-testresult { | ||||
| 	padding: 0.5em 0.5em 0.5em 2.5em; | ||||
| 
 | ||||
| 	color: #2b81af; | ||||
| 	background-color: #D2E0E6; | ||||
| 
 | ||||
| 	border-bottom: 1px solid white; | ||||
| } | ||||
| #qunit-testresult .module-name { | ||||
| 	font-weight: bold; | ||||
| } | ||||
| 
 | ||||
| /** Fixture */ | ||||
| 
 | ||||
| #qunit-fixture { | ||||
| 	position: absolute; | ||||
| 	top: -10000px; | ||||
| 	left: -10000px; | ||||
| 	width: 1000px; | ||||
| 	height: 1000px; | ||||
| } | ||||
							
								
								
									
										2212
									
								
								public/vendor/sizzle/test/libs/qunit/qunit.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2212
									
								
								public/vendor/sizzle/test/libs/qunit/qunit.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										95
									
								
								public/vendor/sizzle/test/unit/extending.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								public/vendor/sizzle/test/unit/extending.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,95 @@ | ||||
| module("extending", { teardown: moduleTeardown }); | ||||
| 
 | ||||
| test("custom pseudos", function() { | ||||
| 	expect( 6 ); | ||||
| 
 | ||||
| 	Sizzle.selectors.filters.foundation = Sizzle.selectors.filters.root; | ||||
| 	deepEqual( Sizzle(":foundation"), [ document.documentElement ], "Copy element filter with new name" ); | ||||
| 	delete Sizzle.selectors.filters.foundation; | ||||
| 
 | ||||
| 	Sizzle.selectors.setFilters.primary = Sizzle.selectors.setFilters.first; | ||||
| 	t( "Copy set filter with new name", "div:primary", ["qunit"] ); | ||||
| 	delete Sizzle.selectors.setFilters.primary; | ||||
| 
 | ||||
| 	Sizzle.selectors.filters.aristotlean = Sizzle.selectors.createPseudo(function() { | ||||
| 		return function( elem ) { | ||||
| 			return !!elem.id; | ||||
| 		}; | ||||
| 	}); | ||||
| 	t( "Custom element filter", "#foo :aristotlean", [ "sndp", "en", "yahoo", "sap", "anchor2", "simon" ] ); | ||||
| 	delete Sizzle.selectors.filters.aristotlean; | ||||
| 
 | ||||
| 	Sizzle.selectors.filters.endswith = Sizzle.selectors.createPseudo(function( text ) { | ||||
| 		return function( elem ) { | ||||
| 			return Sizzle.getText( elem ).slice( -text.length ) === text; | ||||
| 		}; | ||||
| 	}); | ||||
| 	t( "Custom element filter with argument", "a:endswith(ogle)", ["google"] ); | ||||
| 	delete Sizzle.selectors.filters.endswith; | ||||
| 
 | ||||
| 	Sizzle.selectors.setFilters.second = Sizzle.selectors.createPseudo(function() { | ||||
| 		return Sizzle.selectors.createPseudo(function( seed, matches ) { | ||||
| 			if ( seed[1] ) { | ||||
| 				matches[1] = seed[1]; | ||||
| 				seed[1] = false; | ||||
| 			} | ||||
| 		}); | ||||
| 	}); | ||||
| 	t( "Custom set filter", "#qunit-fixture p:second", ["ap"] ); | ||||
| 	delete Sizzle.selectors.filters.second; | ||||
| 
 | ||||
| 	Sizzle.selectors.setFilters.slice = Sizzle.selectors.createPseudo(function( argument ) { | ||||
| 		var bounds = argument.split(":"); | ||||
| 		return Sizzle.selectors.createPseudo(function( seed, matches ) { | ||||
| 			var i = bounds[1]; | ||||
| 
 | ||||
| 			// Match elements found at the specified indexes
 | ||||
| 			while ( --i >= bounds[0] ) { | ||||
| 				if ( seed[i] ) { | ||||
| 					matches[i] = seed[i]; | ||||
| 					seed[i] = false; | ||||
| 				} | ||||
| 			} | ||||
| 		}); | ||||
| 	}); | ||||
| 	t( "Custom set filter with argument", "#qunit-fixture p:slice(1:3)", [ "ap", "sndp" ] ); | ||||
| 	delete Sizzle.selectors.filters.slice; | ||||
| }); | ||||
| 
 | ||||
| test("backwards-compatible custom pseudos", function() { | ||||
| 	expect( 3 ); | ||||
| 
 | ||||
| 	Sizzle.selectors.filters.icontains = function( elem, i, match ) { | ||||
| 		return Sizzle.getText( elem ).toLowerCase().indexOf( (match[3] || "").toLowerCase() ) > -1; | ||||
| 	}; | ||||
| 	t( "Custom element filter with argument", "a:icontains(THIS BLOG ENTRY)", ["simon1"] ); | ||||
| 	delete Sizzle.selectors.filters.icontains; | ||||
| 
 | ||||
| 	Sizzle.selectors.setFilters.podium = function( elements, argument ) { | ||||
| 		var count = argument == null || argument === "" ? 3 : +argument; | ||||
| 		return elements.slice( 0, count ); | ||||
| 	}; | ||||
| 	// Using TAG as the first token here forces this setMatcher into a fail state
 | ||||
| 	// Where the descendent combinator was lost
 | ||||
| 	t( "Custom setFilter", "form#form :PODIUM", ["label-for", "text1", "text2"] ); | ||||
| 	t( "Custom setFilter with argument", "#form input:Podium(1)", ["text1"] ); | ||||
| 	delete Sizzle.selectors.setFilters.podium; | ||||
| }); | ||||
| 
 | ||||
| test("custom attribute getters", function() { | ||||
| 	expect( 2 ); | ||||
| 
 | ||||
| 	var original = Sizzle.selectors.attrHandle.hreflang, | ||||
| 		selector = "a:contains('mark')[hreflang='http://diveintomark.org/en']"; | ||||
| 
 | ||||
| 	Sizzle.selectors.attrHandle.hreflang = function( elem, name ) { | ||||
| 		var href = elem.getAttribute("href"), | ||||
| 			lang = elem.getAttribute( name ); | ||||
| 		return lang && ( href + lang ); | ||||
| 	}; | ||||
| 
 | ||||
| 	deepEqual( Sizzle(selector, createWithFriesXML()), [], "Custom attrHandle (preferred document)" ); | ||||
| 	t( "Custom attrHandle (preferred document)", selector, ["mark"] ); | ||||
| 
 | ||||
| 	Sizzle.selectors.attrHandle.hreflang = original; | ||||
| }); | ||||
							
								
								
									
										1138
									
								
								public/vendor/sizzle/test/unit/selector.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1138
									
								
								public/vendor/sizzle/test/unit/selector.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										169
									
								
								public/vendor/sizzle/test/unit/utilities.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								public/vendor/sizzle/test/unit/utilities.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,169 @@ | ||||
| module("utilities", { teardown: moduleTeardown }); | ||||
| 
 | ||||
| function testAttr( doc ) { | ||||
| 	expect( 9 ); | ||||
| 
 | ||||
| 	var el; | ||||
| 	if ( doc ) { | ||||
| 		// XML
 | ||||
| 		el = doc.createElement( "input" ); | ||||
| 		el.setAttribute( "type", "checkbox" ); | ||||
| 	} else { | ||||
| 		// Set checked on creation by creating with a fragment
 | ||||
| 		// See http://jsfiddle.net/8sVgA/1/show/light in oldIE
 | ||||
| 		el = jQuery( "<input type='checkbox' checked='checked' />" )[0]; | ||||
| 	} | ||||
| 
 | ||||
| 	// Set it again for good measure
 | ||||
| 	el.setAttribute( "checked", "checked" ); | ||||
| 	el.setAttribute( "id", "id" ); | ||||
| 	el.setAttribute( "value", "on" ); | ||||
| 
 | ||||
| 	strictEqual( Sizzle.attr( el, "nonexistent" ), null, "nonexistent" ); | ||||
| 	strictEqual( Sizzle.attr( el, "id" ), "id", "existent" ); | ||||
| 	strictEqual( Sizzle.attr( el, "value" ), "on", "value" ); | ||||
| 	strictEqual( Sizzle.attr( el, "checked" ), "checked", "boolean" ); | ||||
| 	strictEqual( Sizzle.attr( el, "href" ), null, "interpolation risk" ); | ||||
| 	strictEqual( Sizzle.attr( el, "constructor" ), null, | ||||
| 		"Object.prototype property \"constructor\" (negative)" ); | ||||
| 	strictEqual( Sizzle.attr( el, "watch" ), null, | ||||
| 		"Gecko Object.prototype property \"watch\" (negative)" ); | ||||
| 	el.setAttribute( "constructor", "foo" ); | ||||
| 	el.setAttribute( "watch", "bar" ); | ||||
| 	strictEqual( Sizzle.attr( el, "constructor" ), "foo", | ||||
| 		"Object.prototype property \"constructor\"" ); | ||||
| 	strictEqual( Sizzle.attr( el, "watch" ), "bar", | ||||
| 		"Gecko Object.prototype property \"watch\"" ); | ||||
| } | ||||
| 
 | ||||
| test("Sizzle.attr (HTML)", function() { | ||||
| 	testAttr(); | ||||
| }); | ||||
| 
 | ||||
| test("Sizzle.attr (XML)", function() { | ||||
| 	testAttr( jQuery.parseXML("<root/>") ); | ||||
| }); | ||||
| 
 | ||||
| test("Sizzle.contains", function() { | ||||
| 	expect( 16 ); | ||||
| 
 | ||||
| 	var container = document.getElementById("nonnodes"), | ||||
| 		element = container.firstChild, | ||||
| 		text = element.nextSibling, | ||||
| 		nonContained = container.nextSibling, | ||||
| 		detached = document.createElement("a"); | ||||
| 	ok( element && element.nodeType === 1, "preliminary: found element" ); | ||||
| 	ok( text && text.nodeType === 3, "preliminary: found text" ); | ||||
| 	ok( nonContained, "preliminary: found non-descendant" ); | ||||
| 	ok( Sizzle.contains(container, element), "child" ); | ||||
| 	ok( Sizzle.contains(container.parentNode, element), "grandchild" ); | ||||
| 	ok( Sizzle.contains(container, text), "text child" ); | ||||
| 	ok( Sizzle.contains(container.parentNode, text), "text grandchild" ); | ||||
| 	ok( !Sizzle.contains(container, container), "self" ); | ||||
| 	ok( !Sizzle.contains(element, container), "parent" ); | ||||
| 	ok( !Sizzle.contains(container, nonContained), "non-descendant" ); | ||||
| 	ok( !Sizzle.contains(container, document), "document" ); | ||||
| 	ok( !Sizzle.contains(container, document.documentElement), "documentElement (negative)" ); | ||||
| 	ok( !Sizzle.contains(container, null), "Passing null does not throw an error" ); | ||||
| 	ok( Sizzle.contains(document, document.documentElement), "documentElement (positive)" ); | ||||
| 	ok( Sizzle.contains(document, element), "document container (positive)" ); | ||||
| 	ok( !Sizzle.contains(document, detached), "document container (negative)" ); | ||||
| }); | ||||
| 
 | ||||
| if ( jQuery("<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='1' width='1'><g/></svg>")[0].firstChild ) { | ||||
| 	test("Sizzle.contains in SVG (jQuery #10832)", function() { | ||||
| 		expect( 4 ); | ||||
| 
 | ||||
| 		var svg = jQuery( | ||||
| 			"<svg xmlns='http://www.w3.org/2000/svg' version='1.1' height='1' width='1'>" + | ||||
| 				"<g><circle cx='1' cy='1' r='1' /></g>" + | ||||
| 			"</svg>" | ||||
| 		).appendTo("#qunit-fixture")[0]; | ||||
| 
 | ||||
| 		ok( Sizzle.contains( svg, svg.firstChild ), "root child" ); | ||||
| 		ok( Sizzle.contains( svg.firstChild, svg.firstChild.firstChild ), "element child" ); | ||||
| 		ok( Sizzle.contains( svg, svg.firstChild.firstChild ), "root granchild" ); | ||||
| 		ok( !Sizzle.contains( svg.firstChild.firstChild, svg.firstChild ), "parent (negative)" ); | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| test("Sizzle.uniqueSort", function() { | ||||
| 	expect( 14 ); | ||||
| 
 | ||||
| 	function Arrayish( arr ) { | ||||
| 		var i = this.length = arr.length; | ||||
| 		while ( i-- ) { | ||||
| 			this[ i ] = arr[ i ]; | ||||
| 		} | ||||
| 	} | ||||
| 	Arrayish.prototype = { | ||||
| 		slice: [].slice, | ||||
| 		sort: [].sort, | ||||
| 		splice: [].splice | ||||
| 	}; | ||||
| 
 | ||||
| 	var i, tests, | ||||
| 		detached = [], | ||||
| 		body = document.body, | ||||
| 		fixture = document.getElementById("qunit-fixture"), | ||||
| 		detached1 = document.createElement("p"), | ||||
| 		detached2 = document.createElement("ul"), | ||||
| 		detachedChild = detached1.appendChild( document.createElement("a") ), | ||||
| 		detachedGrandchild = detachedChild.appendChild( document.createElement("b") ); | ||||
| 
 | ||||
| 	for ( i = 0; i < 12; i++ ) { | ||||
| 		detached.push( document.createElement("li") ); | ||||
| 		detached[i].id = "detached" + i; | ||||
| 		detached2.appendChild( document.createElement("li") ).id = "detachedChild" + i; | ||||
| 	} | ||||
| 
 | ||||
| 	tests = { | ||||
| 		"Empty": { | ||||
| 			input: [], | ||||
| 			expected: [] | ||||
| 		}, | ||||
| 		"Single-element": { | ||||
| 			input: [ fixture ], | ||||
| 			expected: [ fixture ] | ||||
| 		}, | ||||
| 		"No duplicates": { | ||||
| 			input: [ fixture, body ], | ||||
| 			expected: [ body, fixture ] | ||||
| 		}, | ||||
| 		"Duplicates": { | ||||
| 			input: [ body, fixture, fixture, body ], | ||||
| 			expected: [ body, fixture ] | ||||
| 		}, | ||||
| 		"Detached": { | ||||
| 			input: detached.slice( 0 ), | ||||
| 			expected: detached.slice( 0 ) | ||||
| 		}, | ||||
| 		"Detached children": { | ||||
| 			input: [ | ||||
| 				detached2.childNodes[0], | ||||
| 				detached2.childNodes[1], | ||||
| 				detached2.childNodes[2], | ||||
| 				detached2.childNodes[3] | ||||
| 			], | ||||
| 			expected: [ | ||||
| 				detached2.childNodes[0], | ||||
| 				detached2.childNodes[1], | ||||
| 				detached2.childNodes[2], | ||||
| 				detached2.childNodes[3] | ||||
| 			] | ||||
| 		}, | ||||
| 		"Attached/detached mixture": { | ||||
| 			input: [ detached1, fixture, detached2, document, detachedChild, body, detachedGrandchild ], | ||||
| 			expected: [ document, body, fixture ], | ||||
| 			length: 3 | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	jQuery.each( tests, function( label, test ) { | ||||
| 		var length = test.length || test.input.length; | ||||
| 		deepEqual( Sizzle.uniqueSort( test.input ).slice( 0, length ), test.expected, label + " (array)" ); | ||||
| 		deepEqual( Sizzle.uniqueSort( new Arrayish(test.input) ).slice( 0, length ), test.expected, label + " (quasi-array)" ); | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| testIframeWithCallback( "Sizzle.uniqueSort works cross-window (jQuery #14381)", "mixed_sort.html", deepEqual ); | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user