summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKatherine Senzee2010-11-11 00:38:19 (GMT)
committerKatherine Senzee2010-11-11 00:38:19 (GMT)
commit5ed421159a76a0815baac3aeb97c147e478edce9 (patch)
tree943b3075601475698d96fcd757c2518ec717bd54
Initial commit of CVS checkout.
-rw-r--r--CHANGELOG.txt755
-rw-r--r--CVS/Entries12
-rw-r--r--CVS/Entries.Log15
-rw-r--r--CVS/Repository1
-rw-r--r--CVS/Root1
-rw-r--r--CVS/Tag1
-rw-r--r--D7UPGRADE.txt2
-rw-r--r--README.txt28
-rw-r--r--css/CVS/Entries7
-rw-r--r--css/CVS/Repository1
-rw-r--r--css/CVS/Root1
-rw-r--r--css/CVS/Tag1
-rw-r--r--css/views-admin.css671
-rw-r--r--css/views-list-rtl.css28
-rw-r--r--css/views-list.css80
-rw-r--r--css/views-rtl.css6
-rw-r--r--css/views-tabs.css5
-rw-r--r--css/views.css57
-rw-r--r--docs/CVS/Entries2
-rw-r--r--docs/CVS/Repository1
-rw-r--r--docs/CVS/Root1
-rw-r--r--docs/CVS/Tag1
-rw-r--r--docs/docs.php685
-rw-r--r--documentation-standards.txt6
-rw-r--r--handlers/CVS/Entries39
-rw-r--r--handlers/CVS/Repository1
-rw-r--r--handlers/CVS/Root1
-rw-r--r--handlers/CVS/Tag1
-rw-r--r--handlers/views_handler_area.inc105
-rw-r--r--handlers/views_handler_area_text.inc58
-rw-r--r--handlers/views_handler_argument.inc937
-rw-r--r--handlers/views_handler_argument_date.inc67
-rw-r--r--handlers/views_handler_argument_formula.inc57
-rw-r--r--handlers/views_handler_argument_group_by_numeric.inc18
-rw-r--r--handlers/views_handler_argument_many_to_one.inc171
-rw-r--r--handlers/views_handler_argument_null.inc60
-rw-r--r--handlers/views_handler_argument_numeric.inc94
-rw-r--r--handlers/views_handler_argument_string.inc234
-rw-r--r--handlers/views_handler_field.inc848
-rw-r--r--handlers/views_handler_field_boolean.inc74
-rw-r--r--handlers/views_handler_field_counter.inc42
-rw-r--r--handlers/views_handler_field_custom.inc35
-rw-r--r--handlers/views_handler_field_date.inc77
-rw-r--r--handlers/views_handler_field_group_by_numeric.inc44
-rw-r--r--handlers/views_handler_field_markup.inc46
-rw-r--r--handlers/views_handler_field_math.inc74
-rw-r--r--handlers/views_handler_field_numeric.inc126
-rw-r--r--handlers/views_handler_field_prerender_list.inc122
-rw-r--r--handlers/views_handler_field_url.inc39
-rw-r--r--handlers/views_handler_filter.inc533
-rw-r--r--handlers/views_handler_filter_boolean_operator.inc153
-rw-r--r--handlers/views_handler_filter_boolean_operator_string.inc28
-rw-r--r--handlers/views_handler_filter_date.inc152
-rw-r--r--handlers/views_handler_filter_equality.inc39
-rw-r--r--handlers/views_handler_filter_group_by_numeric.inc47
-rw-r--r--handlers/views_handler_filter_in_operator.inc359
-rw-r--r--handlers/views_handler_filter_many_to_one.inc106
-rw-r--r--handlers/views_handler_filter_numeric.inc302
-rw-r--r--handlers/views_handler_filter_string.inc325
-rw-r--r--handlers/views_handler_relationship.inc152
-rw-r--r--handlers/views_handler_sort.inc192
-rw-r--r--handlers/views_handler_sort_date.inc70
-rw-r--r--handlers/views_handler_sort_formula.inc48
-rw-r--r--handlers/views_handler_sort_group_by_numeric.inc29
-rw-r--r--handlers/views_handler_sort_menu_hierarchy.inc20
-rw-r--r--handlers/views_handler_sort_random.inc27
-rw-r--r--help/CVS/Entries50
-rw-r--r--help/CVS/Entries.Log1
-rw-r--r--help/CVS/Repository1
-rw-r--r--help/CVS/Root1
-rw-r--r--help/CVS/Tag1
-rw-r--r--help/about.html18
-rw-r--r--help/analyze-theme.html24
-rw-r--r--help/api-default-views.html106
-rw-r--r--help/api-example.html181
-rw-r--r--help/api-handlers.html70
-rw-r--r--help/api-plugins.html79
-rw-r--r--help/api-tables.html235
-rw-r--r--help/api-upgrading.html37
-rw-r--r--help/api.html23
-rw-r--r--help/argument.html58
-rw-r--r--help/display-attachment.html2
-rw-r--r--help/display-block.html11
-rw-r--r--help/display-default.html5
-rw-r--r--help/display-feed.html2
-rw-r--r--help/display-page.html6
-rw-r--r--help/display.html8
-rw-r--r--help/embed.html25
-rw-r--r--help/example-author-block.html78
-rw-r--r--help/example-recent-stories.html58
-rw-r--r--help/example-user-feed.html74
-rw-r--r--help/example-users-by-role.html48
-rw-r--r--help/field.html6
-rw-r--r--help/filter.html13
-rw-r--r--help/getting-started.html23
-rw-r--r--help/images/CVS/Entries31
-rw-r--r--help/images/CVS/Repository1
-rw-r--r--help/images/CVS/Root1
-rw-r--r--help/images/CVS/Tag1
-rw-r--r--help/images/node-term_node-term_data-large.pngbin0 -> 4141 bytes
-rw-r--r--help/images/node-term_node-term_data.pngbin0 -> 3457 bytes
-rw-r--r--help/images/overview-ui-large.pngbin0 -> 83826 bytes
-rw-r--r--help/images/overview-ui-small.pngbin0 -> 44890 bytes
-rw-r--r--help/images/style-breakdown-large.pngbin0 -> 47381 bytes
-rw-r--r--help/images/style-breakdown.pngbin0 -> 15182 bytes
-rw-r--r--help/images/views1-admin-large.pngbin0 -> 67878 bytes
-rw-r--r--help/images/views1-admin.pngbin0 -> 24372 bytes
-rw-r--r--help/images/views1-changeviewtype-large.pngbin0 -> 37394 bytes
-rw-r--r--help/images/views1-changeviewtype.pngbin0 -> 17456 bytes
-rw-r--r--help/images/views2-addaview-large.pngbin0 -> 46121 bytes
-rw-r--r--help/images/views2-addaview.pngbin0 -> 19262 bytes
-rw-r--r--help/images/views2-adddisplay-large.pngbin0 -> 43413 bytes
-rw-r--r--help/images/views2-adddisplay.pngbin0 -> 19976 bytes
-rw-r--r--help/images/views2-addfields-large.pngbin0 -> 29487 bytes
-rw-r--r--help/images/views2-addfields.pngbin0 -> 13043 bytes
-rw-r--r--help/images/views2-addfieldsajax-large.pngbin0 -> 26423 bytes
-rw-r--r--help/images/views2-addfieldsajax.pngbin0 -> 16005 bytes
-rw-r--r--help/images/views2-admin-large.pngbin0 -> 53418 bytes
-rw-r--r--help/images/views2-admin.pngbin0 -> 19994 bytes
-rw-r--r--help/images/views2-changedisplaystyle-large.pngbin0 -> 43090 bytes
-rw-r--r--help/images/views2-changedisplaystyle.pngbin0 -> 16163 bytes
-rw-r--r--help/images/views2-fieldspreview-large.pngbin0 -> 40484 bytes
-rw-r--r--help/images/views2-fieldspreview.pngbin0 -> 12480 bytes
-rw-r--r--help/images/views2-newview-large.pngbin0 -> 36263 bytes
-rw-r--r--help/images/views2-newview.pngbin0 -> 17308 bytes
-rw-r--r--help/images/views2-rearrangefields-large.pngbin0 -> 34183 bytes
-rw-r--r--help/images/views2-rearrangefields.pngbin0 -> 19129 bytes
-rw-r--r--help/images/views2-tablestyle-large.pngbin0 -> 38890 bytes
-rw-r--r--help/images/views2-tablestyle.pngbin0 -> 20917 bytes
-rw-r--r--help/menu.html22
-rw-r--r--help/new.html114
-rw-r--r--help/overrides.html7
-rw-r--r--help/path.html8
-rw-r--r--help/relationship.html14
-rw-r--r--help/sort.html25
-rw-r--r--help/style-comment-rss.html2
-rw-r--r--help/style-fields.html6
-rw-r--r--help/style-grid.html21
-rw-r--r--help/style-list.html21
-rw-r--r--help/style-node-rss.html2
-rw-r--r--help/style-node.html10
-rw-r--r--help/style-row.html4
-rw-r--r--help/style-rss.html4
-rw-r--r--help/style-summary-unformatted.html4
-rw-r--r--help/style-summary.html4
-rw-r--r--help/style-table.html14
-rw-r--r--help/style-unformatted.html2
-rw-r--r--help/style.html15
-rw-r--r--help/theme-css.html76
-rw-r--r--help/updating.html3
-rw-r--r--help/upgrading.html6
-rw-r--r--help/using-theme.html51
-rw-r--r--help/view-type.html22
-rw-r--r--help/views.help.ini204
-rw-r--r--images/CVS/Entries6
-rw-r--r--images/CVS/Repository1
-rw-r--r--images/CVS/Root1
-rw-r--r--images/CVS/Tag1
-rw-r--r--images/arrow-active.pngbin0 -> 313 bytes
-rw-r--r--images/expanded-options.pngbin0 -> 228 bytes
-rw-r--r--images/overridden.gifbin0 -> 175 bytes
-rw-r--r--images/sprites.pngbin0 -> 1926 bytes
-rw-r--r--images/status-active.gifbin0 -> 2196 bytes
-rw-r--r--includes/CVS/Entries12
-rw-r--r--includes/CVS/Repository1
-rw-r--r--includes/CVS/Root1
-rw-r--r--includes/CVS/Tag1
-rw-r--r--includes/admin.inc3390
-rw-r--r--includes/ajax.inc353
-rw-r--r--includes/analyze.inc109
-rw-r--r--includes/base.inc199
-rw-r--r--includes/cache.inc201
-rw-r--r--includes/convert.inc552
-rw-r--r--includes/form.inc8
-rw-r--r--includes/handlers.inc1289
-rw-r--r--includes/plugins.inc443
-rw-r--r--includes/tabs.inc196
-rw-r--r--includes/view.inc2090
-rw-r--r--js/CVS/Entries5
-rw-r--r--js/CVS/Repository1
-rw-r--r--js/CVS/Root1
-rw-r--r--js/CVS/Tag1
-rw-r--r--js/ajax.js129
-rw-r--r--js/ajax_view.js168
-rw-r--r--js/base.js128
-rw-r--r--js/tabs.js438
-rw-r--r--modules/CVS/Entries33
-rw-r--r--modules/CVS/Entries.Log15
-rw-r--r--modules/CVS/Repository1
-rw-r--r--modules/CVS/Root1
-rw-r--r--modules/CVS/Tag1
-rw-r--r--modules/aggregator.views.inc416
-rw-r--r--modules/aggregator/CVS/Entries9
-rw-r--r--modules/aggregator/CVS/Repository1
-rw-r--r--modules/aggregator/CVS/Root1
-rw-r--r--modules/aggregator/CVS/Tag1
-rw-r--r--modules/aggregator/views_handler_argument_aggregator_category_cid.inc20
-rw-r--r--modules/aggregator/views_handler_argument_aggregator_fid.inc20
-rw-r--r--modules/aggregator/views_handler_argument_aggregator_iid.inc24
-rw-r--r--modules/aggregator/views_handler_field_aggregator_category.inc53
-rw-r--r--modules/aggregator/views_handler_field_aggregator_item_description.inc13
-rw-r--r--modules/aggregator/views_handler_field_aggregator_title_link.inc44
-rw-r--r--modules/aggregator/views_handler_filter_aggregator_category_cid.inc20
-rw-r--r--modules/aggregator/views_plugin_row_aggregator_rss.inc73
-rw-r--r--modules/book.views.inc124
-rw-r--r--modules/book.views_convert.inc81
-rw-r--r--modules/comment.views.inc551
-rw-r--r--modules/comment.views_convert.inc132
-rw-r--r--modules/comment.views_default.inc317
-rw-r--r--modules/comment/CVS/Entries23
-rw-r--r--modules/comment/CVS/Repository1
-rw-r--r--modules/comment/CVS/Root1
-rw-r--r--modules/comment/CVS/Tag1
-rw-r--r--modules/comment/views_handler_argument_comment_user_uid.inc52
-rw-r--r--modules/comment/views_handler_field_comment.inc50
-rw-r--r--modules/comment/views_handler_field_comment_depth.inc14
-rw-r--r--modules/comment/views_handler_field_comment_link.inc38
-rw-r--r--modules/comment/views_handler_field_comment_link_delete.inc15
-rw-r--r--modules/comment/views_handler_field_comment_link_edit.inc48
-rw-r--r--modules/comment/views_handler_field_comment_link_reply.inc16
-rw-r--r--modules/comment/views_handler_field_comment_node_link.inc62
-rw-r--r--modules/comment/views_handler_field_comment_username.inc50
-rw-r--r--modules/comment/views_handler_field_last_comment_timestamp.inc18
-rw-r--r--modules/comment/views_handler_field_ncs_last_comment_name.inc48
-rw-r--r--modules/comment/views_handler_field_ncs_last_updated.inc12
-rw-r--r--modules/comment/views_handler_field_node_comment.inc19
-rw-r--r--modules/comment/views_handler_field_node_new_comments.inc105
-rw-r--r--modules/comment/views_handler_filter_comment_user_uid.inc24
-rw-r--r--modules/comment/views_handler_filter_ncs_last_updated.inc18
-rw-r--r--modules/comment/views_handler_filter_node_comment.inc15
-rw-r--r--modules/comment/views_handler_sort_comment_thread.inc21
-rw-r--r--modules/comment/views_handler_sort_ncs_last_comment_name.inc23
-rw-r--r--modules/comment/views_handler_sort_ncs_last_updated.inc13
-rw-r--r--modules/comment/views_plugin_row_comment_rss.inc65
-rw-r--r--modules/comment/views_plugin_row_comment_view.inc46
-rw-r--r--modules/contact.views.inc18
-rw-r--r--modules/contact/CVS/Entries2
-rw-r--r--modules/contact/CVS/Repository1
-rw-r--r--modules/contact/CVS/Root1
-rw-r--r--modules/contact/CVS/Tag1
-rw-r--r--modules/contact/views_handler_field_contact_link.inc73
-rw-r--r--modules/field.views.inc256
-rw-r--r--modules/field/CVS/Entries3
-rw-r--r--modules/field/CVS/Repository1
-rw-r--r--modules/field/CVS/Root1
-rw-r--r--modules/field/CVS/Tag1
-rw-r--r--modules/field/views_handler_field_field.inc204
-rw-r--r--modules/field/views_handler_filter_field_list.inc9
-rw-r--r--modules/filter.views.inc41
-rw-r--r--modules/filter/CVS/Entries2
-rw-r--r--modules/filter/CVS/Repository1
-rw-r--r--modules/filter/CVS/Root1
-rw-r--r--modules/filter/CVS/Tag1
-rw-r--r--modules/filter/views_handler_field_filter_format_name.inc29
-rw-r--r--modules/locale.views.inc207
-rw-r--r--modules/locale/CVS/Entries9
-rw-r--r--modules/locale/CVS/Repository1
-rw-r--r--modules/locale/CVS/Root1
-rw-r--r--modules/locale/CVS/Tag1
-rw-r--r--modules/locale/views_handler_argument_locale_group.inc35
-rw-r--r--modules/locale/views_handler_argument_locale_language.inc33
-rw-r--r--modules/locale/views_handler_field_locale_group.inc14
-rw-r--r--modules/locale/views_handler_field_locale_language.inc12
-rw-r--r--modules/locale/views_handler_field_locale_link_edit.inc45
-rw-r--r--modules/locale/views_handler_filter_locale_group.inc18
-rw-r--r--modules/locale/views_handler_filter_locale_language.inc17
-rw-r--r--modules/locale/views_handler_filter_locale_version.inc22
-rw-r--r--modules/node.views.inc702
-rw-r--r--modules/node.views_convert.inc182
-rw-r--r--modules/node.views_default.inc378
-rw-r--r--modules/node/CVS/Entries24
-rw-r--r--modules/node/CVS/Repository1
-rw-r--r--modules/node/CVS/Root1
-rw-r--r--modules/node/CVS/Tag1
-rw-r--r--modules/node/views_handler_argument_dates_various.inc170
-rw-r--r--modules/node/views_handler_argument_node_language.inc32
-rw-r--r--modules/node/views_handler_argument_node_nid.inc25
-rw-r--r--modules/node/views_handler_argument_node_type.inc34
-rw-r--r--modules/node/views_handler_argument_node_vid.inc27
-rw-r--r--modules/node/views_handler_field_history_user_timestamp.inc74
-rw-r--r--modules/node/views_handler_field_node.inc70
-rw-r--r--modules/node/views_handler_field_node_link.inc39
-rw-r--r--modules/node/views_handler_field_node_link_delete.inc28
-rw-r--r--modules/node/views_handler_field_node_link_edit.inc28
-rw-r--r--modules/node/views_handler_field_node_path.inc39
-rw-r--r--modules/node/views_handler_field_node_revision.inc60
-rw-r--r--modules/node/views_handler_field_node_revision_link_delete.inc36
-rw-r--r--modules/node/views_handler_field_node_revision_link_revert.inc37
-rw-r--r--modules/node/views_handler_field_node_type.inc42
-rw-r--r--modules/node/views_handler_filter_history_user_timestamp.inc74
-rw-r--r--modules/node/views_handler_filter_node_access.inc33
-rw-r--r--modules/node/views_handler_filter_node_status.inc14
-rw-r--r--modules/node/views_handler_filter_node_type.inc17
-rw-r--r--modules/node/views_plugin_argument_default_node.inc27
-rw-r--r--modules/node/views_plugin_argument_validate_node.inc126
-rw-r--r--modules/node/views_plugin_row_node_rss.inc111
-rw-r--r--modules/node/views_plugin_row_node_view.inc84
-rw-r--r--modules/poll.views.inc56
-rw-r--r--modules/profile.views.inc223
-rw-r--r--modules/profile.views_convert.inc40
-rw-r--r--modules/profile/CVS/Entries4
-rw-r--r--modules/profile/CVS/Repository1
-rw-r--r--modules/profile/CVS/Root1
-rw-r--r--modules/profile/CVS/Tag1
-rw-r--r--modules/profile/views_handler_field_profile_date.inc82
-rw-r--r--modules/profile/views_handler_field_profile_list.inc34
-rw-r--r--modules/profile/views_handler_filter_profile_selection.inc24
-rw-r--r--modules/search.views.inc207
-rw-r--r--modules/search.views_convert.inc24
-rw-r--r--modules/search.views_default.inc150
-rw-r--r--modules/search/CVS/Entries6
-rw-r--r--modules/search/CVS/Repository1
-rw-r--r--modules/search/CVS/Root1
-rw-r--r--modules/search/CVS/Tag1
-rw-r--r--modules/search/views_handler_argument_search.inc50
-rw-r--r--modules/search/views_handler_field_search_score.inc82
-rw-r--r--modules/search/views_handler_filter_search.inc113
-rw-r--r--modules/search/views_handler_sort_search_score.inc25
-rw-r--r--modules/search/views_plugin_row_search_view.inc39
-rw-r--r--modules/statistics.views.inc251
-rw-r--r--modules/statistics.views_convert.inc52
-rw-r--r--modules/statistics.views_default.inc303
-rw-r--r--modules/statistics/CVS/Entries2
-rw-r--r--modules/statistics/CVS/Repository1
-rw-r--r--modules/statistics/CVS/Root1
-rw-r--r--modules/statistics/CVS/Tag1
-rw-r--r--modules/statistics/views_handler_field_accesslog_path.inc46
-rw-r--r--modules/system.views.inc471
-rw-r--r--modules/system/CVS/Entries8
-rw-r--r--modules/system/CVS/Repository1
-rw-r--r--modules/system/CVS/Root1
-rw-r--r--modules/system/CVS/Tag1
-rw-r--r--modules/system/views_handler_argument_file_fid.inc22
-rw-r--r--modules/system/views_handler_field_file.inc53
-rw-r--r--modules/system/views_handler_field_file_extension.inc15
-rw-r--r--modules/system/views_handler_field_file_filemime.inc32
-rw-r--r--modules/system/views_handler_field_file_status.inc11
-rw-r--r--modules/system/views_handler_field_file_uri.inc31
-rw-r--r--modules/system/views_handler_filter_file_status.inc13
-rw-r--r--modules/taxonomy.views.inc455
-rw-r--r--modules/taxonomy.views_convert.inc95
-rw-r--r--modules/taxonomy.views_default.inc183
-rw-r--r--modules/taxonomy/CVS/Entries16
-rw-r--r--modules/taxonomy/CVS/Repository1
-rw-r--r--modules/taxonomy/CVS/Root1
-rw-r--r--modules/taxonomy/CVS/Tag1
-rw-r--r--modules/taxonomy/views_handler_argument_taxonomy.inc20
-rw-r--r--modules/taxonomy/views_handler_argument_term_node_tid.inc42
-rw-r--r--modules/taxonomy/views_handler_argument_term_node_tid_depth.inc137
-rw-r--r--modules/taxonomy/views_handler_argument_term_node_tid_depth_modifier.inc59
-rw-r--r--modules/taxonomy/views_handler_argument_vocabulary_vid.inc20
-rw-r--r--modules/taxonomy/views_handler_field_taxonomy.inc65
-rw-r--r--modules/taxonomy/views_handler_field_term_link_edit.inc42
-rw-r--r--modules/taxonomy/views_handler_field_term_node_tid.inc138
-rw-r--r--modules/taxonomy/views_handler_filter_term_node_tid.inc337
-rw-r--r--modules/taxonomy/views_handler_filter_term_node_tid_depth.inc89
-rw-r--r--modules/taxonomy/views_handler_filter_vocabulary_machine_name.inc19
-rw-r--r--modules/taxonomy/views_handler_filter_vocabulary_vid.inc19
-rw-r--r--modules/taxonomy/views_handler_relationship_node_term_data.inc94
-rw-r--r--modules/taxonomy/views_plugin_argument_default_taxonomy_tid.inc130
-rw-r--r--modules/taxonomy/views_plugin_argument_validate_taxonomy_term.inc185
-rw-r--r--modules/translation.views.inc148
-rw-r--r--modules/translation/CVS/Entries9
-rw-r--r--modules/translation/CVS/Repository1
-rw-r--r--modules/translation/CVS/Root1
-rw-r--r--modules/translation/CVS/Tag1
-rw-r--r--modules/translation/views_handler_argument_node_tnid.inc25
-rw-r--r--modules/translation/views_handler_field_node_language.inc13
-rw-r--r--modules/translation/views_handler_field_node_link_translate.inc32
-rw-r--r--modules/translation/views_handler_field_node_translation_link.inc33
-rw-r--r--modules/translation/views_handler_filter_node_language.inc16
-rw-r--r--modules/translation/views_handler_filter_node_tnid.inc39
-rw-r--r--modules/translation/views_handler_filter_node_tnid_child.inc16
-rw-r--r--modules/translation/views_handler_relationship_translation.inc97
-rw-r--r--modules/upload.views.inc142
-rw-r--r--modules/upload.views_convert.inc108
-rw-r--r--modules/upload/CVS/Entries4
-rw-r--r--modules/upload/CVS/Repository1
-rw-r--r--modules/upload/CVS/Root1
-rw-r--r--modules/upload/CVS/Tag1
-rw-r--r--modules/upload/views_handler_field_upload_description.inc73
-rw-r--r--modules/upload/views_handler_field_upload_fid.inc88
-rw-r--r--modules/upload/views_handler_filter_upload_fid.inc18
-rw-r--r--modules/user.views.inc434
-rw-r--r--modules/user.views_convert.inc61
-rw-r--r--modules/user/CVS/Entries18
-rw-r--r--modules/user/CVS/Repository1
-rw-r--r--modules/user/CVS/Root1
-rw-r--r--modules/user/CVS/Tag1
-rw-r--r--modules/user/views_handler_argument_user_uid.inc29
-rw-r--r--modules/user/views_handler_argument_users_roles_rid.inc17
-rw-r--r--modules/user/views_handler_field_user.inc48
-rw-r--r--modules/user/views_handler_field_user_language.inc29
-rw-r--r--modules/user/views_handler_field_user_link.inc43
-rw-r--r--modules/user/views_handler_field_user_link_delete.inc18
-rw-r--r--modules/user/views_handler_field_user_link_edit.inc18
-rw-r--r--modules/user/views_handler_field_user_mail.inc33
-rw-r--r--modules/user/views_handler_field_user_name.inc63
-rw-r--r--modules/user/views_handler_field_user_picture.inc29
-rw-r--r--modules/user/views_handler_field_user_roles.inc48
-rw-r--r--modules/user/views_handler_filter_user_current.inc30
-rw-r--r--modules/user/views_handler_filter_user_name.inc144
-rw-r--r--modules/user/views_handler_filter_user_roles.inc11
-rw-r--r--modules/user/views_plugin_argument_default_current_user.inc19
-rw-r--r--modules/user/views_plugin_argument_default_user.inc69
-rw-r--r--modules/user/views_plugin_argument_validate_user.inc125
-rw-r--r--modules/views.views.inc78
-rw-r--r--plugins/CVS/Entries42
-rw-r--r--plugins/CVS/Repository1
-rw-r--r--plugins/CVS/Root1
-rw-r--r--plugins/CVS/Tag1
-rw-r--r--plugins/views_plugin_access.inc82
-rw-r--r--plugins/views_plugin_access_none.inc11
-rw-r--r--plugins/views_plugin_access_perm.inc45
-rw-r--r--plugins/views_plugin_access_role.inc62
-rw-r--r--plugins/views_plugin_argument_default.inc97
-rw-r--r--plugins/views_plugin_argument_default_fixed.inc44
-rw-r--r--plugins/views_plugin_argument_default_php.inc55
-rw-r--r--plugins/views_plugin_argument_validate.inc93
-rw-r--r--plugins/views_plugin_argument_validate_numeric.inc18
-rw-r--r--plugins/views_plugin_argument_validate_php.inc57
-rw-r--r--plugins/views_plugin_cache.inc292
-rw-r--r--plugins/views_plugin_cache_none.inc19
-rw-r--r--plugins/views_plugin_cache_time.inc59
-rw-r--r--plugins/views_plugin_display.inc2366
-rw-r--r--plugins/views_plugin_display_attachment.inc279
-rw-r--r--plugins/views_plugin_display_block.inc198
-rw-r--r--plugins/views_plugin_display_default.inc56
-rw-r--r--plugins/views_plugin_display_feed.inc202
-rw-r--r--plugins/views_plugin_display_page.inc495
-rw-r--r--plugins/views_plugin_exposed_form.inc247
-rw-r--r--plugins/views_plugin_exposed_form_basic.inc13
-rw-r--r--plugins/views_plugin_exposed_form_input_required.inc90
-rw-r--r--plugins/views_plugin_pager.inc214
-rw-r--r--plugins/views_plugin_pager_full.inc305
-rw-r--r--plugins/views_plugin_pager_mini.inc22
-rw-r--r--plugins/views_plugin_pager_none.inc62
-rw-r--r--plugins/views_plugin_pager_some.inc56
-rw-r--r--plugins/views_plugin_query.inc106
-rw-r--r--plugins/views_plugin_query_default.inc1276
-rw-r--r--plugins/views_plugin_row.inc148
-rw-r--r--plugins/views_plugin_row_fields.inc69
-rw-r--r--plugins/views_plugin_style.inc238
-rw-r--r--plugins/views_plugin_style_default.inc25
-rw-r--r--plugins/views_plugin_style_grid.inc53
-rw-r--r--plugins/views_plugin_style_jump_menu.inc160
-rw-r--r--plugins/views_plugin_style_list.inc38
-rw-r--r--plugins/views_plugin_style_rss.inc111
-rw-r--r--plugins/views_plugin_style_summary.inc75
-rw-r--r--plugins/views_plugin_style_summary_jump_menu.inc96
-rw-r--r--plugins/views_plugin_style_summary_unformatted.inc35
-rw-r--r--plugins/views_plugin_style_table.inc255
-rw-r--r--tests/CVS/Entries17
-rw-r--r--tests/CVS/Entries.Log2
-rw-r--r--tests/CVS/Repository1
-rw-r--r--tests/CVS/Root1
-rw-r--r--tests/CVS/Tag1
-rw-r--r--tests/handlers/CVS/Entries15
-rw-r--r--tests/handlers/CVS/Repository1
-rw-r--r--tests/handlers/CVS/Root1
-rw-r--r--tests/handlers/CVS/Tag1
-rw-r--r--tests/handlers/views_handler_area_text.test43
-rw-r--r--tests/handlers/views_handler_argument_null.test65
-rw-r--r--tests/handlers/views_handler_field_boolean.test64
-rw-r--r--tests/handlers/views_handler_field_custom.test40
-rw-r--r--tests/handlers/views_handler_field_date.test55
-rw-r--r--tests/handlers/views_handler_field_file_size.test58
-rw-r--r--tests/handlers/views_handler_field_url.test53
-rw-r--r--tests/handlers/views_handler_field_xss.test54
-rw-r--r--tests/handlers/views_handler_filter_date.test165
-rw-r--r--tests/handlers/views_handler_filter_in_operator.test90
-rw-r--r--tests/handlers/views_handler_filter_numeric.test216
-rw-r--r--tests/handlers/views_handler_sort.test117
-rw-r--r--tests/handlers/views_handler_sort_date.test89
-rw-r--r--tests/handlers/views_handler_sort_random.test85
-rw-r--r--tests/user/CVS/Entries3
-rw-r--r--tests/user/CVS/Repository1
-rw-r--r--tests/user/CVS/Root1
-rw-r--r--tests/user/CVS/Tag1
-rw-r--r--tests/user/views_user_argument_default.test87
-rw-r--r--tests/user/views_user_argument_validate.test114
-rw-r--r--tests/views_access.test149
-rw-r--r--tests/views_argument_default.test107
-rw-r--r--tests/views_argument_validator.test99
-rw-r--r--tests/views_basic.test174
-rw-r--r--tests/views_cache.test147
-rw-r--r--tests/views_exposed_form.test85
-rw-r--r--tests/views_glossary.test58
-rw-r--r--tests/views_groupby.test304
-rw-r--r--tests/views_handlers.test39
-rw-r--r--tests/views_module.test69
-rw-r--r--tests/views_pager.test428
-rw-r--r--tests/views_query.test400
-rw-r--r--tests/views_test.info10
-rw-r--r--tests/views_test.install6
-rw-r--r--tests/views_test.module37
-rw-r--r--tests/views_test.views_default.inc140
-rw-r--r--theme/CVS/Entries21
-rw-r--r--theme/CVS/Repository1
-rw-r--r--theme/CVS/Root1
-rw-r--r--theme/CVS/Tag1
-rw-r--r--theme/theme.inc758
-rw-r--r--theme/views-exposed-form.tpl.php76
-rw-r--r--theme/views-more.tpl.php17
-rw-r--r--theme/views-ui-edit-item.tpl.php46
-rw-r--r--theme/views-ui-edit-tab.tpl.php104
-rw-r--r--theme/views-ui-edit-view.tpl.php46
-rw-r--r--theme/views-ui-list-views.tpl.php42
-rw-r--r--theme/views-view-field.tpl.php23
-rw-r--r--theme/views-view-fields.tpl.php39
-rw-r--r--theme/views-view-grid.tpl.php37
-rw-r--r--theme/views-view-list.tpl.php21
-rw-r--r--theme/views-view-row-comment.tpl.php18
-rw-r--r--theme/views-view-row-node.tpl.php21
-rw-r--r--theme/views-view-row-rss.tpl.php15
-rw-r--r--theme/views-view-rss.tpl.php20
-rw-r--r--theme/views-view-summary-unformatted.tpl.php20
-rw-r--r--theme/views-view-summary.tpl.php20
-rw-r--r--theme/views-view-table.tpl.php42
-rw-r--r--theme/views-view-unformatted.tpl.php17
-rw-r--r--theme/views-view.tpl.php90
-rw-r--r--translations/CVS/Entries9
-rw-r--r--translations/CVS/Entries.Log2
-rw-r--r--translations/CVS/Repository1
-rw-r--r--translations/CVS/Root1
-rw-r--r--translations/CVS/Tag1
-rw-r--r--translations/de.po4439
-rw-r--r--translations/eo.po4100
-rw-r--r--translations/fr.po3951
-rw-r--r--translations/it.po4233
-rw-r--r--translations/pl.po3994
-rw-r--r--translations/sv.po4815
-rw-r--r--translations/uk.po4863
-rw-r--r--translations/views.pot4268
-rw-r--r--views.info302
-rw-r--r--views.install488
-rw-r--r--views.module1445
-rw-r--r--views2.doxy1252
-rw-r--r--views3.doxy1252
-rw-r--r--views_export/CVS/Entries4
-rw-r--r--views_export/CVS/Repository1
-rw-r--r--views_export/CVS/Root1
-rw-r--r--views_export/CVS/Tag1
-rw-r--r--views_export/views_export.css13
-rw-r--r--views_export/views_export.info8
-rw-r--r--views_export/views_export.module279
-rw-r--r--views_ui.info7
-rw-r--r--views_ui.module385
548 files changed, 86746 insertions, 0 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
new file mode 100644
index 0000000..a521bc9
--- /dev/null
+++ b/CHANGELOG.txt
@@ -0,0 +1,755 @@
+CHANGELOG for Views 3 for Drupal 7
+
+Views 3.x-7.x-dev
+ o #580320 by chaps2: Allow "always use more link" setting.
+ o #363516 by dagmar: Validate the uniqueness of exposed filter identifiers.
+ o #480162 by dereine: Count whitespace fields as empty for hiding labels.
+ o #622602: Missing ORDER BY in some views with tables due to incorrect test for default table sorting.
+ o #623498 by marcp: total_rows should be filled in if fetching all records.
+ o #535206: Attachment displays repeat exposed filters because exposed filters were left hanging around during cloning.
+ o #550560 by donquixote: Fix unterminated string in views.help.ini that breaks under php 5.3
+ o #592476 by Garrett Albright: Remove redundant CSS from views-list.css
+ o #581616 by cangeceiro: Defend text color from themes in Views UI.
+ o #589484 by Markus Petrux: External styles could not properly provide advanced help files.
+ o #494490 by Niels Hackius: User picture incorrectly set as an inline element when it should be block.
+ o #616956 by neochief: Exposed form labels should have "for" keyword.
+ o #620046 by cedric: Date validate handler does not fallback properly causing sporadic improper validation.
+ o #515564: Views UI would fail to rearrange with > 25 fields.
+ o #452384: Fix PHP 5.3 compatibility.
+ o #622608: Allow attachments to inherit pager data.
+ o #495606 by Roi Danton and dereine: Introduce views_get_view_result() as a fast way to get just the results of a view.
+ o #619884: Fix incorrect grouping for styles other than table.
+ o #638916 by dereine: views.help.ini strings need quoting to continue to work in PHP 5.3
+ o #576386 by jmorahan: Fix book sort help text to be more accurate by not telling you to do something that will not work.
+ o #630430 by cafuego: Fix typo in argument text.
+ o #324873 by dagmar: Show all paths when listing views, not just the first path.
+ o #651244 by dagmar: Other instances of <Any> are not translatable and should not be run through t().
+ o #653628: init declaration for views_handler_filter_many_to_one() did not match parent init.
+ o #657700: Fixed 'Override normal sorting if click sorting is used' setting on the table style plugin that was broken by #622602.
+ o #473698 by jrglasgow: Fix error in help text regarding custom theming.
+ o #387448 by johttp://drupal.org/files/issues/fix-pager.patchachim: Provide better help text to describe how to use sticky sort.
+ o #652716 by dagmar: "no single" flag on filter objects not completely respected, causing improper default filters.
+ o #648438 by dww: In rare circumstances, unnecessary term_node tables could be joined in when adding term_data relationships.
+ o #621780 by PaulMagrath: Even/Odd classes wrong with grouping due to row numbering no longer being sequential.
+ o #660140 by dagmar: Add a raw user name filter so that we can do more filtering purely on the user name.
+ o #383994 by bendiy: Allow column align setting on tables.
+ o #557372 by brush: Allow sorting by taxonomy term views by vocabulary ID and vocabulary name.
+ o #570558 by yhahn: Segment default views caching to conserve memory used by Views during normal operation.
+ o #373615 by dereine and lonelyrobot: Allow full set of date arguments for comment timestamp.
+ o #623392 by dww: Allow the use of synonyms in summaries for taxonomy arguments.
+ o #629840 by fuerst: Search filter caused bad query on PostgreSQL.
+ o #593668 by neochief: Allow changing of the display ID.
+ o #600242 by pcambra: Allow "search" filter as an argument.
+ o #387748 by recrit: Allow summaries to be ordered by number of records.
+ o #535868 by dagmar: Exposed forms as plugins, helping to isolate exposed form code and increase the ability for modules to change the behavior of exposed forms.
+ o #633482 by dagmar: pre_execute() method needs to be called on exposed forms.
+ o #535206: Attachment displays repeat exposed filters because exposed filters were left hanging around during cloning.
+ o #652742: Replacement pattern tokens for multiple fields did not work.
+ o #659510 by Souvent22 and dereine: glossary AJAX broken.
+ o #335599 by miro_dietiker: Remove the 95% width constraint on the admin hover links to be nicer to themes.
+ o #670308 by Mike Wacker: Make views_get_view() properly set disabled flag when retrieving default views.
+ o #536910 by dehttp://drupal.org/files/issues/fix-pager.patchreine: Theme and language should be taken into account during caching.
+ o #657442 by nicholasThompson and dagmar: Include "mail" field in user picture so that modules that need this do not break when rendering picture in Views.
+ o #455364 by sdrycroft: Prevent modules trying to define the same default view name from breaking everything.
+ o #682140 by dereine: Use new node-building system
+ o #682146 by dereine: node.format is now handled by body-field
+ o #687610 by fgm: Wrong path for module in help message
+ o by dereine: Fix views_get_module_apis, registry is not in anymore.
+ o by dereine: fix notify on views-ui-list-views.tpl.php
+ o by dereine: Fix aggregateCount test case, this does work now
+ o #396380 by merlinofchaos, dereine and dagmar: Initial support for GROUP BY queries!!!!!!!!!!!!
+ o by dereine: Fix filter_format_default in exposed_form plugin.
+ o #571548 by dagmar: Prevent aliases longer than 63 characters which pgsql cannot handle.
+ o #696400 by jenlampton: Use hook_block_info() instead of hook_block_list().
+ o #629984 by dagmar: Ensure that row styles are relationship safe and add fields they need to the query, such as nids and cids.
+ o #628132: Live preview works again.
+ o #697354 by dereine: make comment row plugin working.
+ o #503452: Retool exports to properly use option definition, improving translatability and information use.
+ o #539498: "Comments: Node link" did not work at all. Replaced with "Node: Add comment link" which is what that was supposed to do.
+ o #664382 by dagmar: "Exclude" option on fields not properly stored.
+ o #664518 by dagmar: "Group by" settings on items not properly retained during editing process.
+ o #645150 by dagmar: Incorrect call to deprecated get_exposed_form_plugin() function fixed.
+ o #639094 by dagmar: Exposed forms not working with blocks after exposed plugins.
+ o #635966 by dagmar: Allow the exposed form plugin to actually control the exposed form.
+ o #664492 by dagmar: "Group by" settings not properly stored due to typo.
+ o #329044 by gordon: Check to see if access plugin exists before using to prevent whitescreens.
+ o #662174: handlers with an 'extra form' or other option data that was not in the main form could lose that data.
+ o #646236 by dagmar: User validate plugin did not properly save values.
+ o #99370 by dagmar: Allow a "reset" button as part of the exposed filters.
+ o #627402 by dereine: Aggregator description needed more controllable input filtering.
+ o #699200 by xgretsch: Non-static functions cause strict warning messages.
+ o #705668 by dereine: Fix glossary view, add tests for glossary view.
+ o #586668: Pagers turned into plugins to allow all kinds of new fun stuff with paging.
+ o #652712 by dagmar: Some pager settings were not getting properly stored with pluggable pagers.
+ o #268023 by dagmar and dereine: Allow a number of pages limit in paging.
+ o #694980 by dereine: New views should default to limiting to 10 items, to copy previous behavior.
+ o #366250 by seutje: Fix deprecated jquery selectors so we can work with jquery 1.2.6 as well as 1.3.2.
+ o #706528 by dereine: Fix validation handling.
+ o #608246 by dereine: Use default filter on signature rather than XSS filter.
+ o #706518 by dereine: Fix call to undefined views_process_check_options
+ o by dereine: Fix signature of views_process_check_options.
+ o #705080 by dereine: Fix renamed history_user to history table.
+ o #228510 by dagmar, KarenS and others, ported by chx: Exposed sorts!!!
+ o by dereine: add testing for renaming a exposed form reset button
+ o #660196 by dagmar: Allow changing the "Reset" button label in the exposed form settings.
+ o #669448: items per page override from summary style stopped working with pluggable pagers.
+ o #324092 by dagmar: Expose "Items per page" and "Offset".
+ o by dereine: Fix delete button in views ui.
+ o by dereine: Update recent_comments default view to a working version.
+ o by dereine: Test pluggable access.
+ o by dereine: Test pluggable default argument.
+ o by dereine: Test exposed forms ui.
+ o #721388 by JohnAlbin: Replace clear-block class with clearfix class
+ o #626704 by DamZ: Build views integration for field.module
+ o #721990: Remove todo.
+ o #681726 by drewish: Allow term edit link field.
+ o Test argument validation plugins.
+ o #734062 : Fix use_ajax storage.
+ o by dereine: Fix tablesorts url-query.
+ o #731156 by dereine: Remove debug calls for port.
+ o #734066 by dereine: Fix pager queries.
+ o #422434 by BWPanda: Correct (NULL) to (NOT NULL) in varios operator descriptions for empty/not empty.
+ o #692428 by Roi Danton: Documentation typo fix.
+ o #694094 by yhahn: Allow default views cache to be reset.
+ o #654738 by Scott Reynolds: Offset date filter missing current time.
+ o #716236 by jmiccolis: Allow default menu tabs to also have menu entries.
+ o #687550: Form caching caused display adding to fail. Probably broke other forms here and there too.
+ o #687550: Follow Up remove dsm.
+ o #713210 by dereine: Node language settings could persist for subsequent rows if they should not have had a language.
+ o #674772 by joachim: Unable to distinguish profile.module fields with same name in different profile categories.
+ o #704490 by domidc: Remove invalid short tags from template.
+ o #727798 by SteveReher: Fix typo in overrides.html documentation.
+ o #737120 by james.williams: Fix help text for date offsets which gave incorrect information.
+ o #737118 by DeFr: Allow API calls to delete to not clear the views cache to facilitate batch operations.
+ o #684656 by yhahn: Prevent Views from performing an unneeded variable_set() during block list.
+ o #673852 by yhahn: Allow access plugins to choose whether or not "access all views" should be used.
+ o #550132 by tha_sun: Allow plugins to better control the callbacks used for page type displays.
+ o #546586 by jeffschuler: String 0 values were being treated as empty therefore not displayed as fields.
+ o #651274 by dagmar: Show relationship labels in field lists for style config forms.
+ o #738608 by dagmar: Footer cannot be overridden.
+ o #638004 by stBorchert and BillyMG: If a field "Output as link" ends up with an empty path, do not actually print an empty link.
+ o #658842 by tomgf: Provide a proper ellipsis instead of "...".
+ o #662654 by dereine: Do not use query to load/validate a user if the user happens to be the logged in user.
+ o #548292 by mikeker: Create a "Node: path" field that can be used to display the aliased path to a node.
+ o #657384 by smoothify: Under rare circumstances, date default argument could get wrong value.
+ o #666912 by dereine: Prevent imports of views created by newer, incompatible versions of Views.
+ o #672864 by dereine: Add a column count class to the table style for themers to more easily do generic targeting.
+ o #552498 by dereine: User email as an argument.
+ o reverted #734066 by dereine: Fix pager queries.
+ o #515324 by dereine: Make API documentation easier to find.
+ o #640862 by dereine: Properly clear feed icon when cloning a view to prevent duplicate feed icons in attachments.
+ o #672044 by moshebeeri: Right-To-Left for views.css.
+ o #488314 by yhahn: Allow relationship to fetch nodes from terms.
+ o #677936 by mr.baileys: "views-row-last" class accidentally omitted on grids with just one row.
+ o #673184 by markus petrux: Default views not always properly loaded by language.
+ o #433948 by dereine: "numeric" => FALSE not properly supported in handler definitions.
+ o #730342 by dereine: Inline documentation fix.
+ o #685622 by dereine: Field to provide link to a node revision.
+ o #701588 by dereine: Delete button should say Revert on Overridden views.
+ o #704958 by davisbc1982: Fix working in pager exposed form.
+ o #708618 by thsutton: Friendlier message when a handler is missing.
+ o #508124 by dereine: "accept_null" should have been "accept null" in boolean filter definitions.
+ o #513396 by yhager: Attempt multi-byte safety for "trim at word boundary" setting.
+ o #692970 by dereine: Missing jump menu definition
+ o #739448 by brunodbo: Allow "Jump Menu" to set the "Choose" text in style options.
+ o #721358 by dereine: Unable to select "Limit list to selected items." With tests.
+ o by dereine: Bring simpletest structure to the same level then 6.x-3.x
+ o by dereine: Fix pluggable access tests, by rename hook_perm to hook_permission
+ o by dereine: Fix exceptions for pluggable argument validation tests.
+ o #697224 by Sun, thanoulas, dereine: Replace $.viewsUI.tabs with $.ui.tabs(was commited already)
+ o #418230 by Scott Reynolds: Views adds wrong nid with "Node: Has new content".
+ o #558602 by dboulet and Crashtest_: Summary views should provide "active" class on links properly.
+ o #496634 by dereine: Fix long-standing issue of "0" not being a valid argument for multiple integer CCK types.
+ o #521954 by Agileware: Allow taxonomy breadcrumbs to link to actual taxonomy page instead of back to view.
+ o #720012 by dereine: Exposed offset was accidentally using items per page text and field.
+ o #528838 by zzolo: If exposed form is in a block, and the form does not validate, ensure the form does not render twice.
+ o #727304 by mariusz.slonina: User edit link was disallowing users from editing themselves.
+ o #474174 by dereine: Analyze will now warn about "node/%" not being a valid path for Views.
+ o #711968 by dereine: Taxonomy selections could disappear on upgrade.
+ o #733142 by dereine: Link path field restricts input to too few characters for long links.
+ o #619642 by dereine: Allow argument for user language.
+ o #748168 by dereine: Fix ajax interface based on changed ajax framework in d7.
+ o #697224 Reverted Replace $.viewsUI.tabs with $.ui.tabs
+ o #748168 by dereine: Fix ajax interface based on changed ajax framework in d7(2).
+ o by dereine: Fix views_handler_area_text format form and storage.
+ o by dereine: Fix notive in views_ui_ajax_deliver, if drupal_add_js returns nothing.
+ o #675154 by dereine and Crashtest_: Improvements to rendering trim text and tag stripping.
+ o #675264 by peck66: Freeform profile list field did not output properly.
+ o #663372 by dan.nsk: Allow tokens to work in the "target" field during link rewriting.
+ o #720874 by dereine: Fix division by zero error in full pager when "items per page" is set to 0.
+ o #721168 by infojunkie: Guard against uninstantiated pagers.
+ o #748920 by Infojunkie, dereine: $vars[class] should be an array in inc:template_preprocess_views_view_table()
+ o #698270 by dereine, dagmar: Fix pager legacy functions view::set_items_per_page() and view::set_offset().
+ o #730810 by alex_b: Add fields for authmap table.
+ o #747418 by dereine: Fix taxonomy term ID bug introduced in #496634.
+ o #666920 by dereine: Include actual API version in exports.
+ o #689446 by dereine: Allow use of l() in link rewriting to not check for aliases.
+ o #684608 by dereine: Default argument to acquire a taxonomy tid from the URL or a node in the URL.
+ o #319991 by dereine: Add a search widget for "Enabled" and "Disabled" in view admin.
+ o #740686 by jacine: Introduce $classes array in views-view.tpl.php.
+ o #582348 by dagmar: Allow UI setting a CSS class for views-view.tpl.php
+ o #99370 followup by dereine: add lost get_pager_id
+ o #751340 by David_Rothstein: Remove call to drupal_(un)install_schema on install file.
+ o #755346 by KarenS: Rename fieldapi arguments, introduced by #707724
+ o #755346 by KarenS: Rename fieldapi arguments, introduced by #707724(2)
+ o by dereine: Disable recent comment view by default.
+ o #531686 by jweowu: Update process failed to properly track its history, causing errors when updating from really old sites.
+ o #753808 by KarenS, dereine: Fix Notice: Array to string conversion in template_process().
+ o #756068 by dereine: Fix ajax preview. Follow up of #748168.
+ o #761758 by rfay: Move drupal_alter() for hook_field_views_data_alter() to more useful spot
+ o #761754 by rfay: Removed outdated storage details in field_views_field_default_views_data().
+ o #761828 by rfay: theme uses array as argument for lock-breaking text.
+ o #682030 by killes: Add term relation table integration.
+ o #697794 by dagmar: Fix notice issue when convering from 2.x area handlers.
+ o #339758 by dereine: Better handling for display of set options in multiple choice filters.
+ o #330160 by aditya_kristanto: Improve text to make it easier to find where to edit the view description.
+ o #466250 by alex_b and dereine: Enlarge views_display field to prevent heavy displays from losing data.
+ o #689260 by dereine: Allow "Node type" field to output the machine name as well as the human readable name.
+ o #765022: SA-CONTRIB-2010-036: Fix XSS and PHP vulnerabilities.
+ o #765760 by crea: New setting for raw node type had wrong default.
+ o #765340 by dereine: <front> token accidentally removed by html entity stripping from URLs.
+ o #765352: Fix for postgress versions prior to 8.3 which caused data loss in update.php. Note: This will not repair lost data. If you experienced this you must restore your views_display table from backup.
+ o #740130: #561892 not applied correctly, caused the 'rewrite' checkbox to be ignored and rewrite always used.
+ o #765310 by dagmar: area handlers unable to be added.
+ o #765296: field IDs could get out of sync, causing render path to try to render a field that did not exist leading to whitescreens.
+ o #769464 by dereine, reported by rfay: Remove form.inc replacement.
+ o #769528: Rename tests/views_query.inc to tests/views_query.test
+ o #740120: Fix views_handler_filter_node_status to use the new syntax.
+ o #196439 by dereine: Support last comment field of node comment statistic.
+ o #699200 by dereine: view::db_objects should use statis key.
+ o #774366 by Dave Reid: getInfo() in tests needs to be public static functions
+ o #780156 by marcvanged: Declaration of views_plugin_display::options_submit() should be compatible with that of views_plugin::options_submit().
+ o #770006 by macdee: Taxonomy term default plugin mysteriously broken.
+ o #767146 by bangpound: Validation not passed down into row style plugin.
+ o #513396 by yhager and jcisio: Views trim was not multibyte safe.
+ o #550420 by blauerberg: Views RSS did not properly pass readmore flag from node to RSS item.
+ o #781296 by dereine: Node: Type "link to its node" option broken.
+ o #754294 by dagmar: Fix warnings on taxonomy term filter.
+ o #698270 by dagmar: Pager plugin re-org (again).
+ o #785526 by dereine: convert block cache settings to dbtng.
+ o #790038 by justin2pin: Add missing handler to views.info
+ o #793680 by Amitaibu: Fix views_handler_field_prerender_list::render_items().
+ o #689780 by deviantintegral: AJAX scrolling could go to wrong place.
+ o #773784 by dereine: Support "view own unpublished content".
+ o #626422 by vgarvardt: Static caching of validated taxonomy terms to improve taxonomy_term performance.
+ o #730454 by stella: Add "translate" link along with view/edit/delete links on nodes.
+ o #685938 by dereine: Sync preview widget to current tab to reduce WTFs when previewing the wrong display.
+ o #685938 Follow up by tobiasb: Remove console.log.
+ o #783718 by dereine: Fix strict errors. There might be some more.
+ o by dereine: Fix access tests.
+ o #734066 by dereine: Initial version of the fix for the countquery
+ o #799200 by dereine: Fix live preview
+ o #484600 by dereine: Ability to disable the automatic live preview. Fix live preview css.
+ o by dereine: Remove includes/query.inc. This is a 2.x file. The query is now handled in the pluggable query backend.
+ o by dereine: Add missing file in registry: views_handler_field_user_language.
+ o #496840 by dereine: Allow boolean filters to define additional output formats and provide an additional for Node: Sticky.
+ o by dereine: Rename {file} table to {file_managed}.
+ o #790956 by pwolanin: Adding/import a new View should be a local action.
+ o by dereine: Fix views_export output display.
+ o by dereine: Fix warning in views_plugin_argument_validate_node::convert_options.
+ o by dereine: $node->title is not a fieldapi field anymore. Fix views_plugin_row_node_rss with this patch.
+ o #766046: Live preview broken right after adding new display.
+ o #626732 by dereine: Fix displaying of analyze_view, clicking ok is broken.
+ o #802154 by dereine: Fix views_plugin_argument_validate_taxonomy_term.
+ o #799582 by dereine, Scott Reynolds: Use node_load_multiple for node row plugins.
+ o #801430 by dereine, Scott Reynolds; Use comment_load_multiple for comment rss row plugin, fix comment rss row plugin.
+ o by dereine: Fix missing files in the info file.
+ o #807506 by damZ: Improve the usefulness of ViewsSqlTest.
+ o #807510 by damZ: Test sort handler.
+ o by dereine: Move views_test.created field to viewsSqlTest.
+ o by dereine: Test views_handler_field_boolean.
+ o by dereine: Test views_handler_field_custom.
+ o by dereine: Test views_handler_field_date.
+ o by dereine: Port views_cache tests from d6.
+ o by dereine: Test views_handler_filter_in_operator.
+ o by dereine: Test views_handler_field_url.
+ o by dereine: Test views_handler_area_text.
+ o by dereine: Add $args parameter to ViewsTestCase::executeView.
+ o by dereine: Test views_handler_argument_null.
+ o #808230 by dereine: Fix Problems with XML namespace and dc:creator tag.
+ o by dereine: Test views_handler_field_xss.
+ o by dereine: Test views_handler_field_file_size.
+ o #812196 by yuriy.babenko: Lower the in operator in views_handler_filter_in_operator. This fixes update issues.
+ o #812928 by dereine: Rename expand_checkboxes to form_process_checkboxes.
+ o #812362 by dereine: Fix views_join::build_join, make it more flexibel on act like in views for drupal6.
+ o #810936 by dereine: Clear cache when a instance of a field gets created/updated/deleted.
+ o #722180 by rszrama: Fix field integration for fields across entity types.
+ o by dereine: Remove translatable property for field formatter setting.
+ o by chx: Replace placeholders in the query preview with the values.
+ o by dereine: Fix some other strict warnings. Sighs.
+ o #607418: Fix queries broken with "ambiguous nid" due to uncommon relationships.
+ o #768162: Revert inadvertant change to grid style behavior.
+ o #815392 by killes and dereine: Incorrect construction of $account caused accidental non-permanent change to $user->roles.
+ o by dereine: Fix php error on preview.
+ o by dereine: Fix notice in views_plugin_row_node_view::pre_render.
+ o by dereine: allow test cases to add a example plugin
+ o #854252 by bojanz: Fix advanced_help integration.
+ o #844156 by bojhan and dereine: Use contextual links instead of views own admin hover links.
+ o Change text of the the contextual link to "Edit view".
+ o #856186 by bojanz and dereine: Remove hook_views_handlers and update upgrade docs. Awesome!!
+ o #727894 by stella: Give stronger classes on exposed widgets for easier theming.
+ o #768060 by EmanueleQuinto: Better empty field replacement that continues to respect other rewriting rules.
+ o #464490 by dereine: Allow links to specify that they are absolute.
+ o #780898 by ericduran: New display IDs not used until view is saved.
+ o #317653 by Steven Jones: Allow singular/plural formatting in numeric fields.
+ o #781050 by lewisvance: Performance improvement in unpack_options().
+ o #734706 by joachim: Use proper access control to prevent unregistered users from seeing links to inaccessible contact pages.
+ o #827188 by dereine: Comment ID field should be numeric, not the generic field handler.
+ o #827780 by dereine: Fix RSS feed live preview not getting proper PRE tags.
+ o #780362 by ericduran: Validate display id when changed.
+ o #792582 by ducktape: Validate that view names are not purely numeric, which cannot be loaded by views_get_view().
+ o #594402 by joachim: Clarify text on "Moderation" field.
+ o #848506 by dereine: Add aggregator item ID as an aggregator field.
+ o #798764 by setvik: Fix broken AJAX in some IE circumstances due to odd IE behavior.
+ o #827300 by dereine: Fix authenticated users showing up as "No role" in role summary view.
+ o #746846 by lavamind: url encoding on options could cause visual problems in jump menu.
+ o #839214 by AlexisWilke: Improve encoding on help text snippets.
+ o #846054 by celeritas: Exposed form "Reset" button failed to reset if the name was changed in form options.
+ o #870770 by bojany: Exposed filter settings can't be saved. The same patch as #645146.
+ o by dereine: Rename re_render to rerender.
+ o by dereine: Fix views_import_access by changing the permission to use PHP for settings
+ o by bojanz and dereine: Fix a remaining call to vpr.
+ o by dereine: viewsAddTab used wrong variable, so adding displays is working again.
+ o #873250 by webchick: References to old admin navigation paths
+ o #873238 by dereine: Temporary fix for #561858
+ o #875876 by grendzy: Convert user validation to dbtng.
+ o #706680 by casey: Replace views_css_safe() and views_ui_item_css() with drupal_clean_css_identifier()
+ o by dereine: Convert views_handler_argument_aggregator_fid to dbtng.
+ o by dereine: Fix filter_form error in input_required plugin.
+ o #799604 by KarenS and dereine: Fix add_where with formulas.
+ o #859368 by dereine: Click sort using wrong add_orderby() line caused some click sorts to fail.
+ o #843866 by dagmar: Allow summary views to specify their path rather than assuming the view path all the time.
+ o #526106 by Blackice2999: Fix occasional off-by-one-day problem with date arguments.
+ o #785960 by dereine: Reset button should appear after Apply button, not before.
+ o #863666 by dereine: Revert button redirects to wrong place after view is reverted.
+ o #666870 by dereine and dww: Exposed sorts do not default properly.
+ o #703980 by jmiccolis: Custom date needs to better support "r".
+ o #743682 by nicedawg: Prevent exposed filter in a block from showing up twice on validation error.
+ o #768972 by dereine, cyberwolf and nicedawg: Add an option to disable an error message if terms do not exist on taxonomy term filter.
+ o #812608 by drunken monkey: Views outputs unquoted version in exports.
+ o #402944 by drewish: Cache views block list to reduce overhead when listing blocks.
+ o #792184 by mgriego: Remove unnecessary special handling of option defaulting which actually causes problems in the new world order.
+ o #692988 by joachim: Eliminate an unnecessary query in taxonomy filter.
+ o #857882 by dereine: Fix sorting of fieldapi fields.
+ o #884000 by bojanz: Fill node.moderate column.
+ o #883990 by dereine: Rename history_user to history in the popular default view.
+ o #884512 by bojanz, dereine: Fix notice in views_handler_argument_string
+ o #722454 by DeFr, dereine: Fix taxonomy integration
+ o #887328 by jmaties: Rename profile_values to profile_value.
+ o #884046 by bojanz and dereine: Fix countquery.
+ o #856742 by deriene and aspilicious: Add a special handler for list field type.
+ o #118672: Allow an OR in filters by adding groups in the filter UI.
+ o #788950 (part) by dereine: Add title to no-js form page.
+ o #891902/883230 by sgabe/wizian: Restore removed code from earlier patch.
+ o #893754 by davereid: render_as_link() needs to convert $options['query'] to an array.
+ o #893128 by davereid: Fix E_STRICT notices.
+ o #894350 by elliotttf: Replace template_files with theme_hook_suggestions.
+ o #897694 by jmaties: Replace taxonomy_term_path by entity_uri.
+ o #903466 by das-peter: Undefined offset in theme_pager_* functions.
+ o #894018 by das-peter: Fix notice in includes/view.inc on export.
+ o #905286 by terminal: Fix taxonomy handlers old db code.
+ o #911148 by JeremyFrench: Help out of date for template suggestions.
+ o #894560 by torelad, Chris Gillis and bojanz: Fix timezone_open() and date_timezone_set() warnings on archive.
+ o #915996 by yhahn: Fix for missing vocabulary machine name error in taxonomy field handler.
+ o #911748 by lefnire: _contact_user_tab_access was replaced with _contact_personal_tab_access.
+ o #905118 by dereine: Fix notice in plugin_validate_taxonomy.
+ o #812970 by Scott Reynolds, dereine: Get Views Query substitutions working
+ o #906440 by dereine, berenddeboer: Fix views_handler_filter_user_current.inc and use dbtng syntax.
+ o by dereine: Fix typo in views_query_substitution, reported by agentrickard.
+ o by agentrickard: Fix array-value substitutions.
+ o #921144 by yhahn, dereine: Bad key in field filter handler.
+ o #832954 by dww: Fixed bug that was modifying global user->roles
+ inside argument_validate_user (patch 34).
+ o #914102 by torelad: Correct placeholder in views_date_sql_format.
+ o #931582 by bec: Provide integration of {file_usage} table.
+ o by dereine: Fix in_operator test.
+ o by dereine: Fix more testcases by adding $this->resetAll().
+ o #931886 by bojanz: Remove views_handler_filter_float because numeric handler + dbtng does everything.
+ o #932792 by bec: Extras for formatting {file_managed} fields.
+ o by dereine: Move file_* handlers to extra files.
+ o #934086 by dereine: Attach the contextual links library only once.
+ o #917402 by yhahn: Update taxonomy handlers for d7 changes.
+ o #930582 by berdir, Damz, dereine: Fix query substitutions for subqueries.
+ o #711860 by dereine: 00 entered in pager total fails.
+ o #889770 by tim.plunkett: Empty fields not always hidden based on row settings.
+ o #762484 by master-of-magic: Link to node status could be lost between rows.
+ o #908272 by jaydub: Fix incorrect length of view description form field.
+ o #772782 by mstrelan: Menu normal item menu should default to system default menu rather than "navigation".
+ o #571234 by dereine: Better handling of invalid exposed filters or other methods that cause a view to abort during the build process.
+ o #685554 by MyXelf: Illegal characters in View tag translated improperly when used in theming templates.
+ o #508832 by nick_vh: Documentation improvement on templates.
+ o #887220 by dereine: Fix fatal error when using GROUP BY.
+ o #930714 by brad.bulger: Add aggregator GUID field.
+ o #936828 by xjm: Empty field replacement not quite always working.
+ o #872000 by NaX: Comment edit field needs option to set destination so it can work like comment edit field.
+ o #799580 by dereine: api version of views exports should use views_api_version() not hardcoded number.
+ o #884440 by Amitaibu: Improve token encoding to eliminate double html entity encoding.
+ o #847930 by dereine: Reduce duplicates option not staying set.
+ o #865482 by dereine: RSS options form does not include override.
+ o #813422 by dereine and killes: Improved time-based caching expiration.
+ o #829550 by hefox: Better testing of batch form use by exposed filters.
+ o #570618 by dereine: Enforce denying access to disabled views more strongly.
+ o #667014 by dereine: Prevent notice with relationships and node row style if relationship has no endpoint node.
+ o #835934 by dereine: Provide relationship from files to users.
+ o #738172 by dereine: Fields rewritten to be links with just a fragment did not work.
+ o #694094 by Ian Ward: Allow more static caches to be resettable. (port by aspilicious)
+ o #811226 by dereine: Fix another notice in area text handler. (port by aspilicious)
+ o #917916 by MyXelf: break delimiter not removed from formatted output. (port by aspilicious)
+ o #918654 by Will White: numeric GROUP BY fields missing numeric format options.
+ o by dereine: Test for views_handler_filter_date.
+ o #785236 by e_log: Add aggregator field item id as a field.
+ o #366886 by Scott Reynolds: For "last comment time" if "count zero is empty" is set, use empty text for nodes with no comments.
+ o #611086 by dereine: add -url token to files that can fetch proper URLs with private filesystems.
+ o #635336 by dereine: Remove unused fields from views.
+ o #795270 by dereine: Remove unnecessary links to sections that will have no settings.
+ o #882800 by dereine: Move "Distinct" option to query settings.
+ o #755342 by jcmarco: Improve SQL date field handling.
+ o #338893 by dereine: Aggregator argument not always properly converted to title.
+ o #787184 introduce the long awaited "Update and Override" button.
+ o #718832 by dereine: Add file extension as a field available within the File group.
+ o #941974 by dereine: Use contextual links in the views ui when possible.
+ o #761102 by dereine: test: user default argument.
+ o by dereine: Fix notice in views_ui_add_page.
+ o #667950 by damZ, dereine: Port #dependency form elements to #states.
+ o Added missing file: modules/taxonomy/views_handler_filter_vocabulary_machine_name.inc
+ o #882800 by rszrama: Fix notice for options['distinct'].
+ o #950246 by ZoeN: Fix dbtng in views_handler_argument_aggregator_fid.
+ o #884730 by yched, bojanz, karenS, wundo: Add new UI for formatter settings options to the field settings config.
+ o by dereine: Add the dependeny ctools.
+ o #952576 by yhahn: Use JS_LIBRARY group for adding core library js files.
+ o #563020 by dereine: Replace views object cache with ctools object cache.
+ o #952636 by yhahn: Support string format identifiers in field_markup handler.
+ o #954030 by alweb: Fix title query in views_handler_argument_term_node_tid.
+ o #954784 by tekante: views_join class produces a SQL error when an array is in definition['extra']['value'].
+ o #962756 by bojanz: Field delta shows the placeholder instead of the field name.
+ o #667950 by merlinofchaos, bojanz and dereine: Revert the states patch and use ctools dependency instead.
+ o #960528 by dereine: Clicksort doesn't work for field names that contain special characters.
+ o by dereine: Document add_where for formula.
+ o by dereine: Fix notice in ajax.inc.
+ o #963382 by aidanlis: Fix typo in mathematical expression field help text.
+ o #807614 by dereine: Test filter_numeric.
+ o #928000 by mfer, dereine: form.js dependency missing.
+ o by dereine: Fix some notices.
+ o by dereine: Fix views_exposed_form test.
+ o by dereine: Move test files around.
+ o by dereine: Fix notice in group_by_numeric.
+ o by eporama: Add a test for views_plugin_argument_validate_user.
+ o #788950 by merlinofchaos, bojanz, dereine: Fixed ui when clicking override.
+ o #965432 by bojanz: Display column for single column fields, if that column is not "value".
+ o #965188 by Scott Reynolds: Remove comment.comment column, it does not exist in the database anymore.
+
+Views 6.x-3.x-dev
+ o #396380 by merlinofchaos, dereine and dagmar: Initial support for GROUP BY queries!!!!!!!!!!!!
+ o #535868 by dagmar: Exposed forms as plugins, helping to isolate exposed form code and increase the ability for modules to change the behavior of exposed forms.
+ o #670874 by dereine: Argument validator settings were not getting saved.
+
+Views 6.x-3.0-alpha1
+ Bug fixes:
+ o Table style when not overriding sorts put sorts in wrong order.
+ o #488908 by sl27257: "Node: Has new content" only worked when exposed.
+ o #451110 by wonder95: Fixed missing word in transform case help text.
+ o #385904 by JirkaRybka: Prevent duplication of id edit-submit on views exposed form.
+ o #489888 by TheRec: Remove erroneous "alt" attribute from <a> when using link rewriting.
+ o #499078 by Darren Oh: Make sure theme is initialized for pre_render hook.
+ o #490516 by v_20q: Some fields not properly being marked as translatable due to option unpacking bug.
+ o #484222 by dereine: Attachment displays were ignoring access settings.
+ o #503098 by Davide Goode: Feed displays should have link displays since they link to a page display.
+ o #381346 by ayalon: Allow Taxonomy: Tid as a field, which is now needed for rewrites which may need tids.
+ o #485296 by overall and deekayen: Remove unnecessary t() call.
+ o #460838 by Darren Oh: Make DISTINCT more distinct.
+ o #503774 by dereine: Cache time failed to return the proper cutoff time.
+ o #506098: Table sorting with no default was overriding sorts even tho it was not supposed to.
+ o #407538: Ensure views_break_phrase() will stop providing warnings on empty strings.
+ o #420850 by dereine: Commas should not be used to separate items in a profile list field.
+ o #482162 by agentrickard: link path needed further sanitization to properly encode special characters.
+ o Tables would not accept 0 as having data so columns with zeroes would lose data when merging with other columns.
+ o #529164: Fatal typo in profile list field.
+ o #537870 by dww: Fixed a bug in the [uplodate_fid-size] token where format_size() was called on it twice.
+ o #510910 by mfb: Fixed bug where multiple fields sharing a column in a table was broken so only the final field would display.
+ o #546586 by dww: Fixed bugs that prevented '0' being a valid rewrite text or empty text for a view field. Also fixes a logic bug regarding the handling of the 'Count the number 0 as empty' setting.
+ o #507884 by TheRec: Removed matching title (alt) attribute on node links.\
+ o #468370 by emackn: Proper timezone support on postgres.
+ o #508124 by voxpelli: Optionally allow boolean to treat NULL as FALSE.
+ o #487528 by dereine: Fix typo in 'Maximum length' field instructions.
+ o #303800 by Justin W Freeman: Improve dashes to spaces transformation.
+ o #538530 by elcuco: Views export textareas should be LTR.
+ o #538204 by dereine: User picture should be sortable.
+ o #540122 by stella: Attachment displays should attach even if arguments caused the primary display to abort.
+ o #544098 by joachim: Fix validation quirks with defaulted handlers.
+ o #485872 by dereine: Make sure views.css is always loaded for all users.
+ o #442982 by killes: Make destroy() method more robust so that views are more readily reused.
+ o #520558 by bdurbin: node access filter not properly checking 'view'.
+ o #535424 by Hugo Wetterberg: Download file link could provide empty a tag if no file is available.
+ o #554000 by killes: Preview checking wrong flag for preview state causes feeds to display incorrectly when embedded.
+ o #554016 by webchick: views_embed_view() should check view access.
+ o #523222 by gpk: Contact link should not be allowed for the anonymous user.
+ o #563540 by dereine: Fix description of cache plugin settings.
+ o #564536 by dereine: Node links should allow language setting from node data.
+ o #551752 by dereine: Clean up row counter code.
+ o #451208 by dereine and superbaloo: Fix grid style to not leave missing tds in bottom row.
+ o #561892 by dereine: Unchecking "rewrite this field" but leaving a value caused field to be rewritten anyway.
+ o #408894 by dereine: Views AJAX incorrectly used "access content" permission.
+ o #574150 by dereine: Remove user search because user.module does not store user keywords.
+ o #511908 by dww: Too many check plains in selects because of problems with checkboxes.
+
+ Other changes:
+ o Implement a post_render hook (for themes too) and cache method.
+ o #501552 by neclimdul: Work around a core bug with DISTINCT on nodes.
+ o #430068 by overall and aclight: Improvements to the global "counter" field.
+ o #492002 by iterato: Allow "target" specification in field linking.
+ o #466454 by neclimdul: PHP strict fixes.
+ o Can now directly add a taxonomy term relationship to nodes, allowing more control by vocabulary.
+ o #472194: !1 can now be used with field rewriting to get the raw argument.
+ o #480162: Fields row style now contains option to hide empty fields.
+ o #433318: Special handling for empty fields, allowing them to avoid rewriting and not be displayed.
+ o #354457 by ausvalue: Example integrating node_example.module with Views API.
+ o #479728 by enboig: Allow "Does not start with" and "Does not end with" as string operators.
+ o #511468 by dereine: State which view was saved after saving a view.
+ o #520632 by DamZ: Add comment hostname and mail to available comment fields.
+ o #523580 by JirkaRybka: More documentation on Reduce Duplicates option.
+ o #510920 by apanag: Add set_current_page() method to view class.
+ o #337741 by joachim: Allow profile fields to have "link to user" option.
+ o #534680 by dagmar: Visual indicator if checkbox will expand options.
+ o #512650 by sdboyer: Multiple many to one arguments on the same relationship were not relationship safe.
+ o #536994 by dboulet: Store result in variables for use in unformatted style.
+ o #458194 by voxpelli: Add first and last row classes to table style.
+ o #254895: Add form to clean up Views 1 tables.
+
+Views 2.6
+ Bugs fixed:
+ o #419226 by kelvincool: Respect admin theme during views ajax operations.
+ o #419270 by voxpelli: set_where_group() could fail if no previous groups.
+ o #422054 by yhahn: Protect exports from impropertly indenting multiline strings.
+ o #437070 by mikeryan: Base table formerly limited to 32 characters.
+ o #317271 by quicksketch: ensure_my_table() limited to one relationship per table.
+ o #441520 by jonathan1055: Allow the "time ago" date format to work on future dates as well.
+ o #445398 by casey: reduce_value_options() using wrong value array.
+ o #451370 by skwashd: base.js had some DOS line endings.
+ o #454754 by dww: Fix PGSQL related errors with comment author filtering.
+ o #384286 by dww: Make it possible to expose the filter for "Node: Has new content"
+ o #463634 by alienbrain: "Empty field name" incorrectly specified.
+ o #463580 by ximo: AJAX summary links broken in some displays.
+ o #468336 by psynaptic: Fix broken hook_views_admin_links_alter
+ o #422868 by mattman: Breadcrumbs not properly substuting % replacements.
+ o #440676 by dereine and Razorraser: View import form crashed on empty view input.
+ o #461842 by dereine: Use gmtime() instead of format_date() to prevent localization of dates in RSS feeds.
+ o #316556 by darrenoh and JirkaRybka: More 1.x upgrade fixes.
+ o #382398 by elcuco: Force LTR in the views admin.
+ o #461144: Fix trimming to correctly remove tags when they are trimmed in half.
+ o #330956: Theme: Information only scanned information from the default theme.
+ o SA-CONTRIB-2009-037: Filter checkboxes could be displayed unfiltered allowing XSS attacks.
+
+ Other changes:
+ o #298616: Add argument for node updated time similar to node created time.
+ o #325607 by bangpound: Automatically sort exports from bulk export.
+ o #323049 by yched: Allow Empty/Not Empty on select many to one.
+ o #340701 by swentel: Restore allowing Views to set block caching mode.
+ o #347892 by dww: Allow <any> option in Boolean filters.
+ o #358314 by brmassa: Catch the exposed filter form so it doesn't process twice on a single view.
+ o #154865 by Zack Rosen, josh_k and KarenS: Allow user contact form as a field.
+ o #411880 by fgm: Add "options callback" to items using in_operator handler.
+ o #360657 by yhahn: new hook_views_default_views_alter().
+ o #430068 by dereine: New global counter field for displaying row number.
+ o #420340 by derine: Translate node type filter.
+ o #325796 by yang_yi_cn: Translate node type argument.
+ o #446726 by yhahn: Improved performance for js dependencies.
+ o #437760 by leeneman: Remove duplicate terms from taxonomy term argument title.
+ o #354270 by dereine: Allow "tag" to be added to the theme template suggestions.
+ o #408180 by joachim: Allow taxonomy term parent argument.
+ o #469456 by dereine: Automatically give .info file during views bulk export.
+ o #424460 by thePanz: Customizable breadcrumb title for arguments.
+ o #436398 by Pasqualle: Support for aggregator category table.
+ o #424648 by quicksketch and dereine: Allow format selection on filesize field.
+ o #478312 by yhahn: Provide specific node access filter.
+ o #479878 by dereine: User language field.
+ o #468824 by eaton: Pluggable caching mechanism which can cache both the query result and rendered result.
+ o #399534 by clemens.tolboom and drewish: Add fragment and query string as options when making fields into links.
+ o #315915 by dixon_: Add another base row class to rows.
+ o #353403 by agentrickard: Field to provide "more" text.
+ o #377896 by dereine: When ticked "link to node" show node title as a href title attribute.
+ o #386098 by dereine: Add "watchdog" as a debug logging options.
+ o #409428 by gpk: Missing field: node input format.
+ o #271833 by grugnog, agentrickard and others: Taxonomy depth in filter.
+
+Views 2.5
+ Bugs fixed:
+ o #363817 by thePanz: Empty fields in table could still trigger separators.
+ o #388952 by nikita@protsenko.com: Ensure taxonomy term validator sets the validated title when available.
+ o #392176: Trim on word boundary would stop at newlines.
+ o #415706 by dww: Fix broken relationship in search that caused SQL error.
+ o #428742 by fralenuvol: Fix broken relationship causing sql error with multiple taxonomy term arguments.
+ o #428102 with help from deviantintegral: Broken option_definition() causes warnings.
+
+ Other changes:
+ o #379382 by neochief: Add option to strip tags during advanced rendering.
+ o #400914 by joachim: Add a link field to get to comments for a node that works just like the normal links.
+ o #402650 by drewish: Bulk export views alphabetically by view name.
+ o #349157 by yched: Support CCK build modes in node style.
+
+Views 2.4
+ Bugs fixed:
+ o #371466 by dereine: Fix incorrect link to comments.
+ o #371923 by noahb: Summaries could be distinct even when they should not be.
+ o #368764: Fix User ID validator to actually have proper dependencies.
+ o #375342 by dww: node_comment_statistics should be INNER joined because there is always 1:1 reference.
+ o #372959: Archive view should not use AJAX by default.
+ o #373155: Not clearing "many to one" data breaks some attachment displays.
+ o #375000 by elcuco: View name should always be LTR.
+ o #378534 by dww: Validators do not fire if argument === 0 due to PHP loose type conversions.
+ o #378164 by yched: Unexposed taxonomy filter could accidentally stop working.
+ o #371923 by David_Rothstein: Another DISTINCT fix related to summaries.
+ o #365831 by tomiyana: Fix typos in help.
+ o #357368 by Pasquale: schema descriptions should not be translated.
+ o #379602 by dww: Add a second "time ago" variant to dates to allow NOT printing the word "ago".
+ o #379354 by neochief: Add an extra regex to remove mangled HTML entities in output rewriting.
+ o #362830: Search was mostly broken, especially score but also searching on multiple terms.
+ o #350376 by pfournier: Missing "return" statement caused certain argument date validation to fail.
+ o #364082 by hass: Unique key missing on views_view table.
+ o #366250 by sirkitree: Fix deprecated jquery selectors so we can work with jquery 1.2.6 as well as 1.3.2.
+ o #386986: 2 or more relationships could block a normal table from being added.
+ o #371219 by aclight: Incorrect logic in views_many_to_one_helper::ensure_my_table()
+ o #376570 by yhahn: Better AJAX scrolling.
+ o #412576 by yhahn: Restore missing views_handler_filter_float class.
+ o #378710: Add strip_tags() to path when displaying a field as a link as a path can never have HTML in it.
+ o #380560: UI could suddenly cause errors with get_handlers() in certain situations with relationships.
+ o #342215: Occasional "holes" could appear in taxonomy term field causing query errors when relationship is used but not present.
+ o #414074 by dereine: Prevent fields becoming not editable by having just spaces in them in the Views UI.
+ o #378724: Displaying uploaded files as a link accidentally made the entire field a link rather than each one.
+ o #415672 by yhahn: Views inadvertently rounds negative numbers down instead of up when truncating.
+ o #408414 by rb7: Prevent empty links with the "has new comments" field.
+ o #406680 by Büke Beyond: Missing clear-block caused problems in IE for Views UI.
+ o #373771 by dropcube: Fix missing aggregator feed trying to use non-existing handlers.
+ o #341960 by sun: Clean up dependent.js javascript declarations which potentially caused .js errors.
+ o #372227: On Debian etch, tables would lose fields due to PHP bug.
+
+ Other changes:
+ o #375182 by vaish: Allow a reset parameter to views_get_all_views().
+ o #356276 by nedjo: Locale support.
+ o #316556 by Darren Oh: Better Views 1.x upgrades.
+ o #383242 by dww: Allow - Any - instead of <Any> as an option in the Views tools menu.
+ o #303800 by KarenS: Additional dashes to spaces option in taxonomy argument validator.
+ o #327366 by yched: Allow row styles to follow relationships too.
+ o #405130 by dereine: Make the output field rewrite a textfield rather than textarea.
+
+Views 2.3
+ Bugs fixed:
+ o #349739: Fix arguments not getting transmitted to attachment displays properly.
+ o #354707: Display attachment happened too early preventing default arguments from passing to the attachment.
+ o #277321 by nedjo: Use AJAX properly supports summaries in attachments.
+ o #291292 by sammys (reroll by jaydub): Proper use of DISTINCT on summary views on pgsql.
+ o #291079 by sammys (reroll by jaydub): Fix use of GROUP BY on pgsql.
+ o #295246 by webchick: Wrong table type on views object cache caused truncation of cached data and mysterious errors on large views.
+ o #315007 by Garrett Albright, Paul Kishimoto and catch: Take into account page count when using comment new link.
+ o #317562 by ingaro: Wrong date format for PGSQL.
+ o #327604 by mr.baileys: Fix improper use of multibyte library when mb library unavailable.
+ o #335926 by sapark and drewish: "January, 2009" should be "January 2009".
+ o #341263 by cdale: Prevent exposed filter forms from processing during batch operations.
+ o #342322 by drewish: Correct label for translation status.
+ o #343223 by alienbrain: Ensure path before join.
+ o #343284 by andypost: Fix odd/even reversed in table style compared to Drupal core.
+ o #345545 by mfb: Correct occasional Drupal.settings related javascript error.
+ o #345546: Fix Node: Created day argument off by 1 error.
+ o #345707 by aries: Do not display breadcrumb link if no link text.
+ o #355939 by yhager: Fix missing comment GUID in comment RSS style.
+ o #321332 with help from brahms: views_handler_field_markup only worked if format was named "format".
+ o #348322 by Darren Oh: Fix missing /code in api plugins help.
+ o #353090 by eaton: RSS feeds were not using all of the Drupal hooks to ensure full compatibility with core feeds.
+ o #293832 by drewish: Allow menu items to have administrative description.
+ o #345528: Mini-pager generated invalid HTML with empty li tags.
+ o #351745: Exposed taxonomy term autocomplete filter failed if term existed in multiple vocabularies.
+ o #353002: tracker view had wrong argument and was not picking up comments by the selected user.
+ o Case sensitivity on string filter checkmark was backward.
+ o #355919: views_theme() needed to include plugin theme files to detect functions.
+ o #353515: Many characters could get incorrectly translated in exposed filters combined with ajax tablesorting.
+ o #359818: Delete button should say Revert when reverting a view to default.
+ o #359132 by grugnog: CSS files should be marked conditional so they don't impact the CSS cache.
+ o #360637: Extra slash in theme includes could cause some systems to fail.
+ o #363081: Disabled views could still provide blocks.
+ o #366666 by Deadmonk also yched: File size field should not try to print a size on NULL values.
+ o #367203: Improper caching of default views caused incomplete handlers that could WSOD.
+ o #365283: views_handler_filter_ncs_last_updated improperly registered causing fatal errors trying to use it.
+ o #365712: select list exposed filters were trying to limit to list when selecting "All" even when "limit" was not selected.
+ o #357196 by Grugnog: hook_views_pre_view not getting $display_id sent properly.
+
+ Other changes:
+ o #288801 by drewish and eaton: Aggregator item support! Make views of feeds!
+ o #335647 by markus_petrux: Add memory and a reset button to the Views list page.
+ o #343047 by alienbrain: Allow all handlers to participate in view validation.
+ o #339223 by greggles: Allow taxonomy term tid to be sortable.
+ o #324378 by eigentor: CSS improvements to the view list page.
+ o #354736 by Shai: Clarification on exposed filter text.
+ o #364637 by moshe and dww: Allow preprocessors to add row classes to table style.
+ o #349178 by agentrickard: Add generic link handling plus a custom text field. Also automatic trimming.
+ o #368234 by dww and neclimdul: Allow the "Anonymous" user to have a different (or no) name in User: name field.
+ o #368754 by dww: User ID validator, with role testing.
+ o #369505 by dww: Add helper function to get the value of a view argument.
+ o #353002 by neclimdul: Provide a filter for user posted or commented on to complement the argument with the same functionality.
+
+ 2.3 API Notes:
+ A minor change in the API now requires that styles that render fields MUST
+ render them in order, first by row and then by field ID. Not doing so will
+ cause the token expansion to fail.
+
+Views 2.2
+ Bugs fixed:
+ o #305756: Number formatting caused illogical rounding.
+ o #324272 by neochief: hook_pre_render never called.
+ o #324058: Broken queries created by string values in multiple fields.
+ o #324726: "tag" fields should be autocomplete in View edit.
+ o #324058 by yched: Make aliases safer for many to one tables.
+ o #325765: Prevent key merge errors on query::add_where and query::add_having.
+ o #324378: Minor usability improvements to the list page.
+ o #326934: Need another check to make sure already added aliases do not get blown away.
+ o #324513: If a relationship table was added more than 1 hop away from the base, SQL errors resulted.
+ o #326129 by mindgame: Not between operator did not function.
+ o #326198: != mistakenly typod as = (display only)
+ o #326379: Provide a default title for the archive view.
+ o #327151: Add filter for node_counter.timestamp.
+ o #327113: Clean up error text when display will not validate.
+ o #307287: (Panels related) view::preview() would override previously set arguments if no arguments were sent.
+ o #321589: Comment template preprocessor misnamed so it would not fire.
+ o #329746: Comment rendering in the node row style was not working.
+ o #321109: view::destroy() needs to unset current_display or future init_displays won't work.
+ o #325115: If the block description is not set, show the display title as well as the view name in block administration.
+ o #327604 by henrrrik: should use multibyte string functions.
+ o #328933 by cmyers: views_handler_filter_date fails to use exposed operator.
+ o #332568 by Moonshine: Correct views performance timers.
+ o #332679 by yched: render_link() does not check for empty data.
+ o #333593: Incorrect reference to non-existent views_handler_join in help/api-tables.html.
+ o #334337 by miro_dietiker: Documentation clarification for arguments, blocks and PHP Code plugins.
+ o #336456 by dww: Date filter had trouble with NULL operators.
+ o #336125 by nedjo: Missing filter for node translation.
+ o #337360: Menu selection causes crash if menu module not active.
+ o #339295 by katbailey: AJAX paging could fail with the same view in multiple tabs.
+ o #339676 by nedjo: Source translation had wrong filter handler.
+ o #340002 by hass: Allow the "Add display" button to wrap for translations whose phrase is longer.
+ o #340033 by pancho: Clearer wording on some field help texts.
+ o #340515: views_perm() was incorrectly views_ui_perm().
+ o #330897: Invalid displays causing 'path' lookup to crash.
+ o #339674 by nedjo: Translation code cleanup.
+ o #341897: views_perm() mistakenly declared in views_ui.module.
+
+ Other changes:
+ o Reorganize the analysis code into analyze.inc to make it easier for people to find the code and use it externally.
+ o #298884 by neclimdul: Requested missing filter to filter for whether a user has a picture or not.
+ o #336531 by dww: Set boolean filter to not use a checkbox which is lesser UI.
+ o #338632 by drewish: Remove use of format_rss_channel and use proper templating instead.
+ o #326034 by yched: Allow short names in admin summaries via new "title short" definition.
+ o #335613 by swentel: Add hook_views_api() setting to bulk export.
+ o #339707 by nedjo: Add filter to show child translations.
+ o #284768 by drewish: Proper templates for RSS feeds rather than format_rss_item().
+
+
+Views 2.1
+ Bugs fixed:
+ o #322862: 1.0037 debug code left in.
+ o #322908: README.txt update.
+ o #323014 by yched: Typo in exposed filter text.
+ o #323033: Using empty/is not empty in string/numeric filters caused notices.
+ o #322874 by yched: Errors in summary for some filters.
+ o #323282: Taxonomy term default choice handled incorrectly.
+ o #323318: Exposed taxonomy term failed if not set force single.
+
+Views 2.0
+ o First 2.0 official release
+
diff --git a/CVS/Entries b/CVS/Entries
new file mode 100644
index 0000000..e92a344
--- /dev/null
+++ b/CVS/Entries
@@ -0,0 +1,12 @@
+/CHANGELOG.txt/1.344.4.426/Tue Nov 9 06:42:05 2010//TDRUPAL-7--3
+/D7UPGRADE.txt/1.1.2.1/Mon Jul 19 09:18:42 2010//TDRUPAL-7--3
+/README.txt/1.26.6.1/Mon Nov 2 22:01:25 2009//TDRUPAL-7--3
+/documentation-standards.txt/1.1/Wed Jul 2 02:13:42 2008//TDRUPAL-7--3
+/views.info/1.7.6.46/Sun Nov 7 14:52:39 2010//TDRUPAL-7--3
+/views.install/1.50.4.8/Tue Oct 26 19:06:26 2010//TDRUPAL-7--3
+/views.module/1.341.4.40/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views2.doxy/1.2/Mon Jul 21 20:57:29 2008//TDRUPAL-7--3
+/views3.doxy/1.1.2.1/Mon Nov 2 22:01:25 2009//TDRUPAL-7--3
+/views_ui.info/1.10.6.1/Mon Nov 2 22:01:25 2009//TDRUPAL-7--3
+/views_ui.module/1.109.6.13/Tue Oct 26 19:06:26 2010//TDRUPAL-7--3
+D
diff --git a/CVS/Entries.Log b/CVS/Entries.Log
new file mode 100644
index 0000000..5ca6d32
--- /dev/null
+++ b/CVS/Entries.Log
@@ -0,0 +1,15 @@
+A D/css////
+A D/docs////
+A D/handlers////
+A D/help////
+A D/images////
+A D/includes////
+A D/js////
+A D/modules////
+A D/plugins////
+A D/po////
+A D/tests////
+A D/theme////
+A D/translations////
+A D/views_export////
+R D/po////
diff --git a/CVS/Repository b/CVS/Repository
new file mode 100644
index 0000000..cbbe000
--- /dev/null
+++ b/CVS/Repository
@@ -0,0 +1 @@
+contributions/modules/views
diff --git a/CVS/Root b/CVS/Root
new file mode 100644
index 0000000..127da18
--- /dev/null
+++ b/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal-contrib
diff --git a/CVS/Tag b/CVS/Tag
new file mode 100644
index 0000000..0f07c7f
--- /dev/null
+++ b/CVS/Tag
@@ -0,0 +1 @@
+TDRUPAL-7--3
diff --git a/D7UPGRADE.txt b/D7UPGRADE.txt
new file mode 100644
index 0000000..08d3a3b
--- /dev/null
+++ b/D7UPGRADE.txt
@@ -0,0 +1,2 @@
+Information about upgrading existing views from Drupal 6 to Drupal 7 is located
+in the module's advanced help under api upgrading.
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..f6217bb
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,28 @@
+// $Id: README.txt,v 1.26.6.1 2009/11/02 22:01:25 merlinofchaos Exp $
+
+Welcome to Views 2. Please see the advanced help for more information.
+
+If you're having trouble installing this module, please ensure that your
+tar program is not flattening the directory tree, truncating filenames
+or losing files.
+
+Installing Views:
+
+Place the entirety of this directory in sites/all/modules/views
+
+Navigate to administer >> build >> modules. Enable Views and Views UI.
+
+If upgrading from Drupal 5 and Views 1, your views need to be
+converted manually. See administer >> build >> modules >> views >> tools >> convert.
+
+If you're new to Views, try the Simple Views module which can create some
+often used Views for you, this might save you some time.
+
+Recommended modules for use with Views:
+ CCK
+ Voting API
+ Views Bonus Pack
+ Views Bulk Operations
+
+Experimental modules:
+ Views OR \ No newline at end of file
diff --git a/css/CVS/Entries b/css/CVS/Entries
new file mode 100644
index 0000000..ee71aac
--- /dev/null
+++ b/css/CVS/Entries
@@ -0,0 +1,7 @@
+/views-admin.css/1.14.4.10/Tue Aug 24 16:13:20 2010//TDRUPAL-7--3
+/views-list-rtl.css/1.1/Wed Mar 25 00:08:45 2009//TDRUPAL-7--3
+/views-list.css/1.12.6.2/Wed Nov 18 20:04:07 2009//TDRUPAL-7--3
+/views-rtl.css/1.1.2.1/Fri Mar 12 00:25:30 2010//TDRUPAL-7--3
+/views-tabs.css/1.1.6.3/Sat Mar 20 23:16:37 2010//TDRUPAL-7--3
+/views.css/1.11.6.5/Sun Jul 4 10:04:50 2010//TDRUPAL-7--3
+D
diff --git a/css/CVS/Repository b/css/CVS/Repository
new file mode 100644
index 0000000..77a8206
--- /dev/null
+++ b/css/CVS/Repository
@@ -0,0 +1 @@
+contributions/modules/views/css
diff --git a/css/CVS/Root b/css/CVS/Root
new file mode 100644
index 0000000..127da18
--- /dev/null
+++ b/css/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal-contrib
diff --git a/css/CVS/Tag b/css/CVS/Tag
new file mode 100644
index 0000000..0f07c7f
--- /dev/null
+++ b/css/CVS/Tag
@@ -0,0 +1 @@
+TDRUPAL-7--3
diff --git a/css/views-admin.css b/css/views-admin.css
new file mode 100644
index 0000000..1da3c81
--- /dev/null
+++ b/css/views-admin.css
@@ -0,0 +1,671 @@
+/* $Id: views-admin.css,v 1.14.4.10 2010/08/24 16:13:20 dereine Exp $ */
+
+/*
+ * Summary pad
+ */
+/* set up some defaults so weird themes don't override us too badly. */
+.views-tabset {
+ color: #494949;
+ background-color: white;
+}
+
+.views-tabset a:visited,
+.views-tabset a:hover,
+.views-tabset a {
+ color: #027AC6;
+}
+
+.views-tabset .views-tab fieldset {
+ margin-top: 0;
+}
+
+/*
+ * First column: display drawers
+ */
+.views-tabset .views-tabs {
+ background: #F6F6F6;
+ border-top: #D6DBDE 1px solid;
+ border-bottom: #D6DBDE 1px solid;
+ border-left: #D6DBDE 1px solid;
+ float: left;
+ width: 117px;
+ margin-right: 0;
+}
+
+* html .views-tabset .views-tabs {
+ width: 114px;
+ position: relative;
+ left: 4px;
+}
+
+.views-tabset .views-tabs ul {
+ list-style-type: none !important;
+ list-style-image: none !important;
+ padding: 0;
+ margin: 0;
+ position: relative;
+}
+
+.views-tabset .views-tabs ul li {
+ background: #efefef;
+ list-style-type: none;
+ list-style-image: none;
+ line-height: 100%;
+ border-bottom: #D6DBDE 1px solid;
+ margin: 0;
+ padding: 0;
+ position: relative;
+}
+
+.views-tabset .views-tabs ul li.active {
+ background: #fff url(../images/arrow-active.png) no-repeat right;
+ position: relative;
+ width: 118px;
+ margin-right: -1px;
+}
+
+.views-tabset .views-tabs ul li a {
+ display: block;
+ font-size: 90%;
+ color: #777;
+ font-weight: normal;
+ padding: 0.5em;
+}
+
+.views-tabset .views-tabs ul li a:hover {
+ background-color: #f6f6f6;
+ text-decoration: none;
+}
+
+.views-tabset .views-tabs ul li.active a {
+ color: #000;
+ font-weight: bold;
+}
+
+.views-tabset .views-tabs ul li.active a:hover {
+ color: #000;
+ background: #fff url(../images/arrow-active.png) no-repeat right;
+}
+
+.views-tabset .extra {
+ text-align: center;
+ margin-right: 0;
+}
+
+.views-tabset .extra input {
+ margin-top: 0;
+ margin-right: 0;
+ font-size: 10px;
+ white-space: normal;
+}
+
+/*
+ * Three columns with setting-summaries
+ */
+.views-tabset .views-display {
+ border: #D6DBDE 1px solid;
+ margin-left: 118px; /* 118 -1 causes borders to overlap */
+ min-height: 302px;
+ _height: 300px; /*stupid IE hack */
+}
+
+* html .views-tabset .views-display {
+ margin-left: 114px;
+}
+
+div.views-display-deleted,
+div.views-display-deleted div.top,
+div.views-display-deleted div.tab-section {
+ background-color: #eee;
+}
+
+.views-display {
+ background: #fff;
+}
+
+.views-display div {
+ font-size: 8pt;
+ line-height: 12pt;
+}
+
+.views-display .top {
+ padding: 0.5em 0em 0em 1em;
+ background: #fff;
+}
+
+.views-display .top .display-title {
+ font-weight: bold;
+}
+.views-display .top .display-description {
+ margin-left: 1em;
+ font-style: italic;
+ overflow: hide;
+ white-space: nowrap;
+ font-size: 90%;
+}
+
+.views-display .tab-section {
+ width: 32.5%;
+ padding: 0;
+ margin: 0;
+ float: left;
+ min-height: 273px;
+ _height: 274px;
+}
+
+.views-display .tab-section .inside {
+ margin: 0.5em 0.5em 0.5em 1em;
+}
+
+.views-display .tab-section .inside .views-category {
+ margin-bottom: 1em;
+ background: #f6f6f6;
+ border: 1px #efefef solid;
+}
+
+.views-display .tab-section .inside .views-category-content {
+ padding: 0em 0em 0.5em 1em;
+}
+
+.views-display .tab-section .inside .views-category-title {
+ padding: .1em .1em .1em .3em;
+ margin: 0 0 .1em 0;
+ font-size: 9pt;
+ font-weight: bold;
+ background-color: #efefef;
+ border-bottom: 1px #efefef solid;
+}
+
+.views-display .tab-section .links {
+ float: right;
+ font-size: 6pt;
+ position: relative;
+ display: inline;
+}
+
+.views-display .tab-section .links a {
+ font-size: 6pt;
+ font-style: italic;
+}
+
+.views-display .form-submit,
+#views-ajax-pad .form-submit {
+ margin: 0;
+}
+
+.views-display .middle {
+ width: 34%;
+}
+
+.views-basic-info {
+ margin: 0.5em 0em 0 0;
+ padding: 0.5em;
+}
+
+/*
+ * AJAX pad, the bottom part where settings are edited.
+ */
+#views-ajax-pad {
+ background: transparent;
+ margin-top: 0px;
+}
+
+#views-ajax-pad > div.ajax-progress {
+ display: none;
+}
+
+#views-ajax-title {
+ background: #f6f6f6;
+ color: #000;
+ border-left: #D6DBDE 1px solid;
+ border-right: #D6DBDE 1px solid;
+ margin: 0 0 0 118px;
+ padding: 1em 1em 0em 1em;
+ font-weight: bold;
+}
+
+#views-ajax-pad .message {
+ background: #f6f6f6;
+ color: #000;
+ margin-left: 118px;
+ border: #D6DBDE 1px solid;
+ border-top: 0;
+ /* padding: 3em 0em; */
+ text-align: center;
+ font-style: italic;
+}
+
+#views-ajax-pad form {
+ background: #fff;
+ color: #000;
+ margin-left: 118px;
+ border: #D6DBDE 1px solid;
+ padding-top: 3px;
+ border-top: 0;
+ float: none;
+}
+
+#views-ajax-pad .views-messages {
+ background: transparent;
+ margin-left: 118px;
+ padding: 5px;
+ border: #D6DBDE 1px solid;
+ border-top: 0;
+}
+
+#views-ajax-pad .form-buttons {
+ margin: 0;
+ padding: 0.5em 1em;
+ background: #f6f6f6;
+ clear: left;
+}
+
+#views-ajax-pad .clear {
+ clear: left;
+}
+
+#views-ajax-pad .form-buttons .form-submit {
+ font-size: 10px;
+}
+
+#views-ajax-pad .form-item {
+ margin: 0.5em;
+ padding: 0em 0.5em;
+}
+
+/* These put checkboxes closer together */
+#views-ajax-pad .form-checkboxes .form-item,
+#views-ajax-pad .form-checkboxes .description,
+#views-ajax-pad .form-checkboxes input,
+#views-ajax-pad .form-radios .form-item,
+#views-ajax-pad .form-radios label,
+#views-ajax-pad .form-radios input {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+#views-ajax-pad .form-item .form-checkboxes,
+#views-ajax-pad .form-checkboxes input,
+#views-ajax-pad .form-checkboxes label,
+#views-ajax-pad .form-item .form-checkboxes .form-item,
+#views-ajax-pad .form-item .form-radios,
+#views-ajax-pad .form-radios input,
+#views-ajax-pad .form-radios label,
+#views-ajax-pad .form-item .form-radios .form-item {
+ padding-left: 0;
+ margin-left: 0;
+}
+
+#views-ajax-pad .form-checkboxes .description,
+#views-ajax-pad .form-radios .description {
+ margin-left: 2em;
+}
+
+#views-ajax-pad {
+ display: none;
+}
+
+html.js #views-ajax-pad {
+ display: block;
+}
+
+.views-override,
+.views-expose {
+ padding: 0.5em 1em 0em 1em;
+}
+
+#views-ajax-pad .views-override .form-submit,
+#views-ajax-pad .views-expose .form-submit {
+ float: right;
+ margin: 0 .5em 0 1em;
+}
+
+#views-ajax-pad .views-expose .description,
+#views-ajax-pad .views-override .description {
+ margin-bottom: .25em;
+}
+
+/*
+ * Some column widths for use within the ajax pad
+ */
+#views-ajax-pad .views-left-10 {
+ float: left;
+ width: 10%;
+}
+
+#views-ajax-pad .views-left-20 {
+ float: left;
+ width: 20%;
+}
+
+#views-ajax-pad .views-left-25 {
+ float: left;
+ width: 25%;
+}
+
+#views-ajax-pad .views-left-30 {
+ float: left;
+ width: 30%;
+}
+
+#views-ajax-pad .views-left-40 {
+ float: left;
+ width: 40%;
+}
+
+#views-ajax-pad .views-left-50 {
+ float: left;
+ width: 49.5%;
+}
+
+#views-ajax-pad .views-right-50 {
+ float: right;
+ width: 50%;
+}
+
+#views-ajax-pad .views-right-60 {
+ float: right;
+ width: 60%;
+}
+
+#views-ajax-pad .views-right-70 {
+ float: right;
+ width: 70%;
+}
+
+#views-ajax-pad .views-left-75 {
+ float: left;
+ width: 75%;
+}
+
+#views-ajax-pad .views-radio-box {
+ overflow: auto;
+ height: 22em;
+}
+
+#views-ajax-pad fieldset {
+ margin: 0 .5em;
+}
+
+#views-ajax-pad table td .form-item,
+#views-ajax-pad table td .form-item input,
+#views-ajax-pad table td .form-item select {
+ padding: 0;
+ margin: 0;
+}
+
+#views-ajax-pad label.hidden-options {
+ background: transparent url(../images/arrow-active.png) no-repeat right;
+ height: 12px;
+ padding-right: 12px;
+}
+
+#views-ajax-pad label.expanded-options {
+ background: transparent url(../images/expanded-options.png) no-repeat right;
+ height: 12px;
+ padding-right: 16px;
+}
+
+#views-ajax-pad .dependent-options {
+ padding-left: 30px;
+}
+
+/*
+ * Add, Rearrange and Configure buttons using sprites
+ */
+a.views-button-configure,
+a.views-button-add,
+a.views-button-rearrange,
+a.views-button-remove {
+ background:transparent url(../images/sprites.png);
+ display: inline-block;
+ float: right;
+ height: 12px;
+ width: 16px;
+ margin: 2px 0px 1px 0px;
+ border-bottom: #C2C9CE 1px solid;
+ border-right: #C2C9CE 1px solid;
+ padding: 0px;
+}
+
+a.views-button-remove {
+ background-position: 0px -72px;
+ position: relative;
+}
+a.views-button-remove:hover {
+ background-position: 0px -84px;
+}
+
+a.views-button-configure {
+ background-position: 0px -48px;
+ margin: 0;
+}
+a.views-button-configure:hover {
+ background-position: 0px -60px;
+}
+
+a.views-button-add {
+ background-position: 0px -24px;
+}
+a.views-button-add:hover {
+ background-position: 0px -36px;
+}
+
+a.views-button-rearrange {
+ background-position: 0px 0px;
+}
+a.views-button-rearrange:hover {
+ background-position: 0px -12px;
+}
+
+a.views-button-remove span,
+a.views-button-rearrange span,
+a.views-button-configure span,
+a.views-button-add span {
+ display: none;
+}
+
+html.js #arrange thead {
+ display: none;
+}
+
+html.js .views-remove-checkbox {
+ display: none;
+}
+
+a.views-button-remove {
+ display: none;
+}
+
+html.js a.views-button-remove {
+ display: inline;
+}
+
+#arrange tr.even,
+#arrange tr.odd,
+#arrange td {
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+#arrange .form-item {
+ padding: 0;
+}
+
+div.changed {
+ background-color: #ffe;
+ font-weight: bold;
+}
+
+div.view-changed {
+ display: none;
+ float: right;
+ font-style: italic;
+ color: #f93;
+ padding-left: 1em;
+}
+
+div.views-tab div.changed a {
+
+}
+
+div.changed div.view-changed {
+ display: block;
+}
+
+.views-display .tab-section .inside .overridden {
+ /* all this so we don't mess up background-color */
+/* background-image: url(../images/overridden.gif);
+ background-repeat: no-repeat;
+ background-position: left;
+ padding-left: 10px; */
+}
+
+.views-display .tab-section .views-category-content.overridden {
+ background-image: none;
+}
+
+.views-display .tab-section .inside .defaulted {
+ color: #aaa;
+ font-style: italic;
+}
+
+.views-display .tab-section .inside .defaulted a {
+ font-style: italic;
+}
+
+.hilited {
+ color: #000;
+ font-weight: bold;
+ background-color: #ffd;
+ padding-left: 10px;
+}
+
+#views-ajax-pad fieldset {
+ background: transparent;
+ padding-left: 10px;
+}
+
+#views-ajax-pad pre {
+ overflow: auto;
+ border: 1px solid #333;
+ background-color: #f0f0f0;
+ padding: .5em;
+}
+
+form#views-add-display-form {
+ margin-bottom: 0em;
+ border-bottom: 1px solid #ccc;
+}
+
+form#views-add-display-form select {
+ width: 8.5em;
+}
+
+#views-ui-edit-view-form {
+ margin: 10px 0 0;
+ padding: 0;
+ clear: both;
+}
+
+#views-live-preview {
+ padding-top: .5em;
+}
+
+#views-live-preview form,
+#center #views-live-preview form {
+ border: 1px solid #D6DBDE;
+ margin: 0 0 .5em 0;
+ padding: .5em;
+}
+
+#views-live-preview form div.form-item {
+ float: left;
+ margin: 0;
+ padding: 0 1em 0 0;
+}
+
+#views-live-preview form input#preview-submit {
+ margin: 1em 0 0 0;
+}
+
+.view-locked {
+ color: red;
+ border: 1px solid red;
+ padding: 1em;
+}
+
+/* Hide by default only with js */
+html.js .views-hidden {
+ display: none;
+}
+
+.views-query-info {
+/* overflow: auto; */
+}
+
+.views-query-info pre {
+ white-space: pre; /* CSS2 */
+ white-space: -moz-pre-wrap; /* Mozilla */
+ white-space: -hp-pre-wrap; /* HP printers */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: pre-wrap; /* CSS 2.1 */
+ white-space: pre-line; /* CSS 3 (and 2.1 as well, actually) */
+ word-wrap: break-word; /* IE */
+ max-height: 200px;
+ overflow: scroll;
+}
+
+.views-quick-links {
+ float: right;
+}
+
+.views-quick-links ul.links li {
+ padding-left: 1em;
+}
+
+.views-quick-links li.last {
+}
+
+.views-edit-view .advanced-help-link {
+ padding-right: 3px;
+}
+
+#views-ajax-title .advanced-help-link {
+ position: relative;
+ top: 2px;
+ padding-right: 3px;
+}
+
+#views-ajax-pad input,
+#views-ajax-pad textarea {
+ max-width: 95%;
+}
+
+.clone-display,
+.remove-display {
+ float: right;
+ margin: 0;
+ padding: .2em 1em 0 0;
+ position: relative;
+ top: .1em;
+}
+
+.views-display .remove-display form,
+.remove-display input,
+.views-display .clone-display form,
+.clone-display input {
+ margin: 0 !important;
+}
+
+.views-validator-options {
+ padding: 0 1em;
+ margin: 0 1em;
+ border: 1px solid;
+}
+
+div.views-category #page-title {
+ background: none;
+ padding-top: 0px;
+}
diff --git a/css/views-list-rtl.css b/css/views-list-rtl.css
new file mode 100644
index 0000000..1324621
--- /dev/null
+++ b/css/views-list-rtl.css
@@ -0,0 +1,28 @@
+/* $Id: views-list-rtl.css,v 1.1 2009/03/25 00:08:45 merlinofchaos Exp $ */
+
+table.views-entry {
+ clear: right; /* RTL */
+}
+
+table.views-entry td.view-ops {
+ text-align: left; /* RTL */
+}
+
+#views-ui-list-views-form .form-item {
+ padding-left: 1em; /* RTL */
+ float: right; /* RTL */
+}
+
+#edit-order-wrapper {
+ clear: right; /* RTL */
+}
+
+#edit-views-apply,
+#edit-views-reset {
+ float: right; /* RTL */
+}
+
+.views-entry .advanced-help-link {
+ padding-left: 3px; /* RTL */
+}
+
diff --git a/css/views-list.css b/css/views-list.css
new file mode 100644
index 0000000..29e4c60
--- /dev/null
+++ b/css/views-list.css
@@ -0,0 +1,80 @@
+/* $Id: views-list.css,v 1.12.6.2 2009/11/18 20:04:07 merlinofchaos Exp $ */
+
+table.views-entry {
+ margin: 3px 0;
+ border: 1px solid #ddd;
+ background-color: white;
+ color: #494949; /* matches garland */
+ clear: left; /* LTR */
+ width: 100%;
+}
+
+table.views-entry tbody {
+ border: none;
+}
+
+table.views-entry td.view-ops {
+ width: 45%;
+ text-align: right; /* LTR */
+ background-color: #eee;
+}
+
+table.views-entry td.view-name {
+ background-color: #eee;
+}
+
+table.views-entry .description {
+ vertical-align: top;
+}
+
+body form#views-ui-list-views-form {
+ margin: 0 0 1.5em 0;
+}
+
+#views-ui-list-views-form .form-item {
+ padding-right: 1em; /* LTR */
+ float: left; /* LTR */
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+#edit-order-wrapper {
+ clear: left; /* LTR */
+}
+
+#edit-views-apply,
+#edit-views-reset {
+ margin-top: 1.65em;
+ float: left; /* LTR */
+}
+
+.views-entry .advanced-help-link {
+ position: relative;
+ top: 2px;
+ padding-right: 3px; /* LTR */
+}
+
+table.view-disabled {
+ color: #999;
+}
+
+table.views-entry td {
+ line-height: 1.4;
+ padding-bottom: 10px;
+}
+table.view-disabled td {
+ line-height: 1.4;
+ padding-bottom: 10px;
+ background: none;
+}
+table.view-enabled td.view-name,
+table.view-enabled td.view-ops,
+table.view-disabled td.view-name,
+table.view-disabled td.view-ops {
+ line-height: 1.6;
+ padding-bottom: 0.3em;
+}
+table.view-enabled td.view-name,
+table.view-enabled td.view-ops {
+ background: #E4F0F8;
+}
diff --git a/css/views-rtl.css b/css/views-rtl.css
new file mode 100644
index 0000000..fef2bd9
--- /dev/null
+++ b/css/views-rtl.css
@@ -0,0 +1,6 @@
+
+.views-exposed-form .views-exposed-widget {
+ float: right; /* RTL */
+ padding: .5em 1em 0 0; /* RTL */
+}
+
diff --git a/css/views-tabs.css b/css/views-tabs.css
new file mode 100644
index 0000000..34ed6fe
--- /dev/null
+++ b/css/views-tabs.css
@@ -0,0 +1,5 @@
+/* $Id */
+
+.ui-tabs-hide {
+ display: none;
+}
diff --git a/css/views.css b/css/views.css
new file mode 100644
index 0000000..b909f0b
--- /dev/null
+++ b/css/views.css
@@ -0,0 +1,57 @@
+/* $Id: views.css,v 1.11.6.5 2010/07/04 10:04:50 dereine Exp $ */
+.views-exposed-form .views-exposed-widget {
+ float: left; /* LTR */
+ padding: .5em 1em 0 0; /* LTR */
+}
+
+.views-exposed-form .views-exposed-widget .form-submit {
+ margin-top: 1.6em;
+}
+
+.views-exposed-form .form-item,
+.views-exposed-form .form-submit {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+.views-exposed-form label {
+ font-weight: bold;
+}
+
+.views-exposed-widgets {
+ margin-bottom: .5em;
+}
+
+/* table style column align */
+.views-align-left {
+ text-align: left;
+}
+.views-align-right {
+ text-align: right;
+}
+.views-align-center {
+ text-align: center;
+}
+
+div.view div.views-hide {
+ display: none;
+}
+
+/** For IE we add the class via js; for other browsers we rely on :hover **/
+div.view div.views-hide-hover,
+div.view:hover div.views-hide {
+ display: block;
+ position: absolute;
+ z-index: 200;
+}
+
+/* don't do this one in IE */
+div.view:hover div.views-hide {
+ margin-top: -1.5em;
+}
+
+/* Remove the border on tbody that system puts in */
+.views-view-grid tbody {
+ border-top: none;
+}
+
diff --git a/docs/CVS/Entries b/docs/CVS/Entries
new file mode 100644
index 0000000..54f865f
--- /dev/null
+++ b/docs/CVS/Entries
@@ -0,0 +1,2 @@
+/docs.php/1.16.4.6/Sat Oct 16 08:41:24 2010//TDRUPAL-7--3
+D
diff --git a/docs/CVS/Repository b/docs/CVS/Repository
new file mode 100644
index 0000000..171745d
--- /dev/null
+++ b/docs/CVS/Repository
@@ -0,0 +1 @@
+contributions/modules/views/docs
diff --git a/docs/CVS/Root b/docs/CVS/Root
new file mode 100644
index 0000000..127da18
--- /dev/null
+++ b/docs/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal-contrib
diff --git a/docs/CVS/Tag b/docs/CVS/Tag
new file mode 100644
index 0000000..0f07c7f
--- /dev/null
+++ b/docs/CVS/Tag
@@ -0,0 +1 @@
+TDRUPAL-7--3
diff --git a/docs/docs.php b/docs/docs.php
new file mode 100644
index 0000000..bb54000
--- /dev/null
+++ b/docs/docs.php
@@ -0,0 +1,685 @@
+<?php
+// $Id: docs.php,v 1.16.4.6 2010/10/16 08:41:24 dereine Exp $
+/**
+ * @file
+ * This file contains no working PHP code; it exists to provide additional documentation
+ * for doxygen as well as to document hooks in the standard Drupal manner.
+ */
+
+/**
+ * @mainpage Views 2 API Manual
+ *
+ * Much of this information is actually stored in the advanced help; please
+ * check the API topic. This help will primarily be aimed at documenting
+ * classes and function calls.
+ *
+ * An online version of the advanced help API documentation is available from:
+ * @link http://views-help.doc.logrus.com/help/views/api @endlink
+ *
+ * Topics:
+ * - @ref view_lifetime
+ * - @ref views_hooks
+ * - @ref views_handlers
+ * - @ref views_plugins
+ * - @ref views_templates
+ */
+
+/**
+ * @page view_lifetime The life of a view
+ *
+ * This page explains the basic cycle of a view and what processes happen.
+ */
+
+/**
+ * @page views_handlers About Views' handlers
+ *
+ * This page explains what views handlers are, how they're written, and what
+ * the basic conventions are.
+ *
+ * - @ref views_field_handlers
+ * - @ref views_sort_handlers
+ * - @ref views_filter_handlers
+ * - @ref views_argument_handlers
+ * - @ref views_relationship_handlers
+ */
+
+/**
+ * @page views_plugins About Views' plugins
+ *
+ * This page explains what views plugins are, how they're written, and what
+ * the basic conventions are.
+ *
+ * - @ref views_display_plugins
+ * - @ref views_style_plugins
+ * - @ref views_row_plugins
+ */
+
+/**
+ * @defgroup views_hooks Views' hooks
+ * @{
+ * Hooks that can be implemented by other modules in order to implement the
+ * Views API.
+ */
+
+/**
+ * Describe table structure to Views.
+ *
+ * This hook should be placed in MODULENAME.views.inc and it will be auto-loaded.
+ * This must either be in the same directory as the .module file or in a subdirectory
+ * named 'includes'.
+ *
+ * The full documentation for this hook is in the advanced help.
+ * @link http://views-help.doc.logrus.com/help/views/api-tables @endlink
+ */
+function hook_views_data() {
+ // This example describes how to write hook_views_data() for the following
+ // table:
+ //
+ // CREATE TABLE example_table (
+ // nid INT(11) NOT NULL COMMENT 'Primary key; refers to {node}.nid.',
+ // plain_text_field VARCHAR(32) COMMENT 'Just a plain text field.',
+ // numeric_field INT(11) COMMENT 'Just a numeric field.',
+ // boolean_field INT(1) COMMENT 'Just an on/off field.',
+ // timestamp_field INT(8) COMMENT 'Just a timestamp field.',
+ // PRIMARY KEY(nid)
+ // );
+
+ // The 'group' index will be used as a prefix in the UI for any of this
+ // table's fields, sort criteria, etc. so it's easy to tell where they came
+ // from.
+ $data['example_table']['table']['group'] = t('Example table');
+
+ // Define this as a base table. In reality this is not very useful for
+ // this table, as it isn't really a distinct object of its own, but
+ // it makes a good example.
+ $data['example_table']['table']['base'] = array(
+ 'field' => 'nid',
+ 'title' => t('Example table'),
+ 'help' => t("Example table contains example content and can be related to nodes."),
+ 'weight' => -10,
+ );
+
+ // This table references the {node} table.
+ // This creates an 'implicit' relationship to the node table, so that when 'Node'
+ // is the base table, the fields are automatically available.
+ $data['example_table']['table']['join'] = array(
+ // Index this array by the table name to which this table refers.
+ // 'left_field' is the primary key in the referenced table.
+ // 'field' is the foreign key in this table.
+ 'node' => array(
+ 'left_field' => 'nid',
+ 'field' => 'nid',
+ ),
+ );
+
+ // Next, describe each of the individual fields in this table to Views. For
+ // each field, you may define what field, sort, argument, and/or filter
+ // handlers it supports. This will determine where in the Views interface you
+ // may use the field.
+
+ // Node ID field.
+ $data['example_table']['nid'] = array(
+ 'title' => t('Example content'),
+ 'help' => t('Some example content that references a node.'),
+ // Because this is a foreign key to the {node} table. This allows us to
+ // have, when the view is configured with this relationship, all the fields
+ // for the related node available.
+ 'relationship' => array(
+ 'base' => 'node',
+ 'field' => 'nid',
+ 'handler' => 'views_handler_relationship',
+ 'label' => t('Example node'),
+ ),
+ );
+
+ // Example plain text field.
+ $data['example_table']['plain_text_field'] = array(
+ 'title' => t('Plain text field'),
+ 'help' => t('Just a plain text field.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field',
+ 'click sortable' => TRUE,
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_string',
+ ),
+ 'argument' => array(
+ 'handler' => 'views_handler_argument_string',
+ ),
+ );
+
+ // Example numeric text field.
+ $data['example_table']['numeric_field'] = array(
+ 'title' => t('Numeric field'),
+ 'help' => t('Just a numeric field.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_numeric',
+ 'click sortable' => TRUE,
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_numeric',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ );
+
+ // Example boolean field.
+ $data['example_table']['boolean_field'] = array(
+ 'title' => t('Boolean field'),
+ 'help' => t('Just an on/off field.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_boolean',
+ 'click sortable' => TRUE,
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_boolean_operator',
+ 'label' => t('Published'),
+ 'type' => 'yes-no',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ );
+
+ // Example timestamp field.
+ $data['example_table']['timestamp_field'] = array(
+ 'title' => t('Timestamp field'),
+ 'help' => t('Just a timestamp field.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_date',
+ 'click sortable' => TRUE,
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort_date',
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_date',
+ ),
+ );
+
+ return $data;
+}
+
+/**
+ * Alter table structure.
+ *
+ * You can add/edit/remove to existing tables defined by hook_views_data().
+ *
+ * This hook should be placed in MODULENAME.views.inc and it will be auto-loaded.
+ * This must either be in the same directory as the .module file or in a subdirectory
+ * named 'includes'.
+ *
+ * The full documentation for this hook is in the advanced help.
+ * @link http://views-help.doc.logrus.com/help/views/api-tables @endlink
+ */
+function hook_views_data_alter(&$data) {
+ // This example alters the title of the node: nid field for the admin.
+ $data['node']['nid']['title'] = t('Node-Nid');
+
+ // This example adds a example field to the users table
+ $data['users']['example_field'] = array(
+ 'title' => t('Example field'),
+ 'help' => t('Some examüple content that references a user'),
+ 'handler' => 'hook_handlers_field_example_field',
+ );
+
+ // This example changes the handler of the node title field.
+ // In this handler you could do stuff, like preview of the node, when clicking the node title.
+
+ $data['node']['title']['handler'] = 'modulename_handlers_field_node_title';
+}
+
+
+/**
+ * The full documentation for this hook is now in the advanced help.
+ *
+ * This hook should be placed in MODULENAME.views.inc and it will be auto-loaded.
+ * This must either be in the same directory as the .module file or in a subdirectory
+ * named 'includes'.
+ *
+ * This is a stub list as a reminder that this needs to be doc'd and is not used
+ * in views anywhere so might not be remembered when this is formally documented:
+ * - style: 'even empty'
+ */
+function hook_views_plugins() {
+ // example code here
+}
+
+/**
+ * Alter existing plugins data, defined by modules.
+ */
+function hook_views_plugins_alter(&$plugins) {
+ // Add apachesolr to the base of the node row plugin.
+ $plugins['row']['node']['base'][] = 'apachesolr';
+}
+
+/**
+ * Register View API information. This is required for your module to have
+ * its include files loaded; for example, when implementing
+ * hook_views_default_views().
+ *
+ * @return
+ * An array with the following possible keys:
+ * - api: (required) The version of the Views API the module implements.
+ * - path: (optional) If includes are stored somewhere other than within
+ * the root module directory or a subdirectory called includes, specify
+ * its path here.
+ */
+function hook_views_api() {
+ return array(
+ 'api' => 2,
+ 'path' => drupal_get_path('module', 'example') . '/includes/views',
+ );
+}
+
+/**
+ * This hook allows modules to provide their own views which can either be used
+ * as-is or as a "starter" for users to build from.
+ *
+ * This hook should be placed in MODULENAME.views_default.inc and it will be
+ * auto-loaded. This must either be in the same directory as the .module file
+ * or in a subdirectory named 'includes'.
+ *
+ * The $view->disabled boolean flag indicates whether the View should be
+ * enabled or disabled by default.
+ *
+ * @return
+ * An associative array containing the structures of views, as generated from
+ * the Export tab, keyed by the view name. A best practice is to go through
+ * and add t() to all title and label strings, with the exception of menu
+ * strings.
+ */
+function hook_views_default_views() {
+ // Begin copy and paste of output from the Export tab of a view.
+ $view = new view;
+ $view->name = 'frontpage';
+ $view->description = t('Emulates the default Drupal front page; you may set the default home page path to this view to make it your front page.');
+ $view->tag = t('default');
+ $view->base_table = 'node';
+ $view->api_version = 2;
+ $view->disabled = FALSE; // Edit this to true to make a default view disabled initially
+ $view->display = array();
+ $display = new views_display;
+ $display->id = 'default';
+ $display->display_title = t('Defaults');
+ $display->display_plugin = 'default';
+ $display->position = '1';
+ $display->display_options = array (
+ 'style_plugin' => 'default',
+ 'style_options' =>
+ array (
+ ),
+ 'row_plugin' => 'node',
+ 'row_options' =>
+ array (
+ 'teaser' => 1,
+ 'links' => 1,
+ ),
+ 'relationships' =>
+ array (
+ ),
+ 'fields' =>
+ array (
+ ),
+ 'sorts' =>
+ array (
+ 'sticky' =>
+ array (
+ 'id' => 'sticky',
+ 'table' => 'node',
+ 'field' => 'sticky',
+ 'order' => 'ASC',
+ ),
+ 'created' =>
+ array (
+ 'id' => 'created',
+ 'table' => 'node',
+ 'field' => 'created',
+ 'order' => 'ASC',
+ 'relationship' => 'none',
+ 'granularity' => 'second',
+ ),
+ ),
+ 'arguments' =>
+ array (
+ ),
+ 'filters' =>
+ array (
+ 'promote' =>
+ array (
+ 'id' => 'promote',
+ 'table' => 'node',
+ 'field' => 'promote',
+ 'operator' => '=',
+ 'value' => '1',
+ 'group' => 0,
+ 'exposed' => false,
+ 'expose' =>
+ array (
+ 'operator' => false,
+ 'label' => '',
+ ),
+ ),
+ 'status' =>
+ array (
+ 'id' => 'status',
+ 'table' => 'node',
+ 'field' => 'status',
+ 'operator' => '=',
+ 'value' => '1',
+ 'group' => 0,
+ 'exposed' => false,
+ 'expose' =>
+ array (
+ 'operator' => false,
+ 'label' => '',
+ ),
+ ),
+ ),
+ 'items_per_page' => 10,
+ 'use_pager' => '1',
+ 'pager_element' => 0,
+ 'title' => '',
+ 'header' => '',
+ 'header_format' => '1',
+ 'footer' => '',
+ 'footer_format' => '1',
+ 'empty' => '',
+ 'empty_format' => '1',
+ );
+ $view->display['default'] = $display;
+ $display = new views_display;
+ $display->id = 'page';
+ $display->display_title = t('Page');
+ $display->display_plugin = 'page';
+ $display->position = '2';
+ $display->display_options = array (
+ 'defaults' =>
+ array (
+ 'access' => true,
+ 'title' => true,
+ 'header' => true,
+ 'header_format' => true,
+ 'header_empty' => true,
+ 'footer' => true,
+ 'footer_format' => true,
+ 'footer_empty' => true,
+ 'empty' => true,
+ 'empty_format' => true,
+ 'items_per_page' => true,
+ 'offset' => true,
+ 'use_pager' => true,
+ 'pager_element' => true,
+ 'link_display' => true,
+ 'php_arg_code' => true,
+ 'exposed_options' => true,
+ 'style_plugin' => true,
+ 'style_options' => true,
+ 'row_plugin' => true,
+ 'row_options' => true,
+ 'relationships' => true,
+ 'fields' => true,
+ 'sorts' => true,
+ 'arguments' => true,
+ 'filters' => true,
+ 'use_ajax' => true,
+ 'distinct' => true,
+ ),
+ 'relationships' =>
+ array (
+ ),
+ 'fields' =>
+ array (
+ ),
+ 'sorts' =>
+ array (
+ ),
+ 'arguments' =>
+ array (
+ ),
+ 'filters' =>
+ array (
+ ),
+ 'path' => 'frontpage',
+ );
+ $view->display['page'] = $display;
+ $display = new views_display;
+ $display->id = 'feed';
+ $display->display_title = t('Feed');
+ $display->display_plugin = 'feed';
+ $display->position = '3';
+ $display->display_options = array (
+ 'defaults' =>
+ array (
+ 'access' => true,
+ 'title' => false,
+ 'header' => true,
+ 'header_format' => true,
+ 'header_empty' => true,
+ 'footer' => true,
+ 'footer_format' => true,
+ 'footer_empty' => true,
+ 'empty' => true,
+ 'empty_format' => true,
+ 'use_ajax' => true,
+ 'items_per_page' => true,
+ 'offset' => true,
+ 'use_pager' => true,
+ 'pager_element' => true,
+ 'use_more' => true,
+ 'distinct' => true,
+ 'link_display' => true,
+ 'php_arg_code' => true,
+ 'exposed_options' => true,
+ 'style_plugin' => false,
+ 'style_options' => false,
+ 'row_plugin' => false,
+ 'row_options' => false,
+ 'relationships' => true,
+ 'fields' => true,
+ 'sorts' => true,
+ 'arguments' => true,
+ 'filters' => true,
+ ),
+ 'relationships' =>
+ array (
+ ),
+ 'fields' =>
+ array (
+ ),
+ 'sorts' =>
+ array (
+ ),
+ 'arguments' =>
+ array (
+ ),
+ 'filters' =>
+ array (
+ ),
+ 'displays' =>
+ array (
+ 'default' => 'default',
+ 'page' => 'page',
+ ),
+ 'style_plugin' => 'rss',
+ 'style_options' =>
+ array (
+ 'mission_description' => 1,
+ 'description' => '',
+ ),
+ 'row_plugin' => 'node_rss',
+ 'row_options' =>
+ array (
+ 'item_length' => 'default',
+ ),
+ 'path' => 'rss.xml',
+ 'title' => t('Front page feed'),
+ );
+ $view->display['feed'] = $display;
+ // End copy and paste of Export tab output.
+
+ // Add view to list of views to provide.
+ $views[$view->name] = $view;
+
+ // ...Repeat all of the above for each view the module should provide.
+
+ // At the end, return array of default views.
+ return $views;
+}
+
+/**
+ * This hook is called right before all default views are cached to the
+ * database. It takes a keyed array of views by reference.
+ */
+function hook_views_default_views_alter(&$views) {
+ if (isset($views['taxonomy_term'])) {
+ $views['taxonomy_term']->set_display('default');
+ $views['taxonomy_term']->display_handler->set_option('title', 'Categories');
+ }
+}
+
+/**
+ * Stub hook documentation
+ *
+ * This hook should be placed in MODULENAME.views_convert.inc and it will be auto-loaded.
+ * This must either be in the same directory as the .module file or in a subdirectory
+ * named 'includes'.
+ */
+function hook_views_convert() {
+ // example code here
+}
+
+/**
+ * Stub hook documentation
+ */
+function hook_views_query_substitutions() {
+ // example code here
+}
+
+/**
+ * This hook is called at the very beginning of views processing,
+ * before anything is done.
+ *
+ * Adding output to the view can be accomplished by placing text on
+ * $view->attachment_before and $view->attachment_after.
+ */
+function hook_views_pre_view(&$view, &$display_id, &$args) {
+ // example code here
+}
+
+/**
+ * This hook is called right before the build process, but after displays
+ * are attached and the display performs its pre_execute phase.
+ *
+ * Adding output to the view can be accomplished by placing text on
+ * $view->attachment_before and $view->attachment_after.
+ */
+function hook_views_pre_build(&$view) {
+ // example code here
+}
+
+/**
+ * This hook is called right before the execute process. The query is
+ * now fully built, but it has not yet been run through db_rewrite_sql.
+ *
+ * Adding output to the view can be accomplished by placing text on
+ * $view->attachment_before and $view->attachment_after.
+ */
+function hook_views_pre_execute(&$view) {
+ // example code here
+}
+
+/**
+ * This hook is called right before the render process. The query has
+ * been executed, and the pre_render() phase has already happened for
+ * handlers, so all data should be available.
+ *
+ * Adding output to the view can be accomplished by placing text on
+ * $view->attachment_before and $view->attachment_after. Altering the
+ * content can be achieved by editing the items of $view->result.
+ *
+ * This hook can be utilized by themes.
+ */
+function hook_views_pre_render(&$view) {
+ // example code here
+}
+
+/**
+ * Post process any rendered data.
+ *
+ * This can be valuable to be able to cache a view and still have some level of
+ * dynamic output. In an ideal world, the actual output will include HTML
+ * comment based tokens, and then the post process can replace those tokens.
+ *
+ * Example usage. If it is known that the view is a node view and that the
+ * primary field will be a nid, you can do something like this:
+ *
+ * <!--post-FIELD-NID-->
+ *
+ * And then in the post render, create an array with the text that should
+ * go there:
+ *
+ * strtr($output, array('<!--post-FIELD-1-->', 'output for FIELD of nid 1');
+ *
+ * All of the cached result data will be available in $view->result, as well,
+ * so all ids used in the query should be discoverable.
+ *
+ * This hook can be utilized by themes.
+ */
+function hook_views_post_render(&$view, &$output, &$cache) {
+
+}
+
+/**
+ * Stub hook documentation
+ *
+ * This hook should be placed in MODULENAME.views.inc and it will be auto-loaded.
+ * This must either be in the same directory as the .module file or in a subdirectory
+ * named 'includes'.
+ *
+ */
+function hook_views_query_alter(&$view, &$query) {
+ // example code here
+}
+
+/**
+ * This hook should be placed in MODULENAME.views.inc and it will be auto-loaded.
+ * This must either be in the same directory as the .module file or in a subdirectory
+ * named 'includes'.
+ *
+ * Alter the links that appear over a view. They are in a format suitable for
+ * theme('links').
+ *
+ * Warning: $view is not a reference in PHP4 and cannot be modified here. But it IS
+ * a reference in PHP5, and can be modified. Please be careful with it.
+ *
+ * @see theme_links
+ */
+function hook_views_admin_links_alter(&$links, $view) {
+ // example code here
+}
+
+/**
+ * This hook should be placed in MODULENAME.views.inc and it will be auto-loaded.
+ * This must either be in the same directory as the .module file or in a subdirectory
+ * named 'includes'.
+ *
+ * Alter the rows that appear with a view, which includes path and query information.
+ * The rows are suitable for theme('table').
+ *
+ * Warning: $view is not a reference in PHP4 and cannot be modified here. But it IS
+ * a reference in PHP5, and can be modified. Please be careful with it.
+ *
+ * @see theme_table
+ */
+function hook_views_preview_info_alter(&$rows, $view) {
+ // example code here
+}
+
+/**
+ * @}
+ */
diff --git a/documentation-standards.txt b/documentation-standards.txt
new file mode 100644
index 0000000..ea61135
--- /dev/null
+++ b/documentation-standards.txt
@@ -0,0 +1,6 @@
+- If the interface text is *bolded*, it got strong tags.
+- If it's a button they need to click, that's *bold* too.
+- If the text is not bolded (ex: links to click, options to check), it
+got /italicized/.
+- If it's user-entered text it got 'single quotes'.
+
diff --git a/handlers/CVS/Entries b/handlers/CVS/Entries
new file mode 100644
index 0000000..57ee1f2
--- /dev/null
+++ b/handlers/CVS/Entries
@@ -0,0 +1,39 @@
+/views_handler_area.inc/1.1.4.2/Sun Feb 7 13:44:07 2010//TDRUPAL-7--3
+/views_handler_area_text.inc/1.1.4.6/Sat Oct 16 05:43:01 2010//TDRUPAL-7--3
+/views_handler_argument.inc/1.9.4.10/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_argument_date.inc/1.3.6.3/Thu Mar 11 08:30:24 2010//TDRUPAL-7--3
+/views_handler_argument_formula.inc/1.1.6.2/Thu Aug 12 05:21:28 2010//TDRUPAL-7--3
+/views_handler_argument_group_by_numeric.inc/1.1.4.2/Sun Jan 24 22:37:52 2010//TDRUPAL-7--3
+/views_handler_argument_many_to_one.inc/1.1.6.3/Mon Mar 22 20:40:31 2010//TDRUPAL-7--3
+/views_handler_argument_null.inc/1.1/Wed Sep 3 19:21:28 2008//TDRUPAL-7--3
+/views_handler_argument_numeric.inc/1.1.6.1/Mon Nov 2 22:01:25 2009//TDRUPAL-7--3
+/views_handler_argument_string.inc/1.5.4.5/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_field.inc/1.33.4.29/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_field_boolean.inc/1.3.4.3/Thu Aug 26 09:41:55 2010//TDRUPAL-7--3
+/views_handler_field_counter.inc/1.3.4.4/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_field_custom.inc/1.1.6.2/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_field_date.inc/1.3.4.4/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_field_group_by_numeric.inc/1.1.4.6/Sun Nov 7 11:36:59 2010//TDRUPAL-7--3
+/views_handler_field_markup.inc/1.3.6.4/Tue Oct 26 20:26:37 2010//TDRUPAL-7--3
+/views_handler_field_math.inc/1.1.2.3/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_field_numeric.inc/1.6.4.4/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_field_prerender_list.inc/1.3.4.4/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_field_url.inc/1.1/Wed Sep 3 19:21:28 2008//TDRUPAL-7--3
+/views_handler_filter.inc/1.10.4.11/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_filter_boolean_operator.inc/1.6.4.5/Thu Aug 26 09:41:55 2010//TDRUPAL-7--3
+/views_handler_filter_boolean_operator_string.inc/1.2.4.1/Mon Nov 2 22:01:25 2009//TDRUPAL-7--3
+/views_handler_filter_date.inc/1.3.6.3/Wed Mar 10 20:27:33 2010//TDRUPAL-7--3
+/views_handler_filter_equality.inc/1.2/Wed Sep 10 01:08:06 2008//TDRUPAL-7--3
+/views_handler_filter_group_by_numeric.inc/1.1.4.5/Sat Nov 6 17:56:10 2010//TDRUPAL-7--3
+/views_handler_filter_in_operator.inc/1.12.4.8/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_filter_many_to_one.inc/1.2.4.5/Tue Oct 12 22:14:55 2010//TDRUPAL-7--3
+/views_handler_filter_numeric.inc/1.7.6.4/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_filter_string.inc/1.8.4.4/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/views_handler_relationship.inc/1.4.4.3/Thu Aug 26 09:41:55 2010//TDRUPAL-7--3
+/views_handler_sort.inc/1.2.4.3/Mon Feb 22 10:15:28 2010//TDRUPAL-7--3
+/views_handler_sort_date.inc/1.1/Wed Sep 3 19:21:28 2008//TDRUPAL-7--3
+/views_handler_sort_formula.inc/1.1/Wed Sep 3 19:21:28 2008//TDRUPAL-7--3
+/views_handler_sort_group_by_numeric.inc/1.1.4.3/Thu Aug 26 09:41:55 2010//TDRUPAL-7--3
+/views_handler_sort_menu_hierarchy.inc/1.1/Wed Sep 3 19:21:28 2008//TDRUPAL-7--3
+/views_handler_sort_random.inc/1.1.6.1/Mon Nov 2 22:01:25 2009//TDRUPAL-7--3
+D
diff --git a/handlers/CVS/Repository b/handlers/CVS/Repository
new file mode 100644
index 0000000..86528fe
--- /dev/null
+++ b/handlers/CVS/Repository
@@ -0,0 +1 @@
+contributions/modules/views/handlers
diff --git a/handlers/CVS/Root b/handlers/CVS/Root
new file mode 100644
index 0000000..127da18
--- /dev/null
+++ b/handlers/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal-contrib
diff --git a/handlers/CVS/Tag b/handlers/CVS/Tag
new file mode 100644
index 0000000..0f07c7f
--- /dev/null
+++ b/handlers/CVS/Tag
@@ -0,0 +1 @@
+TDRUPAL-7--3
diff --git a/handlers/views_handler_area.inc b/handlers/views_handler_area.inc
new file mode 100644
index 0000000..70dea65
--- /dev/null
+++ b/handlers/views_handler_area.inc
@@ -0,0 +1,105 @@
+<?php
+// $Id: views_handler_area.inc,v 1.1.4.2 2010/02/07 13:44:07 dereine Exp $
+/**
+ * @file
+ * Views area handlers.
+ */
+
+/**
+ * @defgroup views_area_handlers Views' relationship handlers
+ * @{
+ * Handlers to tell Views what can display in header, footer
+ * and empty text in a view.
+ */
+
+class views_handler_area extends views_handler {
+ /**
+ * Get this field's label.
+ */
+ function label() {
+ if (!isset($this->options['label'])) {
+ return $this->ui_name();
+ }
+ return $this->options['label'];
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $this->definition['field'] = !empty($this->definition['field']) ? $this->definition['field'] : '';
+ $label = !empty($this->definition['label']) ? $this->definition['label'] : $this->definition['field'];
+ $options['label'] = array('default' => $label, 'translatable' => TRUE);
+ $options['empty'] = array('default' => 0, 'bool' => TRUE);
+
+ return $options;
+ }
+
+ /**
+ * Provide extra data to the administration form
+ */
+ function admin_summary() {
+ return $this->label();
+ }
+
+ /**
+ * Default options form that provides the label widget that all fields
+ * should have.
+ */
+ function options_form(&$form, &$form_state) {
+ $form['label'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Label'),
+ '#default_value' => isset($this->options['label']) ? $this->options['label'] : '',
+ '#description' => t('The label for this area that will be displayed only administratively.'),
+ );
+
+ if ($form_state['type'] != 'empty') {
+ $form['empty'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Display even if view has no result'),
+ '#default_value' => isset($this->options['empty']) ? $this->options['empty'] : 0,
+ '#description' => t('If checked this area will be rended, even if the views has no results.'),
+ );
+ }
+ }
+
+ /**
+ * Don't run a query
+ */
+ function query() { }
+
+ /**
+ * Render the area
+ */
+ function render($empty = FALSE) {
+ return '';
+ }
+}
+
+/**
+ * A special handler to take the place of missing or broken handlers.
+ */
+class views_handler_area_broken extends views_handler_area {
+ function ui_name($short = FALSE) {
+ return t('Broken/missing handler');
+ }
+
+ function ensure_my_table() { /* No table to ensure! */ }
+ function query() { /* No query to run */ }
+ function render($empty = FALSE) { return ''; }
+ function options_form(&$form, &$form_state) {
+ $form['markup'] = array(
+ '#prefix' => '<div class="form-item description">',
+ '#value' => t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.'),
+ );
+ }
+
+ /**
+ * Determine if the handler is considered 'broken'
+ */
+ function broken() { return TRUE; }
+}
+
+/**
+ * @}
+ */
diff --git a/handlers/views_handler_area_text.inc b/handlers/views_handler_area_text.inc
new file mode 100644
index 0000000..5d35e28
--- /dev/null
+++ b/handlers/views_handler_area_text.inc
@@ -0,0 +1,58 @@
+<?php
+// $Id: views_handler_area_text.inc,v 1.1.4.6 2010/10/16 05:43:01 dereine Exp $
+
+class views_handler_area_text extends views_handler_area {
+
+ function option_definition() {
+ $options = parent::option_definition();
+ $options['content'] = array('default' => '', 'translatable' => TRUE);
+ $options['format'] = array('default' => variable_get('filter_default_format', 1));
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ $form['content'] = array(
+ '#type' => 'text_format',
+ '#default_value' => $this->options['content'],
+ '#rows' => 6,
+ '#format' => $this->options['format'],
+ );
+ }
+
+ function options_submit(&$form, &$form_state) {
+ $form_state['values']['options']['format'] = $form_state['values']['options']['content']['format'];
+ $form_state['values']['options']['content'] = $form_state['values']['options']['content']['value'];
+ parent::options_submit($form, $form_state);
+ }
+
+ function render($empty = FALSE) {
+ if (!$empty || !empty($this->options['empty'])) {
+ return $this->render_textarea($this->options['content'], $this->options['format']);
+ }
+ return '';
+ }
+
+ /**
+ * Render a text area, using the proper format.
+ */
+ function render_textarea($value, $format) {
+ static $formats = array();
+
+ if (!array_key_exists($format, $formats)) {
+ $filter = filter_format_load($format);
+ $formats[$format] = $filter->name;
+ }
+
+ if (!isset($formats[$format])) {
+ return;
+ }
+
+ if ($value) {
+ return check_markup($value, $format, '', FALSE);
+ }
+ }
+
+}
+
diff --git a/handlers/views_handler_argument.inc b/handlers/views_handler_argument.inc
new file mode 100644
index 0000000..cbcd542
--- /dev/null
+++ b/handlers/views_handler_argument.inc
@@ -0,0 +1,937 @@
+<?php
+// $Id: views_handler_argument.inc,v 1.9.4.10 2010/11/05 07:20:54 dereine Exp $
+
+/**
+ * @defgroup views_argument_handlers Handlers for arguments
+ * @{
+ */
+
+/**
+ * Base class for arguments.
+ *
+ * The basic argument works for very simple arguments such as nid and uid
+ *
+ * Definition terms for this handler:
+ * - name field: The field to use for the name to use in the summary, which is
+ * the displayed output. For example, for the node: nid argument,
+ * the argument itself is the nid, but node.title is displayed.
+ * - name table: The table to use for the name, should it not be in the same
+ * table as the argument.
+ * - empty field name: For arguments that can have no value, such as taxonomy
+ * which can have "no term", this is the string which
+ * will be displayed for this lack of value. Be sure to use
+ * t().
+ * - validate type: A little used string to allow an argument to restrict
+ * which validator is available to just one. Use the
+ * validator ID. This probably should not be used at all,
+ * and may disappear or change.
+ * - numeric: If set to TRUE this field is numeric and will use %d instead of
+ * %s in queries.
+ *
+ * @ingroup views_argument_handlers
+ */
+class views_handler_argument extends views_handler {
+ var $name_field = NULL;
+ /**
+ * Constructor
+ */
+ function construct() {
+ parent::construct();
+
+ if (!empty($this->definition['name field'])) {
+ $this->name_field = $this->definition['name field'];
+ }
+ if (!empty($this->definition['name table'])) {
+ $this->name_table = $this->definition['name table'];
+ }
+ }
+
+ function init(&$view, &$options) {
+ parent::init($view, $options);
+ }
+
+ /**
+ * Give an argument the opportunity to modify the breadcrumb, if it wants.
+ * This only gets called on displays where a breadcrumb is actually used.
+ *
+ * The breadcrumb will be in the form of an array, with the keys being
+ * the path and the value being the already sanitized title of the path.
+ */
+ function set_breadcrumb(&$breadcrumb) { }
+
+ /**
+ * Determine if the argument can generate a breadcrumb
+ *
+ * @return TRUE/FALSE
+ */
+ function uses_breadcrumb() {
+ $info = $this->default_actions($this->options['default_action']);
+ return !empty($info['breadcrumb']);
+ }
+
+ function is_wildcard($arg = NULL) {
+ if (!isset($arg)) {
+ $arg = $this->argument;
+ }
+
+ return !empty($this->options['wildcard']) && $this->options['wildcard'] === $arg;
+ }
+
+ function wildcard_title() {
+ return $this->options['wildcard_substitution'];
+ }
+
+ /**
+ * Determine if the argument needs a style plugin.
+ *
+ * @return TRUE/FALSE
+ */
+ function needs_style_plugin() {
+ $info = $this->default_actions($this->options['default_action']);
+ $validate_info = $this->default_actions($this->options['validate_fail']);
+ return !empty($info['style plugin']) || !empty($validate_info['style plugin']);
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['default_action'] = array('default' => 'ignore');
+ $options['style_plugin'] = array('default' => 'default_summary', 'export' => 'export_style');
+ $options['style_options'] = array('default' => array(), 'export' => FALSE);
+ $options['wildcard'] = array('default' => 'all');
+ $options['wildcard_substitution'] = array('default' => t('All'), 'translatable' => TRUE);
+ $options['title'] = array('default' => '', 'translatable' => TRUE);
+ $options['breadcrumb'] = array('default' => '', 'translatable' => TRUE);
+ $options['default_argument_type'] = array('default' => 'fixed', 'export' => 'export_plugin');
+ $options['default_argument_options'] = array('default' => array(), 'export' => FALSE);
+ $options['validate_type'] = array('default' => 'none', 'export' => 'export_plugin');
+ $options['validate_options'] = array('default' => array(), 'export' => FALSE);
+ $options['validate_fail'] = array('default' => 'not found');
+
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ $defaults = $this->default_actions();
+
+ $form['title'] = array(
+ '#prefix' => '<div class="clearfix">',
+ '#suffix' => '</div>',
+ '#type' => 'textfield',
+ '#title' => t('Title'),
+ '#default_value' => $this->options['title'],
+ '#description' => t('The title to use when this argument is present. It will override the title of the view and titles from previous arguments. You can use percent substitution here to replace with argument titles. Use "%1" for the first argument, "%2" for the second, etc.'),
+ );
+
+ $form['breadcrumb'] = array(
+ '#prefix' => '<div class="clearfix">',
+ '#suffix' => '</div>',
+ '#type' => 'textfield',
+ '#title' => t('Breadcrumb'),
+ '#default_value' => $this->options['breadcrumb'],
+ '#description' => t('The Breadcrumb title to use when this argument is present. If no breadcrumb is set here, default Title values will be used, see "Title" for percent substitutions.'),
+ );
+
+ $form['clear_start'] = array(
+ '#markup' => '<div class="clearfix">',
+ );
+
+ $form['defaults_start'] = array(
+ '#markup' => '<div class="views-left-50">',
+ );
+
+ $form['default_action'] = array(
+ '#type' => 'radios',
+ '#title' => t('Action to take if argument is not present'),
+ '#default_value' => $this->options['default_action'],
+ );
+
+ $form['defaults_stop'] = array(
+ '#markup' => '</div>',
+ );
+
+ $form['wildcard'] = array(
+ '#prefix' => '<div class="views-right-50">',
+ // prefix and no suffix means these two items will be grouped together.
+ '#type' => 'textfield',
+ '#title' => t('Wildcard'),
+ '#size' => 20,
+ '#default_value' => $this->options['wildcard'],
+ '#description' => t('If this value is received as an argument, the argument will be ignored; i.e, "all values"'),
+ );
+
+ $form['wildcard_substitution'] = array(
+ '#suffix' => '</div>',
+ '#type' => 'textfield',
+ '#title' => t('Wildcard title'),
+ '#size' => 20,
+ '#default_value' => $this->options['wildcard_substitution'],
+ '#description' => t('The title to use for the wildcard in substitutions elsewhere.'),
+ );
+
+ $form['clear_stop'] = array(
+ '#markup' => '</div>',
+ );
+
+ $options = array();
+ $validate_options = array();
+ foreach ($defaults as $id => $info) {
+ $options[$id] = $info['title'];
+ if (empty($info['default only'])) {
+ $validate_options[$id] = $info['title'];
+ }
+ if (!empty($info['form method'])) {
+ $this->{$info['form method']}($form, $form_state);
+ }
+ }
+
+ $form['default_action']['#options'] = $options;
+
+ $form['validate_options_div_prefix'] = array(
+ '#id' => 'views-validator-options',
+ '#markup' => '<fieldset id="views-validator-options"><legend>' . t('Validator options') . '</legend>',
+ );
+
+ $form['validate_type'] = array(
+ '#type' => 'select',
+ '#title' => t('Validator'),
+ '#default_value' => $this->options['validate_type'],
+ );
+
+ $validate_types = array('none' => t('<Basic validation>'));
+ $plugins = views_fetch_plugin_data('argument validator');
+ foreach ($plugins as $id => $info) {
+ if (!empty($info['no ui'])) {
+ continue;
+ }
+
+ $valid = TRUE;
+ if (!empty($info['type'])) {
+ $valid = FALSE;
+ if (empty($this->definition['validate type'])) {
+ continue;
+ }
+ foreach ((array) $info['type'] as $type) {
+ if ($type == $this->definition['validate type']) {
+ $valid = TRUE;
+ break;
+ }
+ }
+ }
+
+ // If we decide this validator is ok, add it to the list.
+ if ($valid) {
+ $plugin = $this->get_plugin('argument validator', $id);
+ if ($plugin) {
+ if ($plugin->access() || $this->options['validate_type'] == $id) {
+ $form['argument_validate'][$id] = array(
+ '#prefix' => '<div id="edit-options-validate-options-' . $id . '-wrapper">',
+ '#suffix' => '</div>',
+ '#type' => 'item',
+ '#input' => TRUE, // trick it into checking input to make #process run
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-validate-type' => array($id)
+ ),
+ '#id' => 'edit-options-validate-options-' . $id,
+ );
+ $plugin->options_form($form['argument_validate'][$id], $form_state);
+ $validate_types[$id] = $info['title'];
+ }
+ }
+ }
+ }
+
+ asort($validate_types);
+ $form['validate_type']['#options'] = $validate_types;
+
+ $form['validate_fail'] = array(
+ '#type' => 'select',
+ '#title' => t('Action to take if argument does not validate'),
+ '#default_value' => $this->options['validate_fail'],
+ '#options' => $validate_options,
+ );
+
+ $form['validate_options_div_suffix'] = array(
+ '#markup' => '</fieldset>',
+ );
+ }
+
+ function options_validate(&$form, &$form_state) {
+ if (empty($form_state['values']['options'])) {
+ return;
+ }
+
+ // Let the plugins do validation.
+ $default_id = $form_state['values']['options']['default_argument_type'];
+ $plugin = $this->get_plugin('argument default', $default_id);
+ if ($plugin) {
+ $plugin->options_validate($form['argument_default'][$default_id], $form_state, $form_state['values']['options']['argument_default'][$default_id]);
+ }
+
+ $validate_id = $form_state['values']['options']['validate_type'];
+ $plugin = $this->get_plugin('argument validator', $validate_id);
+ if ($plugin) {
+ $plugin->options_validate($form['argument_validate'][$default_id], $form_state, $form_state['values']['options']['argument_validate'][$validate_id]);
+ }
+
+ }
+
+ function options_submit(&$form, &$form_state) {
+ if (empty($form_state['values']['options'])) {
+ return;
+ }
+
+ // Let the plugins make submit modifications if necessary.
+ $default_id = $form_state['values']['options']['default_argument_type'];
+ $plugin = $this->get_plugin('argument default', $default_id);
+ if ($plugin) {
+ $options = &$form_state['values']['options']['argument_default'][$default_id];
+ $plugin->options_submit($form['argument_default'][$default_id], $form_state, $options);
+ // Copy the now submitted options to their final resting place so they get saved.
+ $form_state['values']['options']['default_argument_options'] = $options;
+ }
+
+ $validate_id = $form_state['values']['options']['validate_type'];
+ $plugin = $this->get_plugin('argument validator', $validate_id);
+ if ($plugin) {
+ $options = &$form_state['values']['options']['argument_validate'][$validate_id];
+ $plugin->options_submit($form['argument_validate'][$validate_id], $form_state, $options);
+ // Copy the now submitted options to their final resting place so they get saved.
+ $form_state['values']['options']['validate_options'] = $options;
+ }
+ }
+
+ /**
+ * Provide a list of default behaviors for this argument if the argument
+ * is not present.
+ *
+ * Override this method to provide additional (or fewer) default behaviors.
+ */
+ function default_actions($which = NULL) {
+ $defaults = array(
+ 'ignore' => array(
+ 'title' => t('Display all values'),
+ 'method' => 'default_ignore',
+ 'breadcrumb' => TRUE, // generate a breadcrumb to here
+ ),
+ 'not found' => array(
+ 'title' => t('Hide view / Page not found (404)'),
+ 'method' => 'default_not_found',
+ 'hard fail' => TRUE, // This is a hard fail condition
+ ),
+ 'empty' => array(
+ 'title' => t('Display empty text'),
+ 'method' => 'default_empty',
+ 'breadcrumb' => TRUE, // generate a breadcrumb to here
+ ),
+ 'summary asc' => array(
+ 'title' => t('Summary, sorted ascending'),
+ 'method' => 'default_summary',
+ 'method args' => array('asc'),
+ 'style plugin' => TRUE,
+ 'breadcrumb' => TRUE, // generate a breadcrumb to here
+ ),
+ 'summary desc' => array(
+ 'title' => t('Summary, sorted descending'),
+ 'method' => 'default_summary',
+ 'method args' => array('desc'),
+ 'style plugin' => TRUE,
+ 'breadcrumb' => TRUE, // generate a breadcrumb to here
+ ),
+ 'summary asc by count' => array(
+ 'title' => t('Summary, sorted by number of records ascending'),
+ 'method' => 'default_summary',
+ 'method args' => array('asc', 'num_records'),
+ 'style plugin' => TRUE,
+ 'breadcrumb' => TRUE, // generate a breadcrumb to here
+ ),
+ 'summary desc by count' => array(
+ 'title' => t('Summary, sorted by number of records descending'),
+ 'method' => 'default_summary',
+ 'method args' => array('desc', 'num_records'),
+ 'style plugin' => TRUE,
+ 'breadcrumb' => TRUE, // generate a breadcrumb to here
+ ),
+ 'default' => array(
+ 'title' => t('Provide default argument'),
+ 'method' => 'default_default',
+ 'form method' => 'default_argument_form',
+ 'has default argument' => TRUE,
+ 'default only' => TRUE, // this can only be used for missing argument, not validation failure
+ ),
+ );
+
+ if ($which) {
+ if (!empty($defaults[$which])) {
+ return $defaults[$which];
+ }
+ }
+ else {
+ return $defaults;
+ }
+ }
+
+ /**
+ * Provide a form for selecting the default argument when the
+ * default action is set to provide default argument.
+ */
+ function default_argument_form(&$form, &$form_state) {
+ $plugins = views_fetch_plugin_data('argument default');
+ $options = array();
+
+ // This construct uses 'hidden' and not markup because process doesn't
+ // run. It also has an extra div because the dependency wants to hide
+ // the parent in situations like this, so we need a second div to
+ // make this work.
+ $form['default_options_div_prefix'] = array(
+ '#type' => 'hidden',
+ '#id' => 'views-default-options',
+ '#prefix' => '<div id="views-default-options-wrapper"><fieldset id="views-default-options"><legend>' . t('Provide default argument options') . '</legend>',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array('radio:options[default_action]' => array('default')),
+ );
+
+ $form['default_argument_type'] = array(
+ '#prefix' => '<div id="edit-options-default-argument-type-wrapper">',
+ '#suffix' => '</div>',
+ '#type' => 'radios',
+ '#id' => 'edit-options-default-argument-type',
+ '#title' => t('Default argument type'),
+ '#default_value' => $this->options['default_argument_type'],
+ );
+
+ foreach ($plugins as $id => $info) {
+ if (!empty($info['no ui'])) {
+ continue;
+ }
+ $plugin = $this->get_plugin('argument default', $id);
+ if ($plugin) {
+ if ($plugin->access() || $this->options['default_argument_type'] == $id) {
+ $form['argument_default'][$id] = array(
+ '#prefix' => '<div id="edit-options-argument-default-options-' . $id . '-wrapper">',
+ '#suffix' => '</div>',
+ '#id' => 'edit-options-argument-default-options-' . $id,
+ '#type' => 'item',
+ '#input' => TRUE, // trick it into checking input to make #process run
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'radio:options[default_action]' => array('default'),
+ 'radio:options[default_argument_type]' => array($id)
+ ),
+ '#dependency_count' => 2,
+ );
+ $options[$id] = $info['title'];
+ $plugin->options_form($form['argument_default'][$id], $form_state);
+ }
+ }
+ }
+
+ $form['default_options_div_suffix'] = array(
+ '#markup' => '</fieldset></div>',
+ );
+
+ asort($options);
+ $form['default_argument_type']['#options'] = $options;
+ }
+
+ /**
+ * Handle the default action, which means our argument wasn't present.
+ *
+ * Override this method only with extreme care.
+ *
+ * @return
+ * A boolean value; if TRUE, continue building this view. If FALSE,
+ * building the view will be aborted here.
+ */
+ function default_action($info = NULL) {
+ if (!isset($info)) {
+ $info = $this->default_actions($this->options['default_action']);
+ }
+
+ if (!$info) {
+ return FALSE;
+ }
+
+ if (!empty($info['method args'])) {
+ return call_user_func_array(array(&$this, $info['method']), $info['method args']);
+ }
+ else {
+ return $this->{$info['method']}();
+ }
+ }
+
+ /**
+ * How to act if validation failes
+ */
+ function validate_fail() {
+ $info = $this->default_actions($this->options['validate_fail']);
+ return $this->default_action($info);
+ }
+ /**
+ * Default action: ignore.
+ *
+ * If an argument was expected and was not given, in this case, simply
+ * ignore the argument entirely.
+ */
+ function default_ignore() {
+ return TRUE;
+ }
+
+ /**
+ * Default action: not found.
+ *
+ * If an argument was expected and was not given, in this case, report
+ * the view as 'not found' or hide it.
+ */
+ function default_not_found() {
+ // Set a failure condition and let the display manager handle it.
+ $this->view->build_info['fail'] = TRUE;
+ return FALSE;
+ }
+
+ /**
+ * Default action: empty
+ *
+ * If an argument was expected and was not given, in this case, display
+ * the view's empty text
+ */
+ function default_empty() {
+ // We return with no query; this will force the empty text.
+ $this->view->built = TRUE;
+ $this->view->executed = TRUE;
+ $this->view->result = array();
+ return FALSE;
+ }
+
+ /**
+ * This just returns true. The view argument builder will know where
+ * to find the argument from.
+ */
+ function default_default() {
+ return TRUE;
+ }
+
+ /**
+ * Determine if the argument is set to provide a default argument.
+ */
+ function has_default_argument() {
+ $info = $this->default_actions($this->options['default_action']);
+ return !empty($info['has default argument']);
+ }
+
+ /**
+ * Get a default argument, if available.
+ */
+ function get_default_argument() {
+ $plugin = $this->get_plugin('argument default');
+ if ($plugin) {
+ return $plugin->get_argument();
+ }
+ }
+
+ /**
+ * Default action: summary.
+ *
+ * If an argument was expected and was not given, in this case, display
+ * a summary query.
+ */
+ function default_summary($order, $by = NULL) {
+ $this->view->build_info['summary'] = TRUE;
+ $this->view->build_info['summary_level'] = $this->options['id'];
+
+ // Change the display style to the summary style for this
+ // argument.
+ $this->view->plugin_name = $this->options['style_plugin'];
+ $this->view->style_options = $this->options['style_options'];
+
+ // Clear out the normal primary field and whatever else may have
+ // been added and let the summary do the work.
+ $this->query->clear_fields();
+ $this->summary_query();
+
+ $this->summary_sort($order, $by);
+
+ // Summaries have their own sorting and fields, so tell the View not
+ // to build these.
+ $this->view->build_sort = $this->view->build_fields = FALSE;
+ return TRUE;
+ }
+
+ /**
+ * Build the info for the summary query.
+ *
+ * This must:
+ * - add_groupby: group on this field in order to create summaries.
+ * - add_field: add a 'num_nodes' field for the count. Usually it will
+ * be a count on $view->base_field
+ * - set_count_field: Reset the count field so we get the right paging.
+ *
+ * @return
+ * The alias used to get the number of records (count) for this entry.
+ */
+ function summary_query() {
+ $this->ensure_my_table();
+ // Add the field.
+ $this->base_alias = $this->query->add_field($this->table_alias, $this->real_field);
+
+ $this->summary_name_field();
+ return $this->summary_basics();
+ }
+
+ /**
+ * Add the name field, which is the field displayed in summary queries.
+ * This is often used when the argument is numeric.
+ */
+ function summary_name_field() {
+ // Add the 'name' field. For example, if this is a uid argument, the
+ // name field would be 'name' (i.e, the username).
+
+ if (isset($this->name_table)) {
+ // if the alias is different then we're probably added, not ensured,
+ // so look up the join and add it instead.
+ if ($this->table_alias != $this->table) {
+ $j = views_get_table_join($this->name_table, $this->table);
+ if ($j) {
+ $join = clone $j;
+ $join->left_table = $this->table_alias;
+ $this->name_table_alias = $this->query->add_table($this->name_table, $this->relationship, $join);
+ }
+ }
+ else {
+ $this->name_table_alias = $this->query->ensure_table($this->name_table, $this->relationship);
+ }
+ }
+ else {
+ $this->name_table_alias = $this->table_alias;
+ }
+
+ if (isset($this->name_field)) {
+ $this->name_alias = $this->query->add_field($this->name_table_alias, $this->name_field);
+ }
+ else {
+ $this->name_alias = $this->base_alias;
+ }
+ }
+
+ /**
+ * Some basic summary behavior that doesn't need to be repeated as much as
+ * code that goes into summary_query()
+ */
+ function summary_basics($count_field = TRUE) {
+ // Add the number of nodes counter
+ $distinct = ($this->view->display_handler->get_option('distinct') && empty($this->query->no_distinct));
+
+ $count_alias = $this->query->add_field($this->query->base_table, $this->query->base_field, 'num_records',
+ array('count' => TRUE, 'distinct' => $distinct));
+ $this->query->add_groupby($this->name_alias);
+
+ if ($count_field) {
+ $this->query->set_count_field($this->table_alias, $this->real_field);
+ }
+
+ $this->count_alias = $count_alias;
+ }
+
+ /**
+ * Sorts the summary based upon the user's selection. The base variant of
+ * this is usually adequte.
+ *
+ * @param $order
+ * The order selected in the UI.
+ */
+ function summary_sort($order, $by = NULL) {
+ $this->query->add_orderby(NULL, NULL, $order, (!empty($by) ? $by : $this->name_alias));
+ }
+
+ /**
+ * Provide the argument to use to link from the summary to the next level;
+ * this will be called once per row of a summary, and used as part of
+ * $view->get_url().
+ *
+ * @param $data
+ * The query results for the row.
+ */
+ function summary_argument($data) {
+ return $data->{$this->base_alias};
+ }
+
+ /**
+ * Provides the name to use for the summary. By default this is just
+ * the name field.
+ *
+ * @param $data
+ * The query results for the row.
+ */
+ function summary_name($data) {
+ $value = $data->{$this->name_alias};
+ if (empty($value) && !empty($this->definition['empty field name'])) {
+ $value = $this->definition['empty field name'];
+ }
+ return check_plain($value);
+ }
+
+ /**
+ * Set up the query for this argument.
+ *
+ * The argument sent may be found at $this->argument.
+ */
+ function query() {
+ $this->ensure_my_table();
+ $this->query->add_where(0, "$this->table_alias.$this->real_field", $this->argument);
+ }
+
+ /**
+ * Get the title this argument will assign the view, given the argument.
+ *
+ * This usually needs to be overridden to provide a proper title.
+ */
+ function title() {
+ return check_plain($this->argument);
+ }
+
+ /**
+ * Called by the view object to get the title. This may be set by a
+ * validator so we don't necessarily call through to title().
+ */
+ function get_title() {
+ if (isset($this->validated_title)) {
+ return $this->validated_title;
+ }
+ else {
+ return $this->title();
+ }
+ }
+
+ /**
+ * Validate that this argument works. By default, all arguments are valid.
+ */
+ function validate_arg($arg) {
+ // By using % in URLs, arguments could be validated twice; this eases
+ // that pain.
+ if (isset($this->argument_validated)) {
+ return $this->argument_validated;
+ }
+
+ if ($this->is_wildcard($arg)) {
+ return $this->argument_validated = TRUE;
+ }
+
+ if ($this->options['validate_type'] == 'none') {
+ return $this->argument_validated = $this->validate_argument_basic($arg);
+ }
+
+ $plugin = $this->get_plugin('argument validator');
+ if ($plugin) {
+ return $this->argument_validated = $plugin->validate_argument($arg);
+ }
+
+ // If the plugin isn't found, fall back to the basic validation path:
+ return $this->argument_validated = $this->validate_argument_basic($arg);
+ }
+
+ /**
+ * Called by the menu system to validate an argument.
+ *
+ * This checks to see if this is a 'soft fail', which means that if the
+ * argument fails to validate, but there is an action to take anyway,
+ * then validation cannot actually fail.
+ */
+ function validate_argument($arg) {
+ $validate_info = $this->default_actions($this->options['validate_fail']);
+ if (empty($validate_info['hard fail'])) {
+ return TRUE;
+ }
+
+ $rc = $this->validate_arg($arg);
+
+ // If the validator has changed the validate fail condition to a
+ // soft fail, deal with that:
+ $validate_info = $this->default_actions($this->options['validate_fail']);
+ if (empty($validate_info['hard fail'])) {
+ return TRUE;
+ }
+
+ return $rc;
+ }
+
+ /**
+ * Provide a basic argument validation.
+ *
+ * This can be overridden for more complex types; the basic
+ * validator only checks to see if the argument is not NULL
+ * or is numeric if the definition says it's numeric.
+ */
+ function validate_argument_basic($arg) {
+ if (!isset($arg) || $arg === '') {
+ return FALSE;
+ }
+
+ if (!empty($this->definition['numeric']) && !isset($this->options['break_phrase']) && !is_numeric($arg)) {
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ /**
+ * Set the input for this argument
+ *
+ * @return TRUE if it successfully validates; FALSE if it does not.
+ */
+ function set_argument($arg) {
+ $this->argument = $arg;
+ return $this->validate_arg($arg);
+ }
+
+ /**
+ * Get the value of this argument.
+ */
+ function get_value() {
+ // If we already processed this argument, we're done.
+ if (isset($this->argument)) {
+ return $this->argument;
+ }
+
+ // Otherwise, we have to pretend to process ourself to find the value.
+ $value = NULL;
+ // Find the position of this argument within the view.
+ $position = 0;
+ foreach ($this->view->argument as $id => $argument) {
+ if ($id == $this->options['id']) {
+ break;
+ }
+ $position++;
+ }
+
+ $arg = isset($this->view->args[$position]) ? $this->view->args[$position] : NULL;
+ $this->position = $position;
+
+ // Clone ourselves so that we don't break things when we're really
+ // processing the arguments.
+ $argument = clone $this;
+ if (!isset($arg) && $argument->has_default_argument()) {
+ $arg = $argument->get_default_argument();
+ }
+ // Set the argument, which will also validate that the argument can be set.
+ if ($argument->set_argument($arg)) {
+ $value = $argument->argument;
+ }
+ unset($argument);
+ return $value;
+ }
+
+ /**
+ * Special handling for the style export.
+ *
+ * Arguments can have styles for the summary view. This special export
+ * handler makes sure this works properly.
+ */
+ function export_style($indent, $prefix, $storage, $option, $definition, $parents) {
+ $output = '';
+ $name = $storage[$option];
+ $options = $storage['style_options'];
+
+ $plugin = views_get_plugin('style', $name);
+ if ($plugin) {
+ $plugin->init($this->view, $this->display, $options);
+ // Write which plugin to use.
+ $output .= $indent . $prefix . "['$option'] = '$name';\n";
+
+ // Pass off to the plugin to export itself.
+ $output .= $plugin->export_options($indent, $prefix . "['style_options']");
+ }
+
+ return $output;
+ }
+
+ /**
+ * Special handling for the style export.
+ *
+ * Arguments can have styles for the summary view. This special export
+ * handler makes sure this works properly.
+ */
+ function export_plugin($indent, $prefix, $storage, $option, $definition, $parents) {
+ $output = '';
+ if ($option == 'default_argument_type') {
+ $type = 'argument default';
+ $option_name = 'default_argument_options';
+ }
+ else {
+ $type = 'argument validator';
+ $option_name = 'validate_options';
+ }
+ $plugin = $this->get_plugin($type);
+ $name = $this->options[$option];
+
+ if ($plugin) {
+ // Write which plugin to use.
+ $output .= $indent . $prefix . "['$option'] = '$name';\n";
+
+ // Pass off to the plugin to export itself.
+ $output .= $plugin->export_options($indent, $prefix . "['$option_name']");
+ }
+
+ return $output;
+ }
+
+ /**
+ * Get the display or row plugin, if it exists.
+ */
+ function get_plugin($type = 'argument default', $name = NULL) {
+ $options = array();
+ switch ($type) {
+ case 'argument default':
+ $plugin_name = 'default_argument_type';
+ $options_name = 'default_argument_options';
+ break;
+ case 'argument validator':
+ $plugin_name = 'validate_type';
+ $options_name = 'validate_options';
+ }
+
+ if (!$name) {
+ $name = $this->options[$plugin_name];
+ }
+
+ // we only fetch the options if we're fetching the plugin actually
+ // in use.
+ if ($name == $this->options[$plugin_name]) {
+ $options = $this->options[$options_name];
+ }
+
+ $plugin = views_get_plugin($type, $name);
+ if ($plugin) {
+ $plugin->init($this->view, $this, $options);
+ return $plugin;
+ }
+ }
+}
+
+/**
+ * A special handler to take the place of missing or broken handlers.
+ *
+ * @ingroup views_argument_handlers
+ */
+class views_handler_argument_broken extends views_handler_argument {
+ function ui_name($short = FALSE) {
+ return t('Broken/missing handler');
+ }
+
+ function ensure_my_table() { /* No table to ensure! */ }
+ function query() { /* No query to run */ }
+ function options_form(&$form, &$form_state) {
+ $form['markup'] = array(
+ '#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
+ );
+ }
+
+ /**
+ * Determine if the handler is considered 'broken'
+ */
+ function broken() { return TRUE; }
+}
+
+/**
+ * @}
+ */
diff --git a/handlers/views_handler_argument_date.inc b/handlers/views_handler_argument_date.inc
new file mode 100644
index 0000000..d987c65
--- /dev/null
+++ b/handlers/views_handler_argument_date.inc
@@ -0,0 +1,67 @@
+<?php
+// $Id: views_handler_argument_date.inc,v 1.3.6.3 2010/03/11 08:30:24 dereine Exp $
+/**
+ * Abstract argument handler for dates.
+ *
+ * Adds an option to set a default argument based on the current date.
+ *
+ * @param $arg_format
+ * The format string to use on the current time when
+ * creating a default date argument.
+ *
+ * Definitions terms:
+ * - many to one: If true, the "many to one" helper will be used.
+ * - invalid input: A string to give to the user for obviously invalid input.
+ * This is deprecated in favor of argument validators.
+ * @see views_many_to_one_helper
+ *
+ * @ingroup views_argument_handlers
+ */
+class views_handler_argument_date extends views_handler_argument_formula {
+ var $option_name = 'default_argument_date';
+ var $arg_format = 'Y-m-d';
+
+ /**
+ * Add an option to set the default value to the current date.
+ */
+ function default_argument_form(&$form, &$form_state) {
+ parent::default_argument_form($form, $form_state);
+ $form['default_argument_type']['#options'] += array('date' => t('Current date'));
+ $form['default_argument_type']['#options'] += array('node_created' => t("Current node's creation time"));
+ $form['default_argument_type']['#options'] += array('node_changed' => t("Current node's update time")); }
+
+ /**
+ * Set the empty argument value to the current date,
+ * formatted appropriately for this argument.
+ */
+ function get_default_argument($raw = FALSE) {
+ if (!$raw && $this->options['default_argument_type'] == 'date') {
+ return date($this->arg_format, REQUEST_TIME);
+ }
+ else if (!$raw && in_array($this->options['default_argument_type'], array('node_created', 'node_changed'))) {
+ foreach (range(1, 3) as $i) {
+ $node = menu_get_object('node', $i);
+ if (!empty($node)) {
+ continue;
+ }
+ }
+
+ if (arg(0) == 'node' && is_numeric(arg(1))) {
+ $node = node_load(arg(1));
+ }
+
+ if (empty($node)) {
+ return parent::get_default_argument();
+ }
+ elseif ($this->options['default_argument_type'] == 'node_created') {
+ return date($this->arg_format, $node->created);
+ }
+ elseif ($this->options['default_argument_type'] == 'node_changed') {
+ return date($this->arg_format, $node->changed);
+ }
+ }
+
+ return parent::get_default_argument($raw);
+
+ }
+}
diff --git a/handlers/views_handler_argument_formula.inc b/handlers/views_handler_argument_formula.inc
new file mode 100644
index 0000000..3971528
--- /dev/null
+++ b/handlers/views_handler_argument_formula.inc
@@ -0,0 +1,57 @@
+<?php
+// $Id: views_handler_argument_formula.inc,v 1.1.6.2 2010/08/12 05:21:28 dereine Exp $
+/**
+ * Abstract argument handler for simple formulae.
+ *
+ * Child classes of this object should implement summary_argument, at least.
+ *
+ * Definition terms:
+ * - formula: The formula to use for this handler.
+ *
+ * @ingroup views_argument_handlers
+ */
+class views_handler_argument_formula extends views_handler_argument {
+ var $formula = NULL;
+ /**
+ * Constructor
+ */
+ function construct() {
+ parent::construct();
+
+ if (!empty($this->definition['formula'])) {
+ $this->formula = $this->definition['formula'];
+ }
+ }
+
+ function get_formula() {
+ return str_replace('***table***', $this->table_alias, $this->formula);
+ }
+
+ /**
+ * Build the summary query based on a formula
+ */
+ function summary_query() {
+ $this->ensure_my_table();
+ // Now that our table is secure, get our formula.
+ $formula = $this->get_formula();
+
+ // Add the field.
+ $this->base_alias = $this->name_alias = $this->query->add_field(NULL, $formula, $this->field);
+ $this->query->set_count_field(NULL, $formula, $this->field);
+
+ return $this->summary_basics(FALSE);
+ }
+
+ /**
+ * Build the query based upon the formula
+ */
+ function query() {
+ $this->ensure_my_table();
+ // Now that our table is secure, get our formula.
+ $formula = $this->get_formula() .' = :views_handler_argument_formula';
+ $placeholders = array(
+ ':views_handler_argument_formula' => $this->argument,
+ );
+ $this->query->add_where(0, $formula, $placeholders, 'formula');
+ }
+}
diff --git a/handlers/views_handler_argument_group_by_numeric.inc b/handlers/views_handler_argument_group_by_numeric.inc
new file mode 100644
index 0000000..c5a7da6
--- /dev/null
+++ b/handlers/views_handler_argument_group_by_numeric.inc
@@ -0,0 +1,18 @@
+<?php
+// $Id: views_handler_argument_group_by_numeric.inc,v 1.1.4.2 2010/01/24 22:37:52 dereine Exp $
+
+/**
+ * Simple handler for arguments using group by.
+ */
+class views_handler_argument_group_by_numeric extends views_handler_argument {
+ function query($group_by = FALSE) {
+ $this->ensure_my_table();
+ $field = $this->get_field();
+
+ $this->query->add_having(0, $field, $this->argument);
+ }
+
+ function ui_name() {
+ return $this->get_field(parent::ui_name());
+ }
+}
diff --git a/handlers/views_handler_argument_many_to_one.inc b/handlers/views_handler_argument_many_to_one.inc
new file mode 100644
index 0000000..e2346c4
--- /dev/null
+++ b/handlers/views_handler_argument_many_to_one.inc
@@ -0,0 +1,171 @@
+<?php
+// $Id: views_handler_argument_many_to_one.inc,v 1.1.6.3 2010/03/22 20:40:31 merlinofchaos Exp $
+/**
+ * An argument handler for use in fields that have a many to one relationship
+ * with the table(s) to the left. This adds a bunch of options that are
+ * reasonably common with this type of relationship.
+ * Definition terms:
+ * - numeric: If true, the field will be considered numeric. Probably should
+ * always be set TRUE as views_handler_argument_string has many to one
+ * capabilities.
+ * - zero is null: If true, a 0 will be handled as empty, so for example
+ * a default argument can be provided or a summary can be shown.
+ *
+ * @ingroup views_argument_handlers
+ */
+class views_handler_argument_many_to_one extends views_handler_argument {
+ function init(&$view, &$options) {
+ parent::init($view, $options);
+ $this->helper = new views_many_to_one_helper($this);
+
+ // Ensure defaults for these, during summaries and stuff:
+ $this->operator = 'or';
+ $this->value = array();
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ if (!empty($this->definition['numeric'])) {
+ $options['break_phrase'] = array('default' => FALSE);
+ }
+
+ $options['add_table'] = array('default' => FALSE);
+ $options['require_value'] = array('default' => FALSE);
+
+ views_many_to_one_helper::option_definition($options);
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ // allow + for or, , for and
+ if (!empty($this->definition['numeric'])) {
+ $form['break_phrase'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Allow multiple terms per argument.'),
+ '#description' => t('If selected, users can enter multiple arguments in the form of 1+2+3 (for OR) or 1,2,3 (for AND).'),
+ '#default_value' => !empty($this->options['break_phrase']),
+ );
+ }
+
+ $form['add_table'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Allow multiple arguments to work together.'),
+ '#description' => t('If selected, multiple instances of this argument can work together, as though multiple terms were supplied to the same argument. This setting is not compatible with the "Reduce duplicates" setting.'),
+ '#default_value' => !empty($this->options['add_table']),
+ );
+
+ $form['require_value'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Do not display items with no value in summary'),
+ '#default_value' => !empty($this->options['require_value']),
+ );
+
+ $this->helper->options_form($form, $form_state);
+ }
+
+ /**
+ * Override ensure_my_table so we can control how this joins in.
+ * The operator actually has influence over joining.
+ */
+ function ensure_my_table() {
+ $this->helper->ensure_my_table();
+ }
+
+ function query() {
+ $empty = FALSE;
+ if (isset($this->definition['zero is null']) && $this->definition['zero is null']) {
+ if (empty($this->argument)) {
+ $empty = TRUE;
+ }
+ }
+ else {
+ if (!isset($this->argument)) {
+ $empty = TRUE;
+ }
+ }
+ if ($empty) {
+ parent::ensure_my_table();
+ $this->query->add_where(0, "$this->table_alias.$this->real_field", NULL, 'IS NULL');
+ return;
+ }
+
+ if (!empty($this->options['break_phrase'])) {
+ views_break_phrase($this->argument, $this);
+ }
+ else {
+ $this->value = array($this->argument);
+ $this->operator = 'or';
+ }
+
+ $this->helper->add_filter();
+ }
+
+ function title() {
+ if (!$this->argument) {
+ return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
+ }
+
+ if (!empty($this->options['break_phrase'])) {
+ views_break_phrase($this->argument, $this);
+ }
+ else {
+ $this->value = array($this->argument);
+ $this->operator = 'or';
+ }
+
+ // @todo -- both of these should check definition for alternate keywords.
+
+ if (empty($this->value)) {
+ return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
+ }
+
+ if ($this->value === array(-1)) {
+ return !empty($this->definition['invalid input']) ? $this->definition['invalid input'] : t('Invalid input');
+ }
+
+ return implode($this->operator == 'or' ? ' + ' : ', ', $this->title_query());
+ }
+
+ function summary_query() {
+ $field = $this->table . '.' . $this->field;
+ $join = $this->get_join();
+
+ if (!empty($this->options['require_value'])) {
+ $join->type = 'INNER';
+ }
+
+ if (empty($this->options['add_table']) || empty($this->view->many_to_one_tables[$field])) {
+ $this->table_alias = $this->query->ensure_table($this->table, $this->relationship, $join);
+ }
+ else {
+ $this->table_alias = $this->helper->summary_join();
+ }
+
+ // Add the field.
+ $this->base_alias = $this->query->add_field($this->table_alias, $this->real_field);
+
+ $this->summary_name_field();
+
+ return $this->summary_basics();
+ }
+
+ function summary_argument($data) {
+ $value = $data->{$this->base_alias};
+ if (empty($value)) {
+ $value = 0;
+ }
+
+ return $value;
+ }
+
+ /**
+ * Override for specific title lookups.
+ */
+ function title_query() {
+ return $this->value;
+ }
+}
+
diff --git a/handlers/views_handler_argument_null.inc b/handlers/views_handler_argument_null.inc
new file mode 100644
index 0000000..884e557
--- /dev/null
+++ b/handlers/views_handler_argument_null.inc
@@ -0,0 +1,60 @@
+<?php
+// $Id: views_handler_argument_null.inc,v 1.1 2008/09/03 19:21:28 merlinofchaos Exp $
+/**
+ * Argument handler that ignores the argument.
+ */
+class views_handler_argument_null extends views_handler_argument {
+ function option_definition() {
+ $options = parent::option_definition();
+ $options['must_not_be'] = array('default' => FALSE);
+ return $options;
+ }
+
+ /**
+ * Override options_form() so that only the relevant options
+ * are displayed to the user.
+ */
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+ $form['must_not_be'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Fail basic validation if any argument is given'),
+ '#default_value' => !empty($this->options['must_not_be']),
+ '#description' => t('By checking this field, you can use this to make sure views with more arguments than necessary fail validation.'),
+ );
+
+ unset($form['wildcard']);
+ unset($form['wildcard_substitution']);
+ }
+
+ /**
+ * Override default_actions() to remove actions that don't
+ * make sense for a null argument.
+ */
+ function default_actions($which = NULL) {
+ if ($which) {
+ if (in_array($which, array('ignore', 'not found', 'empty', 'default'))) {
+ return parent::default_actions($which);
+ }
+ return;
+ }
+ $actions = parent::default_actions();
+ unset($actions['summary asc']);
+ unset($actions['summary desc']);
+ return $actions;
+ }
+
+ function validate_argument_basic($arg) {
+ if (!empty($this->options['must_not_be'])) {
+ return !isset($arg);
+ }
+
+ return parent::validate_argument_basic($arg);
+ }
+
+ /**
+ * Override the behavior of query() to prevent the query
+ * from being changed in any way.
+ */
+ function query() {}
+}
diff --git a/handlers/views_handler_argument_numeric.inc b/handlers/views_handler_argument_numeric.inc
new file mode 100644
index 0000000..6d5d785
--- /dev/null
+++ b/handlers/views_handler_argument_numeric.inc
@@ -0,0 +1,94 @@
+<?php
+// $Id: views_handler_argument_numeric.inc,v 1.1.6.1 2009/11/02 22:01:25 merlinofchaos Exp $
+/**
+ * @file
+ * Contains the numeric argument handler.
+ */
+
+/**
+ * Basic argument handler for arguments that are numeric. Incorporates
+ * break_phrase.
+ *
+ * @ingroup views_argument_handlers
+ */
+class views_handler_argument_numeric extends views_handler_argument {
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['break_phrase'] = array('default' => FALSE);
+ $options['not'] = array('default' => FALSE);
+
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ // allow + for or, , for and
+ $form['break_phrase'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Allow multiple terms per argument.'),
+ '#description' => t('If selected, users can enter multiple arguments in the form of 1+2+3 or 1,2,3.'),
+ '#default_value' => !empty($this->options['break_phrase']),
+ );
+
+ $form['not'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Exclude the argument'),
+ '#description' => t('If selected, the numbers entered in the argument will be excluded rather than limiting the view.'),
+ '#default_value' => !empty($this->options['not']),
+ );
+ }
+
+ function title() {
+ if (!$this->argument) {
+ return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
+ }
+
+ if (!empty($this->options['break_phrase'])) {
+ views_break_phrase($this->argument, $this);
+ }
+ else {
+ $this->value = array($this->argument);
+ $this->operator = 'or';
+ }
+
+ if (empty($this->value)) {
+ return !empty($this->definition['empty field name']) ? $this->definition['empty field name'] : t('Uncategorized');
+ }
+
+ if ($this->value === array(-1)) {
+ return !empty($this->definition['invalid input']) ? $this->definition['invalid input'] : t('Invalid input');
+ }
+
+ return implode($this->operator == 'or' ? ' + ' : ', ', $this->title_query());
+ }
+
+ /**
+ * Override for specific title lookups.
+ */
+ function title_query() {
+ return $this->value;
+ }
+
+ function query() {
+ $this->ensure_my_table();
+
+ if (!empty($this->options['break_phrase'])) {
+ views_break_phrase($this->argument, $this);
+ }
+ else {
+ $this->value = array($this->argument);
+ }
+
+ if (count($this->value) > 1) {
+ $operator = empty($this->options['not']) ? 'IN' : 'NOT IN';
+ $placeholders = implode(', ', array_fill(0, sizeof($this->value), '%d'));
+ $this->query->add_where(0, "$this->table_alias.$this->real_field", $this->value, $operator);
+ }
+ else {
+ $operator = empty($this->options['not']) ? '=' : '!=';
+ $this->query->add_where(0, "$this->table_alias.$this->real_field", $this->argument, $operator);
+ }
+ }
+}
diff --git a/handlers/views_handler_argument_string.inc b/handlers/views_handler_argument_string.inc
new file mode 100644
index 0000000..226b1d2
--- /dev/null
+++ b/handlers/views_handler_argument_string.inc
@@ -0,0 +1,234 @@
+<?php
+// $Id: views_handler_argument_string.inc,v 1.5.4.5 2010/11/05 07:20:54 dereine Exp $
+
+/**
+ * Basic argument handler to implement string arguments that may have length
+ * limits.
+ *
+ * @ingroup views_argument_handlers
+ */
+class views_handler_argument_string extends views_handler_argument {
+ function init(&$view, &$options) {
+ parent::init($view, $options);
+ if (!empty($this->definition['many to one'])) {
+ $this->helper = new views_many_to_one_helper($this);
+
+ // Ensure defaults for these, during summaries and stuff:
+ $this->operator = 'or';
+ $this->value = array();
+ }
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['glossary'] = array('default' => FALSE);
+ $options['limit'] = array('default' => 0);
+ $options['case'] = array('default' => 'none');
+ $options['path_case'] = array('default' => 'none');
+ $options['transform_dash'] = array('default' => FALSE);
+
+ if (!empty($this->definition['many to one'])) {
+ $options['add_table'] = array('default' => FALSE);
+ $options['require_value'] = array('default' => FALSE);
+ }
+
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ $form['glossary'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Glossary mode'),
+ '#description' => t('Glossary mode applies a limit to the number of characters used in the argument, which allows the summary view to act as a glossary.'),
+ '#default_value' => $this->options['glossary'],
+ );
+
+ $form['limit'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Character limit'),
+ '#description' => t('How many characters of the argument to filter against. If set to 1, all fields starting with the letter in the argument would be matched.'),
+ '#default_value' => $this->options['limit'],
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array('edit-options-glossary' => array(TRUE)),
+ );
+
+ $form['case'] = array(
+ '#type' => 'select',
+ '#title' => t('Case'),
+ '#description' => t('When printing the argument result, how to transform the case.'),
+ '#options' => array(
+ 'none' => t('No transform'),
+ 'upper' => t('Upper case'),
+ 'lower' => t('Lower case'),
+ 'ucfirst' => t('Capitalize first letter'),
+ 'ucwords' => t('Capitalize each word'),
+ ),
+ '#default_value' => $this->options['case'],
+ );
+
+ $form['path_case'] = array(
+ '#type' => 'select',
+ '#title' => t('Case in path'),
+ '#description' => t('When printing url paths, how to transform the case of the argument. Do not use this unless with Postgres as it uses case sensitive comparisons.'),
+ '#options' => array(
+ 'none' => t('No transform'),
+ 'upper' => t('Upper case'),
+ 'lower' => t('Lower case'),
+ 'ucfirst' => t('Capitalize first letter'),
+ 'ucwords' => t('Capitalize each word'),
+ ),
+ '#default_value' => $this->options['path_case'],
+ );
+
+ $form['transform_dash'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Transform spaces to dashes in URL'),
+ '#default_value' => $this->options['transform_dash'],
+ );
+
+ if (!empty($this->definition['many to one'])) {
+ $form['add_table'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Allow multiple arguments to work together.'),
+ '#description' => t('If selected, multiple instances of this argument can work together, as though multiple terms were supplied to the same argument. This setting is not compatible with the "Reduce duplicates" setting.'),
+ '#default_value' => !empty($this->options['add_table']),
+ );
+
+ $form['require_value'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Do not display items with no value in summary'),
+ '#default_value' => !empty($this->options['require_value']),
+ );
+ }
+ }
+
+ /**
+ * Build the summary query based on a string
+ */
+ function summary_query() {
+ if (empty($this->definition['many to one'])) {
+ $this->ensure_my_table();
+ }
+ else {
+ $this->table_alias = $this->helper->summary_join();
+ }
+
+ if (empty($this->options['glossary'])) {
+ // Add the field.
+ $this->base_alias = $this->name_alias = $this->query->add_field($this->table_alias, $this->real_field);
+ $this->query->set_count_field($this->table_alias, $this->real_field);
+ }
+ else {
+ // Add the field.
+ $formula = $this->get_formula();
+ $params = array(
+ 'placeholders' => array(
+ ':length' => intval($this->options['limit']),
+ ),
+ );
+
+ $this->base_alias = $this->name_alias = $this->query->add_field(NULL, $formula, $this->field . '_truncated', $params);
+ $this->query->set_count_field(NULL, $formula, $this->field, $this->field . '_truncated');
+ }
+
+ return $this->summary_basics(FALSE);
+ }
+
+ /**
+ * Get the formula for this argument.
+ *
+ * $this->ensure_my_table() MUST have been called prior to this.
+ */
+ function get_formula() {
+ return "SUBSTRING($this->table_alias.$this->real_field, 1, :length)";
+ }
+
+ /**
+ * Build the query based upon the formula
+ */
+ function query() {
+ $argument = $this->argument;
+ if (!empty($this->options['transform_dash'])) {
+ $argument = strtr($argument, '-', ' ');
+ }
+
+ if (!empty($this->definition['many to one'])) {
+ if (!empty($this->options['glossary'])) {
+ $this->helper->formula = TRUE;
+ }
+ $this->value = array($argument);
+ $this->helper->ensure_my_table();
+ $this->helper->add_filter();
+ return;
+ }
+
+ $this->ensure_my_table();
+ $formula = FALSE;
+ if (empty($this->options['glossary'])) {
+ $field = "$this->table_alias.$this->real_field";
+ }
+ else {
+ $formula = TRUE;
+ $field = $this->get_formula();
+ }
+
+ if ($formula) {
+ $field .= ' = :views_handler_argument_string';
+ $placeholders = array(
+ ':length' => intval($this->options['limit']),
+ ':views_handler_argument_string' => $argument,
+ );
+ $this->query->add_where(0, $field, $placeholders, 'formula');
+ }
+ else {
+ $this->query->add_where(0, $field, $argument);
+ }
+ }
+
+ function summary_argument($data) {
+ $value = $this->case_transform($data->{$this->base_alias}, 'path_case');
+ if (!empty($this->options['transform_dash'])) {
+ $value = strtr($value, ' ', '-');
+ }
+ return $value;
+ }
+
+ function case_transform($string, $option) {
+ global $multibyte;
+
+ switch ($this->options[$option]) {
+ default:
+ return $string;
+ case 'upper':
+ return drupal_strtoupper($string);
+ case 'lower':
+ return drupal_strtolower($string);
+ case 'ucfirst':
+ return drupal_strtoupper(drupal_substr($string, 0, 1)) . drupal_substr($string, 1);
+ case 'ucwords':
+ if ($multibyte == UNICODE_MULTIBYTE) {
+ return mb_convert_case($string, MB_CASE_TITLE);
+ } else {
+ return ucwords($string);
+ }
+ }
+ }
+
+ function title() {
+ $title = $this->case_transform($this->argument, 'case');
+ if (!empty($this->options['transform_dash'])) {
+ $title = strtr($title, '-', ' ');
+ }
+
+ return check_plain($title);
+ }
+
+ function summary_name($data) {
+ return $this->case_transform(parent::summary_name($data), 'case');
+ }
+
+}
+
diff --git a/handlers/views_handler_field.inc b/handlers/views_handler_field.inc
new file mode 100644
index 0000000..2ad4c1d
--- /dev/null
+++ b/handlers/views_handler_field.inc
@@ -0,0 +1,848 @@
+<?php
+// $Id: views_handler_field.inc,v 1.33.4.29 2010/11/05 07:20:54 dereine Exp $
+/**
+ * @defgroup views_field_handlers Views' field handlers
+ * @{
+ * Handlers to tell Views how to build and display fields.
+ *
+ */
+
+/**
+ * Base field handler that has no options and renders an unformatted field.
+ *
+ * Definition terms:
+ * - additional fields: An array of fields that should be added to the query
+ * for some purpose. The array is in the form of:
+ * array('identifier' => array('table' => tablename,
+ * 'field' => fieldname); as many fields as are necessary
+ * may be in this array.
+ * - click sortable: If TRUE, this field may be click sorted.
+ */
+class views_handler_field extends views_handler {
+ var $field_alias = 'unknown';
+ var $aliases = array();
+
+ /**
+ * Construct a new field handler.
+ */
+ function construct() {
+ parent::construct();
+
+ $this->additional_fields = array();
+ if (!empty($this->definition['additional fields'])) {
+ $this->additional_fields = $this->definition['additional fields'];
+ }
+
+ if (!isset($this->options['exclude'])) {
+ $this->options['exclude'] = '';
+ }
+ }
+
+ /**
+ * Determine if this field can allow advanced rendering.
+ *
+ * Fields can set this to FALSE if they do not wish to allow
+ * token based rewriting or link-making.
+ */
+ function allow_advanced_render() {
+ return TRUE;
+ }
+
+ function init(&$view, &$options) {
+ parent::init($view, $options);
+
+ $this->options += array(
+ 'exclude' => FALSE,
+ );
+ }
+
+ /**
+ * Called to add the field to a query.
+ */
+ function query() {
+ $this->ensure_my_table();
+ // Add the field.
+ $this->field_alias = $this->query->add_field($this->table_alias, $this->real_field);
+
+ $this->add_additional_fields();
+ }
+
+ /**
+ * Add 'additional' fields to the query.
+ *
+ * @param $fields
+ * An array of fields. The key is an identifier used to later find the
+ * field alias used. The value is either a string in which case it's
+ * assumed to be a field on this handler's table; or it's an array in the
+ * form of
+ * @code array('table' => $tablename, 'field' => $fieldname) @endcode
+ */
+ function add_additional_fields($fields = NULL) {
+ if (!isset($fields)) {
+ // notice check
+ if (empty($this->additional_fields)) {
+ return;
+ }
+ $fields = $this->additional_fields;
+ }
+ if (!empty($fields) && is_array($fields)) {
+ foreach ($fields as $identifier => $info) {
+ if (is_array($info)) {
+ if (isset($info['table'])) {
+ $table_alias = $this->query->ensure_table($info['table'], $this->relationship);
+ }
+ else {
+ $table_alias = $this->table_alias;
+ }
+
+ if (empty($table_alias)) {
+ debug(t('Handler @handler tried to add additional_field @identifier but @table could not be added!', array('@handler' => $this->definition['handler'], '@identifier' => $identifier, '@table' => $info['table'])));
+ $this->aliases[$identifier] = 'broken';
+ continue;
+ }
+
+ $params = array();
+ if (!empty($info['params'])) {
+ $params = $info['params'];
+ }
+
+ $this->aliases[$identifier] = $this->query->add_field($table_alias, $info['field'], NULL, $params);
+ }
+ else {
+ $this->aliases[$info] = $this->query->add_field($this->table_alias, $info);
+ }
+ }
+ }
+ }
+
+ /**
+ * Called to determine what to tell the clicksorter.
+ */
+ function click_sort($order) {
+ $this->query->add_orderby($this->table_alias, $this->real_field, $order, $this->field_alias);
+ }
+
+ /**
+ * Determine if this field is click sortable.
+ */
+ function click_sortable() {
+ return !empty($this->definition['click sortable']);
+ }
+
+ /**
+ * Get this field's label.
+ */
+ function label() {
+ if (!isset($this->options['label'])) {
+ return '';
+ }
+ return $this->options['label'];
+ }
+
+ /**
+ * Return DIV or SPAN based upon the field's element type.
+ */
+ function element_type() {
+ if (isset($this->definition['element type'])) {
+ return $this->definition['element type'];
+ }
+
+ return 'span';
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['label'] = array('default' => $this->definition['title'], 'translatable' => TRUE);
+ $options['exclude'] = array('default' => FALSE, 'bool' => TRUE);
+ $options['alter'] = array(
+ 'contains' => array(
+ 'alter_text' => array('default' => FALSE),
+ 'text' => array('default' => '', 'translatable' => TRUE),
+ 'make_link' => array('default' => FALSE),
+ 'path' => array('default' => '', 'translatable' => TRUE),
+ 'absolute' => array('default' => '', 'translatable' => FALSE),
+ 'alt' => array('default' => '', 'translatable' => TRUE),
+ 'link_class' => array('default' => ''),
+ 'prefix' => array('default' => '', 'translatable' => TRUE),
+ 'suffix' => array('default' => '', 'translatable' => TRUE),
+ 'target' => array('default' => '', 'translatable' => TRUE),
+ 'trim' => array('default' => FALSE),
+ 'max_length' => array('default' => ''),
+ 'word_boundary' => array('default' => TRUE),
+ 'ellipsis' => array('default' => TRUE),
+ 'strip_tags' => array('default' => FALSE),
+ 'html' => array('default' => FALSE),
+ ),
+ );
+ $options['empty'] = array('default' => '', 'translatable' => TRUE);
+ $options['hide_empty'] = array('default' => FALSE);
+ $options['empty_zero'] = array('default' => FALSE);
+
+ return $options;
+ }
+
+ /**
+ * Default options form that provides the label widget that all fields
+ * should have.
+ */
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ $form['label'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Label'),
+ '#default_value' => isset($this->options['label']) ? $this->options['label'] : '',
+ '#description' => t('The label for this field that will be displayed to end users if the style requires it.'),
+ );
+ $form['exclude'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Exclude from display'),
+ '#default_value' => $this->options['exclude'],
+ '#description' => t('Check this box to not display this field, but still load it in the view. Use this option to not show a grouping field in each record, or when doing advanced theming.'),
+ );
+
+ if ($this->allow_advanced_render()) {
+ $form['alter']['#tree'] = TRUE;
+ $form['alter']['alter_text'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Rewrite the output of this field'),
+ '#description' => t('If checked, you can alter the output of this field by specifying a string of text with replacement tokens that can use any existing field output.'),
+ '#default_value' => $this->options['alter']['alter_text'],
+ );
+
+ $form['alter']['text'] = array(
+ '#title' => t('Text'),
+ '#type' => 'textarea',
+ '#default_value' => $this->options['alter']['text'],
+ '#description' => t('The text to display for this field. You may include HTML. You may enter data from this view as per the "Replacement patterns" below.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-alter-text' => array(1)
+ ),
+ );
+
+ $form['alter']['make_link'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Output this field as a link'),
+ '#description' => t('If checked, this field will be made into a link. The destination must be given below.'),
+ '#default_value' => $this->options['alter']['make_link'],
+ );
+ $form['alter']['path'] = array(
+ '#title' => t('Link path'),
+ '#type' => 'textfield',
+ '#default_value' => $this->options['alter']['path'],
+ '#description' => t('The Drupal path or absolute URL for this link. You may enter data from this view as per the "Replacement patterns" below.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-make-link' => array(1)
+ ),
+ '#maxlength' => 255,
+ );
+ $form['alter']['absolute'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Use absolute path'),
+ '#default_value' => $this->options['alter']['absolute'],
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-make-link' => array(1)
+ ),
+ );
+
+ $form['alter']['link_class'] = array(
+ '#title' => t('Link class'),
+ '#type' => 'textfield',
+ '#default_value' => $this->options['alter']['link_class'],
+ '#description' => t('The CSS class to apply to the link.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-make-link' => array(1)
+ ),
+ );
+ $form['alter']['alt'] = array(
+ '#title' => t('Alt text'),
+ '#type' => 'textfield',
+ '#default_value' => $this->options['alter']['alt'],
+ '#description' => t('Text to place as "alt" text which most browsers display as a tooltip when hovering over the link.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-make-link' => array(1)
+ ),
+ );
+ $form['alter']['prefix'] = array(
+ '#title' => t('Prefix text'),
+ '#type' => 'textfield',
+ '#default_value' => $this->options['alter']['prefix'],
+ '#description' => t('Any text to display before this link. You may include HTML.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-make-link' => array(1)
+ ),
+ );
+ $form['alter']['suffix'] = array(
+ '#title' => t('Suffix text'),
+ '#type' => 'textfield',
+ '#default_value' => $this->options['alter']['suffix'],
+ '#description' => t('Any text to display after this link. You may include HTML.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-make-link' => array(1)
+ ),
+ );
+ $form['alter']['target'] = array(
+ '#title' => t('Target'),
+ '#type' => 'textfield',
+ '#default_value' => $this->options['alter']['target'],
+ '#description' => t("Target of the link, such as _blank, _parent or an iframe's name. This field is rarely used."),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-make-link' => array(1)
+ ),
+ );
+
+
+ // Get a list of the available fields and arguments for token replacement.
+ $options = array();
+ foreach ($this->view->display_handler->get_handlers('field') as $field => $handler) {
+ $options[t('Fields')]["[$field]"] = $handler->ui_name();
+ // We only use fields up to (and including) this one.
+ if ($field == $this->options['id']) {
+ break;
+ }
+ }
+ $count = 0; // This lets us prepare the key as we want it printed.
+ foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
+ $options[t('Arguments')]['%' . ++$count] = t('@argument title', array('@argument' => $handler->ui_name()));
+ $options[t('Arguments')]['!' . $count] = t('@argument input', array('@argument' => $handler->ui_name()));
+ }
+
+ $this->document_self_tokens($options[t('Fields')]);
+
+ // Default text.
+ $output = t('<p>You must add some additional fields to this display before using this field. These fields may be marked as <em>Exclude from display</em> if you prefer. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.</p>');
+ // We have some options, so make a list.
+ if (!empty($options)) {
+ $output = t('<p>The following tokens are available for this field. Note that due to rendering order, you cannot use fields that come after this field; if you need a field not listed here, rearrange your fields.</p>');
+ foreach (array_keys($options) as $type) {
+ if (!empty($options[$type])) {
+ $items = array();
+ foreach ($options[$type] as $key => $value) {
+ $items[] = $key . ' == ' . $value;
+ }
+ $output .= theme('item_list',
+ array(
+ 'items' => $items,
+ 'type' => $type
+ ));
+ }
+ }
+ }
+ // This construct uses 'hidden' and not markup because process doesn't
+ // run. It also has an extra div because the dependency wants to hide
+ // the parent in situations like this, so we need a second div to
+ // make this work.
+ $form['alter']['help'] = array(
+ '#type' => 'hidden',
+ '#id' => 'views-tokens-help',
+ '#prefix' => '<div><fieldset id="views-tokens-help"><legend>' . t('Replacement patterns') . '</legend>' . $output . '</fieldset></div>',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-make-link' => array(1),
+ 'edit-options-alter-alter-text' => array(1),
+ ),
+ );
+
+ $form['alter']['trim'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Trim this field to a maximum length'),
+ '#description' => t('If checked, this field be trimmed to a maximum length in characters.'),
+ '#default_value' => $this->options['alter']['trim'],
+ );
+
+ $form['alter']['max_length'] = array(
+ '#title' => t('Maximum length'),
+ '#type' => 'textfield',
+ '#default_value' => $this->options['alter']['max_length'],
+ '#description' => t('The maximum number of characters this field can be.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-trim' => array(1)
+ ),
+ );
+
+ $form['alter']['word_boundary'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Trim only on a word boundary'),
+ '#description' => t('If checked, this field be trimmed only on a word boundary. This is guaranteed to be the maximum characters stated or less. If there are no word boundaries this could trim a field to nothing.'),
+ '#default_value' => $this->options['alter']['word_boundary'],
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-trim' => array(1)
+ ),
+ );
+
+ $form['alter']['ellipsis'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Add an ellipsis'),
+ '#description' => t('If checked, a "..." will be added if a field was trimmed.'),
+ '#default_value' => $this->options['alter']['ellipsis'],
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-trim' => array(1)
+ ),
+ );
+
+ $form['alter']['html'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Field can contain HTML'),
+ '#description' => t('If checked, HTML corrector will be run to ensure tags are properly closed after trimming.'),
+ '#default_value' => $this->options['alter']['html'],
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-alter-trim' => array(1)
+ ),
+ );
+
+ $form['alter']['strip_tags'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Strip HTML tags'),
+ '#description' => t('If checked, all HTML tags will be stripped.'),
+ '#default_value' => $this->options['alter']['strip_tags'],
+ '#process' => array('ctools_dependent_process'),
+ );
+ }
+
+ $form['empty'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Empty text'),
+ '#default_value' => $this->options['empty'],
+ '#description' => t('If the field is empty, display this text instead.'),
+ );
+
+ $form['empty_zero'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Count the number 0 as empty'),
+ '#default_value' => $this->options['empty_zero'],
+ '#description' => t('If the field contains the number zero, display the empty text instead'),
+ );
+
+ $form['hide_empty'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Hide if empty'),
+ '#default_value' => $this->options['hide_empty'],
+ '#description' => t('Do not display anything for this field if it is empty. Note that the field label may still be displayed. Check style or row style settings to hide labels for empty fields.'),
+ );
+ }
+
+ /**
+ * Provide extra data to the administration form
+ */
+ function admin_summary() {
+ return $this->label();
+ }
+
+ /**
+ * Run before any fields are rendered.
+ *
+ * This gives the handlers some time to set up before any handler has
+ * been rendered.
+ *
+ * @param $values
+ * An array of all objects returned from the query.
+ */
+ function pre_render($values) { }
+
+ /**
+ * Render the field.
+ *
+ * @param $values
+ * The values retrieved from the database.
+ */
+ function render($values) {
+ $value = $values->{$this->field_alias};
+ return check_plain($value);
+ }
+
+ /**
+ * Render a field using advanced settings.
+ *
+ * This renders a field normally, then decides if render-as-link and
+ * text-replacement rendering is necessary.
+ */
+ function advanced_render($values) {
+ if ($this->allow_advanced_render() && method_exists($this, 'render_item')) {
+ $raw_items = $this->get_items($values);
+ }
+ else {
+ $this->last_render = $value = $this->render($values);
+ $this->original_value = $value;
+ }
+
+ if ($this->allow_advanced_render()) {
+ $tokens = NULL;
+ if (method_exists($this, 'render_item')) {
+ $items = array();
+ foreach ($raw_items as $count => $item) {
+ $this->last_render = $this->render_item($count, $item);
+ $this->original_value = $this->last_render;
+
+ $alter = $item + $this->options['alter'];
+ $items[] = $this->render_text($alter);
+ }
+
+ $value = $this->render_items($items);
+ }
+ else {
+ $value = $this->render_text($this->options['alter']);
+ }
+
+ // This happens here so that render_as_link can get the unaltered value of
+ // this field as a token rather than the altered value.
+ $this->last_render = $value;
+ }
+
+ if (empty($this->last_render)) {
+ if (($this->last_render !== 0 && $this->last_render !== '0') || !empty($this->options['empty_zero'])) {
+ $this->options['alter']['alter_text'] = 1;
+ $this->options['alter']['text'] = $this->options['empty'];
+ $this->last_render = $this->render_text($this->options['alter']);
+ }
+ }
+
+ return $this->last_render;
+ }
+
+ /**
+ * Perform an advanced text render for the item.
+ *
+ * This is separated out as some fields may render lists, and this allows
+ * each item to be handled individually.
+ */
+ function render_text($alter) {
+ $value = trim($this->last_render);
+
+ if (!empty($alter['alter_text']) && $alter['text'] !== '') {
+ $tokens = $this->get_render_tokens($alter);
+ $value = $this->render_altered($alter, $tokens);
+ }
+
+ if ($this->options['hide_empty'] && empty($value) && ($value !== 0 || $this->options['empty_zero'])) {
+ return '';
+ }
+
+ if (!empty($alter['strip_tags'])) {
+ $value = strip_tags($value);
+ }
+
+ if (!empty($alter['trim']) && !empty($alter['max_length'])) {
+ $value = $this->render_trim_text($alter, $value);
+ }
+
+ if (!empty($alter['make_link']) && !empty($alter['path'])) {
+ if (!isset($tokens)) {
+ $tokens = $this->get_render_tokens($alter);
+ }
+ $value = $this->render_as_link($alter, $value, $tokens);
+ }
+
+ return $value;
+ }
+
+ /**
+ * Render this field as altered text, from a fieldset set by the user.
+ */
+ function render_altered($alter, $tokens) {
+ // Filter this right away as our substitutions are already sanitized.
+ $value = filter_xss_admin($alter['text']);
+ $value = strtr($value, $tokens);
+
+ return $value;
+ }
+
+ /**
+ * Trim the field down to the specified length.
+ */
+ function render_trim_text($alter, $value) {
+ if (!empty($alter['strip_tags'])) {
+ // NOTE: It's possible that some external fields might override the
+ // element type so if someone from, say, CCK runs into a bug here,
+ // this may be why =)
+ $this->definition['element type'] = 'span';
+ }
+ return views_trim_text($alter, $value);
+ }
+
+ /**
+ * Render this field as a link, with the info from a fieldset set by
+ * the user.
+ */
+ function render_as_link($alter, $text, $tokens) {
+ $value = '';
+
+ if (!empty($alter['prefix'])) {
+ $value .= filter_xss_admin(strtr($alter['prefix'], $tokens));
+ }
+
+ $options = array(
+ 'html' => TRUE,
+ 'absolute' => !empty($alter['absolute']) ? TRUE : FALSE,
+ );
+
+ // $path will be run through check_url() by l() so we do not need to
+ // sanitize it ourselves.
+ $path = $alter['path'];
+
+ // html_entity_decode removes <front>, so check whether its different to front.
+ if ($path != '<front>') {
+ // Use strip tags as there should never be HTML in the path.
+ // However, we need to preserve special characters like " that
+ // were removed by check_plain().
+ $path = strip_tags(html_entity_decode(strtr($path, $tokens)));
+ }
+
+ // If the path is empty do not build a link around the given text and return
+ // it as is.
+ if (empty($path)) {
+ return $text;
+ }
+
+ // Parse the URL and move any query and fragment parameters out of the path.
+ $url = parse_url($path);
+ if (isset($url['query'])) {
+ $path = strtr($path, array('?' . $url['query'] => ''));
+ $options['query'] = drupal_get_query_array($url['query']);
+ }
+ if (isset($url['fragment'])) {
+ $path = strtr($path, array('#' . $url['fragment'] => ''));
+ // If the path is empty we want to have a fragment for the current site.
+ if ($path == '') {
+ $options['external'] = TRUE;
+ }
+ $options['fragment'] = $url['fragment'];
+ }
+
+ $alt = strtr($alter['alt'], $tokens);
+ // Set the title attribute of the link only if it improves accessibility
+ if ($alt && $alt != $text) {
+ $options['attributes']['title'] = $alt;
+ }
+
+ $class = strtr($alter['link_class'], $tokens);
+ if ($class) {
+ $options['attributes']['class'] = array($class);
+ }
+
+ $target = check_plain(trim(strtr($alter['target'],$tokens)));
+ if (!empty($target)) {
+ $options['attributes']['target'] = $target;
+ }
+
+ // If the query and fragment were programatically assigned overwrite any
+ // parsed values.
+ if (isset($alter['query'])) {
+ // Convert the query to a string, perform token replacement, and then
+ // convert back to an array form for l().
+ $options['query'] = drupal_http_build_query($alter['query']);
+ $options['query'] = strtr($alter['query'], $tokens);
+ $options['query'] = drupal_get_query_array($options['query']);
+ }
+ if (isset($alter['alias'])) {
+ // Alias is a boolean field, so no token.
+ $options['alias'] = $alter['alias'];
+ }
+ if (isset($alter['fragment'])) {
+ $options['fragment'] = strtr($alter['fragment'], $tokens);
+ }
+ if (isset($this->options['alter']['language'])) {
+ $options['language'] = $this->options['alter']['language'];
+ }
+
+ $value .= l($text, $path, $options);
+
+ if (!empty($alter['suffix'])) {
+ $value .= filter_xss_admin(strtr($alter['suffix'], $tokens));
+ }
+
+ return $value;
+ }
+
+ /**
+ * Get the 'render' tokens to use for advanced rendering.
+ *
+ * This runs through all of the fields and arguments that
+ * are available and gets their values. This will then be
+ * used in one giant str_replace().
+ */
+ function get_render_tokens($item) {
+ $tokens = array();
+ if (!empty($this->view->build_info['substitutions'])) {
+ $tokens = $this->view->build_info['substitutions'];
+ }
+ $count = 0;
+ foreach ($this->view->display_handler->get_handlers('argument') as $arg => $handler) {
+ $token = '%' . ++$count;
+ if (!isset($tokens[$token])) {
+ $tokens[$token] = '';
+ }
+
+ // Use strip tags as there should never be HTML in the path.
+ // However, we need to preserve special characters like " that
+ // were removed by check_plain().
+ $tokens['!' . $count] = isset($this->view->args[$count - 1]) ? strip_tags(html_entity_decode($this->view->args[$count - 1])) : '';
+ }
+
+ // Now add replacements for our fields.
+ foreach ($this->view->display_handler->get_handlers('field') as $field => $handler) {
+ if (isset($handler->last_render)) {
+ $tokens["[$field]"] = $handler->last_render;
+ }
+ else {
+ $tokens["[$field]"] = '';
+ }
+ $this->add_self_tokens($tokens, $item);
+
+ // We only use fields up to (and including) this one.
+ if ($field == $this->options['id']) {
+ break;
+ }
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Add any special tokens this field might use for itself.
+ *
+ * This method is intended to be overridden by items that generate
+ * fields as a list. For example, the field that displays all terms
+ * on a node might have tokens for the tid and the term.
+ *
+ * By convention, tokens should follow the format of [token-subtoken]
+ * where token is the field ID and subtoken is the field. If the
+ * field ID is terms, then the tokens might be [terms-tid] and [terms-name].
+ */
+ function add_self_tokens(&$tokens, $item) { }
+
+ /**
+ * Document any special tokens this field might use for itself.
+ *
+ * @see add_self_tokens() for details.
+ */
+ function document_self_tokens(&$tokens) { }
+
+ /**
+ * Call out to the theme() function, which probably just calls render() but
+ * allows sites to override output fairly easily.
+ */
+ function theme($values) {
+ return theme($this->theme_functions(),
+ array(
+ 'view' => $this->view,
+ 'field' => $this,
+ 'row' => $values
+ ));
+ }
+
+ function theme_functions() {
+ $themes = array();
+ $hook = 'views_view_field';
+
+ $display = $this->view->display[$this->view->current_display];
+
+ if (!empty($display)) {
+ $themes[] = $hook . '__' . $this->view->name . '__' . $display->id . '__' . $this->options['id'];
+ $themes[] = $hook . '__' . $this->view->name . '__' . $display->id;
+ $themes[] = $hook . '__' . $display->id . '__' . $this->options['id'];
+ $themes[] = $hook . '__' . $display->id;
+ if ($display->id != $display->display_plugin) {
+ $themes[] = $hook . '__' . $this->view->name . '__' . $display->display_plugin . '__' . $this->options['id'];
+ $themes[] = $hook . '__' . $this->view->name . '__' . $display->display_plugin;
+ $themes[] = $hook . '__' . $display->display_plugin . '__' . $this->options['id'];
+ $themes[] = $hook . '__' . $display->display_plugin;
+ }
+ }
+ $themes[] = $hook . '__' . $this->view->name . '__' . $this->options['id'];
+ $themes[] = $hook . '__' . $this->view->name;
+ $themes[] = $hook . '__' . $this->options['id'];
+ $themes[] = $hook;
+
+ return $themes;
+ }
+}
+
+/**
+ * A special handler to take the place of missing or broken handlers.
+ */
+class views_handler_field_broken extends views_handler_field {
+ function ui_name($short = FALSE) {
+ return t('Broken/missing handler');
+ }
+
+ function ensure_my_table() { /* No table to ensure! */ }
+ function query() { /* No query to run */ }
+ function options_form(&$form, &$form_state) {
+ $form['markup'] = array(
+ '#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
+ );
+ }
+
+ /**
+ * Determine if the handler is considered 'broken'
+ */
+ function broken() { return TRUE; }
+}
+
+/**
+ * Render a numeric value as a size.
+ */
+class views_handler_field_file_size extends views_handler_field {
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['file_size_display'] = array('default' => 'formatted');
+
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+ $form['file_size_display'] = array(
+ '#title' => t('File size display'),
+ '#type' => 'select',
+ '#options' => array(
+ 'formatted' => t('Formatted (in KB or MB)'),
+ 'bytes' => t('Raw bytes'),
+ ),
+ );
+ }
+
+ function render($values) {
+ if ($values->{$this->field_alias}) {
+ switch ($this->options['file_size_display']) {
+ case 'bytes':
+ return $values->{$this->field_alias};
+ case 'formatted':
+ default:
+ return format_size($values->{$this->field_alias});
+ }
+ }
+ else {
+ return '';
+ }
+ }
+}
+
+/**
+ * A handler to run a field through simple XSS filtering
+ */
+class views_handler_field_xss extends views_handler_field {
+ function render($values) {
+ $value = $values->{$this->field_alias};
+ return filter_xss($value);
+ }
+}
+
+/**
+ * @}
+ */
+
diff --git a/handlers/views_handler_field_boolean.inc b/handlers/views_handler_field_boolean.inc
new file mode 100644
index 0000000..ad2ee71
--- /dev/null
+++ b/handlers/views_handler_field_boolean.inc
@@ -0,0 +1,74 @@
+<?php
+// $Id: views_handler_field_boolean.inc,v 1.3.4.3 2010/08/26 09:41:55 dereine Exp $
+
+/**
+ * A handler to provide proper displays for booleans.
+ *
+ * Allows for display of true/false, yes/no, on/off.
+ *
+ * Definition terms:
+ * - output formats: An array where the first entry is displayed on boolean false
+ * and the second is displayed on boolean true. An example for sticky is:
+ * @code
+ * 'output formats' => array(
+ * 'sticky' => array('', t('Sticky')),
+ * ),
+ * @endcode
+ *
+ * @ingroup views_field_handlers
+ */
+class views_handler_field_boolean extends views_handler_field {
+ function option_definition() {
+ $options = parent::option_definition();
+ $options['type'] = array('default' => 'yes-no');
+ $options['not'] = array('definition bool' => 'reverse');
+
+ return $options;
+ }
+
+ function init(&$view, &$options) {
+ parent::init($view, $options);
+
+ $default_formats = array(
+ 'yes-no' => array(t('Yes'), t('No')),
+ 'true-false' => array(t('True'), t('False')),
+ 'on-off' => array(t('On'), t('Off')),
+ );
+ $output_formats = isset($this->definition['output formats']) ? $this->definition['output formats'] : array();
+ $this->formats = array_merge($default_formats, $output_formats);
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+ foreach ($this->formats as $key => $item) {
+ $options[$key] = implode('/', $item);
+ }
+
+ $form['type'] = array(
+ '#type' => 'select',
+ '#title' => t('Output format'),
+ '#options' => $options,
+ '#default_value' => $this->options['type'],
+ );
+ $form['not'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Reverse'),
+ '#description' => t('If checked, true will be displayed as false.'),
+ '#default_value' => $this->options['not'],
+ );
+ }
+
+ function render($values) {
+ $value = $values->{$this->field_alias};
+ if (!empty($this->options['not'])) {
+ $value = !$value;
+ }
+
+ if (isset($this->formats[$this->options['type']])) {
+ return $value ? $this->formats[$this->options['type']][0] : $this->formats[$this->options['type']][1];
+ }
+ else {
+ return $value ? $this->formats['yes-no'][0] : $this->formats['yes-no'][1];
+ }
+ }
+}
diff --git a/handlers/views_handler_field_counter.inc b/handlers/views_handler_field_counter.inc
new file mode 100644
index 0000000..4bf4c2a
--- /dev/null
+++ b/handlers/views_handler_field_counter.inc
@@ -0,0 +1,42 @@
+<?php
+// $Id: views_handler_field_counter.inc,v 1.3.4.4 2010/11/05 07:20:54 dereine Exp $
+
+class views_handler_field_counter extends views_handler_field {
+ function option_definition() {
+ $options = parent::option_definition();
+ $options['counter_start'] = array('default' => 1);
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ $form['counter_start'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Starting value'),
+ '#default_value' => $this->options['counter_start'],
+ '#description' => t('Specify the number the counter should start at.'),
+ //'#process' => array('ctools_dependent_process'),
+ '#size' => 2,
+ );
+ }
+
+ function query() {
+ // do nothing -- to override the parent query.
+ }
+
+ function render($values) {
+ // Note: 1 is subtracted from the counter start value below because the
+ // counter value is incremented by 1 at the end of this function.
+ $count = is_numeric($this->options['counter_start']) ? $this->options['counter_start'] - 1 : 0;
+ $pager = $this->view->query->pager;
+ // Get the base count of the pager.
+ if ($pager->use_pager()) {
+ $count += ($pager->get_items_per_page() * $pager->get_current_page() + $pager->get_offset());
+ }
+ // Add the counter for the current site.
+ $count += $this->view->row_index + 1;
+
+ return $count;
+ }
+}
diff --git a/handlers/views_handler_field_custom.inc b/handlers/views_handler_field_custom.inc
new file mode 100644
index 0000000..8b3a641
--- /dev/null
+++ b/handlers/views_handler_field_custom.inc
@@ -0,0 +1,35 @@
+<?php
+// $Id: views_handler_field_custom.inc,v 1.1.6.2 2010/11/05 07:20:54 dereine Exp $
+
+/**
+ * A handler to provide a field that is completely custom by the administrator.
+ *
+ * @ingroup views_field_handlers
+ */
+class views_handler_field_custom extends views_handler_field {
+ function query() {
+ // do nothing -- to override the parent query.
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ // Override the alter text option to always alter the text.
+ $options['alter']['contains']['alter_text'] = array('default' => TRUE);
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ // Remove the checkbox
+ unset($form['alter']['alter_text']);
+ unset($form['alter']['text']['#dependency']);
+ unset($form['alter']['text']['#process']);
+ }
+
+ function render($values) {
+ // Nothing to render.
+ return '';
+ }
+}
diff --git a/handlers/views_handler_field_date.inc b/handlers/views_handler_field_date.inc
new file mode 100644
index 0000000..3ce5b45
--- /dev/null
+++ b/handlers/views_handler_field_date.inc
@@ -0,0 +1,77 @@
+<?php
+// $Id: views_handler_field_date.inc,v 1.3.4.4 2010/11/05 07:20:54 dereine Exp $
+/**
+ * A handler to provide proper displays for dates.
+ *
+ * @ingroup views_field_handlers
+ */
+class views_handler_field_date extends views_handler_field {
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['date_format'] = array('default' => 'small');
+ $options['custom_date_format'] = array('default' => '');
+
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ $form['date_format'] = array(
+ '#type' => 'select',
+ '#title' => t('Date format'),
+ '#options' => array(
+ 'small' => format_date(REQUEST_TIME, 'small'),
+ 'medium' => format_date(REQUEST_TIME, 'medium'),
+ 'large' => format_date(REQUEST_TIME, 'large'),
+ 'custom' => t('Custom'),
+ 'raw time ago' => t('Time ago'),
+ 'time ago' => t('Time ago (with "ago" appended)'),
+ 'raw time span' => t('Time span (future dates start with - )'),
+ 'time span' => t('Time span (with "ago/hence" appended)'),
+ ),
+ '#default_value' => isset($this->options['date_format']) ? $this->options['date_format'] : 'small',
+ );
+ $form['custom_date_format'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Custom date format'),
+ '#description' => t('If "Custom", see <a href="http://us.php.net/manual/en/function.date.php" target="_blank">the PHP docs</a> for date formats. If "Time ago" this is the the number of different units to display, which defaults to two.'),
+ '#default_value' => isset($this->options['custom_date_format']) ? $this->options['custom_date_format'] : '',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array('edit-options-date-format' => array('custom', 'raw time ago', 'time ago', 'raw time span', 'time span')),
+ );
+ }
+
+ function render($values) {
+ $value = $values->{$this->field_alias};
+ $format = $this->options['date_format'];
+ if (in_array($format, array('custom', 'raw time ago', 'time ago', 'raw time span', 'time span'))) {
+ $custom_format = $this->options['custom_date_format'];
+ }
+
+ if (!$value) {
+ return theme('views_nodate');
+ }
+ else {
+ $time_diff = REQUEST_TIME - $value; // will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence)
+ switch ($format) {
+ case 'raw time ago':
+ return format_interval($time_diff, is_numeric($custom_format) ? $custom_format : 2);
+ case 'time ago':
+ return t('%time ago', array('%time' => format_interval($time_diff, is_numeric($custom_format) ? $custom_format : 2)));
+ case 'raw time span':
+ return ($time_diff < 0 ? '-' : '') . format_interval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2);
+ case 'time span':
+ return t(($time_diff < 0 ? '%time hence' : '%time ago'), array('%time' => format_interval(abs($time_diff), is_numeric($custom_format) ? $custom_format : 2)));
+ case 'custom':
+ if ($custom_format == 'r') {
+ return format_date($value, $format, $custom_format, null, 'en');
+ }
+ return format_date($value, $format, $custom_format);
+ default:
+ return format_date($value, $format);
+ }
+ }
+ }
+}
diff --git a/handlers/views_handler_field_group_by_numeric.inc b/handlers/views_handler_field_group_by_numeric.inc
new file mode 100644
index 0000000..3e2c211
--- /dev/null
+++ b/handlers/views_handler_field_group_by_numeric.inc
@@ -0,0 +1,44 @@
+<?php
+// $Id: views_handler_field_group_by_numeric.inc,v 1.1.4.6 2010/11/07 11:36:59 dereine Exp $
+
+/**
+ * Handler for GROUP BY on simple numeric fields.
+ */
+class views_handler_field_group_by_numeric extends views_handler_field_numeric {
+ function init(&$view, &$options) {
+ parent::init($view, $options);
+
+ // Initialize the original handler.
+ $this->handler = views_get_handler($options['table'], $options['field'], 'field');
+ $this->handler->init($view, $options);
+ }
+
+ /**
+ * Called to add the field to a query.
+ */
+ function query() {
+ $this->ensure_my_table();
+ // Add the field, taking care of any aggregation that may affect it.
+ $params = array(
+ 'function' => $this->options['group_type'],
+ );
+
+ $this->field_alias = $this->query->add_field($this->table_alias, $this->real_field, NULL, $params);
+ $this->add_additional_fields();
+ }
+
+ /**
+ * Called to determine what to tell the clicksorter.
+ */
+ function click_sort($order) {
+ $params = array(
+ 'function' => $this->options['group_type'],
+ );
+
+ $this->query->add_orderby($this->table, $this->field, $order, $this->field_alias, $params);
+ }
+
+ function ui_name($short = FALSE) {
+ return $this->get_field(parent::ui_name($short));
+ }
+}
diff --git a/handlers/views_handler_field_markup.inc b/handlers/views_handler_field_markup.inc
new file mode 100644
index 0000000..076de98
--- /dev/null
+++ b/handlers/views_handler_field_markup.inc
@@ -0,0 +1,46 @@
+<?php
+// $Id: views_handler_field_markup.inc,v 1.3.6.4 2010/10/26 20:26:37 dereine Exp $
+
+/**
+ * A handler to run a field through check_markup, using a companion
+ * format field.
+ *
+ * - format: (REQUIRED) Either a string format id to use for this field or an
+ * array('field' => {$field}) where $field is the field in this table
+ * used to control the format such as the 'format' field in the node,
+ * which goes with the 'body' field.
+ *
+ * @ingroup views_field_handlers
+ */
+class views_handler_field_markup extends views_handler_field {
+ /**
+ * Constructor; calls to base object constructor.
+ */
+ function construct() {
+ parent::construct();
+
+ $this->format = $this->definition['format'];
+
+ $this->additional_fields = array();
+ if (is_array($this->format)) {
+ $this->additional_fields['format'] = $this->format;
+ }
+ }
+
+ function render($values) {
+ $value = $values->{$this->field_alias};
+ $format = is_array($this->format) ? $values->{$this->aliases['format']} : $this->format;
+ if ($value) {
+ $value = str_replace('<!--break-->', '', $value);
+ return check_markup($value, $format, '');
+ }
+ }
+
+ function element_type() {
+ if (isset($this->definition['element type'])) {
+ return $this->definition['element type'];
+ }
+
+ return 'div';
+ }
+}
diff --git a/handlers/views_handler_field_math.inc b/handlers/views_handler_field_math.inc
new file mode 100644
index 0000000..d5200c3
--- /dev/null
+++ b/handlers/views_handler_field_math.inc
@@ -0,0 +1,74 @@
+<?php
+// $Id: views_handler_field_math.inc,v 1.1.2.3 2010/11/05 07:20:54 dereine Exp $
+/**
+ * Render a mathematical expression as a numeric value
+ *
+ * Definition terms:
+ * - float: If true this field contains a decimal value. If unset this field
+ * will be assumed to be integer.
+ *
+ * @ingroup views_field_handlers
+ */
+class views_handler_field_math extends views_handler_field_numeric {
+ function option_definition() {
+ $options = parent::option_definition();
+ $options['expression'] = array('default' => '');
+
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ $form['expression'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Expression'),
+ '#description' => t('Enter mathematical expressions such as 2 + 2 or sqrt(5). You my assign variables and create mathematical functions and evaluate them. Use the ; to separate these. For example: f(x) = x + 2; f(2).'),
+ '#default_value' => $this->options['expression'],
+ );
+
+ // Create a place for the help
+ $form['expression_help'] = array();
+ parent::options_form($form, $form_state);
+
+ // Then move the existing help:
+ $form['expression_help'] = $form['alter']['help'];
+ unset($form['expression_help']['#dependency']);
+ unset($form['expression_help']['#process']);
+ unset($form['alter']['help']);
+ }
+
+ function render($values) {
+ ctools_include('math-expr');
+ $value = strtr($this->options['expression'], $this->get_render_tokens(array()));
+ $expressions = explode(';', $value);
+ $math = new ctools_math_expr;
+ foreach ($expressions as $expression) {
+ if ($expression !== '') {
+ $value = $math->evaluate($expression);
+ }
+ }
+
+ // The rest is directly from views_handler_field_numeric but because it
+ // does not allow the value to be passed in, it is copied.
+ if (!empty($this->options['set_precision'])) {
+ $value = number_format($value, $this->options['precision'], $this->options['decimal'], $this->options['separator']);
+ }
+ else {
+ $remainder = abs($value) - intval(abs($value));
+ $value = $value > 0 ? floor($value) : ceil($value);
+ $value = number_format($value, 0, '', $this->options['separator']);
+ if ($remainder) {
+ // The substr may not be locale safe.
+ $value .= $this->options['decimal'] . substr($remainder, 2);
+ }
+ }
+
+ // Check to see if hiding should happen before adding prefix and suffix.
+ if ($this->options['hide_empty'] && empty($value) && ($value !== 0 || $this->options['empty_zero'])) {
+ return '';
+ }
+
+ return check_plain($this->options['prefix'] . $value . $this->options['suffix']);
+ }
+
+ function query() { }
+}
diff --git a/handlers/views_handler_field_numeric.inc b/handlers/views_handler_field_numeric.inc
new file mode 100644
index 0000000..a9ccb61
--- /dev/null
+++ b/handlers/views_handler_field_numeric.inc
@@ -0,0 +1,126 @@
+<?php
+// $Id: views_handler_field_numeric.inc,v 1.6.4.4 2010/11/05 07:20:54 dereine Exp $
+/**
+ * Render a field as a numeric value
+ *
+ * Definition terms:
+ * - float: If true this field contains a decimal value. If unset this field
+ * will be assumed to be integer.
+ *
+ * @ingroup views_field_handlers
+ */
+class views_handler_field_numeric extends views_handler_field {
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['set_precision'] = array('default' => FALSE);
+ $options['precision'] = array('default' => 0);
+ $options['decimal'] = array('default' => '.', 'translatable' => TRUE);
+ $options['separator'] = array('default' => ',', 'translatable' => TRUE);
+ $options['format_plural'] = array('default' => FALSE);
+ $options['format_plural_singular'] = array('default' => '1');
+ $options['format_plural_plural'] = array('default' => '@count');
+ $options['prefix'] = array('default' => '', 'translatable' => TRUE);
+ $options['suffix'] = array('default' => '', 'translatable' => TRUE);
+
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ if (!empty($this->definition['float'])) {
+ $form['set_precision'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Round'),
+ '#description' => t('If checked, the number will be rounded.'),
+ '#default_value' => $this->options['set_precision'],
+ );
+ $form['precision'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Precision'),
+ '#default_value' => $this->options['precision'],
+ '#description' => t('Specify how many digits to print after the decimal point.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array('edit-options-set-precision' => array(TRUE)),
+ '#size' => 2,
+ );
+ $form['decimal'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Decimal point'),
+ '#default_value' => $this->options['decimal'],
+ '#description' => t('What single character to use as a decimal point.'),
+ '#size' => 2,
+ );
+ }
+ $form['separator'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Thousands separator'),
+ '#default_value' => $this->options['separator'],
+ '#description' => t('What single character to use as the thousands separator.'),
+ '#size' => 2,
+ );
+ $form['format_plural'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Format plural'),
+ '#description' => t('If checked, special handling will be used for plurality.'),
+ '#default_value' => $this->options['format_plural'],
+ );
+ $form['format_plural_singular'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Singular form'),
+ '#default_value' => $this->options['format_plural_singular'],
+ '#description' => t('Text to use for the singular form.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array('edit-options-format-plural' => array(TRUE)),
+ );
+ $form['format_plural_plural'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Plural form'),
+ '#default_value' => $this->options['format_plural_plural'],
+ '#description' => t('Text to use for the plural form, @count will be replaced with the value.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array('edit-options-format-plural' => array(TRUE)),
+ );
+ $form['prefix'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Prefix'),
+ '#default_value' => $this->options['prefix'],
+ '#description' => t('Text to put before the number, such as currency symbol.'),
+ );
+ $form['suffix'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Suffix'),
+ '#default_value' => $this->options['suffix'],
+ '#description' => t('Text to put after the number, such as currency symbol.'),
+ );
+ }
+
+ function render($values) {
+ $value = $values->{$this->field_alias};
+ if (!empty($this->options['set_precision'])) {
+ $value = number_format($value, $this->options['precision'], $this->options['decimal'], $this->options['separator']);
+ }
+ else {
+ $remainder = abs($value) - intval(abs($value));
+ $value = $value > 0 ? floor($value) : ceil($value);
+ $value = number_format($value, 0, '', $this->options['separator']);
+ if ($remainder) {
+ // The substr may not be locale safe.
+ $value .= $this->options['decimal'] . substr($remainder, 2);
+ }
+ }
+
+ // Check to see if hiding should happen before adding prefix and suffix.
+ if ($this->options['hide_empty'] && empty($value) && ($value !== 0 || $this->options['empty_zero'])) {
+ return '';
+ }
+
+ // Should we format as a plural.
+ if (!empty($this->options['format_plural'])) {
+ $value = format_plural($value, $this->options['format_plural_singular'], $this->options['format_plural_plural']);
+ }
+
+ return check_plain($this->options['prefix'] . $value . $this->options['suffix']);
+ }
+}
diff --git a/handlers/views_handler_field_prerender_list.inc b/handlers/views_handler_field_prerender_list.inc
new file mode 100644
index 0000000..a8869ad
--- /dev/null
+++ b/handlers/views_handler_field_prerender_list.inc
@@ -0,0 +1,122 @@
+<?php
+// $Id: views_handler_field_prerender_list.inc,v 1.3.4.4 2010/11/05 07:20:54 dereine Exp $
+
+/**
+ * Field handler to provide a list of items.
+ *
+ * The items are expected to be loaded by a child object during pre_render,
+ * and 'my field' is expected to be the pointer to the items in the list.
+ *
+ * Items to render should be in a list in $this->items
+ *
+ * @ingroup views_field_handlers
+ */
+class views_handler_field_prerender_list extends views_handler_field {
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['type'] = array('default' => 'separator');
+ $options['separator'] = array('default' => ', ');
+
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+ $form['type'] = array(
+ '#type' => 'radios',
+ '#title' => t('Display type'),
+ '#options' => array(
+ 'ul' => t('Unordered list'),
+ 'ol' => t('Ordered list'),
+ 'separator' => t('Simple separator'),
+ ),
+ '#default_value' => $this->options['type'],
+ );
+
+ $form['separator'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Separator'),
+ '#default_value' => $this->options['separator'],
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array('radio:options[type]' => array('separator')),
+ );
+ }
+
+ /**
+ * Render the field.
+ *
+ * This function is deprecated, but left in for older systems that have not
+ * yet or won't update their prerender list fields. If a render_item method
+ * exists, this will not get used by advanced_render.
+ */
+ function render($values) {
+ $field = $values->{$this->field_alias};
+ if (!empty($this->items[$field])) {
+ if ($this->options['type'] == 'separator') {
+ return implode(check_plain($this->options['separator']), $this->items[$field]);
+ }
+ else {
+ return theme('item_list',
+ array(
+ 'items' => $this->items[$field],
+ 'title' => NULL,
+ 'type' => $this->options['type']
+ ));
+ }
+ }
+ }
+
+ /**
+ * Render all items in this field together.
+ *
+ * When using advanced render, each possible item in the list is rendered
+ * individually. Then the items are all pasted together.
+ */
+ function render_items($items) {
+ if (!empty($items)) {
+ if ($this->options['type'] == 'separator') {
+ return implode(check_plain($this->options['separator']), $items);
+ }
+ else {
+ return theme('item_list',
+ array(
+ 'items' => $items,
+ 'title' => NULL,
+ 'type' => $this->options['type']
+ ));
+ }
+ }
+ }
+
+ /**
+ * Return an array of items for the field.
+ *
+ * Items should be stored in the result array, if possible, as an array
+ * with 'value' as the actual displayable value of the item, plus
+ * any items that might be found in the 'alter' options array for
+ * creating links, such as 'path', 'fragment', 'query' etc, such a thing
+ * is to be made. Additionally, items that might be turned into tokens
+ * should also be in this array.
+ */
+ function get_items($values) {
+ $field = $values->{$this->field_alias};
+ if (!empty($this->items[$field])) {
+ return $this->items[$field];
+ }
+
+ return array();
+ }
+
+ /**
+ * Determine if advanced rendering is allowed.
+ *
+ * By default, advanced rendering will NOT be allowed if the class
+ * inheriting from this does not implement a 'render_items' method.
+ */
+ function allow_advanced_render() {
+ // Note that the advanced render bits also use the presence of
+ // this method to determine if it needs to render items as a list.
+ return method_exists($this, 'render_item');
+ }
+}
diff --git a/handlers/views_handler_field_url.inc b/handlers/views_handler_field_url.inc
new file mode 100644
index 0000000..dc3cd36
--- /dev/null
+++ b/handlers/views_handler_field_url.inc
@@ -0,0 +1,39 @@
+<?php
+// $Id: views_handler_field_url.inc,v 1.1 2008/09/03 19:21:28 merlinofchaos Exp $
+
+/**
+ * Field handler to provide simple renderer that turns a URL into a clickable link.
+ *
+ * @ingroup views_field_handlers
+ */
+class views_handler_field_url extends views_handler_field {
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['display_as_link'] = array('default' => TRUE);
+
+ return $options;
+ }
+
+ /**
+ * Provide link to the page being visited.
+ */
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+ $form['display_as_link'] = array(
+ '#title' => t('Display as link'),
+ '#type' => 'checkbox',
+ '#default_value' => !empty($this->options['display_as_link']),
+ );
+ }
+
+ function render($values) {
+ $value = $values->{$this->field_alias};
+ if (!empty($this->options['display_as_link'])) {
+ return l(check_plain($value), $value, array('html' => TRUE));
+ }
+ else {
+ return $value;
+ }
+ }
+}
diff --git a/handlers/views_handler_filter.inc b/handlers/views_handler_filter.inc
new file mode 100644
index 0000000..ec453f3
--- /dev/null
+++ b/handlers/views_handler_filter.inc
@@ -0,0 +1,533 @@
+<?php
+// $Id: views_handler_filter.inc,v 1.10.4.11 2010/11/05 07:20:54 dereine Exp $
+/**
+ * @defgroup views_filter_handlers Views' filter handlers
+ * @{
+ * Handlers to tell Views how to filter queries.
+ *
+ * Definition items:
+ * - allow empty: If true, the 'IS NULL' and 'IS NOT NULL' operators become
+ * available as standard operators.
+ * -
+ */
+
+/**
+ * Base class for filters.
+ */
+class views_handler_filter extends views_handler {
+ /**
+ * Provide some extra help to get the operator/value easier to use.
+ *
+ * This likely has to be overridden by filters which are more complex
+ * than simple operator/value.
+ */
+ function init(&$view, &$options) {
+ parent::init($view, $options);
+
+ $this->operator = $this->options['operator'];
+ $this->value = $this->options['value'];
+
+ // Compatibility: Set use_operator to true if the old way of using
+ // the operator is set and use_operator is NULL (was never set).
+ if (!empty($options['exposed']) && !empty($options['expose']['operator']) && !isset($options['expose']['use_operator'])) {
+ $this->options['expose']['use_operator'] = TRUE;
+ }
+
+ // If there are relationships in the view, allow empty should be true
+ // so that we can do IS NULL checks on items. Not all filters respect
+ // allow empty, but string and numeric do and that covers enough.
+ if ($this->view->display_handler->get_option('relationships')) {
+ $this->definition['allow empty'] = TRUE;
+ }
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['operator'] = array('default' => '=');
+ $options['value'] = array('default' => '');
+ $options['group'] = array('default' => '0');
+ $options['exposed'] = array('default' => FALSE);
+ $options['expose'] = array(
+ 'contains' => array(
+ 'operator' => array('default' => FALSE),
+ 'label' => array('default' => '', 'translatable' => TRUE),
+ 'use_operator' => array('default' => 0),
+ 'operator' => array('default' => ''),
+ 'identifier' => array('default' => ''),
+ 'optional' => array('default' => 1),
+ 'remember' => array('default' => 0),
+ 'single' => array('default' => 1),
+ ),
+ );
+
+ return $options;
+ }
+
+ /**
+ * Display the filter on the administrative summary
+ */
+ function admin_summary() {
+ return check_plain((string) $this->operator) . ' ' . check_plain((string) $this->value);
+ }
+
+ /**
+ * Determine if a filter can be exposed.
+ */
+ function can_expose() { return TRUE; }
+
+ /**
+ * Provide the basic form which calls through to subforms.
+ * If overridden, it is best to call through to the parent,
+ * or to at least make sure all of the functions in this form
+ * are called.
+ */
+ function options_form(&$form, &$form_state) {
+ if ($this->can_expose()) {
+ $this->show_expose_button($form, $form_state);
+ }
+ $form['op_val_start'] = array('#markup' => '<div class="clearfix">');
+ $this->show_operator_form($form, $form_state);
+ $this->show_value_form($form, $form_state);
+ $form['op_val_end'] = array('#markup' => '</div>');
+ if ($this->can_expose()) {
+ $this->show_expose_form($form, $form_state);
+ }
+ }
+
+ /**
+ * Simple validate handler
+ */
+ function options_validate(&$form, &$form_state) {
+ $this->operator_validate($form, $form_state);
+ $this->value_validate($form, $form_state);
+ if (!empty($this->options['exposed'])) {
+ $this->expose_validate($form, $form_state);
+ }
+
+ }
+
+ /**
+ * Simple submit handler
+ */
+ function options_submit(&$form, &$form_state) {
+ unset($form_state['values']['expose_button']); // don't store this.
+ $this->operator_submit($form, $form_state);
+ $this->value_submit($form, $form_state);
+ if (!empty($this->options['exposed'])) {
+ $this->expose_submit($form, $form_state);
+ }
+ }
+
+ /**
+ * Shortcut to display the operator form.
+ */
+ function show_operator_form(&$form, &$form_state) {
+ $this->operator_form($form, $form_state);
+ $form['operator']['#prefix'] = '<div class="views-left-30">';
+ $form['operator']['#suffix'] = '</div>';
+ }
+
+ /**
+ * Provide a form for setting the operator.
+ *
+ * This may be overridden by child classes, and it must
+ * define $form['operator'];
+ */
+ function operator_form(&$form, &$form_state) {
+ $options = $this->operator_options();
+ if (!empty($options)) {
+ $form['operator'] = array(
+ '#type' => count($options) < 10 ? 'radios' : 'select',
+ '#title' => t('Operator'),
+ '#default_value' => $this->operator,
+ '#options' => $options,
+ );
+ }
+ }
+
+ /**
+ * Provide a list of options for the default operator form.
+ * Should be overridden by classes that don't override operator_form
+ */
+ function operator_options() { return array(); }
+
+ /**
+ * Validate the operator form.
+ */
+ function operator_validate($form, &$form_state) { }
+
+ /**
+ * Perform any necessary changes to the form values prior to storage.
+ * There is no need for this function to actually store the data.
+ */
+ function operator_submit($form, &$form_state) { }
+
+ /**
+ * Shortcut to display the value form.
+ */
+ function show_value_form(&$form, &$form_state) {
+ $this->value_form($form, $form_state);
+ if (empty($this->no_operator)) {
+ $form['value']['#prefix'] = '<div class="views-right-70">' . (isset($form['value']['#prefix']) ? $form['value']['#prefix'] : '');
+ $form['value']['#suffix'] = (isset($form['value']['#suffix']) ? $form['value']['#suffix'] : '') . '</div>';
+ }
+ }
+
+ /**
+ * Provide a form for setting options.
+ *
+ * This should be overridden by all child classes and it must
+ * define $form['value']
+ */
+ function value_form(&$form, &$form_state) { $form['value'] = array(); }
+
+ /**
+ * Validate the options form.
+ */
+ function value_validate($form, &$form_state) { }
+
+ /**
+ * Perform any necessary changes to the form values prior to storage.
+ * There is no need for this function to actually store the data.
+ */
+ function value_submit($form, &$form_state) { }
+
+ /**
+ * Handle the 'left' side fo the exposed options form.
+ */
+ function expose_form_left(&$form, &$form_state) {
+ if (!empty($form['operator']['#type'])) {
+ $form['expose']['use_operator'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Unlock operator'),
+ '#description' => t('When checked, the operator will be exposed to the user'),
+ '#default_value' => !empty($this->options['expose']['use_operator']),
+ );
+ $form['expose']['operator'] = array(
+ '#type' => 'textfield',
+ '#default_value' => $this->options['expose']['operator'],
+ '#title' => t('Operator identifier'),
+ '#size' => 40,
+ '#description' => t('This will appear in the URL after the ? to identify this operator.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-expose-use-operator' => array(1)
+ ),
+ );
+ }
+ else {
+ $form['expose']['operator'] = array(
+ '#type' => 'value',
+ '#value' => '',
+ );
+ }
+
+ $form['expose']['identifier'] = array(
+ '#type' => 'textfield',
+ '#default_value' => $this->options['expose']['identifier'],
+ '#title' => t('Filter identifier'),
+ '#size' => 40,
+ '#description' => t('This will appear in the URL after the ? to identify this filter. Cannot be blank.'),
+ );
+ $form['expose']['label'] = array(
+ '#type' => 'textfield',
+ '#default_value' => $this->options['expose']['label'],
+ '#title' => t('Label'),
+ '#size' => 40,
+ );
+ }
+
+ /**
+ * Handle the 'right' side fo the exposed options form.
+ */
+ function expose_form_right(&$form, &$form_state) {
+ $form['expose']['optional'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Optional'),
+ '#description' => t('This exposed filter is optional and will have added options to allow it not to be set.'),
+ '#default_value' => $this->options['expose']['optional'],
+ );
+ if (empty($this->no_single)) {
+ $form['expose']['single'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Force single'),
+ '#description' => t('Force this exposed filter to accept only one option.'),
+ '#default_value' => $this->options['expose']['single'],
+ );
+ }
+ $form['expose']['remember'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Remember'),
+ '#description' => t('Remember the last setting the user gave this filter.'),
+ '#default_value' => $this->options['expose']['remember'],
+ );
+ }
+
+ /**
+ * Validate the options form.
+ */
+ function expose_validate($form, &$form_state) {
+ if (empty($this->options['expose']['identifier'])) {
+ if (empty($form_state['values']['options']['expose']['identifier'])) {
+ form_error($form['expose']['identifier'], t('The identifier is required if the filter is exposed.'));
+ }
+ }
+
+ if (!empty($form_state['values']['options']['expose']['identifier']) && $form_state['values']['options']['expose']['identifier'] == 'value') {
+ form_error($form['expose']['identifier'], t('This identifier is not allowed.'));
+ }
+
+ if (!$this->view->display_handler->is_identifier_unique($form_state['id'], $form_state['values']['options']['expose']['identifier'])) {
+ form_error($form['expose']['identifier'], t('This identifier is used by another handler.'));
+ }
+ }
+
+ /**
+ * Provide default options for exposed filters.
+ */
+ function expose_options() {
+ $this->options['expose'] = array(
+ 'use_operator' => FALSE,
+ 'operator' => $this->options['id'] . '_op',
+ 'identifier' => $this->options['id'],
+ 'label' => $this->ui_name(),
+ 'remember' => FALSE,
+ 'single' => TRUE,
+ 'optional' => TRUE,
+ );
+ }
+
+ /**
+ * Render our chunk of the exposed filter form when selecting
+ *
+ * You can override this if it doesn't do what you expect.
+ */
+ function exposed_form(&$form, &$form_state) {
+ if (empty($this->options['exposed'])) {
+ return;
+ }
+
+ // Build the exposed form, when its based on an operator.
+ if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator'])) {
+ $operator = $this->options['expose']['operator'];
+ $this->operator_form($form, $form_state);
+ $form[$operator] = $form['operator'];
+
+ if (isset($form[$operator]['#title'])) {
+ unset($form[$operator]['#title']);
+ }
+
+ $this->exposed_translate($form[$operator], 'operator');
+
+ unset($form['operator']);
+ }
+
+ // Build the form and set the value based on the identifier.
+ if (!empty($this->options['expose']['identifier'])) {
+ $value = $this->options['expose']['identifier'];
+ $this->value_form($form, $form_state);
+ $form[$value] = $form['value'];
+
+ if (isset($form[$value]['#title']) && !empty($form[$value]['#type']) && $form[$value]['#type'] != 'checkbox') {
+ unset($form[$value]['#title']);
+ }
+
+ $this->exposed_translate($form[$value], 'value');
+
+ if (!empty($form['#type']) && ($form['#type'] == 'checkboxes' || ($form['#type'] == 'select' && !empty($form['#multiple'])))) {
+ unset($form[$value]['#default_value']);
+ }
+
+ if (!empty($form['#type']) && $form['#type'] == 'select' && empty($form['#multiple'])) {
+ $form[$value]['#default_value'] = 'All';
+ }
+
+ if ($value != 'value') {
+ unset($form['value']);
+ }
+ }
+ }
+
+ /**
+ * Make some translations to a form item to make it more suitable to
+ * exposing.
+ */
+ function exposed_translate(&$form, $type) {
+ if (!isset($form['#type'])) {
+ return;
+ }
+
+ if ($form['#type'] == 'radios') {
+ $form['#type'] = 'select';
+ }
+ // Checkboxes don't work so well in exposed forms due to GET conversions.
+ if ($form['#type'] == 'checkboxes') {
+ if (empty($form['#no_convert']) || !empty($this->options['expose']['single'])) {
+ $form['#type'] = 'select';
+ }
+ if (empty($this->options['expose']['single'])) {
+ $form['#multiple'] = TRUE;
+ }
+ }
+ if (!empty($this->options['expose']['single']) && isset($form['#multiple'])) {
+ unset($form['#multiple']);
+ $form['#size'] = NULL;
+ }
+
+ if ($type == 'value' && !empty($this->options['expose']['optional']) && $form['#type'] == 'select' && empty($form['#multiple'])) {
+ $any_label = variable_get('views_exposed_filter_any_label', 'old_any') == 'old_any' ? t('<Any>') : t('- Any -');
+ $form['#options'] = array('All' => $any_label) + $form['#options'];
+ $form['#default_value'] = 'All';
+ }
+ }
+
+ /**
+ * Tell the renderer about our exposed form. This only needs to be
+ * overridden for particularly complex forms. And maybe not even then.
+ *
+ * @return
+ * An array with the following keys:
+ * - operator: The $form key of the operator. Set to NULL if no operator.
+ * - value: The $form key of the value. Set to NULL if no value.
+ * - label: The label to use for this piece.
+ */
+ function exposed_info() {
+ if (empty($this->options['exposed'])) {
+ return;
+ }
+
+ return array(
+ 'operator' => $this->options['expose']['operator'],
+ 'value' => $this->options['expose']['identifier'],
+ 'label' => $this->options['expose']['label'],
+ );
+ }
+
+ /**
+ * Check to see if input from the exposed filters should change
+ * the behavior of this filter.
+ */
+ function accept_exposed_input($input) {
+ if (empty($this->options['exposed'])) {
+ return TRUE;
+ }
+
+
+ if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator']) && isset($input[$this->options['expose']['operator']])) {
+ $this->operator = $input[$this->options['expose']['operator']];
+ }
+
+ if (!empty($this->options['expose']['identifier'])) {
+ $value = $input[$this->options['expose']['identifier']];
+
+ // Various ways to check for the absence of optional input.
+ if (!empty($this->options['expose']['optional'])) {
+ if ($value == 'All' || $value === array()) {
+ return FALSE;
+ }
+
+ if (!empty($this->no_single) && $value === '') {
+ return FALSE;
+ }
+ }
+
+
+ if (isset($value)) {
+ $this->value = $value;
+ if (empty($this->no_single) && !empty($this->options['expose']['single'])) {
+ $this->value = array($value);
+ }
+ }
+ else {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ }
+
+ function store_exposed_input($input, $status) {
+ if (empty($this->options['exposed']) || empty($this->options['expose']['identifier'])) {
+ return TRUE;
+ }
+
+ if (empty($this->options['expose']['remember'])) {
+ return;
+ }
+
+ // Figure out which display id is responsible for the filters, so we
+ // know where to look for session stored values.
+ $display_id = ($this->view->display_handler->is_defaulted('filters')) ? 'default' : $this->view->current_display;
+
+ // shortcut test.
+ $operator = !empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator']);
+
+ // false means that we got a setting that means to recuse ourselves,
+ // so we should erase whatever happened to be there.
+ if (!$status && isset($_SESSION['views'][$this->view->name][$display_id])) {
+ $session = &$_SESSION['views'][$this->view->name][$display_id];
+ if ($operator && isset($session[$this->options['expose']['operator']])) {
+ unset($session[$this->options['expose']['operator']]);
+ }
+
+ if (isset($session[$this->options['expose']['identifier']])) {
+ unset($session[$this->options['expose']['identifier']]);
+ }
+ }
+
+ if ($status) {
+ if (!isset($_SESSION['views'][$this->view->name][$display_id])) {
+ $_SESSION['views'][$this->view->name][$display_id] = array();
+ }
+
+ $session = &$_SESSION['views'][$this->view->name][$display_id];
+
+ if ($operator && isset($input[$this->options['expose']['operator']])) {
+ $session[$this->options['expose']['operator']] = $input[$this->options['expose']['operator']];
+ }
+
+ $session[$this->options['expose']['identifier']] = $input[$this->options['expose']['identifier']];
+ }
+ }
+
+ /**
+ * Add this filter to the query.
+ *
+ * Due to the nature of fapi, the value and the operator have an unintended
+ * level of indirection. You will find them in $this->operator
+ * and $this->value respectively.
+ */
+ function query() {
+ $this->ensure_my_table();
+ $this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field", $this->value, $this->operator);
+ }
+}
+
+
+/**
+ * A special handler to take the place of missing or broken handlers.
+ */
+class views_handler_filter_broken extends views_handler_filter {
+ function ui_name($short = FALSE) {
+ return t('Broken/missing handler');
+ }
+
+ function ensure_my_table() { /* No table to ensure! */ }
+ function query() { /* No query to run */ }
+ function options_form(&$form, &$form_state) {
+ $form['markup'] = array(
+ '#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
+ );
+ }
+
+ /**
+ * Determine if the handler is considered 'broken'
+ */
+ function broken() { return TRUE; }
+}
+
+
+/**
+ * @}
+ */
diff --git a/handlers/views_handler_filter_boolean_operator.inc b/handlers/views_handler_filter_boolean_operator.inc
new file mode 100644
index 0000000..d7dcebb
--- /dev/null
+++ b/handlers/views_handler_filter_boolean_operator.inc
@@ -0,0 +1,153 @@
+<?php
+// $Id: views_handler_filter_boolean_operator.inc,v 1.6.4.5 2010/08/26 09:41:55 dereine Exp $
+/**
+ * Simple filter to handle matching of boolean values
+ *
+ * Definition items:
+ * - label: (REQUIRED) The label for the checkbox.
+ * - type: For basic 'true false' types, an item can specify the following:
+ * - true-false: True/false (this is the default)
+ * - yes-no: Yes/No
+ * - on-off: On/Off
+ */
+class views_handler_filter_boolean_operator extends views_handler_filter {
+ // exposed filter options
+ var $no_single = TRUE;
+ // Don't display empty space where the operator would be.
+ var $no_operator = TRUE;
+ // Whether to accept NULL as a false value or not
+ var $accept_null = FALSE;
+
+ function construct() {
+ $this->value_value = t('True');
+ if (isset($this->definition['label'])) {
+ $this->value_value = $this->definition['label'];
+ }
+ if (isset($this->definition['accept_null'])) {
+ $this->accept_null = (bool) $this->definition['accept_null'];
+ }
+ $this->value_options = NULL;
+ parent::construct();
+ }
+
+ /**
+ * Return the possible options for this filter.
+ *
+ * Child classes should override this function to set the possible values
+ * for the filter. Since this is a boolean filter, the array should have
+ * two possible keys: 1 for "True" and 0 for "False", although the labels
+ * can be whatever makes sense for the filter. These values are used for
+ * configuring the filter, when the filter is exposed, and in the admin
+ * summary of the filter. Normally, this should be static data, but if it's
+ * dynamic for some reason, child classes should use a guard to reduce
+ * database hits as much as possible.
+ */
+ function get_value_options() {
+ if (isset($this->definition['type'])) {
+ if ($this->definition['type'] == 'yes-no') {
+ $this->value_options = array(1 => t('Yes'), 0 => t('No'));
+ }
+ if ($this->definition['type'] == 'on-off') {
+ $this->value_options = array(1 => t('On'), 0 => t('Off'));
+ }
+ }
+
+ // Provide a fallback if the above didn't set anything.
+ if (!isset($this->value_options)) {
+ $this->value_options = array(1 => t('True'), 0 => t('False'));
+ }
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['value']['default'] = FALSE;
+
+ return $options;
+ }
+
+ function operator_form(&$form, &$form_state) {
+ $form['operator'] = array();
+ }
+
+ function value_form(&$form, &$form_state) {
+ if (empty($this->value_options)) {
+ // Initialize the array of possible values for this filter.
+ $this->get_value_options();
+ }
+ if (!empty($form_state['exposed'])) {
+ // Exposed filter: use a select box to save space.
+ $filter_form_type = 'select';
+ }
+ else {
+ // Configuring a filter: use radios for clarity.
+ $filter_form_type = 'radios';
+ }
+ $form['value'] = array(
+ '#type' => $filter_form_type,
+ '#title' => $this->value_value,
+ '#options' => $this->value_options,
+ '#default_value' => $this->value,
+ );
+ if (!empty($this->options['exposed'])) {
+ $identifier = $this->options['expose']['identifier'];
+ if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
+ $form_state['input'][$identifier] = $this->value;
+ }
+ // If we're configuring an exposed filter, add an <Any> option.
+ $any_label = variable_get('views_exposed_filter_any_label', 'old_any') == 'old_any' ? '<Any>' : t('- Any -');
+ if ($form['value']['#type'] != 'select') {
+ $any_label = check_plain($any_label);
+ }
+ $form['value']['#options'] = array('All' => $any_label) + $form['value']['#options'];
+ }
+ }
+
+ function value_validate($form, &$form_state) {
+ if ($form_state['values']['options']['value'] == 'All' && empty($form_state['values']['options']['expose']['optional'])) {
+ form_set_error('value', t('You must select a value unless this is an optional exposed filter.'));
+ }
+ }
+
+ function admin_summary() {
+ if (!empty($this->options['exposed'])) {
+ return t('exposed');
+ }
+ if (empty($this->value_options)) {
+ $this->get_value_options();
+ }
+ // Now that we have the valid options for this filter, just return the
+ // human-readable label based on the current value. The value_options
+ // array is keyed with either 0 or 1, so if the current value is not
+ // empty, use the label for 1, and if it's empty, use the label for 0.
+ return $this->value_options[!empty($this->value)];
+ }
+
+ function expose_options() {
+ parent::expose_options();
+ $this->options['expose']['operator'] = '';
+ $this->options['expose']['label'] = $this->value_value;
+ $this->options['expose']['optional'] = FALSE;
+ }
+
+ function query() {
+ $this->ensure_my_table();
+ $field = "$this->table_alias.$this->real_field";
+
+ if (empty($this->value)) {
+
+ if ($this->accept_null) {
+ $or = db_or()
+ ->condition($field, 0, '=')
+ ->condition($field, NULL, 'IS NULL');
+ $this->query->add_where($this->options['group'], $or);
+ }
+ else {
+ $this->query->add_where($this->options['group'], $field, 0, '=');
+ }
+ }
+ else {
+ $this->query->add_where($this->options['group'], $field, 0, '<>');
+ }
+ }
+}
diff --git a/handlers/views_handler_filter_boolean_operator_string.inc b/handlers/views_handler_filter_boolean_operator_string.inc
new file mode 100644
index 0000000..f5b5cb1
--- /dev/null
+++ b/handlers/views_handler_filter_boolean_operator_string.inc
@@ -0,0 +1,28 @@
+<?php
+// $Id: views_handler_filter_boolean_operator_string.inc,v 1.2.4.1 2009/11/02 22:01:25 merlinofchaos Exp $
+/**
+ * Simple filter to handle matching of boolean values.
+ *
+ * This handler checks to see if a string field is empty (equal to '') or not.
+ * It is otherwise identical to the parent operator.
+ *
+ * Definition items:
+ * - label: (REQUIRED) The label for the checkbox.
+ */
+class views_handler_filter_boolean_operator_string extends views_handler_filter_boolean_operator {
+ function query() {
+ $this->ensure_my_table();
+ $where = "$this->table_alias.$this->real_field ";
+
+ if (empty($this->value)) {
+ $where .= "= ''";
+ if ($this->accept_null) {
+ $where = '(' . $where . " OR $this->table_alias.$this->real_field IS NULL)";
+ }
+ }
+ else {
+ $where .= "<> ''";
+ }
+ $this->query->add_where($this->options['group'], $where);
+ }
+}
diff --git a/handlers/views_handler_filter_date.inc b/handlers/views_handler_filter_date.inc
new file mode 100644
index 0000000..5e197e6
--- /dev/null
+++ b/handlers/views_handler_filter_date.inc
@@ -0,0 +1,152 @@
+<?php
+// $Id: views_handler_filter_date.inc,v 1.3.6.3 2010/03/10 20:27:33 merlinofchaos Exp $
+
+/**
+ * Filter to handle dates stored as a timestamp.
+ */
+class views_handler_filter_date extends views_handler_filter_numeric {
+ function option_definition() {
+ $options = parent::option_definition();
+
+ // value is already set up properly, we're just adding our new field to it.
+ $options['value']['contains']['type']['default'] = 'date';
+
+ return $options;
+ }
+
+ /**
+ * Add a type selector to the value form
+ */
+ function value_form(&$form, &$form_state) {
+ if (empty($form_state['exposed'])) {
+ $form['value']['type'] = array(
+ '#type' => 'radios',
+ '#title' => t('Value type'),
+ '#options' => array(
+ 'date' => t('A date in any machine readable format. CCYY-MM-DD HH:MM:SS is preferred.'),
+ 'offset' => t('An offset from the current time such as "+1 day" or "-2 hours -30 minutes"'),
+ ),
+ '#default_value' => !empty($this->value['type']) ? $this->value['type'] : 'date',
+ );
+ }
+ parent::value_form($form, $form_state);
+ }
+
+ function options_validate(&$form, &$form_state) {
+ parent::options_validate($form, $form_state);
+
+ if (!empty($form_state['values']['options']['expose']['optional'])) {
+ // Who cares what the value is if it's exposed and optional.
+ return;
+ }
+
+ $this->validate_valid_time($form['value'], $form_state['values']['options']['operator'], $form_state['values']['options']['value']);
+ }
+
+ function exposed_validate(&$form, &$form_state) {
+ if (empty($this->options['exposed'])) {
+ return;
+ }
+
+ if (!empty($this->options['expose']['optional'])) {
+ // Who cares what the value is if it's exposed and optional.
+ return;
+ }
+
+ $value = &$form_state['values'][$this->options['expose']['identifier']];
+ if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator'])) {
+ $operator = $form_state['values'][$this->options['expose']['operator']];
+ }
+ else {
+ $operator = $this->operator;
+ }
+
+ $this->validate_valid_time($this->options['expose']['identifier'], $operator, $value);
+
+ }
+
+ /**
+ * Validate that the time values convert to something usable.
+ */
+ function validate_valid_time(&$form, $operator, $value) {
+ $operators = $this->operators();
+
+ if ($operators[$operator]['values'] == 1) {
+ $convert = strtotime($value['value']);
+ if ($convert == -1 || $convert === FALSE) {
+ form_error($form['value'], t('Invalid date format.'));
+ }
+ }
+ elseif ($operators[$operator]['values'] == 2) {
+ $min = strtotime($value['min']);
+ if ($min == -1 || $min === FALSE) {
+ form_error($form['min'], t('Invalid date format.'));
+ }
+ $max = strtotime($value['max']);
+ if ($max == -1 || $max === FALSE) {
+ form_error($form['max'], t('Invalid date format.'));
+ }
+ }
+ }
+
+ function accept_exposed_input($input) {
+ if (empty($this->options['exposed'])) {
+ return TRUE;
+ }
+
+ // Store this because it will get overwritten.
+ $type = $this->value['type'];
+ $rc = parent::accept_exposed_input($input);
+
+ // Don't filter if value(s) are empty.
+ $operators = $this->operators();
+ if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator'])) {
+ $operator = $input[$this->options['expose']['operator']];
+ }
+ else {
+ $operator = $this->operator;
+ }
+
+ if ($operators[$operator]['values'] == 1) {
+ if ($this->value['value'] == '') {
+ return FALSE;
+ }
+ }
+ else {
+ if ($this->value['min'] == '' || $this->value['max'] == '') {
+ return FALSE;
+ }
+ }
+
+ // restore what got overwritten by the parent.
+ $this->value['type'] = $type;
+ return $rc;
+ }
+
+ function op_between($field) {
+ if ($this->operator == 'between') {
+ $a = intval(strtotime($this->value['min'], 0));
+ $b = intval(strtotime($this->value['max'], 0));
+ }
+ else {
+ $a = intval(strtotime($this->value['max'], 0));
+ $b = intval(strtotime($this->value['min'], 0));
+ }
+
+ if ($this->value['type'] == 'offset') {
+ $a = '***CURRENT_TIME***' . sprintf('%+d', $a); // keep sign
+ $b = '***CURRENT_TIME***' . sprintf('%+d', $b); // keep sign
+ }
+ // %s is safe here because strtotime scrubbed the input and we might
+ // have a string if using offset.
+ $this->query->add_where($this->options['group'], $field, array($a, $b), 'BETWEEN');
+ }
+
+ function op_simple($field) {
+ $value = intval(strtotime($this->value['value'], 0));
+ if (!empty($this->value['type']) && $this->value['type'] == 'offset') {
+ $value = '***CURRENT_TIME***' . sprintf('%+d', $value); // keep sign
+ }
+ $this->query->add_where($this->options['group'], $field, $value, $this->operator);
+ }
+}
diff --git a/handlers/views_handler_filter_equality.inc b/handlers/views_handler_filter_equality.inc
new file mode 100644
index 0000000..cd5a618
--- /dev/null
+++ b/handlers/views_handler_filter_equality.inc
@@ -0,0 +1,39 @@
+<?php
+// $Id: views_handler_filter_equality.inc,v 1.2 2008/09/10 01:08:06 merlinofchaos Exp $
+/**
+ * Simple filter to handle equal to / not equal to filters
+ */
+class views_handler_filter_equality extends views_handler_filter {
+ // exposed filter options
+ var $no_single = TRUE;
+
+ /**
+ * Provide simple equality operator
+ */
+ function operator_options() {
+ return array(
+ '=' => t('Is equal to'),
+ '!=' => t('Is not equal to'),
+ );
+ }
+
+ /**
+ * Provide a simple textfield for equality
+ */
+ function value_form(&$form, &$form_state) {
+ $form['value'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Value'),
+ '#size' => 30,
+ '#default_value' => $this->value,
+ );
+
+ if (!empty($form_state['exposed'])) {
+ $identifier = $this->options['expose']['identifier'];
+ if (!isset($form_state['input'][$identifier])) {
+ $form_state['input'][$identifier] = $this->value;
+ }
+ }
+ }
+}
+
diff --git a/handlers/views_handler_filter_group_by_numeric.inc b/handlers/views_handler_filter_group_by_numeric.inc
new file mode 100644
index 0000000..a7d61d6
--- /dev/null
+++ b/handlers/views_handler_filter_group_by_numeric.inc
@@ -0,0 +1,47 @@
+<?php
+// $Id: views_handler_filter_group_by_numeric.inc,v 1.1.4.5 2010/11/06 17:56:10 dereine Exp $
+
+/**
+ * Simple filter to handle greater than/less than filters
+ */
+class views_handler_filter_group_by_numeric extends views_handler_filter_numeric {
+ function query() {
+ $this->ensure_my_table();
+ $field = $this->get_field();
+
+ $info = $this->operators();
+ if (!empty($info[$this->operator]['method'])) {
+ $this->{$info[$this->operator]['method']}($field);
+ }
+ }
+ function op_between($field) {
+ if ($this->operator == 'between') {
+ $this->query->add_having($this->options['group'], $field, $this->value['min'], '>=');
+ $this->query->add_having($this->options['group'], $field, $this->value['max'], '<=');
+ }
+ else {
+ $this->query->add_having($this->options['group'], $field, db_or()->condition($field, $this->value['min'], '>=')->condition($field, $this->value['max'], '<=')
+ );
+ }
+ }
+
+ function op_simple($field) {
+ $this->query->add_having($this->options['group'], $field, $this->value['value'], $this->operator);
+ }
+
+ function op_empty($field) {
+ if ($this->operator == 'empty') {
+ $operator = "IS NULL";
+ }
+ else {
+ $operator = "IS NOT NULL";
+ }
+
+ $this->query->add_having($this->options['group'], $field, NULL, $operator);
+ }
+
+ function ui_name($short = FALSE) {
+ return $this->get_field(parent::ui_name($short));
+ }
+}
+
diff --git a/handlers/views_handler_filter_in_operator.inc b/handlers/views_handler_filter_in_operator.inc
new file mode 100644
index 0000000..9fcbc85
--- /dev/null
+++ b/handlers/views_handler_filter_in_operator.inc
@@ -0,0 +1,359 @@
+<?php
+// $Id: views_handler_filter_in_operator.inc,v 1.12.4.8 2010/11/05 07:20:54 dereine Exp $
+/**
+ * Simple filter to handle matching of multiple options selectable via checkboxes
+ *
+ * Definition items:
+ * - numeric: If set to true, this item will use numeric operators instead of string.
+ *
+ */
+class views_handler_filter_in_operator extends views_handler_filter {
+ var $value_form_type = 'checkboxes';
+
+ function construct() {
+ parent::construct();
+ $this->value_title = t('Options');
+ $this->value_options = NULL;
+ }
+
+ /**
+ * Child classes should be used to override this function and set the
+ * 'value options', unless 'options callback' is defined as a valid function
+ * or static public method to generate these values.
+ *
+ * This can use a guard to be used to reduce database hits as much as
+ * possible.
+ */
+ function get_value_options() {
+ if (isset($this->value_options)) {
+ return;
+ }
+
+ if (isset($this->definition['options callback']) && is_callable($this->definition['options callback'])) {
+ $this->value_options = call_user_func($this->definition['options callback']);
+ }
+ else {
+ $this->value_options = array(t('Yes'), t('No'));
+ }
+ }
+
+ function expose_options() {
+ parent::expose_options();
+ $this->options['expose']['reduce'] = FALSE;
+ }
+
+ function expose_form_right(&$form, &$form_state) {
+ parent::expose_form_right($form, $form_state);
+ $form['expose']['reduce'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Limit list to selected items'),
+ '#description' => t('If checked, the only items presented to the user will be the ones selected here.'),
+ '#default_value' => !empty($this->options['expose']['reduce']), // safety
+ );
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['operator']['default'] = 'in';
+ $options['value']['default'] = array();
+ $options['expose']['contains']['reduce'] = array('default' => FALSE);
+
+ return $options;
+ }
+
+ /**
+ * This kind of construct makes it relatively easy for a child class
+ * to add or remove functionality by overriding this function and
+ * adding/removing items from this array.
+ */
+ function operators() {
+ $operators = array(
+ 'in' => array(
+ 'title' => t('Is one of'),
+ 'short' => t('in'),
+ 'short_single' => t('='),
+ 'method' => 'op_simple',
+ 'values' => 1,
+ ),
+ 'not in' => array(
+ 'title' => t('Is not one of'),
+ 'short' => t('not in'),
+ 'short_single' => t('<>'),
+ 'method' => 'op_simple',
+ 'values' => 1,
+ ),
+ );
+ // if the definition allows for the empty operator, add it.
+ if (!empty($this->definition['allow empty'])) {
+ $operators += array(
+ 'empty' => array(
+ 'title' => t('Is empty (NULL)'),
+ 'method' => 'op_empty',
+ 'short' => t('empty'),
+ 'values' => 0,
+ ),
+ 'not empty' => array(
+ 'title' => t('Is not empty (NOT NULL)'),
+ 'method' => 'op_empty',
+ 'short' => t('not empty'),
+ 'values' => 0,
+ ),
+ );
+ }
+
+ return $operators;
+ }
+
+ /**
+ * Build strings from the operators() for 'select' options
+ */
+ function operator_options($which = 'title') {
+ $options = array();
+ foreach ($this->operators() as $id => $info) {
+ $options[$id] = $info[$which];
+ }
+
+ return $options;
+ }
+
+ function operator_values($values = 1) {
+ $options = array();
+ foreach ($this->operators() as $id => $info) {
+ if (isset($info['values']) && $info['values'] == $values) {
+ $options[] = $id;
+ }
+ }
+
+ return $options;
+ }
+
+ function value_form(&$form, &$form_state) {
+ $form['value'] = array();
+
+ $this->get_value_options();
+ $options = $this->value_options;
+ $default_value = (array) $this->value;
+
+ $which = 'all';
+ if (!empty($form['operator'])) {
+ $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
+ }
+ if (!empty($form_state['exposed'])) {
+ $identifier = $this->options['expose']['identifier'];
+
+ if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
+ // exposed and locked.
+ $which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
+ }
+ else {
+ $source = 'edit-' . drupal_html_id($this->options['expose']['operator']);
+ }
+
+ if (!empty($this->options['expose']['reduce'])) {
+ $options = $this->reduce_value_options();
+
+ if (empty($this->options['expose']['single']) && !empty($this->options['expose']['optional'])) {
+ $default_value = array();
+ }
+ }
+
+ if (!empty($this->options['expose']['single'])) {
+ if (!empty($this->options['expose']['optional']) && (empty($default_value) || !empty($this->options['expose']['reduce']))) {
+ $default_value = 'All';
+ }
+ elseif (empty($default_value)) {
+ $keys = array_keys($options);
+ $default_value = array_shift($keys);
+ }
+ else {
+ $copy = $default_value;
+ $default_value = array_shift($copy);
+ }
+ }
+ }
+
+ if ($which == 'all' || $which == 'value') {
+ $form['value'] = array(
+ '#type' => $this->value_form_type,
+ '#title' => $this->value_title,
+ '#options' => $options,
+ '#default_value' => $default_value,
+ // These are only valid for 'select' type, but do no harm to checkboxes.
+ '#multiple' => TRUE,
+ '#size' => count($options) > 8 ? 8 : count($options),
+ );
+ if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
+ $form_state['input'][$identifier] = $default_value;
+ }
+
+ $process = array();
+ if ($this->value_form_type == 'checkboxes') {
+ // If this form element will use checkboxes in the UI, we need to
+ // check_plain() all the options ourselves since FAPI is inconsistent
+ // about this. However, instead of directly doing that to the #options
+ // right now, we define a #process callback since we might change our
+ // mind later and convert this into a 'select' form element, which
+ // would lead to double-escaping the options.
+ $process[] = 'views_process_check_options';
+ }
+ if ($which == 'all') {
+ if (empty($form_state['exposed']) && ($this->value_form_type == 'checkboxes' || $this->value_form_type == 'radios')) {
+ $process[] = "form_process_$this->value_form_type";
+ $form['value']['#prefix'] = '<div id="edit-options-value-wrapper">';
+ $form['value']['#suffix'] = '</div>';
+ }
+ $process[] = 'ctools_dependent_process';
+ $form['value']['#dependency'] = array($source => $this->operator_values(1));
+ }
+ if (!empty($process)) {
+ $form['value']['#process'] = $process;
+ }
+ }
+ }
+
+ /**
+ * When using exposed filters, we may be required to reduce the set.
+ */
+ function reduce_value_options($input = NULL) {
+ if (!isset($input)) {
+ $input = $this->value_options;
+ }
+
+ // Because options may be an array of strings, or an array of mixed arrays
+ // and strings (optgroups) or an array of objects, we have to
+ // step through and handle each one individually.
+ $options = array();
+ foreach ($input as $id => $option) {
+ if (is_array($option)) {
+ $options[$id] = $this->reduce_value_options($option);
+ continue;
+ }
+ elseif (is_object($option)) {
+ $keys = array_keys($option->option);
+ $key = array_shift($keys);
+ if (isset($this->options['value'][$key])) {
+ $options[$id] = $option;
+ }
+ }
+ elseif (isset($this->options['value'][$id])) {
+ $options[$id] = $option;
+ }
+ }
+ return $options;
+ }
+
+ function accept_exposed_input($input) {
+ // A very special override because the All state for this type of
+ // filter could have a default:
+ if (empty($this->options['exposed'])) {
+ return TRUE;
+ }
+
+ // If this is single and optional, this says that yes this filter will
+ // participate, but using the default settings, *if* 'limit is true.
+ if (!empty($this->options['expose']['single']) && !empty($this->options['expose']['optional']) && !empty($this->options['expose']['limit'])) {
+ $identifier = $this->options['expose']['identifier'];
+ if ($input[$identifier] == 'All') {
+ return TRUE;
+ }
+ }
+
+ return parent::accept_exposed_input($input);
+ }
+
+ function value_submit($form, &$form_state) {
+ // Drupal's FAPI system automatically puts '0' in for any checkbox that
+ // was not set, and the key to the checkbox if it is set.
+ // Unfortunately, this means that if the key to that checkbox is 0,
+ // we are unable to tell if that checkbox was set or not.
+
+ // Luckily, the '#value' on the checkboxes form actually contains
+ // *only* a list of checkboxes that were set, and we can use that
+ // instead.
+
+ $form_state['values']['options']['value'] = $form['value']['#value'];
+ }
+
+ function admin_summary() {
+ if (!empty($this->options['exposed'])) {
+ return t('exposed');
+ }
+ $info = $this->operators();
+
+ $this->get_value_options();
+
+ if (!is_array($this->value)) {
+ return;
+ }
+
+ $operator = check_plain($info[$this->operator]['short']);
+ $values = '';
+ if (in_array($this->operator, $this->operator_values(1))) {
+ // Remove every element which is not known.
+ foreach ($this->value as $value) {
+ if (!isset($this->value_options[$value])) {
+ unset($this->value[$value]);
+ }
+ }
+ // Choose different kind of ouput for 0, a single and multiple values.
+ if (count($this->value) == 0) {
+ $values = t('Unknown');
+ }
+ else if (count($this->value) == 1) {
+ // If any, use the 'single' short name of the operator instead.
+ if (isset($info[$this->operator]['short_single'])) {
+ $operator = check_plain($info[$this->operator]['short_single']);
+ }
+
+ $keys = $this->value;
+ $value = array_shift($keys);
+ $values = check_plain($this->value_options[$value]);
+ }
+ else {
+ foreach ($this->value as $value) {
+ if ($values !== '') {
+ $values .= ', ';
+ }
+ if (strlen($values) > 8) {
+ $values .= '...';
+ break;
+ }
+ $values .= check_plain($this->value_options[$value]);
+ }
+ }
+ }
+
+ return $operator . (($values !== '') ? ' ' . $values : '');
+ }
+
+ function query() {
+ $info = $this->operators();
+ if (!empty($info[$this->operator]['method'])) {
+ $this->{$info[$this->operator]['method']}();
+ }
+ }
+
+ function op_simple() {
+ if (empty($this->value)) {
+ return;
+ }
+ $this->ensure_my_table();
+
+ // We use array_values() because the checkboxes keep keys and that can cause
+ // array addition problems.
+ $this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field", array_values($this->value), $this->operator);
+ }
+
+ function op_empty() {
+ $this->ensure_my_table();
+ if ($this->operator == 'empty') {
+ $operator = "IS NULL";
+ }
+ else {
+ $operator = "IS NOT NULL";
+ }
+
+ $this->query->add_where($this->options['group'], "$this->table_alias.$this->real_field", NULL, $operator);
+ }
+}
diff --git a/handlers/views_handler_filter_many_to_one.inc b/handlers/views_handler_filter_many_to_one.inc
new file mode 100644
index 0000000..6871654
--- /dev/null
+++ b/handlers/views_handler_filter_many_to_one.inc
@@ -0,0 +1,106 @@
+<?php
+// $Id: views_handler_filter_many_to_one.inc,v 1.2.4.5 2010/10/12 22:14:55 merlinofchaos Exp $
+
+/**
+ * Complex filter to handle filtering for many to one relationships,
+ * such as terms (many terms per node) or roles (many roles per user).
+ *
+ * The construct method needs to be overridden to provide a list of options;
+ * alternately, the value_form and admin_summary methods need to be overriden
+ * to provide something that isn't just a select list.
+ */
+class views_handler_filter_many_to_one extends views_handler_filter_in_operator {
+ function init(&$view, &$options) {
+ parent::init($view, $options);
+ $this->helper = new views_many_to_one_helper($this);
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['operator']['default'] = 'or';
+ $options['value']['default'] = array();
+
+ views_many_to_one_helper::option_definition($options);
+
+ return $options;
+ }
+
+ function operators() {
+ $operators = array(
+ 'or' => array(
+ 'title' => t('Is one of'),
+ 'short' => t('or'),
+ 'short_single' => t('='),
+ 'method' => 'op_helper',
+ 'values' => 1,
+ 'ensure_my_table' => 'helper',
+ ),
+ 'and' => array(
+ 'title' => t('Is all of'),
+ 'short' => t('and'),
+ 'short_single' => t('='),
+ 'method' => 'op_helper',
+ 'values' => 1,
+ 'ensure_my_table' => 'helper',
+ ),
+ 'not' => array(
+ 'title' => t('Is none of'),
+ 'short' => t('not'),
+ 'short_single' => t('<>'),
+ 'method' => 'op_helper',
+ 'values' => 1,
+ 'ensure_my_table' => 'helper',
+ ),
+ );
+ // if the definition allows for the empty operator, add it.
+ if (!empty($this->definition['allow empty'])) {
+ $operators += array(
+ 'empty' => array(
+ 'title' => t('Is empty (NULL)'),
+ 'method' => 'op_empty',
+ 'short' => t('empty'),
+ 'values' => 0,
+ ),
+ 'not empty' => array(
+ 'title' => t('Is not empty (NOT NULL)'),
+ 'method' => 'op_empty',
+ 'short' => t('not empty'),
+ 'values' => 0,
+ ),
+ );
+ }
+
+ return $operators;
+ }
+
+ var $value_form_type = 'select';
+ function value_form(&$form, &$form_state) {
+ parent::value_form($form, $form_state);
+
+ if (empty($form_state['exposed'])) {
+ $this->helper->options_form($form, $form_state);
+ }
+ }
+
+ /**
+ * Override ensure_my_table so we can control how this joins in.
+ * The operator actually has influence over joining.
+ */
+ function ensure_my_table() {
+ // Defer to helper if the operator specifies it.
+ $info = $this->operators();
+ if (isset($info[$this->operator]['ensure_my_table']) && $info[$this->operator]['ensure_my_table'] == 'helper') {
+ return $this->helper->ensure_my_table();
+ }
+
+ return parent::ensure_my_table();
+ }
+
+ function op_helper() {
+ if (empty($this->value)) {
+ return;
+ }
+ $this->helper->add_filter();
+ }
+}
diff --git a/handlers/views_handler_filter_numeric.inc b/handlers/views_handler_filter_numeric.inc
new file mode 100644
index 0000000..2e97286
--- /dev/null
+++ b/handlers/views_handler_filter_numeric.inc
@@ -0,0 +1,302 @@
+<?php
+// $Id: views_handler_filter_numeric.inc,v 1.7.6.4 2010/11/05 07:20:54 dereine Exp $
+
+/**
+ * Simple filter to handle greater than/less than filters
+ */
+class views_handler_filter_numeric extends views_handler_filter {
+ var $no_single = TRUE;
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['value'] = array(
+ 'contains' => array(
+ 'min' => array('default' => ''),
+ 'max' => array('default' => ''),
+ 'value' => array('default' => ''),
+ ),
+ );
+
+ return $options;
+ }
+
+ function operators() {
+ $operators = array(
+ '<' => array(
+ 'title' => t('Is less than'),
+ 'method' => 'op_simple',
+ 'short' => t('<'),
+ 'values' => 1,
+ ),
+ '<=' => array(
+ 'title' => t('Is less than or equal to'),
+ 'method' => 'op_simple',
+ 'short' => t('<='),
+ 'values' => 1,
+ ),
+ '=' => array(
+ 'title' => t('Is equal to'),
+ 'method' => 'op_simple',
+ 'short' => t('='),
+ 'values' => 1,
+ ),
+ '!=' => array(
+ 'title' => t('Is not equal to'),
+ 'method' => 'op_simple',
+ 'short' => t('!='),
+ 'values' => 1,
+ ),
+ '>=' => array(
+ 'title' => t('Is greater than or equal to'),
+ 'method' => 'op_simple',
+ 'short' => t('>='),
+ 'values' => 1,
+ ),
+ '>' => array(
+ 'title' => t('Is greater than'),
+ 'method' => 'op_simple',
+ 'short' => t('>'),
+ 'values' => 1,
+ ),
+ 'between' => array(
+ 'title' => t('Is between'),
+ 'method' => 'op_between',
+ 'short' => t('between'),
+ 'values' => 2,
+ ),
+ 'not between' => array(
+ 'title' => t('Is not between'),
+ 'method' => 'op_between',
+ 'short' => t('not between'),
+ 'values' => 2,
+ ),
+ );
+
+ // if the definition allows for the empty operator, add it.
+ if (!empty($this->definition['allow empty'])) {
+ $operators += array(
+ 'empty' => array(
+ 'title' => t('Is empty (NULL)'),
+ 'method' => 'op_empty',
+ 'short' => t('empty'),
+ 'values' => 0,
+ ),
+ 'not empty' => array(
+ 'title' => t('Is not empty (NOT NULL)'),
+ 'method' => 'op_empty',
+ 'short' => t('not empty'),
+ 'values' => 0,
+ ),
+ );
+ }
+
+ return $operators;
+ }
+
+ /**
+ * Provide a list of all the numeric operators
+ */
+ function operator_options($which = 'title') {
+ $options = array();
+ foreach ($this->operators() as $id => $info) {
+ $options[$id] = $info[$which];
+ }
+
+ return $options;
+ }
+
+ function operator_values($values = 1) {
+ $options = array();
+ foreach ($this->operators() as $id => $info) {
+ if ($info['values'] == $values) {
+ $options[] = $id;
+ }
+ }
+
+ return $options;
+ }
+ /**
+ * Provide a simple textfield for equality
+ */
+ function value_form(&$form, &$form_state) {
+ $form['value']['#tree'] = TRUE;
+
+ // We have to make some choices when creating this as an exposed
+ // filter form. For example, if the operator is locked and thus
+ // not rendered, we can't render dependencies; instead we only
+ // render the form items we need.
+ $which = 'all';
+ if (!empty($form['operator'])) {
+ $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
+ }
+
+ if (!empty($form_state['exposed'])) {
+ $identifier = $this->options['expose']['identifier'];
+
+ if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
+ // exposed and locked.
+ $which = in_array($this->operator, $this->operator_values(2)) ? 'minmax' : 'value';
+ }
+ else {
+ $source = 'edit-' . drupal_html_id($this->options['expose']['operator']);
+ }
+ }
+
+ if ($which == 'all') {
+ $form['value']['value'] = array(
+ '#type' => 'textfield',
+ '#title' => empty($form_state['exposed']) ? t('Value') : '',
+ '#size' => 30,
+ '#default_value' => $this->value['value'],
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array($source => array_map('htmlentities', $this->operator_values(1))),
+ );
+ if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['value'])) {
+ $form_state['input'][$identifier]['value'] = $this->value['value'];
+ }
+ }
+ elseif ($which == 'value') {
+ // When exposed we drop the value-value and just do value if
+ // the operator is locked.
+ $form['value'] = array(
+ '#type' => 'textfield',
+ '#title' => empty($form_state['exposed']) ? t('Value') : '',
+ '#size' => 30,
+ '#default_value' => $this->value['value'],
+ );
+ if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
+ $form_state['input'][$identifier] = $this->value['value'];
+ }
+ }
+
+ if ($which == 'all' || $which == 'minmax') {
+ $form['value']['min'] = array(
+ '#type' => 'textfield',
+ '#title' => empty($form_state['exposed']) ? t('Min') : '',
+ '#size' => 30,
+ '#default_value' => $this->value['min'],
+ );
+ $form['value']['max'] = array(
+ '#type' => 'textfield',
+ '#title' => empty($form_state['exposed']) ? t('And max') : t('And'),
+ '#size' => 30,
+ '#default_value' => $this->value['max'],
+ );
+ if ($which == 'all') {
+ $dependency = array(
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array($source => $this->operator_values(2)),
+ );
+ $form['value']['min'] += $dependency;
+ $form['value']['max'] += $dependency;
+ }
+ if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['min'])) {
+ $form_state['input'][$identifier]['min'] = $this->value['min'];
+ }
+ if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['max'])) {
+ $form_state['input'][$identifier]['max'] = $this->value['max'];
+ }
+
+ if (!isset($form['value'])) {
+ // Ensure there is something in the 'value'.
+ $form['value'] = array(
+ '#type' => 'value',
+ '#value' => NULL
+ );
+ }
+ }
+ }
+
+ function query() {
+ $this->ensure_my_table();
+ $field = "$this->table_alias.$this->real_field";
+
+ $info = $this->operators();
+ if (!empty($info[$this->operator]['method'])) {
+ $this->{$info[$this->operator]['method']}($field);
+ }
+ }
+
+ function op_between($field) {
+ if ($this->operator == 'between') {
+ $this->query->add_where($this->options['group'], $field, array($this->value['min'], $this->value['max']), 'BETWEEN');
+ }
+ else {
+ $this->query->add_where($this->options['group'], db_or()->condition($field, $this->value['min'], '<=')->condition($field, $this->value['max'], '>='));
+ }
+ }
+
+ function op_simple($field) {
+ $this->query->add_where($this->options['group'], $field, $this->value['value'], $this->operator);
+ }
+
+ function op_empty($field) {
+ if ($this->operator == 'empty') {
+ $operator = "IS NULL";
+ }
+ else {
+ $operator = "IS NOT NULL";
+ }
+
+ $this->query->add_where($this->options['group'], $field, NULL, $operator);
+ }
+
+ function admin_summary() {
+ if (!empty($this->options['exposed'])) {
+ return t('exposed');
+ }
+
+ $options = $this->operator_options('short');
+ $output = check_plain($options[$this->operator]);
+ if (in_array($this->operator, $this->operator_values(2))) {
+ $output .= ' ' . t('@min and @max', array('@min' => $this->value['min'], '@max' => $this->value['max']));
+ }
+ elseif (in_array($this->operator, $this->operator_values(1))) {
+ $output .= ' ' . check_plain($this->value['value']);
+ }
+ return $output;
+ }
+
+ /**
+ * Do some minor translation of the exposed input
+ */
+ function accept_exposed_input($input) {
+ if (empty($this->options['exposed'])) {
+ return TRUE;
+ }
+
+ // rewrite the input value so that it's in the correct format so that
+ // the parent gets the right data.
+ if (!empty($this->options['expose']['identifier'])) {
+ $value = &$input[$this->options['expose']['identifier']];
+ if (!is_array($value)) {
+ $value = array(
+ 'value' => $value,
+ );
+ }
+ }
+
+ $rc = parent::accept_exposed_input($input);
+
+ if (!empty($this->options['expose']['optional'])) {
+ // We have to do some of our own optional checking.
+ $info = $this->operators();
+ if (!empty($info[$this->operator]['values'])) {
+ switch ($info[$this->operator]['values']) {
+ case 1:
+ if ($value['value'] === '') {
+ return FALSE;
+ }
+ break;
+ case 2:
+ if ($value['min'] === '' && $value['max'] === '') {
+ return FALSE;
+ }
+ break;
+ }
+ }
+ }
+
+ return $rc;
+ }
+}
diff --git a/handlers/views_handler_filter_string.inc b/handlers/views_handler_filter_string.inc
new file mode 100644
index 0000000..948f2a9
--- /dev/null
+++ b/handlers/views_handler_filter_string.inc
@@ -0,0 +1,325 @@
+<?php
+// $Id: views_handler_filter_string.inc,v 1.8.4.4 2010/11/05 07:20:54 dereine Exp $
+
+/**
+ * Basic textfield filter to handle string filtering commands
+ * including equality, like, not like, etc.
+ */
+class views_handler_filter_string extends views_handler_filter {
+ // exposed filter options
+ var $no_single = TRUE;
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['case'] = array('default' => TRUE);
+
+ return $options;
+ }
+
+ /**
+ * This kind of construct makes it relatively easy for a child class
+ * to add or remove functionality by overriding this function and
+ * adding/removing items from this array.
+ */
+ function operators() {
+ $operators = array(
+ '=' => array(
+ 'title' => t('Is equal to'),
+ 'short' => t('='),
+ 'method' => 'op_equal',
+ 'values' => 1,
+ ),
+ '!=' => array(
+ 'title' => t('Is not equal to'),
+ 'short' => t('!='),
+ 'method' => 'op_equal',
+ 'values' => 1,
+ ),
+ 'contains' => array(
+ 'title' => t('Contains'),
+ 'short' => t('contains'),
+ 'method' => 'op_contains',
+ 'values' => 1,
+ ),
+ 'word' => array(
+ 'title' => t('Contains any word'),
+ 'short' => t('has word'),
+ 'method' => 'op_word',
+ 'values' => 1,
+ ),
+ 'allwords' => array(
+ 'title' => t('Contains all words'),
+ 'short' => t('has all'),
+ 'method' => 'op_word',
+ 'values' => 1,
+ ),
+ 'starts' => array(
+ 'title' => t('Starts with'),
+ 'short' => t('begins'),
+ 'method' => 'op_starts',
+ 'values' => 1,
+ ),
+ 'not_starts' => array(
+ 'title' => t('Does not start with'),
+ 'short' => t('not_begins'),
+ 'method' => 'op_not_starts',
+ 'values' => 1,
+ ),
+ 'ends' => array(
+ 'title' => t('Ends with'),
+ 'short' => t('ends'),
+ 'method' => 'op_ends',
+ 'values' => 1,
+ ),
+ 'not_ends' => array(
+ 'title' => t('Does not end with'),
+ 'short' => t('not_ends'),
+ 'method' => 'op_not_ends',
+ 'values' => 1,
+ ),
+ 'not' => array(
+ 'title' => t('Does not contain'),
+ 'short' => t('!has'),
+ 'method' => 'op_not',
+ 'values' => 1,
+ ),
+ 'shorterthan' => array(
+ 'title' => t('Length is shorter than'),
+ 'short' => t('shorter than'),
+ 'method' => 'op_shorter',
+ 'values' => 1,
+ ),
+ 'longerthan' => array(
+ 'title' => t('Length is longer than'),
+ 'short' => t('longer than'),
+ 'method' => 'op_longer',
+ 'values' => 1,
+ ),
+ );
+ // if the definition allows for the empty operator, add it.
+ if (!empty($this->definition['allow empty'])) {
+ $operators += array(
+ 'empty' => array(
+ 'title' => t('Is empty (NULL)'),
+ 'method' => 'op_empty',
+ 'short' => t('empty'),
+ 'values' => 0,
+ ),
+ 'not empty' => array(
+ 'title' => t('Is not empty (NOT NULL)'),
+ 'method' => 'op_empty',
+ 'short' => t('not empty'),
+ 'values' => 0,
+ ),
+ );
+ }
+
+ return $operators;
+ }
+
+ /**
+ * Build strings from the operators() for 'select' options
+ */
+ function operator_options($which = 'title') {
+ $options = array();
+ foreach ($this->operators() as $id => $info) {
+ $options[$id] = $info[$which];
+ }
+
+ return $options;
+ }
+
+ function admin_summary() {
+ if (!empty($this->options['exposed'])) {
+ return t('exposed');
+ }
+
+ $options = $this->operator_options('short');
+ $output = check_plain($options[$this->operator]);
+ if (in_array($this->operator, $this->operator_values(1))) {
+ $output .= ' ' . check_plain($this->value);
+ }
+ return $output;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+ $form['case'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Case sensitive'),
+ '#default_value' => $this->options['case'],
+ '#description' => t('Case sensitive filters may be faster. MySQL might ignore case sensitivity.'),
+ );
+ }
+
+ function operator_values($values = 1) {
+ $options = array();
+ foreach ($this->operators() as $id => $info) {
+ if (isset($info['values']) && $info['values'] == $values) {
+ $options[] = $id;
+ }
+ }
+
+ return $options;
+ }
+
+ /**
+ * Provide a simple textfield for equality
+ */
+ function value_form(&$form, &$form_state) {
+ // We have to make some choices when creating this as an exposed
+ // filter form. For example, if the operator is locked and thus
+ // not rendered, we can't render dependencies; instead we only
+ // render the form items we need.
+ $which = 'all';
+ if (!empty($form['operator'])) {
+ $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
+ }
+ if (!empty($form_state['exposed'])) {
+ $identifier = $this->options['expose']['identifier'];
+
+ if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
+ // exposed and locked.
+ $which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
+ }
+ else {
+ $source = 'edit-' . drupal_html_id($this->options['expose']['operator']);
+ }
+ }
+
+ if ($which == 'all' || $which == 'value') {
+ $form['value'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Value'),
+ '#size' => 30,
+ '#default_value' => $this->value,
+ );
+ if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
+ $form_state['input'][$identifier] = $this->value;
+ }
+
+ if ($which == 'all') {
+ $form['value'] += array(
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array($source => $this->operator_values(1)),
+ );
+ }
+ }
+
+ if (!isset($form['value'])) {
+ // Ensure there is something in the 'value'.
+ $form['value'] = array(
+ '#type' => 'value',
+ '#value' => NULL
+ );
+ }
+ }
+
+ function operator() {
+ if (!empty($this->options['case'])) {
+ return $this->operator;
+ }
+ else {
+ return $this->operator == '=' ? 'LIKE' : 'NOT LIKE';
+ }
+ }
+
+ /**
+ * Add this filter to the query.
+ *
+ * Due to the nature of fapi, the value and the operator have an unintended
+ * level of indirection. You will find them in $this->operator
+ * and $this->value respectively.
+ */
+ function query() {
+ $this->ensure_my_table();
+ $field = "$this->table_alias.$this->real_field";
+
+ $info = $this->operators();
+ if (!empty($info[$this->operator]['method'])) {
+ $this->{$info[$this->operator]['method']}($field);
+ }
+ }
+
+ function op_equal($field) {
+ $this->query->add_where($this->options['group'], $field, $this->value, $this->operator());
+ }
+
+ function op_contains($field) {
+ $this->query->add_where($this->options['group'], $field, "%$this->value%", 'LIKE');
+ }
+
+ function op_word($field, $upper) {
+ $where = $this->operator == 'word' ? db_or() : db_and();
+
+ preg_match_all('/ (-?)("[^"]+"|[^" ]+)/i', ' ' . $this->value, $matches, PREG_SET_ORDER);
+ foreach ($matches as $match) {
+ $phrase = false;
+ // Strip off phrase quotes
+ if ($match[2]{0} == '"') {
+ $match[2] = substr($match[2], 1, -1);
+ $phrase = true;
+ }
+ $words = trim($match[2], ',?!();:-');
+ $words = $phrase ? array($words) : preg_split('/ /', $words, -1, PREG_SPLIT_NO_EMPTY);
+ foreach ($words as $word) {
+ $where->condition($field, trim($word, " ,!?"), 'LIKE');
+ }
+ }
+
+ if (!$where) {
+ return;
+ }
+
+ if ($this->operator == 'word') {
+ $where = '(' . implode(' OR ', $where) . ')';
+ }
+ else {
+ $where = implode(' AND ', $where);
+ }
+ // previously this was a call_user_func_array but that's unnecessary
+ // as views will unpack an array that is a single arg.
+ $this->query->add_where($this->options['group'], $where, $values);
+ }
+
+ function op_starts($field, $upper) {
+ $this->query->add_where($this->options['group'], "$upper($field)", $this->value . '%', 'LIKE');
+ }
+
+ function op_not_starts($field, $upper) {
+ $this->query->add_where($this->options['group'], "$upper($field)", $this->value . '%', 'NOT LIKE');
+ }
+
+ function op_ends($field, $upper) {
+ $this->query->add_where($this->options['group'], "$upper($field)", '%' . $this->value, 'LIKE');
+ }
+
+ function op_not_ends($field, $upper) {
+ $this->query->add_where($this->options['group'], "$upper($field)", '%' . $this->value, 'NOT LIKE');
+ }
+
+ function op_not($field, $upper) {
+ $this->query->add_where($this->options['group'], "$upper($field)", '%' . $this->value . '%', 'NOT LIKE');
+ }
+
+ function op_shorter($field, $upper) {
+ $this->query->add_where($this->options['group'], "LENGTH($upper($field))", $this->value, '<');
+ }
+
+ function op_longer($field, $upper) {
+ $this->query->add_where($this->options['group'], "LENGTH($upper($field))", $this->value, '>');
+ }
+
+ function op_empty($field) {
+ if ($this->operator == 'empty') {
+ $operator = "IS NULL";
+ }
+ else {
+ $operator = "IS NOT NULL";
+ }
+
+ $this->query->add_where($this->options['group'], $field, NULL, $operator);
+ }
+
+}
diff --git a/handlers/views_handler_relationship.inc b/handlers/views_handler_relationship.inc
new file mode 100644
index 0000000..9eb75ad
--- /dev/null
+++ b/handlers/views_handler_relationship.inc
@@ -0,0 +1,152 @@
+<?php
+// $Id: views_handler_relationship.inc,v 1.4.4.3 2010/08/26 09:41:55 dereine Exp $
+/**
+ * @file
+ * Views' relationship handlers.
+ */
+
+/**
+ * @defgroup views_relationship_handlers Views' relationship handlers
+ * @{
+ * Handlers to tell Views how to create alternate relationships.
+ */
+
+/**
+ * Simple relationship handler that allows a new version of the primary table
+ * to be linked in.
+ *
+ * The base relationship handler can only handle a single join. Some relationships
+ * are more complex and might require chains of joins; for those, you must
+ * utilize a custom relationship handler.
+ *
+ * Definition items:
+ * - base: The new base table this relationship will be adding. This does not
+ * have to be a declared base table, but if there are no tables that
+ * utilize this base table, it won't be very effective.
+ * - base field: The field to use in the relationship; if left out this will be
+ * assumed to be the primary field.
+ * - relationship table: The actual table this relationship operates against.
+ * This is analogous to using a 'table' override.
+ * - relationship field: The actual field this relationship operates against.
+ * This is analogous to using a 'real field' override.
+ * - label: The default label to provide for this relationship, which is
+ * shown in parentheses next to any field/sort/filter/argument that uses
+ * the relationship.
+ */
+class views_handler_relationship extends views_handler {
+ /**
+ * Init handler to let relationships live on tables other than
+ * the table they operate on.
+ */
+ function init(&$view, &$options) {
+ parent::init($view, $options);
+ if (isset($this->definition['relationship table'])) {
+ $this->table = $this->definition['relationship table'];
+ }
+ if (isset($this->definition['relationship field'])) {
+ $this->field = $this->definition['relationship field'];
+ }
+ }
+
+ /**
+ * Get this field's label.
+ */
+ function label() {
+ if (!isset($this->options['label'])) {
+ return $this->ui_name();
+ }
+ return $this->options['label'];
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $label = !empty($this->definition['label']) ? $this->definition['label'] : $this->definition['field'];
+ $options['label'] = array('default' => $label, 'translatable' => TRUE);
+ $options['required'] = array('default' => FALSE);
+
+ return $options;
+ }
+
+ /**
+ * Default options form that provides the label widget that all fields
+ * should have.
+ */
+ function options_form(&$form, &$form_state) {
+ $form['label'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Label'),
+ '#default_value' => isset($this->options['label']) ? $this->options['label'] : '',
+ '#description' => t('The label for this relationship that will be displayed only administratively.'),
+ );
+
+ $form['required'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Require this relationship'),
+ '#description' => t('If required, items that do not contain this relationship will not appear.'),
+ '#default_value' => !empty($this->options['required']),
+ );
+ }
+
+ /**
+ * Called to implement a relationship in a query.
+ */
+ function query() {
+ // Figure out what base table this relationship brings to the party.
+ $table_data = views_fetch_data($this->definition['base']);
+ $base_field = empty($this->definition['base field']) ? $table_data['table']['base']['field'] : $this->definition['base field'];
+
+ $this->ensure_my_table();
+
+ $def = $this->definition;
+ $def['table'] = $this->definition['base'];
+ $def['field'] = $base_field;
+ $def['left_table'] = $this->table_alias;
+ $def['left_field'] = $this->field;
+ if (!empty($this->options['required'])) {
+ $def['type'] = 'INNER';
+ }
+
+ if (!empty($def['join_handler']) && class_exists($def['join_handler'])) {
+ $join = new $def['join_handler'];
+ }
+ else {
+ $join = new views_join();
+ }
+
+ $join->definition = $def;
+ $join->construct();
+ $join->adjusted = TRUE;
+
+ // use a short alias for this:
+ $alias = $def['table'] . '_' . $this->table;
+
+ $this->alias = $this->query->add_relationship($alias, $join, $this->definition['base'], $this->relationship);
+ }
+}
+
+/**
+ * A special handler to take the place of missing or broken handlers.
+ */
+class views_handler_relationship_broken extends views_handler_relationship {
+ function ui_name($short = FALSE) {
+ return t('Broken/missing handler');
+ }
+
+ function ensure_my_table() { /* No table to ensure! */ }
+ function query() { /* No query to run */ }
+ function options_form(&$form, &$form_state) {
+ $form['markup'] = array(
+ '#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
+ );
+ }
+
+ /**
+ * Determine if the handler is considered 'broken'
+ */
+ function broken() { return TRUE; }
+}
+
+/**
+ * @}
+ */
diff --git a/handlers/views_handler_sort.inc b/handlers/views_handler_sort.inc
new file mode 100644
index 0000000..d1fac1d
--- /dev/null
+++ b/handlers/views_handler_sort.inc
@@ -0,0 +1,192 @@
+<?php
+// $Id: views_handler_sort.inc,v 1.2.4.3 2010/02/22 10:15:28 dereine Exp $
+/**
+ * @defgroup views_sort_handlers Views' sort handlers
+ * @{
+ * Handlers to tell Views how to sort queries
+ */
+
+/**
+ * Base sort handler that has no options and performs a simple sort
+ */
+class views_handler_sort extends views_handler {
+
+ /**
+ * Determine if a sort can be exposed.
+ */
+ function can_expose() { return TRUE; }
+
+ /**
+ * Called to add the sort to a query.
+ */
+ function query() {
+ $this->ensure_my_table();
+ // Add the field.
+ $this->query->add_orderby($this->table_alias, $this->real_field, $this->options['order']);
+ }
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['order'] = array('default' => 'ASC');
+ $options['exposed'] = array('default' => FALSE);
+ $options['expose'] = array(
+ 'contains' => array(
+ 'label' => array('default' => '', 'translatable' => TRUE),
+ ),
+ );
+ return $options;
+ }
+
+ /**
+ * Display whether or not the sort order is ascending or descending
+ */
+ function admin_summary() {
+ if (!empty($this->options['exposed'])) {
+ return t('Exposed');
+ }
+ switch ($this->options['order']) {
+ case 'ASC':
+ case 'asc':
+ default:
+ return t('asc');
+ break;
+ case 'DESC';
+ case 'desc';
+ return t('desc');
+ break;
+ }
+ }
+
+ /**
+ * Basic options for all sort criteria
+ */
+ function options_form(&$form, &$form_state) {
+ if ($this->can_expose()) {
+ $this->show_expose_button($form, $form_state);
+ }
+ $form['op_val_start'] = array('#value' => '<div class="clearfix">');
+ $this->show_sort_form($form, $form_state);
+ $form['op_val_end'] = array('#value' => '</div>');
+ if ($this->can_expose()) {
+ $this->show_expose_form($form, $form_state);
+ }
+ }
+
+ /**
+ * Simple validate handler
+ */
+ function options_validate(&$form, &$form_state) {
+ $this->sort_validate($form, $form_state);
+ if (!empty($this->options['exposed'])) {
+ $this->expose_validate($form, $form_state);
+ }
+
+ }
+
+ /**
+ * Simple submit handler
+ */
+ function options_submit(&$form, &$form_state) {
+ unset($form_state['values']['expose_button']); // don't store this.
+ $this->sort_submit($form, $form_state);
+ if (!empty($this->options['exposed'])) {
+ $this->expose_submit($form, $form_state);
+ }
+ }
+
+ /**
+ * Shortcut to display the value form.
+ */
+ function show_sort_form(&$form, &$form_state) {
+ $options = $this->sort_options();
+ if (!empty($options)) {
+ $form['order'] = array(
+ '#type' => 'radios',
+ '#options' => $options,
+ '#default_value' => $this->options['order'],
+ );
+ }
+ }
+
+ function sort_validate(&$form, &$form_state) { }
+
+ function sort_submit(&$form, &$form_state) { }
+
+ /**
+ * Provide a list of options for the default sort form.
+ * Should be overridden by classes that don't override sort_form
+ */
+ function sort_options() {
+ return array(
+ 'ASC' => t('Sort ascending'),
+ 'DESC' => t('Sort descending'),
+ );
+ }
+
+ /**
+ * Since all exposed sorts are grouped into one select box.
+ * We don't return nothing when views call to exposed_form()
+ */
+ function exposed_form(&$form, &$form_state) { }
+
+ /**
+ * Handle the 'left' side fo the exposed options form.
+ */
+ function expose_form_left(&$form, &$form_state) {
+ $form['expose']['label'] = array(
+ '#type' => 'textfield',
+ '#default_value' => $this->options['expose']['label'],
+ '#title' => t('Label'),
+ '#required' => TRUE,
+ '#size' => 40,
+ );
+ }
+
+ /**
+ * Handle the 'right' side fo the exposed options form.
+ */
+ function expose_form_right(&$form, &$form_state) {
+ $form['expose']['order'] = array(
+ '#type' => 'value',
+ '#value' => 'ASC',
+ );
+ }
+
+ /**
+ * Provide default options for exposed sorts.
+ */
+ function expose_options() {
+ $this->options['expose'] = array(
+ 'order' => $this->options['order'],
+ 'label' => $this->ui_name(),
+ );
+ }
+}
+
+/**
+ * A special handler to take the place of missing or broken handlers.
+ */
+class views_handler_sort_broken extends views_handler_sort {
+ function ui_name($short = FALSE) {
+ return t('Broken/missing handler');
+ }
+
+ function ensure_my_table() { /* No table to ensure! */ }
+ function query() { /* No query to run */ }
+ function options_form(&$form, &$form_state) {
+ $form['markup'] = array(
+ '#markup' => '<div class="form-item description">' . t('The handler for this item is broken or missing and cannot be used. If a module provided the handler and was disabled, re-enabling the module may restore it. Otherwise, you should probably delete this item.') . '</div>',
+ );
+ }
+
+ /**
+ * Determine if the handler is considered 'broken'
+ */
+ function broken() { return TRUE; }
+}
+
+
+/**
+ * @}
+ */
diff --git a/handlers/views_handler_sort_date.inc b/handlers/views_handler_sort_date.inc
new file mode 100644
index 0000000..9f0c76b
--- /dev/null
+++ b/handlers/views_handler_sort_date.inc
@@ -0,0 +1,70 @@
+<?php
+// $Id: views_handler_sort_date.inc,v 1.1 2008/09/03 19:21:28 merlinofchaos Exp $
+
+/**
+ * Basic sort handler for dates.
+ *
+ * This handler enables granularity, which is the ability to make dates
+ * equivalent based upon nearness.
+ *
+ * @ingroup views_sort_handlers
+ */
+class views_handler_sort_date extends views_handler_sort {
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['granularity'] = array('default' => 'second');
+
+ return $options;
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+
+ $form['granularity'] = array(
+ '#type' => 'radios',
+ '#title' => t('Granularity'),
+ '#options' => array(
+ 'second' => t('Second'),
+ 'minute' => t('Minute'),
+ 'hour' => t('Hour'),
+ 'day' => t('Day'),
+ 'month' => t('Month'),
+ 'year' => t('Year'),
+ ),
+ '#description' => t('The granularity is the smallest unit to use when determining whether two dates are the same; for example, if the granularity is "Year" then all dates in 1999, regardless of when they fall in 1999, will be considered the same date.'),
+ '#default_value' => $this->options['granularity'],
+ );
+ }
+
+ /**
+ * Called to add the sort to a query.
+ */
+ function query() {
+ $this->ensure_my_table();
+ switch ($this->options['granularity']) {
+ case 'second':
+ default:
+ $this->query->add_orderby($this->table_alias, $this->real_field, $this->options['order']);
+ return;
+ case 'minute':
+ $formula = views_date_sql_format('YmdHi', "$this->table_alias.$this->real_field");
+ break;
+ case 'hour':
+ $formula = views_date_sql_format('YmdH', "$this->table_alias.$this->real_field");
+ break;
+ case 'day':
+ $formula = views_date_sql_format('Ymd', "$this->table_alias.$this->real_field");
+ break;
+ case 'month':
+ $formula = views_date_sql_format('Ym', "$this->table_alias.$this->real_field");
+ break;
+ case 'year':
+ $formula = views_date_sql_format('Y', "$this->table_alias.$this->real_field");
+ break;
+ }
+
+ // Add the field.
+ $this->query->add_orderby(NULL, $formula, $this->options['order'], $this->table_alias . '_' . $this->field . '_' . $this->options['granularity']);
+ }
+}
diff --git a/handlers/views_handler_sort_formula.inc b/handlers/views_handler_sort_formula.inc
new file mode 100644
index 0000000..aa07a2e
--- /dev/null
+++ b/handlers/views_handler_sort_formula.inc
@@ -0,0 +1,48 @@
+<?php
+// $Id: views_handler_sort_formula.inc,v 1.1 2008/09/03 19:21:28 merlinofchaos Exp $
+/**
+ * Base sort handler that has no options and performs a simple sort
+ *
+ * Definition items:
+ * - formula: The formula to use to sort on, such as with a random sort.
+ * The formula should be an array, with keys for database
+ * types, and 'default' for non-specified. 'default' is
+ * required, all others ('mysql', 'mysqli' and 'pgsql' are
+ * optional). It is recommended you use 'default' for mysql
+ * and create specific overrides for pgsql when the formulae
+ * differ.
+ *
+ * @ingroup views_sort_handlers
+ */
+class views_handler_sort_formula extends views_handler_sort {
+ /**
+ * Constructor to take the formula this sorts on.
+ */
+ function construct() {
+ $this->formula = $this->definition['formula'];
+ if (is_array($this->formula) && !isset($this->formula['default'])) {
+ $this->error = t('views_handler_sort_formula missing default: @formula', array('@formula' => var_export($this->formula, TRUE)));
+ }
+ parent::construct();
+ }
+ /**
+ * Called to add the sort to a query.
+ */
+ function query() {
+ if (is_array($this->formula)) {
+ global $db_type;
+ if (isset($this->formula[$db_type])) {
+ $formula = $this->formula[$db_type];
+ }
+ else {
+ $formula = $this->formula['default'];
+ }
+ }
+ else {
+ $formula = $this->formula;
+ }
+ $this->ensure_my_table();
+ // Add the field.
+ $this->query->add_orderby(NULL, $formula, $this->options['order'], $this->table_alias . '_' . $this->field);
+ }
+}
diff --git a/handlers/views_handler_sort_group_by_numeric.inc b/handlers/views_handler_sort_group_by_numeric.inc
new file mode 100644
index 0000000..eebf9c7
--- /dev/null
+++ b/handlers/views_handler_sort_group_by_numeric.inc
@@ -0,0 +1,29 @@
+<?php
+// $Id: views_handler_sort_group_by_numeric.inc,v 1.1.4.3 2010/08/26 09:41:55 dereine Exp $
+/**
+ * Handler for GROUP BY on simple numeric fields.
+ */
+class views_handler_sort_group_by_numeric extends views_handler_sort {
+ function init(&$view, &$options) {
+ parent::init($view, $options);
+
+ // Initialize the original handler.
+ $this->handler = views_get_handler($options['table'], $options['field'], 'sort');
+ $this->handler->init($view, $options);
+ }
+
+ /**
+ * Called to add the field to a query.
+ */
+ function query() {
+ $params = array(
+ 'function' => $this->options['group_type'],
+ );
+
+ $this->query->add_orderby($this->table, $this->field, $this->options['order'], NULL, $params);
+ }
+
+ function ui_name() {
+ return $this->get_field(parent::ui_name());
+ }
+}
diff --git a/handlers/views_handler_sort_menu_hierarchy.inc b/handlers/views_handler_sort_menu_hierarchy.inc
new file mode 100644
index 0000000..43a2b92
--- /dev/null
+++ b/handlers/views_handler_sort_menu_hierarchy.inc
@@ -0,0 +1,20 @@
+<?php
+// $Id: views_handler_sort_menu_hierarchy.inc,v 1.1 2008/09/03 19:21:28 merlinofchaos Exp $
+
+/**
+ * Sort in menu hierarchy order.
+ *
+ * Given a field name of 'p' this produces an ORDER BY on p1, p2, ..., p9.
+ * This is only really useful for the {menu_links} table.
+ *
+ * @ingroup views_sort_handlers
+ */
+class views_handler_sort_menu_hierarchy extends views_handler_sort {
+ function query() {
+ $this->ensure_my_table();
+ $max_depth = isset($this->definition['max depth']) ? $this->definition['max depth'] : MENU_MAX_DEPTH;
+ for ($i = 1; $i <= $max_depth; ++$i) {
+ $this->query->add_orderby($this->table_alias, $this->field . $i, $this->options['order']);
+ }
+ }
+}
diff --git a/handlers/views_handler_sort_random.inc b/handlers/views_handler_sort_random.inc
new file mode 100644
index 0000000..0a1c0a5
--- /dev/null
+++ b/handlers/views_handler_sort_random.inc
@@ -0,0 +1,27 @@
+<?php
+// $Id: views_handler_sort_random.inc,v 1.1.6.1 2009/11/02 22:01:25 merlinofchaos Exp $
+
+/**
+ * Handle a random sort.
+ */
+class views_handler_sort_random extends views_handler_sort {
+ function query() {
+ switch (db_driver()) {
+ case 'mysql':
+ case 'mysqli':
+ $formula = 'RAND()';
+ break;
+ case 'pgsql':
+ $formula = 'RANDOM()';
+ break;
+ }
+ if (!empty($formula)) {
+ $this->query->add_orderby(NULL, $formula, $this->options['order'], '_' . $this->field);
+ }
+ }
+
+ function options_form(&$form, &$form_state) {
+ parent::options_form($form, $form_state);
+ $form['order']['#access'] = FALSE;
+ }
+}
diff --git a/help/CVS/Entries b/help/CVS/Entries
new file mode 100644
index 0000000..4d2eedc
--- /dev/null
+++ b/help/CVS/Entries
@@ -0,0 +1,50 @@
+/about.html/1.5.6.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/analyze-theme.html/1.5.6.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/api-default-views.html/1.3.6.3/Wed Aug 4 05:54:08 2010//TDRUPAL-7--3
+/api-example.html/1.2.4.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/api-handlers.html/1.4.6.2/Mon Jul 19 09:18:42 2010//TDRUPAL-7--3
+/api-plugins.html/1.7.6.2/Wed Jul 28 06:58:25 2010//TDRUPAL-7--3
+/api-tables.html/1.8.4.3/Tue Oct 12 21:21:02 2010//TDRUPAL-7--3
+/api-upgrading.html/1.1.2.3/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/api.html/1.5.6.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/argument.html/1.8.6.1/Fri Mar 19 23:03:13 2010//TDRUPAL-7--3
+/display-attachment.html/1.2/Tue Apr 29 00:35:07 2008//TDRUPAL-7--3
+/display-block.html/1.5/Tue Oct 14 17:06:02 2008//TDRUPAL-7--3
+/display-default.html/1.2/Tue Apr 29 00:35:07 2008//TDRUPAL-7--3
+/display-feed.html/1.2/Mon May 5 05:09:36 2008//TDRUPAL-7--3
+/display-page.html/1.3.6.1/Thu Mar 25 20:31:11 2010//TDRUPAL-7--3
+/display.html/1.2.6.1/Fri Mar 19 23:03:13 2010//TDRUPAL-7--3
+/embed.html/1.1/Fri Jun 13 00:56:19 2008//TDRUPAL-7--3
+/example-author-block.html/1.1.6.2/Fri Aug 13 22:22:28 2010//TDRUPAL-7--3
+/example-recent-stories.html/1.1.6.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/example-user-feed.html/1.1.6.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/example-users-by-role.html/1.1.6.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/field.html/1.2/Thu May 15 19:17:11 2008//TDRUPAL-7--3
+/filter.html/1.3/Fri Feb 20 20:46:48 2009//TDRUPAL-7--3
+/getting-started.html/1.8/Tue Oct 14 18:20:25 2008//TDRUPAL-7--3
+/menu.html/1.2.6.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/new.html/1.5.6.1/Tue Oct 12 21:35:03 2010//TDRUPAL-7--3
+/overrides.html/1.2.6.1/Wed Mar 10 20:00:30 2010//TDRUPAL-7--3
+/path.html/1.3/Wed Jun 25 19:26:01 2008//TDRUPAL-7--3
+/relationship.html/1.6/Fri Feb 20 20:46:48 2009//TDRUPAL-7--3
+/sort.html/1.2/Fri Jun 13 00:56:19 2008//TDRUPAL-7--3
+/style-comment-rss.html/1.1/Fri Jun 13 00:56:19 2008//TDRUPAL-7--3
+/style-fields.html/1.3/Tue Jun 17 20:07:03 2008//TDRUPAL-7--3
+/style-grid.html/1.3.6.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/style-list.html/1.3.6.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/style-node-rss.html/1.2/Fri Jun 13 00:56:19 2008//TDRUPAL-7--3
+/style-node.html/1.4.6.1/Wed Sep 15 09:01:01 2010//TDRUPAL-7--3
+/style-row.html/1.1/Fri Jun 13 00:56:19 2008//TDRUPAL-7--3
+/style-rss.html/1.2/Fri Jun 13 00:56:19 2008//TDRUPAL-7--3
+/style-summary-unformatted.html/1.1/Fri Jun 13 00:56:19 2008//TDRUPAL-7--3
+/style-summary.html/1.2/Fri Jun 13 00:56:19 2008//TDRUPAL-7--3
+/style-table.html/1.2/Fri Jun 13 00:56:19 2008//TDRUPAL-7--3
+/style-unformatted.html/1.2/Fri Jun 13 00:56:19 2008//TDRUPAL-7--3
+/style.html/1.4.6.1/Tue Mar 16 22:27:29 2010//TDRUPAL-7--3
+/theme-css.html/1.3.6.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/updating.html/1.3/Thu Jul 3 05:05:12 2008//TDRUPAL-7--3
+/upgrading.html/1.1.2.1/Thu Aug 26 19:00:51 2010//TDRUPAL-7--3
+/using-theme.html/1.6.6.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/view-type.html/1.5/Fri Feb 20 20:46:48 2009//TDRUPAL-7--3
+/views.help.ini/1.18.4.5/Thu Aug 26 19:00:51 2010//TDRUPAL-7--3
+D
diff --git a/help/CVS/Entries.Log b/help/CVS/Entries.Log
new file mode 100644
index 0000000..375967b
--- /dev/null
+++ b/help/CVS/Entries.Log
@@ -0,0 +1 @@
+A D/images////
diff --git a/help/CVS/Repository b/help/CVS/Repository
new file mode 100644
index 0000000..0dea52c
--- /dev/null
+++ b/help/CVS/Repository
@@ -0,0 +1 @@
+contributions/modules/views/help
diff --git a/help/CVS/Root b/help/CVS/Root
new file mode 100644
index 0000000..127da18
--- /dev/null
+++ b/help/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal-contrib
diff --git a/help/CVS/Tag b/help/CVS/Tag
new file mode 100644
index 0000000..0f07c7f
--- /dev/null
+++ b/help/CVS/Tag
@@ -0,0 +1 @@
+TDRUPAL-7--3
diff --git a/help/about.html b/help/about.html
new file mode 100644
index 0000000..3f91b99
--- /dev/null
+++ b/help/about.html
@@ -0,0 +1,18 @@
+<!-- $Id: about.html,v 1.5.6.1 2009/11/02 22:01:26 merlinofchaos Exp $ -->
+The views module allows administrators and site designers to create, manage, and display lists of content. Each list managed by the views module is known as a "view", and the output of a view is known as a "display". Displays are provided in either block or page form, and a single view may have multiple displays. Optional navigation aids, including a system path and menu item, can be set for each page-based display of a view. By default, views may be created that list content (a <em>Node</em> view type), content revisions (a <em>Node revisions</em> view type) or users (a <em>User</em> view type). A view may be restricted to members of specific user roles, and may be added, edited or deleted at the <a href="base_url:admin/structure/views">views administration page</a>
+
+The "building block" design of the views system provides power and flexibility, allowing parameters to be specified only when needed. While an advanced view may use all of available parameters to create complex and highly interactive applications, a simple content listing may specify only a few options. All views rely on a conceptual framework that includes:
+
+<ul>
+ <li><a href="topic:views/field">Fields</a>, or the individual pieces of data being displayed. Adding the fields <em>Node: Title</em>, <em>Node: Type</em>, and <em>Node: Post date</em> to a node view, for example, includes the title, content type and creation date in the displayed results </li>
+
+ <li><a href="topic:views/relationship">Relationships</a>, or information about how data elements relate to one another. If relationship data is available, like that provided by a CCK <em>nodereference</em> field, items from a related node may be included in the view </li>
+
+ <li><a href="topic:views/argument">Arguments</a>, or additional parameters that dynamically refine the view results, passed as part of the path. Adding an argument of <em>Node: Type</em> to a node view with a path of "content", for example, dynamically filters the displayed items by content type. In this example (shown with Clean URLs enabled), accessing the view through the path "<em>http://www.example.com/content/page</em>" displays all posts of the type "page", the path "<em>http://www.example.com/content/story</em>" displays all posts of the type "story", and "<em>http://www.example.com/content</em>" displays all posts regardless of type) </li>
+
+ <li><a href="topic:views/sort">Sort criteria</a>, which determine the order of items displayed in the view results. Adding the sort criteria <em>Node: Post date</em> (in descending order) to a node <em>view</em>, for example, sorts the displayed posts in descending order by creation date </li>
+
+ <li><a href="topic:views/filter">Filters</a>, which limit items displayed in the results. Adding the filter <em>Node: Published</em> (and setting it equal to "Published") to a node view, for example, prevents unpublished items from being displayed</li>
+
+ <li><a href="topic:views/display">Displays</a>, which control where the output will be seen. Every view has a default display, which doesn't actually display the view anywhere, but is used to hold the default settings for the view, and is used when the view is called programmatically if another display is not specified. Much more useful to users are the <a href="topic:views/display-page">page</a> display, which gives a view a path and allows it to be the primary content of a page, or the <a href="topic:views/display-block">block</a> display which allows it to appear as secondary content on other pages.</li>
+</ul>
diff --git a/help/analyze-theme.html b/help/analyze-theme.html
new file mode 100644
index 0000000..6605a30
--- /dev/null
+++ b/help/analyze-theme.html
@@ -0,0 +1,24 @@
+<!-- $Id: analyze-theme.html,v 1.5.6.1 2009/11/02 22:01:26 merlinofchaos Exp $ -->
+<p>You may use any of the following possible theme files to modify individual parts of your view. In total, there are four parts to theming a view.</p>
+<ul>
+ <li> The <strong>display</strong> theme is usually views-view.tpl.php and it largely controls the decorations around a view; where the header, footer, pager, more link, feed icon, etc, will be placed. </li>
+
+ <li> The <strong>style</strong> will control how all of the results of the display are put together. It may be as simple as just displaying all of the rows, or it may be a complex table generator or something in between. </li>
+
+ <li> The <strong>row</strong> style controls each individual row; not all styles utilize the row style (notably the table), but most others do.
+
+ <li> Finally, <strong>field</strong> themes allow you to override the look and even the data of each individual field, if the style uses fields. The actual template the system will use should be hilighted in <strong>bold</strong>.</li>
+</ul>
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/style-breakdown-large.png"><img src="path:images/style-breakdown.png" /></a>
+<em>A breakdown of View output</em>
+</div>
+
+<p>The link to the left of each type will give you information about the default template used for that type. You may cut and paste this and place it in your theme with the appropriate template, or you may copy the base file from the views/theme directory (or, if provided by a module, from the module's directory). <strong>It is important that you clear the theme registry cache every time you add a new template, or the new template will not be picked up.</strong></p>
+
+<p><strong>Important note:</strong> You place your custom template files in your theme directory, <strong>not views/theme</strong>. This is always true of theming with Drupal.
+
+<p>In addition to this tool, the very useful <a href="http://drupal.org/project/devel">devel</a> module contains a tool called the "Theme developer" which does a good job of visually showing you which areas of your site use which themes. Be careful with it, though, as the theme developer causes the Views edit page to break.</p>
+
+<p>Also, this feature will only work properly with Drupal 6.3 and later; prior to Drupal 6.3 <a href="http://drupal.org/node/241570">this patch</a> will be required.</p>
diff --git a/help/api-default-views.html b/help/api-default-views.html
new file mode 100644
index 0000000..353bebe
--- /dev/null
+++ b/help/api-default-views.html
@@ -0,0 +1,106 @@
+<!-- $Id: api-default-views.html,v 1.3.6.3 2010/08/04 05:54:08 dereine Exp $ -->
+Views can be stored in the database, which is typical of smaller sites and hobby sites. However, Views may also be stored directly in the code as "default" views, (which simply means they're available by default). Modules often come with views that are specific to the module data, but it's also possible -- and <b>highly</b> recommended -- that sites which have separate "development" and "production" sites export their views into default views in a site-specific module. This makes it very easy to transfer views from dev to production without making database changes.
+
+<h3>Creating a module</h3>
+First, create a directory in <em>sites/all/modules</em> for your new module. Call it whatever you like, but for this example we will call it <em>mymodule</em>.
+
+In this directory, create a <em>mymodule.module</em> file. It can be empty for now, but it should at least contain an opening PHP tag:
+<pre>&lt;?php
+// $Id $
+</pre>
+
+It should not contain a closing ?&gt; tag, as the closing ?&gt; tag is not required and anything AFTER the closing tag, such as a space or a linefeed, will be displayed directly to the browser and can potentially cause problems.
+
+The .module file will contain functions and drupal hooks. Hooks are specially named functions that Drupal will call in order to get your module's response at certain times while generating pages. The only function you will need for this exercise is the 'views_api' hook that tells Views that this module supports the Views API and what version:
+
+<pre>function mymodule_views_api() {
+ return array('api' => 2.0);
+}
+</pre>
+
+For other uses you may well add additional functions.
+
+Second, you need to create a <em>mymodule.info</em> file:
+
+<pre>; $Id $
+name = My module
+description = My site specific module.
+core = 6.x
+</pre>
+
+Once you have these two files set up, you should be able to activate your new module at the <em>Administer >> Modules</em> page.
+<h3>Exporting your views</h3>
+
+The easiest way to do this is to activate the 'views_export' module, and navigate to <em>Administer >> Structure >> Views >> Tools >> Bulk export</em> Place a check next to each view that you want in your module, type the module name into the text field, and click export. This will create the entire <em>hook_views_default_views()</em> function for you.
+
+You can also export individual views. If you do this, keep in mind that this export does not include the line that adds the exported $view into the larger $views array:
+
+<pre>$views[$view->name] = $view</pre>
+
+To place this into your <em>hook_views_default_views()</em> you will need to place that after the view, and make sure the function returns $views at the end.
+
+<h3>Placing your exported views into your module</h3>
+Cut and paste the entire output of the bulk export tool into mymodule.views_default.inc -- and be sure to put a &lt;?php at the top of the file so that the webserver knows that it's PHP code! Then visit the Views tools page and clear the Views cache. Your views should now be listed as <b>Overridden</b> on the view list page. If you <b>revert</b> these views, they will be removed from the database, but will remain in code.
+
+<h3>Theming your views in your module</h3>
+You can theme these views in the module and not need to rely on the theme to do this at all; and in fact, the theme can continue to override these just like it ordinarily would, even if your module provides a theme. This is very useful for distributing a module where the view needs to look "just so."
+
+To do this, you need to implement <em>hook_theme()</em> in your module:
+<pre>function mymodule_theme($existing) {
+ return array(
+ 'views_view__viewname__displayid' => array (
+ 'arguments' => array('view' => NULL),
+ 'template' => 'views-view--viewname--displayid',
+ 'original hook' => 'views_view',
+ 'path' => drupal_get_path('module', 'mymodule'),
+ ),
+ );
+}
+</pre>
+
+There are a small number of gotchas in doing this that you must be aware of.
+
+<ol>
+<li>When referring to a template filename, you always use dashes in the name. i.e, <em>views-view--viewname--displayid.tpl.php</em>. However, when referring to the hook or function names, you use underscores instead of dashes. i.e, <em>views_view</em> and <em>views_view__viewname__displayid</em></li>
+
+<li>The 'arguments' change based upon which of the 3 types you're overriding. There's the 'display', the 'style' and the 'row' style. The above code is assuming the display, which is usually just <em>views_view</em>. Here are the possibilities:
+
+<pre>display: array('view' => NULL),
+style: array('view' => NULL, 'options' => NULL, 'rows' => NULL, 'title' => NULL),
+row style: array('view' => NULL, 'options' => NULL, 'row' => NULL),
+</pre>
+
+Be sure to use the right arguments line or the theme system will not properly translate.
+</li>
+<li>The 'template' line should never include the extension, so drop the .tpl.php from it.</li>
+
+<li>You need to make sure that the Views preprocess functions get registered. The 'original hook' line in the definition does that, but it can only do it if it comes after the Views registration, which actually happens very late in theme building. 99% of the time, your module will come before Views. You have two choices to deal with this:
+<ol>
+ <li>Set your module's weight to 11 or higher in the database. Views' weight is 10. You can make this happen automatically when the module is first installed by creating a mymodule.install file and using this code:
+ <pre>function mymodule_install() {
+ db_query("UPDATE {system} SET weight = 11 WHERE name = 'mymodule'");
+}
+</pre>
+ If you use this method, the <em>original hook</em> should be set to the name of the original template being used. i.e, if this is a variate of views-view-list.tpl.php, this should be 'views_view_list'.
+ </li>
+ <li>You can also just force it to list the preprocessors without actually having to detect them. This doesn't require modifying your module's weight, which is not always possible, you can insert this code into the array:
+ <pre> 'preprocess functions' => array(
+ 'template_preprocess',
+ 'template_preprocess_views_view',
+ 'mymodule_preprocess_views_view__viewname_displayid',
+ ),
+</pre>
+
+ The first one is the global 'template_preprocess' function which all templates utilize. It does some basic things such as setting up $zebra and a few other items. See <a href="http://api.drupal.org/api/function/template_preprocess/6">api.drupal.org</a> for specifics.
+
+ The second one is the plugin specific preprocess. Like 'original hook' it should conform to the name used by the original template. i.e, if the original template was <em>views-view-list.tpl.php</em> then that preprocess function would be named <em>template_preprocess_views_view_list</em>.
+
+ The third one is your module's preprocess function, if it needs one. In general, you probably will not need one, and you should only attempt to use one if you are reasonably familiar with the concept of preprocess functions and Drupal's theme system in general. See Drupal's theme documentation for more information.
+ </li>
+</ol>
+</li>
+<li>
+ If you leave the path blank the template file will be searched for in "./" which is the Drupal install base path.
+</li>
+</ol>
+
diff --git a/help/api-example.html b/help/api-example.html
new file mode 100644
index 0000000..9e17100
--- /dev/null
+++ b/help/api-example.html
@@ -0,0 +1,181 @@
+<!-- $Id: api-example.html,v 1.2.4.1 2009/11/02 22:01:26 merlinofchaos Exp $ -->
+
+For the new table defined by the Node example module to be understood by the views module you need to create a node_example.views.inc file that describes the table and its relationships to the rest of the database. In order for views to know that this file is to be loaded you need to implement hook_views_api. This is done by adding the following function into your node_example.module file
+
+<pre>
+&lt;?php
+/**
+ * Implements hook_views_api().
+ *
+ * This tells drupal that there is Views integration file named
+ * module-name.views.inc
+ */
+function node_example_views_api() {
+ // Note that you can include 'path' in this array so that your views.inc
+ // file can be stored in a different location.
+ return array(
+ 'api' => 2.0
+ );
+}
+?&gt;
+</pre>
+
+Below is the contents of a simple node_example.views.inc file that allows you to create views that include the new color and quantity information.
+
+<pre>
+&lt;?php
+// $Id: api-example.html,v 1.2.4.1 2009/11/02 22:01:26 merlinofchaos Exp $
+
+/**
+ * This file is used to tell the views module about the new node_example table.
+ *
+ * Database definition:
+ * @code
+ * CREATE TABLE node_example (
+ * vid int(10) unsigned NOT NULL default '0',
+ * nid int(10) unsigned NOT NULL default '0',
+ * color varchar(255) NOT NULL default '',
+ * quantity int(10) unsigned NOT NULL default '0',
+ * PRIMARY KEY (vid, nid),
+ * KEY `node_example_nid` (nid)
+ * )
+ * @endcode
+ */
+
+function node_example_views_data() {
+ // Basic table information.
+
+ // ----------------------------------------------------------------
+ // node_example table
+ // New group within Views called 'Example'
+ // The group will appear in the UI in the dropdown tha allows you
+ // to narrow down which fields and filters are available.
+
+ $data = array();
+ $data['node_example']['table']['group'] = t('Example');
+
+ // Let Views know that our example table joins to the 'node'
+ // base table. This means it will be available when listing
+ // nodes and automatically make its fields appear.
+ //
+ // We also show up for node revisions.
+ $data['node_example']['table']['join'] = array(
+ 'node_revisions' => array(
+ 'left_field' => 'vid',
+ 'field' => 'vid',
+ ),
+ 'node' => array(
+ 'left_field' => 'vid',
+ 'field' => 'vid',
+ ),
+ );
+
+ // quantity
+ $data['node_example']['quantity'] = array(
+ 'title' => t('Quantity'),
+ 'help' => t('Quantity of items.'),
+ 'field' => array(
+ 'handler' => 'views_handler_field_numeric',
+ 'click sortable' => TRUE,
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_numeric',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ );
+
+ // Color
+ $data['node_example']['color'] = array(
+ 'title' => t('Color'),
+ 'help' => t('Color of item.'),
+
+ 'field' => array(
+ 'handler' => 'views_handler_field',
+ 'click sortable' => TRUE,
+ ),
+ 'filter' => array(
+ 'handler' => 'views_handler_filter_string',
+ ),
+ 'argument' => array(
+ 'handler' => 'views_handler_argument_string',
+ ),
+ 'sort' => array(
+ 'handler' => 'views_handler_sort',
+ ),
+ );
+
+ return $data;
+}
+
+?&gt;
+</pre>
+
+Some notes on usage:
+
+Within Views, click on the Add tab. You have a number of type options here. Normally you would select either 'Node' (if you only want to display information on current nodes) or 'Node revision' (if you want to display information on all revisions of the nodes)
+
+With this configuration you always pull out of the database, data for every single node, whether or not it has color and quantity information. To display information on just those nodes that have color and quantity information you can use a filter so that only nodes which don't have a NULL color or a NULL quantity are displayed.
+
+<h3>Type/relationship extension</h3>
+
+When your tables have first class data, you will often need to have own View types and View relationships defined. With the current node_example table this isn't required although I try to justify it below on an efficiency basis. See [[http://groups.drupal.org/node/17236#comment-58980|this discussion]] as to why it isn't justified.
+
+Pulling data out of the database for every node when you only want data for the new Example node type is inefficient. To reduce the initial data extraction to just that relating to the new Example nodes requires that you make the node_example table the base table. This can be done by adding the following code into the node_example.views.inc file just before the 'return $data;'
+
+<pre>
+&lt;?php
+
+// **** Begin optional extra for type and relationships ****
+
+ // Use node_example as a new base table
+ // by creating a new views type called 'Node example'
+ // This allows it to be selected as the 'view type'
+ // when you initially add a new view.
+ $data['node_example']['table']['base'] = array(
+ 'field' => 'vid',
+ 'title' => t('Node example'),
+ 'help' => t("Node example type with color and quantity information."),
+ 'weight' => -9,
+ );
+
+ // When using the new 'Node example' type you need to use relationships
+ // to access fields in other tables.
+
+ // Relationship to the 'Node revision' table
+ $data['node_example']['vid'] = array(
+ 'title' => t('Node revision'),
+ 'help' => t('The particular node revision the color and quantity is attached to'),
+ 'relationship' => array(
+ 'label' => t('Node revision'),
+ 'base' => 'node_revisions',
+ 'base field' => 'vid',
+ // This allows us to not show this relationship if the base is already
+ // node_revisions so users won't create circular relationships.
+ 'skip base' => array('node', 'node_revisions'),
+ ),
+ );
+
+ // Relationship to the 'Node' table
+ $data['node_example']['nid'] = array(
+ 'title' => t('Node'),
+ 'help' => t('The particular node the color and quantity is attached to'),
+ 'relationship' => array(
+ 'label' => t('Node'),
+ 'base' => 'node',
+ 'base field' => 'nid',
+ // This allows us to not show this relationship if the base is already
+ // node so users won't create circular relationships.
+ 'skip base' => array('node', 'node_revisions'),
+ ),
+ );
+
+// **** End optional extra for type and relationships ****
+
+?&gt;
+</pre>
+
+The above code adds a new 'Node example' to the view types that can be selected within the Add tab window of views. Selecting this sets the node_example table to be the base table.
+
+If you select 'Node example' as view type, when you initially go into the edit window of views you will find the only fields available are the color and quantity fields. To get fields from other tables you need to add a relationship. Relationships may be found at the top in the same column as the fields.
diff --git a/help/api-handlers.html b/help/api-handlers.html
new file mode 100644
index 0000000..b222618
--- /dev/null
+++ b/help/api-handlers.html
@@ -0,0 +1,70 @@
+<!-- $Id: api-handlers.html,v 1.4.6.2 2010/07/19 09:18:42 dereine Exp $ -->
+In Views, a handler is an object that is part of the view and is part of the query building flow.
+
+Handlers are objects; much of the time, the base handlers will work, but often you'll need to override the handler for something. One typical handler override will be views_handler_filter_operator_in which allows you to have a filter select from a list of options; you'll need to override this to provide your list.
+
+Handlers have two distint code flows; the UI flow and the view building flow.
+
+For the query flow:
+
+<dl>
+<dt>handler-&gt;construct()</dt>
+<dd>Create the initial handler; at this time it is not yet attached to a view. It is here that you can set basic defaults if needed, but there will be no knowledge of the environment yet.</dd>
+<dt>handler-&gt;set_definition()</dt>
+<dd>Set the data from hook_views_data() relevant to the handler.</dd>
+<dt>handler-&gt;init()</dt>
+<dd>Attach the handler to a view, and usually provides the options from the display.</dd>
+<dt>handler-&gt;pre_query()</dt>
+<dd>Run prior to the query() stage to do early processing.</dd>
+<dt>handler-&gt;query()</dt>
+<dd>Do the bulk of the work this handler needs to do to add itself to the query.</dd>
+</dl>
+
+Fields, being the only handlers concerned with output, also have an extended piece of the flow:
+<dl>
+<dt>handler-&gt;pre_render()</dt>
+<dd>Called prior to the actual rendering, this allows handlers to query for extra data; the entire resultset is available here, and this is where items that have "multiple values" per record can do their extra query for all of the records available. There are several examples of this at work in the code.</dd>
+<dt>handler-&gt;render()</dt>
+<dd>This does the actual work of rendering the field.</dd>
+</dl>
+
+Most handlers are just extensions of existing classes with a few tweaks that are specific to the field in question. For example:
+
+<pre>
+/**
+ * Filter by node type
+ */
+class views_handler_filter_node_type extends views_handler_filter_in_operator {
+ function get_value_options() {
+ if (!isset($this-&gt;value_options)) {
+ $this-&gt;value_title = t('Node type');
+ $types = node_get_types();
+ foreach ($types as $type =&gt; $info) {
+ $options[$type] = $info-&gt;name;
+ }
+ $this-&gt;value_options = $options;
+ }
+ }
+}
+</pre>
+
+<i>views_handler_filter_in_operator</i> provides a simple mechanism to set the list used and the rest of the handler is perfectly fine for this.
+
+Handlers are stored in their own files and loaded on demand.
+Like all other module files, they must first be registered through the module's info file. For example:
+<pre>
+name = Example module
+description = "Gives an example of a module."
+core = 7.x
+files[] = example.module
+files[] = example.install
+
+; Views handlers
+files[] = includes/views/handlers/example_handler_argument_string.inc
+</pre>
+
+The best place to learn more about handlers and how they work is to explore <a href="http://views.doc.logrus.com">the views API site</a> and use existing handlers as a guide and a model. Understanding how views_handler and its child classes work is handy but you can do a lot just following these models. You can also explore the views module directory, particularly node.views.inc.
+
+Please note that while all handler names in views are prefixed with views_, you should use your own module's name to prefix your handler names in order to ensure namespace safety. Note that the basic pattern for handler naming goes like this:
+
+[module]_handler_[type]_[tablename]_[fieldname]. Sometimes table and fieldname are not appropriate, but something that resembles what the table/field would be can be used.
diff --git a/help/api-plugins.html b/help/api-plugins.html
new file mode 100644
index 0000000..1390038
--- /dev/null
+++ b/help/api-plugins.html
@@ -0,0 +1,79 @@
+<!-- $Id: api-plugins.html,v 1.7.6.2 2010/07/28 06:58:25 dereine Exp $ -->
+In Views, a plugin is a bit like a handler, but plugins are not directly responsible for building the query. Instead, they are objects that are used to display the view or make other modifications.
+
+There are 6 types of plugins in Views:
+<dl>
+<dt>Display</dt>
+<dd>Display plugins are responsible for controlling <strong>where</strong> a view lives. Page and block are the most common displays, as well as the ubiquitous 'default' display which is likely what will be embedded.</dd>
+<dt>Style</dt>
+<dd>Style plugins control how a view is displayed. For the most part they are object wrappers around theme templates.
+<dt>Row style</dt>
+<dd>Row styles handle each individual record from a node.</dd>
+<dt>Argument default</dt>
+<dd>Argument default plugins allow pluggable ways of providing arguments for blocks. Views includes plugins to extract node and user IDs from the URL; additional plugins could be used for a wide variety of tasks.</dd>
+<dt>Argument validator</dt>
+<dd>Validator plugins can ensure arguments are valid, and even do transformations on the arguments.</dd>
+<dt>Access</dt>
+<dd>Access plugins are responsible for controlling access to the view.</dd>
+</dl>
+
+Plugins are registered by implementing <strong>hook_views_plugins()</strong> in your modulename.views.inc file and returning an array of data.
+
+The array will look something like this:
+<pre>
+ return array(
+ 'display' =&gt; array(
+ // ... list of display plugins,
+ ),
+ 'style' =&gt; array(
+ // ... list of style plugins,
+ ),
+ 'row' =&gt; array(
+ // ... list of row style plugins,
+ ),
+ 'argument default' =&gt; array(
+ // ... list of argument default plugins,
+ ),
+ 'argument validator' =&gt; array(
+ // ... list of argument validator plugins,
+ ),
+ 'access' =&gt; array(
+ // ... list of access plugins,
+ ),
+ );
+</pre>
+
+Each plugin will be registered with an identifier for the plugin, plus a fairly lengthy list of items that can define how and where the plugin is used. Here is an example from Views core:
+
+<pre>
+ 'node' =&gt; array(
+ 'title' =&gt; t('Node'),
+ 'help' =&gt; t('Display the node with standard node view.'),
+ 'handler' =&gt; 'views_plugin_row_node_view',
+ 'path' =&gt; drupal_get_path('module', 'views') . '/modules/node', // not necessary for most modules
+ 'theme' =&gt; 'views_view_row_node',
+ 'base' =&gt; array('node'), // only works with 'node' as base.
+ 'uses options' =&gt; TRUE,
+ 'type' =&gt; 'normal',
+ ),
+</pre>
+
+Of particular interest is the <em>path</em> directive, which works a little differently from handler registration; each plugin must define its own path, rather than relying on a global info for the paths. For example:
+
+<pre>
+ 'feed' =&gt; array(
+ 'title' =&gt; t('Feed'),
+ 'help' =&gt; t('Display the view as a feed, such as an RSS feed.'),
+ 'handler' =&gt; 'views_plugin_display_feed',
+ 'uses hook menu' =&gt; TRUE,
+ 'use ajax' =&gt; FALSE,
+ 'use pager' =&gt; FALSE,
+ 'accept attachments' =&gt; FALSE,
+ 'admin' =&gt; t('Feed'),
+ 'help topic' =&gt; 'display-feed',
+ ),
+</pre>
+
+Please be sure to prefix your plugin identifiers with your module name to ensure namespace safety; after all, two different modules could try to implement the 'grid2' plugin, and that would cause one plugin to completely fail.
+
+...TODO: Finish this document....
diff --git a/help/api-tables.html b/help/api-tables.html
new file mode 100644
index 0000000..288c4dd
--- /dev/null
+++ b/help/api-tables.html
@@ -0,0 +1,235 @@
+<!-- $Id: api-tables.html,v 1.8.4.3 2010/10/12 21:21:02 merlinofchaos Exp $ -->
+Tables are described to Views via hook_views_data(), which returns an array of table information, keyed by the name of the table. For example, if your module is describing three tables, 'foo', 'bar' and 'baz', your array will look like this:
+<pre>$data = array(
+ 'foo' =&gt; array(
+ // ...info here...
+ ),
+ 'bar' =&gt; array(
+ // ...info here...
+ ),
+ 'baz' =&gt; array(
+ // ...info here...
+ ),
+);
+</pre>
+
+The key should be the actual database name of the table (not including prefix), but it can be an alias as long as the join information (explained later) contains the real name of the table.
+
+Each item in the array should be a field in the table, with the exception of a special information section called 'table'. Example:
+
+<pre>$data['foo'] = array(
+ 'table' =&gt; array(
+ // ... info about the table, described later ...
+ ),
+ 'bar' =&gt; array(
+ // ... info about the field named 'bar', i.e, foo.bar,
+ ),
+ 'baz' =&gt; array(
+ // ... info about the field named 'baz', i.e, foo.baz,
+ ),
+);
+</pre>
+
+Once you get down to an array that contains actual data, that piece of the array will often be referred to as the definition.
+
+<h2>The 'table' section</h2>
+Each table should have a 'table' section in it, which is used to set default information for the table, such as the group, as well as the very important joins and whether or not this is a base table.
+
+First, there are several items that are actually for fields but can be placed here so that all fields within the table inherit them:
+<dl>
+<dt>group</dt>
+<dd>The name of the group this item will be with. In the UI, this is displayed as Group: Title. For example, "Node: Node ID", "Taxonomy: Term description", etc. It is important to be consistent with groups, because the UI sorts by group, and allows filtering by group to find fields as well.</dd>
+<dt>title</dt>
+<dd>The actual name of the field; it should be concise and descriptive.</dd>
+<dt>help</dt>
+<dd>A longer description to help describe what the field is or does. It should try to be only a line or two so as not to clutter the UI.</dd>
+</dl>
+
+In general, having 'title' and 'help' at the table level doesn't make a lot of sense, but usually every item in a table is in the same group. Thus it is very common to define the 'group':
+
+<pre>
+ $data['foo']['table']['group'] = t('Foo');
+</pre>
+
+<h3>Base table</h3>
+If your table is a base table -- meaning it can be the primary, central table for a View to use, you can declare it to be a base table. This primarily provides UI information so that it can be selected.
+For example:
+<pre>
+ // Advertise this table as a possible base table
+ $data['node']['table']['base'] = array(
+ 'field' =&gt; 'nid',
+ 'title' =&gt; t('Node'),
+ 'help' =&gt; t("Nodes are a Drupal site's primary content."),
+ 'weight' =&gt; -10,
+ );
+</pre>
+
+The following tags are available in the
+<dl>
+<dt>field</dt>
+<dd>The primary key field for this table. For Views to treat any table as a base table, it <b>must</b> have a primary field. For node this is the 'nid', for users this is the 'uid', etc. <strong>Without a single primary key field (i.e. not a composite key), Views will not be able to utilize the table as a base table.</strong> If your table does not have a primary key field, it is not too difficult to just add a serial field to it, usually.</dd>
+<dt>title</dt>
+<dd>The title of this table in the UI. It should be singular and describe the object that this table contains from the perspective of the user.</dd>
+<dt>help</dt>
+<dd>A short piece of text to describe what object this table contains.</dd>
+<dt>database</dt>
+<dd>If this table is held in a different database from your Drupal database, specify it as a string in the exact same format as the settings.php file. This is a special purpose variable that will probably be only used in site specific code, and <b>it must be the same database type as your Drupal database</b>. Also, don't try to join it to any table that isn't in the same database. That'll just create all kinds of silly errors. For example:
+<pre>
+ // In settings.php for your site
+ // Your drupal (site) database needs to be called 'default'
+ $db_url['default'] = 'mysqli://user:pass@host/drupal_db';
+ $db_url['budget'] = 'mysqli://user:pass@host/other_db';
+</pre>
+Then when you are describing the external database in your base table you would write something like this:
+<pre>
+ $data[$table]['table']['base'] = array(
+ 'field' => 'Primary key',
+ 'title' => t('Field name'),
+ 'help' => t('Field description'),
+ 'database' => 'budget',
+ 'weight' => -10,
+ );
+</pre>
+</dd>
+</dl>
+
+<h3>Linking your table to existing base tables</h3>
+For Views to use your table, it has to either be a base table, or know how to link to an existing base table. Or sometimes both. Views uses this information to create a path to the base table; when the table is added to the query, Views will walk along this path, adding all tables required into the query.
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/node-term_node-term_data-large.png"><img src="path:images/node-term_node-term_data.png" /></a>
+<em>How taxonomy_term_data joins to node</em>
+</div>
+
+In the above example, to use these with 'node' as the base table, both 'taxonomy_term_data' and 'term_node' need to be defined, and they each need a join handler for node:
+
+<pre>
+$data['taxonomy_term_data']['table']['join']['node'] = array(
+ 'left_table' =&gt; 'term_node',
+ 'left_field' =&gt; 'tid',
+ 'field' =&gt; 'tid',
+);
+</pre>
+
+The above can be read as "In order to join to the node table, the taxonomy_term_data table must first link to the term_node table, and they join on the 'tid' field.". When adding this table to the query for a node view, Views will look at this and then look for the term_node table.
+
+<pre>
+$data['term_node']['table']['join']['node'] = array(
+ 'left_field' =&gt; 'nid',
+ 'field' =&gt; 'nid',
+);
+</pre>
+
+Above, the fact that 'left_table' is left out lets us know that term_node links directly to the node table, using the 'nid' field on both sides of the join.
+
+Quite a few more fields are available in this definition:
+<dl>
+ <dt>handler</dt>
+ <dd>The name of the handler object to use. Defaults to 'views_join'. You may create custom join handlers that may or may not use any of the data below, as they see fit.</dd>
+ <dt>table</dt>
+ <dd>Table to join. This is optional, and should only be used if the table being referenced is an alias.</dd>
+ <dt>field</dt>
+ <dd>Field to join on. This is required.</dd>
+ <dt>left_table</dt>
+ <dd>The next step toward the final destination. If this is the final destination it may be omitted.</dd>
+ <dt>left_field</dt>
+ <dd>The field to join to on the left side. This is required.</dd>
+ <dt>type</dt>
+ <dd>Either LEFT (default) or INNER.</dd>
+ <dt>extra</dt>
+ <dd>Either a string that's directly added, or an array of items. Each item is, itself, an array:
+ <dl>
+ <dt>field</dt>
+ <dd>Field or formula</dd>
+ <dt>operator</dt>
+ <dd>Similar to filters, this is the operator, such as &gt;, &lt;, =, etc. Defaults to = or IN.</dd>
+ <dt>value</dt>
+ <dd>Must be set. If an array, operator will be defaulted to IN.</dd>
+ <dt>numeric</dt>
+ <dd>If true, the value will not be surrounded in quotes, and %d will be used for its placeholder.</dd>
+ </dl>
+ </dd>
+ <dt>extra type</dt>
+ <dd> How all the extras will be combined. Either AND or OR. Defaults to AND.</dd>
+</dl>
+
+<h2>Describing fields on tables</h2>
+Aside from the special table tag, each table can also have an unlimited number of field designations; these correspond roughly to fields on the table, though it is very common to use non-fields to display data that isn't directly in a field, such as data arrived from formulae, or special links related to the object the table is part of.
+
+Each field is described in the view data with an array, keyed to the database name of the field. This array may contain some information fields, plus an entry in each of the five types of items Views has per field: argument, field, filter, relationship, sort. For example:
+
+<pre>
+$data['node']['nid'] = array(
+ 'title' =&gt; t('Nid'),
+ 'help' =&gt; t('The node ID of the node.'), // The help that appears on the UI,
+ // Information for displaying the nid
+ 'field' =&gt; array(
+ 'handler' =&gt; 'views_handler_field_node',
+ 'click sortable' =&gt; TRUE,
+ ),
+ // Information for accepting a nid as an argument
+ 'argument' =&gt; array(
+ 'handler' =&gt; 'views_handler_argument_node_nid',
+ 'name field' =&gt; 'title', // the field to display in the summary.
+ 'numeric' =&gt; TRUE,
+ 'validate type' =&gt; 'nid',
+ ),
+ // Information for accepting a nid as a filter
+ 'filter' =&gt; array(
+ 'handler' =&gt; 'views_handler_filter_numeric',
+ ),
+ // Information for sorting on a nid.
+ 'sort' =&gt; array(
+ 'handler' =&gt; 'views_handler_sort',
+ ),
+);
+</pre>
+
+The above example describes the 'nid' field on the 'node' table, providing 4 of the 5 handlers. Note that while field is normally expected to be the database name of the field, it doesn't have to be; you can use an alias (which is how you get multiple handlers per field) or something completely made up for items that aren't tied to the database. For example:
+
+<pre>
+$data['node']['edit_node'] = array(
+ 'field' =&gt; array(
+ 'title' =&gt; t('Edit link'),
+ 'help' =&gt; t('Provide a simple link to edit the node.'),
+ 'handler' =&gt; 'views_handler_field_node_link_edit',
+ ),
+);
+</pre>
+
+The above handler definition an edit link to a node, but this isn't a field in and of itself. For aliased fields, here is another example:
+
+<pre>
+$data['users']['uid_current'] = array(
+ 'real field' =&gt; 'uid',
+ 'title' =&gt; t('Current'),
+ 'help' =&gt; t('Filter the view to the currently logged in user.'),
+ 'filter' =&gt; array(
+ 'handler' =&gt; 'views_handler_filter_user_current',
+ ),
+);
+</pre>
+
+The above definition provides an alternate filter handler on the uid field for the current user.
+
+The following items are allowed in the field definition:
+
+<dl>
+<dt>group, title, help</dt>
+<dd>As above, these fields are for the UI. If placed here, any of these fields will override a setting on the base table.</dd>
+<dt>real field</dt>
+<dd>If this field is an alias, the "real field" may be placed here, and the handler will never know the difference.</dd>
+
+<dt>field</dt>
+<dd>A handler definition for the "Field" section, which is a field that may be displayed in a view. The definition is an array; the contents of the array are completely up to the handler, other than the 'handler' definition. If omitted, handler will default to 'views_handler_field'.</dd>
+<dt>filter</dt>
+<dd>A handler definition for the "Filters" section, which will be used to apply WHERE clauses to the view. The definition is an array; the contents of the array are completely up to the handler, other than the 'handler' definition. If omitted, handler will default to 'views_handler_filter'.</dd>
+<dt>sort</dt>
+<dd>A handler definition for the "Sort criteria" section, which will be used to add an ORDER BY clause to the view. The definition is an array; the contents of the array are completely up to the handler, other than the 'handler' definition. If omitted, handler will default to 'views_handler_sort'.</dd>
+<dt>relationship</dt>
+<dd>A handler definition for the "Field" section, which is a way to bring in new or alternative base tables in the view. The definition is an array; the contents of the array are completely up to the handler, other than the 'handler' definition. If omitted, handler will default to 'views_handler_relationship'. The basic relationship handler requires 'base' and 'base field' to be set; 'base' and 'base field' represent the "right" half of the join that will use this field as the left side.</dd>
+<dt>argument</dt>
+<dd>A handler definition for the "Field" section, which is method of accepting user input from the URL or some other source. The definition is an array; the contents of the array are completely up to the handler, other than the 'handler' definition. If omitted, handler will default to 'views_handler_argument'.</dd>
+</dl>
+
+For more information about what handlers need/use what data, visit <a href="http://views.doc.logrus.com">the Views API site</a> and check out the available handlers.
diff --git a/help/api-upgrading.html b/help/api-upgrading.html
new file mode 100644
index 0000000..c106f8e
--- /dev/null
+++ b/help/api-upgrading.html
@@ -0,0 +1,37 @@
+<!-- $Id: api-upgrading.html,v 1.1.2.3 2010/11/05 07:20:54 dereine Exp $ -->
+In order to take advantage of the changes in Drupal 7, Views has gone through several API changes.
+Here's what you should know.
+
+<h3>Handler registry</h3>
+
+Views now uses Drupal's dynamic-loading code registry.
+You can safely remove your implementations of hook_views_handlers(), since they are no longer used.
+
+Please remember to specify the handlers in your module's .info file. For example:
+<pre>
+name = Example module
+description = "Gives an example of a module."
+core = 7.x
+files[] = example.module
+files[] = example.install
+
+; Views handlers
+files[] = includes/views/handlers/example_handler_argument_string.inc
+</pre>
+
+<h3>Removed handlers</h3>
+
+Note that views_handler_filter_float has been removed.
+This functionality is now handled by views_handler_filter_numeric.
+There's no need for having a special handler any more, thanks to the new DB layer in Drupal 7.
+
+<h3>Ctools dependency</h3>
+Views requires ctools now, so it can use the dependency system of ctools.
+The only thing you have to do is to replace
+<pre>
+'#process' => array('views_process_dependeny')
+</pre>
+with
+<pre>
+'#process' => array('ctools_dependent_process'),
+</pre> \ No newline at end of file
diff --git a/help/api.html b/help/api.html
new file mode 100644
index 0000000..8cf3764
--- /dev/null
+++ b/help/api.html
@@ -0,0 +1,23 @@
+<!-- $Id: api.html,v 1.5.6.1 2009/11/02 22:01:26 merlinofchaos Exp $ -->
+Views allows modules to describe their tables relationships to each other, as well as fields, filters, sort criteria and arguments via <strong>hook_views_data()</strong>. Whenever Views deems it necessary, this hook is called, the data aggregated together and cached. <strong>hook_views_data_alter()</strong> may also be used to modify existing data, changing other module's handlers or adding handlers to other module's tables.
+
+Views also allows modules to create new display types, style types, row styles, argument default handlers and argument validators via <strong>hook_views_handlers()</strong> and <strong>hook_views_plugins()</strong>.
+
+These hooks are kept in a file named MODULENAME.views.inc. This file is automatically included upon need, so there is no need to try and include this in hook_init or any other method of including .inc files. This file should store hook_views_data, hook_views_data_alter(), hook_views_plugins(), hook_views_handlers(), as well as any other hooks and subsidiary data that will only be used by your module when Views is active. All handlers and plugins provided by your module should be in separate .inc files.
+
+There are two similar files, MODULENAME.views_default.inc and MODULENAME.views_convert.inc which contain default views and views 1 to views 2 convert helpers, respectively.
+
+<h3>hook_views_api()</h3>
+<strong>In order for your files to be included, your module must first implement hook_views_api()</strong> in the main .module file. This module should return array of information. The following items may be returned:
+
+<dl>
+<dt><strong>api</strong></dt>
+<dd>This must appear; it should be the oldest API version that your module can work with. If Views is currently running an older version of the API, it will ignore your module's views integration. This is a good thing, as it will prevent code crashes, at the expense of your module's functionality disappearing.
+<br />
+You may find the current Views API version by calling <strong>views_api_version()</strong> which is implemented at the top of views.module. This version numbering starts at 2.0. Every time changes are made to the Views handlers and plugins or other aspects of the Views API, the number will tick up (by either .001, .01 .1 or 1 depending upon how major the changes are). Note that <strong>views_api_version()</strong> was introduced in Views 2.0-rc2 and may not exist prior to that version. You may use drupal_function_exists() to test to see if this function is there.
+<br />
+Often these versions are basically compatible with each other and Views won't care if your module implements 2.000, 2.001, 2.002, etc. Your module can request that it won't work with any version older than a given version, however. Views will determine, itself, if a newer version will work.
+</dd>
+<dt><strong>path</strong></dt>
+<dd>If your *.views*.inc files are not in the same directory as the .module file, then return the full path here. You should probably use something like drupal_get_path('module', 'yourmodulename') . '/includepath'.</dd>
+</dl>
diff --git a/help/argument.html b/help/argument.html
new file mode 100644
index 0000000..992f62d
--- /dev/null
+++ b/help/argument.html
@@ -0,0 +1,58 @@
+<!-- $Id: argument.html,v 1.8.6.1 2010/03/19 23:03:13 merlinofchaos Exp $ -->
+Arguments are input. While they often come from the URL, <strong>they don't always</strong> so please don't be shocked when they don't. Each display type may have its own source for arguments. Block displays have no source of arguments at all; they cannot pull arguments from the URL, and often require use of the default argument PHP code in order to get arguments. The argument default plugins can be used to get arguments into a block view. See "Provide default", below.
+
+In general, arguments are used to filter the view, and in that sense they have a very close relationship to filters, but that isn't necessarily true for every argument. Arguments can be used for any purpose, really; the extent of what the argument does is up to the developer of the argument, but the arguments that come with Views are almost entirely filters.
+
+A typical use of an argument might be to reduce a view to a single node, a single user, or nodes with a given taxonomy term.
+
+<h3>Action to take if argument is not present</h3>
+<dl>
+<dt>Ignore</dt>
+<dd>The argument is removed from the view as though it weren't there and all results will be displayed.</dd>
+
+<dt>Hide view / Page not found</dt>
+<dd>The view will remove itself entirely if the argument is not present; for a block this means it simply won't appear. For page views the View will return a 404 and present a "Page not found" error. </dd>
+
+<dt>Display empty text</dt>
+<dd>The value of the <a href=topic:views/empty-text>empty text</a> will be displayed.</dd>
+
+<dt>Summary</dt>
+<dd>The view will attempt to display a summary of arguments available, based upon the view, and provide links to the view with those arguments. Summaries have their own style handlers as well as options. The default summary style simply displays a list of arguments with a count of entries found per argument. This special mode is a very powerful part of Views.</dd>
+
+<dt>Provide default</dt>
+<dd>If no argument is given, a default argument can be selected. The method of choosing the default argument is selectable and pluggable.</dd>
+</dl>
+
+<h3>Wildcards</h3>
+All arguments have a 'wildcard', which is an argument that means to use all values. In practice, it is the same as 'Ignore' above, where the argument is simply removed and the view is created without the argument. The wildcard title is used in titles and breadcrumb trails.
+<h3>Default arguments</h3>
+Default argument selection is available <strong>only if the action to take is "Provide default"</strong>. When that is selected, a new fieldset will appear letting you choose what the default argument will be. Views provides the following default selectors by default (but other modules may add more):
+<dl>
+<dt>Fixed entry </dt>
+<dd>You may directly enter what the argument will be. This is not a variable, it will always be the same argument. </dd>
+<dt>Node ID from URL</dt>
+<dd>This will attempt to find a Node ID from the URL, and is primarily useful for the Node: ID argument (though other arguments that use Node IDs, such as the CCK Node Reference argument, will find it useful too). For example, when visiting the path 'node/1' or 'node/1/edit' it will know that the '1' in that path is a node ID and use it.</dd>
+<dt>User ID from URL</dt>
+<dd>Like Node ID from URL, this will attempt to find a user ID from the path. It also includes an option to look for a node and use the node author as the user ID.</dd>
+<dt>User ID from logged in user</dt>
+<dd>You can use this to easily default a menu item to the logged in user. For example, if you created the path 'blogs' and gave it a User: ID argument with this default, 'blogs' would go to the user's own blogs, and blogs/1 would go to User ID 1's blogs.</dd>
+</dl>
+
+Please bear in mind that the selection of default argument happens only if an argument is not provided. If using a display that has no argument source, such as a block, this will always be used. However, if using a display that reads arguments from the URL, this will happen only if the URL did not contain an argument.
+<h3>Argument validation</h3>
+Arguments can also have validators, which are pluggable systems used to ensure that arguments fit within certain parameters. When a validator is chosen, it may provide some settings for the validator, including the action to take if an argument is presented, but it fails to validate. These actions are generally the same as the default actions above, excluding the ability to provide another default.
+
+If a view provides a menu option, such as a tab, if the argument does not validate the tab will not appear.
+
+This sytem can have other validators plugged in; by default, Views provides:
+<dl>
+<dt>Basic validation</dt>
+<dd>Ensures that the argument is present. A PHP NULL value (from eg. PHP default argument code) will invalidate.</dd>
+<dt>Node</dt>
+<dd>Ensure that the argument is a valid Node ID. You may select which types of node the validator will accept.</dd>
+<dt>Taxonomy term</dt>
+<dd>Ensure that the argument is a valid taxonomy term. This includes options to limit to specific vocabularies and can transform the argument to the right type depending upon the actual argument. Set the Argument Type option to the actual type of data that the argument being used is expecting.</dd>
+<dt>PHP Code</dt>
+<dd>You may enter arbitrary PHP code, similar to the php block visibility code, to determine if the argument is valid or not.</dd>
+
+</dl>
diff --git a/help/display-attachment.html b/help/display-attachment.html
new file mode 100644
index 0000000..3a682ed
--- /dev/null
+++ b/help/display-attachment.html
@@ -0,0 +1,2 @@
+<!-- $Id: display-attachment.html,v 1.2 2008/04/29 00:35:07 merlinofchaos Exp $ -->
+Attachment displays are 'attached' to another display in the same view. When the display is visited, the attached display will also be rendered and may be placed before, after or both before and after the original display. Attachment displays are often useful for displaying an argument summary view along with a page display that accepts arguments. This can be used to provide a kind of glossary. \ No newline at end of file
diff --git a/help/display-block.html b/help/display-block.html
new file mode 100644
index 0000000..713c6ef
--- /dev/null
+++ b/help/display-block.html
@@ -0,0 +1,11 @@
+<!-- $Id: display-block.html,v 1.5 2008/10/14 17:06:02 merlinofchaos Exp $ -->
+Block displays will show up on your blocks administration page. Once a block display is created and saved, it can be enabled and positioned in your theme by visiting <strong>administer &gt;&gt; site building &gt;&gt; blocks</strong> and selecting it from the list.
+
+Blocks <strong>do not</strong> accept arguments from any source; the only way to get arguments to a block is to provide defaults to it, possibly via the PHP Code default setting.
+
+<ul>
+<li>Edit the argument in question; you may want to override this argument if you have multiple displays using it.</li>
+<li>Change the "Action to take if argument is not present" to "Provide default argument". This will bring up a new box called "Provide default argument options".</li>
+<li>The most common default argument type used for blocks is Node from URL, where it attempts to determine if the URL refers to a node, for example if visiting 'node/1' or 'node/1/edit'. User ID from URL is also very common.</li>
+<li>If you change the default argument type to 'PHP Code' (note: You must have permission to use PHP code on your site) you can enter PHP to define the argument needed. Simply return the argument.</li>
+</ul>
diff --git a/help/display-default.html b/help/display-default.html
new file mode 100644
index 0000000..c50b503
--- /dev/null
+++ b/help/display-default.html
@@ -0,0 +1,5 @@
+<!-- $Id: display-default.html,v 1.2 2008/04/29 00:35:07 merlinofchaos Exp $ -->
+The default display is primarily a display to store settings, and isn't actually used anywhere within the Views system. It is possible for external programs to use the default display, but if they do they will (hopefully) tell you which display they will be working with. The default display is also a convenient display to use to embed into your site using PHP snippets; this is useful, for example, in node content, but this is something that should generally only be done by administrators.
+
+In general, you probably want to add either a <a href="topic:views/display-page">page display</a> or a <a href="topic:views/display-block">block display</a>.
+
diff --git a/help/display-feed.html b/help/display-feed.html
new file mode 100644
index 0000000..690d640
--- /dev/null
+++ b/help/display-feed.html
@@ -0,0 +1,2 @@
+<!-- $Id: display-feed.html,v 1.2 2008/05/05 05:09:36 merlinofchaos Exp $ -->
+A feed display allows you to attach an RSS feed to a view. \ No newline at end of file
diff --git a/help/display-page.html b/help/display-page.html
new file mode 100644
index 0000000..1ea3338
--- /dev/null
+++ b/help/display-page.html
@@ -0,0 +1,6 @@
+<!-- $Id: display-page.html,v 1.3.6.1 2010/03/25 20:31:11 merlinofchaos Exp $ -->
+Page displays have a <a href="topic:views/path">path</a> and an optional <a href="topic:views/menu">menu</a> component. Page displays will be the primary content for the page, meaning they will be displayed in the main content area when you visit the URL that corresponds to the path.
+
+Page displays take their arguments from the URL. You can embed arguments into the URL using %; in previous versions of Views, this was '$arg'. For example, 'node/%/foo' will accept URLs such as 'node/1/foo'.
+
+Please remember that using a % placeholder makes the argument required. If you wish to have an optional argument, simply omit the % from the path. I.e. using "page/%" as the path requires an argument and visiting 'http://www.example.com/page' will not trigger the view. \ No newline at end of file
diff --git a/help/display.html b/help/display.html
new file mode 100644
index 0000000..d48ee40
--- /dev/null
+++ b/help/display.html
@@ -0,0 +1,8 @@
+<!-- $Id: display.html,v 1.2.6.1 2010/03/19 23:03:13 merlinofchaos Exp $ -->
+Displays tell Views where the output should go. By adding a display to a View, you can have your view appear as a page, or as a block, or even as an attachment to a different display on the view.
+
+Each display can have its own settings, but when it's created, a display will take all of its <em>basic settings</em> from the <strong>default display</strong> which all Views must have. For most settings, there is an <strong>override</strong> button that will override that single setting for the current display. Overridden settings will have a mark in the summary for that display. All 'default display settings' are shown in the other displays '<i>italic</i>'. When you override a setting, than it is shown 'normal'.
+
+Please keep in mind that when you are editing a setting on a display that is not overridden, then by default you are editing that for all displays.
+
+For <strong>fields</strong>, <strong>arguments</strong>, <strong>sorts</strong>, <strong>filters</strong> and <strong>relationships</strong>, you can only override <em>all</em> of them or none of them. To do this, click on the header for the filters or the rearrange button. Once you override, the display will then have its own copies of the fields/filters/etc and changes to the defaults will not be reflected on your display. \ No newline at end of file
diff --git a/help/embed.html b/help/embed.html
new file mode 100644
index 0000000..f66ecc4
--- /dev/null
+++ b/help/embed.html
@@ -0,0 +1,25 @@
+<!-- $Id: embed.html,v 1.1 2008/06/13 00:56:19 merlinofchaos Exp $ -->
+You can easily embed the results of a view into other parts of your site;
+either with code as a module, or in nodes or blocks as snippets. The
+easiest way is to use the function <strong>views_embed_view()</strong>:
+
+<code>/**
+ * Embed a view using a PHP snippet.
+ *
+ * This function is meant to be called from PHP snippets, should one wish to
+ * embed a view in a node or something. It's meant to provide the simplest
+ * solution and doesn't really offer a lot of options, but breaking the function
+ * apart is pretty easy, and this provides a worthwhile guide to doing so.
+ *
+ * @param $name
+ * The name of the view to embed.
+ * @param $display_id
+ * The display id to embed. If unsure, use 'default', as it will always be
+ * valid. But things like 'page' or 'block' should work here.
+ * @param ...
+ * Any additional parameters will be passed as arguments.
+ */
+function views_embed_view($name, $display_id = 'default') {
+</code>
+
+To figure out the id of a display, hover your mouse over the tab to select that display. Everything after the '#views-tab-' is the id of that display. This ID is guaranteed never to change unless you delete the display and create a new one.
diff --git a/help/example-author-block.html b/help/example-author-block.html
new file mode 100644
index 0000000..e8c11e1
--- /dev/null
+++ b/help/example-author-block.html
@@ -0,0 +1,78 @@
+<!-- $Id: example-author-block.html,v 1.1.6.2 2010/08/13 22:22:28 merlinofchaos Exp $ -->
+<p>In this example you will create a context-sensitive block that shows the titles of recent blog entries by an author when viewing one of their posts. This will demonstrate using Views <em>arguments</em> to dynamically filter a view's contents at display time.</p>
+
+<p>Before working through this example, enable the <strong>Blog</strong> module and populate some entries from a few different users.</p>
+
+<h3>Creating the View</h3>
+<p>The first step is creating a view for our recent blog entries block. Because the block will show the titles of blog entries, this view is considered a "Node" type. Go to <a target="_blank" href="/admin/structure/views/add">add new view</a>, enter the following properties, and click <strong>Next</strong>:</p>
+
+<dl>
+ <dt>View name</dt>
+ <dd>recent_blog_entries</dd>
+ <dt>View description</dt>
+ <dd>List of recent blog entries for a given author.</dd>
+ <dt>View tag</dt>
+ <dd>blog</dd>
+ <dt>View type</dt>
+ <dd>Node</dd>
+</dl>
+
+<h3>Generating a list of blog entries</h3>
+<p>It will be much easier to see the view progress if we can see it doing something. In this section, we will create a basic view displaying blog entry titles.</p>
+
+<ol>
+<li>In the third column, locate the <strong>Fields</strong> area. Generally speaking, fields are the pieces of information that you want to display in the view (in this case, node title). Click the <strong>+</strong> icon to add a field.</li>
+<li>Scroll down to <strong>Defaults: Add fields</strong>, below the settings table. A large selection of fields will be available.</li>
+<li>In the <strong>Groups</strong> drop-down menu, select <em>Node</em>. This will limit the list to only the default fields exposed by Node module.</li>
+<li>Scroll down the list, select the <em>Node: Title</em> field, and click <strong>Add</strong>.</li>
+<li>You will now be presented with settings for the <em>Node: Title</em> field. Delete the label from the <strong>Label</strong> field, so that each individual node title is not prefixed with the word "Title." Additionally, check the <em>Link this field to its node</em> box so that visitors who see an interesting title can click directly on it to read the blog entry to which it belongs.</li>
+<li>When finished, click <strong>Update</strong>. If you scroll down to the <strong>Live Preview</strong> section, you should now see a list of several node titles; however both blog entries and other node types will be in the list. Let's fix that.</li>
+<li>In the fourth column, locate the <strong>Filters</strong> area. Filters limit the results displayed in the view, and we can use this to our advantage here by showing node titles only from blog entries and not every type of node. Click the <strong>+</strong> icon to add a filter.</li>
+<li>As before, scroll down to the <strong>Defaults: Add filters</strong> section, select <em>Node</em> from the <strong>Groups</strong> select box to limit the list of options to only those exposed by Node module.</li>
+<li>Scroll down and select the <em>Node: Type</em> field and click <strong>Add</strong>. In the settings page that appears, leave <strong>Operator</strong> as <em>Is one of</em> and select <em>Blog entry</em> under <strong>Node type</strong>. Click <strong>Update</strong> when finished.</li>
+<li>Now, by scrolling down to <strong>Live preview</strong>, you'll see that the list only shows blog entries.</li>
+</ol>
+
+<h3>Adding context with arguments</h3>
+<p>While filters are very useful for limiting the results of a view when the condition is always consistent (for example, a view of blog entry nodes should <em>always</em> be filtered by the blog entry type), something filters can't do is smart decision-making based on the page context. In our case, we want the view to display a different list of blog entries when looking at a post by user 'admin' than we do when looking at a post by user 'member', and filters won't be able to help.</p>
+
+<p>Luckily, there's another way to filter a view's content: <em>arguments</em>. Through arguments, Views are able to obtain additional context (typically via dynamic URLs with IDs in them) and can take this context into consideration when displaying the view.</p>
+
+<p>Let's walk through adding and configuring an argument to our view so that we can change its contents based on post author.</p>
+
+<ol>
+<li>In the third column, locate the <strong>Arguments</strong> area. Click the <strong>+</strong> icon to add an argument.</li>
+<li>Because we are basing the view around content <em>authors</em>, this time under <strong>Groups</strong> select <em>User</em>. Check <em>User: Uid</em> and click <strong>Add</strong>.</li>
+<li>The <strong>Defaults: Configure Argument User: Uid</strong> settings page has a lot going on, but only a few things that need our attention.</li>
+<li>The <strong>Title</strong> field here, unlike the Title field under <em>Basic Settings</em>, can be based upon the context that the view is being displayed in. Change the title to 'Recent entries by %1.' %1 will later be expanded to the user's name (based on the User: Uid argument) when the view is displayed.</li>
+<li>Under <strong>Action to take if argument is not present</strong>, there are a variety of options, ranging from displaying a 404 or a 403 page to simply displaying all values in the view. In our case, if an argument isn't specified (which it won't be, since this view will be displayed in a sidebar block, not as a page with its own URL), we want to give it a default one to act on. Select <em>Provide default argument</em>.</li>
+<li>Assuming JavaScript is enabled in your browser, you should now get another selection for <strong>Default argument type</strong>. Select <em>User ID from URL</em>. This will cause Views to first see if it can figure out a user ID from the current URL (for example, user/1). If it can't, it will instead check to see if the current page is a node page (such as node/42) and, if so, take the user ID from the node's author field instead.</li>
+<li><strong>Validator options</strong> provide a useful way to control what kind of arguments your view will accept. Select <em>User</em> as the <strong>Validator</strong>. By default, changing this setting will check the incoming argument and ensure it's a valid user ID; if not, the view will be hidden from the page.</li>
+<li>Once you have changed the argument's title, default argument, and validator options, click <strong>Update</strong> to save your changes.</li>
+<li>You'll notice that now the Live preview no longer shows anything. Did we just break the view? Fortunately, no. It's merely abiding by our wishes to hide itself if there is no valid user ID given to it. Try entering a '1' in the <strong>Arguments</strong> box and clicking <strong>Preview</strong>. You should now see a list of only user 1's blog entries.</li>
+</ol>
+
+<h3>Creating the block</h3>
+<p>So the live preview is now showing basically what we want. There's just one problem: we have no way to stick what we've done so far into a sidebar block! Let's fix that by adding a new <strong>Display</strong>.</p>
+
+<ol>
+<li>In the first column, under <strong>Defaults</strong>, there is a select box containing entries such as <em>Page</em>, <em>Feed</em>, and, yes, <em>Block</em>! Select <em>Block</em> and click <strong>Add display</strong>.</li>
+<li>There's not much else to do here as far as Views is concerned. Under <strong>Block settings</strong>, click the <em>None</em> link next to <strong>Admin</strong> and fill in a description for the block in the administrative interface, such as: 'Recent blog entries by author.' and click <strong>Update</strong>.</li>
+<li>Save your work by clicking the <strong>Save</strong> button at the bottom of the Views interface. You should receive a message that the view has been saved.</li>
+<li>Next, navigate to the <a target="_blank" href="/admin/build/block">blocks interface</a> and drag the 'Recent blog entries by author' block to the right sidebar region (or similar) and click <strong>Save blocks</strong>.</li>
+<li>You'll notice this appeared to do nothing. No block shows in the sidebar. But remember, we are looking at an adminitrative page; we are not looking at a page that would provide a user ID context. Navigate to the <a target="_blank" href="/blog">main blog listing</a> and click on an entry there. You should now see a sidebar block, titled something like "Recent entries by admin," with a list of blog entries beneath it.</li>
+</ol>
+
+<h3>Finishing touches</h3>
+<p>There are still a few remaining things to do before our view is complete. For example, we said that the block was to show <em>recent</em> blog entries, but instead it's showing them in the order they were entered, with oldest on top. Additionally, even unpublished entries are showing in the list currently.</p>
+
+<ol>
+<li>Return to the <a target="_blank" href="/admin/structure/views/edit/recent_blog_entries">recent_blog_entries view edit page</a>.</li>
+<li>Add an additional filter by clicking the <strong>+</strong> icon in the <strong>Filters</strong> section in the fourth column.</li>
+<li>Change <strong>Groups</strong> to <em>Node</em> and select <em>Node: Published</em>. Click <strong>Add</strong>.</li>
+<li>Under the <strong>Published</strong> selection, choose <em>Yes</em> and click <strong>Update</strong>.</li>
+<li>To handle sorting, locate the <strong>Sort criteria</strong> area, just above filters, and click the <strong>+</strong> icon there.</li>
+<li>Under <strong>Groups</strong>, again select <em>Node</em>. From the list of options, check <em>Node: Post date</em> and click <strong>Add</strong>.</li>
+<li>In the settings page, change <strong>Sort order</strong> to <em>Descending</em>. This will place the newer posts on top of the older ones. Click <strong>Update</strong> when finished.</li>
+<li>Finally, <strong>Save</strong> the view for your new settings to take effect.</li>
+</ol>
diff --git a/help/example-recent-stories.html b/help/example-recent-stories.html
new file mode 100644
index 0000000..57f373a
--- /dev/null
+++ b/help/example-recent-stories.html
@@ -0,0 +1,58 @@
+<!-- $Id: example-recent-stories.html,v 1.1.6.1 2009/11/02 22:01:26 merlinofchaos Exp $ -->
+In this example you will create a list of nodes of the content type "story", to be shown in a block. Through this step-by-step process, you will become familiar with some basic steps in creating a view, and familiarize yourself with the Views User Interface.
+
+<ol>
+<li><h3>Creating a new view</h3>
+<p>Go to <a target="_blank" href="base_url:admin/structure/views/add">add new view</a>. Give your new view the name 'recent_stories', description 'Recent Stories', tag 'story', type 'Node' and click <strong>Next</strong>.</p></li>
+<li><h3>About the interface</h3>
+<p>You have been brought to Views User Interface. As you start, you are editing the "Default" options for the view. In the 1st column on the left you can see the drop-down menu offers 'block', for example, to select settings specific only to block views. In the remaining columns, you will be able to add or change options by clicking on links or icons. These options will then appear below this main area. Most likely, you will need to scroll a bit to see the options appear.</p></li>
+<li><h3>Selecting the fields to display</h3>
+ <ol>
+ <li>In 3rd column locate the <strong>Fields</strong> options. Click the <strong>+</strong> icon to add fields.</li>
+ <li>Scroll down to <strong>Defaults: Add fields</strong>. In the <strong>Groups</strong> drop-down menu select 'Node', then check the following two fields: <em>Node: Post date</em>, <em>Node: Title</em>. Then click <strong>Add</strong>.</li>
+ <li>You will be taken through the fields you added one at a time. Make the changes specified below.
+ <ul>
+ <li>For the <em>Post date</em> field: Delete the 'Post date' label. Change the <strong>Date format</strong> to <em>Custom</em>, and the <strong>Custom date format</strong> to 'F j, Y, g:i a' (do not type the single quotes; for the meaning of these letter codes, click on <em>the PHP docs</em> link under that box to arrive at the explanation). Click <strong>Update</strong>.</li>
+ <li>For the <em>Title</em> field: Delete the 'Title' label. Select <em>Link this field to its node.</em> Click <strong>Update</strong>.</li>
+ </ul>
+ </li>
+ <li>Scroll back up to <strong>Fields</strong> and click the <strong>&uarr;&darr;</strong> icon to rearrange fields.</li>
+ <li>Drag the four-sided arrow next to <em>Node: Title</em> so that it appears above <em>Node: Post date</em>. Click <strong>Update</strong> to save the new field order.</li>
+ </ol>
+</li>
+<li><h3>Filtering to <em>story</em> nodes only</h3>
+ <ol>
+ <li>Click the <strong>+</strong> icon next to <strong>Filters</strong>.</li>
+ <li>In the <strong>Groups</strong> drop-down menu select 'Node', then check the <em>Node: Published</em> and <em>Node: Type</em> filters, and click <strong>Add</strong>.</li>
+ <li>Select the <em>Published</em> checkbox. Click <strong>Update</strong></li>
+ <li>Select <em>Is one of</em> and check <em>Story</em> in the <em>Node Type</em> field. Click <strong>Update</strong>.</li>
+ </ol>
+</li>
+<li><h3>Sorting to show most recent first</h3>
+ <ol>
+ <li>Scroll up to <strong>Sort criteria</strong> and click the <strong>+</strong> icon.</li>
+ <li>In the <strong>Groups</strong> drop-down menu below, select 'Node', then check <em>Node: Post date</em>, and click <strong>Add</strong>. Alternatively, you may instead check <em>Node: Last comment time</em>, or <em>Node: Updated/commented date</em>, or <em>Node: Updated date</em>.</li>
+ <li>Select <em>Descending</em> <strong>Sort order</strong>. Click <strong>Update</strong>.</li>
+ </ol>
+</li>
+<li><h3>Refining the basic settings</h3>
+ <ul>
+ <li>In 1st column under <strong>Basic settings</strong> locate these options:
+ <ul>
+ <li><em>Items to Display</em> setting, click <em>10</em>. Change the '10' to '4'. Click <strong>Update</strong></li>
+ <li><em>Style</em> setting, click <em>Unformatted</em>. Change to <em>List</em>. Click <strong>Update</strong>.</li>
+ </ul>
+ </li>
+ </ul>
+</li>
+<li><h3>Adding a block display for custom options</h3>
+ <ol>
+ <li>In the dropdown on the left, ensure that <em>Block</em> is selected, and click <strong>Add Display</strong>.</li>
+ <li>Under <strong>Block settings</strong>, click the <em>None</em> link next to the <em>Admin</em> setting. Change <strong>Block: Block admin description</strong> to 'Recent Stories'.</li>
+ </ol>
+</li>
+<li><h3>Saving the view</h3>
+<p>Click <strong>Save</strong> to save your work.</p></li>
+<li><h3>Instructing Drupal to show the block</h3>
+<p>Finally, you should tell Drupal to show this block. Configure your block by going to <a target="_blank" href="base_url:admin/build/block">admin/build/block</a>. Locate the block in the list: it is labeled <em>Recent Stories</em>. Place this block in a region and click <strong>Save</strong>. You may click <em>Configure</em> to set a different title, to determine which roles can view the block, and on which pages it appears; If you want your block on the front page only, enter '&lt;front&gt;'.</p></li>
+</ol>
diff --git a/help/example-user-feed.html b/help/example-user-feed.html
new file mode 100644
index 0000000..58e8ab3
--- /dev/null
+++ b/help/example-user-feed.html
@@ -0,0 +1,74 @@
+<!-- $Id: example-user-feed.html,v 1.1.6.1 2009/11/02 22:01:26 merlinofchaos Exp $ -->
+<p>In this example you will create a <em>Feed display</em> to show nodes by individual users, dynamically selected through the URL. You will become familiar with the Views 2 interface, as well as learn how to use an argument to pull in a user name and use it in a dynamically created path.</p>
+<p>A <em>feed</em> is a data format that places your site's content into a file that can be read and displayed by news reader programs. When visiting a site, you may notice a small <a href="http://drupal.org/misc/feed.png">RSS transmission icon</a>, whereby clicking on it, you can subscribe to the site's most recent content. This makes it easier for your visitors to keep up to date with your website. You can also use this format to aggregate information into other sites. For more information, please watch a video from Common Craft about <a href="http://www.commoncraft.com/rss_plain_english">RSS in plain English</a>.</p>
+<p>Note, Drupal automatically creates a feed for your website, but you may want to create feeds with specific information. In this case, a list per user. </p>
+<ol>
+ <li>
+ <h3>Creating a new view </h3>
+ <ol>
+ <li>Go to <a target="_blank" href="/admin/structure/views/add">add new view</a>. Give it the name 'user_feed', description 'A feed of user nodes.', tag 'users', type 'Node' and click Next.</li>
+ </ol>
+ </li>
+ <li><strong>About the Interface.</strong> You have been brought to the Views User Interface. As you start, you are editing the &quot;Default&quot; options for the view. In the 1st column on the left- you can see the pull-down menu offers 'Feed', for example, to select settings specific only to RSS views. In the remaining columns, you will be able to add or change options by clicking on links or icons. These options appear below this main area. Most likely, you will need to scroll to see the options appear. As you make changes, these options will appear in bold until you save your view.</li>
+ <li>
+ <h3>Change default display</h3>
+ <ol>
+ <li>Under <strong>Basic Settings</strong> in the 2nd column, click <em>Row style: Fields</em></li>
+ <li>A menu loads below, <em>Defaults: How should each row in this view be styled</em>, check the <em>Node</em> option, and click <strong>Update</strong>.</li>
+ <li>This loads another options menu, <em>Defaults: Row style options</em> click <strong>Update</strong>.</li>
+ </ol>
+ </li>
+ <li>
+ <h3>Create the RSS view </h3>
+ <ol>
+ <li>In the 1st column, select 'Feed' in the drop-down menu, and click <strong>Add Display</strong>.</li>
+ <li>Under <strong>Basic Settings </strong>in the 2nd column, click<em> Row style:Missing style plugin</em></li>
+ <li>Note, options appear below the Views Interface, you may need to scroll to see <em>Feed: How should each row in this view be styled</em><br />
+ tick <strong>Node</strong>, then <strong>Update</strong></li>
+ <li>This loads the next options menu- <em>Display type: </em>select &quot;Use default RSS settings&quot;, click <strong>Update</strong>.</li>
+ </ol>
+ </li>
+ <li>
+ <h3>Set the path for accessing your feed</h3>
+ <ol>
+ <li> In the 2nd column under <strong>Feed settings</strong>, click <em>Path: None </em></li>
+ <li>In options below <em>Feed: The menu path or URL of this view</em> enter in the path with an argument feeds/%/rss.xml</li>
+ <li>Click <strong>Update</strong></li>
+ </ol>
+ </li>
+ <li>
+ <h3>Set up your arguments to say which user's nodes to display</h3>
+ <ol>
+ <li>To the right of <strong>Arguments</strong>, click the + sign to add and argument</li>
+ <li>In the Feed: Add arguments menu that loads below, select User in the pull-down menu</li>
+ <li>Check the box <em>User: Name</em>, click <strong>Add</strong></li>
+ <li>Scroll down to options to find <strong>Case in path:</strong> select <em>Lower case</em></li>
+ <li>Check the box <em>Transform spaces to dashes in URL</em></li>
+ <li>Click <strong>Update default display</strong></li>
+ </ol>
+ </li>
+ <li>
+ <h3>Sort to show most recent at top of feed</h3>
+ <ol>
+ <li>Scroll up to <strong>Sort criteria</strong> in the right most column and click the + icon.</li>
+ <li>In the <strong>Groups</strong> drop-down menu below, select 'Node', then check <em>Node: Post date</em>, and click <strong>Add</strong>. </li>
+ <li>Select <em>Descending</em> <strong>Sort order</strong>. Click <strong>Update</strong>.</li>
+ </ol>
+ </li>
+ <li>
+ <h3>Set filters to hide unpublished entries</h3>
+ <ol>
+ <li>Click the + icon next to <strong>Filters</strong>. In the options below, select <em>Node</em> under <strong>Groups</strong> drop-down menu, choose the <em>Node: Published</em> filter, and click <strong>Add</strong>.</li>
+ <li>Check the box <em>Published</em>. Click <strong>Update default display</strong></li>
+ </ol>
+ </li>
+ <li>
+ <h3>Test</h3>
+ <ol>
+ <li>Click <strong>Save</strong></li>
+ <li>Under <strong>Live preview</strong> type in the name of a user, in lowercase, replacing spaces with dashes, click <strong>Preview</strong>.</li>
+ <li>You should test and find your feeds at URLs like http://yoursite.com/feeds/user-name/rss.xml</li>
+ <li>You can use this path for aggregating on another site. You can also attach the RSS feed to another display of view to make the feed link appear on that display.</li>
+ </ol>
+ </li>
+</ol> \ No newline at end of file
diff --git a/help/example-users-by-role.html b/help/example-users-by-role.html
new file mode 100644
index 0000000..1d8033e
--- /dev/null
+++ b/help/example-users-by-role.html
@@ -0,0 +1,48 @@
+<!-- $Id: example-users-by-role.html,v 1.1.6.1 2009/11/02 22:01:26 merlinofchaos Exp $ -->
+In this example you will create a page view listing users on your site. Through this step-by-step process, you will become familiar with some basic steps in creating a view, and familiarize yourself with the Views User Interface.
+
+<ol>
+<li><h3>Creating a new view</h3>
+<p>Go to <a target="_blank" href="base_url:admin/structure/views/add">add new view</a>. Give your new view the name 'user_list', description 'A simple user listing.', tag 'users', type 'User' and click <strong>Next</strong>.</p></li>
+<li><h3>About the Interface</h3>
+<p>You have been brought to the Views User Interface. As you start, you are editing the "Default" options for the view. In the 1st column on the left you can see the drop-down menu offers 'block', for example, to select settings specific only to block views. In the remaining columns, you will be able to add or change options by clicking on links or icons. These options will then appear below this main area. Most likely, you will need to scroll to see the options appear. As you make changes, these options will appear in bold until you save your view.</p></li>
+<li><h3>Creating a page display; choosing a URL and creating a menu link</h3>
+ <ol>
+ <li>In the 1st column, ensure that 'Page' is selected in the drop-down menu, and click <strong>Add Display</strong>.</li>
+ <li>Next we'll define the path for this page. A page must have a path, and we define it early so that Views doesn't warn us "Display Page uses path but path is undefined." Locate the <strong>Page settings</strong> in the 2nd column, and click the <em>None</em> link next to the <em>Path</em> setting. In the options editing area that appears below, set the path to 'user_list' (or something Implement you prefer) and click <strong>Update</strong>.</li>
+ <li>Next to <em>Menu</em> setting, Click the <em>No menu</em> link. In the options which appear below, select <em>Normal menu entry</em>, and set the title to 'User list' and click <strong>Update</strong>.</li>
+ <li>Scroll up to <strong>Basic settings</strong>, in that same 2nd column, and click the <em>No</em> link next to <em>Use pager</em>. Below, in the options, select <em>Full pager</em> and click <strong>Update default display</strong>.</li>
+ </ol>
+</li>
+<li><h3>Selecting the fields to display</h3>
+ <ol>
+ <li>In 3rd column locate the <strong>Fields</strong> options. Click the <strong>+</strong> icon to add fields.</li>
+ <li>Scroll down to <strong>Defaults: Add fields</strong>. In the <strong>Groups</strong> drop-down menu select 'User', then check the following fields: <em>User: Created date</em>, <em>User: Delete link</em>, <em>User: Edit link</em>, <em>User: Last access</em>, <em>User: Name</em> and <em>User: Picture</em>. Then click <strong>Add</strong>.</li>
+ <li>You will be taken through the fields you added one at a time. Click <strong>Update default display</strong> to go to each next field. Leave the default options on all fields except <em>Delete link</em>; change that field's label to 'Operations'.</li>
+ <li>Scroll back up to <strong>Fields</strong> and click the <strong>&uarr;&darr;</strong> icon to rearrange fields. Down below, drag the <em>Name</em> field, by dragging its four-sided arrow, to the top. Drag the <em>Delete link (Operations)</em> field to the bottom, and the <em>Edit link</em> field just above it. Then click <strong>Update</strong>.</li>
+ </ol>
+</li>
+<li><h3>Seeing what we've done so far</h3>
+<p>At this point, you have done enough to create a valid view. If you scroll down, you will see a preview of your view. If it doesn't show already, click the <strong>Preview</strong> button; but generally this display updates automatically whenever you finish working in one of the mini forms.</p></li>
+<li><h3>Styling the view as a table; combining related fields into columns</h3>
+ <ol>
+ <li>Under <strong>Basic settings</strong>, in the 1st column, click the <em>Unformatted</em> link next to the <em>Style</em> setting. In the options below, under <strong>Page: How should this view be styled</strong>, choose <em>Table</em> and click <strong>Update default display</strong>.</li>
+ <li>You will be taken to a <strong>Page: Style options</strong> form to edit the table settings. Locate our <em>Edit link</em> field in this mini form, and notice the <strong>Column</strong> drop-down. Change this drop-down to show <em>Operations</em>. In the <strong>Separator</strong> column next to the <em>Operations</em> field, type ' | ' (note the spaces around the <strong>|</strong> symbol). Check all of the <strong>Sortable</strong> checkboxes, and set <strong>Default sort</strong> to <em>Name</em>. When finished, click <strong>Update default display</strong>.</li>
+ </ol>
+</li>
+<li><h3>Filtering the user list to exclude unwanted entries</h3>
+ <ol>
+ <li>Click the <strong>+</strong> icon next to <strong>Filters</strong>.</li>
+ <li>In the <strong>Groups</strong> drop-down menu select 'User', then check the <em>User: Name</em> filter, and click <strong>Add</strong>.</li>
+ <li>Select <em>Is not one of</em> and enter 'Anonymous' in the <strong>Usernames</strong> box. Click <strong>Update default display</strong>.</li>
+ </ol>
+</li>
+<li><h3>Adding an argument to list users by role dynamically</h3>
+ <ol>
+ <li>Scroll up to <strong>Arguments</strong>, and click its <strong>+</strong> icon.</li>
+ <li>Check the <em>User: Roles</em> argument, and click <strong>Add</strong>. Set the title to '%1' (don't type the quotes), and under <strong>Action to take if argument is not present</strong> select <em>Summary, sorted ascending</em>. Leave the other settings as they are. Click <strong>Update default display</strong>, and click <strong>Update</strong> through the prompts that follow to accept their default values.</li>
+ </ol>
+</li>
+<li><h3>Saving the view</h3>
+<p>Finally, click the <strong>Save</strong> button to save your work. At the very top, click <strong>View "Page"</strong> to go to your new view!</p></li>
+</ol>
diff --git a/help/field.html b/help/field.html
new file mode 100644
index 0000000..83e42ae
--- /dev/null
+++ b/help/field.html
@@ -0,0 +1,6 @@
+<!-- $Id: field.html,v 1.2 2008/05/15 19:17:11 merlinofchaos Exp $ -->
+Fields are the individual pieces of data being displayed. Adding the fields <em>Node: Title</em>, <em>Node: Type</em>, and <em>Node: Post date</em> to a node view, for example, includes the title, content type and creation date in the displayed results).
+
+Fields may not appear on every display, because not all style plugins actually use fields. For example, the 'node' row plugin simply displays the node through Drupal's normal mechanisms, and fields are not involved.
+
+For the most part, the field settings should be self explanatory. Fields will appear in the order that they are arranged in, and they will usually appear with the label they are given. \ No newline at end of file
diff --git a/help/filter.html b/help/filter.html
new file mode 100644
index 0000000..447862e
--- /dev/null
+++ b/help/filter.html
@@ -0,0 +1,13 @@
+<!-- $Id: filter.html,v 1.3 2009/02/20 20:46:48 merlinofchaos Exp $ -->
+Filters are used to reduce the data set that Views provides. That is to say, without any filters applied, Views will return all of your content. You don't want that, so at least some filters must be used.
+
+Some very commonly used filters:
+<ul>
+<li> The 'Node: Published' filter is used to restrict a node View to only nodes that are are have the 'published' box checked. This can be very important to prevent users from viewing content they should not have access to.</li>
+<li> The 'Node: Promoted to front page' filter can be used to show only nodes that have the 'promote to front page' turned on. </li>
+<li> The 'Node: Type' filter is useful for showing only certain types of nodes. Let's say you wanted users to see only nodes that were 'book' nodes, or a combination of 'book' nodes and 'staff-blog' nodes. This filter allows you to select exactly that.</li>
+<li> The 'User: Current' filter will show only nodes that the logged in user has authored.</li>
+<li> The 'Node: Post date' filter can be used to show only nodes posted before, after, or between a range of dates.</li>
+</ul>
+
+The above list is only a tiny fraction of the filters available in Views, referenced here to give an idea of the kinds of tasks filters can accomplish.
diff --git a/help/getting-started.html b/help/getting-started.html
new file mode 100644
index 0000000..a29a2c6
--- /dev/null
+++ b/help/getting-started.html
@@ -0,0 +1,23 @@
+<!-- $Id: getting-started.html,v 1.8 2008/10/14 18:20:25 merlinofchaos Exp $ -->
+For those new to Views, it can be a complex system that appears totally overwhelming. The good news is that the UI is designed to compartmentalize everything; this means that for the most part, you can ignore the parts you're not interested in. Start small and build your way up.
+
+Because of this, the edit UI can seem overwhelming at first, but there are really just a few things you <strong>have</strong> to know. The rest you can find through exploration. The Views Edit UI image, below, gives an overview of what you'll find on the edit UI.
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/overview-ui-large.png"><img src="path:images/overview-ui-small.png" /></a>
+<em>The Views Edit UI</em>
+</div>
+
+Notes:
+1) Every view has a number of <a href="topic:views/display">displays</a> which represent where output will be placed. If you're familiar with the original Views 1, you could set a view to be a 'page', with a URL (path), or a block that could show up in a sidebar. With Views 2, you can add as many displays as you like. In addition, you have the <em>default</em> display which contains the basic settings, but doesn't actually show up anywhere.
+
+2) When you click on the link for an item, a form will open up. For browsers with smaller resolutions, you may have to scroll down a little to see this form. If a form is open, the item its attached to will be highlighted.
+
+3) <a href="topic:views/overrides">Overrides</a> mean that a particular display is <strong>not</strong> using default settings. When you create a new display, many of its settings will start off using default values. This will be indicated by italics and a lighter color. <strong>If you change these values without first overriding them, you will change the default value for all displays that use them.</strong>
+
+4) Some items, particularly styles, have additional settings. Ordinarily when you <em>update</em> a style, if it has additional settings you will automatically see that form next. Often, you will need to go directly to those settings.
+
+5) You can safely leave a view page to go and do other things. If you come back, the view will still be there, stored in a cache. Keep in mind, however, that while you do this, that view is <em>locked</em>, meaning another user cannot edit this view without breaking the lock. Breaking the lock will discard your changes.
+
+It helps to have something particular in mind that you want to accomplish when using Views. Here are a couple of ideas and a brief sketch of how to accomplish what you want.
+
diff --git a/help/images/CVS/Entries b/help/images/CVS/Entries
new file mode 100644
index 0000000..a15b52b
--- /dev/null
+++ b/help/images/CVS/Entries
@@ -0,0 +1,31 @@
+/node-term_node-term_data-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/node-term_node-term_data.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/overview-ui-large.png/1.1/Tue Aug 12 23:21:51 2008/-kb/TDRUPAL-7--3
+/overview-ui-small.png/1.1/Tue Aug 12 23:21:51 2008/-kb/TDRUPAL-7--3
+/style-breakdown-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/style-breakdown.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views1-admin-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views1-admin.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views1-changeviewtype-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views1-changeviewtype.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-addaview-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-addaview.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-adddisplay-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-adddisplay.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-addfields-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-addfields.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-addfieldsajax-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-addfieldsajax.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-admin-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-admin.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-changedisplaystyle-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-changedisplaystyle.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-fieldspreview-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-fieldspreview.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-newview-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-newview.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-rearrangefields-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-rearrangefields.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-tablestyle-large.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+/views2-tablestyle.png/1.2/Fri Aug 8 17:56:44 2008/-kb/TDRUPAL-7--3
+D
diff --git a/help/images/CVS/Repository b/help/images/CVS/Repository
new file mode 100644
index 0000000..6dae84d
--- /dev/null
+++ b/help/images/CVS/Repository
@@ -0,0 +1 @@
+contributions/modules/views/help/images
diff --git a/help/images/CVS/Root b/help/images/CVS/Root
new file mode 100644
index 0000000..127da18
--- /dev/null
+++ b/help/images/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal-contrib
diff --git a/help/images/CVS/Tag b/help/images/CVS/Tag
new file mode 100644
index 0000000..0f07c7f
--- /dev/null
+++ b/help/images/CVS/Tag
@@ -0,0 +1 @@
+TDRUPAL-7--3
diff --git a/help/images/node-term_node-term_data-large.png b/help/images/node-term_node-term_data-large.png
new file mode 100644
index 0000000..4fcd191
--- /dev/null
+++ b/help/images/node-term_node-term_data-large.png
Binary files differ
diff --git a/help/images/node-term_node-term_data.png b/help/images/node-term_node-term_data.png
new file mode 100644
index 0000000..de1273c
--- /dev/null
+++ b/help/images/node-term_node-term_data.png
Binary files differ
diff --git a/help/images/overview-ui-large.png b/help/images/overview-ui-large.png
new file mode 100644
index 0000000..04fbe90
--- /dev/null
+++ b/help/images/overview-ui-large.png
Binary files differ
diff --git a/help/images/overview-ui-small.png b/help/images/overview-ui-small.png
new file mode 100644
index 0000000..ed7595f
--- /dev/null
+++ b/help/images/overview-ui-small.png
Binary files differ
diff --git a/help/images/style-breakdown-large.png b/help/images/style-breakdown-large.png
new file mode 100644
index 0000000..698b8cc
--- /dev/null
+++ b/help/images/style-breakdown-large.png
Binary files differ
diff --git a/help/images/style-breakdown.png b/help/images/style-breakdown.png
new file mode 100644
index 0000000..d7513a8
--- /dev/null
+++ b/help/images/style-breakdown.png
Binary files differ
diff --git a/help/images/views1-admin-large.png b/help/images/views1-admin-large.png
new file mode 100644
index 0000000..06744bd
--- /dev/null
+++ b/help/images/views1-admin-large.png
Binary files differ
diff --git a/help/images/views1-admin.png b/help/images/views1-admin.png
new file mode 100644
index 0000000..398c145
--- /dev/null
+++ b/help/images/views1-admin.png
Binary files differ
diff --git a/help/images/views1-changeviewtype-large.png b/help/images/views1-changeviewtype-large.png
new file mode 100644
index 0000000..5c58d81
--- /dev/null
+++ b/help/images/views1-changeviewtype-large.png
Binary files differ
diff --git a/help/images/views1-changeviewtype.png b/help/images/views1-changeviewtype.png
new file mode 100644
index 0000000..6b1798a
--- /dev/null
+++ b/help/images/views1-changeviewtype.png
Binary files differ
diff --git a/help/images/views2-addaview-large.png b/help/images/views2-addaview-large.png
new file mode 100644
index 0000000..bbad1b1
--- /dev/null
+++ b/help/images/views2-addaview-large.png
Binary files differ
diff --git a/help/images/views2-addaview.png b/help/images/views2-addaview.png
new file mode 100644
index 0000000..546ea16
--- /dev/null
+++ b/help/images/views2-addaview.png
Binary files differ
diff --git a/help/images/views2-adddisplay-large.png b/help/images/views2-adddisplay-large.png
new file mode 100644
index 0000000..51c3675
--- /dev/null
+++ b/help/images/views2-adddisplay-large.png
Binary files differ
diff --git a/help/images/views2-adddisplay.png b/help/images/views2-adddisplay.png
new file mode 100644
index 0000000..dff143e
--- /dev/null
+++ b/help/images/views2-adddisplay.png
Binary files differ
diff --git a/help/images/views2-addfields-large.png b/help/images/views2-addfields-large.png
new file mode 100644
index 0000000..b7c1ba5
--- /dev/null
+++ b/help/images/views2-addfields-large.png
Binary files differ
diff --git a/help/images/views2-addfields.png b/help/images/views2-addfields.png
new file mode 100644
index 0000000..e70c758
--- /dev/null
+++ b/help/images/views2-addfields.png
Binary files differ
diff --git a/help/images/views2-addfieldsajax-large.png b/help/images/views2-addfieldsajax-large.png
new file mode 100644
index 0000000..a9308a0
--- /dev/null
+++ b/help/images/views2-addfieldsajax-large.png
Binary files differ
diff --git a/help/images/views2-addfieldsajax.png b/help/images/views2-addfieldsajax.png
new file mode 100644
index 0000000..3043d04
--- /dev/null
+++ b/help/images/views2-addfieldsajax.png
Binary files differ
diff --git a/help/images/views2-admin-large.png b/help/images/views2-admin-large.png
new file mode 100644
index 0000000..d262bc5
--- /dev/null
+++ b/help/images/views2-admin-large.png
Binary files differ
diff --git a/help/images/views2-admin.png b/help/images/views2-admin.png
new file mode 100644
index 0000000..c273363
--- /dev/null
+++ b/help/images/views2-admin.png
Binary files differ
diff --git a/help/images/views2-changedisplaystyle-large.png b/help/images/views2-changedisplaystyle-large.png
new file mode 100644
index 0000000..09925df
--- /dev/null
+++ b/help/images/views2-changedisplaystyle-large.png
Binary files differ
diff --git a/help/images/views2-changedisplaystyle.png b/help/images/views2-changedisplaystyle.png
new file mode 100644
index 0000000..5a82ea5
--- /dev/null
+++ b/help/images/views2-changedisplaystyle.png
Binary files differ
diff --git a/help/images/views2-fieldspreview-large.png b/help/images/views2-fieldspreview-large.png
new file mode 100644
index 0000000..e2730b4
--- /dev/null
+++ b/help/images/views2-fieldspreview-large.png
Binary files differ
diff --git a/help/images/views2-fieldspreview.png b/help/images/views2-fieldspreview.png
new file mode 100644
index 0000000..5a41ab2
--- /dev/null
+++ b/help/images/views2-fieldspreview.png
Binary files differ
diff --git a/help/images/views2-newview-large.png b/help/images/views2-newview-large.png
new file mode 100644
index 0000000..498627a
--- /dev/null
+++ b/help/images/views2-newview-large.png
Binary files differ
diff --git a/help/images/views2-newview.png b/help/images/views2-newview.png
new file mode 100644
index 0000000..b522d2c
--- /dev/null
+++ b/help/images/views2-newview.png
Binary files differ
diff --git a/help/images/views2-rearrangefields-large.png b/help/images/views2-rearrangefields-large.png
new file mode 100644
index 0000000..acfed4c
--- /dev/null
+++ b/help/images/views2-rearrangefields-large.png
Binary files differ
diff --git a/help/images/views2-rearrangefields.png b/help/images/views2-rearrangefields.png
new file mode 100644
index 0000000..562df08
--- /dev/null
+++ b/help/images/views2-rearrangefields.png
Binary files differ
diff --git a/help/images/views2-tablestyle-large.png b/help/images/views2-tablestyle-large.png
new file mode 100644
index 0000000..67e9e6b
--- /dev/null
+++ b/help/images/views2-tablestyle-large.png
Binary files differ
diff --git a/help/images/views2-tablestyle.png b/help/images/views2-tablestyle.png
new file mode 100644
index 0000000..f899740
--- /dev/null
+++ b/help/images/views2-tablestyle.png
Binary files differ
diff --git a/help/menu.html b/help/menu.html
new file mode 100644
index 0000000..208d52d
--- /dev/null
+++ b/help/menu.html
@@ -0,0 +1,22 @@
+<!-- $Id: menu.html,v 1.2.6.1 2009/11/02 22:01:26 merlinofchaos Exp $ -->
+Page displays can hook into the Drupal menu system and provide <strong>menu links</strong> that will appear in the Navigation system as well as <strong>tabs</strong> that can be used to keep Views next to each other.
+
+For simple <strong>menu links</strong>, there is very little you need to do; simply select 'Normal menu entry' and fill in the text for the title. This will appear in the Navigation menu by default; you will need to visit the menu administration page to move this to another menu.
+
+Tabs are not quite so simple; there are some complex rules for using tabs in Drupal.
+<ol>
+<li> All tabs must have a parent, which is the next level up in the path hierarchy. For example, if the view path is 'example/taba' then the parent must be 'example'.
+<li> All tabs must have one and only one default tab; this is usually the same content as the parent.
+<li> If a parent does not exist, when creating the 'default' tab, Views will allow you to also create a parent item. It will automatically set up the URL for you when it does this.
+<li> Tab weight is used to control what order the tabs are displayed in. Lower numbers will display more to the left. For tabs whose numbers are the same, they will be displayed alphabetically.
+<li> Drupal only supports 2 levels of tabs, so be careful about trying to put tabs within tabs within tabs. That won't work.
+</ol>
+
+For example, if you have two views that you want to be tabs, you could set it up like this:
+<ul>
+<li> In the first view, set the path to 'tabs/tab1'. Set it to be the 'default tab', set the title to 'Tab 1' and the weight to 0.
+<li> Click update and you will be taken to a form that lets you define the parent. Since 'tabs' doesn't already exist in the system, select 'Normal menu item', and set the title to 'Tabs'.
+<li> On the second view, set the path to 'tabs/tab2'; set it to be a 'Menu tab', and set the title to 'Tab 2'.
+</ul>
+
+With this done, you will now have a Navigation link named 'Tabs' and when you click on it, you will go to the tabs, with 'Tab 1' being the default tab that appears. You can then click between Tab 1 and Tab 2.
diff --git a/help/new.html b/help/new.html
new file mode 100644
index 0000000..606f6a6
--- /dev/null
+++ b/help/new.html
@@ -0,0 +1,114 @@
+<!-- $Id: new.html,v 1.5.6.1 2010/10/12 21:35:03 merlinofchaos Exp $ -->
+Views 2 is the newest major release of Views and it is specifically coded for Drupal 6. Views 2 retains all of the core functionality of Views 1, together with a completely revamped user interface and a large set of new features which greatly expand upon the original feature-set of Views 1. This document is a side-by-side comparison of Views 1 versus Views 2 from a user's perspective, detailing the UI changes, some new ways to perform old tasks, the cool new features of Views 2 and how these features can be used to address some of the shortcomings of Views 1.
+
+<h2>Admin interface</h2>
+The first thing that pops out after you install Views 2 is the radically different admin interface:
+<div class="help-box" style="text-align:center">
+<a href="path:images/views2-admin-large.png"><img src="path:images/views2-admin.png" /></a>
+<em>Views 2 admin interface</em>
+</div>
+
+compared to the old comfy Views 1 interface:
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/views1-admin-large.png"><img src="path:images/views1-admin.png" /></a>
+<em>Views 1 admin interface</em>
+</div>
+
+The new admin interface performs the same functions as the old -- listing all the views in the system, providing links to add or import views and a link to Views Tools -- but has been compacted, with each view displayed as a paragraph style-row compared to the table of Views 1 and set of filters on top to ease locating views among a large list.
+
+Context-help is available by clicking the small blue question-mark icon. Context-help in Views 2 is provided by the <a href="http://drupal.org/project/advanced_help">Advanced Help</a> module, so make sure to install that together with installing Views 2. The small blue help icons will be available in various parts of the Views UI. In particular, look for them as part of the description of a <strong>display</strong>, when setting <strong>style</strong> options, and in various editing sections such as <strong>path</strong>, <strong>menu</strong> and the like.
+
+Several new attributes of each view are visible in the filter header:
+<ol>
+<li><strong>Tag</strong> - This is just another label for organizing and sorting views. Tags can be any text. Views that are provided by modules will often be tagged together to make it easy to find them. Tags are also added to your template suggestions, so take care what you set here. For example setting the tag <i>Page</i> will give all your views the Page template.</li>
+<li><strong>Display</strong> - In Views 1 each view query was tied to its display; in other words your fields, sorts, filters, and arguments could only be displayed in the single page or block display provided in the view definition. In Views 2, view displays have been decoupled from view queries - it is now possible to have multiple page, block, and feed displays from a single view. More on view displays later. </li>
+<li><strong>Type</strong> - Views 2 view types are radically different from Views 1 types. Views 1 types basically defined how the node list displays were <i>styled</i> - you had Full Nodes, Teaser List, Table View, and so on. In Views 2 view display styles have been broken out into the separate <i>Style</i> attribute. View types now refer to the primary table on which information for the query will be retrieved which controls what arguments, fields, sort criteria and filters are available. Views 2 view types are discussed later.
+</li>
+</ol>
+
+<h2>Adding a view</h2>
+So let's jump in and add a view. For this example, we're going to create a <strong>user</strong> view, which will display a list of users.
+<div class="help-box" style="text-align:center">
+<a href="path:images/views2-addaview-large.png"><img src="path:images/views2-addaview.png" /></a>
+<em>Adding a view</em>
+</div>
+
+The first step in adding a view is simply entering a name (only alphanumeric characters, no spaces) a description, tag, and the view type. To get the user view, we selected the <strong>User</strong> radio button.
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/views2-newview-large.png"><img src="path:images/views2-newview.png" /></a>
+<em>Configuring the new view</em>
+</div>
+
+This might be the 2nd whoa moment as the interface here is also completely revamped from Views 1.x. The best way to summarize is to say all the pieces from the Views 1.x interface are still there...just in different places. Fields, arguments, sort critera and filters are all still there there, just in new AJAXY-flavours.
+
+Let's start by adding some fields:
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/views2-addfields-large.png"><img src="path:images/views2-addfields.png" /></a>
+<em>Adding fields</em>
+</div>
+
+Clicking on the [+] icon next to the word Fields unfurls a section beneath the view information with all the available fields grouped by Comment, File, Node, Node revision, Taxonomy and User, and probably a few others. This is a general paradigm for the Views 2 interface -- clicking on a widget or link unfurls a section beneath the view information with the relevant interface. Usually, what is being edited will be hilited in yellow, as well.
+
+When adding items, you can use the Groups drop-down box to show only a subset of the fields available according to the above groups, or select All to see all fields available, which is what was selected when the section unfurled. For our example, we're selecting the 'User' group and adding the <strong>User: E-mail</strong>, <strong>User: Name</strong> and <strong>User: Picture</strong> fields.
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/views2-addfieldsajax-large.png"><img src="path:images/views2-addfieldsajax.png" /></a>
+<em>Adding fields</em>
+</div>
+
+Once we add our fields they show up in the Fields section of the interface. We will be walked through each field we added, so keep clicking <strong>update</strong>, even if you don't make changes to the field and you will see the next one.
+
+The fields we added can be rearranged by clicking the up/down icon, right next to the add icon we used earlier. We can also remove a field using the same interface.
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/views2-rearrangefields-large.png"><img src="path:images/views2-rearrangefields.png" /></a>
+<em>Rearranging fields</em>
+</div>
+
+From here, the fields can be dragged up and down by grabbing the little drag handle on the left and moving them where you like. Making a change to any part of the view by clicking update usually triggers a refresh of the view preview which is conveniently located right below the main interface.
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/views2-fieldspreview-large.png"><img src="path:images/views2-fieldspreview.png" /></a>
+<em>Views preview</em>
+</div>
+
+Now that we have some fields set up we can turn our attention to Basic Settings for the view.
+
+It's important to note that all the interface elements pertain to the current <i>Display</i> selected for the view. As mentioned before a view can have multiple displays. The first time you create a view you'll be manipulating the <i>Default</i> display. You can add displays using the Add Display button, whose Basic Settings are completely different from each other; this lets you have as many displays of a view as you would like all sharing items such as Sort Criteria, Filters and Arguments but different display settings like Title, Style, Fields, and Pager settings. Also, any display you add automatically inherits display settings from the default display initially, so you can keep a core of common settings in your default display and add additional settings for every other display.
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/views2-adddisplay-large.png"><img src="path:images/views2-adddisplay.png" /></a>
+<em>Adding a <strong>Page</strong> display </em>
+</div>
+Let's stick with the Default display and twiddle some settings. We can set the <i>Title</i> to "User View 1" and the <i>Style</i> to Table. As mentioned earlier, view styles in Views 2 correspond more to view types in Views 1 (remember, List, Table, Teasers, Full nodes).
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/views1-changeviewtype-large.png"><img src="path:images/views1-changeviewtype.png" /></a>
+<em>Selecting a Views 1 View Type</em>
+</div>
+
+In Views 2, view <i>styles</i> control how a view display looks. These styles are significantly different from the Types in Views 1; in particular, types have been 'broken up'; there is now the <em>style</em> as well as the <em>row style</em> which focus on different parts of the output.
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/style-breakdown-large.png"><img src="path:images/style-breakdown.png" /></a>
+<em>A breakdown of View output</em>
+</div>
+
+We change the style by clicking on the current style on the left hand side of the View information area.
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/views2-changedisplaystyle-large.png"><img src="path:images/views2-changedisplaystyle.png" /></a>
+<em>Selecting a Views 2 Display Style</em>
+</div>
+
+We're given the style options of <strong>Grid</strong>, <strong>List</strong>, <strong>Table</strong> and <strong>Unformatted</strong>. Additional display styles can be added by modules which have Views <i>style plugins</i>. Choosing a style reveals a "settings" button which you can click to configure the style you've chosen. In the shot below we've selected and are configuring the Table style, which we're using to produce a more compact output than we had earlier.
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/views2-tablestyle-large.png"><img src="path:images/views2-tablestyle.png" /></a>
+<em>Selecting and configuring the table style</em>
+</div>
+
+... TODO: Finish this document ...
diff --git a/help/overrides.html b/help/overrides.html
new file mode 100644
index 0000000..59b68a9
--- /dev/null
+++ b/help/overrides.html
@@ -0,0 +1,7 @@
+<!-- $Id: overrides.html,v 1.2.6.1 2010/03/10 20:00:30 merlinofchaos Exp $ -->
+
+If an item is <strong>using defaults</strong> then it is using values from the <strong>default display</strong>. <em>IMPORTANT NOTE:</em> If you modify this value, you are modifying the <strong>default display</strong> and thus modifying for all displays that are using default values.
+
+If that is not what you intend, you must click the <strong>override</strong> button. Once overridden, that display now has its own version of the value; modifying it will not modify it for other displays.
+
+For <strong>Relationships</strong>, <strong>arguments</strong>, <strong>fields</strong>, <strong>sort criteria</strong>, and <strong>filters</strong>, each of these must be overridden as a group! In other words, you cannot override a single filter, but instead must override all filters. A message will appear on the item to let you know what its status is, but you can only change the status by clicking on the header or the rearrange button for that item.
diff --git a/help/path.html b/help/path.html
new file mode 100644
index 0000000..2c4404e
--- /dev/null
+++ b/help/path.html
@@ -0,0 +1,8 @@
+<!-- $Id: path.html,v 1.3 2008/06/25 19:26:01 merlinofchaos Exp $ -->
+If a display has a path that means that it can be retrieved directly by calling a URL as a first class page on your Drupal site. Any items after the path will be passed into the view as arguments. For example, if the path is <strong>foo/bar</strong> and a user visits <strong>http://www.example.com/foo/bar/baz/beta</strong>, 'baz' and 'beta' will be given as arguments to the view. These can be handled by adding items to the <a href="topic:views/arguments">arguments</a> section.
+
+You may also use placeholders in your path to represent arguments that come in the middle. For example, the path <strong>node/%/someview</strong> would expect the first argument to be the second part of the path. For example, <strong>node/21/someview</strong> would have an argument of '21'.
+
+<em>Note:</em> Views 1 used <strong>$arg</strong> for this kind of thing. $arg is no longer allowed as part of the path. You must use % instead.
+
+If multiple displays <strong>within the same view</strong> have the same path, the user will get the first display they have access to. This means you can create successfuly less restricted displays in order to give administrators and privileged users different content at the same path. \ No newline at end of file
diff --git a/help/relationship.html b/help/relationship.html
new file mode 100644
index 0000000..b37ce14
--- /dev/null
+++ b/help/relationship.html
@@ -0,0 +1,14 @@
+<!-- $Id: relationship.html,v 1.6 2009/02/20 20:46:48 merlinofchaos Exp $ -->
+Relationships allow you to expand the query to include objects other than the base query. This is actually made more difficult to understand by the fact that Views actually includes a few relationships by default, and doesn't tell you they're there. For historical reasons, it would be inconvenient to remove these default relationships. When relationships are present, all fields (including relationships) will gain a new form item to let you select which relationship they will use. They will default to using no relationship at all.
+
+The main example of the relationship that is there by default is the node --&gt; user relationship; every node has an author, and if a node is in the query, the user who wrote that node is automatically made available. [Note: the author considers it an error that this relationship is automatic, but by the time it was realized this was in error, it was too late to change it.]
+
+A similar relationship that is <b>not</b> automatically made available is for node revisions. Each revision has its own author, which is the user who made the revision. By adding the "Node revision: User" relationship, all of the 'user' fields, sorts, filters and arguments available to a user will now be available for the revision author.
+
+When a relationship is added to the view, all applicable items will gain a "Relationship" select box, where you can choose which version of that particular item you wish to use. This can be illustrated with an example:
+
+A 'comment' view contains the relationships 'Comment: node' and 'Comment: user'. This means that all the fields for the node that a comment is attached to are available, and all the user fields for that node author also become available. The other relationship makes fields for the author of the comment available -- very often not the author of the node!
+
+When you add the "User: name" field, you will be presented with a select box. Either the node relationship or the user relationship must be selected, because there are two possible user names in the view to choose from.
+
+Another example of relationships involves the <strong>Files</strong> table. In Drupal, files are related to users, but files are not necessarily related to nodes. However, the upload.module allows some files to be attached to nodes. The only way for Views to deal with this discrepancy is with relationships. When creating a 'node' view, it's possible to add an uploaded files relationship to get file data for nodes that were attached with the upload module. It is also possible to go the other way; from a files view you may add a relationship via the Upload table to view information about the node.
diff --git a/help/sort.html b/help/sort.html
new file mode 100644
index 0000000..645f2dd
--- /dev/null
+++ b/help/sort.html
@@ -0,0 +1,25 @@
+<!-- $Id: sort.html,v 1.2 2008/06/13 00:56:19 merlinofchaos Exp $ -->
+Sort criteria determine what order the records are retrieved from the database and displayed in; generally, all you need to do is pick a field and choose ascending (1, 2, 3, 4) or descending (4, 3, 2, 1) and it will be done. If you have multiple sort criteria, the second (and later) items only come into play if the first item is the same.
+
+Different data types sort just a little bit differently from others:
+<dl>
+<dt>Number fields</dt>
+<dd>Number fields sort like you would expect. 1 comes before 2 which comes before 10 which comes before 100 which comes before 200, etc.</dd>
+<dt>Text fields</dt>
+<dd>Text fields always sort alphabetically, even if the text contains numbers. This can have some odd effects if you have numbers stored in text, because the values 1, 3, 7, 10, 12, 20, 100, 120 will sort like this:
+<ul>
+<li> 1 </li>
+<li> 10 </li>
+<li> 100 </li>
+<li> 12 </li>
+<li> 120 </li>
+<li> 200 </li>
+<li> 3 </li>
+<li> 7 </li>
+</ul>
+
+This is because these fields sort purely by characters, and not numeric value. i.e, comparing 200 and 3, the '2' comes before the '3', therefore, '200' is "smaller" than '3'.
+</dd>
+<dt>Date fields</dt>
+<dd>Date fields often can have a 'granularity', which is a way of making similar dates actually be the same date. Take two dates that are close to each other: <strong>May 1, 2007 5:30 am</strong> and <strong>May 1, 2007 9:45am</strong>. Without granularity, the two dates are compared and the first date comes before the second date. However, if the granularity is set to 'day' it only looks at the parts of the date up to the day: <strong>May 1, 2007</strong> and <strong>May 1, 2007</strong>. At that point, they are the same, and the sort would move on to the next sort criterion.</dd>
+</dl>
diff --git a/help/style-comment-rss.html b/help/style-comment-rss.html
new file mode 100644
index 0000000..774359c
--- /dev/null
+++ b/help/style-comment-rss.html
@@ -0,0 +1,2 @@
+<!-- $Id: style-comment-rss.html,v 1.1 2008/06/13 00:56:19 merlinofchaos Exp $ -->
+This row style is only available to RSS styles. It produces XML necessary for an RSS feed for the comment. \ No newline at end of file
diff --git a/help/style-fields.html b/help/style-fields.html
new file mode 100644
index 0000000..05a173b
--- /dev/null
+++ b/help/style-fields.html
@@ -0,0 +1,6 @@
+<!-- $Id: style-fields.html,v 1.3 2008/06/17 20:07:03 merlinofchaos Exp $ -->
+The <strong>fields</strong> row style displays each field defined in the view, one after another. Each field defines its own output.
+
+By default, each field is put in a &lt;div&gt; unless it is selected to be <em>inline</em>. If it is inline, it is put in a &lt;span&gt;. Two items in &lt;div&gt;s will be displayed one after another, with the second one below the first. Two items in &lt;span&gt;s will be displayed on the same line. One item in a &lt;span&gt; next to &lt;div&gt;s is the same as two items in &lt;div&gt;s. This means that for the <em>inline</em> setting to do anything, at least two consecutive items must be set inline.
+
+You may define a separator which will be placed between each item. This separator may be html. You can use &amp;nbsp; to print blank space. \ No newline at end of file
diff --git a/help/style-grid.html b/help/style-grid.html
new file mode 100644
index 0000000..d9b24fc
--- /dev/null
+++ b/help/style-grid.html
@@ -0,0 +1,21 @@
+<!-- $Id: style-grid.html,v 1.3.6.1 2009/11/02 22:01:26 merlinofchaos Exp $ -->
+The <strong>grid</strong> style will display each row of your view within a grid. You may customize the number of columns, though it defaults to 4. A grid looks like this:
+
+<table width="100%">
+<tr><td>row 1</td><td>row 2</td><td>row 3</td><td>row 4</td></tr>
+<tr><td>row 5</td><td>row 6</td><td>row 7</td><td>row 8</td></tr>
+<tr><td>row 9</td><td>row 10</td><td>row 11</td><td>row 12</td></tr>
+<tr><td>row 13</td><td>row 14</td><td>row 15</td><td>row 16</td></tr>
+</table>
+
+The above uses the 'horizontal' alignment, where rows are added into the grid from left to right.
+
+With a vertical alignment, rows will be placed from top to bottom, like this:
+<table width="100%">
+<tr><td>row 1</td><td>row 5</td><td>row 9</td><td>row 13</td></tr>
+<tr><td>row 2</td><td>row 6</td><td>row 10</td><td>row 14</td></tr>
+<tr><td>row 3</td><td>row 7</td><td>row 11</td><td>row 15</td></tr>
+<tr><td>row 4</td><td>row 8</td><td>row 12</td><td>row 16</td></tr>
+</table>
+
+This style uses a <a href="topic:views/style-row">row style</a> to determine what each row will look like. \ No newline at end of file
diff --git a/help/style-list.html b/help/style-list.html
new file mode 100644
index 0000000..f5e98ba
--- /dev/null
+++ b/help/style-list.html
@@ -0,0 +1,21 @@
+<!-- $Id: style-list.html,v 1.3.6.1 2009/11/02 22:01:26 merlinofchaos Exp $ -->
+The <strong>List</strong> view style will display every row of the view as part of an HTML list construct. For example:
+<ul>
+<li> Row 1 </li>
+<li> Row 2 </li>
+<li> Row 3 </li>
+<li> Row 4 </li>
+</ul>
+
+You may select whether or not the list is <em>ordered</em> which just means whether or not it uses numbers instead of the bullet:
+
+<ol>
+<li> Row 1 </li>
+<li> Row 2 </li>
+<li> Row 3 </li>
+<li> Row 4 </li>
+</ol>
+
+The list style also uses a <em>row style</em> which means that it doesn't care what the actual output for each row of the view is.
+
+If you need information about using CSS to style list views, you may find this <a href="http://www.alistapart.com/stories/taminglists/">A list apart guide to styling lists</a> useful. \ No newline at end of file
diff --git a/help/style-node-rss.html b/help/style-node-rss.html
new file mode 100644
index 0000000..332b285
--- /dev/null
+++ b/help/style-node-rss.html
@@ -0,0 +1,2 @@
+<!-- $Id: style-node-rss.html,v 1.2 2008/06/13 00:56:19 merlinofchaos Exp $ -->
+This row style is only available to RSS styles. It produces XML necessary for an RSS feed for the node record. \ No newline at end of file
diff --git a/help/style-node.html b/help/style-node.html
new file mode 100644
index 0000000..360b96f
--- /dev/null
+++ b/help/style-node.html
@@ -0,0 +1,10 @@
+<!-- $Id: style-node.html,v 1.4.6.1 2010/09/15 09:01:01 dereine Exp $ -->
+The <strong>node</strong> row style will display each item of the view through Drupal's standard <em>node_view()</em> function. Views has very little control over this output, except for the options you see. Instead, the output is run through the standard node template mechanism (typically <strong>node.tpl.php</strong> or a variant thereof) and any decisions about what is output may be done there.
+
+Views does add an extra 'suggestion' to the list of possible node templates: <strong>node--view--VIEWNAME.tpl.php</strong> -- you may use this to theme a node specifically for the view. This can be handy for creating very small teasers and the like.
+
+You may opt to display the full node body or the node teaser, and you may add the node links (such as he 'comment' links that appear after a node) or not.
+
+Because of this behavior, <strong>the node row style does not utilize fields</strong> and the Fields section will not be displayed.
+
+<strong>Please note that this row style performs a node_load() for every row, and as such can produce a lot of extra queries.</strong> Sometimes this is necessary, but it can have a negative impact on your site's performance!
diff --git a/help/style-row.html b/help/style-row.html
new file mode 100644
index 0000000..2d98303
--- /dev/null
+++ b/help/style-row.html
@@ -0,0 +1,4 @@
+<!-- $Id: style-row.html,v 1.1 2008/06/13 00:56:19 merlinofchaos Exp $ -->
+A row style is an individual style to display only an individual record within a view. For example, a <strong>node</strong> type view would display one node per row; a <strong>user</strong> type view would display one user per row.
+
+Some row styles use <em>fields</em> which means you select from the available fields to display; others do not; they are able to use the base type and create a display. Usually, row styles that do not use fields <em>produce less efficient (slower) views</em>, so bear this in mind when contemplating the performance of your site. \ No newline at end of file
diff --git a/help/style-rss.html b/help/style-rss.html
new file mode 100644
index 0000000..d661fd7
--- /dev/null
+++ b/help/style-rss.html
@@ -0,0 +1,4 @@
+<!-- $Id: style-rss.html,v 1.2 2008/06/13 00:56:19 merlinofchaos Exp $ -->
+The <strong>RSS</strong> output style is only available for <em>Feed</em> display types. It will display the view as an RSS feed, which is a specialized XML output. This output is not user visible, but can be parsed by feed readers for aggregation.
+
+You may supply a description for the RSS feed; most feed readers will display this description along with the contents of the feed. You may also select to use the site's mission statement for the description. \ No newline at end of file
diff --git a/help/style-summary-unformatted.html b/help/style-summary-unformatted.html
new file mode 100644
index 0000000..2350a15
--- /dev/null
+++ b/help/style-summary-unformatted.html
@@ -0,0 +1,4 @@
+<!-- $Id: style-summary-unformatted.html,v 1.1 2008/06/13 00:56:19 merlinofchaos Exp $ -->
+The <strong>unformatted summary</strong> style is only available for <em>summary</em> styles, which are when an argument has been set to provide a summary if it was not provided with a value. This summary provides the possible candidates for the argument one after another with no special formatting. If <em>inline</em> is selected, the summary items will be enclosed within &lt;span&gt; tags. Otherwise the items will be in &lt;div&gt; tags.
+
+You can also elect to display the number of matching records for the argument, plus change the number of items per page for the summary. This is often useful because summary views are often quite small, but other views quite space intensive. It is very common to have far more records available in the summary view than in the more normal view. \ No newline at end of file
diff --git a/help/style-summary.html b/help/style-summary.html
new file mode 100644
index 0000000..f6012a4
--- /dev/null
+++ b/help/style-summary.html
@@ -0,0 +1,4 @@
+<!-- $Id: style-summary.html,v 1.2 2008/06/13 00:56:19 merlinofchaos Exp $ -->
+The <strong>list summary</strong> style is only available for <em>summary</em> styles, which are when an argument has been set to provide a summary if it was not provided with a value. This summary provides a list of possible candidates for the argument in a standard HTML list. Like the normal list style, you may set this list to be ordered or not.
+
+You can also elect to display the number of matching records for the argument, plus change the number of items per page for the summary. This is often useful because summary views are often quite small, but other views quite space intensive. It is very common to have far more records available in the summary view than in the more normal view. \ No newline at end of file
diff --git a/help/style-table.html b/help/style-table.html
new file mode 100644
index 0000000..e7fb89b
--- /dev/null
+++ b/help/style-table.html
@@ -0,0 +1,14 @@
+<!-- $Id: style-table.html,v 1.2 2008/06/13 00:56:19 merlinofchaos Exp $ -->
+The <strong>table</strong> style will display the View results as a table; each row of the table will correspond to a row from the view result.
+
+When setting the table options, each field in the view will be presented with some information next to each field:
+<dl>
+<dt> <strong>Column</strong> </dt>
+<dd> By default, each field is its own column. However, you can place multiple fields in the same column. To do this, pick which field you want to represent the column, then pick another field and set the 'column' value to that field. You can place as many fields as you like in a single column, but only the main field in a column can be click-sorted.</dd>
+<dt> <strong>Separator</strong> </dt>
+<dd> If you have multiple fields in the same column, the separator will be placed between each one. At the very least, &amp;nbsp; should be used, as without the separator the fields will be placed very close to each other. Common separators are a bullet, the | symbol, and a comma. If there are no other fields in the column, the separator will have no effect.</dd>
+<dt> <strong>Sortable</strong> </dt>
+<dd> If checked, the header for the column will be clickable, and the user may re-sort the table by clicking on this to sort by that field. At this time Views does not support click-sorting to sort by multiple columns at the same time.</dd>
+<dt> <strong>Default sort</strong> </dt>
+<dd> You may select a column which will be sorted by default when the table is first viewed. This column will be highlighted to the user. You may also select whether the default sort is ascending or descending.</dd>
+</dl> \ No newline at end of file
diff --git a/help/style-unformatted.html b/help/style-unformatted.html
new file mode 100644
index 0000000..777d2ed
--- /dev/null
+++ b/help/style-unformatted.html
@@ -0,0 +1,2 @@
+<!-- $Id: style-unformatted.html,v 1.2 2008/06/13 00:56:19 merlinofchaos Exp $ -->
+The unformatted output style simply places each row of the view, one after another, with no additional formatting.
diff --git a/help/style.html b/help/style.html
new file mode 100644
index 0000000..3eb6fdf
--- /dev/null
+++ b/help/style.html
@@ -0,0 +1,15 @@
+<!-- $Id: style.html,v 1.4.6.1 2010/03/16 22:27:29 merlinofchaos Exp $ -->
+The Views' <strong>style</strong> system is how you customize the output produced by your view. A view style is basically a smart theme template that processes the view data and then outputs it. All styles in Views can be <a href="topic:views/using-theme">overridden</a> by placing copies of the templates in your theme directory and then modifying them. See the <a href="topic:views/analyze-theme">theme: information</a> link available on all views to get hints for which templates a given view is using.
+
+<div class="help-box" style="text-align:center">
+<a href="path:images/style-breakdown-large.png"><img src="path:images/style-breakdown.png" /></a>
+<em>A breakdown of View output</em>
+</div>
+By default, the style is <em>unformatted</em>, which means that there is very little style actually used; the records are simply displayed one after another, enclosed in a &lt;div&gt; tag so that you can use <a href="topic:views/theme-css">CSS to manipulate the view</a>.
+
+Some styles use a separate <a href="topic:views/style-row">row style</a> to determine how each row of the View looks. This is useful for mixing and matching styles to more readily produce exactly the kind of output you need.
+
+Many styles can be <strong>grouped</strong>. For styles that can, there will be a 'grouping field' option; pick one of the fields to group by. This grouping field will be displayed as a header, and all rows will be displayed beneath it.
+With the Theme Developer module enabled, the field grouping in Views does not work. Disable the Theme Developer module before grouping by fields.
+
+Each style is its own entity.
diff --git a/help/theme-css.html b/help/theme-css.html
new file mode 100644
index 0000000..bfa3593
--- /dev/null
+++ b/help/theme-css.html
@@ -0,0 +1,76 @@
+<!-- $Id: theme-css.html,v 1.3.6.1 2009/11/02 22:01:26 merlinofchaos Exp $ -->
+Views uses a wide array of CSS classes on all of its content to ensure that you can easily and accurately select exactly the content you need in order to manipulate it with CSS.
+
+Typically, every view is wrapped in a div with the name of the view as part of its class (for all these examples, we will assume the name of the view is <strong>myview</strong>), as well as the generic class 'view':
+
+<pre>
+&lt;div class="view view-myview"&gt;
+...
+&lt;/div&gt;
+</pre>
+
+In your CSS, you can modify all views:
+
+<pre>
+div.view {
+ border: 1px solid black;
+}
+</pre>
+
+Or just your view:
+
+<pre>
+div.view-myview {
+ background: yellow;
+}
+</pre>
+
+By default, the general view template also provides the following classes to easily style other areas of the view:
+<ul>
+<li> .view-header </li>
+<li> .view-filters </li>
+<li> .view-content </li>
+<li> .view-empty (if an "empty" text is used when the view has no results) </li>
+<li> .view-footer </li>
+<li> .feed-icon </li>
+<li> .attachment-before (if using an "attachment" display)</li>
+<li> .attachment-after (if using an "attachment" display)</li>
+</ul>
+
+So for example:
+<pre>
+div.view-myview div.view-header {
+ /* make the header stand out */
+ font-size: 120%;
+ font-weight: bold;
+}
+
+div.view-myview div.view-footer {
+ /* Make the footer less important */
+ font-size: 80%;
+ font-style: italic;
+ color: #CCC;
+}
+</pre>
+
+In the above example, we whimsically made the header bold and in a bigger font, and the footer smaller, italicized, and greyish.
+
+<h3>Views with fields</h3>
+If your view has fields, each field is uniquely tagged with its ID. A field's ID may be gleaned from the Theme: Information page. Note that due to CSS rules, any _ in the id will be converted to - automatically, so if you have a field whose id is 'edit_node' (this is the field used to provide an "edit" link to a node), it will be 'edit-node'. Additionally, to make sure that the view IDs don't conflict with other css classes in the system, they will be pretended with 'views-field-'; thus, the final CSS class for the field with the id 'edit_node' will be <strong>views-field-edit-node</strong>.
+
+Exactly how this appears is going to depend upon the style you're using. For example, the 'unformatted' style uses <strong>div.views-field-edit-node</strong> and <strong>div.views-label-edit-node</strong> to access that particular field, but a table would use <strong>td.views-field-edit-node</strong> and <strong>th.views-field-edit-node</strong> to access the table header; or just <strong>.views-field-edit-node</strong> to affect both.
+
+<pre>
+.view-myview th {
+ color: red; /* make all headers red */
+}
+
+.view-myview .views-field-title {
+ font-weight: bold; /* Make the 'title' field bold */
+}
+
+.view-myview td.views-field-body {
+ font-size: 60%; /* Make the text in the body field small */
+}
+</pre>
+
diff --git a/help/updating.html b/help/updating.html
new file mode 100644
index 0000000..67f246a
--- /dev/null
+++ b/help/updating.html
@@ -0,0 +1,3 @@
+<!-- $Id: updating.html,v 1.3 2008/07/03 05:05:12 merlinofchaos Exp $ -->
+TODO: This document needs to be fleshed out.
+
diff --git a/help/upgrading.html b/help/upgrading.html
new file mode 100644
index 0000000..a4c6dab
--- /dev/null
+++ b/help/upgrading.html
@@ -0,0 +1,6 @@
+;<!-- $Id: upgrading.html,v 1.1.2.1 2010/08/26 19:00:51 dereine Exp $ -->
+
+<h3>Updating templates</h3>
+If you have theme files for node-view-$viewname of comment-view-$viewname you have
+to convert them to node--view--$viewname or comment--view--$viewname.
+
diff --git a/help/using-theme.html b/help/using-theme.html
new file mode 100644
index 0000000..c94bbd5
--- /dev/null
+++ b/help/using-theme.html
@@ -0,0 +1,51 @@
+<!-- $Id: using-theme.html,v 1.6.6.1 2009/11/02 22:01:26 merlinofchaos Exp $ -->
+Views theme templates are straightforward to use with the Drupal theming system. If you are unfamiliar with the theming system at all, you should probably at least read <a href="http://drupal.org/node/173880">drupal.org theming documentation</a>. That said, these are the important things you need to know:
+
+<ol>
+<li> Copy a base Views template to one of the names provided from the Theme: Information section of the View. Copy this template right into your theme directory. </li>
+<li> Clear the theme registry. See the <a href="http://drupal.org/node/173880#theme-registry">instructions</a> for how to do this. </li>
+<li> Your new template should now operate; assuming you picked a nicely named template that includes the view name, that template should now be active for your view. A good example is <strong>views-view-list--foobar.tpl.php</strong> which would work for a view named 'foobar'.</li>
+<li> You can now modify this template all you like.</li>
+</ol>
+
+For any template that uses fields, the fields will be in array. In order to use this effectively, you will need to understand enough PHP to fetch data from an array. This is a place where the <a href="http://drupal.org/project/devel">devel module</a> can really help you, because you can use its dsm() function right in your template to see what variables it uses. There is an alternative to dsm() that works without devel module, but it's a bit longer to use.
+
+For example, I placed the following code inside a loop in views-view-table.php.php:
+<code> &lt;?php drupal_set_message('&lt;pre&gt;' . var_export($row, true) . '&lt;/pre&gt;'); ?&gt;
+</code>
+
+And it produced this output:
+<code> array (
+ 'nid' =&gt; '97',
+ 'title' =&gt; 'Scisco Ideo Vicis Feugiat Qui',
+ 'name' =&gt; 'luwrepuslan',
+ )
+</code>
+
+My view had three fields:
+<code>Node: Nid
+Node: Title
+User: Name
+</code>
+
+The contents of the $row variable included these fields, in precisely the order that I had arranged them to using the Views rearrange link. Also worth noting, though, is that each field also has an identifier so it can easily be pulled out of the row should I want to display it differently. Using
+<code>&lt;?php print $row['title']; ?&gt;
+</code>
+
+Would print just the title for that row. Please remember that I'm doing this inside the loop, so this will get repeated for every row of the view.
+
+The IDs used to fetch items from the array, id <strong>$row['title']</strong> can be quickly and easily looked up on the Theme: Information page. Once a field has been added to the view, its ID will not change, but note that if there are two "title" fields in a view, one will be 'title' and the other will be 'title1', in order to prevent namespace collisions.
+
+The important thing here is that Views does provide IDs. Views doesn't tell you what these IDs are, but it's easy to get them by dumping the row data and doing a simple visual inspection. Views does guarantee that these IDs will not change, unless you actually add a new field and remove the existing one (in which case 'title', above, would become 'title1').
+
+<h2>The basic fields template</h2>
+
+The most common template people will need to rewrite is the "simple" views-view-fields.tpl.php, which is the template used by the <i>Fields</i> row style and all it does is display a simple list of fields. However, it is not that simple to the user. Because the template can't inherently know what the fields are, it has to go through an array in a loop.
+
+This loop isn't very handy when you really want to have fine control over the template by placing your fields precisely where and how you want. Relax, though; if you know what your fields are, you can rewrite this. If you end up writing your own HTML, the only part that is really important is the content for each field. We know from above that you can get the ID for each field on the Theme: Information page from the view. In the header for the template, we can see that the fields are all in the $fields array, and each field is an object. That leads us to this:
+
+<code>&lt;?php print $fields['some_id']-&gt;content; ?&gt;</code>
+
+Assuming you replace some_id with an id found on the theme: information page, this code will print the content for that field. You can also get the label and some other data about the field, as well as the raw information. Complete details for what is available are documented directly in views-view-fields.tpl.php.
+
+Keep in mind that if you rewrite your templates using this, you'll need to maintain this template whenever changes are made to the fields of the view; while this isn't generally recommend, sometimes it's necessary to get the kind of control you might ultimately need.
diff --git a/help/view-type.html b/help/view-type.html
new file mode 100644
index 0000000..3285a85
--- /dev/null
+++ b/help/view-type.html
@@ -0,0 +1,22 @@
+<!-- $Id: view-type.html,v 1.5 2009/02/20 20:46:48 merlinofchaos Exp $ -->
+<p>The <strong>view type</strong> describes how this view is stored; Views is capable of having Views entirely in code that are not in the database. This allows modules to easily ship with Views built in, and it allows you to create a module to store your views for easy deployment between development and production servers.</p>
+
+<dl>
+<dt><strong>Normal</strong></dt>
+<dd>Normal views are stored in your database and are completely local to your system.</dd>
+
+<dt><strong>Default</strong></dt>
+<dd>Default views are stored only in code and are not anywhere in your database. They may be <strong>enabled</strong> or <strong>disabled</strong> but you may not completely remove them from your system. You can <strong>override</strong> the view which will create a local copy of your view. If you do this, future updates to the version in code will not affect your view.</dd>
+
+<dt><strong>Overridden</strong></dt>
+<dd>Overridden views are stored both in code and in the database; while overridden, the version that is in code is completely dormant. If you <strong>revert</strong> the view, the version in the database will be deleted, and the version that is in code will once again be used.</dd>
+</dl>
+
+You may store your views in code with the following procedure:
+<ol>
+<li> Create a module to store the views. </li>
+<li> Add the function <em>MODULENAME_views_default_views()</em> to this module. </li>
+<li> Export the view you wish to store in your module in code. Cut and paste that into the abovenamed function. Make sure the last line of the view is: <em>$views[$view-&gt;name] = $view;</em></li>
+<li> Make sure the last line of the function is <em>return $views;</em></li>
+<li> After you make any changes, be sure to <strong>clear the Views' cache</strong>. You may do this from the <strong>Tools</strong> menu.</li>
+</ol>
diff --git a/help/views.help.ini b/help/views.help.ini
new file mode 100644
index 0000000..0895d5a
--- /dev/null
+++ b/help/views.help.ini
@@ -0,0 +1,204 @@
+; $Id: views.help.ini,v 1.18.4.5 2010/08/26 19:00:51 dereine Exp $
+[advanced help settings]
+line break = TRUE
+
+[about]
+title = "What is Views?"
+weight = -40
+
+[getting-started]
+title = "Getting started"
+weight = -45
+
+[example-users-by-role]
+title = "Create a page to list users by role"
+parent = getting-started
+weight = -10
+
+[example-recent-stories]
+title = "Create a block of recent stories"
+parent = getting-started
+weight = 0
+
+[example-user-feed]
+title = "Create an RSS feed of user posts"
+parent = getting-started
+weight = 30
+
+[example-author-block]
+title = "Create a block of author's recent blog posts"
+parent = getting-started
+weight = 40
+
+[view-type]
+title = "View types"
+
+[display]
+title = "Displays"
+weight = -30
+
+[display-default]
+title = "Default display"
+parent = display
+weight = -20
+
+[display-page]
+title = "Page display"
+parent = display
+weight = -15
+
+[display-block]
+title = "Block display"
+parent = display
+weight = -10
+
+[display-attachment]
+title = "Attachment display"
+parent = display
+
+[display-feed]
+title = "Feed display"
+parent = display
+
+[argument]
+title = "Arguments"
+parent = about
+
+[field]
+title = "Fields"
+parent = about
+
+[sort]
+title = "Sorts"
+parent = about
+
+[filter]
+title = "Filters"
+parent = about
+
+[relationship]
+title = "Relationships"
+parent = about
+
+[style]
+title = "Output styles (View styles)"
+weight = -20
+
+[style-row]
+title = "View row styles"
+parent = style
+weight = 10
+
+[style-list]
+title = "List output style"
+parent = style
+
+[style-unformatted]
+title = "Unformatted output style"
+parent = style
+weight = -6
+
+[style-table]
+title = "Table output style"
+parent = style
+weight = -5
+
+[style-grid]
+title = "Grid output style"
+parent = style
+weight = -5
+
+[style-rss]
+title = "RSS output style"
+parent = style
+weight = -5
+
+[style-fields]
+title = "Fields row style"
+parent = style-row
+
+[style-node]
+title = "Node row style"
+parent = style-row
+
+[style-node-rss]
+title = "Node RSS item row style"
+parent = style-row
+
+[style-comment-rss]
+title = "Comment RSS item row style"
+parent = style-row
+
+[style-summary-unformatted]
+title = "Unformatted summary style"
+parent = "style"
+weight = 10
+
+[style-summary]
+title = "List summary style"
+parent = "style"
+weight = 10
+
+[menu]
+title = "Menu options (page display)"
+
+[path]
+title = "Path options (page display)"
+
+[analyze-theme]
+title = "Theme information"
+
+[using-theme]
+title = "Using Views templates"
+parent = analyze-theme
+
+[theme-css]
+title = "Using CSS with Views"
+parent = analyze-theme
+
+[overrides]
+title = "What are overrides?"
+
+[embed]
+title = "Embedding a view into other parts of your site"
+
+[new]
+title = "What's new in Views 2"
+weight = -42
+
+[upgrading]
+title = "Upgrading your Views from Drupal 6 to Drupal 7"
+
+; API related
+[api]
+title = "Views' API"
+weight = 100
+
+[api-tables]
+title = "Describing tables to Views"
+weight = -100
+parent = api
+
+[api-default-views]
+title = "Using default views in your module"
+weight = -90
+parent = api
+
+[api-handlers]
+title = "How Views handlers work"
+weight = -50
+parent = api
+
+[api-plugins]
+title = "How Views plugins work"
+weight = -40
+parent = api
+
+[api-upgrading]
+title = "Upgrading to Drupal 7 (API)"
+parent = api
+
+[api-example]
+title = "Integrating the Node Example module"
+parent = api
+weight = 100
diff --git a/images/CVS/Entries b/images/CVS/Entries
new file mode 100644
index 0000000..90659c7
--- /dev/null
+++ b/images/CVS/Entries
@@ -0,0 +1,6 @@
+/arrow-active.png/1.1/Fri May 16 01:15:54 2008/-kb/TDRUPAL-7--3
+/expanded-options.png/1.2/Tue Sep 15 17:32:19 2009/-kb/TDRUPAL-7--3
+/overridden.gif/1.1/Fri Aug 8 16:57:44 2008/-kb/TDRUPAL-7--3
+/sprites.png/1.1/Wed Feb 13 06:30:36 2008/-kb/TDRUPAL-7--3
+/status-active.gif/1.1/Sat Mar 29 00:57:38 2008/-kb/TDRUPAL-7--3
+D
diff --git a/images/CVS/Repository b/images/CVS/Repository
new file mode 100644
index 0000000..e2830b1
--- /dev/null
+++ b/images/CVS/Repository
@@ -0,0 +1 @@
+contributions/modules/views/images
diff --git a/images/CVS/Root b/images/CVS/Root
new file mode 100644
index 0000000..127da18
--- /dev/null
+++ b/images/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal-contrib
diff --git a/images/CVS/Tag b/images/CVS/Tag
new file mode 100644
index 0000000..0f07c7f
--- /dev/null
+++ b/images/CVS/Tag
@@ -0,0 +1 @@
+TDRUPAL-7--3
diff --git a/images/arrow-active.png b/images/arrow-active.png
new file mode 100644
index 0000000..3bbd3c2
--- /dev/null
+++ b/images/arrow-active.png
Binary files differ
diff --git a/images/expanded-options.png b/images/expanded-options.png
new file mode 100644
index 0000000..b7b755c
--- /dev/null
+++ b/images/expanded-options.png
Binary files differ
diff --git a/images/overridden.gif b/images/overridden.gif
new file mode 100644
index 0000000..b781191
--- /dev/null
+++ b/images/overridden.gif
Binary files differ
diff --git a/images/sprites.png b/images/sprites.png
new file mode 100644
index 0000000..9083622
--- /dev/null
+++ b/images/sprites.png
Binary files differ
diff --git a/images/status-active.gif b/images/status-active.gif
new file mode 100644
index 0000000..207e95c
--- /dev/null
+++ b/images/status-active.gif
Binary files differ
diff --git a/includes/CVS/Entries b/includes/CVS/Entries
new file mode 100644
index 0000000..1cdfc44
--- /dev/null
+++ b/includes/CVS/Entries
@@ -0,0 +1,12 @@
+/admin.inc/1.161.4.58/Sun Nov 7 19:47:42 2010//TDRUPAL-7--3
+/ajax.inc/1.20.4.16/Sun Nov 7 19:47:42 2010//TDRUPAL-7--3
+/analyze.inc/1.1.6.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/base.inc/1.3.4.5/Thu Aug 26 09:41:55 2010//TDRUPAL-7--3
+/cache.inc/1.25.4.8/Tue Oct 26 19:06:26 2010//TDRUPAL-7--3
+/convert.inc/1.17.4.1/Mon Nov 2 22:01:26 2009//TDRUPAL-7--3
+/form.inc/1.11.4.3/Mon Apr 12 21:59:58 2010//TDRUPAL-7--3
+/handlers.inc/1.119.4.16/Fri Nov 5 07:20:54 2010//TDRUPAL-7--3
+/plugins.inc/1.156.4.11/Sat Nov 6 16:52:34 2010//TDRUPAL-7--3
+/tabs.inc/1.7.6.3/Sat Mar 20 23:16:37 2010//TDRUPAL-7--3
+/view.inc/1.167.4.30/Thu Oct 14 20:08:16 2010//TDRUPAL-7--3
+D
diff --git a/includes/CVS/Repository b/includes/CVS/Repository
new file mode 100644
index 0000000..73012cc
--- /dev/null
+++ b/includes/CVS/Repository
@@ -0,0 +1 @@
+contributions/modules/views/includes
diff --git a/includes/CVS/Root b/includes/CVS/Root
new file mode 100644
index 0000000..127da18
--- /dev/null
+++ b/includes/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous:anonymous@cvs.drupal.org:/cvs/drupal-contrib
diff --git a/includes/CVS/Tag b/includes/CVS/Tag
new file mode 100644
index 0000000..0f07c7f
--- /dev/null
+++ b/includes/CVS/Tag
@@ -0,0 +1 @@
+TDRUPAL-7--3
diff --git a/includes/admin.inc b/includes/admin.inc
new file mode 100644
index 0000000..b31bfe5
--- /dev/null
+++ b/includes/admin.inc
@@ -0,0 +1,3390 @@
+<?php
+// $Id: admin.inc,v 1.161.4.58 2010/11/07 19:47:42 dereine Exp $
+/**
+ * @file admin.inc
+ * Provides the Views' administrative interface.
+ */
+
+/**
+ * Page callback to list views in the system.
+ */
+function views_ui_list_views($arg = NULL) {
+ if ($arg != NULL) {
+ return drupal_not_found();
+ }
+
+ $output = theme('views_ui_list_views');
+ views_ui_check_advanced_help();
+ return $output;
+}
+
+/**
+ * Check to see if the advanced help module is installed, and if not put up
+ * a message.
+ *
+ * Only call this function if the user is already in a position for this to
+ * be useful.
+ */
+function views_ui_check_advanced_help() {
+ if (variable_get('views_hide_help_message', FALSE)) {
+ return;
+ }
+
+ if (!module_exists('advanced_help')) {
+ $filename = db_query_range("SELECT filename FROM {system} WHERE type = 'module' AND name = 'advanced_help'", 0, 1)
+ ->fetchField();
+ if ($filename && file_exists($filename)) {
+ drupal_set_message(t('If you <a href="@modules">enable the advanced help module</a>, Views will provide more and better help. <a href="@hide">Hide this message.</a>', array('@modules' => url('admin/modules'),'@hide' => url('admin/structure/views/tools'))));
+ }
+ else {
+ drupal_set_message(t('If you install the advanced help module from !href, Views will provide more and better help. <a href="@hide">Hide this message.</a>', array('!href' => l('http://drupal.org/project/advanced_help', 'http://drupal.org/project/advanced_help'), '@hide' => url('admin/structure/views/tools'))));
+ }
+ }
+}
+
+/**
+ * Preprocess the list views theme
+ */
+function template_preprocess_views_ui_list_views(&$vars) {
+ $items = array();
+ $sorts = array();
+
+ $views = views_get_all_views();
+
+ // Respond to a reset command by clearing session and doing a drupal goto
+ // back to the base URL.
+ if (isset($_GET['op']) && $_GET['op'] == t('Reset')) {
+ unset($_SESSION['views']['#admin']);
+ drupal_goto('admin/structure/views');
+ }
+ if (count($_GET) <= 1) {
+ if (isset($_SESSION['views']['#admin']) && is_array($_SESSION['views']['#admin'])) {
+ $_GET += $_SESSION['views']['#admin'];
+ }
+ }
+ else {
+ $_SESSION['views']['#admin'] = $_GET;
+ unset($_SESSION['views']['#admin']['q']);
+ }
+
+ $form_state = array(
+ 'views' => $views,
+ 'method' => 'get',
+ 'rerender' => TRUE,
+ 'no_redirect' => TRUE,
+ 'always_process' => TRUE,
+ 'build_info' => array(
+ 'args' => array(),
+ ),
+ );
+
+ $vars['widgets'] = drupal_build_form('views_ui_list_views_form', $form_state);
+ unset($vars['widgets']['form_id']);
+ unset($vars['widgets']['form_build_id']);
+ $vars['widgets'] = drupal_render($vars['widgets']);
+
+ $vars['help_type_icon'] = '';
+ if (module_exists('advanced_help')) {
+ $vars['help_type_icon'] = theme('advanced_help_topic', array('module' => 'views', 'topic' => 'view-type'));
+ }
+
+ $base_tables = views_fetch_base_tables();
+
+ foreach ($views as $view) {
+ if ($form_state['values']['tag'] != 'all') {
+ if ($form_state['values']['tag'] == 'none') {
+ if (!empty($view->tag)) {
+ continue;
+ }
+ }
+ elseif ($form_state['values']['tag'] != $view->tag) {
+ continue;
+ }
+ }
+ if ($form_state['values']['type'] != 'all' && $form_state['values']['type'] != $view->type) {
+ continue;
+ }
+
+ if ($form_state['values']['base'] != 'all' && $form_state['values']['base'] != $view->base_table) {
+ continue;
+ }
+
+ if ($form_state['values']['display'] != 'all' && empty($view->display[$form_state['values']['display']])) {
+ continue;
+ }
+
+ if ($form_state['values']['status'] != 'all' && (!empty($view->disabled) == $form_state['values']['status'])) {
+ continue;
+ }
+
+ $item = new stdClass();
+ $item->ops = array();
+
+ if (empty($view->disabled)) {
+ $item->ops[] = l(t('Edit'), "admin/structure/views/edit/$view->name");
+ $item->ops[] = l(t('Export'), "admin/structure/views/export/$view->name");
+ $item->ops[] = l(t('Clone'), "admin/structure/views/clone/$view->name");
+ }
+ if ($view->type != t('Default')) {
+ $text = $view->type == t('Overridden') ? t('Revert') : t('Delete');
+ $item->ops[] = l($text, "admin/structure/views/delete/$view->name");
+ }
+ else {
+ if (empty($view->disabled)) {
+ $item->ops[] = l(t('Disable'), "admin/structure/views/disable/$view->name", array('query' => drupal_get_destination()));
+ }
+ else {
+ $item->ops[] = l(t('Enable'), "admin/structure/views/enable/$view->name", array('query' => drupal_get_destination()));
+ }
+ }
+
+ $item->ops = implode(' | ', $item->ops);
+ if (empty($view->display)) {
+ $item->path = t('Warning! Broken view!');
+ }
+ else {
+ $view->init_display(); // Make sure all the handlers are set up
+ $all_paths = array();
+ foreach ($view->display as $display) {
+ if (!empty($display->handler) && $display->handler->has_path()) {
+ $one_path = $display->handler->get_option('path');
+ if (empty($path_sort)) {
+ $path_sort = strtolower($one_path);
+ }
+ if (empty($view->disabled) && strpos($one_path, '%') === FALSE) {
+ $all_paths[] = l($one_path, $one_path);
+ }
+ else {
+ $all_paths[] = check_plain($one_path);
+ }
+ }
+ }
+ if (!empty($all_paths)) {
+ $item->path = implode(', ', array_unique($all_paths));
+ }
+ }
+
+ $item->type = $view->type;
+ $item->name = $view->name;
+
+ if (!empty($view->tag)) {
+ $item->tag = $view->tag;
+ }
+
+ $item->title = $view->get_title();
+ $item->base = !empty($base_tables[$view->base_table]['title']) ? $base_tables[$view->base_table]['title'] : t('Broken');
+
+ $item->displays = array();
+ foreach ($view->display as $display) {
+ if (!empty($display->handler->definition['admin'])) {
+ $item->displays[$display->handler->definition['admin']] = TRUE;
+ }
+ }
+
+ if ($item->displays) {
+ ksort($item->displays);
+ $item->displays = implode(', ', array_keys($item->displays));
+ }
+
+ $item->description = check_plain($view->description);
+ $item->classes = empty($view->disabled) ? 'view-enabled' : 'view-disabled';
+ $items[] = $item;
+
+ $sort = intval(empty($view->disabled) xor $form_state['values']['sort'] == 'asc');
+
+ switch ($form_state['values']['order']) {
+ case 'name':
+ default:
+ $sort .= strtolower($view->name);
+ break;
+ case 'title':
+ $sort .= strtolower($item->title);
+ break;
+ case 'path':
+ $sort .= strtolower($raw_path); // $path;
+ break;
+ case 'type':
+ $sort .= $view->type . $view->name;
+ break;
+ case 'tag':
+ $sort .= strtolower($view->tag);
+ break;
+ case 'desc':
+ $sort .= strtolower($view->description);
+ break;
+ }
+
+ $sorts[] = $sort;
+ }
+
+ if ($form_state['values']['sort'] == 'desc') {
+ arsort($sorts);
+ }
+ else {
+ asort($sorts);
+ }
+
+ $i = array();
+ foreach ($sorts as $id => $title) {
+ $i[] = $items[$id];
+ }
+
+ views_add_css('views-list');
+ $vars['views'] = $i;
+
+ $getting_started = '';
+ if (module_exists('advanced_help')) {
+ $getting_started = theme('advanced_help_topic', array('module' => 'views', 'topic' => 'getting-started', 'type' => 'title'));
+ }
+ if (!$getting_started) {
+ $getting_started = t('Install the advanced help module for the getting started');
+ }
+
+ $vars['help'] = t('Not sure what to do? Try the "!getting-started" page.', array('!getting-started' => $getting_started));
+}
+
+/**
+ * Provide a form for sorting and filtering the list of views.
+ */
+function views_ui_list_views_form($form, &$form_state) {
+ if (!variable_get('clean_url', FALSE)) {
+ $form['q'] = array(
+ '#type' => 'hidden',
+ '#value' => $_GET['q'],
+ );
+ }
+
+ $all = array('all' => t('<All>'));
+ $none = array('none' => t('<None>'));
+
+ $form['type'] = array(
+ '#type' => 'select',
+ '#title' => t('Storage'),
+ '#options' => array(
+ 'all' => t('<All>'),
+ t('Normal') => t('Normal'),
+ t('Default') => t('Default'),
+ t('Overridden') => t('Overridden'),
+ ),
+ '#default_value' => 'all',
+ );
+
+ $status = array(
+ '0' => t('Disabled'),
+ '1' => t('Enabled'),
+ );
+ $form['status'] = array(
+ '#type' => 'select',
+ '#title' => t('Status'),
+ '#options' => array_merge($all, $status),
+ '#default_value' => 'all',
+ );
+
+ $bases = array();
+ foreach (views_fetch_base_tables() as $table => $info) {
+ $bases[$table] = $info['title'];
+ }
+
+ $form['base'] = array(
+ '#type' => 'select',
+ '#title' => t('Type'),
+ '#options' => array_merge($all, $bases),
+ '#default_value' => 'all',
+ );
+
+ $tags = array();
+
+ $extras = array();
+ if (isset($form_state['views'])) {
+ foreach ($form_state['views'] as $name => $view) {
+ if (!empty($view->tag)) {
+ $tags[$view->tag] = $view->tag;
+ }
+ }
+ }
+
+ asort($tags);
+
+ $form['tag'] = array(
+ '#type' => 'select',
+ '#title' => t('Tag'),
+ '#options' => array_merge($all, $none, $tags),
+ '#default_value' => 'all',
+ );
+
+ $displays = array();
+ foreach (views_fetch_plugin_data('display') as $id => $info) {
+ if (!empty($info['admin'])) {
+ $displays[$id] = $info['admin'];
+ }
+ }
+
+ asort($displays);
+
+ $form['display'] = array(
+ '#type' => 'select',
+ '#title' => t('Displays'),
+ '#options' => array_merge($all, $displays),
+ '#default_value' => 'all',
+ );
+
+ $form['order'] = array(
+ '#type' => 'select',
+ '#title' => t('Sort by'),
+ '#options' => array(
+ 'name' => t('Name'),
+ 'title' => t('Title'),
+ 'tag' => t('Tag'),
+ 'path' => t('Path'),
+ 'type' => t('Type'),
+ 'desc' => t('Description'),
+ ),
+ '#default_value' => 'name',
+ );
+
+ $form['sort'] = array(
+ '#type' => 'select',
+ '#title' => t('Order'),
+ '#options' => array(
+ 'asc' => t('Up'),
+ 'desc' => t('Down'),
+ ),
+ '#default_value' => 'asc',
+ );
+
+ $form['submit'] = array(
+ '#name' => '', // so it won't in the $_GET args
+ '#type' => 'submit',
+ '#id' => 'edit-views-apply',
+ '#value' => t('Apply'),
+ );
+
+ if (!empty($_SESSION['views']['#admin'])) {
+ $form['reset'] = array(
+ '#type' => 'submit',
+ '#id' => 'edit-views-reset',
+ '#value' => t('Reset'),
+ );
+ }
+ $form['#token'] = FALSE;
+
+ return $form;
+}
+
+/**
+ * Page callback for the live preview.
+ *
+ * @todo make this use a template
+ */
+function views_ui_preview($js, $view) {
+ // Take off the items we know so that we can have just the args passed
+ // in for later use.
+ $func_args = func_get_args();
+ array_shift($func_args); // $js
+ array_shift($func_args); // $view
+ $display_id = (count($func_args)) ? array_shift($func_args) : 'default';
+
+ $form_state = array(
+ 'display_id' => $display_id,
+ 'view_args' => $func_args ? implode('/', $func_args) : '',
+ 'rerender' => TRUE,
+ 'no_redirect' => TRUE,
+ 'view' => &$view,
+ 'ajax' => $js,
+ 'build_info' => array(
+ 'args' => array(),
+ ),
+ );
+
+ $output = drupal_render(drupal_build_form('views_ui_preview_form', $form_state));
+ $args = array();
+ if (isset($form_state['view_args']) && $form_state['view_args'] !== '') {
+ $args = explode('/', $form_state['view_args']);
+ }
+
+ $errors = $view->validate();
+ if ($errors === TRUE) {
+ $view->ajax = $js;
+ $view->live_preview = TRUE;
+ $view->set_exposed_input($_POST);
+
+ // Store the current view URL for later use:
+ $view->set_display($form_state['display_id']);
+ $view->set_arguments($args);
+
+ if ($view->display_handler->get_option('path')) {
+ $path = $view->get_url();
+ }
+
+ // Make view links come back to preview.
+ $view->override_path = 'admin/structure/views/nojs/preview/' . $view->name . '/' . $form_state['display_id'];
+
+ // also override $_GET['q'] so we get the pager
+ $_GET['q'] = $view->override_path;
+ if ($form_state['view_args']) {
+ $_GET['q'] .= '/' . $form_state['view_args'];
+ }
+
+ $preview = $view->preview($form_state['display_id'], $args);
+
+ // Get information from the preview for display.
+ if (!empty($view->build_info['query'])) {
+ $rows = array();
+ $query = $view->build_info['query'];
+ $rows[] = array('<strong>' . t('Query') . '</strong>', '<pre>' . check_plain(strtr($query, $query->getArguments())) . '</pre>');
+ if (!empty($view->additional_queries)) {
+ $queries = '<strong>' . t('These queries were run during view rendering:') . '</strong>';
+ foreach ($view->additional_queries as $query) {
+ if ($queries) {
+ $queries .= "\n";
+ }
+ $queries .= t('[@time ms]', array('@time' => intval($query[1] * 100000) / 100)) . ' ' . $query[0];
+ }
+
+ $rows[] = array('<strong>' . t('Other queries') . '</strong>', '<pre>' . $queries . '</pre>');
+ }
+
+ $rows[] = array('<strong>' . t('Title') . '</strong>', filter_xss_admin($view->get_title()));
+ if (isset($path)) {
+ $path = l($path, $path);
+ }
+ else {
+ $path = t('This display has no path.');
+ }
+
+ $rows[] = array('<strong>' . t('Path') . '</strong>', $path);
+
+ $rows[] = array('<strong>' . t('Query build time') . '</strong>', t('@time ms', array('@time' => intval($view->build_time * 100000) / 100)));
+ $rows[] = array('<strong>' . t('Query execute time') . '</strong>', t('@time ms', array('@time' => intval($view->execute_time * 100000) / 100)));
+ $rows[] = array('<strong>' . t('View render time') . '</strong>', t('@time ms', array('@time' => intval($view->render_time * 100000) / 100)));
+ drupal_alter('views_preview_info', $rows, $view);
+
+ $info = theme('table', array('rows' => $rows));
+ }
+ else {
+ $info = theme('table', array('rows' => array(array('<strong>' . t('Query') . '</strong>', t('No query was run')))));
+ }
+ }
+ else {
+ foreach ($errors as $error) {
+ drupal_set_message($error, 'error');
+ }
+ $preview = t('Unable to preview due to validation errors.');
+ $info = '';
+ }
+
+ $info = '<div class="views-query-info">' . $info . '</div>';
+
+ if (variable_get('views_ui_query_on_top', FALSE)) {
+ $output .= $info . $preview;
+ }
+ else {
+ $output .= $preview . $info;
+ }
+
+ if (!$js) {
+ views_add_css('views-admin');
+ drupal_set_title($view->get_title());
+ return $output;
+ }
+ else {
+ $commands = array();
+ if (!empty($view->js_settings)) {
+ $commands[] = ajax_command_settings($view->js_settings);
+ }
+ $display = '';
+ if ($messages = theme('status_messages')) {
+ $display = '<div class="views-messages">' . $messages . '</div>';
+ }
+ $display .= $output;
+ if ($display) {
+ $commands[] = ajax_command_html('div#views-live-preview', $display);
+ }
+ return $js ? array('#type' => 'ajax', '#commands' => $commands) : $commands;
+ }
+}
+
+/**
+ * Form for generating argument information for the live preview.
+ */
+function views_ui_preview_form($form, &$form_state) {
+ $view = &$form_state['view'];
+ $view->init_display();
+ $options = array();
+ foreach ($view->display as $id => $display) {
+ $options[$id] = $display->display_title;
+ }
+
+ $form['#attributes'] = array(
+ 'class' => array('clearfix'),
+ );
+
+ $form['display_id'] = array(
+ '#type' => 'select',
+ '#title' => t('Display'),
+ '#options' => $options,
+ '#default_value' => $form_state['display_id'],
+ '#id' => 'preview-display-id',
+ );
+
+ $form['args'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Arguments'),
+ '#default_value' => $form_state['view_args'],
+ '#description' => t('Separate arguments with a / as though they were a URL path.'),
+ '#id' => 'preview-args',
+ );
+
+ $form['preview'] = array(
+ '#type' => 'submit',
+ '#value' => t('Preview'),
+ '#id' => 'preview-submit',
+ );
+
+ $form['live_preview'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Automatic live preview'),
+ '#default_value' => !variable_get('views_ui_disable_live_preview', 0),
+ );
+
+ $form['#action'] = url("admin/structure/views/nojs/preview/$view->name");
+ return $form;
+}
+
+/**
+ * Submit the preview form.
+ *
+ * This just takes the data and stores it on the form state in a
+ * known location. The caller will be responsible for using it.
+ */
+function views_ui_preview_form_submit(&$form, &$form_state) {
+ $form_state['display_id'] = $form_state['values']['display_id'];
+ $form_state['view_args'] = $form_state['values']['args'];
+}
+
+/**
+ * Page callback to add a new view.
+ */
+function views_ui_add_page() {
+ $form_state = array(
+ 'view' => NULL,
+ 'build_info' => array(
+ 'args' => array(),
+ ),
+ );
+
+ $form = drupal_build_form('views_ui_add_form', $form_state);
+ return drupal_render($form);
+}
+
+/**
+ * Page callback to add a new view.
+ */
+function views_ui_clone_page($view) {
+ $form_state = array(
+ 'view' => $view->copy(),
+ 'build_info' => array(
+ 'args' => array(),
+ ),
+ );
+
+ drupal_set_title(t('Clone view %view', array('%view' => $view->name)), PASS_THROUGH);
+ return drupal_render(drupal_build_form('views_ui_add_form', $form_state));
+}
+
+/**
+ * Form constructor callback to create the views Add Form, phase 1.
+ */
+function views_ui_add_form($form, &$form_state) {
+ $view = $form_state['view'];
+ $form = array();
+
+ $form['name'] = array(
+ '#type' => 'textfield',
+ '#title' => t('View name'),
+ '#description' => t('This is the unique name of the view. It must contain only alphanumeric characters and underscores; it is used to identify the view internally and to generate unique theming template names for this view. If overriding a module provided view, the name must not be changed or instead a new view will be created.'),
+ '#required' => TRUE,
+ '#maxlength' => 32,
+ '#default_value' => $view ? $view->name : '',
+ '#attributes' => array('dir'=>'ltr'),
+ );
+
+ $form['description'] = array(
+ '#type' => 'textfield',
+ '#title' => t('View description'),
+ '#description' => t('This description will appear on the Views administrative UI to tell you what the view is about.'),
+ '#default_value' => $view ? $view->description : '',
+ '#maxlength' => 255,
+ );
+
+ $form['tag'] = array(
+ '#type' => 'textfield',
+ '#title' => t('View tag'),
+ '#description' => t('Enter an optional tag for this view; it is used only to help sort views on the administrative page.'),
+ '#default_value' => $view ? $view->tag : '',
+ '#autocomplete_path' => 'admin/views/ajax/autocomplete/tag',
+ );
+
+ $base_tables = array();
+ foreach (views_fetch_base_tables() as $table => $info) {
+ $base_tables[$table] = $info['title'] . '<div class="description">' . $info['description'] . '</div>';
+ }
+
+ $form['base_table'] = array(
+ '#type' => 'radios',
+ '#title' => t('View type'),
+ '#description' => t('The view type is the primary table for which information is being retrieved. The view type controls what arguments, fields, sort criteria and filters are available, so once this is set it <strong>cannot be changed</strong>.'),
+ '#default_value' => $view ? $view->base_table : 'node',
+ '#options' => $base_tables,
+ );
+
+ if ($view) {
+ $form['base_table']['#disabled'] = TRUE;
+ }
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Next'),
+ '#validate' => array('views_ui_add_form_validate'),
+ '#submit' => array('views_ui_add_form_submit'),
+ );
+
+ return $form;
+}
+
+/**
+ * Validate the add view form.
+ */
+function views_ui_add_form_validate($form, &$form_state) {
+ $name = $form_state['values']['name'];
+
+ // View name must be alphanumeric or underscores, no other punctuation.
+ if (preg_match('/[^a-zA-Z0-9_]/', $name) || is_numeric($name)) {
+ form_error($form['name'], t('View name must be alphanumeric or underscores only, but cannot be numeric.'));
+ }
+
+ // View name must already exist.
+ $view = views_get_view($form_state['values']['name']);
+ if ($view && $view->type != t('Default')) {
+ form_error($form['name'], t('You must use a unique name for this view.'));
+ }
+}
+
+/**
+ * Process the add view form
+ */
+function views_ui_add_form_submit($form, &$form_state) {
+ $view = $form_state['view'] ? $form_state['view'] : views_new_view();
+ $view->name = $form_state['values']['name'];
+ $view->description = $form_state['values']['description'];
+ $view->tag = $form_state['values']['tag'];
+ if (empty($form['base_table']['#disabled'])) {
+ $view->base_table = $form_state['values']['base_table'];
+ }
+
+ views_ui_cache_set($view);
+ $form_state['redirect'] ='admin/structure/views/edit/' . $view->name;
+}
+
+/**
+ * Page to delete a view.
+ */
+function views_ui_delete_confirm($form, &$form_state, $view) {
+ $form_state['view'] = &$view;
+ $form = array();
+
+ $cancel = 'admin/structure/views';
+ if (!empty($_REQUEST['cancel'])) {
+ $cancel = $_REQUEST['cancel'];
+ }
+
+ if ($view->type == t('Overridden')) {
+ $title = t('Are you sure you want to revert the view %name?', array('%name' => $view->name));
+ $desc = t('Reverting the view will delete the view that is in the database, reverting it to the original default view. Any changes you have made will be lost and cannot be recovered.');
+ $button = t('Revert');
+ }
+ else {
+ $title = t('Are you sure you want to delete the view %name?', array('%name' => $view->name));
+ $desc = t('Deleting a view cannot be undone.');
+ $button = t('Delete');
+ }
+
+ return confirm_form($form,
+ $title,
+ $cancel,
+ $desc,
+ $button,
+ t('Cancel'));
+}
+
+/**
+ * Submit handler to delete a view.
+ */
+function views_ui_delete_confirm_submit(&$form, &$form_state) {
+ $form_state['view']->delete();
+ ctools_object_cache_clear('view', $form_state['view']->name);
+ drupal_set_message(t('The view has been deleted.'));
+ $form_state['redirect'] = 'admin/structure/views';
+}
+
+/**
+ * Page to delete a view.
+ */
+function views_ui_break_lock_confirm($form, &$form_state, $view) {
+ $form_state['view'] = &$view;
+ $form = array();
+
+ if (empty($view->locked)) {
+ return t('There is no lock on view %view to break.', array('%name' => $view->name));
+ }
+
+ $cancel = 'admin/structure/views/edit/' . $view->name;
+ if (!empty($_REQUEST['cancel'])) {
+ $cancel = $_REQUEST['cancel'];
+ }
+
+ $account = user_load($view->locked->uid);
+ return confirm_form($form,
+ t('Are you sure you want to break the lock on view %name?',
+ array('%name' => $view->name)),
+ $cancel,
+ t('By breaking this lock, any unsaved changes made by !user will be lost!', array('!user' => theme('username', array('account' => $account)))),
+ t('Break lock'),
+ t('Cancel'));
+}
+
+/**
+ * Submit handler to break_lock a view.
+ */
+function views_ui_break_lock_confirm_submit(&$form, &$form_state) {
+ ctools_object_cache_clear_all('view', $form_state['view']->name);
+ $form_state['redirect'] = 'admin/structure/views/edit/' . $form_state['view']->name;
+ drupal_set_message(t('The lock has been broken and you may now edit this view.'));
+}
+
+/**
+ * The main view edit page
+ */
+function views_ui_edit_page($view) {
+ drupal_set_title(t('Edit view %view', array('%view' => $view->name)), PASS_THROUGH);
+ $output = theme('views_ui_edit_view', array('view' => $view));
+ views_ui_check_advanced_help();
+ return $output;
+}
+
+/**
+ * Export a view for cut & paste.
+ */
+function views_ui_export_page($form, &$form_state, $view) {
+ $code = $view->export();
+ $lines = substr_count($code, "\n");
+ $form['code'] = array(
+ '#type' => 'textarea',
+ '#title' => $view->name,
+ '#default_value' => $code,
+ '#rows' => $lines,
+ );
+ return $form;
+}
+
+/**
+ * Import a view from cut & paste
+ */
+function views_ui_import_page($form, &$form_state) {
+ $form['name'] = array(
+ '#type' => 'textfield',
+ '#title' => t('View name'),
+ '#description' => t('Enter the name to use for this view if it is different from the source view. Leave blank to use the name of the view.'),
+ );
+
+ $form['view'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Paste view code here'),
+ '#required' => TRUE,
+ );
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Import'),
+ '#submit' => array('views_ui_import_submit'),
+ '#validate' => array('views_ui_import_validate'),
+ );
+ return $form;
+}
+
+/**
+ * Validate handler to import a view
+ */
+function views_ui_import_validate($form, &$form_state) {
+ $view = '';
+ views_include('view');
+ ob_start();
+ eval($form_state['values']['view']);
+ ob_end_clean();
+
+ if (!is_object($view)) {
+ return form_error($form['view'], t('Unable to interpret view code.'));
+ }
+
+ if (empty($view->api_version) || $view->api_version < 2) {
+ // Check for some value that would only exist on a Views 1 view.
+ if (isset($view->url) || isset($view->page) || isset($view->block)) {
+ views_include('convert');
+ $view = views1_import($view);
+ drupal_set_message(t('You are importing a view created in Views version 1. You may need to adjust some parameters to work correctly in version 2.'), 'warning');
+ }
+ else {
+ form_error($form['view'], t('That view is not compatible with this version of Views.'));
+ }
+ }
+ elseif ($view->api_version > views_api_version()) {
+ form_error($form['view'], t('That view is created for the version @import_version of views, but you only have @api_version', array(
+ '@import_version' => $view->api_version,
+ '@api_version' => views_api_version())));
+ }
+
+ // View name must be alphanumeric or underscores, no other punctuation.
+ if (!empty($form_state['values']['name']) && preg_match('/[^a-zA-Z0-9_]/', $form_state['values']['name'])) {
+ form_error($form['name'], t('View name must be alphanumeric or underscores only.'));
+ }
+
+ if ($form_state['values']['name']) {
+ $view->name = $form_state['values']['name'];
+ }
+
+ $test = views_get_view($view->name);
+ if ($test && $test->type != t('Default')) {
+ form_set_error('', t('A view by that name already exists; please choose a different name'));
+ }
+
+ $view->init_display();
+
+ $broken = FALSE;
+ // Make sure that all plugins and handlers needed by this view actually exist.
+ foreach ($view->display as $id => $display) {
+ if (empty($display->handler) || !empty($display->handler->broken)) {
+ drupal_set_message(t('Display plugin @plugin is not available.', array('@plugin' => $display->display_plugin)), 'error');
+ $broken = TRUE;
+ continue;
+ }
+
+ $plugin = views_get_plugin('style', $display->handler->get_option('style_plugin'));
+ if (!$plugin) {
+ drupal_set_message(t('Style plugin @plugin is not available.', array('@plugin' => $display->handler->get_option('style_plugin'))), 'error');
+ $broken = TRUE;
+ }
+ elseif ($plugin->uses_row_plugin()) {
+ $plugin = views_get_plugin('row', $display->handler->get_option('row_plugin'));
+ if (!$plugin) {
+ drupal_set_message(t('Row plugin @plugin is not available.', array('@plugin' => $display->handler->get_option('row_plugin'))), 'error');
+ $broken = TRUE;
+ }
+ }
+
+ foreach (views_object_types() as $type => $info) {
+ $handlers = $display->handler->get_handlers($type);
+ if ($handlers) {
+ foreach ($handlers as $id => $handler) {
+ if ($handler->broken()) {
+ drupal_set_message(t('@type handler @table.@field is not available.', array(
+ '@type' => $info['stitle'],
+ '@table' => $handler->table,
+ '@field' => $handler->field,
+ )), 'error');
+ $broken = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ if ($broken) {
+ form_set_error('', t('Unable to import view.'));
+ }
+
+ $form_state['view'] = &$view;
+}
+
+/**
+ * Submit handler for view import
+ */
+function views_ui_import_submit($form, &$form_state) {
+ // Store in cache and then go to edit.
+ views_ui_cache_set($form_state['view']);
+ $form_state['redirect'] = 'admin/structure/views/edit/' . $form_state['view']->name;
+}
+
+/**
+ * The main edit view form, which is really just a save/cancel/delete button.
+ */
+function views_ui_edit_view_form($form, &$form_state, $view) {
+ $form['buttons']['save'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save'),
+ '#validate' => array('views_ui_edit_view_form_validate'),
+ '#submit' => array('views_ui_edit_view_form_submit'),
+ );
+
+ $form['buttons']['cancel'] = array(
+ '#type' => 'submit',
+ '#value' => t('Cancel'),
+ '#submit' => array('views_ui_edit_view_form_cancel'),
+ );
+
+ if (is_numeric($view->vid)) {
+ $form['buttons']['delete'] = array(
+ '#type' => 'submit',
+ '#value' => $view->type == t('Overridden') ? t('Revert') : t('Delete'),
+ '#submit' => array('views_ui_edit_view_form_delete'),
+ );
+ }
+
+ $form_state['view'] = &$view;
+ return $form;
+}
+
+/**
+ * Validate that a view is complete and whole.
+ */
+function views_ui_edit_view_form_validate($form, &$form_state) {
+ // Do not validate cancel or delete or revert.
+ if (empty($form_state['clicked_button']['#value']) || $form_state['clicked_button']['#value'] != t('Save')) {
+ return;
+ }
+
+ $errors = $form_state['view']->validate();
+ if ($errors !== TRUE) {
+ foreach ($errors as $error) {
+ form_set_error('', $error);
+ }
+ }
+}
+
+/**
+ * Submit handler for the edit view form.
+ */
+function views_ui_edit_view_form_submit($form, &$form_state) {
+ // Go through and remove displayed scheduled for removal.
+ foreach ($form_state['view']->display as $id => $display) {
+ if (!empty($display->deleted)) {
+ unset($form_state['view']->display[$id]);
+ }
+ }
+ // Rename display ids if needed.
+ foreach ($form_state['view']->display as $id => $display) {
+ if (!empty($display->new_id)) {
+ $form_state['view']->display[$id]->id = $display->new_id;
+ }
+ }
+
+ $form_state['view']->save();
+ drupal_set_message(t('The view %name has been saved.', array('%name' => $form_state['view']->name)));
+
+ // Make sure menu items get rebuilt as neces
+ menu_rebuild();
+
+ // Clear the views cache.
+ cache_clear_all('*', 'cache_views');
+
+ // Clear the page cache.
+ cache_clear_all();
+
+ // Remove this view from cache so we can edit it properly.
+ ctools_object_cache_clear('view', $form_state['view']->name);
+}
+
+/**
+ * Submit handler for the edit view form.
+ */
+function views_ui_edit_view_form_cancel($form, &$form_state) {
+ // Remove this view from cache so edits will be lost.
+ ctools_object_cache_clear('view', $form_state['view']->name);
+ if (empty($form['view']->vid)) {
+ // I seem to have to drupal_goto here because I can't get fapi to
+ // honor the redirect target. Not sure what I screwed up here.
+ drupal_goto('admin/structure/views');
+ }
+}
+
+function views_ui_edit_view_form_delete($form, &$form_state) {
+ unset($_REQUEST['destination']);
+ // Redirect to the delete confirm page
+ $form_state['redirect'] = array('admin/structure/views/delete/' . $form_state['view']->name, array('query' => drupal_get_destination() + array('cancel' => 'admin/structure/views/edit/' . $form_state['view']->name)));
+}
+
+/**
+ * Preprocess the view edit page.
+ */
+function template_preprocess_views_ui_edit_view(&$vars) {
+ $view = &$vars['view'];
+ ctools_include('dependent');
+
+ // The form has to be saved as variable because of strict warnings.
+ $form = drupal_get_form('views_ui_edit_view_form', $view);
+ $vars['save_button'] = drupal_render($form);
+
+ $table = views_fetch_data($view->base_table);
+ $vars['base_table'] = !empty($table['table']['base']['title']) ?
+ $table['table']['base']['title'] : t('Unknown or missing table name');
+
+ views_include('tabs');
+ $tabs = new views_tabset;
+
+ $vars['message'] = '<div class="message">' . t("Click on an item to edit that item's details.") . '</div>';
+
+ if (!$view->set_display('default')) {
+ drupal_set_message(t('This view has a broken default display and cannot be used.'), 'error');
+ }
+
+ foreach ($view->display as $display) {
+ list($title, $body) = views_ui_display_tab($view, $display);
+ // The first display is the default.
+ $tabs->set($display->id, $title, $body);
+ }
+
+ // This is the area that will render beneath the links
+ $form_state = array(
+ 'view' => &$view,
+ 'ajax' => FALSE,
+ 'build_info' => array(
+ 'args' => array(),
+ ),
+ 'no_cache' => TRUE,
+ );
+
+ $form = drupal_build_form('views_ui_add_display_form', $form_state);
+ $display_button = drupal_render($form);
+ $form = drupal_get_form('views_ui_analyze_view_button', $view);
+ $analyze_button = drupal_render($form);
+ $tabs->add_extra($display_button . $analyze_button);
+
+ $vars['tabs'] = $tabs->render();
+
+ $form_state = array(
+ 'display_id' => 'default',
+ 'view_args' => '',
+ 'rerender' => FALSE,
+ 'no_redirect' => TRUE,
+ 'view' => &$view,
+ 'input' => array(),
+ 'build_info' => array(
+ 'args' => array(),
+ ),
+ );
+ $preview_form = drupal_build_form('views_ui_preview_form', $form_state);
+ $vars['preview'] = drupal_render($preview_form);
+
+ $vars['locked'] = NULL;
+ if (isset($view->locked) && is_object($view->locked)) {
+ $account = array();
+ $account['account'] = user_load($view->locked->uid);
+ $account['name'] = $account['account']->name;
+ $vars['locked'] = theme('username', array('account' => $account['account']));
+ $vars['lock_age'] = format_interval(REQUEST_TIME - $view->locked->updated);
+ $vars['break'] = url('admin/structure/views/break-lock/' . $view->name);
+ }
+
+ $vars['quick_links_raw'] = array(
+ array(
+ 'title' => t('Export'),
+ 'alt' => t("Export this view"),
+ 'href' => "admin/structure/views/export/$view->name",
+ ),
+ array(
+ 'title' => t('Clone'),
+ 'alt' => t("Create a copy of this view"),
+ 'href' => "admin/structure/views/clone/$view->name",
+ ),
+ );
+
+ $paths = array();
+ foreach ($view->display as $id => $display) {
+ if (!empty($display->handler) && $display->handler->has_path()) {
+ $path = $display->handler->get_path();
+ if (strpos($path, '%') === FALSE && !isset($paths[$path])) {
+ $vars['quick_links_raw'][] = array(
+ 'title' => t('View "@display"', array('@display' => $display->display_title)),
+ 'alt' => t("Go to the real page for this display"),
+ 'href' => $path,
+ );
+ // Displays can have the same path; no point in showing more than one link.
+ $paths[$path] = TRUE;
+ }
+ }
+ }
+
+ if (module_exists('contextual')) {
+ $build = array(
+ '#prefix' => '<div class="contextual-links-wrapper">',
+ '#suffix' => '</div>',
+ '#theme' => 'links__contextual',
+ '#links' => $vars['quick_links_raw'],
+ '#attributes' => array('class' => array('contextual-links')),
+ '#attached' => array(
+ 'library' => array(array('contextual', 'contextual-links')),
+ ),
+ );
+ $vars['quick_links'] = drupal_render($build);
+ }
+ else {
+ $vars['quick_links'] = theme('links__views_quick_links', array('links' => $vars['quick_links_raw']));
+ }
+ views_add_css('views-admin');
+ views_add_js('ajax');
+ drupal_add_js('misc/jquery.form.js', array('group' => JS_LIBRARY));
+ // @TODO Remove this line when http://drupal.org/node/561858 is in.
+ drupal_add_js('misc/jquery.cookie.js', array('group' => JS_LIBRARY));
+
+ // Also add any js files required by plugins:
+ $plugins = views_fetch_plugin_data();
+ foreach ($plugins as $type => $type_plugins) {
+ foreach ($type_plugins as $name => $plugin) {
+ if (!empty($plugin['js'])) {
+ foreach ($plugin['js'] as $file) {
+ drupal_add_js($file);
+ }
+ }
+ }
+ }
+
+ $settings = array('views' => array('ajax' => array(
+ 'id' => '#views-ajax-pad',
+ 'title' => '#views-ajax-title',
+ 'defaultForm' => $vars['message'],
+ )));
+
+ drupal_add_js($settings, 'setting');
+}
+
+function template_preprocess_views_ui_edit_tab(&$vars) {
+ $view = $vars['view'];
+ $display = $vars['display'];
+ $plugin = $display->handler->definition;
+
+ $top = $left = $middle = $right = '';
+
+ // If this form was submitted it was already handled, so force it not to
+ // submit again.
+
+ $vars['remove'] = '';
+ $vars['clone'] = '';
+ if (empty($plugin['no remove'])) {
+ if (!empty($_POST['form_id']) && in_array($_POST['form_id'], array('views_ui_remove_display_form', 'views_ui_clone_display_form'))) {
+ unset($_POST['form_id']);
+ }
+ $form_state = array('view' => &$view, 'display_id' => $display->id, 'ajax' => FALSE, 'build_info' => array('args' => array()));
+ $remove_form = drupal_build_form('views_ui_remove_display_form', $form_state);
+ $clone_form = drupal_build_form('views_ui_clone_display_form', $form_state);
+ $vars['remove'] = drupal_render($remove_form);
+ $vars['clone'] = drupal_render($clone_form);
+ }
+
+ // basic fields
+ $vars['title'] = check_plain($display->display_title);
+ $vars['description'] = check_plain($plugin['help']);
+
+ // Special fields if tihs is the default display.
+ $vars['default'] = ($display->id == 'default');
+ $vars['details_class'] = drupal_clean_css_identifier('details');
+ if (!empty($view->changed_sections['details'])) {
+ $vars['details_changed'] = TRUE;
+ }
+
+ $tag = empty($view->tag) ? t('None') : $view->tag;
+ $vars['details'] = t('Description') . '/' . t('Tag') . ': ' . l($tag, "admin/structure/views/nojs/details/$view->name", array('attributes' => array('class' => array('views-ajax-link'), 'id' => 'views-tag')));
+
+ // Calculate options from display plugin.
+ $options = $categories = array();
+ $display->handler->options_summary($categories, $options);
+
+ // Build all of the options we were returned and put them into the
+ // category data fields.
+ foreach ($options as $id => $option) {
+ if (empty($categories[$option['category']]['data'])) {
+ $categories[$option['category']]['data'] = array();
+ }
+ $categories[$option['category']]['data'][$id] = array();
+ $data = &$categories[$option['category']]['data'][$id];
+ $data['content'] = '';
+ $data['links'] = '';
+ $data['overridden'] = FALSE;
+ $data['defaulted'] = FALSE;
+
+ // If there are optional links, build them first so they float properly.
+ if (!empty($option['links'])) {
+ foreach ($option['links'] as $link_id => $link_value) {
+ $data['links'] .= $display->handler->option_link($link_value, $link_id, 'views-button-configure');
+ }
+ }
+ if (!empty($option['title'])) {
+ $data['content'] .= $option['title'] . ': ';
+ }
+
+ $data['content'] .= $display->handler->option_link($option['value'], $id, '', empty($option['desc']) ? '' : $option['desc']);
+ if (!empty($display->handler->options['defaults'][$id])) {
+ $display_id = 'default';
+ $data['defaulted'] = TRUE;
+ }
+ else {
+ $display_id = $display->id;
+ if (!$display->handler->is_default_display()) {
+ if ($display->handler->defaultable_sections($id)) {
+ $data['overridden'] = TRUE;
+ }
+ }
+ }
+ $data['class'][] = drupal_clean_css_identifier($display_id . '-' . $id);
+ if (!empty($view->changed_sections[$display_id . '-' . $id])) {
+ $data['changed'] = TRUE;
+ }
+ }
+
+ $vars['categories'] = $categories;
+
+ // Add a help icon
+ if (isset($plugin['help topic']) && module_exists('advanced_help')) {
+ $vars['display_help_icon'] = theme('advanced_help_topic', array('module' => $plugin['module'], 'topic' => $plugin['help topic']));
+ }
+ else {
+ $vars['display_help_icon'] = '';
+ }
+
+ // Fetch style plugin info because it has some effect on how/what we render.
+ $style_plugin = $display->handler->get_plugin();
+
+ $vars['fields'] = '';
+ $vars['areas'] = array();
+ foreach (array('header', 'footer', 'empty') as $area) {
+ $vars['areas'][$area] = theme('views_ui_edit_item', array(
+ 'type' => $area, 'view' => $view, 'display' => $display,
+ ));
+ }
+ $vars['fields'] = theme('views_ui_edit_item', array('type' => 'field', 'vi