Browse Source

merged flag_lists submodule. TODO a new version is officially available compatible with flag 3 branch, TEST IT!

Bachir Soussi Chiadmi 9 years ago
parent
commit
28db07faf7
19 changed files with 4684 additions and 0 deletions
  1. 78 0
      sites/all/modules/contrib/flag/flag_lists/CHANGELOG.txt
  2. 339 0
      sites/all/modules/contrib/flag/flag_lists/LICENSE.txt
  3. 0 0
      sites/all/modules/contrib/flag/flag_lists/css/flag_lists_ops.css
  4. 599 0
      sites/all/modules/contrib/flag/flag_lists/flag_lists.admin.inc
  5. 27 0
      sites/all/modules/contrib/flag/flag_lists/flag_lists.info
  6. 207 0
      sites/all/modules/contrib/flag/flag_lists/flag_lists.install
  7. 1737 0
      sites/all/modules/contrib/flag/flag_lists/flag_lists.module
  8. 332 0
      sites/all/modules/contrib/flag/flag_lists/includes/flag_lists.views.inc
  9. 864 0
      sites/all/modules/contrib/flag/flag_lists/includes/flag_lists.views_default.inc
  10. 26 0
      sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_argument_fid.inc
  11. 56 0
      sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_field_list.inc
  12. 50 0
      sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_field_list_delete.inc
  13. 50 0
      sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_field_list_edit.inc
  14. 94 0
      sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_field_ops.inc
  15. 55 0
      sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_field_template.inc
  16. 65 0
      sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_field_template_types.inc
  17. 17 0
      sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_filter_template.inc
  18. 79 0
      sites/all/modules/contrib/flag/flag_lists/js/flag_lists_ops.js
  19. 9 0
      sites/all/modules/contrib/flag/flag_lists/theme/flag_lists.css

+ 78 - 0
sites/all/modules/contrib/flag/flag_lists/CHANGELOG.txt

@@ -0,0 +1,78 @@
+// $id: $
+
+Flag lists (Jan. 27, 2011
+Fix bug: Incorrectly checking status of non-flag_lists flags.
+Fix bug: Incorrectly applying hook_flag_access() on non-flag_lists flags.
+
+Flag lists (Jan. 14, 2011
+#1002292 Fixed Tokens not replaced in add-to-list and remove-from-list js messages.
+#1002292 Token module now a required dependency.
+
+Flag lists (Jan. 12, 2011)
+#1023432 by erikwebb: Fixed No default value for $account in flag_lists_fl_delete().
+#1002294 by architectJpres: Fixed List block incompatible with block caching.
+  Block caching turned off for now. Still not making db updates so you need to
+  remove the block from its region and then put it back to turn on caching.
+
+Flag lists (Nov. 24, 2010)
+=====
+Fix bug: Use array_filter instead of array_unique on flag_lists_template_submit()
+  and flag_lists_template_validate();
+Fix bug: Remove GROUP BY in flag_lists_get_user_flags(). Caused postgres bug.
+Fix bug: flag_lists_insert() db_last_insert_id() used wrong table.
+Fix typos in flag_lists_theme().
+Remove flag_lists link ops from regular flag links.
+Add flag-lists-links to item list in theme_flag_lists_list().
+
+
+Flag lists (Nov. 07, 2010)
+=====
+Update view flags_lists_user_lists
+Add view flag_lists_user_list
+Use views when enabled.
+
+Flag lists (Nov. 07, 2010)
+Show which types are in use in template config form.
+Move key from type to name in flag_list_types *NOT creating update for this.
+Fix template naming. Was not saved correctly to flag_lists_types table.
+Change default template messages to anticipate token use.
+Add token support including list terminology and title.
+Added argument handler for fid. Uses list title for display instead fid.
+
+Flag lists (Oct. 11, 2010)
+=====
+flag_lists_get_user_flags() sets $flag->module = flag_lists for lists, and also
+merges in flag module flags.
+theme_flag_lists_list($node, $create = TRUE, $ops = TRUE, $flags = FALSE) adds
+the $flags boolean, which if TRUE will add flag module flags to the list.
+Invoke hook_flag() in flag_lists_do_flag();
+Add hook_flag_lists($flag, $user) with update and insert ops.
+Add config options to list block.
+Don't return anything to the block if there are no available flags or list
+templates.
+Fix theme_flag_lists_list to use block options.
+Fix bug (wrong variable name) in flag_lists_get_user_flags().
+Fix query in flag_lists_get_user_flags(). Was not loading all list type rows.
+Add list and listing generate fucntionality if devel_generate exists.
+Added $account as argument to a variety of functions where the user may not always
+be the current user.
+
+Flag lists (Sept. 24, 2010)
+=====
+Fix rebuild menu path
+
+Flag lists (Sept. 22, 2010)
+=====
+code cleanup
+fix hook_flag_delete
+Change template names from name_fl_template to fl_template_name.
+Text changes in template form.
+Page title change for template form.
+flag_lists_form will take list fid or name.
+Use fids on list edit links
+change menu paths for edit, delete
+improve some messages
+allow users with "administer flags" permission to bypass flag_lists_is_owner()
+checks.
+First run at views integration
+Better admin table for lists

+ 339 - 0
sites/all/modules/contrib/flag/flag_lists/LICENSE.txt

@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

+ 0 - 0
sites/all/modules/contrib/flag/flag_lists/css/flag_lists_ops.css


+ 599 - 0
sites/all/modules/contrib/flag/flag_lists/flag_lists.admin.inc

@@ -0,0 +1,599 @@
+<?php
+
+/**
+ * @file
+ * Contains administrative pages for creating, editing, and deleting flag lists.
+ */
+
+/**
+ * Flag administration page. Display a list of existing flags.
+ */
+function flag_lists_admin_page() {
+  return theme('flag_lists_admin_page', array('flag' => NULL));
+}
+
+/**
+ * Theme the output for the main flag administration page.
+ */
+function theme_flag_lists_admin_page($variables) {
+  $flag = $variables['flag'];
+
+  drupal_set_title(t('Flag lists'));
+  $output = '<p>' . t('This page shows all the <em>lists</em> that are currently defined on this system.') . '</p>';
+
+  // Can we use our default view?
+  if (module_exists('views')) {
+    $view = views_get_view('flag_lists', FALSE);
+    if (!empty($view)) {
+      $view->set_display('default');
+      $output .= $view->render();
+    }
+  }
+
+  // Else build a simplified display.
+  else {
+    $header = array(
+      array('data' => t('List'), 'field' => 'name'),
+      array('data' => t('List title'), 'field' => 'title'),
+      array('data' => t('List type')),
+      array('data' => t('Owner'), 'field' => 'uid'),
+      array('data' => t('Node types')),
+      array('data' => t('Operations')),
+    );
+    $flags = flag_lists_get_flags(25, $header);
+    foreach ($flags as $flag) {
+      $ops = theme('flag_lists_ops', $flag);
+
+      $name = db_select('users', 'u')
+        ->fields('u', array('name'))
+        ->condition('uid', $flag->uid)
+        ->execute()
+        ->fetchField();
+      $owner = l($name, 'user/' . $flag->uid, array('attributes' => array('title' => t('View user profile.'))));
+      $rows[] = array(
+        $flag->name,
+        $flag->title,
+        $flag->content_type,
+        $owner,
+        $flag->types ? implode(', ', $flag->types) : '-',
+        $ops,
+      );
+    }
+    if (!$flags) {
+      $rows[] = array(
+        array('data' => t('No flags are currently defined.'), 'colspan' => 6),
+      );
+    }
+
+    $output .= theme('table', array('header' => $header, 'rows' => $rows));
+    $output .= theme('pager', NULL, 25, 0);
+  }
+
+  return $output;
+}
+
+function flag_lists_add($type = NULL) {
+  if (is_null($type)) {
+    drupal_access_denied();
+  }
+
+  return drupal_get_form('flag_lists_form', NULL, $type);
+}
+
+/**
+ * Callback for adding new lists through AJAX.
+ */
+function flag_lists_add_js($type = NULL) {
+  if (is_null($type)) {
+    drupal_json_output(array('error' => t('Type not supplied.')));
+    exit();
+  }
+
+  $name = check_plain($_REQUEST['name']);
+  if (!isset($name) || empty($name)) {
+    drupal_json_output(array('error' => t('List name not supplied.')));
+    exit();
+  }
+
+  if (drupal_strlen($name) > 255) {
+    drupal_json_output(array('error' => t('List name is too long. Maximum is 255 characters.')));
+    exit();
+  }
+
+  if (flag_lists_title_exists($name, $type)) {
+    drupal_json_output(array('error' => t('You already have a @name with this name for this type of content.', array('@name' => variable_get('flag_lists_name', t('list'))))));
+    exit();
+  }
+
+  if (!isset($account)) {
+    $account = $GLOBALS['user'];
+  }
+
+  // New flag. Load the template row.
+  $query = db_select('flag', 'f');
+  $query->leftJoin('flag_lists_types', 'fl', 'f.name = fl.name');
+  $query->fields('f')
+    ->fields('fl')
+    ->condition('fl.type', $type);
+  
+  $row = $query->execute()
+    ->fetchObject();
+
+  $newflag = flag_flag::factory_by_entity_type('node');
+
+  $flag = $newflag->factory_by_row($row);
+  // The template fid becomes the flag_lists parent flag.
+  $flag->pfid = $row->fid;
+  // The fid is NULL because this is really a new flag.
+  $flag->fid = NULL;
+  // The name is created in the save function.
+  $flag->name = NULL;
+  $flag->link_type = 'toggle';
+  $flag->title = $name;
+  $flag->types = array($type);
+  $flag->uid = $account->uid;
+  flag_lists_set_messages($flag);
+
+  // Save it.
+  flag_lists_save($flag, $account);
+
+  drupal_json_output(array('error' => '', 'flag' => $flag));
+}
+
+/**
+ * Form to Add or edit a list.
+ */
+function flag_lists_form($form, $form_state, $name = NULL, $type = NULL) {
+  // First some sanity checks. $name and $type can't both be NULL.
+  // There must be a template for this content type.
+  if (is_null($name) && is_null($type)) {
+    drupal_access_denied();
+  }
+  if (!flag_lists_template_exists($type) && is_null($name)) {
+    return;
+  }
+  // If name is numeric, then we have the fid, so get the name.
+  if (is_numeric($name)) {
+    $name = db_select('flag_lists_flags', 'f')
+      ->fields('f', array('name'))
+      ->condition('fid', $name)
+      ->execute()
+      ->fetchField();
+  }
+  // Adding a new list.
+  if (!isset($name)) {
+    drupal_set_title(t('Add a new list'));
+    $form['edit'] = array(
+      '#type' => 'hidden',
+      '#value' => FALSE,
+    );
+  }
+
+  // Editing an existing list.
+  else {
+    $flag = flag_lists_get_flag($name);
+
+    $title_string_name = variable_get('flag_lists_name', 'list');
+    $title_string = t('Edit your "@title" @name title', array('@title' => $flag->get_title(), '@name' => $title_string_name));
+    drupal_set_title();
+    
+    $form['edit'] = array(
+      '#type' => 'hidden',
+      '#value' => TRUE,
+    );
+    $form['name'] = array(
+      '#type' => 'hidden',
+      '#value' => $name,
+    );
+  }
+
+  $form['title'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Title'),
+    '#default_value' => empty($flag->title) ? '' : $flag->title,
+    '#description' => t('A short, descriptive title for this @name list. Limit to 255 characters.', array('@name' => variable_get('flag_lists_name', t('list')))),
+    '#maxlength' => 255,
+    '#required' => TRUE,
+    '#access' => empty($flag->locked['title']),
+    '#weight' => -2,
+  );
+  $form['type'] = array(
+    '#type' => 'hidden',
+    '#value' => $type,
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+  return $form;
+}
+
+/**
+ * Validate a list.
+ */
+function flag_lists_form_validate($form, $form_state) {
+  // Ensure 255 charactor or less name.
+  if (drupal_strlen($form_state['values']['title']) > 255) {
+    form_set_error('name', t('The @name title may only be 255 characters long.', array('@name' => variable_get('flag_lists_name', t('list')))));
+  }
+  // Ensure the machine name is unique.
+  if (!$form_state['values']['edit']) {
+    if (flag_lists_title_exists($form_state['values']['title'], $form_state['values']['type'])) {
+      form_set_error('title', t('You already have a @name with this name for this type of content.', array('@name' => variable_get('flag_lists_name', t('list')))));
+    }
+  }
+}
+
+/**
+ * Save a list.
+ */
+function flag_lists_form_submit($form, $form_state, $account = NULL) {
+  if (!isset($account)) {
+    $account = $GLOBALS['user'];
+  }
+
+  if (!empty($form_state['values']['edit'])) {
+    // Editing the title.
+    $flag = flag_lists_get_flag($form_state['values']['name']);
+    $flag->title = $form_state['values']['title'];
+    flag_lists_set_messages($flag);
+    flag_lists_save($flag);
+    _flag_lists_clear_cache();
+  }
+  else {
+    // New flag. Load the template row.
+    $type = $form_state['values']['type'];
+    $query = db_select('flag', 'f');
+    $query->leftJoin('flag_lists_types', 'fl', 'f.name = fl.name');
+    $query->fields('f')
+      ->fields('fl')
+      ->condition('fl.type', $type);
+    
+    $row = $query->execute()
+      ->fetchObject();
+
+    $newflag = flag_flag::factory_by_entity_type('node');
+
+    $flag = $newflag->factory_by_row($row);
+    // The template fid becomes the flag_lists parent flag.
+    $flag->pfid = $row->fid;
+    // The fid is NULL because this is really a new flag.
+    $flag->fid = NULL;
+    // The name is created in the save function.
+    $flag->name = NULL;
+    $flag->link_type = 'toggle';
+    $flag->title = $form_state['values']['title'];
+    $flag->types = array($type);
+    $flag->uid = $account->uid;
+    flag_lists_set_messages($flag);
+    // Save it.
+    flag_lists_save($flag, $account);
+  }
+}
+
+/**
+ * Flag lists settings page.
+ */
+function flag_lists_settings_form($form, $form_state) {
+  drupal_set_title(t('Flag lists settings'));
+  $form['text'] = array(
+    '#title' => t('Using flag lists'),
+    '#markup' => t('Flag lists allow users to create their own personal flags.
+      No user can add to another user\'s lists. Lists inherit their
+      settings from template flags, which exist as flags in the flags\' module.'
+    ),
+  );
+
+  $form['flag_lists_name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Substitute "list" with your own terminology'),
+    '#default_value' => variable_get('flag_lists_name', t('list')),
+    '#description' => t('You can choose to use another name for "list", such as "favorites" or "bookmarks". Lowercase and plural names usually work best.'),
+    '#required' => TRUE,
+  );
+  $form['rebuild'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Global rebuild'),
+    '#description' => t('Changes to list templates and  settings normally apply
+      to only newly created flags. However, you can globally apply changes here.
+      First adjust the settings above and the list templates and save them. Then
+      click the link below. This will change ALL existing flag lists. It cannot
+      be undone.'),
+    '#tree' => FALSE,
+  );
+  $form['rebuild']['global_rebuild'] = array(
+    '#markup' => l(t('Rebuild all flag lists.'), FLAG_ADMIN_PATH . '/flag-lists/rebuild'),
+  );
+
+  return system_settings_form($form);
+}
+
+/**
+ * Confirm global settings rebuild.
+ */
+function flag_lists_rebuild_confirm($form, $form_state) {
+  return confirm_form($form,
+    t('Are you sure you want to rebuild all flag lists?'),
+    FLAG_ADMIN_PATH . '/lists/settings',
+    t('This action cannot be undone.'),
+    t('Rebuild'), t('Cancel')
+  );
+}
+
+/**
+ * Confirm global settings rebuild.
+ */
+function flag_lists_rebuild_confirm_submit($form, $form_state) {
+  flag_lists_rebuild();
+  drupal_set_message(t('All flag lists have been rebuilt.'));
+  drupal_goto(FLAG_ADMIN_PATH . '/lists/settings');
+}
+
+/**
+ * Delete flag lists page.
+ */
+function flag_lists_delete_confirm($form, $form_state, $name) {
+  $flag = flag_lists_get_flag($name);
+  if (empty($flag)) {
+    drupal_goto();
+  }
+
+  $form['fid'] = array('#type' => 'value', '#value' => $flag->fid);
+
+  return confirm_form($form,
+    t('Are you sure you want to delete %title?', array('%title' => $flag->get_title())),
+    isset($_GET['destination']) ? $_GET['destination'] : '/',
+    t('This action cannot be undone.'),
+    t('Delete'), t('Cancel')
+  );
+}
+
+function flag_lists_delete_confirm_submit($form, &$form_state) {
+  $flag = flag_lists_get_flag($form_state['values']['fid']);
+  if ($form_state['values']['confirm']) {
+    flag_lists_fl_delete($flag);
+  }
+}
+
+/**
+ * Form to create a new template.
+ */
+function flag_lists_create_template_form($form, $form_state) {
+  drupal_set_title(t('Add a new list template'));
+  $form['help'] = array(
+    '#value' => t('This form creates a new, blank list template. After saving, you will be able to configure further options.'),
+  );
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Template name'),
+    '#description' => t('The machine-name for this template. It may be up to 32 characters long and my only contain lowercase letters, underscores, and numbers.'),
+    '#maxlength' => 255,
+    '#required' => TRUE,
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+  return $form;
+}
+
+/**
+ * New template validation.
+ */
+function flag_lists_create_template_form_validate($form, &$form_state) {
+  // Ensure a safe machine name.
+  if (!preg_match('/^[a-z_][a-z0-9_]*$/', $form_state['values']['name'])) {
+    form_set_error('name', t('The flag name may only contain lowercase letters, underscores, and numbers.'));
+  }
+  // Ensure 32 charactor or less name.
+  if (drupal_strlen($form_state['values']['name']) > 32) {
+    form_set_error('name', t('The flag name may only be 32 characters long.'));
+  }
+  // Ensure the machine name is unique.
+  $flag = flag_get_flag('fl_template_' . $form_state['values']['name']);
+  if ($flag) {
+    form_set_error('name', t('Flag names must be unique. This flag name is already in use.'));
+  }
+}
+
+/**
+ * New template submit.
+ */
+function flag_lists_create_template_form_submit($form, &$form_state) {
+  $template = flag_lists_flag_default_flags('fl_template_' . $form_state['values']['name']);
+  $flag = flag_flag::factory_by_array($template[0]);
+  $flag->title = t('List template') . ' ' . $form_state['values']['name'];
+  $flag->save();
+  // Enter the new template into flag_lists_types.
+  db_insert('flag_lists_types')
+    ->fields(array(
+      'name' => $flag->name,
+    ))
+    ->execute();
+  $form_state['redirect'] = FLAG_ADMIN_PATH . '/edit/' . $flag->name;
+}
+
+
+
+/**
+ * Developer tool to generate dummy lists and listings.
+ */
+
+// @todo use batch api.
+function flag_lists_generate_lists_form() {
+  $templates = flag_lists_get_templates();
+  $options = array();
+  foreach ($templates as $template) {
+    $options[$template->fid] = $template->name . ' (' . implode(', ', $template->types) . ')';
+  }
+  $form['templates'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Generate lists and/or listings for the following templates.'),
+    '#options' => $options,
+  );
+
+  $form['lists'] = array(
+    '#type' => 'textfield',
+    '#title' => t('How many lists should be generated?'),
+    '#default_value' => '0',
+    '#size' => 7,
+    '#maxlength' => 7,
+  );
+
+  $form['listings'] = array(
+    '#type' => 'textfield',
+    '#title' => t('How many listings should be generated?'),
+    '#default_value' => '0',
+  );
+
+  $form['kill_lists'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Delete ALL existing lists and listings before generating new ones? Templates will not be deleted.'),
+    '#default_value' => FALSE,
+  );
+  $form['kill_listings'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Delete ALL existing listings before generating new ones? (Lists are not deleted unless the above is checked.)'),
+    '#default_value' => FALSE,
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Do it!'),
+  );
+  return $form;
+}
+
+/**
+ * Validation handler for flag_lists_generate_lists_form.
+ */
+function flag_lists_generate_lists_form_validate($form, &$form_state) {
+  if ($form_state['values']['lists'] && !is_numeric($form_state['values']['lists']) || $form_state['values']['lists'] < 0) {
+    form_set_error('lists', t('Number of lists to generate must be a number, 1 or more.'));
+  }
+  if ($form_state['values']['listings'] && !is_numeric($form_state['values']['listings']) || $form_state['values']['listings'] < 0) {
+    form_set_error('listings', t('Number of listings to generate must be a number, 1 or more.'));
+  }
+  if ($form_state['values']['lists'] > 0 && !count(array_filter($form_state['values']['templates']))) {
+    form_set_error('templates', t('You must select at least 1 template for the lists to be genereated'));
+  }
+  if ($form_state['values']['listings'] > 0 && !count(array_filter($form_state['values']['templates']))) {
+    form_set_error('templates', t('You must select at least 1 template for the listings to be genereated'));
+  }
+}
+
+/**
+ * Submit handler for flag_lists_generate_lists_form.
+ */
+function flag_lists_generate_lists_form_submit($form, &$form_state) {
+  global $user;
+  module_load_include('inc', 'devel_generate');
+
+  // Delete listings.
+  if ($form_state['values']['kill_listings']) {
+      $flags = flag_lists_get_flags();
+    foreach ($flags as $flag) {
+      $result = db_select('flag_lists_content', 'f')
+        ->fields('f', array('fcid', 'content_id'))
+        ->condition('fid', $flag->fid)
+        ->execute();
+
+      foreach ($result as $row) {
+        db_delete('flag_lists_content')->condition('fid', $flag->fid)->execute();
+        db_delete('flag_lists_counts')->condition('fid', $flag->fid)->execute();
+
+        module_invoke_all('flag', 'unflag', $flag, $row->content_id, $account, $row->fcid);
+      }
+    }
+    drupal_set_message(t('All listings were deleted.'));
+  }
+
+  // Delete lists and listings.
+  if ($form_state['values']['kill_lists']) {
+    // If we loaded all flags above, don't reload them here.
+    if (!count($flags)) {
+      $flags = flag_lists_get_flags();
+    }
+    foreach ($flags as $flag) {
+      flag_lists_fl_delete($flag, $user);
+    }
+    drupal_set_message(t('All lists and their listings were deleted.'));
+  }
+
+
+  $templates = array_filter($form_state['values']['templates']);
+  $uids = array_filter(devel_get_users()); // Don't use the anon user.
+
+  // Generate lists.
+  if ($form_state['values']['lists'] && count($templates)) {
+    for ($i = 1; $i <= $form_state['values']['lists']; $i++ ) {
+      $template = flag_get_flag(NULL, array_rand($templates));
+      $account->uid = $uids[array_rand($uids)];
+      $edit['values']['title'] = devel_create_greeking(7, TRUE);
+      $edit['values']['type'] = $template->types[array_rand($template->types)];
+      $form = array();
+      flag_lists_form_submit($form, $edit, $account);
+    }
+  drupal_set_message(t('@lists created.', array('@lists' => format_plural($form_state['values']['lists'], '1 list', '@count lists'))));
+  }
+
+  // Generate listings.
+  if ($form_state['values']['listings']) {
+
+    $count = 0;
+
+    for ($i = 1; $i <= $form_state['values']['listings']; $i++ ) {
+      $account->uid = $uids[array_rand($uids)];
+      $lists = flag_lists_get_user_flags(NULL, $account);
+
+      // Remove any lists that don't use the chosen templates.
+      foreach ($lists as $key => $list) {
+       if (!isset($templates[$list->pfid])) {
+        unset($lists[$key]);
+        }
+      }
+
+      // Ensure user has lists.
+      if (!count($lists)) {
+        continue;
+      }
+
+      $list = $lists[array_rand($lists)];
+      $content_type = $list->types[array_rand($list->types)];
+
+      // We get the random nid with 2 SELECTS to avoid slow ORDER BY Rand().
+      // Get max nid for our content type.
+      $query = db_select('node')
+        ->condition('type', $content_type);
+      $query->addExpression('MAX(nid)', 'max');
+      $max_nid = $query->execute()->fetchField();
+
+      // Ensure a node exists for the type.
+      if (!$max_nid) {
+        continue;
+      }
+
+      $r = rand(1, $max_nid);
+      $content_id = db_select('node', 'n')
+        ->fields('n', array('nid'))
+        ->condition('type', $content_type)
+        ->condition('nid', $r)
+        ->range(0, 1)
+        ->execute()
+        ->fetchField();
+
+      // We can't assume that every attempt will result in a listing because
+      // we may have a node type with no nodes yet or a user with no lists.
+      // Also, if a listing already exists, we count it, but it can only be in
+      // the db once.
+      if (flag_lists_do_flag($list, 'flag', $content_id, $account, TRUE)) {
+        $count++;
+      }
+    }
+  drupal_set_message(t('@listings listed.', array('@listings' => format_plural($count, '1 node', '@count nodes'))));
+  if ($count < $form_state['values']['listings']) {
+    drupal_set_message(t('Listings are generated randomly. Occassionally a listing will not be created if the random user has no lists or if the node type to be listed has no nodes.'));
+  }
+  }
+}
+
+

+ 27 - 0
sites/all/modules/contrib/flag/flag_lists/flag_lists.info

@@ -0,0 +1,27 @@
+name = Flag lists
+core = 7.x
+package = Flags
+dependencies[] = flag
+dependencies[] = token
+
+files[] = flag_lists.admin.inc
+files[] = flag_lists.module
+files[] = flag_lists.install
+files[] = includes/flag_lists.views.inc
+files[] = includes/flag_lists.views_default.inc
+files[] = includes/flag_lists_handler_argument_fid.inc
+files[] = includes/flag_lists_handler_field_list.inc
+files[] = includes/flag_lists_handler_field_list_delete.inc
+files[] = includes/flag_lists_handler_field_list_edit.inc
+files[] = includes/flag_lists_handler_field_ops.inc
+files[] = includes/flag_lists_handler_field_template.inc
+files[] = includes/flag_lists_handler_field_template_types.inc
+files[] = includes/flag_lists_handler_filter_template.inc
+
+description = Allows users to create personal flag lists.
+; Information added by drupal.org packaging script on 2012-05-03
+version = "7.x-1.1"
+core = "7.x"
+project = "flag_lists"
+datestamp = "1336060255"
+

+ 207 - 0
sites/all/modules/contrib/flag/flag_lists/flag_lists.install

@@ -0,0 +1,207 @@
+<?php
+
+/**
+ * @file
+ * The Flag lists module install file.
+ */
+
+ /**
+ * Implementation of hook_install().
+ */
+function flag_lists_schema() {
+  $schema = array();
+  $schema['flag_lists_flags'] = array(
+    'fields' => array(
+      'fid' => array(
+        'type' => 'serial',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'pfid' => array(
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'uid' => array(
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'entity_type' => array(
+        'type' => 'varchar',
+        'length' => '32',
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'name' => array(
+        'type' => 'varchar',
+        'length' => '32',
+        'not null' => FALSE,
+        'default' => '',
+      ),
+      'title' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => FALSE,
+        'default' => '',
+      ),
+      'options' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+      ),
+    ),
+    'primary key' => array('fid'),
+    'unique keys' => array(
+      'name' => array('name'),
+    ),
+  );
+  $schema['flag_lists_content'] = array(
+    'fields' => array(
+      'fcid' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'fid' => array(
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'entity_type' => array(
+        'type' => 'varchar',
+        'length' => '32',
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'entity_id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'uid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'sid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'timestamp' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'disp-size' => 11,
+      )
+    ),
+    'primary key' => array('fcid'),
+    'unique keys' => array(
+      'fid_entity_id_uid_sid' => array('fid', 'entity_id', 'uid', 'sid'),
+    ),
+    'indexes' => array(
+      'entity_type_entity_id' => array('entity_type', 'entity_id'),
+      'entity_type_uid_sid' => array('entity_type', 'uid', 'sid'),
+    ),
+  );
+  $schema['flag_lists_counts'] = array(
+    'fields' => array(
+      'fid' => array(
+        'type' => 'int',
+        'size' => 'small',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'entity_type' => array(
+        'type' => 'varchar',
+        'length' => '32',
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'entity_id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'disp-width' => '10',
+      ),
+      'count' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'disp-width' => '10',
+      )
+    ),
+    'primary key' => array('fid', 'entity_id'),
+    'indexes' => array(
+      'fid_entity_type' => array('fid', 'entity_type'),
+      'entity_type_entity_id' => array('entity_type', 'entity_id'),
+      'count' => array('count'),
+    ),
+  );
+  $schema['flag_lists_types'] = array(
+    'fields' => array(
+      'name' => array(
+        'type' => 'varchar',
+        'length' => '32',
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'type' => array(
+        'type' => 'varchar',
+        'length' => '32',
+        'not null' => FALSE,
+        'default' => '')
+    ),
+    'primary key' => array('name', 'type'),
+    'indexes' => array(
+      'name' => array('name'),
+    ),
+  );
+  return $schema;
+}
+
+/**
+ * Implements hook_install().
+ */
+function flag_lists_install() {
+  // Set up our default template.
+  db_insert('flag_lists_types')
+    ->fields(array(
+      'name' => 'fl_template',
+    ))
+    ->execute();
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function flag_lists_uninstall() {
+  // Remove our template flags.
+  $query = db_select('flag_lists_types', 'fl');
+  $query->leftJoin('flag', 'f', 'fl.name = f.name');
+  $query->addField('fl', 'fid', 'fid');
+  $query->distinct();
+  $fids = $query->execute();
+
+  foreach ($fids as $fid) {
+    db_delete('flag')->condition('fid', $fid->fid);
+    db_delete('flag_content')->condition('fid', $fid->fid);
+    db_delete('flag_types')->condition('fid', $fid->fid);
+    db_delete('flag_counts')->condition('fid', $fid->fid);
+  }
+
+  db_delete('variable')->condition('name', 'flag_lists%', 'LIKE');
+  drupal_set_message(t('Flag lists has been uninstalled.'));
+}

+ 1737 - 0
sites/all/modules/contrib/flag/flag_lists/flag_lists.module

@@ -0,0 +1,1737 @@
+<?php
+
+module_load_include('inc', 'flag', 'includes/flag.admin');
+module_load_include('inc', 'flag', 'flag');
+
+/**
+ * @file
+ * The Flag Lists module.
+ *
+ * Extends flag to allow individual users to create personal flags.
+ */
+
+/**
+ * Implementation of hook_menu().
+ */
+function flag_lists_menu() {
+  $items = array();
+  $items[FLAG_ADMIN_PATH . '/lists'] = array(
+    'title' => 'Lists',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('flag_lists_settings_form'),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer flags'),
+    'description' => 'Configure default settings allowing users to mark content with personal flags.',
+    'file' => 'flag_lists.admin.inc',
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 100,
+  );
+  $items[FLAG_ADMIN_PATH . '/lists/settings'] = array(
+    'title' => 'Settings',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('flag_lists_settings_form'),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer flags'),
+    'description' => 'Configure default settings allowing users to mark content with personal flags.',
+    'file' => 'flag_lists.admin.inc',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => 1,
+  );
+  $items[FLAG_ADMIN_PATH . '/lists/list'] = array(
+    'title' => 'List',
+    'page callback' => 'flag_lists_admin_page',
+    'access callback' => 'user_access',
+    'access arguments' => array('administer flags'),
+    'file' => 'flag_lists.admin.inc',
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 2,
+  );
+  $items[FLAG_ADMIN_PATH . '/lists/template'] = array(
+    'title' => 'New template',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('flag_lists_create_template_form'),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer flags'),
+    'file' => 'flag_lists.admin.inc',
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 3,
+  );
+  if (module_exists('devel_generate')) {
+    $items['admin/config/development/generate/flag-lists'] = array(
+      'title' => 'Generate lists',
+      'description' => 'Generate a given number of lists and listings on site content. Optionally delete existing lists and listings.',
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('flag_lists_generate_lists_form'),
+      'access callback' => 'user_access',
+      'access arguments' => array('administer flags'),
+      'file' => 'flag_lists.admin.inc',
+    );
+  }
+  $items['flag-lists/add/%'] = array(
+    'title' => 'Add a list',
+    'page callback' => 'flag_lists_add',
+    'page arguments' => array(2),
+    'access callback' => 'user_access',
+    'access arguments' => array('create flag lists'),
+    'file' => 'flag_lists.admin.inc',
+    'type' => MENU_NORMAL_ITEM,
+  );
+  // Callback for adding a new list through JS
+  $items['flag-lists/add/%/js'] = array(
+    'title' => 'Add a list',
+    'page callback' => 'flag_lists_add_js',
+    'page arguments' => array(2),
+    'access callback' => 'user_access',
+    'access arguments' => array('create flag lists'),
+    'file' => 'flag_lists.admin.inc',
+    'type' => MENU_CALLBACK,
+  );
+
+  $items['flags/lists/edit/%'] = array(
+    'title' => 'Edit a list',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('flag_lists_form', 3),
+    'access callback' => 'flag_lists_is_owner',
+    'access arguments' => array(2, 3),
+    'file' => 'flag_lists.admin.inc',
+    'type' => MENU_CALLBACK,
+  );
+  $items['flags/lists/delete/%'] = array(
+    'title' => 'Delete a list',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('flag_lists_delete_confirm', 3),
+    'access callback' => 'flag_lists_is_owner',
+    'access arguments' => array(2, 3),
+    'file' => 'flag_lists.admin.inc',
+    'type' => MENU_CALLBACK,
+  );
+  $items[FLAG_ADMIN_PATH . '/flag-lists/rebuild'] = array(
+    'title' => 'Rebuild all flag lists',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('flag_lists_rebuild_confirm'),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer flag lists'),
+    'file' => 'flag_lists.admin.inc',
+    'type' => MENU_CALLBACK,
+  );
+  $items['flag-lists'] = array(
+    'title' => 'Flag',
+    'page callback' => 'flag_lists_page',
+    'access callback' => 'user_access',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+
+  $items['user/%user/flags/lists'] = array(
+    'title' => ucfirst(variable_get('flag_lists_name', 'list')),
+    'page callback' => 'flag_lists_user_page',
+    'page arguments' => array(1),
+    'access callback' => 'user_access',
+    'access arguments' => array('view flag lists'),
+    'type' => MENU_LOCAL_TASK,
+  );
+  $items['user/%user/flags/lists/%'] = array(
+    'title' => ucfirst(variable_get('flag_lists_name', 'list')) . ' content',
+    'page callback' => 'flag_lists_user_list',
+    'page arguments' => array(1, 4),
+    'access callback' => 'user_access',
+    'access arguments' => array('view flag lists'),
+    'type' => MENU_CALLBACK,
+  );
+  return $items;
+}
+
+/**
+ * User flag page. Display a list of user-created flag lists.
+ */
+function flag_lists_user_page($user) {
+    // Can we use our default view?
+  if (module_exists('views')) {
+    $view = views_get_view('flag_lists_user_lists', FALSE);
+    if (!empty($view)) {
+      $view->set_display('default');
+      $view->set_arguments(array($user->uid));
+      $output = $view->render();
+      drupal_set_title(str_replace(array_keys($view->build_info['substitutions']), $view->build_info['substitutions'], $view->build_info['title']));
+    }
+    return $output;
+  }
+  else {
+    return theme('flag_lists_user_page', array('uid' => $user->uid));
+  }
+}
+
+/**
+ * Theme the output for a user flag administration page.
+ */
+function theme_flag_lists_user_page($variables) {
+  $uid = $variables['uid'];
+
+  $account = user_load($uid);
+  drupal_set_title(t('Lists'));
+  if ($flags = flag_lists_get_user_flags(NULL, $account)) {
+    // Build the list of flag lists for this node.
+    foreach ($flags as $flag) {
+      $ops = theme('flag_lists_ops', array('flag' => $flag));
+      $items[] = l($flag->title, "user/$uid/flags/lists/" . $flag->fid) . $ops;
+    }
+  }
+  drupal_add_css(drupal_get_path('module', 'flag_lists') . '/theme/flag_lists.css');
+  return theme('item_list', array('items' => $items));
+}
+
+/**
+ * List the contents of a user-defined list
+ */
+function flag_lists_user_list($user, $fid) {
+  $uid = $user->uid;
+    // Can we use our default view?
+  if (module_exists('views')) {
+    $view = views_get_view('flag_lists_user_list', FALSE);
+    if (!empty($view)) {
+      $view->set_display('default');
+      $view->set_arguments(array($fid));
+      $output = $view->render();
+      drupal_set_title(str_replace(array_keys($view->build_info['substitutions']), $view->build_info['substitutions'], $view->build_info['title']));
+    }
+    return $output;
+  }
+
+  else {
+    return theme('flag_lists_user_list', array('uid' => $uid, 'fid' => $fid));
+  }
+}
+
+/**
+ * Theme the output of user-defined list page
+ */
+function theme_flag_lists_user_list($variables) {
+  $uid = $variables['uid'];
+  $fid = $variables['fid'];
+
+  $flag = flag_lists_get_flag($fid);
+  drupal_set_title($flag->title);
+  $content = flag_lists_get_flagged_content($fid, $uid);
+  foreach ($content as $item) {
+    if ($item->content_type == 'node') {
+      $node = node_load($item->entity_id);
+      $items[] = l($node->title, 'node/' . $node->nid);
+    }
+  }
+
+  $breadcrumb = menu_get_active_breadcrumb();
+  $breadcrumb[] = l(t('@name lists', array('@name' => drupal_ucfirst(variable_get('flag_lists_name', t('lists'))))), 'user/' . arg(1) . '/flags/lists');
+  drupal_set_breadcrumb($breadcrumb);
+  return theme('item_list', array('items' => $items));
+}
+
+/**
+ * Implementation of hook_theme().
+ */
+function flag_lists_theme() {
+  $path = drupal_get_path('module', 'flag') . '/theme';
+
+  return array(
+    'flag_lists_list' => array(
+      'variables' => array('node' => NULL, 'create' => NULL, 'ops' => NULL, 'use_flags' => NULL),
+    ),
+    'flag_lists_admin_page' => array(
+      'variables' => array('flags' => NULL),
+    ),
+    'flag_lists_user_page' => array(
+      'variables' => array('uid' => NULL),
+    ),
+    'flag_lists_user_list' => array(
+      'variables' => array('flag_name' => NULL),
+    ),
+    'flag_lists_ops' => array(
+      'variables' => array('flag' => NULL),
+    )
+  );
+}
+
+/**
+ * Implementation of hook_permission().
+ */
+function flag_lists_permission() {
+  return array(
+    'create flag lists' => array(
+      'title' => t('Create flag lists'),
+      'description' => t(''),
+    ),
+    'edit own flag lists' => array(
+      'title' => t('Edit own flag lists'),
+      'description' => t(''),
+    ),
+    'delete own flag lists' => array(
+      'title' => t('Delete own flag lists'),
+      'description' => t(''),
+    ),
+    'view flag lists' => array(
+      'title' => t('View flag lists'),
+      'description' => t(''),
+    ));
+}
+
+/**
+ * Implementation of hook_form_alter().
+ */
+function flag_lists_form_alter(&$form, &$form_state, $form_id) {
+  switch ($form_id) {
+    case 'flag_form':
+      // A template flag should always have a record in the flag_lists_types table.
+      $result = db_select('flag_lists_types', 'f')->fields('f')->execute();
+      foreach ($result as $type) {
+        $types[$type->name] = $type->type;
+      }
+
+      if (isset($types[$form['name']['#default_value']])) {
+        $form['name']['#type'] = 'value';
+        $form['global']['#type'] = 'value';
+        $form['title']['#description'] = t('A short, descriptive title for this template. It will be used in administrative interfaces to refer to this template.');
+
+        // Warn about types that already have a template.
+        foreach ($form['access']['types']['#options'] as $option => $value) {
+          if (in_array($option, $types) && $form['access']['types']['#default_value'] != $option) {
+            $form['access']['types']['#options'][$option] .= '<span class="description">' . t('(Already has a template.)') . '</span>';
+          }
+        }
+        $form['access']['types']['#description'] .= t('A type may only be selected in one list template.');
+
+        // Unset anon permissions for now. @todo allow anon listing.
+        unset($form['access']['roles']['flag']['#options'][1]);
+        unset($form['access']['roles']['unflag']['#options'][1]);
+
+        foreach (element_children($form['display']) as $display) {
+          $form['display'][$display]['#type'] = 'value';
+        }
+        $form['display']['link_type']['#default_value'] = 'fl_template';
+        $form['display']['#description'] = t('Unlike normal flags, lists are only displayed in a block provided by this module or in views blocks. See <a href="/admin/build/block/list">the block admin page</a> to place the block.');
+
+        $form['#validate'][] = 'flag_lists_template_validate';
+        $form['#submit'][] = 'flag_lists_template_submit';
+      }
+    break;
+
+    case 'views_exposed_form':
+      // Force the exposed filters to perform actions on the page itself because
+      // the views default viwe didn't come with a page display
+      if ($form['#id'] == 'views-exposed-form-flag-lists-default') {
+        $form['#action'] = '/' . implode('/', arg());
+      }
+    break;
+  }
+
+  // Flag lists operations related changes
+  if (strpos($form_id, 'views_form_') === 0) {
+    $flo = _flag_lists_ops_get_field($form_state['build_info']['args'][0]);
+
+    // Not a FLO-enabled views form.
+    if (empty($flo)) {
+      return;
+    }
+
+    // Add FLO's custom callbacks.
+    $form['#validate'][] = 'flag_lists_ops_form_validate';
+    $form['#submit'][] = 'flag_lists_ops_form_submit';
+
+    // Allow FLO to work when embedded using views_embed_view(), or in a block.
+    if (empty($flo->view->override_path)) {
+      if (!empty($flo->view->preview) || $flo->view->display_handler instanceof views_plugin_display_block) {
+        $flo->view->override_path = $_GET['q'];
+      }
+    }
+
+    // Quickfix for FLO & exposed filters using ajax. See http://drupal.org/node/1191928.
+    $query = drupal_get_query_parameters($_GET, array('q'));
+    $form['#action'] = url($flo->view->get_url(), array('query' => $query));
+
+    // Add basic FLO functionality.
+    if ($form_state['step'] == 'views_form_views_form') {
+      $form = flag_lists_ops_form($form, $form_state, $flo);
+    }
+  }
+}
+
+/**
+ * Add the Flag list select menu widget.
+ */
+function flag_lists_ops_form($form, &$form_state, $flo) {
+  $form['#attached']['js'][] = drupal_get_path('module', 'flag_lists') . '/js/flag_lists_ops.js';
+  $form['#attached']['css'][] = drupal_get_path('module', 'flag_lists') . '/css/flag_lists_ops.css';
+  $form['#prefix'] = '<div class="flo-views-form">';
+  $form['#suffix'] = '</div>';
+
+  $form_state['flo_operation'] = $flo->options['flo']['operation'];
+
+  // Force browser to reload the page if Back is hit.
+  if (preg_match('/msie/i', $_SERVER['HTTP_USER_AGENT'])) {
+    drupal_add_http_header('Cache-Control', 'no-cache'); // works for IE6+
+  }
+  else {
+    drupal_add_http_header('Cache-Control', 'no-store'); // works for Firefox and other browsers
+  }
+
+  global $user;
+  global $base_url;
+  $account = user_load($user->uid);
+  $items = array();
+  if ($flags = flag_lists_get_user_flags(NULL, $account)) {
+    // Build the list of flag lists for this node.
+    foreach ($flags as $flag) {
+      $items[((string)$flag->fid)] = $flag->title;
+    }
+  }
+
+  // Group items into a fieldset for easier theming.
+  $form['flag_lists_' . $form_state['flo_operation']] = array(
+    '#type' => 'fieldset',
+    '#title' => t('List operations'),
+    '#tree' => TRUE,
+    '#attributes' => array('class' => array('flag-lists-ops-fieldset')),
+  );
+  switch ($flo->options['flo']['operation']) {
+    case 'unflag':
+      $null_text = 'Remove from a list';
+      $operation = 'unflag';
+      $form['flag_lists_' . $form_state['flo_operation']]['list'] = array(
+        '#type' => 'button',
+        '#value' => t('Remove from list'),
+        '#ajax' => array(
+          'callback' => 'flag_lists_ops_form_ajax_callback',
+          'wrapper' => 'flag-list-ops-container-' . $flo->options['flo']['operation'],
+        ),
+      );
+      break;
+    default:
+      $null_text = 'Add to a list';
+      $operation = 'flag';
+      drupal_add_library('system', 'ui.dialog');
+      $form['flag_lists_' . $form_state['flo_operation']]['list'] = array(
+        '#type' => 'select',
+        '#options' => array('0' => t('- ' . $null_text . ' -')) + $items,
+        '#default_value' => '0',
+        '#ajax' => array(
+         'callback' => 'flag_lists_ops_form_ajax_callback',
+         'wrapper' => 'flag-list-ops-container-' . $flo->options['flo']['operation'],
+        ),
+        '#attributes' => array(
+          'class' => array(
+            'flag-lists-ops-dropdown',
+          ),
+        ),
+      );
+
+      // Add the necessary JS for creating a new list via AJAX
+      $result = db_select('flag_lists_types')
+        ->fields('flag_lists_types')
+        ->execute();
+      $list_types = array();
+      foreach ($result as $row) {
+        if (!empty($row->type)) {
+          $list_types[] = $row->type;
+        }
+      }
+      drupal_add_js(array('flag_lists' => array('types' => $list_types, 'json_path' => $base_url . '/flag-lists/add/%/js')), 'setting');
+      break;
+  }
+
+  // Get the $ops from the originating form.
+  if (!empty($form_state['values']['flag_lists_' . $form_state['flo_operation']]['list'])) {
+    $list = $form_state['values']['flag_lists_' . $form_state['flo_operation']]['list'];
+  }
+  if (!empty($_REQUEST['flag_lists_ops'])) {
+    $ops = $_REQUEST['flag_lists_ops'];
+  }
+  if (!empty($ops) && !empty($list) && $form_state['values']['flag_lists_' . $form_state['flo_operation']]['operation'] == 'unflag') {
+    $hidden_deleted_values = '';
+    foreach ($ops as $nid) {
+      $hidden_deleted_values .= '<input type="hidden" class="flo-deleted-value" value="' . $nid . '" />';
+    }
+  }
+
+  $form['flag_lists_' . $form_state['flo_operation']]['operation'] = array(
+    '#type' => 'hidden',
+    '#value' => $operation,
+  );
+  $form['flag_lists_' . $form_state['flo_operation']]['go'] = array(
+    '#type' => 'submit',
+    '#value' => t('Go'),
+    '#attributes' => array(
+      'class' => array('flag-lists-ops-go'),
+    ),
+  );
+  unset($form['actions']['submit']);
+
+  // Generate a status message for AJAX submission.
+  $form['flag_lists_' . $form_state['flo_operation']]['status_message'] = array('#markup' => '');
+  $form['flag_lists_' . $form_state['flo_operation']]['#prefix'] = '<div id="flag-list-ops-container-' . $flo->options['flo']['operation'] . '">';
+  $form['flag_lists_' . $form_state['flo_operation']]['#suffix'] = (!empty($hidden_deleted_values)) ? $hidden_deleted_values : '' . '</div>';
+
+  return $form;
+}
+
+function flag_lists_ops_form_ajax_callback($form, $form_state) {
+  // The form has already been submitted and updated. We can return the replaced
+  // item as it is.
+  if (!flag_lists_ops_form_validate($form, $form_state)) {
+    $message = flag_lists_ops_form_submit($form, $form_state);
+  }
+
+  $form['flag_lists_' . $form_state['flo_operation']]['status_message']['#markup'] = '<div class="alert alert-success">' . $message . '</div>';
+  if ($form_state['flo_operation'] == 'flag') $form['flag_lists_' . $form_state['flo_operation']]['list']['#value'] = '0';
+  $form['flag_lists_' . $form_state['flo_operation']]['status_message']['#attributes']['class'][] = 'alert-success';
+
+  return $form['flag_lists_' . $form_state['flo_operation']];
+}
+
+function flag_lists_ops_form_validate(&$form, &$form_state) {
+  global $user;
+
+  $error_count = 0;
+
+  // Check to see if an items are selected, if not fail right away.
+  if (!isset($_REQUEST['flag_lists_ops']) || empty($_REQUEST['flag_lists_ops'])) {
+    form_set_error('', t('No content selected.'));
+    $error_count++;
+    return $error_count;
+  }
+
+  switch ($form_state['values']['flag_lists_' . $form_state['flo_operation']]['operation']) {
+    case 'unflag':
+      $ops = $_REQUEST['flag_lists_ops'];
+      foreach ($ops as $key => $op) {
+        $ops[$key] = explode('-', $op);
+        if (empty($ops[$key][1]) || !($flag = flag_lists_get_flag($ops[$key][1]))) {
+          form_set_error('flag_lists][remove', t('Invalid options list selected to remove from.'));
+          $error_count++;
+        }
+        else if ($flag->uid != $user->uid) {
+          form_set_error('flag_lists][remove', t('You are only allowed to remove content from your own lists.'));
+          $error_count++;
+        }
+      }
+      break;
+    default:
+      if (empty($form_state['values']['flag_lists_' . $form_state['flo_operation']]['list'])) {
+        form_set_error('flag_lists][list', t('No list selected. Please select a list to add to.'));
+        $error_count++;
+      }
+      else if (!($flag = flag_lists_get_flag($form_state['values']['flag_lists_' . $form_state['flo_operation']]['list']))) {
+        form_set_error('flag_lists][list', t('Invalid list selected. Please select a list to add to.'));
+        $error_count++;
+      }
+      else if ($flag->uid != $user->uid) {
+        form_set_error('flag_lists][list', t('Invalid list selected. Please select a list to add to.'));
+        $error_count++;
+      }
+      break;
+  }
+
+  return $error_count;
+}
+
+function flag_lists_ops_form_submit(&$form, &$form_state) {
+  // Get the $ops from the originating form.
+  $ops = $_REQUEST['flag_lists_ops'];
+  $success_count = 0;
+
+  // Get the operation, or set it
+  switch ($form_state['values']['flag_lists_' . $form_state['flo_operation']]['operation']) {
+    case 'unflag':
+      $operation = 'unflag';
+      $message = 'removed from';
+
+      foreach ($ops as $op) {
+        // Process the ID into 2 parts
+        list($nid, $fid) = explode('-', $op);
+        if (empty($nid) || empty($fid)) return;
+
+        if (($flag = flag_lists_get_flag($fid)) && ($node = node_load($nid))) {
+          if (flag_lists_do_flag($flag, $operation, $nid)) {
+            $success_count++;
+          }
+        }
+      }
+      break;
+    default:
+      $operation = 'flag';
+      $message = 'added to';
+
+      if ($flag = flag_lists_get_flag($form_state['values']['flag_lists_' . $form_state['flo_operation']]['list'])) {
+        foreach ($ops as $nid) {
+          if (flag_lists_do_flag($flag, $operation, $nid)) {
+            $success_count++;
+          }
+        }
+      }
+      break;
+  }
+
+  $message = t('@count item(s) ' . $message . ' !title', array('@count' => $success_count, '!title' => $flag->title));
+  if ($_GET['q'] != 'system/ajax') {
+    drupal_set_message($message);
+  }
+  else {
+    return $message;
+  }
+}
+
+/**
+ * Gets the FLO field if it exists on the passed-in view.
+ *
+ * @return
+ *  The field object if found. Otherwise, FALSE.
+ */
+function _flag_lists_ops_get_field($view) {
+  foreach ($view->field as $field_name => $field) {
+    if ($field instanceof flag_lists_handler_field_ops) {
+      // Add in the view object for convenience.
+      $field->view = $view;
+      return $field;
+    }
+  }
+  return FALSE;
+}
+
+function flag_lists_template_validate($form, &$form_state) {
+  $types = array_filter($form_state['values']['types']);
+  $errors = array();
+  foreach ($types as $type) {
+    $result = db_select('flag_lists_types', 'f')
+      ->fields('f')
+      ->condition('type', $type)
+      ->condition('name', $form_state['values']['name'], '<>')
+      ->execute();
+    foreach ($result as $errors) {
+      $content_types[] = $errors->type;
+      $templates[] = $errors->name;
+    }
+  }
+  if (isset($content_types) && count($content_types)) {
+    $content_types = implode(', ', $content_types);
+    $templates = implode(', ', array_unique($templates));
+    form_set_error('types', t('The flaggable content type(s) "@type" is(are) already assigned to the template(s) "@template." A content type may be assigned to only one template. To reassign a content type you must first remove its other assignment.', array('@type' => $content_types, '@template' => $templates)));
+  }
+}
+
+function flag_lists_template_submit($form, &$form_state) {
+  $types = array_filter($form_state['values']['types']);
+  // Clean out the old types, then add the new.
+  $num_deleted = db_delete('flag_lists_types')
+    ->condition('name', $form_state['values']['name'])
+    ->execute();
+  foreach ($types as $type) {
+    db_insert('flag_lists_types')
+      ->fields(array(
+        'name' => $form_state['values']['name'],
+        'type' => $type,
+      ))
+      ->execute();
+  }
+}
+/**
+ * Helper function to build an array of all lists available to or owned by the
+ * current user and that are available on the current content type.
+ */
+function flag_lists_get_content_fids() {
+  global $user;
+
+  // This is a node view. We only care about nodes for now.
+  if (arg(0) == 'node' && is_numeric(arg(1)) && is_null(arg(2))) {
+    $type = db_select('node', 'n')
+      ->fields('n', array('type'))
+      ->condition('nid', arg(1))
+      ->execute()
+      ->fetchField();
+
+    // Get current user's flags for this node.
+    $query = db_select('flag_lists', 'fc')
+      ->fields('f', 'fid')
+      ->condition('fc.uid', $user->uid)
+      ->condition('fn.type', $type);
+    $query->leftJoin('flag_types', 'fn', 'fn.fid = fc.fid');
+    $query->leftJoin('flags', 'f', 'fc.fid = f.fid');
+    $fc_result = $query->execute();
+
+    foreach ($fc_result as $row) {
+      $fids[] = $row->fid;
+    }
+  }
+
+  // This is the flag / unflag callback
+  elseif (arg(0) == 'flag' && (arg(1) == 'flag' || arg(1) == 'unflag')) {
+    // Get the flag for this request.
+    $fids[] = db_select('flags', 'f')
+      ->fields('f', array('fid'))
+      ->condition('name', arg(2))
+      ->execute()
+      ->fetchField();
+  }
+
+  // Get the regular flags for this node. The flag module will narrow by role,
+  // etc. when flag_get_flags() is called. These flag ids are always returned.
+  $query = db_select('flags', 'f')
+    ->fields('f', array('fid'))
+    ->condition('fc.fid', NULL);
+  $query->leftJoin('flag_lists', 'fc', 'fc.fid = f.fid');
+  $f_result = $query->execute();
+
+  foreach ($f_result as $obj) {
+    $fids[] = $obj->fid;
+  }
+  if (is_array($fids)) {
+    return array_unique($fids);
+  }
+  else {
+    return array();
+  }
+}
+
+/**
+ * Implements hook_block_info();
+ */
+function flag_lists_block_info() {
+  return array(
+    'flag_lists' => array(
+      'info' => t('Lists'),
+      'cache' => DRUPAL_NO_CACHE,
+    ),
+    'flag_lists_list' => array(
+      'info' => t('My lists'),
+      'cache' => DRUPAL_NO_CACHE,
+    ),
+  );
+}
+
+/**
+ * Implements hook_block_configure().
+ */
+function flag_lists_block_configure($delta = '') {
+  $form = array();
+
+  switch ($delta) {
+    case 'flag_lists':
+      $form = array(
+        'create_lists' => array(
+          '#type' => 'checkbox',
+          '#title' => t('Show link to add new list'),
+          '#default_value' => variable_get('flag_lists_create_lists', 0),
+          '#description' => t('Checking this adds a link to the create new list form.'),
+        ),
+        'ops' => array(
+          '#type' => 'checkbox',
+          '#title' => t('Show edit and delete links'),
+          '#default_value' => variable_get('flag_lists_ops', 0),
+          '#description' => t('Checking this appends edit and delete links to each list name for users with access.'),
+        ),
+        'include_flags' => array(
+          '#type' => 'checkbox',
+          '#title' => t('Include flag module flags'),
+          '#default_value' => variable_get('flag_lists_include_flags', 0),
+          '#description' => t('Checking this will append flag module flags to the list of lists.'),
+        ),
+      );
+      break;
+  }
+  return $form;
+}
+
+/**
+ * Implements hook_block_save().
+ */
+function flag_lists_block_save($delta = '', $edit = array()) {
+  switch ($delta) {
+    case 'flag_lists':
+      variable_set('flag_lists_create_lists', $edit['create_lists']);
+      variable_set('flag_lists_ops', $edit['ops']);
+      variable_set('flag_lists_include_flags', $edit['include_flags']);
+      break;
+  }
+}
+
+/**
+ * Implements hook_block_view().
+ */
+function flag_lists_block_view($delta = '') {
+  $block = array();
+
+  switch ($delta) {
+    case 'flag_lists':
+      if (user_access('create flag lists')) {
+        $block = array(
+          'subject' => t('My lists'),
+          'content' => theme('flag_lists_list', array('node' => NULL, 'create' => variable_get('flag_lists_create_lists', 0), 'ops' =>variable_get('flag_lists_ops', 0), 'use_flags' => variable_get('flag_lists_include_flags', 0))),
+        );
+      }
+      break;
+    case 'flag_lists_list':
+      if (user_access('create flag lists')) {
+        global $user;
+        $account = user_load($user->uid);
+
+        $block = array(
+          'subject' => t('My lists'),
+          'content' => flag_lists_user_page($account),
+        );
+      }
+      break;
+  }
+  return (!empty($block['content'])) ? $block : array();
+}
+
+/**
+ * Implementation of hook_user_delete().
+ */
+function flag_lists_user_delete($account) {
+  // Remove personal flags by this user.
+  $num_deleted = db_delete('flag_lists_flags')
+    ->condition('uid', $account->uid)
+    ->execute();
+}
+
+/**
+ * Build a flag's messages.
+ */
+function flag_lists_set_messages(&$flag) {
+  // Get the parent flag. These are cached by the flag module.
+  $pflag = flag_get_flag(NULL, $flag->pfid);
+  $title = $flag->title;
+  $lists_name = variable_get('flag_lists_name', t('list'));
+  $flag->flag_short      = $pflag->flag_short;
+  $flag->flag_long       = $pflag->flag_long;
+  $flag->flag_message    = $pflag->flag_message;
+  $flag->unflag_short    = $pflag->unflag_short;
+  $flag->unflag_long     = $pflag->unflag_long;
+  $flag->unflag_message  = $pflag->unflag_message;
+}
+
+/**
+ * Implementation of hook_flag_access().
+ *
+ * Make sure a user can only see his/her own personal flags.
+ */
+function flag_lists_flag_access($flag, $entity_id, $action, $account) {
+  if (!empty($flag->module) && $flag->module == 'flag_lists') {
+  switch ($action) {
+    case 'flag':
+    case 'unflag':
+      $fid = db_select('flag_lists_flags', 'f')
+        ->fields('f')
+        ->condition('f.uid', $account->uid)
+        ->execute()
+        ->fetchField();
+      if (!empty($fid)) {
+        return array('flag_lists' => TRUE);
+      }
+      else {
+        return array('flag_lists' => FALSE);
+      }
+  }
+}
+}
+
+/**
+ * Implementation of hook_link().
+ */
+// There may be a better way to keep flag lists out of the links, but this
+// works for now. @todo Find a better way to keep flags lists out of links.
+function flag_lists_link_alter(&$links, $node) {
+  if (!variable_get('flag_lists_use_links', 1)) {
+    foreach ($links as $name => $link) {
+      if (stristr($name, 'flag-fl_')) {
+        unset($links[$name]);
+      }
+    }
+  }
+}
+
+/**
+ * Implementation of hook_flag_alter().
+ */
+function flag_lists_flag_alter(&$flag) {
+}
+
+/**
+ * Implementation of hook_flag_delete().
+ *
+ * This is not in flag yet.
+ */
+function flag_lists_flag_delete($flag) {
+  // Template flag is being deleted. Clean up our tables.
+  // Collect the sub-flag fids so we can delete counts and content records.
+  $results = db_select('flag_lists_flags', 'f')
+    ->fields('f', array('fid', 'name'))
+    ->condition('pfid', $flag->fid)
+    ->execute();
+  foreach ($results as $fid) {
+    db_delete('flag_lists_counts')
+      ->condition('fid', $flag->fid)
+      ->execute();
+    db_delete('flag_lists_content')
+      ->condition('fid', $flag->fid)
+      ->execute();
+  }
+
+  // flag_lists_types uses the template flag name, not our own fid.
+  db_delete('flag_lists_types')
+      ->condition('name', $flag->name)
+      ->execute();
+
+  // Now delete the sub-flags.
+  $num_deleted = db_delete('flag_lists_flags')
+      ->condition('pfid', $flag->fid)
+      ->execute();
+  if (!empty($num_deleted)) {
+    drupal_set_message(t('The template flag "@title" and all its sub-flags have been deleted.', array('@title' => $flag->title)));
+  }
+}
+
+/**
+ * Implementation of hook_views_api().
+ */
+function flag_lists_views_api() {
+  return array(
+    'api' => 2.0,
+    'path' => drupal_get_path('module', 'flag_lists') . '/includes',
+  );
+}
+
+/**
+ * Helper function to test if a flag is owned by the current user, or current
+ * user can administer flags.
+ */
+function flag_lists_is_owner($action, $name) {
+  global $user;
+  if (user_access('administer flags')) {
+    return TRUE;
+  }
+
+  // If we don't have an fid, then we have the flag name.
+  if (is_numeric($name)) {
+    $query = db_select('flag_lists_flags', 'f')->condition('fid', $name);
+    $query->addField('f', 'name');
+    $name = $query->execute()->fetchField();
+  }
+
+  if (!user_access($action . ' own flag lists')) {
+    return FALSE;
+  }
+  if (db_select('flag_lists_flags', 'f')->fields('f')->condition('f.name', $name)->condition('f.uid', $user->uid)->countQuery()->execute()->fetchField()) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Get a single user's lists, and merge in flag module flags
+ */
+function flag_lists_get_user_flags($content_type = NULL, $account = NULL, $use_flags = FALSE) {
+  $flags = array();
+  $lists = array();
+  if (!isset($account)) {
+    $account = $GLOBALS['user'];
+  }
+  // Get flag lists flags
+  $query = db_select('flag_lists_flags', 'fl')
+    ->fields('fl')
+    ->condition('fl.uid', $account->uid);
+  $query->leftJoin('flag', 'f', 'fl.pfid = f.fid');
+  $query->leftJoin('flag_lists_types', 'ft', 'ft.name = f.name');
+  $query->addField('ft', 'type');
+  if ($content_type) {
+    $query->condition('ft.type', $content_type);
+  }
+
+  $result = $query->execute();
+  foreach ($result as $row) {
+    if (!isset($lists[$row->name])) {
+      $lists[$row->name] = flag_flag::factory_by_row($row);
+      $lists[$row->name]->module = 'flag_lists';
+    }
+    else {
+      $lists[$row->name]->types[] = $row->type;
+    }
+  }
+  // Get regular flags.
+  if ($use_flags) {
+    $flags = flag_get_flags('node', $content_type, $account);
+
+    // Strip out any list templates
+    foreach ($flags as $key => $flag) {
+      if (stristr($flag->name, 'fl_template') !== FALSE) {
+        unset($flags[$key]);
+      }
+    }
+  }
+
+  $flags = array_merge($lists, $flags);
+  return $flags;
+}
+
+/**
+ * Theme function to return edit, delete links.
+ *
+ * @param $flag
+ *   The flag whose links are being built.
+ */
+function theme_flag_lists_ops($variables) {
+  $flag = $variables['flag'];
+
+  $links = array(
+    'flags_edit' =>  array('title' => t('edit'), 'href' => 'flags/lists/edit/' . $flag->name, 'query' => drupal_get_destination()),
+    'flags_delete' =>  array('title' => t('delete'), 'href' => 'flags/lists/delete/' . $flag->name, 'query' => drupal_get_destination()),
+  );
+  return theme('links', array('links' => $links, 'attributes' => array('class' => 'flag_lists_ops')));
+}
+
+/**
+ * Theme a list of lists
+ *
+ * @param $node
+ *   The listable node
+ * @param boolean $create
+ *   Show the create list form.
+ * @param boolean $ops
+ *   Show the edit / delete links for lists
+ * @param boolean $use_flags
+ *   Show flags from the flag module
+ * @return <type>
+ */
+
+// @todo Separate out the code from the theming better.
+function theme_flag_lists_list($variables) {
+  $node = $variables['node'];
+  $create = $variables['create'];
+  $ops = $variables['ops'];
+  $use_flags = $variables['use_flags'];
+
+  $items = array();
+
+  // Make sure we have a node.
+  if (is_object($node) && user_access('create flag lists')) {
+    $content_type = $node->type;
+    $entity_id = $node->nid;
+  }
+  // Or at least confirm we are on a node page and use has access.
+  elseif (arg(0) == 'node' && is_numeric(arg(1)) && user_access('create flag lists')) {
+    $entity_id = arg(1);
+    $query = db_select('node')->condition('nid', $entity_id);
+    $query->addField('node', 'type');
+    $content_type = $query->execute()->fetchField();
+  }
+  else {
+    return;
+  }
+
+  // Do we have a list template for this node type, or are we s
+  if (!flag_lists_template_exists($content_type) && !$use_flags) {
+    return;
+  }
+
+  global $user;
+  if ($flags = flag_lists_get_user_flags($content_type, $user, $use_flags)) {
+    // Build the list of lists for this node.
+    foreach ($flags as $flag) {
+      if ($flag->module == 'flag_lists') {
+      $action = _flag_lists_is_flagged($flag, $entity_id, $user->uid, 0) ? 'unflag' : 'flag';
+      }
+      else {
+        $action = $flag->is_flagged($entity_id) ? 'unflag' : 'flag';;
+      }
+
+      // Do we need the ops?
+      if ($ops && $flag->module == 'flag_lists') {
+        $ops_links = theme('flag_lists_ops', array('flag' => $flag));
+        $link = $flag->theme($action, $entity_id) . $ops_links;
+      }
+      else {
+        $link = $flag->theme($action, $entity_id);
+      }
+
+      // If it's a list, fix the link.
+      if ($flag->module == 'flag_lists') {
+        flag_lists_fix_link($link, $action);
+      }
+      $items[] = $link;
+    }
+  }
+  if ($create && flag_lists_template_exists($content_type)) {
+    $items[] = l(t('Make a new @name', array('@name' => variable_get('flag_lists_name', t('list')))), 'flag-lists/add/' . $content_type, array('query' => drupal_get_destination()));
+  }
+
+  // Return if nothing to display.
+  if (empty($items) || !count($items)) {
+    return;
+  }
+
+  drupal_add_css(drupal_get_path('module', 'flag_lists') . '/theme/flag_lists.css');
+  return theme('item_list', array('items' => $items, 'type' => 'ul', 'attributes' => array('class' => 'flag-lists-links')));
+}
+
+
+// Do we still need this, and/or do we need our own cache?
+/**
+ * Clear the flag cache.
+ *
+ * This is a less severe cache clear than provided by flag. All flag lists
+ * users must be authorized, so we don't need to flush the page cache. For now,
+ * flag lists titles won't be in the menu, so no need to clear that.
+ */
+function _flag_lists_clear_cache() {
+  // We're not using _flag_clear_cache because we probably don't need the menu
+  // rebuild and don't need to clear the page cache.
+  if (module_exists('views')) {
+    views_invalidate_cache();
+  }
+}
+
+/**
+ * Update ALL flag lists with settings form values.
+ */
+function flag_lists_rebuild() {
+  $flags = flag_lists_get_flags();
+  foreach ($flags as $flag) {
+    flag_lists_set_messages($flag);
+    $flag->link_type = 'toggle';
+    flag_lists_save($flag);
+  }
+}
+
+/**
+ * Build array of all flag lists.
+ *
+ * @return If limit and header arguments are provided, the paged flags, otherwise
+ * an array of all flags.
+ */
+function flag_lists_get_flags($limit = NULL, $header = NULL) {
+  $flags = array();
+  if ($limit) {
+    $query = db_select('flag_lists_flags', 'fl')
+      ->fields('fl')
+      ->groupBy('fl.fid')
+      ->extend('PagerDefault')
+        ->limit($limit);
+    $query->leftJoin('flag_types', 'ft', 'ft.fid = fl.pfid');
+    $query->addExpression('GROUP_CONCAT(ft.type)', 'types');
+    $result = $query->execute();
+  }
+  else {
+    $query = db_select('flag_lists_flags', 'fl')
+      ->fields('fl')
+      ->groupBy('fl.fid');
+    $query->leftJoin('flag_types', 'ft', 'ft.fid = fl.pfid');
+    $query->addExpression('GROUP_CONCAT(ft.type)', 'types');
+    $result = $query->execute();
+  }
+  foreach ($result as $row) {
+    $flags[$row->name] = flag_flag::factory_by_row($row);
+    $flags[$row->name]->types = explode(',', $row->types);
+    $flags[$row->name]->uid = $row->uid;
+  }
+  return $flags;
+}
+
+/**
+ * Get a specific flag.
+ *
+ * Using this instead of flag_get_flag() for performance.
+ */
+function flag_lists_get_flag($fid) {
+  // If we don't have an fid, then we have the flag name.
+  if (!is_numeric($fid)) {
+    $query = db_select('flag_lists_flags')
+      ->condition('name', $fid);
+    $query->addField('flag_lists_flags', 'fid');
+    $fid = $query->execute()->fetchField();
+  }
+
+  $query = db_select('flag_lists_flags', 'fl')
+    ->fields('fl')
+    ->condition('fl.fid', $fid);
+  $query->leftJoin('flag_types', 'ft', 'ft.fid = fl.pfid');
+  $query->addField('ft', 'type');
+  $result = $query->execute();
+
+  foreach ($result as $row) {
+    if (!isset($flag->name)) {
+      $flag = flag_flag::factory_by_row($row);
+    }
+    else {
+      $flag->types[] = $row->type;
+    }
+  }
+  return $flag;
+}
+
+/**
+ * Get all flagged content in a flag.
+ *
+ * Using this instead of flag_get_flagged_content() because we need to make sure that we use flag_lists_get_flags()
+ *
+ * @param
+ *   The flag name for which to retrieve flagged content.
+ */
+function flag_lists_get_flagged_content($fid, $uid) {
+  $return = array();
+  $flag = flag_lists_get_flag($fid);
+
+  $result = db_select('flag_lists_content', 'f')
+    ->fields('f')
+    ->condition('f.fid', $flag->fid)
+    ->condition('f.uid', $uid)
+    ->execute();
+
+  foreach ($result as $row) {
+    $return[] = $row;
+  }
+  return $return;
+}
+
+
+/**
+ * Implementation of hook_flag_link().
+ *
+ * When Flag uses a link type provided by this module, it will call this
+ * implementation of hook_flag_link(). It returns a single link's attributes,
+ * using the same structure as hook_link(). Note that "title" is provided by
+ * the Flag configuration if not specified here.
+ *
+ * @param $flag
+ *   The full flag object of for the flag link being generated.
+ * @param $action
+ *   The action this link will perform. Either 'flag' or 'unflag'.
+ * @param $entity_id
+ *   The ID of the node, comment, user, or other object being flagged.
+ * @return
+ *   An array defining properties of the link.
+ */
+function flag_lists_flag_link($flag, $action, $entity_id) {
+  return array();
+}
+
+/**
+ * Implementation of hook_flag_link_types().
+ */
+function flag_lists_flag_link_types() {
+  return array(
+    'fl_template' => array(
+      'title' => t('Flag Lists toggle'),
+      'description' => t('If you are creating a Flag lists template flag, you must select this link type.'),
+    ),
+  );
+}
+
+
+function flag_lists_flag_default_flags($name = 'fl_template') {
+  // return array(
+  //   array(
+  //     'api_version' => 2,
+  //     'name' => $name,
+  //     'module' => 'flag_lists',
+  //     'content_type' => 'node',
+  //     'global' => 0,
+  //     'show_on_page' => 0,
+  //     'show_on_teaser' => 0,
+  //     'show_on_form' => 0,
+  //     // The following UI labels aren't wrapped in t() because they are written
+  //     // to the DB in English. They are passed to t() later, thus allowing for
+  //     // multilingual sites.
+  //     'title' => 'Flag lists template',
+  //     'flag_short' => 'Add to your [flag_lists:title] [flag_lists:term]',
+  //     'flag_long' => 'Add this post to your [flag_lists:title] [flag_lists:term]',
+  //     'flag_message' => 'This post has been added to your [flag_lists:title] [flag_lists:term]',
+  //     'unflag_short' => 'Remove this from your [flag_lists:title] [flag_lists:term]',
+  //     'unflag_long' => 'Remove this post from your [flag_lists:title] [flag_lists:term]',
+  //     'unflag_message' => 'This post has been removed from your [flag_lists:title] [flag_lists:term]',
+  //     'types' => array(),
+  //     'link_type' => 'toggle',
+  //   ),
+  // );
+
+$flags = array();
+// Exported flag: "Flag lists template".
+$flags['fl_template'] = array(
+  'entity_type' => 'node',
+  'title' => 'Flag lists template',
+  'global' => 0,
+  'types' => array(),
+  'flag_short' => 'Add to your [flag_lists:title] [flag_lists:term]',
+  'flag_long' => 'Add this post to your [flag_lists:title] [flag_lists:term]',
+  'flag_message' => 'This post has been added to your [flag_lists:title] [flag_lists:term]',
+  'unflag_short' => 'Remove this from your [flag_lists:title] [flag_lists:term]',
+  'unflag_long' => 'Remove this post from your [flag_lists:title] [flag_lists:term]',
+  'unflag_message' => 'This post has been removed from your [flag_lists:title] [flag_lists:term]',
+  'unflag_denied_text' => '',
+  'link_type' => 'toggle',
+  'weight' => 0,
+  'api_version' => 3,
+  'module' => 'flag_lists',
+  'show_on_page' => 0,
+  'show_on_teaser' => 0,
+  'show_on_form' => 0,
+  'status' => FALSE,
+  'import_roles' => array(
+    'flag' => array(),
+    'unflag' => array(),
+  ),
+);
+return $flags;
+
+  
+}
+
+/**
+ * Saves a flag to the database. It is a wrapper around update($flag) and insert($flag).
+ */
+function flag_lists_save(&$flag, $account = NULL) {
+  if (!isset($account)) {
+    $account = $GLOBALS['user'];
+  }
+
+  if (isset($flag->fid)) {
+    flag_lists_update($flag);
+    $flag->is_new = FALSE;
+    module_invoke_all('flag_lists', $flag, $account);
+  }
+  else {
+    flag_lists_insert($flag);
+    $flag->is_new = TRUE;
+    module_invoke_all('flag_lists', $flag, $account);
+  }
+  // Clear the page cache for anonymous users.
+//    cache_clear_all('*', 'cache_page', TRUE);
+}
+
+/**
+ * Saves an existing flag to the database. Better use save($flag).
+ */
+function flag_lists_update($flag) {
+  $num_updated = db_update('flag_lists_flags')
+    ->fields(array(
+      'title' => $flag->title,
+      'name' => $flag->name,
+      'options' => $flag->get_serialized_options($flag),
+    ))
+    ->condition('fid', $flag->fid)
+    ->execute();
+}
+
+/**
+ * Saves a new flag to the database. Better use save($flag).
+ */
+function flag_lists_insert($flag) {
+  $flag->fid = db_insert('flag_lists_flags')
+    ->fields(array(
+      'pfid' => $flag->pfid,
+      'uid' => $flag->uid,
+      'entity_type' => $flag->entity_type,
+      'name' => $flag->name,
+      'title' => $flag->title,
+      'options' => $flag->get_serialized_options($flag),
+    ))
+    ->execute();
+  $flag->name = 'flag_lists_' . $flag->uid . '_' . $flag->fid;
+  flag_lists_update($flag);
+}
+
+/**
+ * Delete a flag_lists flag.
+ *
+ */
+function flag_lists_fl_delete($flag, $account = NULL) {
+  if (!isset($account)) {
+    $account = $GLOBALS['user'];
+  }
+
+  db_delete('flag_lists_counts')->condition('fid', $flag->fid)->execute();
+  db_delete('flag_lists_content')->condition('fid', $flag->fid)->execute();
+  db_delete('flag_lists_flags')->condition('fid', $flag->fid)->execute();
+
+  $flag->is_deleted = TRUE;
+  module_invoke_all('flag_lists', $flag, $account);
+  _flag_lists_clear_cache();
+  drupal_set_message(t('The @name @title has been deleted.', array('@name' => variable_get('flag_lists_name', t('list')), '@title' => $flag->title)));
+}
+
+
+/**
+ * Menu callback for (un)flagging a node.
+ *
+ * Used both for the regular callback as well as the JS version. We use this
+ * instead of the flag module's because our flags are not in the flags table.
+ */
+function flag_lists_page($action = NULL, $flag_name = NULL, $entity_id = NULL) {
+  global $user;
+
+  // Shorten up the variables that affect the behavior of this page.
+  $js = isset($_REQUEST['js']);
+  $token = $_REQUEST['token'];
+
+  // Specifically $_GET to avoid getting the $_COOKIE variable by the same key.
+  $has_js = isset($_GET['has_js']);
+
+  // Check the flag token, then perform the flagging.
+  if (!flag_check_token($token, $entity_id)) {
+    $error = t('Bad token. You seem to have followed an invalid link.');
+  }
+  elseif ($user->uid == 0 && !$has_js) {
+    $error = t('You must have JavaScript and cookies enabled in your browser to flag content.');
+  }
+  else {
+    if (empty($flag_name) || !($flag = flag_lists_get_flag($flag_name))) {
+      // Flag does not exist.
+      $error = t('You are not allowed to flag, or unflag, this content.');
+    }
+
+    // Identify it as ours.
+    $flag->module = 'flag_lists';
+    flag_lists_do_flag($flag, $action, $entity_id);
+  }
+
+  // If an error was received, set a message and exit.
+  if (isset($error)) {
+    if ($js) {
+      drupal_add_http_header('Content-Type', 'text/javascript; charset=utf-8');
+      print drupal_to_js(array(
+        'status' => FALSE,
+        'errorMessage' => $error,
+      ));
+      exit;
+    }
+    else {
+      drupal_set_message($error);
+      drupal_access_denied();
+      return;
+    }
+  }
+
+  // If successful, return data according to the request type.
+  if ($js) {
+    drupal_add_http_header('Content-Type', 'text/javascript; charset=utf-8');
+//    $flag = flag_lists_get_flag($flag_name);
+ //   $flag->link_type = 'toggle';
+    $sid = flag_get_sid($user->uid);
+    $new_action = _flag_lists_is_flagged($flag, $entity_id, $user->uid, $sid) ? 'unflag' : 'flag';
+    $new_link = $flag->theme($new_action, $entity_id, array("after_flagging" => TRUE));
+    flag_lists_fix_link($new_link, $new_action);
+    drupal_json_output(array(
+      'status' => TRUE,
+      'newLink' => $new_link,
+      // Further information for the benefit of custom JavaScript event handlers:
+      'contentId' => $entity_id,
+      'contentType' => $flag->content_type,
+      'flagName' => $flag->name,
+      'flagStatus' => $action,
+    ));
+    exit;
+  }
+  else {
+    $flag = flag_lists_get_flag($flag->fid);
+    drupal_set_message($flag->get_label($action . '_message', $entity_id));
+    drupal_goto();
+  }
+}
+
+function flag_lists_fix_link(&$link, $action) {
+  // This is a hack to let us use our own flag/unflag callbacks without having
+  // to override $flag->theme and creating our own flag_link type.
+  $link = str_replace('/flag/' . $action . '/', '/flag-lists/' . $action . '/', $link);
+}
+
+  /**
+   * Flags, or unflags, an item.
+   *
+   * @param $action
+   *   Either 'flag' or 'unflag'.
+   * @param $entity_id
+   *   The ID of the item to flag or unflag.
+   * @param $account
+   *   The user on whose behalf to flag. Leave empty for the current user.
+   * @param $skip_permission_check
+   *   Flag the item even if the $account user doesn't have permission to do so.
+   * @return
+   *   FALSE if some error occured (e.g., user has no permission, flag isn't
+   *   applicable to the item, etc.), TRUE otherwise.
+   */
+  function flag_lists_do_flag($flag, $action, $entity_id, $account = NULL, $skip_permission_check = FALSE) {
+    if (!isset($account)) {
+      $account = $GLOBALS['user'];
+    }
+    if (!$account) {
+      return FALSE;
+    }
+    if (!$skip_permission_check) {
+      if (!$flag->access($entity_id, $action, $account)) {
+        // User has no permission to flag/unflag this object.
+        return FALSE;
+      }
+    }
+    else {
+      // We are skipping permission checks. However, at a minimum we must make
+      // sure the flag applies to this content type:
+      if (!$flag->applies_to_content_id($entity_id)) {
+        return FALSE;
+      }
+    }
+
+    // Clear various caches; We don't want code running after us to report
+    // wrong counts or false flaggings.
+//    flag_get_counts(NULL, NULL, TRUE);
+//    flag_get_user_flags(NULL, NULL, NULL, NULL, TRUE);
+
+    // Find out which user id to use.
+    $uid = $flag->global ? 0 : $account->uid;
+
+    $sid = flag_get_sid($uid);
+    // Anonymous users must always have a session id.
+    if ($sid == 0 && $account->uid == 0) {
+      return FALSE;
+    }
+
+    // Perform the flagging or unflagging of this flag. We invoke hook_flag here
+    // because we do our own flagging.
+    $flagged = _flag_lists_is_flagged($flag, $entity_id, $uid, $sid);
+    if ($action == 'unflag') {
+      if ($flagged) {
+        $fcid = _flag_lists_unflag($flag, $entity_id, $uid, $sid);
+        module_invoke_all('flag', 'unflag', $flag, $entity_id, $account, $fcid);
+      }
+    }
+    elseif ($action == 'flag') {
+      if (!$flagged) {
+        $fcid = _flag_lists_flag($flag, $entity_id, $uid, $sid);
+        module_invoke_all('flag', 'flag', $flag, $entity_id, $account, $fcid);
+      }
+    }
+
+    return TRUE;
+  }
+
+
+  /**
+   * Returns TRUE if a certain user has flagged this content.
+   *
+   *
+   * This method is similar to is_flagged() except that it does direct SQL and
+   * doesn't do caching. Use it when you want to not affect the cache, or to
+   * bypass it.
+   *
+   */
+  function _flag_lists_is_flagged($flag, $entity_id, $uid, $sid) {
+    $query = db_select('flag_lists_content')
+      ->condition('fid', $flag->fid)
+      ->condition('uid', $uid)
+      ->condition('sid', $sid)
+      ->condition('entity_id', $entity_id);
+    $query->addField('flag_lists_content', 'fid');
+    return $query->execute()->fetchField();
+  }
+
+  /**
+   * A low-level method to flag content.
+   *
+   * You probably shouldn't call this raw private method: call the
+   * flag_lists_do_flag() function instead.
+   *
+   */
+  function _flag_lists_flag($flag, $entity_id, $uid, $sid) {
+    $fcid = db_insert('flag_lists_content')
+      ->fields(array(
+        'fid' => $flag->fid,
+        'entity_type' => $flag->entity_type,
+        'entity_id' => $entity_id,
+        'uid' => $uid,
+        'sid' => $sid,
+        'timestamp' => REQUEST_TIME,
+      ))
+      ->execute();
+
+    _flag_lists_update_count($flag, $entity_id);
+    return $fcid;
+  }
+
+  /**
+   * A low-level method to unflag content.
+   *
+   * You probably shouldn't call this raw private method: call the
+   * flag_lists_do_flag() function instead.
+   *
+   */
+  function _flag_lists_unflag($flag, $entity_id, $uid, $sid) {
+    $query = db_select('flag_lists_content')
+      ->condition('fid', $flag->fid)
+      ->condition('entity_id', $entity_id)
+      ->condition('uid', $uid)
+      ->condition('sid', $sid);
+    $query->addField('flag_lists_content', 'fcid');
+    $fcid = $query->execute()->fetchField();
+    if ($fcid) {
+      db_delete('flag_lists_content')
+        ->condition('fcid', $fcid)
+        ->execute();
+      _flag_lists_update_count($flag, $entity_id);
+    }
+    return $fcid;
+  }
+
+  /**
+   * Updates the flag count for this content
+   */
+  function _flag_lists_update_count($flag, $entity_id) {
+    $count = db_select('flag_lists_content', 'f')
+      ->fields('f')
+      ->condition('fid', $flag->fid)
+      ->condition('entity_id', $entity_id)
+      ->countQuery()
+      ->execute()
+      ->fetchField();
+
+    if (empty($count)) {
+      $num_deleted = db_delete('flag_lists_counts')
+        ->condition('fid', $flag->fid)
+        ->condition('entity_id', $entity_id)
+        ->execute();
+    }
+    else {
+      $num_updated = db_update('flag_lists_counts')
+        ->fields(array(
+          'count' => $count,
+        ))
+        ->condition('fid', $flag->fid)
+        ->condition('entity_id', $entity_id)
+        ->execute();
+      if (empty($num_updated)) {
+        db_insert('flag_lists_counts')
+          ->fields(array(
+            'fid' => $flag->fid,
+            'entity_type' => $flag->entity_type,
+            'entity_id' => $entity_id,
+            'count' => $count,
+          ))
+          ->execute();
+      }
+    }
+  }
+
+/**
+ * Checks for a list template for a content type.
+ */
+function flag_lists_template_exists($type) {
+  $query = db_select('flag_lists_types')
+    ->condition('type', $type);
+  $query->addField('flag_lists_types', 'type');
+  $exists = $query->execute()->fetchField();
+  if (!empty($exists)) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Checks for a list title by node type.
+ */
+function flag_lists_title_exists($title, $type) {
+  return db_query("SELECT COUNT(flf.fid) FROM {flag_lists_flags} flf LEFT JOIN {flag_types} ft ON flf.pfid=ft.fid WHERE flf.title=:title AND ft.type=:type AND flf.uid=:uid", array(':title' => $title, ':type' => $type, ':uid' => $GLOBALS['user']->uid))->fetchField();
+}
+
+/**
+ * Get a list of template flag names.
+ */
+function flag_lists_get_templates() {
+  $templates = array();
+  $result = db_select('flag_lists_types', 'f')
+    ->fields('f', array(
+      'name'
+    ))
+    ->distinct()
+    ->execute();
+  foreach ($result as $obj) {
+    $templates[] = flag_get_flag($obj->name);
+  }
+  return $templates;
+}
+
+
+/**
+ * Implements hook_token_info().
+ */
+function flag_lists_token_info() {
+  $type = array(
+    'name' => t('Flag lists'),
+    'description' => t('Tokens related to flag lists.'),
+    'needs-data' => 'flag_lists',
+  );
+
+  $flag_lists['term'] = array(
+    'name' => t("Term"),
+    'description' => t("The terminology used to name the lists, such as list, wishlist, favorites, etc."),
+  );
+  $flag_lists['title'] = array(
+    'name' => t("Title"),
+    'description' => t("The title of the list."),
+  );
+
+  return array(
+    'types' => array('flag_lists' => $type),
+    'tokens' => array('flag_lists' => $flag_lists),
+  );
+}
+
+/**
+ * Implements hook_tokens().
+ */
+function flag_lists_tokens($type, $tokens, array $data = array(), array $options = array()) {
+  $replacements = array();
+
+  if ($type == 'flag_lists' && !empty($data['flag_lists'])) {
+    $flag_list = $data['flag_lists'];
+    foreach ($tokens as $name => $original) {
+      switch ($name) {
+        case 'title':
+          $replacements[$original] = $flag_list->title;
+          break;
+        case 'term':
+          $replacements[$original] = variable_get('flag_lists_name', t('list'));
+          break;
+      }
+    }
+  }
+  return $replacements;
+}
+
+/**
+ * Preprocess link title and text for the flag.tpl.php
+ *
+ * This seems to be the only place to do this
+ */
+function flag_lists_preprocess_flag(&$variables) {
+  if (module_exists('token') && !empty($variables['flag']->module) && $variables['flag']->module == 'flag_lists') {
+    if (!empty($variables['link_text'])) {
+      $variables['link_text'] = token_replace($variables['link_text'], array('flag_lists' => $variables['flag']));
+    }
+    if (!empty($variables['link_title'])) {
+      $variables['link_title'] = token_replace($variables['link_title'], array('flag_lists' => $variables['flag']));
+    }
+    if (!empty($variables['message_text'])) {
+      $variables['message_text'] = token_replace($variables['message_text'], array('flag_lists' => $variables['flag']));
+    }
+  }
+}
+
+/**
+ * Implements hook_views_form_substitutions().
+ */
+function flag_lists_views_form_substitutions() {
+  // Views check_plains the column label, so Flag lists needs to do the same
+  // in order for the replace operation to succeed.
+  $select_all_placeholder = check_plain('<!--flag-lists-ops-select-all-->');
+  $select_all = array(
+    '#type' => 'checkbox',
+    '#default_value' => FALSE,
+    '#attributes' => array('class' => array('flo-table-select-all')),
+  );
+  return array(
+    $select_all_placeholder => drupal_render($select_all),
+  );
+}

+ 332 - 0
sites/all/modules/contrib/flag/flag_lists/includes/flag_lists.views.inc

@@ -0,0 +1,332 @@
+<?php
+
+/**
+ * @file
+ * Provides support for the Views module.
+ */
+
+/**
+ * Implementation of hook_views_handlers().
+ */
+function flag_lists_views_handlers() {
+  return array(
+    'info' => array(
+      'path' => drupal_get_path('module', 'flag_lists') . '/includes',
+    ),
+    'handlers' => array(
+      'flag_lists_handler_field_list' => array(
+        'parent' => 'views_handler_field',
+        'file' => 'flag_lists_handler_field_list.inc',
+      ),
+      'flag_lists_handler_field_template' => array(
+        'parent' => 'views_handler_field',
+        'file' => 'flag_lists_handler_field_template.inc',
+      ),
+      'flag_lists_handler_field_list_edit' => array(
+        'parent' => 'views_handler_field',
+        'file' => 'flag_lists_handler_field_list_edit.inc',
+      ),
+      'flag_lists_handler_field_list_delete' => array(
+        'parent' => 'views_handler_field',
+        'file' => 'flag_lists_handler_field_list_delete.inc',
+      ),
+      'flag_lists_handler_field_template_types' => array(
+        'parent' => 'views_handler_field_prerender_list',
+        'file' => 'flag_lists_handler_field_template_types.inc',
+      ),
+      'flag_lists_handler_filter_template' => array(
+        'parent' => 'views_handler_filter_in_operator',
+        'file' => 'flag_lists_handler_filter_template.inc',
+      ),
+      'flag_lists_handler_argument_fid' => array(
+        'parent' => 'views_handler_argument_numeric',
+        'file' => 'flag_lists_handler_argument_fid.inc',
+    ),
+    ),
+  );
+}
+
+
+/**
+ * Implementation of hook_views_data_alter().
+ */
+function flag_lists_views_data_alter(&$data) {
+
+  // We want access to users table fields.
+  $data['users']['table']['join']['flag_lists_flags'] = array(
+    'left_field' => 'uid',
+    'field' => 'uid',
+  );
+
+  // We need fid and name form flags' data, and join.
+  $data['flags'] = array(
+    'table' => array(
+      'group' => t('Flag'),
+      'join' => array(
+        'flag_lists_flags' => array(
+          'left_field' => 'pfid',
+          'field' => 'fid',
+        ),
+      ),
+    ),
+    'fid' => array(
+      'title' => t('Flag fid'),
+      'help' => t('Flag id'),
+      'field' => array(
+        'click sortable' => TRUE,
+      ),
+      'filter' => array(
+        'handler' => 'views_handler_filter_numeric',
+        'allow empty' => TRUE,
+      ),
+      'argument' => array(
+        'handler' => 'views_handler_argument_numeric',
+      ),
+      'sort' => array(
+        'handler' => 'views_handler_sort',
+      ),
+    ),
+    'name' => array(
+      'title' => t('Template name'),
+      'help' => t('The name of the list template flag'),
+      'field' => array(
+        'handler' => 'flag_lists_handler_field_template',
+        'click sortable' => TRUE,
+      ),
+      'filter' => array(
+        'handler' => 'flag_lists_handler_filter_template',
+        'allow empty' => TRUE,
+      ),
+      'sort' => array(
+        'handler' => 'views_handler_sort',
+      ),
+    ),
+  );
+
+  // Add the checkbox for flagging nodes VBO style, minus batch API
+  foreach (entity_get_info() as $entity_type => $info) {
+    if (isset($info['base table']) && $info['base table'] == 'node' && isset($data[$info['base table']])) {
+      $data[$info['base table']]['flag_lists_ops'] = array(
+        'title' => t('Flag lists operations'),
+        'help' => t('Provide a checkbox to select the row for flag lists operations.'),
+        'real field' => $info['entity keys']['id'],
+        'field' => array(
+          'handler' => 'flag_lists_handler_field_ops',
+          'click sortable' => FALSE,
+        ),
+      );
+      break;
+    }
+  }
+}
+
+/**
+ * Implementation of hook_views_data().
+ */
+function flag_lists_views_data() {
+  $data = array();
+
+  // flag_lists_flags data
+  $data['flag_lists_flags'] = array(
+    'table' => array(
+      'base' => array(
+        'field' => 'fid',
+        'title' => t('Flag lists'),
+        'help' => 'User created flag lists',
+        'weight' => 10,
+        'database' => 'default',
+      ),
+      'group' => t('Flag lists'),
+      'join' => array(
+        'node' => array(
+          'table' => 'flag_lists_flags',
+          'left_table' => 'flag_lists_content',
+          'left_field' => 'fid',
+          'field' => 'fid',
+        ),
+      ),
+    ),
+    'fid' => array(
+      'title' => t('fid'),
+      'help' => t('Flag list id, required for Flag lists operationis\'s "unflag" action.'),
+      'field' => array(
+        'handler' => 'flag_lists_handler_field_list',
+        'click sortable' => TRUE,
+      ),
+      'filter' => array(
+        'handler' => 'views_handler_filter_numeric',
+        'allow empty' => TRUE,
+      ),
+      'argument' => array(
+        'handler' => 'flag_lists_handler_argument_fid',
+      ),
+      'sort' => array(
+        'handler' => 'views_handler_sort',
+      ),
+    ),
+    'pfid' => array(
+      'title' => t('pfid'),
+      'help' => t('Template flag id'),
+      'field' => array(
+        'handler' => 'flag_lists_handler_field_pfid',
+        'click sortable' => TRUE,
+      ),
+      'filter' => array(
+        'handler' => 'views_handler_filter_numeric',
+        'allow empty' => TRUE,
+      ),
+      'argument' => array(
+        'handler' => 'views_handler_argument_numeric',
+      ),
+      'sort' => array(
+        'handler' => 'views_handler_sort',
+      ),
+    ),
+
+    'uid' => array(
+      'title' => t('Uid'),
+      'help' => t('The list owner\'s uid'), // The help that appears on the UI,
+      'field' => array(
+        'handler' => 'views_handler_field_user',
+        'click sortable' => TRUE,
+      ),
+      'argument' => array(
+        'handler' => 'views_handler_argument_user_uid',
+        'name field' => 'name', // display this field in the summary
+      ),
+      'filter' => array(
+        'title' => t('Name'),
+        'handler' => 'views_handler_filter_user_name',
+      ),
+      'sort' => array(
+        'handler' => 'views_handler_sort',
+      ),
+    ),
+    'name' => array(
+      'title' => t('machine name'),
+      'help' => t('Machine name of the list'),
+      'field' => array(
+        'handler' => 'flag_lists_handler_field_list',
+        'click sortable' => TRUE,
+      ),
+      'filter' => array(
+        'handler' => 'views_handler_filter_string',
+        'allow empty' => TRUE,
+      ),
+      'argument' => array(
+        'handler' => 'views_handler_argument_string',
+      ),
+      'sort' => array(
+        'handler' => 'views_handler_sort',
+      ),
+    ),
+    'title' => array(
+      'title' => t('List title'),
+      'help' => t('Title of the list'),
+      'field' => array(
+        'click sortable' => TRUE,
+        'handler' => 'flag_lists_handler_field_list',
+      ),
+      'filter' => array(
+        'handler' => 'views_handler_filter_string',
+        'allow empty' => TRUE,
+      ),
+      'argument' => array(
+        'handler' => 'views_handler_argument_string',
+      ),
+      'sort' => array(
+        'handler' => 'views_handler_sort',
+      ),
+    ),
+    'edit_list' => array(
+      'field' => array(
+        'title' => t('Edit link'),
+        'help' => t('Link to edit the list title'),
+        'handler' => 'flag_lists_handler_field_list_edit',
+      ),
+    ),
+    'delete_list' => array(
+      'field' => array(
+        'title' => t('Delete link'),
+        'help' => t('Link to delete the list'),
+        'handler' => 'flag_lists_handler_field_list_delete',
+      ),
+    ),
+  );
+
+  // Flag_lists_content data
+
+  $data['flag_lists_content'] = array(
+    'table' => array(
+      'join' => array(
+        'node' => array(
+          'left_field' => 'nid',
+          'field' => 'content_id',
+        ),
+      ),
+      'group' => t('Flag lists'),
+    ),
+    'uid' => array(
+      'relationship' => array(
+        'title' => t('User'),
+        'help' => t('The user who listed this node'),
+        'base' => 'users',
+        'handler' => 'views_handler_relationship',
+        'label' => t('List user'),
+      ),
+    ),
+    'content_id' => array(
+      'relationship' => array(
+        'title' => t('Node'),
+        'help' => t('The node that has been listed'),
+        'base' => 'node',
+        'handler' => 'views_handler_relationship',
+        'label' => t('Listed content'),
+      ),
+    ),
+    'timestamp' => array(
+      'title' => t('Time listed'),
+      'help' => t('The time this node was listed'),
+      'field' => array(
+      'handler' => 'views_handler_field_date',
+        'click sortable' => TRUE,
+      ),
+      'filter' => array(
+        'handler' => 'views_handler_filter_numeric',
+        'allow empty' => TRUE,
+      ),
+      'argument' => array(
+        'handler' => 'views_handler_argument_numeric',
+      ),
+      'sort' => array(
+        'handler' => 'views_handler_sort',
+      ),
+    ),
+  );
+
+  // Flag_lists_types data
+
+  $data['flag_lists_types'] = array(
+    'table' => array(
+      'group' => t('Flag lists'),
+      'join' => array(
+        'flag_lists_flags' => array(
+          'table' => 'flag_lists_types',
+          'type' => 'INNER',
+          'left_table' => 'flags',
+          'left_field' => 'name',
+          'field' => 'name',
+        ),
+      ),
+    ),
+    'type' => array(
+      'title' => t('Template types'),
+      'help' => t('Node types that can be listed by lists using this template'),
+      'field' => array(
+        'click sortable' => FALSE,
+        'handler' => 'flag_lists_handler_field_template_types',
+      ),
+    ),
+  );
+  return $data;
+}

+ 864 - 0
sites/all/modules/contrib/flag/flag_lists/includes/flag_lists.views_default.inc

@@ -0,0 +1,864 @@
+<?php
+/**
+ * @file
+ * Contains default views for the flag_lists module.
+ */
+
+/**
+ * Implementation of hook_views_default_views().
+ */
+function flag_lists_views_default_views() {
+  $view = new view;
+  $view->name = 'flag_lists';
+  $view->description = 'Flag lists';
+  $view->tag = '';
+  $view->view_php = '';
+  $view->base_table = 'flag_lists_flags';
+  $view->is_cacheable = FALSE;
+  $view->api_version = 2;
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->override_option('fields', array(
+    'title' => array(
+      'label' => 'List',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'link_to_list' => 1,
+      'exclude' => 0,
+      'id' => 'title',
+      'table' => 'flag_lists_flags',
+      'field' => 'title',
+      'relationship' => 'none',
+    ),
+    'name' => array(
+      'label' => 'Owner',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'link_to_user' => 1,
+      'overwrite_anonymous' => 0,
+      'anonymous_text' => '',
+      'exclude' => 0,
+      'id' => 'name',
+      'table' => 'users',
+      'field' => 'name',
+      'relationship' => 'none',
+    ),
+    'edit_list' => array(
+      'label' => 'Operations',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'text' => 'edit',
+      'exclude' => 0,
+      'id' => 'edit_list',
+      'table' => 'flag_lists_flags',
+      'field' => 'edit_list',
+      'relationship' => 'none',
+    ),
+    'delete_list' => array(
+      'label' => 'Delete link',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'text' => '',
+      'exclude' => 0,
+      'id' => 'delete_list',
+      'table' => 'flag_lists_flags',
+      'field' => 'delete_list',
+      'relationship' => 'none',
+    ),
+    'name_2' => array(
+      'label' => 'Edit template',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 0,
+        'ellipsis' => 0,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'link_to_template' => 1,
+      'exclude' => 0,
+      'link_to_list' => FALSE,
+      'id' => 'name_2',
+      'table' => 'flags',
+      'field' => 'name',
+      'relationship' => 'none',
+    ),
+    'type' => array(
+      'label' => 'Template types',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'type' => 'separator',
+      'separator' => ', ',
+      'exclude' => 0,
+      'id' => 'type',
+      'table' => 'flag_lists_types',
+      'field' => 'type',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('filters', array(
+    'title' => array(
+      'operator' => 'contains',
+      'value' => '',
+      'group' => '0',
+      'exposed' => TRUE,
+      'expose' => array(
+        'use_operator' => 0,
+        'operator' => 'title_op',
+        'identifier' => 'title',
+        'label' => 'List title',
+        'optional' => 1,
+        'remember' => 1,
+      ),
+      'case' => 0,
+      'id' => 'title',
+      'table' => 'flag_lists_flags',
+      'field' => 'title',
+      'relationship' => 'none',
+    ),
+    'uid' => array(
+      'operator' => 'in',
+      'value' => '',
+      'group' => '0',
+      'exposed' => TRUE,
+      'expose' => array(
+        'use_operator' => 0,
+        'operator' => 'uid_op',
+        'identifier' => 'uid',
+        'label' => 'Owner',
+        'optional' => 1,
+        'remember' => 1,
+        'reduce' => 0,
+      ),
+      'id' => 'uid',
+      'table' => 'flag_lists_flags',
+      'field' => 'uid',
+      'relationship' => 'none',
+    ),
+    'name' => array(
+      'operator' => 'in',
+      'value' => array(),
+      'group' => '0',
+      'exposed' => TRUE,
+      'expose' => array(
+        'use_operator' => 0,
+        'operator' => 'name_op',
+        'identifier' => 'name',
+        'label' => 'Template name',
+        'optional' => 1,
+        'single' => 1,
+        'remember' => 0,
+        'reduce' => 0,
+      ),
+      'id' => 'name',
+      'table' => 'flags',
+      'field' => 'name',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('access', array(
+    'type' => 'perm',
+    'perm' => 'administer flags',
+  ));
+  $handler->override_option('cache', array(
+    'type' => 'none',
+  ));
+  $handler->override_option('items_per_page', 25);
+  $handler->override_option('use_pager', '1');
+  $handler->override_option('style_plugin', 'table');
+  $handler->override_option('style_options', array(
+    'grouping' => '',
+    'override' => 1,
+    'sticky' => 0,
+    'order' => 'asc',
+    'columns' => array(
+      'title' => 'title',
+      'name' => 'name',
+      'edit_list' => 'edit_list',
+      'delete_list' => 'edit_list',
+      'name_2' => 'name_2',
+    ),
+    'info' => array(
+      'title' => array(
+        'sortable' => 1,
+        'separator' => '',
+      ),
+      'name' => array(
+        'sortable' => 1,
+        'separator' => '',
+      ),
+      'edit_list' => array(
+        'separator' => ' ',
+      ),
+      'delete_list' => array(
+        'separator' => '',
+      ),
+      'name_2' => array(
+        'sortable' => 0,
+        'separator' => '',
+      ),
+    ),
+    'default' => 'title',
+  ));
+  $views[$view->name] = $view;
+
+  $view = new view;
+  $view->name = 'flag_lists_content';
+  $view->description = 'Flag lists listed content';
+  $view->tag = '';
+  $view->view_php = '';
+  $view->base_table = 'node';
+  $view->is_cacheable = FALSE;
+  $view->api_version = 2;
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->override_option('relationships', array(
+    'entity_id' => array(
+      'label' => 'Listed content',
+      'required' => 1,
+      'id' => 'entity_id',
+      'table' => 'flag_lists_content',
+      'field' => 'entity_id',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('fields', array(
+    'title' => array(
+      'label' => 'Node Title',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'link_to_node' => 1,
+      'exclude' => 0,
+      'id' => 'title',
+      'table' => 'node',
+      'field' => 'title',
+      'relationship' => 'none',
+    ),
+    'title_1' => array(
+      'label' => 'List title',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'link_to_list' => 1,
+      'exclude' => 0,
+      'id' => 'title_1',
+      'table' => 'flag_lists_flags',
+      'field' => 'title',
+      'relationship' => 'none',
+    ),
+    'name' => array(
+      'label' => 'Name',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'link_to_user' => 1,
+      'overwrite_anonymous' => 0,
+      'anonymous_text' => '',
+      'exclude' => 0,
+      'id' => 'name',
+      'table' => 'users',
+      'field' => 'name',
+      'relationship' => 'uid',
+    ),
+    'timestamp' => array(
+      'label' => 'Time listed',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'date_format' => 'small',
+      'custom_date_format' => '',
+      'exclude' => 0,
+      'id' => 'timestamp',
+      'table' => 'flag_lists_content',
+      'field' => 'timestamp',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('filters', array(
+    'status' => array(
+      'operator' => '=',
+      'value' => '1',
+      'group' => '0',
+      'exposed' => FALSE,
+      'expose' => array(
+        'operator' => FALSE,
+        'label' => '',
+      ),
+      'id' => 'status',
+      'table' => 'node',
+      'field' => 'status',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('access', array(
+    'type' => 'perm',
+    'perm' => 'view flag lists',
+  ));
+  $handler->override_option('cache', array(
+    'type' => 'none',
+  ));
+  $handler->override_option('items_per_page', 25);
+  $handler->override_option('use_pager', '1');
+  $handler->override_option('style_plugin', 'table');
+  $handler->override_option('style_options', array(
+    'grouping' => '',
+    'override' => 1,
+    'sticky' => 0,
+    'order' => 'desc',
+    'columns' => array(
+      'title' => 'title',
+      'title_1' => 'title_1',
+      'name' => 'name',
+      'timestamp' => 'timestamp',
+    ),
+    'info' => array(
+      'title' => array(
+        'sortable' => 1,
+        'separator' => '',
+      ),
+      'title_1' => array(
+        'sortable' => 1,
+        'separator' => '',
+      ),
+      'name' => array(
+        'sortable' => 1,
+        'separator' => '',
+      ),
+      'timestamp' => array(
+        'sortable' => 1,
+        'separator' => '',
+      ),
+    ),
+    'default' => 'timestamp',
+  ));
+  $views[$view->name] = $view;
+
+  $view = new view;
+  $view->name = 'flag_lists_user_lists';
+  $view->description = 'Flag lists user lists';
+  $view->tag = '';
+  $view->view_php = '';
+  $view->base_table = 'flag_lists_flags';
+  $view->is_cacheable = FALSE;
+  $view->api_version = 2;
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->override_option('fields', array(
+    'title' => array(
+      'label' => 'List',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'link_to_list' => 1,
+      'exclude' => 0,
+      'id' => 'title',
+      'table' => 'flag_lists_flags',
+      'field' => 'title',
+      'relationship' => 'none',
+    ),
+    'edit_list' => array(
+      'label' => 'Edit link',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'text' => 'Edit',
+      'exclude' => 0,
+      'id' => 'edit_list',
+      'table' => 'flag_lists_flags',
+      'field' => 'edit_list',
+      'relationship' => 'none',
+    ),
+    'delete_list' => array(
+      'label' => 'Delete link',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'text' => '',
+      'exclude' => 0,
+      'id' => 'delete_list',
+      'table' => 'flag_lists_flags',
+      'field' => 'delete_list',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('arguments', array(
+    'uid' => array(
+      'default_action' => 'not found',
+      'style_plugin' => 'default_summary',
+      'style_options' => array(),
+      'wildcard' => 'all',
+      'wildcard_substitution' => 'All',
+      'title' => '%1\'s lists',
+      'breadcrumb' => '',
+      'default_argument_type' => 'fixed',
+      'default_argument' => '',
+      'validate_type' => 'none',
+      'validate_fail' => 'not found',
+      'break_phrase' => 0,
+      'not' => 0,
+      'id' => 'uid',
+      'table' => 'flag_lists_flags',
+      'field' => 'uid',
+      'validate_user_argument_type' => 'uid',
+      'validate_user_roles' => array(
+        '2' => 0,
+      ),
+      'relationship' => 'none',
+      'default_options_div_prefix' => '',
+      'default_argument_fixed' => '',
+      'default_argument_user' => 0,
+      'default_argument_php' => '',
+      'validate_argument_node_type' => array(
+        'page' => 0,
+        'story' => 0,
+      ),
+      'validate_argument_node_access' => 0,
+      'validate_argument_nid_type' => 'nid',
+      'validate_argument_vocabulary' => array(),
+      'validate_argument_type' => 'tid',
+      'validate_argument_transform' => 0,
+      'validate_user_restrict_roles' => 0,
+      'validate_argument_node_flag_name' => '*relationship*',
+      'validate_argument_node_flag_test' => 'flaggable',
+      'validate_argument_node_flag_id_type' => 'id',
+      'validate_argument_user_flag_name' => '*relationship*',
+      'validate_argument_user_flag_test' => 'flaggable',
+      'validate_argument_user_flag_id_type' => 'id',
+      'validate_argument_php' => '',
+    ),
+  ));
+  $handler->override_option('access', array(
+    'type' => 'perm',
+    'perm' => 'view flag lists',
+  ));
+  $handler->override_option('cache', array(
+    'type' => 'none',
+  ));
+  $handler->override_option('items_per_page', 25);
+  $handler->override_option('use_pager', '1');
+  $handler->override_option('style_plugin', 'table');
+  $handler->override_option('style_options', array(
+    'grouping' => '',
+    'override' => 1,
+    'sticky' => 0,
+    'order' => 'asc',
+    'columns' => array(
+      'title' => 'title',
+      'name' => 'name',
+    ),
+    'info' => array(
+      'title' => array(
+        'sortable' => 1,
+        'separator' => '',
+      ),
+      'name' => array(
+        'sortable' => 1,
+        'separator' => '',
+      ),
+    ),
+    'default' => 'title',
+  ));
+  $views[$view->name] = $view;
+
+  $view = new view;
+  $view->name = 'flag_lists_user_list';
+  $view->description = 'Flag lists - one of a user\'s lists';
+  $view->tag = '';
+  $view->view_php = '';
+  $view->base_table = 'node';
+  $view->is_cacheable = FALSE;
+  $view->api_version = 2;
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->override_option('fields', array(
+    'title' => array(
+      'label' => '',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'link_to_node' => 1,
+      'exclude' => 0,
+      'id' => 'title',
+      'table' => 'node',
+      'field' => 'title',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('sorts', array(
+    'timestamp' => array(
+      'order' => 'DESC',
+      'id' => 'timestamp',
+      'table' => 'flag_lists_content',
+      'field' => 'timestamp',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('arguments', array(
+    'fid' => array(
+      'default_action' => 'not found',
+      'style_plugin' => 'default_summary',
+      'style_options' => array(),
+      'wildcard' => 'all',
+      'wildcard_substitution' => 'All',
+      'title' => '%1',
+      'breadcrumb' => '',
+      'default_argument_type' => 'fixed',
+      'default_argument' => '',
+      'validate_type' => 'none',
+      'validate_fail' => 'not found',
+      'break_phrase' => 0,
+      'not' => 0,
+      'id' => 'fid',
+      'table' => 'flag_lists_flags',
+      'field' => 'fid',
+      'validate_user_argument_type' => 'uid',
+      'validate_user_roles' => array(
+        '2' => 0,
+        '3' => 0,
+        '4' => 0,
+      ),
+      'relationship' => 'none',
+      'default_options_div_prefix' => '',
+      'default_argument_fixed' => '',
+      'default_argument_user' => 0,
+      'default_argument_image_size' => '_original',
+      'default_argument_php' => '',
+      'validate_argument_node_type' => array(
+        'image' => 0,
+        'club' => 0,
+        'club_topic' => 0,
+        'page' => 0,
+        'profile' => 0,
+        'story' => 0,
+        'vehicle' => 0,
+      ),
+      'validate_argument_node_access' => 0,
+      'validate_argument_nid_type' => 'nid',
+      'validate_argument_vocabulary' => array(
+        '1' => 0,
+        '3' => 0,
+      ),
+      'validate_argument_type' => 'tid',
+      'validate_argument_transform' => 0,
+      'validate_user_restrict_roles' => 0,
+      'validate_argument_node_flag_name' => '*relationship*',
+      'validate_argument_node_flag_test' => 'flaggable',
+      'validate_argument_node_flag_id_type' => 'id',
+      'validate_argument_user_flag_name' => '*relationship*',
+      'validate_argument_user_flag_test' => 'flaggable',
+      'validate_argument_user_flag_id_type' => 'id',
+      'image_size' => array(
+        '_original' => '_original',
+        'thumbnail' => 'thumbnail',
+        'preview' => 'preview',
+        'home' => 'home',
+        'expanded' => 'expanded',
+        'block_icon' => 'block_icon',
+        'club_grid' => 'club_grid',
+        'full' => 'full',
+      ),
+      'validate_argument_is_member' => 'OG_VIEWS_DO_NOT_VALIDATE_MEMBERSHIP',
+      'validate_argument_group_node_type' => array(
+        'club' => 0,
+      ),
+      'validate_argument_php' => '',
+      'override' => array(
+        'button' => 'Override',
+      ),
+    ),
+  ));
+  $handler->override_option('filters', array(
+    'status' => array(
+      'operator' => '=',
+      'value' => '1',
+      'group' => '0',
+      'exposed' => FALSE,
+      'expose' => array(
+        'operator' => FALSE,
+        'label' => '',
+      ),
+      'id' => 'status',
+      'table' => 'node',
+      'field' => 'status',
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('access', array(
+    'type' => 'none',
+  ));
+  $handler->override_option('cache', array(
+    'type' => 'none',
+  ));
+  $handler = $view->new_display('page', 'Page', 'page_1');
+  $handler->override_option('path', 'flags/lists/%');
+  $handler->override_option('menu', array(
+    'type' => 'none',
+    'title' => '',
+    'description' => '',
+    'weight' => 0,
+    'name' => 'navigation',
+  ));
+  $handler->override_option('tab_options', array(
+    'type' => 'none',
+    'title' => '',
+    'description' => '',
+    'weight' => 0,
+    'name' => 'navigation',
+  ));
+
+ $views[$view->name] = $view;
+  return $views;
+}

+ 26 - 0
sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_argument_fid.inc

@@ -0,0 +1,26 @@
+<?php
+/**
+ * @file
+ * Provide list fid argument handler.
+ */
+
+/**
+ * Argument handler to accept a list id.
+ */
+class flag_lists_handler_argument_fid extends views_handler_argument_numeric {
+  /**
+   * Override the behavior of title(). Get the title of the list.
+   */
+  function title_query() {
+    $titles = array();
+    $result = db_select('flag_lists_flags', 'fl')
+      ->fields('fl', array('title'))
+      ->condition('fl.fid', $this->value, 'IN')
+      ->execute();
+    foreach ($result as $term) {
+      $titles[] = check_plain($term->title);
+    }
+    return $titles;
+  }
+}
+

+ 56 - 0
sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_field_list.inc

@@ -0,0 +1,56 @@
+<?php
+// $I$
+/**
+ * @file
+ * Contains the basic 'list title' field handler.
+ */
+
+/**
+ * Field handler to provide simple renderer that allows linking to a list.
+ */
+class flag_lists_handler_field_list extends views_handler_field {
+  /**
+   * Constructor to provide additional field to add.
+   */
+  function construct() {
+    parent::construct();
+    $this->additional_fields['fid'] = array('table' => 'flag_lists_flags', 'field' => 'fid');
+    $this->additional_fields['uid'] = array('table' => 'flag_lists_flags', 'field' => 'uid');
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['link_to_list'] = array('default' => FALSE);
+    return $options;
+  }
+
+  /**
+   * Provide link to list option
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['link_to_list'] = array(
+      '#title' => t('Link this field to its list'),
+      '#description' => t('This will override any other link you have set.'),
+      '#type' => 'checkbox',
+      '#default_value' => !empty($this->options['link_to_list']),
+    );
+  }
+
+  /**
+   * Render whatever the data is as a link to the list.
+   *
+   * Data should be made XSS safe prior to calling this function.
+   */
+  function render_link($data, $values) {
+    if (!empty($this->options['link_to_list']) && $data !== NULL && $data !== '') {
+      $this->options['alter']['make_link'] = TRUE;
+      $this->options['alter']['path'] = "user/" . $values->{$this->aliases['uid']} . "/flags/lists/" . $values->{$this->aliases['fid']};
+    }
+    return $data;
+  }
+
+  function render($values) {
+    return $this->render_link(check_plain($values->{$this->field_alias}), $values);
+  }
+}

+ 50 - 0
sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_field_list_delete.inc

@@ -0,0 +1,50 @@
+<?php
+// $I$
+/**
+ * @file
+ * Contains the basic 'list delete' field handler.
+ */
+
+/**
+ * Field handler to provide simple renderer that links to the list edit page.
+ */
+class flag_lists_handler_field_list_delete extends views_handler_field {
+  function construct() {
+    parent::construct();
+    $this->additional_fields['fid'] = 'fid';
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['text'] = array('default' => '', 'translatable' => TRUE);
+
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['text'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Text to display'),
+      '#default_value' => $this->options['text'],
+    );
+  }
+
+  function query() {
+    $this->ensure_my_table();
+    $this->add_additional_fields();
+  }
+
+  function render($values) {
+    $fid = $values->{$this->aliases['fid']};
+
+    // Check delete access.
+    if (!flag_lists_is_owner('delete', $fid)) {
+      return;
+    }
+
+    $text = !empty($this->options['text']) ? $this->options['text'] : t('delete');
+    return l($text, "flags/lists/delete/" . $fid,  array('query' => drupal_get_destination()));
+  }
+}

+ 50 - 0
sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_field_list_edit.inc

@@ -0,0 +1,50 @@
+<?php
+// $I$
+/**
+ * @file
+ * Contains the basic 'list edit' field handler.
+ */
+
+/**
+ * Field handler to provide simple renderer that links to the list edit page.
+ */
+class flag_lists_handler_field_list_edit extends views_handler_field {
+  function construct() {
+    parent::construct();
+    $this->additional_fields['fid'] = 'fid';
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['text'] = array('default' => '', 'translatable' => TRUE);
+
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['text'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Text to display'),
+      '#default_value' => $this->options['text'],
+    );
+  }
+
+  function query() {
+    $this->ensure_my_table();
+    $this->add_additional_fields();
+  }
+
+  function render($values) {
+    $fid = $values->{$this->aliases['fid']};
+
+    // Check edit access.
+    if (!flag_lists_is_owner('edit', $fid)) {
+      return;
+    }
+
+    $text = !empty($this->options['text']) ? $this->options['text'] : t('edit');
+    return l($text, "flags/lists/edit/" . $fid,  array('query' => drupal_get_destination()));
+  }
+}

+ 94 - 0
sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_field_ops.inc

@@ -0,0 +1,94 @@
+<?php
+
+class flag_lists_handler_field_ops extends views_handler_field {
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['flo'] = array(
+      'contains' => array(
+        'force_single' => array('default' => FALSE),
+        'operation' => array('default' => 'flag'),
+      ),
+    );
+
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $form['flo'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Flag lists operations'),
+      '#collapsible' => FALSE,
+      '#collapsed' => FALSE,
+    );
+    $form['flo']['force_single'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Force single'),
+      '#default_value' => $this->options['flo']['force_single'],
+      '#description' => t('Check this box to restrict selection to a single value.'),
+    );
+    $form['flo']['operation'] = array(
+      '#type' => 'radios',
+      '#title' => t('Operation'),
+      '#default_value' => $this->options['flo']['operation'],
+      '#description' => t('The flag lists operation for this selection.'),
+      '#options' => array(
+        'flag' => 'Add to list',
+        'unflag' => 'Remove from list',
+      ),
+      '#required' => TRUE,
+    );
+  }
+
+  /**
+   * If the view is using a table style, provide a
+   * placeholder for a "select all" checkbox.
+   */
+  function label() {
+    if ($this->view->style_plugin instanceof views_plugin_style_table && !$this->options['flo']['force_single']) {
+      return '<!--flag-lists-ops-select-all-->';
+    }
+    else {
+      return parent::label();
+    }
+  }
+
+  function render($values) {
+    return '<!--form-item-' . $this->options['id'] . '--' . $this->view->row_index . '-->';
+  }
+
+  function views_form(&$form, &$form_state) {
+    // The view is empty, abort.
+    if (empty($this->view->result)) {
+      return;
+    }
+
+    $form[$this->options['id']] = array(
+      '#tree' => TRUE,
+    );
+
+    // At this point, the query has already been run, so we can access the results
+    // in order to get the base key value (for example, nid for nodes).
+    foreach ($this->view->result as $row_index => $row) {
+      $entity_id = $this->get_value($row);
+
+      if ($this->options['flo']['force_single']) {
+        $form[$this->options['id']][$row_index] = array(
+          '#type' => 'radio',
+          '#parents' => array($this->options['id']),
+          '#return_value' => $entity_id,
+        );
+      }
+      else {
+        $form[$this->options['id']][$row_index] = array(
+          '#type' => 'checkbox',
+          '#return_value' => $entity_id . (isset($row->flag_lists_flags_fid) ? ('-' . $row->flag_lists_flags_fid) : ''),
+          '#default_value' => FALSE,
+          '#attributes' => array('class' => array('flo-select')),
+        );
+      }
+    }
+  }
+}

+ 55 - 0
sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_field_template.inc

@@ -0,0 +1,55 @@
+<?php
+// $I$
+/**
+ * @file
+ * Contains the basic 'list template' field handler.
+ */
+
+/**
+ * Field handler to provide simple renderer that allows linking to a list's template flag.
+ */
+class flag_lists_handler_field_template extends views_handler_field {
+  /**
+   * Constructor to provide additional field to add.
+   */
+  function construct() {
+    parent::construct();
+    $this->additional_fields['name'] = array('table' => 'flags', 'field' => 'name');
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['link_to_template'] = array('default' => FALSE);
+    return $options;
+  }
+
+  /**
+   * Provide link to list option
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['link_to_template'] = array(
+      '#title' => t('Link this field to its list template'),
+      '#description' => t('This will override any other link you have set.'),
+      '#type' => 'checkbox',
+      '#default_value' => !empty($this->options['link_to_template']),
+    );
+  }
+
+  /**
+   * Render whatever the data is as a link to the list.
+   *
+   * Data should be made XSS safe prior to calling this function.
+   */
+  function render_link($data, $values) {
+    if (!empty($this->options['link_to_template']) && $data !== NULL && $data !== '') {
+      $this->options['alter']['make_link'] = TRUE;
+      $this->options['alter']['path'] = "admin/build/flags/edit/" . $values->{$this->aliases['name']};
+    }
+    return $data;
+  }
+
+  function render($values) {
+    return $this->render_link(check_plain($values->{$this->field_alias}), $values);
+  }
+}

+ 65 - 0
sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_field_template_types.inc

@@ -0,0 +1,65 @@
+<?php
+/**
+ * @file flag_lists_handler_field_template_types.inc
+ * Field handler to provide a list of template node types.
+ */
+class flag_lists_handler_field_template_types extends views_handler_field_prerender_list {
+  function construct() {
+    parent::construct();
+    $this->additional_fields['name'] = array('table' => 'flags', 'field' => 'name');
+  }
+  function query() {
+    $this->add_additional_fields();
+    $this->field_alias = $this->aliases['name'];
+  }
+
+  function pre_render($values) {
+    $names = array();
+    $this->items = array();
+
+    foreach ($values as $result) {
+      $names[] = $result->{$this->aliases['name']};
+    }
+
+    if (count($names)) {
+      $query = db_select('flag_lists_types', 'flt');
+      $query->innerJoin('flags', 'f', 'flt.name = f.name');
+      $result = $query->fields('flt', array('type', 'name'))
+        ->condition('f.name', $names, 'IN')
+        ->orderBy('flt.type')
+        ->execute();
+      foreach ($result as $type) {
+        $this->items[$type->name][$type->type] = check_plain($type->type);
+      }
+    }
+  }
+
+  function render($values) {
+    $field = $values->{$this->field_alias};
+    if (!empty($this->items[$field])) {
+      if ($this->options['type'] == 'separator') {
+        return implode($this->sanitize_value($this->options['separator']), $this->items[$field]);
+      }
+      else {
+        return theme('item_list',
+          array(
+            'items' => $this->items[$field],
+            'title' => NULL,
+            'type' => $this->options['type']
+          ));
+      }
+    }
+  }
+
+  function get_value($values, $field = NULL, $raw = FALSE) {
+    if ($raw) {
+      return parent::get_value($values, $field);
+    }
+    $item = $this->get_items($values);
+    $item = (array) $item;
+    if (isset($field) && isset($item[$field])) {
+      return $item[$field];
+    }
+    return $item;
+  }
+}

+ 17 - 0
sites/all/modules/contrib/flag/flag_lists/includes/flag_lists_handler_filter_template.inc

@@ -0,0 +1,17 @@
+<?php
+/**
+ * @file flag_lists_handler_filter_template.inc
+ * Filter by list template
+ */
+class flag_lists_handler_filter_template extends views_handler_filter_in_operator {
+  function get_value_options() {
+    if (!isset($this->value_options)) {
+      $this->value_title = t('List templates');
+      $templates = flag_lists_get_templates();
+      foreach ($templates as $template) {
+        $options[$template->name] = $template->name;
+      }
+      $this->value_options = $options;
+    }
+  }
+}

+ 79 - 0
sites/all/modules/contrib/flag/flag_lists/js/flag_lists_ops.js

@@ -0,0 +1,79 @@
+(function ($) {
+  Drupal.behaviors.flagListsOps = {
+    attach: function(context) {
+      // Hide the go button, as it is not needed for JS enabled browsers.
+      $('.flag-lists-ops-go', context).hide();
+
+      // Make select all checkbox work
+      $('input.flo-table-select-all', context).each(function(i) {
+        var selectall = $(this);
+
+        if (!selectall.hasClass('processed')) {
+          selectall.change(function(e) {
+            $('input.flo-select', $(this).parents('form')).attr('checked', $(this).attr('checked'));
+          }).addClass('processed');
+        }
+      });
+
+      // Animate the deletion for AJAX deleting.
+      $('.flo-deleted-value', context).each(function(i) {
+        var parent = $(this).parents('.view');
+        $('.flo-select[value='+$(this).val()+']', parent).each(function(i) {
+          $(this).parents('.views-row, tr').fadeOut().delay(300).remove();
+        });
+      });
+
+      // Add new options to bottom of list ops dropdown to create new lists on the spot
+      $('.flag-lists-ops-dropdown', context).each(function(i) {
+        var select = $(this);
+        if (!select.hasClass('new-list-processed')) {
+          select.addClass('new-list-processed');
+
+          if (Drupal.settings.flag_lists.types.length > 0) {
+            $(this).after('<a href="#" class="create-a-new-list">New list?</a><div class="new-list-form"><form><select name="type" class="type"></select><label for="name">List name</label><input type="textfield" name="name" class="name" /></form></div>');
+            var dialog = $('.new-list-form', $(this).parent()).dialog({
+              autoOpen: false,
+              height: 300,
+              width: 350,
+              modal: true,
+              buttons: {
+                "Create a new list": function() {
+                  var name = $('input.name', $(this)).val();
+                  var type = $('select.type', $(this)).val();
+
+                  $.getJSON(Drupal.settings.flag_lists.json_path.replace('%', type)+'?name='+name, function(data) {
+                    if (data.error) {
+                      alert(data.error);
+                    }
+                    else {
+                      select.append('<option value="'+data.flag.fid+'">'+data.flag.title+'</option>');
+                      $('input.name', $(this)).val('');
+                      dialog.dialog('close');
+                    }
+                  });
+                },
+                Cancel: function() {
+                  dialog.dialog('close');
+                }
+              },
+              close: function() {
+
+              }
+            });
+            $('.create-a-new-list', $(this).parent())
+              .button()
+              .click(function(e) {
+                dialog.dialog('open');
+              });
+          }
+
+          // Put entries into the optgroup
+          for (j in Drupal.settings.flag_lists.types) {
+            var type = Drupal.settings.flag_lists.types[j];
+            $('.new-list-form form select.type').append('<option value="'+type+'" class="'+type+'">List for '+type+'</option>');
+          }
+        }
+      });
+    }
+  }
+})(jQuery);

+ 9 - 0
sites/all/modules/contrib/flag/flag_lists/theme/flag_lists.css

@@ -0,0 +1,9 @@
+.block-flag_lists .flag-message {
+  position: relative;
+  clear: both;
+  top:0;
+  left:0;
+  line-height: normal;
+  width: auto;
+  font-size: .8em;
+}