Print document from cross-origin iframe

When you need to show content from some other site, such as Google Docs, you can easily embed it inside an iframe. Google Docs even generates it for you. But what if you need to print that document via some button click? You can not do that, because the cross-origin policy does not allow it.

You have basically two options.

A) Create some proxy function on your server. But that is only available when you actually have a server and not just some hosted WordPress.

B) Create proxy iframe, which you are actually allowed to print, because there is no cross-origin involved. Then load the desired iframe inside the proxy iframe. Attach onload=”print()” on the target iframe, so the print starts automatically once it is loaded.

Working solution is below, have a nice day 🙂 Let me know, if it helped you.

Comments and suggestions for improvements are welcome. Hints: The iframe is not destroyed after print() is invoked, which might lead to memory leaks. Second issue is that you might need to calculate height of the iframe content, so that it is correctly printed. But if you can safely guess it, then you are fine.

  /**
   * Load iframe from cross-origin via proxy iframe
   * and then invokes the print dialog.
   * It is not possible to call window.print() on the target iframe directly
   * because of cross-origin policy.
   * 
   * Downside is that the iframe stays loaded. 
   */
  function printIframe(url) {
    var proxyIframe = document.createElement('iframe');
    var body = document.getElementsByTagName('body')[0];
    body.appendChild(proxyIframe);
    proxyIframe.style.width = '100%';
    proxyIframe.style.height = '100%';
    proxyIframe.style.display = 'none';

    var contentWindow = proxyIframe.contentWindow;
    contentWindow.document.open();
    // Set dimensions according to your needs.
    // You may need to calculate the dynamically after the content has loaded
    contentWindow.document.write('<iframe src="' + url + '" onload="print();" width="1000" height="1800" frameborder="0" marginheight="0" marginwidth="0">');
    contentWindow.document.close();
  }

Confirmation dialog in EmberJs

I am fairly new to EmberJs and I needed to create a nice confirmation dialog when user clicks a delete button. I’ve came up with following solution. Use it or copy it as you wish (please let me know in comments) or propose me a better solution if you know one, I will be glad to improve 🙂

Scenario

We have a list of items displayed in a table. Each item has a name, ID and a delete button. When user clicks it, confirmation dialog should appear.

Solution

For modal dialog we will use Ember Modal component. It will be wrapped inside {{#if}} helper, like this

{{#if hasItemToDelete}}
    {{#modal-dialog close=(action 'closeConfirmationDialog') translucentOverlay=true}}
        <h2 class="ui header">{{t "confirmation.are-you-sure-to-delete-name-placeholder" name=itemToDelete.name}}</h2>
        
        <div class="ui divider"></div>
        <button type="button" {{action "doRemoveItem"}} class="ui button primary">{{t "delete"}}</button>
        <button type="button" {{action "closeConfirmationDialog"}} class="ui button right floated">{{t "cancel"}}</button>
        
    {{/modal-dialog}}
{{/if}}

The result should look like this

confirm_delete

 

You may notice that the {{modal-dialog}} block is wrapped in {{#if hasItemToDelete}}. When user clicks a delete button, the clicked item is stored in variable itemToDelete. Then I have a computed property hasItemToDelete which is true when itemToDelete is not null. Like this:

import Ember from 'ember';
const {computed} = Ember;

export default Ember.Component.extend({
    i18n: Ember.inject.service(),
    
    itemToDelete: null,
    
    hasItemToDelete: computed('itemToDelete', function(){
       return this.get('itemToDelete') != null; 
    }),
    
    _closeConfirmationDialog: function() {
      this.set('itemToDelete', null);
    },
    
    items: [
      {id: 1, name: 'first item'},
      {id: 2, name: 'second item'},
      {id: 3, name: 'third item'},
      {id: 4, name: 'fourth item'},
      {id: 5, name: 'fifth item'},
    ],

    actions: {
      removeItem(item) {
          this.set('itemToDelete', item);
      },
      
      /**
       * DO NOT CALL THIS METHOD DIRECTLY
       * BUT ALWAYS VIA CONFIRMATION DIALOG
       */
      doRemoveItem() {
          const itemToDelete = this.get('itemToDelete');
          
          if (!itemToDelete){
              return;
          }
          
          // normally you would call something like itemToDelete.destroyRecord()
          // but this just a simplified example ....
          // so ... you know what to do 🙂
      },
     }
}

Working example

Unfortunately Twiddle does not let me use {{modal-dialog}} helper, even when it is in the dependencies, so I had to omit it.

Buffer
GetSocial