The previous version interfered with the full screen shortcut (Ctrl + Alt + P). The new version only intercepts Cmd/Ctrl + P (all browsers). And Ctrl + Shift + P in Chrome / Opera (Presto and Chromium), because these browsers also associate a Print operation with the shortcut.
		
			
				
	
	
		
			145 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 | 
						|
/* Copyright 2013 Mozilla Foundation
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
/* globals HTMLCanvasElement */
 | 
						|
 | 
						|
'use strict';
 | 
						|
(function mozPrintCallbackPolyfillClosure() {
 | 
						|
  if ('mozPrintCallback' in document.createElement('canvas')) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  // Cause positive result on feature-detection:
 | 
						|
  HTMLCanvasElement.prototype.mozPrintCallback = undefined;
 | 
						|
 | 
						|
  var canvases;   // During print task: non-live NodeList of <canvas> elements
 | 
						|
  var index;      // Index of <canvas> element that is being processed
 | 
						|
 | 
						|
  var print = window.print;
 | 
						|
  window.print = function print() {
 | 
						|
    if (canvases) {
 | 
						|
      console.warn('Ignored window.print() because of a pending print job.');
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    try {
 | 
						|
      dispatchEvent('beforeprint');
 | 
						|
    } finally {
 | 
						|
      canvases = document.querySelectorAll('canvas');
 | 
						|
      index = -1;
 | 
						|
      next();
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  function dispatchEvent(eventType) {
 | 
						|
    var event = document.createEvent('CustomEvent');
 | 
						|
    event.initCustomEvent(eventType, false, false, 'custom');
 | 
						|
    window.dispatchEvent(event);
 | 
						|
  }
 | 
						|
 | 
						|
  function next() {
 | 
						|
    if (!canvases) {
 | 
						|
      return; // Print task cancelled by user (state reset in abort())
 | 
						|
    }
 | 
						|
 | 
						|
    renderProgress();
 | 
						|
    if (++index < canvases.length) {
 | 
						|
      var canvas = canvases[index];
 | 
						|
      if (typeof canvas.mozPrintCallback === 'function') {
 | 
						|
        canvas.mozPrintCallback({
 | 
						|
          context: canvas.getContext('2d'),
 | 
						|
          abort: abort,
 | 
						|
          done: next
 | 
						|
        });
 | 
						|
      } else {
 | 
						|
        next();
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      renderProgress();
 | 
						|
      print.call(window);
 | 
						|
      setTimeout(abort, 20); // Tidy-up
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  function abort() {
 | 
						|
    if (canvases) {
 | 
						|
      canvases = null;
 | 
						|
      renderProgress();
 | 
						|
      dispatchEvent('afterprint');
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  function renderProgress() {
 | 
						|
    var progressContainer = document.getElementById('mozPrintCallback-shim');
 | 
						|
    if (canvases) {
 | 
						|
      var progress = Math.round(100 * index / canvases.length);
 | 
						|
      var progressBar = progressContainer.querySelector('progress');
 | 
						|
      var progressPerc = progressContainer.querySelector('.relative-progress');
 | 
						|
      progressBar.value = progress;
 | 
						|
      progressPerc.textContent = progress + '%';
 | 
						|
      progressContainer.removeAttribute('hidden');
 | 
						|
      progressContainer.onclick = abort;
 | 
						|
    } else {
 | 
						|
      progressContainer.setAttribute('hidden', '');
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  var hasAttachEvent = !!document.attachEvent;
 | 
						|
 | 
						|
  window.addEventListener('keydown', function(event) {
 | 
						|
    // Intercept Cmd/Ctrl + P in all browsers.
 | 
						|
    // Also intercept Cmd/Ctrl + Shift + P in Chrome and Opera
 | 
						|
    if (event.keyCode === 80/*P*/ && (event.ctrlKey || event.metaKey) &&
 | 
						|
        !event.altKey && (!event.shiftKey || window.chrome || window.opera)) {
 | 
						|
      window.print();
 | 
						|
      if (hasAttachEvent) {
 | 
						|
        // Only attachEvent can cancel Ctrl + P dialog in IE <=10
 | 
						|
        // attachEvent is gone in IE11, so the dialog will re-appear in IE11.
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      event.preventDefault();
 | 
						|
      if (event.stopImmediatePropagation) {
 | 
						|
        event.stopImmediatePropagation();
 | 
						|
      } else {
 | 
						|
        event.stopPropagation();
 | 
						|
      }
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    if (event.keyCode === 27 && canvases) { // Esc
 | 
						|
      abort();
 | 
						|
    }
 | 
						|
  }, true);
 | 
						|
  if (hasAttachEvent) {
 | 
						|
    document.attachEvent('onkeydown', function(event) {
 | 
						|
      event = event || window.event;
 | 
						|
      if (event.keyCode === 80/*P*/ && event.ctrlKey) {
 | 
						|
        event.keyCode = 0;
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  if ('onbeforeprint' in window) {
 | 
						|
    // Do not propagate before/afterprint events when they are not triggered
 | 
						|
    // from within this polyfill. (FF/IE).
 | 
						|
    var stopPropagationIfNeeded = function(event) {
 | 
						|
      if (event.detail !== 'custom' && event.stopImmediatePropagation) {
 | 
						|
        event.stopImmediatePropagation();
 | 
						|
      }
 | 
						|
    };
 | 
						|
    window.addEventListener('beforeprint', stopPropagationIfNeeded, false);
 | 
						|
    window.addEventListener('afterprint', stopPropagationIfNeeded, false);
 | 
						|
  }
 | 
						|
})();
 |