Using the standard upload module, I have uploaded a number of .pdf files to supplement the information contained within the pages, but when a visitor clicks on the attachment, the .pdf file opens in THAT window, taking the visitor away from my site.
Is there an easy way to ensure that attachments open in new windows?

Comments

Chill35’s picture

Maybe the solution lies in how the link is outputed ?

There is a themeable function in the upload.module file :

function theme_upload_attachments($files) {
  $header = array(t('Attachment'), t('Size'));
  $rows = array();
  foreach ($files as $file) {
    if ($file->list) {
      $href = $file->fid ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path()));
      $text = $file->description ? $file->description : $file->filename;
      $rows[] = array(l($text, $href), format_size($file->filesize));
    }
  }
  if (count($rows)) {
    return theme('table', $header, $rows, array('id' => 'attachments'));
  }
}

That function outputs the X(HTML) for the attachment table in the node.

Here is what you can do :

STEP 1 OF 2 : "Override" that function in your theme template.php file. More info can be found on how to override themeable functions right here : http://drupal.org/node/55126

STEP 2 OF 2 : And you see where that function l() is called in the code quoted above...? $rows[] = array(l($text, $href), format_size($file->filesize)); ... You can tell that l() function to open the link in a new window. By the way, l() stands for "link". So you can modify your override function to tell that link to open the pdf file in a new window.

I would first check if the mime type ($file->mimetype) is 'application/pdf' (something like that?), or simply check if the file extension is 'pdf' then I would call the function l() that way :

l($text, $href, array('target' => 'pdf'))

The third argument is an associative array of HTML attributes to apply to the anchor tag.

Notice I am not using '_blank' here, but 'pdf' : use '_blank' instead if you want the user to open a new window each time he clicks on an attached pdf file, otherwise 'pdf' (arbitrary name) if you want the user to open the pdf file in a new window (separate from Drupal's window) but always the same (other) window.

More info on Drupal's l() function can be found here : http://api.drupal.org/api/5/function/l

I will be happy to clarify any of the above info.

There are probably other ways to achieve what you want, but no other solution comes to my mind now. Maybe someone else will have an idea.

Caroline
Who am I | Where are we
11 heavens

pauldreed’s picture

Thanks for the comprehensive reply Caroline.
Unfortunatly I am only 2 weeks into drupal and finding it a steep learning curve! especially when it involves coding, so I think I would struggle to acheive this.
I thought that I would just be able to add target="_blank" to the link code.

I am developing a Community site and wanted to allow visitors access to some help documents (.pdf), so I will probably need to find another solution.

Thanks anyway

Chill35’s picture

I thought that I would just be able to add target="_blank" to the link code.

You can do this.

You can hack the code and add the _blank in upload.module if you want.

I have a notebook where I keep a record of where I hacked the code and why, with line number... ;) Sometime, we don't have enough time.

Try this, then : (modifying that function in upload.module)

function theme_upload_attachments($files) {
  $header = array(t('Attachment'), t('Size'));
  $rows = array();
  foreach ($files as $file) {
    if ($file->list) {
      $href = $file->fid ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path()));
      $text = $file->description ? $file->description : $file->filename;
      $rows[] = array(l($text, $href, array('target' => '_blank')), format_size($file->filesize));
    }
  }
  if (count($rows)) {
    return theme('table', $header, $rows, array('id' => 'attachments'));
  }
}

Caroline
Who am I | Where are we
11 heavens

pauldreed’s picture

Caroline, that appears to work, and I have checked much of the site and it does not appear to have affected anything elso, menus and other links appear to work as before.
Each of the documents now open in a fresh window, leaving my site open in the background.

Great!

Thanks again.

Chill35’s picture

I am so glad it does :) I had my fingers crossed that my code would not produce a php parsing error for lack of a parenthesis, or something like that. That change will not break anything. People can always 'right click' and 'save as'. Really that function only affects the attachment table that you see at the bottom of "nodes", that table that gives the name of the file, next to its size.

Caroline
Who am I | Where are we
11 heavens

Ella-1’s picture

Thanks, Caroline. Just had a look around your site, too.

Just want to point out, for other users who might want to do this - that if you have only one Drupal site it's fine to hack the upload module, but if you have several sites, and you do that, then the attachments will open in new windows on all your sites. That's why the theme-funcion override is the best way to do it (i'm going to try that now) if you only want to change one of your Drupal sites.

Ella

weickmann’s picture

Merci pour ce morceau de code
Philippe (Narbonne-France)

UnicornSong’s picture

Wow thanks chill, I thought this was going to be a challenge but thanks to your post it was a 5 minute job!!

function phptemplate_upload_attachments($files) {
  $header = array(t('Attachment'), t('Size'));
  $rows = array();
  foreach ($files as $file) {
    if ($file->list) {
      $href = $file->fid ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path()));
      $text = $file->description ? $file->description : $file->filename;
      $rows[] = array(l($text, $href, array('target' => '_blank')), format_size($file->filesize));
    }
  }
  if (count($rows)) {
    return theme('table', $header, $rows, array('id' => 'attachments'));
  }
Chill35’s picture

Your code is a 500% better than mine, as it does not hack core. I was a newbie then, I know better now.

The use of this phptemplate_ prefixed function in your theme is awesome.

[EDIT] Oh so it seems that I was overriding the theming function too, later on in this thread...

Caroline
11 heavens.com

Ella-1’s picture

I'm getting stuck with this. Broken my site now, too, though i can get it back by logging in as another user with another theme.

Can you help? this is what I have at the moment. It's Drupal 5:

function phptemplate_theme_upload_attachments($files) {
  $header = array(t('Attachment'), t('Size'));
  $rows = array();
  foreach ($files as $file) {
    if ($file->list) {
      $href = $file->fid ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path()));
      $text = $file->description ? $file->description : $file->filename;
      $rows[] = arrayl($text, $href, array('target' => '_blank')), format_size($file->filesize));
    }
  }
  if (count($rows)) {
    return _phptemplate_theme('table', $header, $rows, array('id' => 'attachments'));
  }
}
Chill35’s picture

Your code is :

function phptemplate_theme_upload_attachments($files) {
  $header = array(t('Attachment'), t('Size'));
  $rows = array();
  foreach ($files as $file) {
    if ($file->list) {
      $href = $file->fid ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path()));
      $text = $file->description ? $file->description : $file->filename;
      $rows[] = arrayl($text, $href, array('target' => '_blank')), format_size($file->filesize));
    }
  }
  if (count($rows)) {
    return _phptemplate_theme('table', $header, $rows, array('id' => 'attachments'));
  }
}

Change the name of the function to phptemplate_upload_attachments($files),

This line of code has an error in it :

$rows[] = arrayl($text, $href, array('target' => '_blank')), format_size($file->filesize));

How about changing it to :

$rows[] = array(l($text, $href, array('target' => '_blank')), format_size($file->filesize));

Caroline
A coder's guide to file download in Drupal
Who am I | Where are we
11 heavens

Ella-1’s picture

Thank you.

Now my site is back, but when I click on any story that has attachments, the page goes blank. Apologies that I am not a programmer, but I have done a theme-function overrride before (with a little help from another programmer who's not available at the moment).

Thanks

Ella

Chill35’s picture

Another mistake in your code...

Change this :


if (count($rows)) {
    return _phptemplate_theme('table', $header, $rows, array('id' => 'attachments'));
  }

To this :


if (count($rows)) {
    return theme('table', $header, $rows, array('id' => 'attachments'));
  }

If you're not a programmer, then you probably should not do 'theming'. Drupal sucks like that : you have to (I think) be a programmer (self-taught is fine, fine) if you don't want a Drupal cookie-cutter web site.

Caroline
A coder's guide to file download in Drupal
Who am I | Where are we
11 heavens

STyL3’s picture

I've done all of this...At first my site didn't show up, but then i made the corrections to the code. Now my site shows up, but my attachment links still do not pop in a blank window. The still open on top of the site itself. Here's my code:

/**
 * Displays file attachments in table
 */
function theme_upload_attachments($files) {
  $header = array(t('Attachment'), t('Size'));
  $rows = array();
  foreach ($files as $file) {
    if ($file->list) {
      $href = $file->fid ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path()));
      $text = $file->description ? $file->description : $file->filename;
      $rows[] = array(l($text, $href, array('target' => '_blank')), format_size($file->filesize));
    }
  }
  if (count($rows)) {
    return theme('table', $header, $rows, array('id' => 'attachments'));
  }
}
keesje’s picture

Cool, dont even have to think myself, you did it for me :)

Change
function theme_upload_attachments($files) {

to

function phptemplate_upload_attachments($files) {

And place it in phptemplate.php, and you're good to go without hacking.

Kees

Webbased applicaties, content management systemen, websites, webdesign

svekkeKT’s picture

Qrios, what do you mean with "And place it in phptemplate.php, and you're good to go without hacking."
I can't find that file? I did find the phptemplate directory but don't know what I have to change there.

I'm using Drupal 6.2, but the attachment code doesn't seem to work.

My code in upload.module is the following
...
...

function phptemplate_upload_attachments($files) {
  $header = array(t('Attachment'), t('Size'));
  $rows = array();
  foreach ($files as $file) {
    if ($file->list) {
      $href = $file->fid ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path()));
      $text = $file->description ? $file->description : $file->filename;
      $rows[] = array(l($text, $href, array('target' => '_blank')), format_size($file->filesize));
    }
  }
  if (count($rows)) {
    return theme('table', $header, $rows, array('id' => 'attachments'));
  }
}

On my site, I receive this error:
warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, 'theme_upload_attachments' was given in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\drupal\includes\theme.inc on line 591.

I hope somebody can help me.

Kind regards,

Sven

keesje’s picture

Code is D5 tested, don't know (yet) for D6.

wadley0’s picture

Try this (in your template.php file):

/**
*  Override for attachments to be target="_blank"
*/
function phptemplate_upload_attachments($files) {
  $header = array(t('Attachment'), t('Size'));
  $rows = array();
  foreach ($files as $file) {
    $file = (object)$file;
    if ($file->list && empty($file->remove)) {
      $href = file_create_url($file->filepath);
      $text = $file->description ? $file->description : $file->filename;

      $rows[] = array(l($text, $href, array('attributes' => array('target' => '_blank'))), format_size($file->filesize));
    }
  }
  if (count($rows)) {
    return theme('table', $header, $rows, array('id' => 'attachments'));
  }
}
svekkeKT’s picture

Hello

I used your code in template.php and used the original code in upload.module.
The attachments still opened in the same window.

Then I tried to change the code in upload.module to the code given above in this thread.
When I wanted to view my site, I only got a blank screen.
Rightnow I'm using the original upload.module again.

Am I doing something wrong?

Thanks for your help!

Grtz,

Sven

keesje’s picture

What version Drupal (D6?)
Try copying the original function to phptemplate.php, change functionname to "phptemplate_upload_attachments".
See if it works by changing something easy like "array(t('Attachment')" to "array(t('Changed')".
Then alter the code by adding the attributes array.

Switch off other modules, disable caching.

svekkeKT’s picture

Thank you wadley0 & qrios!!

After some tests, I used this code and it worked:

function phptemplate_upload_attachments($files) {
  $header = array(t('Attachment'), t('Size'));
  $rows = array();
  foreach ($files as $file) {
    $file = (object)$file;
    if ($file->list && empty($file->remove)) {
      $href = file_create_url($file->filepath);
      $text = $file->description ? $file->description : $file->filename;
      $rows[] = array(l($text, $href, array('attributes' => array('target' => '_blank'))), format_size($file->filesize));
    }
  }
  if (count($rows)) {
    return theme('table', $header, $rows, array('id' => 'attachments'));
  }
}
pjabode’s picture

Jipie,

Thanks!

I copied the code into my template.php in my sub-theme folder, and
it worked. I changed the _blank to: new
so that it would only open one new window when attachment links
are clicked.

Mathews_1’s picture

subscribing

Mathews_1’s picture

I copied it to my template.php and it crashed my site. Had to change it back to get site up. I'm running Drupal 6.8 where in the template.php did yo copy it? Does anyone know of a stable option that works for Drupal 6.x?

Zucker’s picture

Thank you, thats it! :)

cgjohnson’s picture

How do I do this when using a View to display content?
(It works in the node but not in a view)
Thanks

mmirza’s picture

There's an easier and more simple way of doing this by using the external links module, the patterns matching settings in the external links module configuration need to be set.

In the Include Links Matching the Pattern
Type the following .*doc|.*pdf
This should solve any problems, or you can use the webfile manager module which has an option to open documents in a new window.

shunshifu’s picture

MMirza,

Thank you, I would have never thought of that. Very helpful.
Just a note, it's the external links module not the external links filter

Thanks again.

Phil

Brainwrap’s picture

Hi, I just tried your External Links solution to force PDFs and DOCs to open into a new window.

Unfortunately, I forgot the "." at the beginning of the Pattern Matching field, as follows:

*doc|.*pdf

instead of

.*doc|.*pdf

Since doing this, none of the administrative menu expansion options work on any modules, *including* external links!

In other words, I can no longer even open up "Pattern Matching" in order to fix the problem!

The only solution I've found so far is to disable/remove the External Links module completely, which is a shame since it's otherwise very handy.

Any suggestions?

UPDATE: OK, the good news is that the fix is painfully simple--just turn javascript off in your browser and add the "." in front of the DOC wildcard.

I'm gonna leave this comment up anyway, however, as a cautionary note for anyone else who makes the same mistake I did.

izmeez’s picture

@brainwrap Yes, it is easy to mess up the pattern matching and lose the link to get back in and fix it. But, you don't have to disable and remove the module you can just click on "Reset to defaults" and go from there.

widiotter’s picture

Oh yeah, works for me on 6.20! Tx for this hint!

marranca’s picture

I've spent two hours trying to find the correct module. There appear to be a great many modules with similar names.

None of the ones I've tried have an "include links matching the pattern" field in the configuration. We would benefit from a direct link to the specific module referenced here.

Thanks!
-Joe M

stickDeath’s picture

This one worked for me.

Thnks a lot dude!

frankie’s picture

Hi,
.*doc|.*pdf will match with all the urls that contains doc or pdf (e.g. www.example.com/my_ocuments)

For me the correct pattern is
.*doc$|.*pdf$
this regexp will match only with files extension xyz.doc or xyz.pdf

David.W’s picture

@mmirza:
Very nice solution. Love it!

Thank you very much

Advocat’s picture

I have a site with a lot of external links, including links leading to .pdfs on other sites. I need to prevent all of those from opening in new windows, while letting my attached files do so.

While experimenting on how to filter out the other domains, I entered the general domain endings (\.com) etc. for all common domains. This then cause External Links to ignore my own domain, so links in new windows wouldn't work. I attempted to add an include pattern, but there was no change. Likely I'm screwing up the pattern matching code, but I can't really tell.

What I need to do is exclude all major domains, including other .com domains, from being forced to open in new windows, but retain the ability to force the attached .pdfs on my domain to open in new windows.

After spending several hours experimenting, it's time to call for help!

If this helps, my attached pdfs have a common name ending, eg: somename_fact_sheets.pdf

Any assistance appreciated!

widiotter’s picture

Oh yeah, external link-module works for me on 6.20! Tx for this hint!

akaserer’s picture

you can use this jquery statement:

$(' #attachments').find('a').attr('target','_blank');

cmstom’s picture

I'm using Open Atrium 1.x (Drupal 6) and I wanted to post why the provided code in this post wouldn't work for me. Under a standard Drupal installation, using the theme function override in template.php would have worked, however in Open Atrium 1, they are using the iTweak Upload module to provide enhancements to the displaying of attachments in node. This prevents the template.php theme function override from working. Luckily iTweak Upload added the ability to hook into their modifications of the link.

This code in template.php would not work:

function phptemplate_upload_attachments($files) {
  $header = array(t('Attachment'), t('Size'));
  $rows = array();
  foreach ($files as $file) {
    if ($file->list) {
      $href = $file->fid ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path()));
      $text = $file->description ? $file->description : $file->filename;
      $rows[] = array(l($text, $href, array('target' => '_blank')), format_size($file->filesize));
    }
  }
  if (count($rows)) {
    return theme('table', $header, $rows, array('id' => 'attachments'));
  }
}

Creating a new module with this in .module will work (only applies if you have iTweaks Upload installed)

<?php
function [custom_module_name]_itweak_uploads_prerender_alter(&$data) {
  $data['options'] = array('attributes' => array('target' => '_blank'));
}

Thomas Newman
Drupal Developer, Site Builder, Themer

augustyip’s picture

For Drupal 7 version, should override theme_file_link() function in file.module

/**
 * Returns HTML for a link to a file.
 *
 * @param $variables
 *   An associative array containing:
 *   - file: A file object to which the link will be created.
 *   - icon_directory: (optional) A path to a directory of icons to be used for
 *     files. Defaults to the value of the "file_icon_directory" variable.
 *
 * @ingroup themeable
 */
function theme_file_link($variables) {
  $file = $variables['file'];
  $icon_directory = $variables['icon_directory'];

  $url = file_create_url($file->uri);
  $icon = theme('file_icon', array('file' => $file, 'icon_directory' => $icon_directory));

  // Set options as per anchor format described at
  // http://microformats.org/wiki/file-format-examples
  $options = array(
    'attributes' => array(
      'type' => $file->filemime . '; length=' . $file->filesize,
    ),
  );

  // Use the description as the link text if available.
  if (empty($file->description)) {
    $link_text = $file->filename;
  }
  else {
    $link_text = $file->description;
    $options['attributes']['title'] = check_plain($file->filename);
  }

  return '<span class="file">' . $icon . ' ' . l($link_text, $url, $options) . '</span>';
}

icf-vpathak’s picture

To address this issue.

I added the following code snippet in my JS file

(function ($) {
Drupal.behaviors.externalLink = {
attach: function (context, settings) {
$('.YOUR_CLASS_NAME a', context).attr("target", "_blank");
}
}
}(jQuery));

so the above code will open all the links under the specified class in a new window.

The following links helped me in figuring out this issue.
1. Open Link in New Window in Drupal 7
2. Jquery: Add rel attribute to 'a' tags of a certain class