Feel free to ignore this, but it seems like implementing the Libraries API might be helpful for this module, since it implements an external library (http://timeago.yarp.com/jquery.timeago.js).

Context: I was recently messing around with my site, and downloaded the the dev version of timeago to overwrite the old version I had installed. Got distracted with other issues, then discovered that something weird was going on with javascript on my site, and timeago didn't seem to be working correctly. Well, I had completely forgotten about the external library requirements of the module, and that I needed to download http://timeago.yarp.com/jquery.timeago.js again and put it in the module folder. That fixed things. But since I was dealing with a bunch of issues, and a complex site, and had installed this module so long ago, it took me a bit longer that it should have to realize the problem. Which I think is the point of the Libraries API: making module upgrades more standardized (no need to keep track of which modules depend on an external library and then go and download the library with every upgrade).

Anyway, like I said, feel free to ignore this if you feel it would be too much work, but I thought I'd throw it out there.

Comments

icecreamyou’s picture

Status: Active » Needs review
StatusFileSize
new1.91 KB

Here's an untested patch to add support for Libraries API v2.

jordanmagnuson’s picture

Thanks Isaac!

I applied the patch, moved jquery.timeago.js to sites/all/libraries/timeago/, and so far everything seems to be working fine.

One small issue: status report is not registering the correct version of timeago, or the fact that the library is installed:

Time ago library 0.9.3 [should be 0.10.0]
Library does not exist. Download the library and put it in the timeago module folder.

icecreamyou’s picture

Well, you're probably using version 0.9.3. The current version of the library is actually 0.10.1. You can go download the current version from http://timeago.yarp.com/jquery.timeago.js. If that works for you, you can mark this issue RTBC.

jordanmagnuson’s picture

Actually, I'm using version 0.10.0. That's the version of jquery.timeago.js I have, and the version I have declared in the timeago module:

/**
 * Implements hook_library().
 */
function timeago_library() {
  $path = drupal_get_path('module', 'timeago');
  return array(
    'timeago' => array(
      'title' => t('Time ago'),
      'website' => 'http://timeago.yarp.com/',
      'version' => '0.10.0',
      'js' => array(
        $path . '/jquery.timeago.js' => array(),
        $path . '/timeago.js' => array(),
      ),
    ),
  );
}

The problem lies in timeago.install, which needs to be patched to work with Libraries API:

/**
 * Implements hook_requirements().
 */
function timeago_requirements($phase) {
  $t = get_t();
  $requirements = array('timeago' => array(
    'title' => $t('Time ago library'),
    'value' => '0.9.3',
  ));
  $exists = file_exists(drupal_get_path('module', 'timeago') . '/jquery.timeago.js');
  if ($exists) {
    $requirements['timeago']['description'] = $t('Library exists.');
    $requirements['timeago']['severity'] = REQUIREMENT_OK;
  }
  else {
    $requirements['timeago']['description'] = $t('Library does not exist. <a href="http://timeago.yarp.com/jquery.timeago.js">Download the library</a> and put it in the timeago module folder.');
    $requirements['timeago']['severity'] = ($phase == 'runtime' ? REQUIREMENT_ERROR : REQUIREMENT_WARNING);
  }
  return $requirements;
}

I'm also wondering why the jquery.timeago.js version number is hard-wired into the code, both here and in .module...? Shouldn't it be checking to see what version you have installed (from jquery.timeago.js @version), rather than telling you?

icecreamyou’s picture

StatusFileSize
new3.62 KB

Okay, try this one.

I don't really get why the version has to be hard-coded either, but that's what the core hook_library() mandates.

jordanmagnuson’s picture

StatusFileSize
new4.98 KB

Thanks for your help on this once again Isaac. I noticed that your patched install file just ignores the case of libraries api being installed... of course that fixes the error message, but doesn't give a lot of feedback if, like me, you are using the libraries api... of course, I realize that you're probably short on time, and getting the libraries api fully integrated probably isn't high on your todo list, which is totally understandable...

So anyway, I messed around a bit with the code myself, and created a new patch file, that gives a bit more status page feedback, regardless of whether you have libraries api installed or not. It also pulls the library version number from the actual javascript file, rather than hardcoding it. The install file is the only thing I've changed... the rest of the patch should be identical to yours...

I'm relatively new at Drupal development, and this is the first time I've attempted to create an actual patch file, so if I've done something terribly wrong, let me know, and I'll try to do better!

Anyway, let me know

jordanmagnuson’s picture

StatusFileSize
new4.98 KB

Okay, a bunch of bad whitespace and tabs in that last one, so here's another try...

icecreamyou’s picture

Status: Needs review » Needs work
+++ b/timeago.install
@@ -9,24 +9,69 @@
+  // Path to jquery.timeago.js
+  if (module_exists('libraries')) {
+    $path = 'sites/all/libraries/timeago/jquery.timeago.js';
+  }
+  else {
+    $path = drupal_get_path('module', 'timeago') . '/jquery.timeago.js';
+  }

There is no guarantee that the library is in sites/all/libraries. The Libraries module checks several locations. The right way to check if a library is installed is to call libraries_load() and check the "installed" key of the returned array. Also check out libraries_get_path().

+++ b/timeago.install
@@ -9,24 +9,69 @@
-    'title' => $t('Time ago library'),
-    'value' => '0.9.3',
+      'title' => $t('Time ago library'),

extra indenting here

+++ b/timeago.install
@@ -9,24 +9,69 @@
+    if ($update_version > $version) {

Use PHP's version_compare() function.

+++ b/timeago.install
@@ -9,24 +9,69 @@
+      $requirements['timeago']['description'] = $t('It appears that a newer version of this library is available. You may want to download the latest version from <a href="http://timeago.yarp.com/jquery.timeago.js">http://timeago.yarp.com/jquery.timeago.js</a> and overwrite the current version located at ' . "@path.", array('@path' => $path));

Why are you putting "@path" in a separate string? It's not a PHP variable so it doesn't need to be in double quotes, and concatenating strings confuses the translation script.

+++ b/timeago.install
@@ -9,24 +9,69 @@
-    $requirements['timeago']['description'] = $t('Library does not exist. <a href="http://timeago.yarp.com/jquery.timeago.js">Download the library</a> and put it in the timeago module folder.');
+    $requirements['timeago']['description'] = $t('Library does not exist. <a href="http://timeago.yarp.com/jquery.timeago.js">Download the library</a> and put it at ' . "@path.", array('@path' => $path));

Same comment as above -- putting "@path" in a separate string doesn't make sense

+++ b/timeago.install
@@ -9,24 +9,69 @@
 /**
+ * Returns param version of a file, or false if no version detected.
+ * @param $path
+ *  The path of the file to check.
+ * @param $pattern
+ *  A string containing a regular expression (PCRE) to match the
+ *  file version. For example: '@version\s+([0-9a-zA-Z\.-]+)@'.
+ */

Add a line between the description and @params. Also add an extra space before the @param descriptions (there should be 3 spaces after the *) and add "@see libraries_get_version()".

+++ b/timeago.install
@@ -9,24 +9,69 @@
+function timeago_get_version($path, $pattern = '@version\s+([0-9a-zA-Z\.-]+)@') {
+  $version = false;
+  $file = fopen($path, 'r');
+  if ($file) {
+    while ($line = fgets($file)) {
+      if (preg_match($pattern, $line, $matches)) {
+        $version = $matches[1];
+        break;
+      }
+    }
+    fclose($file);
+  }
+  return $version;
+}

This needs to handle the case where the file cannot be reached, e.g. no internet access is available. It also fails if no version string is found.

+++ b/timeago.module
@@ -83,7 +83,7 @@ function timeago_library() {
-      'version' => '0.9.3',
+      'version' => '0.10.0',

latest version is 0.11.1

Thanks

jordanmagnuson’s picture

StatusFileSize
new7.09 KB

Thank you for the pointers Isaac. I've tried to address everything you mention.

Regarding timeago_get_version, I think it should work if the remote file cannot be reached, as it will return false in that case (fopen will return false), and the install function will report that update information cannot be found... I tried accessing a nonexistent remote file, and it seemed to behave as desired.

One addition I made in this patch was to define constants for the library website, file name, and download url... was starting to reference them in a number of strings, etc, and it seemed like having constants defined would make things simpler in the future, should the library ever change its location, or file name. I've seen this method used in a number of other modules, but if it's undesirable for some reason, of course I can revert.

I also fixed a couple of spacing issues in timeago.module after running the code through coder, and changed timeago_add_js so that it looks for language files in the correct location if libraries is installed.

icecreamyou’s picture

One addition I made in this patch was to define constants for the library website, file name, and download url... was starting to reference them in a number of strings, etc, and it seemed like having constants defined would make things simpler in the future, should the library ever change its location, or file name. I've seen this method used in a number of other modules, but if it's undesirable for some reason, of course I can revert.

Yeah this is fine.

+++ b/timeago.install
@@ -5,28 +5,90 @@
+  if (module_exists('libraries')) {
+    $path = libraries_get_path('timeago');
+    if (libraries_get_path('timeago')) {
+      $path = libraries_get_path('timeago') . '/' . TIMEAGO_LIBRARY_FILENAME;
+    }
+    else {
+      $path = 'sites/all/libraries/timeago/' . TIMEAGO_LIBRARY_FILENAME;
+    }
+  }
+  else {
+    $path = drupal_get_path('module', 'timeago') . '/' . TIMEAGO_LIBRARY_FILENAME;
+  }

The logic here should be:

  • If the libraries module exists, $path = libraries_get_path('timeago');
  • If $path is empty (i.e. the library was not found or the libraries module is not installed) then look for the path in the module folder.

There is no circumstance under which you can assume that the path should be in sites/all/libraries/timeago.

+++ b/timeago.install
@@ -5,28 +5,90 @@
-  $exists = file_exists(drupal_get_path('module', 'timeago') . '/jquery.timeago.js');
+  $exists = file_exists($path);
+
+  // If file exists...
   if ($exists) {

Let's just do if (file_exists($path)) instead of using an intermediate variable since we don't use that variable anywhere else.

+++ b/timeago.install
@@ -5,28 +5,90 @@
+    $update_version = timeago_get_version(TIMEAGO_LIBRARY_DOWNLOAD_URL);

We should probably cache this so that we don't have to request a foreign URL every time the Status Report page is loaded.

+++ b/timeago.install
@@ -5,28 +5,90 @@
+      $requirements['timeago']['description'] = $t('No update information was found. If desired, you can manually check <a href="@library_download_url">@library_download_url</a> for a newer version of the library.', array('@library_download_url' => TIMEAGO_LIBRARY_DOWNLOAD_URL));

This message should have some indication that the library was installed, not just that no information was found.

+++ b/timeago.install
@@ -5,28 +5,90 @@
+      $requirements['timeago']['description'] = $t('It appears that a newer version of the library is available. You may want to download the latest version from <a href="@library_download_url">@library_download_url</a> and overwrite the current version located at @path.', array('@library_download_url' => TIMEAGO_LIBRARY_DOWNLOAD_URL, '@path' => $path));

Remove the phrase "It appears that" and so the message starts with "A newer version of the library is available"

+++ b/timeago.install
@@ -5,28 +5,90 @@
+    while ($line = fgets($file)) {
+      if (preg_match($pattern, $line, $matches)) {
+        $version = $matches[1];
+        break;
+      }
+    }

This will still check the whole file for a version string -- it should only check the first 200 characters of the first 20 lines or whatever the libraries module does.

Thanks for your work on this.

jordanmagnuson’s picture

StatusFileSize
new8.5 KB

Thanks again for the recommendations: I've tried to address everything. Tested with and without libraries api, in various states, and seems to be working.

The only thing I question is:

The logic here should be:

  • If the libraries module exists, $path = libraries_get_path('timeago');
  • If $path is empty (i.e. the library was not found or the libraries module is not installed) then look for the path in the module folder.

There is no circumstance under which you can assume that the path should be in sites/all/libraries/timeago.

I agree that bothother locations should be checked first (which I neglected on the last patch), but if the user has libraries api installed, but does not yet have jquery.timeago.js installed in either location, I think the status message should recommend installing to the default libraries api location, rather than within the modules directory, as a best practice. I think the libraries module should have some kind of libraries_get_default_path() function, but instead, the default location is just hardcoded into the module (as 'sites/all/libraries'). I agree that 'sites/all/libraries/' is not the only place that the library could go (given that other locations are also checked), but if it is not installed already, I think the libraries default path should be recommended.

jordanmagnuson’s picture

StatusFileSize
new8.23 KB

Moved the constant definitions from .install to .module, where they should be, and got rid of some left-over comments...

icecreamyou’s picture

Status: Needs work » Fixed

Committed #12 to dev with minor modifications to the description strings for the status report page. Thanks!

icecreamyou’s picture

Version: 7.x-2.x-dev » 6.x-2.x-dev
Status: Fixed » Patch (to be ported)

Oh actually this needs to be backported to 6.x... reopening

icecreamyou’s picture

Version: 6.x-2.x-dev » 7.x-2.x-dev
Status: Patch (to be ported) » Needs work

The change in #13 causes these notices when the module is installed because the .install file is loaded before the .module file:

Notice: Use of undefined constant TIMEAGO_LIBRARY_FILENAME - assumed 'TIMEAGO_LIBRARY_FILENAME' in timeago_requirements() (line 17 of ...\sites\all\modules\timeago\timeago.install).
Notice: Use of undefined constant TIMEAGO_LIBRARY_DOWNLOAD_URL - assumed 'TIMEAGO_LIBRARY_DOWNLOAD_URL' in timeago_requirements() (line 63 of ...\sites\all\modules\timeago\timeago.install).

Probably we should just load the module file at the top of hook_requirements() if it isn't already loaded.

icecreamyou’s picture

Version: 7.x-2.x-dev » 6.x-2.x-dev
Status: Needs work » Patch (to be ported)

Committed fix to dev. Took the easy way out.

icecreamyou’s picture

Status: Patch (to be ported) » Fixed

I'm actually okay with not backporting this to D6.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.