summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--css/ie/views-admin.ie7.css91
-rw-r--r--css/views-admin-rtl.css102
-rw-r--r--css/views-admin.advanced_help.css24
-rw-r--r--css/views-admin.contextual.css63
-rw-r--r--css/views-admin.css762
-rw-r--r--css/views-admin.ctools.css224
-rw-r--r--css/views-admin.seven-rtl.css29
-rw-r--r--css/views-admin.seven.css209
-rw-r--r--css/views-admin.theme-rtl.css208
-rw-r--r--css/views-admin.theme.css921
-rw-r--r--docs/docs.php27
-rw-r--r--handlers/views_handler_area.inc2
-rw-r--r--handlers/views_handler_area_view.inc82
-rw-r--r--handlers/views_handler_argument.inc520
-rw-r--r--handlers/views_handler_argument_date.inc1
-rw-r--r--handlers/views_handler_argument_formula.inc2
-rw-r--r--handlers/views_handler_argument_many_to_one.inc10
-rw-r--r--handlers/views_handler_argument_null.inc6
-rw-r--r--handlers/views_handler_argument_numeric.inc4
-rw-r--r--handlers/views_handler_argument_string.inc17
-rw-r--r--handlers/views_handler_field.inc175
-rw-r--r--handlers/views_handler_field_boolean.inc2
-rw-r--r--handlers/views_handler_field_counter.inc4
-rw-r--r--handlers/views_handler_field_custom.inc11
-rw-r--r--handlers/views_handler_field_date.inc4
-rw-r--r--handlers/views_handler_field_numeric.inc4
-rw-r--r--handlers/views_handler_field_prerender_list.inc2
-rw-r--r--handlers/views_handler_field_url.inc2
-rw-r--r--handlers/views_handler_filter.inc193
-rw-r--r--handlers/views_handler_filter_boolean_operator.inc12
-rw-r--r--handlers/views_handler_filter_date.inc19
-rw-r--r--handlers/views_handler_filter_equality.inc5
-rw-r--r--handlers/views_handler_filter_in_operator.inc26
-rw-r--r--handlers/views_handler_filter_numeric.inc10
-rw-r--r--handlers/views_handler_filter_string.inc10
-rw-r--r--handlers/views_handler_relationship.inc6
-rw-r--r--handlers/views_handler_sort.inc69
-rw-r--r--help/api-tables.html18
-rw-r--r--help/api-upgrading.html19
-rw-r--r--help/example-author-block.html2
-rw-r--r--images/sprites.pngbin1926 -> 58287 bytes
-rw-r--r--includes/admin.inc4069
-rw-r--r--includes/ajax.inc33
-rw-r--r--includes/cache.inc99
-rw-r--r--includes/convert.inc2
-rw-r--r--includes/handlers.inc143
-rw-r--r--includes/plugins.inc31
-rw-r--r--includes/view.inc77
-rw-r--r--js/ajax.js92
-rw-r--r--js/ajax_view.js1
-rw-r--r--js/base.js32
-rw-r--r--js/tabs.js1
-rw-r--r--js/views-admin.js797
-rw-r--r--js/views-contextual.js18
-rw-r--r--js/views-list.js23
-rw-r--r--modules/aggregator/views_handler_field_aggregator_category.inc2
-rw-r--r--modules/aggregator/views_handler_field_aggregator_title_link.inc2
-rw-r--r--modules/aggregator/views_handler_filter_aggregator_category_cid.inc1
-rw-r--r--modules/book.views_convert.inc1
-rw-r--r--modules/comment.views.inc42
-rw-r--r--modules/comment.views_convert.inc1
-rw-r--r--modules/comment.views_default.inc12
-rw-r--r--modules/comment/views_handler_argument_comment_user_uid.inc2
-rw-r--r--modules/comment/views_handler_field_comment.inc4
-rw-r--r--modules/comment/views_handler_field_comment_link.inc2
-rw-r--r--modules/comment/views_handler_field_comment_link_edit.inc1
-rw-r--r--modules/comment/views_handler_field_comment_node_link.inc4
-rw-r--r--modules/comment/views_handler_field_comment_username.inc2
-rw-r--r--modules/comment/views_handler_field_node_new_comments.inc5
-rw-r--r--modules/contact/views_handler_field_contact_link.inc2
-rw-r--r--modules/field/views_handler_field_field.inc25
-rw-r--r--modules/filter.views.inc5
-rw-r--r--modules/locale/views_handler_field_locale_link_edit.inc2
-rw-r--r--modules/node.views.inc96
-rw-r--r--modules/node.views_default.inc9
-rw-r--r--modules/node/views_handler_argument_node_type.inc2
-rw-r--r--modules/node/views_handler_field_history_user_timestamp.inc1
-rw-r--r--modules/node/views_handler_field_node.inc7
-rw-r--r--modules/node/views_handler_field_node_link.inc2
-rw-r--r--modules/node/views_handler_field_node_path.inc3
-rw-r--r--modules/node/views_handler_field_node_revision.inc7
-rw-r--r--modules/node/views_handler_field_node_type.inc7
-rw-r--r--modules/node/views_handler_filter_history_user_timestamp.inc8
-rw-r--r--modules/node/views_handler_filter_node_status.inc1
-rw-r--r--modules/node/views_handler_filter_node_type.inc2
-rw-r--r--modules/node/views_plugin_argument_validate_node.inc11
-rw-r--r--modules/node/views_plugin_row_node_rss.inc26
-rw-r--r--modules/node/views_plugin_row_node_view.inc43
-rw-r--r--modules/profile.views.inc1
-rw-r--r--modules/search.views_convert.inc1
-rw-r--r--modules/search.views_default.inc3
-rw-r--r--modules/search/views_handler_argument_search.inc2
-rw-r--r--modules/search/views_handler_field_search_score.inc1
-rw-r--r--modules/search/views_handler_filter_search.inc2
-rw-r--r--modules/statistics.views.inc2
-rw-r--r--modules/statistics.views_default.inc3
-rw-r--r--modules/statistics/views_handler_field_accesslog_path.inc2
-rw-r--r--modules/system.views.inc12
-rw-r--r--modules/system/views_handler_field_file.inc4
-rw-r--r--modules/system/views_handler_field_file_filemime.inc4
-rw-r--r--modules/system/views_handler_field_file_uri.inc2
-rw-r--r--modules/taxonomy.views.inc17
-rw-r--r--modules/taxonomy.views_default.inc3
-rw-r--r--modules/taxonomy/views_handler_argument_term_node_tid_depth.inc4
-rw-r--r--modules/taxonomy/views_handler_argument_term_node_tid_depth_modifier.inc2
-rw-r--r--modules/taxonomy/views_handler_field_taxonomy.inc4
-rw-r--r--modules/taxonomy/views_handler_field_term_link_edit.inc2
-rw-r--r--modules/taxonomy/views_handler_field_term_node_tid.inc5
-rw-r--r--modules/taxonomy/views_handler_filter_term_node_tid.inc16
-rw-r--r--modules/taxonomy/views_handler_relationship_node_term_data.inc6
-rw-r--r--modules/translation.views.inc18
-rw-r--r--modules/translation/views_handler_filter_node_tnid.inc5
-rw-r--r--modules/upload.views.inc4
-rw-r--r--modules/user.views.inc5
-rw-r--r--modules/user/views_handler_field_user.inc4
-rw-r--r--modules/user/views_handler_field_user_link.inc2
-rw-r--r--modules/user/views_handler_field_user_mail.inc2
-rw-r--r--modules/user/views_handler_field_user_name.inc8
-rw-r--r--modules/user/views_handler_filter_user_name.inc2
-rw-r--r--modules/user/views_plugin_argument_validate_user.inc2
-rw-r--r--modules/views.views.inc8
-rw-r--r--plugins/export_ui/views_ui.class.php373
-rw-r--r--plugins/export_ui/views_ui.inc34
-rw-r--r--plugins/views_plugin_argument_default_fixed.inc5
-rw-r--r--plugins/views_plugin_argument_validate.inc2
-rw-r--r--plugins/views_plugin_display.inc183
-rw-r--r--plugins/views_plugin_display_attachment.inc63
-rw-r--r--plugins/views_plugin_display_block.inc10
-rw-r--r--plugins/views_plugin_display_feed.inc4
-rw-r--r--plugins/views_plugin_display_page.inc4
-rw-r--r--plugins/views_plugin_exposed_form.inc8
-rw-r--r--plugins/views_plugin_exposed_form_basic.inc8
-rw-r--r--plugins/views_plugin_exposed_form_input_required.inc4
-rw-r--r--plugins/views_plugin_pager_full.inc4
-rw-r--r--plugins/views_wizard/comment.inc29
-rw-r--r--plugins/views_wizard/file_managed.inc15
-rw-r--r--plugins/views_wizard/node.inc28
-rw-r--r--plugins/views_wizard/node_revision.inc21
-rw-r--r--plugins/views_wizard/taxonomy_term.inc16
-rw-r--r--plugins/views_wizard/users.inc22
-rw-r--r--plugins/views_wizard/views_ui_base_views_wizard.class.php761
-rw-r--r--plugins/views_wizard/views_ui_comment_views_wizard.class.php95
-rw-r--r--plugins/views_wizard/views_ui_file_managed_views_wizard.class.php45
-rw-r--r--plugins/views_wizard/views_ui_node_revision_views_wizard.class.php46
-rw-r--r--plugins/views_wizard/views_ui_node_views_wizard.class.php124
-rw-r--r--plugins/views_wizard/views_ui_taxonomy_term_views_wizard.class.php29
-rw-r--r--plugins/views_wizard/views_ui_users_views_wizard.class.php30
-rw-r--r--tests/handlers/views_handler_filter_date.test14
-rw-r--r--tests/templates/views-view--frontpage.tpl.php7
-rw-r--r--tests/test_plugins/views_test_plugin_access_test_dynamic.inc2
-rw-r--r--tests/user/views_user_argument_default.test8
-rw-r--r--tests/user/views_user_argument_validate.test6
-rw-r--r--tests/views_access.test20
-rw-r--r--tests/views_analyze.test8
-rw-r--r--tests/views_argument_default.test13
-rw-r--r--tests/views_argument_validator.test8
-rw-r--r--tests/views_cache.test2
-rw-r--r--tests/views_exposed_form.test24
-rw-r--r--tests/views_groupby.test32
-rw-r--r--tests/views_handlers.test4
-rw-r--r--tests/views_pager.test65
-rw-r--r--tests/views_query.test6
-rw-r--r--tests/views_test.views_default.inc39
-rw-r--r--tests/views_translatable.test16
-rw-r--r--tests/views_ui.test760
-rw-r--r--tests/views_view.test55
-rw-r--r--theme/theme.inc55
-rw-r--r--theme/views-ui-display-tab-bucket.tpl.php15
-rw-r--r--theme/views-ui-display-tab-setting.tpl.php16
-rw-r--r--theme/views-ui-edit-view.tpl.php2
-rw-r--r--theme/views-view.tpl.php8
-rw-r--r--views.info7
-rw-r--r--views.install53
-rw-r--r--views.module549
-rw-r--r--views_export/views_export.module4
-rw-r--r--views_ui.info3
-rw-r--r--views_ui.module860
177 files changed, 10545 insertions, 3892 deletions
diff --git a/css/ie/views-admin.ie7.css b/css/ie/views-admin.ie7.css
new file mode 100644
index 0000000..346d6a1
--- /dev/null
+++ b/css/ie/views-admin.ie7.css
@@ -0,0 +1,91 @@
+/**
+ * The query details collapsible divs are not visible in IE7 because has-layout
+ * is not being triggered. Trigger has-layout with height: 1%;
+ */
+.views-edit-view .collapsible > .fieldset-wrapper {
+ height: 1%;
+}
+
+/**
+ * The column width for the bucket containers in the query details section
+ * is not being calculated to 32% correctly. Give IE7 a slightly smaller
+ * width so that the three columns line up next to each other
+ */
+.views-edit-view .views-display-column {
+ width: 31.95%;
+}
+
+/**
+ * IE7 has no idea how large this container should be and it doesn't
+ * apply has-layout. Expand it's width to 100% and trigger has-layout.
+ */
+.views-edit-view .views-displays {
+ height: 1%;
+ width: 100%;
+}
+
+/**
+ * IE7 isn't positioning the span correctly as a display-inline element
+ */
+.views-edit-view .views-displays .icon {
+ display: block;
+ float: left;
+}
+
+.views-edit-view .views-displays .icon-add {
+ top: 2px;
+}
+
+/**
+ * The add display query dropdown needs a lot of help
+ */
+
+.views-edit-view .views-displays .tabs.secondary {
+ position: relative;
+ z-index: 100;
+}
+
+.views-edit-view .views-displays .secondary .open > a {
+ border-bottom: 1px solid #f1f1f1;
+}
+
+.views-edit-view .views-displays .secondary .action-list {
+ border-bottom: 1px solid #cbcbcb;
+ top: 30px;
+}
+
+.views-edit-view .views-displays .secondary input {
+ text-align: left;
+}
+
+/**
+ * IE7 does not interpret div > * correctly
+ */
+.page-admin-structure-views #content .views-ui-display-tab-bucket {
+ padding-left: 0;
+ padding-right: 0;
+ zoom: 1;
+}
+
+.page-admin-structure-views #content .views-display-column + .views-display-column {
+ margin-top: 0;
+}
+
+/**
+ * IE7 is interpreting a top margin of 18px from somewhere. remove it
+ */
+
+.page-admin-structure-views #content .views-display-setting {
+ margin-top: 0;
+}
+
+/**
+ * IE7 can't handle the + selector that indents form wrappers after a checkbox on the add page
+ * zoom is necessary to trigger has layout. !imporant is necessary because IE7 is precedent
+ * to the theme.css stylesheet, even though it is included before this file.
+ */
+
+.page-admin-structure-views #content .form-type-checkbox + .form-wrapper {
+ margin-left: 27px !important;
+ zoom: 1;
+} \ No newline at end of file
diff --git a/css/views-admin-rtl.css b/css/views-admin-rtl.css
new file mode 100644
index 0000000..cb3edaa
--- /dev/null
+++ b/css/views-admin-rtl.css
@@ -0,0 +1,102 @@
+/**
+ * The .css file is intended to only contain positioning and size declarations
+ * For example: display, position, float, clear, and overflow.
+ */
+
+/* @group Inline lists */
+
+.horizontal > * {
+ float: right;
+}
+
+.horizontal.right {
+ float: left;
+}
+
+/* @end */
+
+/* @group Attachment details
+ *
+ * The attachment details section, its tabs for each section and the buttons
+ * to add a new section
+ */
+
+.form-actions {
+ float: left;
+}
+
+.views-displays {
+ float: right;
+}
+
+/* @end */
+
+/* @group Attachment details tabs
+ *
+ * The tabs that switch between sections
+ */
+
+.views-displays .secondary > li {
+ float: right;
+}
+
+/* @end */
+
+/* @group Attachment details new section button */
+
+.views-displays .secondary .action-list {
+ left: auto;
+ right: 0;
+}
+
+/* @end */
+
+/* @group Attachment details collapsible fieldset */
+
+.views-display-tab .fieldset-legend {
+ left: auto;
+ right: -5px;
+}
+
+/* @end */
+
+/* @group Attachment details actions
+ *
+ * Display the "Delete" and "Duplicate" buttons to the right.
+ */
+.views-display-tab .fieldset-wrapper > .views-ui-display-tab-bucket .actions {
+ left: 0;
+ right: auto;
+}
+
+/* @end */
+
+/* @group Attachment configuration columns */
+
+.views-display-columns > * {
+ float: right;
+ margin-left: 0;
+ margin-right: 1%;
+ padding-left: 0;
+ padding-right: 1%;
+}
+
+.views-display-columns > *:first-child {
+ margin-right: 0;
+ padding-right: 0;
+}
+
+/* @end */
+
+/* @group Settings forms */
+
+.views-dependent {
+ margin-right: 1.5em;
+}
+
+.views-display-setting .label,
+.views-display-setting .views-ajax-link {
+ float: right;
+}
+
+/* @end */
diff --git a/css/views-admin.advanced_help.css b/css/views-admin.advanced_help.css
new file mode 100644
index 0000000..9e804d4
--- /dev/null
+++ b/css/views-admin.advanced_help.css
@@ -0,0 +1,24 @@
+/**
+ * The .advanced_help.css file is intended to contain styles that override declarations
+ * in the Advanced Help module.
+ */
+
+/**
+ * Adjust the advanced help icons
+ */
+.views-ui-display-tab-bucket .advanced-help-link {
+ padding: 0;
+ margin: 5px 3px 0px 6px; /* LTR */
+}
+
+.views-ui-display-tab-bucket .icon-text {
+ padding-left: 25px; /* LTR */
+}
+
+.views-ui-display-tab-bucket .icon-linked {
+ background-position: 6px -151px; /* LTR */
+}
+
+.views-ui-display-tab-bucket .icon-unlinked {
+ background-position: 6px -193px; /* LTR */
+}
diff --git a/css/views-admin.contextual.css b/css/views-admin.contextual.css
new file mode 100644
index 0000000..502e949
--- /dev/null
+++ b/css/views-admin.contextual.css
@@ -0,0 +1,63 @@
+/**
+ * The .contextual.css file is intended to contain styles that override declarations
+ * in the Contextual module.
+ */
+
+/* @group Wrapper */
+
+#views-live-preview .contextual-links-region-active {
+ outline: medium none;
+}
+
+#views-live-preview div.contextual-links-wrapper {
+ right: auto;
+ top: auto;
+}
+
+html.js #views-live-preview div.contextual-links-wrapper {
+ display: inline;
+}
+
+/* @end */
+
+/* @group Trigger */
+
+#views-live-preview a.contextual-links-trigger {
+ display: block;
+}
+
+/* @end */
+
+/* @group List */
+
+div.contextual-links-wrapper ul.contextual-links {
+ -moz-border-radius: 0 4px 4px 4px;
+ -webkit-border-radius: 0 4px 4px 4px;
+ border-radius: 0 4px 4px 4px;
+ min-width: 10em;
+ padding: 6px 6px 9px 6px;
+ right: auto;
+}
+
+ul.contextual-links li a,
+ul.contextual-links li span {
+ padding-bottom: 0.25em;
+ padding-right: 0.1667em;
+ padding-top: 0.25em;
+}
+
+ul.contextual-links li span {
+ font-weight: bold;
+}
+
+ul.contextual-links li a {
+ color: #666666 !important;
+ margin: 0.25em 0;
+ padding-left: 1em;
+}
+
+ul.contextual-links li a:hover {
+ background-color: #badbec;
+}
+
+/* @end */
diff --git a/css/views-admin.css b/css/views-admin.css
index 2a80ba9..0702c18 100644
--- a/css/views-admin.css
+++ b/css/views-admin.css
@@ -1,723 +1,319 @@
-
-/*
- * 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
+/**
+ * The .css file is intended to only contain positioning and size declarations
+ * For example: display, position, float, clear, and overflow.
*/
-.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;
-}
+/* @group Inline lists */
-.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;
+.horizontal > * {
+ clear: none;
+ float: left; /* LTR */
}
-.views-display .tab-section .links {
+.horizontal.right {
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%;
+.horizontal label {
+ position: absolute;
}
-.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;
+.horizontal .form-item > [class] {
+ margin-top: 25px;
}
-#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 {
+.horizontal .form-item > [class] + [class] {
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;
-}
+/* @end */
+
+/* @group Columns */
-.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 {
+.views-left-25 {
float: left;
width: 25%;
}
-#views-ajax-pad .views-left-30 {
+.views-left-30 {
float: left;
width: 30%;
}
-#views-ajax-pad .views-left-40 {
+.views-left-40 {
float: left;
width: 40%;
}
-#views-ajax-pad .views-left-50 {
+.views-left-50 {
float: left;
- width: 49.5%;
+ width: 50%;
}
-#views-ajax-pad .views-right-50 {
+.views-left-75 {
+ float: left;
+ width: 75%;
+}
+
+.views-right-50 {
float: right;
width: 50%;
}
-#views-ajax-pad .views-right-60 {
+.views-right-60 {
float: right;
width: 60%;
}
-#views-ajax-pad .views-right-70 {
+.views-right-70 {
float: right;
width: 70%;
}
-#views-ajax-pad .views-left-75 {
- float: left;
- width: 75%;
-}
+/* @end */
-#views-ajax-pad .views-radio-box {
- overflow: auto;
- height: 22em;
-}
+/* @group Attachment details
+ *
+ * The attachment details section, its tabs for each section and the buttons
+ * to add a new section
+ */
-#views-ajax-pad fieldset {
- margin: 0 .5em;
+.form-actions {
+ float: right; /* LTR */
}
-#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-displays {
+ clear: both;
+ float:left; /* LTR */
}
-#views-ajax-pad label.expanded-options {
- background: transparent url(../images/expanded-options.png) no-repeat right;
- height: 12px;
- padding-right: 16px;
+.views-displays .secondary {
+ overflow: visible;
}
-#views-ajax-pad .dependent-options {
- padding-left: 30px;
-}
+/* @end */
-/*
- * Add, Rearrange and Configure buttons using sprites
+/* @group Attachment details tabs
+ *
+ * The tabs that switch between sections
*/
-a.views-button-configure,
-a.views-button-add,
-a.views-button-rearrange,
-a.views-button-remove {
- background:transparent url(../images/sprites.png);
+
+.views-displays .secondary > li {
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;
+ float: left; /* LTR */
}
-a.views-button-remove {
- background-position: 0px -72px;
+.views-displays .secondary .open > a {
position: relative;
-}
-a.views-button-remove:hover {
- background-position: 0px -84px;
+ z-index: 51;
}
-a.views-button-configure {
- background-position: 0px -48px;
- margin: 0;
-}
-a.views-button-configure:hover {
- background-position: 0px -60px;
+.views-displays .views-display-deleted-link {
+ text-decoration: line-through;
}
-a.views-button-add {
- background-position: 0px -24px;
-}
-a.views-button-add:hover {
- background-position: 0px -36px;
+.views-display-deleted > fieldset > legend,
+.views-display-deleted .fieldset-wrapper > .views-ui-display-tab-bucket > *,
+.views-display-deleted .views-display-columns {
+ opacity: 0.25;
}
-a.views-button-rearrange {
- background-position: 0px 0px;
-}
-a.views-button-rearrange:hover {
- background-position: 0px -12px;
+.views-display-tab .fieldset-wrapper > .views-ui-display-tab-bucket .actions {
+ opacity: 1.0;
}
+/* @end */
-a.views-button-remove span,
-a.views-button-rearrange span,
-a.views-button-configure span,
-a.views-button-add span {
- display: none;
-}
+/* @group Attachment details new section button */
-html.js #arrange thead {
- display: none;
+.views-displays .secondary li.add {
+ position: relative;
}
-html.js #ungroupable_arrange .views-hide-label {
- color: #D4E7F3;
+.views-displays .secondary .action-list {
+ left: 0; /* LTR */
+ margin: 0;
+ position: absolute;
+ top: 22px;
+ z-index: 50;
}
-#ungroupable_arrange thead tr {
- /* this CSS mirrors what is found in core for blocks admin. */
- background-color: #D4E7F3;
- border-bottom: 1px solid #B4D7F0;
- border-top: 1.5em solid #FFFFFF;
- color: #455067;
- padding-top: 0;
- padding-bottom: 0;
+.views-displays .secondary .action-list li {
+ display: block;
}
-html.js .views-remove-checkbox {
- display: none;
-}
+/* @end */
-a.views-button-remove {
- display: none;
-}
+/* @group Attachment details collapsible fieldset */
-html.js a.views-button-remove {
- display: inline;
+.views-display-tab .fieldset-legend {
+ left: -5px; /* LTR */
+ position: relative;
}
-.arrange tr.even,
-.arrange tr.odd,
-.arrange td {
- padding-top: 0;
- padding-bottom: 0;
+.views-display-tab .fieldset-wrapper {
+ position: relative;
}
-.arrange .form-item {
- padding: 0;
-}
+/* @end */
-div.changed {
- background-color: #ffe;
- font-weight: bold;
+/* @group Attachment details actions
+ *
+ * Display the "Delete" and "Duplicate" buttons to the right.
+ */
+.views-display-tab .fieldset-wrapper > .views-ui-display-tab-bucket .actions {
+ position: absolute;
+ right: 0; /* LTR */
+ top: -5px;
}
-div.view-changed {
- display: none;
- float: right;
- font-style: italic;
- color: #f93;
- padding-left: 1em;
-}
+/* @end */
-div.views-tab div.changed a {
+/* @group Attachment configuration columns */
+.views-display-columns > * {
+ float: left; /* LTR */
+ margin-left: 1%; /* LTR */
+ padding-left: 1%; /* LTR */
+ width: 32%;
}
-div.changed div.view-changed {
- display: block;
+.views-display-columns > *:first-child {
+ margin-left: 0; /* LTR */
+ padding-left: 0; /* LTR */
}
-.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; */
-}
+/* @end */
-.views-display .tab-section .views-category-content.overridden {
- background-image: none;
-}
+/* @group Modal dialog box */
-.views-display .tab-section .inside .defaulted {
- color: #aaa;
- font-style: italic;
+.views-ui-dialog .ui-dialog-titlebar {
+ display: none;
}
-.views-display .tab-section .inside .defaulted a {
- font-style: italic;
+.views-ui-dialog #views-ajax-popup {
+ padding: 0;
}
-.hilited {
- color: #000;
- font-weight: bold;
- background-color: #ffd;
- padding-left: 10px;
+.views-ui-dialog #views-ajax-title,
+.views-ui-dialog #views-ajax-body {
+ margin: 0;
+ padding: 0;
}
-#views-ajax-pad fieldset {
- background: transparent;
- padding-left: 10px;
+.views-ui-dialog #views-ajax-popup {
+ overflow: hidden;
}
-#views-ajax-pad pre {
+.views-ui-dialog .scroll {
+ max-height: 400px;
overflow: auto;
- border: 1px solid #333;
- background-color: #f0f0f0;
- padding: .5em;
-}
-
-form#views-ui-reorder-displays-button {
- margin-bottom: 0em;
- border-bottom: 1px solid #ccc;
-}
-form#views-ui-reorder-displays-button input.form-submit{
- margin-bottom: 2em;
}
-form#views-add-display-form {
- margin-bottom: 0em;
- border-bottom: 1px solid #ccc;
+#views-filterable-options-controls {
+ display: none;
}
-form#views-add-display-form select {
- width: 8.5em;
+.views-ui-dialog #views-filterable-options-controls {
+ display: block;
}
-#views-ui-edit-view-form {
- margin: 10px 0 0;
- padding: 0;
- clear: both;
-}
+/* @end */
-#views-live-preview {
- padding-top: .5em;
-}
+/* @group Settings forms */
-#views-live-preview form,
-#center #views-live-preview form {
- border: 1px solid #D6DBDE;
- margin: 0 0 .5em 0;
- padding: .5em;
+.views-dependent {
+ margin-left: 1.5em; /* LTR */
}
-#views-live-preview form div.form-item {
- float: left;
- margin: 0;
- padding: 0 1em 0 0;
+.views-display-setting .label,
+.views-display-setting .views-ajax-link {
+ display: inline-block;
+ float: left; /* LTR */
}
-#views-live-preview form input#preview-submit {
- margin: 1em 0 0 0;
-}
+/* @end */
-.view-locked {
- color: red;
- border: 1px solid red;
- padding: 1em;
-}
+/* @group Filter Settings form */
-/* Hide by default only with js */
-html.js .views-hidden {
+div.form-item-options-value-all {
display: none;
}
+/* @end */
-.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;
-}
+/* @group Drupal overrides */
-.views-quick-links {
- float: right;
+/* The .progress-disabled class added to the form on submit floats the element
+ * left and causes the form width to shrink-wrap to the content. Setting the
+ * width to 100% prevents this.
+ */
+#views-ajax-body form {
+ width: 100%;
}
-.views-quick-links ul.links li {
- padding-left: 1em;
-}
+/* @end */
-.views-quick-links li.last {
-}
+/* @group Clearfix
+ *
+ * @see http://perishablepress.com/press/2009/12/06/new-clearfix-hack
+ */
-.views-edit-view .advanced-help-link {
- padding-right: 3px;
+ /* Reset the formatting context for all modern browsers */
+.views-display-tab .fieldset-wrapper:after,
+ul.secondary:after {
+ clear: both;
+ content: " x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x ";
+ display: block;
+ font-size: xx-large;
+ height: 0 !important;
+ line-height: 0;
+ overflow: hidden;
+ visibility: hidden;
}
-#views-ajax-title .advanced-help-link {
- position: relative;
- top: 2px;
- padding-right: 3px;
+/* Reset the formatting context for IE */
+.views-display-tab .fieldset-wrapper,
+ul.secondary {
+ zoom: 1;
}
-#views-ajax-pad input,
-#views-ajax-pad textarea {
- max-width: 95%;
-}
+/* @end */
-.clone-display,
-.remove-display {
- float: right;
- margin: 0;
- padding: .2em 1em 0 0;
- position: relative;
- top: .1em;
-}
+/* @group Javascript dependent styling */
-.views-display .remove-display form,
-.remove-display input,
-.views-display .clone-display form,
-.clone-display input {
- margin: 0 !important;
+.js-only {
+ display: none;
}
-.views-validator-options {
- padding: 0 1em;
- margin: 0 1em;
- border: 1px solid;
+html.js .js-only {
+ display: inherit;
}
-div.views-category #page-title {
- background: none;
- padding-top: 0px;
+html.js span.js-only {
+ display: inline;
}
-.group-populated {
- display: none;
-}
+/* @end */
-td.group {
- /* this CSS mirrors what is found in core for blocks admin. */
- background-color: #D4E7F3;
- border-bottom: 1px solid #B4D7F0;
- border-top: 1.5em solid #FFFFFF;
- color: #455067;
-}
+/* @group AJAX throbber */
-td.group-title {
- font-weight: bold;
+/* Base Page */
+.views-admin .ajax-progress-throbber {
+ left: 45%;
+ position: fixed;
+ top: 45%;
}
-
-tr.group-message {
- font-style: italic;
- color:#999999;
+.views-admin .ajax-progress-throbber .message {
+ display: none;
}
-.group-message .form-submit,
-#views-add-group {
- float: right;
- clear: both;
+/* Modal */
+#views-ajax-popup .ajax-progress-throbber {
+ left: 45%;
+ position: fixed;
+ top: 45%;
}
-
-html.js .views-group-select {
+#views-ajax-popup .ajax-progress-throbber .message {
display: none;
}
+
+/* @end */
diff --git a/css/views-admin.ctools.css b/css/views-admin.ctools.css
new file mode 100644
index 0000000..644f32c
--- /dev/null
+++ b/css/views-admin.ctools.css
@@ -0,0 +1,224 @@
+/* @group Buttons */
+
+.ctools-button {
+ background-color: #ffffff;
+ background-image:
+ -moz-linear-gradient(
+ -90deg,
+ #ffffff 0px,
+ #f9f9f9 100%);
+ background-image:
+ -webkit-gradient(
+ linear,
+ left top,
+ left bottom,
+ color-stop(0.0, rgba(255, 255, 255, 1.0)),
+ color-stop(1.0, rgba(249, 249, 249, 1.0))
+ );
+ background-image:
+ -webkit-linear-gradient(
+ -90deg,
+ #ffffff 0px,
+ #f9f9f9 100%);
+ background-image:
+ linear-gradient(
+ -90deg,
+ #ffffff 0px,
+ #f9f9f9 100%);
+ border-color: #cccccc;
+ -moz-border-radius: 11px 11px 11px 11px;
+ -webkit-border-radius: 11px 11px 11px 11px;
+ border-radius: 11px 11px 11px 11px;
+ font-size: 11px;
+ padding-bottom: 2px;
+ padding-top: 2px;
+}
+
+.ctools-button:hover {
+ background-image:
+ -moz-linear-gradient(
+ -90deg,
+ #ffffff 0px,
+ #f1f1f1 100%);
+ background-image:
+ -webkit-gradient(
+ linear,
+ left top,
+ left bottom,
+ color-stop(0.0, rgba(255, 255, 255, 1.0)),
+ color-stop(1.0, rgba(241, 241, 241, 1.0))
+ );
+ background-image:
+ -webkit-linear-gradient(
+ -90deg,
+ #ffffff 0px,
+ #f1f1f1 100%);
+ background-image:
+ linear-gradient(
+ -90deg,
+ #ffffff 0px,
+ #f1f1f1 100%);
+ border-color: #b8b8b8;
+}
+
+.ctools-button:active {
+ border-color: #a0a0a0;
+}
+
+.ctools-button .ctools-content {
+ padding-bottom: 0;
+ padding-top: 0;
+}
+
+.ctools-dropbutton .ctools-content {
+ border-right: 1px solid #e8e8e8;
+}
+
+.ctools-button .ctools-content a {
+ background-image: none;
+ border: medium none;
+}
+
+.ctools-dropbutton.open:hover {
+ background-image:
+ -moz-linear-gradient(
+ -90deg,
+ #ffffff 0px,
+ #f9f9f9 100%);
+ background-image:
+ -webkit-gradient(
+ linear,
+ left top,
+ left bottom,
+ color-stop(0.0, rgba(255, 255, 255, 1.0)),
+ color-stop(1.0, rgba(249, 249, 249, 1.0))
+ );
+ background-image:
+ -webkit-linear-gradient(
+ -90deg,
+ #ffffff 0px,
+ #f9f9f9 100%);
+ background-image:
+ linear-gradient(
+ -90deg,
+ #ffffff 0px,
+ #f9f9f9 100%);
+ border-color: #D0D0D0;
+}
+
+.ctools-dropbutton.open {
+ -moz-box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
+ -webkit-box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
+ box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
+ z-index: 100;
+}
+
+.ctools-dropbutton .ctools-link {
+ border-left: 1px solid #ffffff;
+}
+
+.ctools-dropbutton.open .ctools-content {
+ padding-bottom: 4px;
+}
+
+.ctools-dropbutton li {
+ padding-right: 9px;
+}
+
+.ctools-dropbutton.open li + li {
+ border-top: 1px solid #efefef;
+ margin-top: 4px;
+ padding-bottom: 0;
+ padding-top: 4px;
+}
+
+.views-display-top .ctools-button {
+ font-size: 12px;
+ position: absolute;
+ right: 12px;
+ top: 7px;
+}
+
+.views-ui-display-tab-bucket .ctools-button {
+ position: absolute;
+}
+
+.views-ui-display-tab-bucket .ctools-button {
+ right: 5px;
+ top: 4px;
+}
+
+.views-ui-display-tab-actions .ctools-button input {
+ background: none;
+ border: medium;
+ color: #0074BD;
+ font-family: inherit;
+ font-size: 12px;
+ padding: 0;
+}
+
+/* @end */
+
+/* @group Collapsible */
+
+.ctools-toggle {
+ border-bottom-color: transparent;
+ border-left-color: transparent;
+ border-right-color: transparent;
+ border-style: solid;
+ border-width: 5px 5px 0;
+ display: inline-block;
+ float: left;
+ height: 0;
+ margin-right: 2px;
+ margin-top: 0.6667em;
+ width: 0;
+}
+
+.ctools-toggle.ctools-toggle-collapsed {
+ border-bottom-color: transparent;
+ border-left: 4px solid;
+ border-right-color: transparent;
+ border-top-color: transparent;
+ border-width: 5px 0 5px 5px;
+ margin-left: 2px;
+ margin-right: 5px;
+ margin-top: 0.5em;
+}
+
+.ctools-toggle:hover,
+.ctools-collapsible-handle:hover {
+ cursor: pointer;
+}
+
+.ctools-export-ui-row {
+ margin-bottom: 5px;
+}
+
+.ctools-export-ui-row label {
+ display: block;
+ float: left;
+ width: 55px;
+}
+
+.views-display-settings .ctools-toggle {
+ color: #008BCB;
+}
+
+/* @end */
+
+/* @group Export */
+
+.ctools-export-ui-fourth-row input {
+ margin-top: 5px !important;
+}
+
+/* @end */
+
+/* @group Jump list */
+
+#views-live-preview .ctools-jump-menu-select{
+ max-width: 450px;
+}
+
+/* @end */
diff --git a/css/views-admin.seven-rtl.css b/css/views-admin.seven-rtl.css
new file mode 100644
index 0000000..e01f830
--- /dev/null
+++ b/css/views-admin.seven-rtl.css
@@ -0,0 +1,29 @@
+/**
+ * The .seven.css file is intended to contain styles that override declarations
+ * in the Seven admin theme.
+ */
+
+/* @group Forms */
+
+.views-admin .form-submit,
+.views-admin a.button {
+ margin-left: 0;
+}
+
+/* @end */
+
+/* @group Lists */
+
+.views-admin .links li {
+ padding-left: 0;
+}
+
+/* @end */
+
+/* @group Attachments */
+
+.views-displays .secondary {
+ text-align: right;
+}
+
+/* @end */
diff --git a/css/views-admin.seven.css b/css/views-admin.seven.css
new file mode 100644
index 0000000..9ac55c0
--- /dev/null
+++ b/css/views-admin.seven.css
@@ -0,0 +1,209 @@
+/**
+ * The .seven.css file is intended to contain styles that override declarations
+ * in the Seven admin theme.
+ */
+
+/* @group Content */
+
+.views-ui-display-tab-bucket h1,
+.views-ui-display-tab-bucket h2,
+.views-ui-display-tab-bucket h3,
+.views-ui-display-tab-bucket h4,
+.views-ui-display-tab-bucket h5 {
+ margin-bottom: 0;
+ margin-top: 0;
+}
+
+/* @end */
+
+/* @group Forms */
+
+fieldset {
+ padding-top: 0;
+}
+
+fieldset fieldset {
+ border: medium none;
+}
+
+.views-display-tab fieldset {
+ padding: 0 12px;
+}
+
+.views-display-tab .fieldset-wrapper {
+ padding: 10px 12px 12px;
+}
+
+.views-display-tab fieldset.box-padding .fieldset-wrapper {
+ padding: 0;
+}
+
+.views-display-tab legend + .fieldset-wrapper {
+ padding-top: 2.5em;
+}
+
+.views-admin input.form-submit,
+.views-ui-dialog input.form-submit,
+.views-admin a.button,
+.views-ui-dialog a.button {
+ margin-bottom: 0;
+ margin-right: 0; /* LTR */
+ margin-top: 0;
+}
+
+/* Override for a button on the edit display screen */
+#edit-displays-preview-controls .form-submit {
+ display: inline-block;
+ margin-right: 1em;
+}
+
+/* Override for filter button on the views list screen */
+#ctools-export-ui-list-form .form-submit {
+ margin-top: 1.3em;
+}
+
+.form-item {
+ margin-bottom: 0;
+ margin-top: 15px;
+ padding-bottom: 0;
+ padding-top: 0;
+}
+
+.form-actions {
+ margin-bottom: 0;
+ margin-top: 0;
+}
+
+.form-item .form-item {
+ padding-bottom: 0;
+ padding-top: 0;
+}
+
+/* @end */
+
+/* @group Lists */
+
+.views-admin ul.secondary,
+.views-admin .item-list ul {
+ margin: 0;
+ padding: 0;
+}
+
+.views-admin ul.secondary {
+ clear: none;
+}
+
+.views-displays ul.secondary li a {
+ padding: 2px 7px 3px;
+}
+
+.views-admin .links li {
+ padding-right: 0; /* LTR */
+}
+
+.views-admin .button .links li {
+ padding-right: 12px; /* LTR */
+}
+
+.page-admin-structure-views #content ul.action-links {
+ padding-left: 0;
+ padding-right: 0;
+}
+
+.views-display-top ul.secondary {
+ background-color: transparent;
+}
+
+/* @end */
+
+/* @group Buttons */
+
+.ctools-button ul {
+ margin: 0;
+}
+
+/* Override for input elements that are themed like ctools-buttons */
+.ctools-button input.form-submit:hover {
+ background-image: none;
+ color: #0074BD;
+ text-shadow: none;
+}
+
+.ctools-button input.form-submit:active {
+ background: none;
+ border: medium none;
+ color: #0074BD;
+ text-shadow: none;
+}
+
+/* @end */
+
+/* @group Tables */
+
+table td,
+table th {
+ vertical-align: top;
+}
+
+/* @end */
+
+/* @group Attachment buckets
+ *
+ * These are the individual "buckets," or boxes, inside the display settings area
+ */
+
+.views-ui-display-tab-bucket .links {
+ padding: 2px 6px 4px;
+}
+
+.views-ui-display-tab-bucket .links li + li {
+ margin-left: 3px;
+}
+
+/* @end */
+
+/* @group Rearrange filter criteria */
+
+#views-ui-rearrange-filter-form .action-links {
+ margin: 0;
+ padding: 0;
+}
+
+#views-ui-rearrange-filter-form table {
+ border: medium none;
+}
+
+#views-ui-rearrange-filter-form [id^="views-row"] {
+ border: medium none;
+}
+
+#views-ui-rearrange-filter-form tr td:last-child {
+ border-right: medium none;
+}
+
+#views-ui-rearrange-filter-form .filter-group-operator-row {
+ border-left: 1px solid transparent !important;
+ border-right: 1px solid transparent !important;
+}
+
+#views-ui-rearrange-filter-form tr.drag td {
+ background-color: #FFEE77 !important;
+}
+
+#views-ui-rearrange-filter-form tr.drag-previous td {
+ background-color: #FFFFBB !important;
+}
+
+/* @end */
+
+/* @group Attachments */
+
+.views-displays .secondary {
+ text-align: left; /* LTR */
+}
+
+.views-displays .secondary > li:first-child {
+ padding-left: 0;
+}
+
+/* @end */
diff --git a/css/views-admin.theme-rtl.css b/css/views-admin.theme-rtl.css
new file mode 100644
index 0000000..1b0c011
--- /dev/null
+++ b/css/views-admin.theme-rtl.css
@@ -0,0 +1,208 @@
+/**
+ * The .theme.css file is intended to contain presentation declarations including
+ * images, borders, colors, and fonts.
+ */
+
+/* @end */
+
+/* @group Icons */
+
+.actions a,
+.views-admin .icon,
+.views-admin .icon-text {
+ background-position: right top;
+}
+
+/* Targets any element with an icon -> text combo */
+.views-admin .icon-text {
+ padding-right: 19px;
+}
+
+.views-admin .icon-linked {
+ background-position: right -153px;
+}
+
+.views-admin .icon-unlinked {
+ background-position: right -195px;
+}
+
+.actions .views-button-add {
+ background-position: right -39px;
+}
+
+.actions .views-button-rearrange {
+ background-position: right -96px;
+}
+
+.actions .views-button-add:hover {
+ background-position: right -58px;
+}
+
+.actions .views-button-rearrange:hover {
+ background-position: right -115px;
+}
+
+.actions .views-button-add:active {
+ background-position: right -77px;
+}
+
+.actions .views-button-rearrange:active {
+ background-position: right -134px;
+}
+
+.views-displays .icon-add {
+ background-position: right -3px;
+}
+
+.views-displays .secondary a:hover > .icon-add {
+ background-position: right -21px;
+}
+
+.views-displays .secondary .open a:hover > .icon-add {
+ background-position: right -3px;
+}
+
+/* @end */
+
+/* @group Forms */
+
+.form-submit + .form-submit,
+.views-admin a.button + a.button {
+ margin-right: 1em;
+}
+
+.container-inline > * + *,
+.container-inline .fieldset-wrapper > * + * {
+ padding-left: 0;
+ padding-right: 4pt;
+}
+
+/* @end */
+
+/* @group Lists */
+
+.horizontal > * + * {
+ margin-right: 9px;
+ padding-right: 9px;
+}
+
+/* @end */
+
+/* @group Attachments */
+
+.views-displays .secondary {
+ padding: 6px 8px 8px;
+}
+
+.views-displays .views-display-top > ul > li + li {
+ margin-right: 3px;
+}
+
+.views-displays .views-extra-actions {
+ left: 10px;
+}
+
+/* @end */
+
+/* @group Attachment details tabs
+ *
+ * The tabs that switch between sections
+ */
+
+.views-displays .secondary .action-list li:first-child {
+ -moz-border-radius: 7px 0 0 0;
+ -webkit-border-top-left-radius: 7px;
+ -webkit-border-top-right-radius: 0;
+ border-radius: 7px 0 0 0;
+}
+
+/* @end */
+
+/* @group Attachment details collapsible fieldset
+ *
+ * The attachment details section is a collapsible fieldset, but should not
+ * have a border around it.
+ */
+
+.views-display-tab .fieldset-legend {
+ left: auto;
+ right: -5px;
+}
+
+/* @end */
+
+/* @group Auto preview
+ *
+ * The auto-preview checkbox line. This may have more stuff added to it.
+ */
+
+div.form-item-displays-live-preview {
+ text-align: left;
+}
+
+/* @end */
+
+/* @group Attachment buckets
+ *
+ * These are the individual "buckets," or boxes, inside the three columns in the
+ * attachment details section.
+ */
+
+.views-ui-display-tab-bucket .icon-text {
+ padding-right: 25px;
+}
+
+.views-ui-display-tab-bucket.overridden .views-display-setting {
+ margin-right: 15px;
+}
+
+/* @end */
+
+/* @group Attachment bucket rows
+ *
+ * This is each row within one of the "boxes."
+ */
+
+.views-display-setting .label {
+ margin-left: 3pt;
+}
+
+/* @end */
+
+/* @group Modal dialog box
+ *
+ * The contents of the popup dialog on the views edit form.
+ */
+
+#views-filterable-options-controls .form-item {
+ margin-left: 2%;
+}
+
+.views-ui-dialog #views-progress-indicator {
+ left: 10px;
+ right: auto;
+}
+
+/* @end */
+
+/* @group Rearrange filters
+ *
+ * Styling for the form that allows views filters to be rearranged.
+ */
+.views-operator-label {
+ padding-right: 0.5em;
+}
+
+/* @end */
+
+/* @group Live preview elements */
+
+/* @group HTML list */
+
+#views-live-preview .view-content > .item-list > ul {
+ padding-right: 21px;
+}
+
+/* @end */
+
+/* @end */
diff --git a/css/views-admin.theme.css b/css/views-admin.theme.css
new file mode 100644
index 0000000..5c92a45
--- /dev/null
+++ b/css/views-admin.theme.css
@@ -0,0 +1,921 @@
+/**
+ * The .theme.css file is intended to contain presentation declarations including
+ * images, borders, colors, and fonts.
+ */
+
+/* @group Reset */
+
+.views-admin .links {
+ list-style: none outside none;
+ margin: 0;
+}
+
+.views-admin a:hover {
+ text-decoration: none;
+}
+
+/* @end */
+
+/* @group Layout */
+
+.box-padding {
+ padding-left: 12px;
+ padding-right: 12px;
+}
+
+.box-margin {
+ margin-left: 12px;
+ margin-right: 12px;
+}
+
+/* @end */
+
+/* @group Icons */
+
+.views-admin .icon {
+ height: 16px;
+ width: 16px;
+}
+
+.views-admin .icon,
+.views-admin .icon-text {
+ background-attachment: scroll;
+ background-image: url("../images/sprites.png");
+ background-position: left top; /* LTR */
+ background-repeat: no-repeat;
+}
+
+.views-admin a.icon {
+ background-image:
+ url("../images/sprites.png"),
+ -moz-linear-gradient(
+ -90deg,
+ #ffffff 0px,
+ #e8e8e8 100%);
+ background-image:
+ url("../images/sprites.png"),
+ -webkit-gradient(
+ linear,
+ left top,
+ left bottom,
+ color-stop(0.0, rgba(255, 255, 255, 1.0)),
+ color-stop(1.0, rgba(232, 232, 232, 1.0))
+ );
+ background-image:
+ url("../images/sprites.png"),
+ -webkit-linear-gradient(
+ -90deg,
+ #ffffff 0px,
+ #e8e8e8 100%);
+ background-repeat: no-repeat, repeat-y;
+ border: 1px solid #dddddd;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ -moz-box-shadow: 0 0 0 rgba(0,0,0,0.3333) inset;
+ -webkit-box-shadow: 0 0 0 rgba(0,0,0,0.3333) inset;
+ box-shadow: 0 0 0 rgba(0,0,0,0.3333) inset;
+}
+
+.views-admin a.icon:hover {
+ border-color: #d0d0d0;
+ -moz-box-shadow: 0 0 1px rgba(0,0,0,0.3333) inset;
+ -webkit-box-shadow: 0 0 1px rgba(0,0,0,0.3333) inset;
+ box-shadow: 0 0 1px rgba(0,0,0,0.3333) inset;
+}
+
+.views-admin a.icon:active {
+ border-color: #c0c0c0;
+}
+
+/**
+ * Targets a <span> element inside an <a> element.
+ * This assumes no visible text from the span.
+ */
+.views-admin span.icon {
+ display: inline-block;
+ float: left;
+ position: relative;
+}
+
+.views-admin .icon.compact {
+ display: block;
+ overflow: hidden;
+ text-indent: -9999px;
+}
+
+/* Targets any element with an icon -> text combo */
+.views-admin .icon-text {
+ padding-left: 19px; /* LTR */
+}
+
+.views-admin .icon.linked {
+ background-position: center -153px;
+}
+
+.views-admin .icon.unlinked {
+ background-position: center -195px;
+}
+
+.views-admin .icon.add {
+ background-position: center 3px;
+}
+
+.views-admin a.icon.add {
+ background-position: center 3px, left top;
+}
+
+.views-admin .icon.delete {
+ background-position: center -52px;
+}
+
+.views-admin a.icon.delete {
+ background-position: center -52px, left top;
+}
+
+.views-admin .icon.rearrange {
+ background-position: center -111px;
+}
+
+.views-admin a.icon.rearrange {
+ background-position: center -111px, left top;
+}
+
+.views-displays .secondary a:hover > .icon.add {
+ background-position: center -25px;
+}
+
+.views-displays .secondary .open a:hover > .icon.add {
+ background-position: center 3px;
+}
+
+/* @end */
+
+/* @group Forms */
+
+.views-admin-dependent {
+ padding-left: 17px;
+}
+
+fieldset.box-padding {
+ border: none;
+}
+
+.form-item {
+ margin-top: 15px;
+ padding-bottom: 0;
+ padding-top: 0;
+}
+
+input.form-checkbox,
+input.form-radio {
+ vertical-align: baseline;
+}
+
+.form-submit + .form-submit,
+.views-admin a.button + a.button {
+ margin-left: 1em; /* LTR */
+}
+
+/*.fieldset-wrapper > * + *,
+.form-wrapper > * + * {
+ margin-top: 15px;
+}*/
+
+.container-inline {
+ padding-top: 15px;
+}
+
+.container-inline > * + *,
+.container-inline .fieldset-wrapper > * + * {
+ padding-left: 4pt; /* LTR */
+}
+
+.views-admin .form-type-checkbox + .form-wrapper {
+ margin-left: 16px;
+}
+
+/* Hide 'remove' checkboxes. This might be scoped too widely. */
+[class*="form-type-checkbox"][class*="remove"] {
+ display: none;
+}
+
+/* sizes the labels of checkboxes and radio button to the height of the text */
+.form-type-checkbox label,
+.form-type-radio label {
+ line-height: 2;
+}
+
+/* @end */
+
+/* @group Lists */
+
+.horizontal > * + * {
+ margin-left: 9px; /* LTR */
+ padding-left: 9px; /* LTR */
+}
+
+.views-ui-view-title {
+ font-weight: bold;
+}
+
+/* @end */
+
+/* @group Messages */
+
+.view-changed {
+ margin-bottom: 21px;
+}
+
+/* @end */
+
+/* @group Headings */
+
+/* Intentionally targeting h1 */
+.views-admin h1.unit-title {
+ font-size: 15px;
+ line-height: 1.6154;
+ margin-bottom: 0;
+ margin-top: 18px;
+}
+
+/* @end */
+
+/* @group Tables */
+
+table td,
+table th {
+ vertical-align: top;
+}
+
+/* @end */
+
+/* @group List views */
+
+/* These header classes are ambiguous and should be scoped to th elements */
+
+th.views-ui-name {
+ width: 18%;
+}
+
+th.views-ui-description {
+ width: 26%;
+}
+
+th.views-ui-tag {
+ width: 8%;
+}
+
+th.views-ui-path {
+ width: auto;
+}
+
+th.views-ui-operations {
+ width: 24%;
+}
+
+/* @end */
+
+/* @group Add view */
+
+/**
+ * I wish this didn't have to be so specific
+ */
+.form-item-description-enable + .form-item-description {
+ margin-top: 0;
+}
+
+.form-item-description-enable label {
+ font-weight: bold;
+}
+
+/* This could be made more general if more than one instance occurs */
+#edit-page-style .fieldset-wrapper {
+ padding-left: 0;
+ padding-right: 0;
+}
+
+/* @end */
+
+/* @group Rearrange filters
+ *
+ * Styling for the form that allows views filters to be rearranged.
+ */
+
+.group-populated {
+ display: none;
+}
+
+td.group-title {
+ font-weight: bold;
+}
+
+.views-ui-dialog td.group-title {
+ margin: 0;
+ padding: 0;
+}
+
+.views-ui-dialog td.group-title span {
+ display: block;
+ height: 1px;
+ overflow: hidden;
+}
+
+.group-message .form-submit,
+.views-remove-group-link,
+#views-add-group {
+ float: right;
+ clear: both;
+}
+
+.views-operator-label {
+ font-style: italic;
+ font-weight: bold;
+ padding-left: 0.5em; /* LTR */
+ text-transform: uppercase;
+}
+
+.form-item-show-wizard-key label {
+ float: left;
+}
+
+.form-item-show-wizard-key select {
+ margin-left: 5px;
+}
+
+.exposed-description {
+ float: left;
+ padding-top: 3px;
+ padding-right: 10px;
+}
+
+#edit-options-more {
+ clear: both;
+}
+
+/* @end */
+
+/* @group Attachments */
+
+.views-displays {
+ border: 1px solid #CCC;
+ padding-bottom: 18px;
+}
+
+.views-display-top {
+ background-color: #F9F9F9;
+ border-bottom: 1px solid #CCCCCC;
+ margin-bottom: 14px;
+ padding: 8px 8px 6px; /* LTR */
+ position: relative;
+}
+
+.views-display-top .secondary > li + li {
+ margin-left: 6px;
+ padding-left: 0;
+}
+
+#views-display-extra-actions li {
+ padding: 3px 9px;
+}
+
+#views-display-extra-actions .analyze {
+ border-color: #aaa;
+ border-style: solid;
+ border-width: 0 1px;
+ margin-right: 1px;
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+/* @end */
+
+/* @group Attachment details tabs
+ *
+ * The tabs that switch between sections
+ */
+
+.views-displays .secondary a {
+ background-color: #f1f1f1;
+ border: 1px solid #cbcbcb;
+ -moz-border-radius: 7px;
+ -webkit-border-radius: 7px;
+ border-radius: 7px;
+ color: #008BCB;
+ display: inline-block;
+ padding: 2px 7px 3px;
+}
+
+.views-displays .secondary a:focus {
+ outline: none;
+}
+
+.views-displays .secondary a:hover,
+.views-displays .secondary .active a {
+ background-color: #666666;
+ color: #ffffff;
+}
+
+.views-displays .secondary .open > a {
+ -moz-border-radius: 7px 7px 0 0;
+ -webkit-border-radius: 7px 7px 0 0;
+ border-radius: 7px 7px 0 0;
+ border-bottom: 1px solid transparent;
+ position: relative;
+}
+
+.views-displays .secondary .open > a:hover {
+ background-color: #f1f1f1;
+ color: #008BCB;
+}
+
+.views-displays .secondary .action-list li {
+ background-color: #f1f1f1;
+ border-color: #cbcbcb;
+ border-style: solid;
+ border-width: 0 1px;
+ padding: 2px 9px;
+}
+
+.views-displays .secondary .action-list li:first-child {
+ -moz-border-radius: 0 7px 0 0;
+ -webkit-border-radius: 0 7px 0 0;
+ border-radius: 0 7px 0 0;
+ border-width: 1px 1px 0;
+}
+
+.views-displays .secondary .action-list li.last {
+ border-width: 0 1px 1px;
+}
+
+.views-displays .secondary .action-list li:last-child {
+ -moz-border-radius: 0 0 7px 7px;
+ -webkit-border-radius: 0 0 7px 7px;
+ border-radius: 0 0 7px 7px;
+ border-width: 0 1px 1px;
+}
+
+.views-displays .secondary .action-list input.form-submit {
+ background: none repeat scroll 0 0 transparent;
+ border: medium none;
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ border-radius: 0;
+ color: #008BCB;
+ padding: 0;
+}
+
+.views-displays .secondary .action-list li:hover {
+ background-color: #dddddd;
+}
+
+/* @end */
+
+/* @group Attachment details */
+
+#edit-display-settings {
+ border-bottom: 3px solid #CCC;
+ padding-bottom: 12px;
+}
+
+#edit-display-settings-title {
+ color: #008BCB;
+ font-size: 14px;
+ line-height: 1.5;
+ margin: 0;
+}
+
+#edit-display-settings-top {
+ padding-bottom: 4px;
+}
+
+#edit-display-settings-content {
+ margin-top: 12px;
+}
+
+#edit-display-settings-main {
+ margin-top: 15px;
+}
+
+/* @end */
+
+/* @group Attachment columns
+ *
+ * The columns that contain the option buckets e.g. Format and Basic Settings
+ */
+
+.views-display-column + .views-display-column {
+ margin-top: 0;
+ }
+
+ /* @end */
+
+/* @group Auto preview
+ *
+ * The auto-preview checkbox line.
+ */
+
+#edit-display-preview-controls {
+ margin-top: 36px;
+}
+
+#edit-display-preview-controls > div,
+#edit-display-preview-controls > input {
+ float: left;
+}
+
+#edit-display-preview-controls > .form-type-checkbox {
+ margin-top: 4px;
+}
+
+#edit-display-preview-controls > .form-type-textfield {
+ margin-top: 5px;
+}
+
+#edit-display-preview-controls .arguments-preview,
+#edit-display-preview-controls .arguments-preview + .form-item {
+ margin-left: 14px;
+}
+
+#edit-display-preview-controls .form-type-textfield label {
+ position: absolute;
+}
+
+#edit-display-preview-controls .form-type-textfield input,
+#edit-display-preview-controls .form-type-textfield .description {
+ margin-left: 82px;
+}
+
+/* @end */
+
+/* @group Attachment buckets
+ *
+ * These are the individual "buckets," or boxes, inside the display settings area
+ */
+
+.views-ui-display-tab-bucket {
+ border: 1px solid #f3f3f3;
+ line-height: 20px;
+ margin: 0;
+ padding-top: 4px;
+}
+
+.views-ui-display-tab-bucket + .views-ui-display-tab-bucket {
+ border-top: medium none;
+}
+
+.views-ui-display-tab-bucket > h3,
+.views-ui-display-tab-bucket > .views-display-setting {
+ padding: 2px 6px 4px;
+}
+
+.views-ui-display-tab-bucket h3 {
+ font-size: 12px;
+ text-transform: uppercase;
+}
+
+.views-ui-display-tab-bucket .links.actions {
+ margin-top: 2px;
+}
+
+/* @end */
+
+/* @group Attachment bucket overridden
+ *
+ * Applies a broken link icon to overridden buckets.
+ * The better way to implement this would be to add the overridden class
+ * to the bucket header when the bucket is overridden and style it as a
+ * generic icon classed element. For the moment, we'll style the bucket
+ * header specifically with the broken link icon.
+ */
+
+.views-ui-display-tab-bucket.overridden > h3 {
+ background-attachment: scroll;
+ background-image: url("../images/sprites.png");
+ background-position: left -172px; /* LTR */
+ background-repeat: no-repeat;
+ overflow: hidden;
+ padding-left: 21px;
+ zoom: 1;
+}
+
+.views-ui-display-tab-bucket.overridden .views-display-setting {
+ margin-left: 15px; /* LTR */
+}
+
+/* @end */
+
+/* @group Attachment bucket drop button */
+
+.views-ui-display-tab-bucket {
+ position: relative;
+}
+
+/* @end */
+
+/* @group Attachment bucket rows
+ *
+ * This is each row within one of the "boxes."
+ */
+
+.views-ui-display-tab-bucket .views-display-setting {
+ color: #666666;
+ font-size: 12px;
+ padding-bottom: 2px;
+}
+
+.views-ui-display-tab-bucket .even {
+ background-color: #f9f9f9;
+}
+
+.views-ui-display-tab-bucket .views-group-text {
+ margin-top: 6px;
+ margin-bottom: 6px;
+}
+
+.views-display-setting .label {
+ margin-right: 3pt; /* LTR */
+}
+
+/* @end */
+
+/* @group Preview
+ *
+ * The preview controls and the preview pane
+ */
+
+#edit-displays-preview-controls .fieldset-wrapper > * {
+ float: left;
+}
+
+#edit-displays-preview-controls .fieldset-wrapper > .form-item {
+ margin-top: 0.3333em;
+}
+
+#edit-displays-preview-controls .form-submit {
+ display: inline-block;
+ margin-right: 1em;
+}
+
+#edit-displays-preview-controls .form-type-textfield {
+ margin-left: 1em;
+ position: relative;
+}
+
+#edit-displays-preview-controls .form-type-textfield label {
+ border-left: 1px solid #999;
+ padding-left: 1em;
+ position: absolute;
+}
+
+#edit-displays-preview-controls .form-type-textfield label:after {
+ content: ":";
+}
+
+#edit-displays-preview-controls .form-type-textfield label ~ * {
+ margin-left: 105px;
+}
+
+/* @end */
+
+/* @group Modal dialog box
+ *
+ * The contents of the popup dialog on the views edit form.
+ */
+
+.views-ui-dialog {
+ padding: 0;
+}
+
+.views-ui-dialog fieldset.collapsible {
+ padding-top: 1.5em;
+}
+
+.views-ui-dialog fieldset.collapsed {
+ padding-top: 2.5em;
+}
+
+div.views-filterable-options .form-type-checkbox {
+ border: 1px solid #CCC;
+ padding: 5px 8px;
+ border-top: none;
+}
+
+div.views-filterable-options {
+ border-top: 1px solid #CCC;
+}
+
+div.views-filterable-options .even .form-type-checkbox {
+ background-color: #F3F4EE;
+}
+
+div.views-filterable-options .form-type-checkbox .description {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+#views-filterable-options-controls {
+ margin: 1em 0;
+}
+
+#views-filterable-options-controls .form-item {
+ width: 45%;
+ margin-right: 2%; /* LTR */
+}
+
+#views-filterable-options-controls input,
+#views-filterable-options-controls select {
+ width: 200px;
+}
+
+.views-ui-dialog .views-filterable-options {
+ margin-bottom: 10px;
+}
+
+.views-ui-dialog .views-add-form-selected {
+ margin: 5px 16px;
+}
+
+.views-ui-dialog #views-ajax-title,
+.views-ui-dialog .views-override {
+ background-color: #F3F4EE;
+}
+
+.views-ui-dialog .views-override {
+ padding: 8px 13px;
+}
+
+.views-ui-dialog .views-override > * {
+ margin: 0;
+}
+
+.views-ui-dialog #views-ajax-title {
+ font-size: 15px;
+ padding: 8px 13px;
+}
+
+.views-ui-dialog #views-progress-indicator {
+ font-size: 11px;
+ position: absolute;
+ right: 10px; /* LTR */
+ top: 8px;
+}
+
+.views-ui-dialog #views-progress-indicator:before {
+ content: "\003C\00A0";
+}
+
+.views-ui-dialog #views-progress-indicator:after {
+ content: "\00A0\003E";
+}
+
+.views-ui-dialog .scroll {
+ border: 1px solid #CCC;
+ border-width: 1px 0;
+ padding: 8px 13px;
+}
+
+.views-ui-dialog .form-buttons {
+ background-color: #F3F4EE;
+ padding: 8px 13px;
+}
+.views-ui-dialog .form-buttons input {
+ margin-bottom: 0;
+}
+
+/* @end */
+
+/* @group Configure filter criteria */
+
+/* @todo the width and border info could be moved into a more generic class */
+/* @todo Make this a class to be used anywhere there's node types? */
+.form-type-checkboxes #edit-options-value,
+.form-type-checkboxes #edit-options-validate-options-node-types {
+ border-color: #CCCCCC;
+ border-style: solid;
+ border-width: 1px;
+ max-height: 210px;
+ overflow: auto;
+ padding: 5px 5px 0;
+ width: 190px;
+}
+
+/* @end */
+
+/* @group Rearrange filter criteria */
+
+#views-ui-rearrange-filter-form table {
+ border-collapse: collapse;
+}
+
+#views-ui-rearrange-filter-form tr td[rowspan] {
+ border-color: #CDCDCD;
+ border-style: solid;
+ border-width: 0 1px 1px 1px;
+}
+
+#views-ui-rearrange-filter-form tr[id^="views-row"] {
+ border-right: 1px solid #CDCDCD;
+}
+
+#views-ui-rearrange-filter-form tr[id^="views-row"].even td {
+ background-color: #F3F4ED;
+}
+
+#views-ui-rearrange-filter-form .views-group-title {
+ border-top: 1px solid #CDCDCD;
+}
+
+#views-ui-rearrange-filter-form .group-empty {
+ border-bottom: 1px solid #CDCDCD;
+}
+
+/* @end */
+
+/* @group Live preview elements */
+
+/**
+ * Create a horizontal rule above the live preview area.
+ */
+#views-live-preview {
+ margin: 0 12px;
+}
+
+/* Intentionally targeting h1 */
+#views-live-preview h1.section-title {
+ color: #818181;
+ display: inline-block;
+ font-size: 13px;
+ font-weight: normal;
+ line-height: 1.6154;
+ margin-bottom: 0;
+ margin-top: 0;
+}
+
+#views-live-preview .view > * {
+ margin-top: 18px;
+}
+
+#views-live-preview a,
+#views-live-preview a:link,
+#views-live-preview a:visited {
+ color: #000000;
+}
+
+#views-live-preview .preview-section {
+ border: 1px dashed #DEDEDE;
+ margin: 0 -5px;
+ padding: 3px 5px;
+}
+
+#views-live-preview li.views-row + li.views-row {
+ margin-top: 18px;
+}
+
+/* The div.views-row is intentional and excludes li.views-row, for example */
+#views-live-preview div.views-row + div.views-row {
+ margin-top: 36px;
+}
+
+/* @group Grid */
+
+#views-live-preview .views-view-grid th,
+#views-live-preview .views-view-grid td {
+ vertical-align: top;
+}
+
+/* @end */
+
+/* @group HTML list */
+
+#views-live-preview .view-content > .item-list > ul {
+ list-style-position: outside;
+ padding-left: 21px; /* LTR */
+}
+
+/* @end */
+
+/* @end */
+
+/* @group Add/edit argument form */
+
+#edit-options-default-action {
+ width: 300px;
+ float: left;
+}
+
+#edit-options-exception {
+ float: right;
+ width: 250px;
+ margin-top: 0pt;
+}
+
+#edit-options-argument-present .form-item {
+ margin-top: 10px;
+}
+
+#edit-options-exception .form-type-textfield, #edit-options-argument-present .form-type-textfield {
+ margin-top: 0;
+}
+
+/* @end */
diff --git a/docs/docs.php b/docs/docs.php
index 21912ac..e0c8917 100644
--- a/docs/docs.php
+++ b/docs/docs.php
@@ -309,7 +309,7 @@ function hook_views_default_views() {
$view->display = array();
$display = new views_display;
$display->id = 'default';
- $display->display_title = t('Defaults');
+ $display->display_title = t('Master');
$display->display_plugin = 'default';
$display->position = '1';
$display->display_options = array (
@@ -678,25 +678,12 @@ function hook_views_query_alter(&$view, &$query) {
* 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').
+ * Alter the rows that appear with a view preview, which include query and
+ * performance statistics. $rows is an associative array with two keys:
+ * - query: An array of rows suitable for theme('table'), containing information
+ * about the query and the display title and path.
+ * - statistics: An array of rows suitable for theme('table'), containing
+ * performance statistics.
*
* 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.
diff --git a/handlers/views_handler_area.inc b/handlers/views_handler_area.inc
index 191085f..fd82f46 100644
--- a/handlers/views_handler_area.inc
+++ b/handlers/views_handler_area.inc
@@ -85,7 +85,7 @@ class views_handler_area_broken extends views_handler_area {
}
function ensure_my_table() { /* No table to ensure! */ }
- function query() { /* No query to run */ }
+ function query($group_by = FALSE) { /* No query to run */ }
function render($empty = FALSE) { return ''; }
function options_form(&$form, &$form_state) {
$form['markup'] = array(
diff --git a/handlers/views_handler_area_view.inc b/handlers/views_handler_area_view.inc
new file mode 100644
index 0000000..d4f7cc7
--- /dev/null
+++ b/handlers/views_handler_area_view.inc
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Views area handlers. Insert a view inside of an area.
+ */
+class views_handler_area_view extends views_handler_area {
+
+ function option_definition() {
+ $options = parent::option_definition();
+
+ $options['view_to_insert'] = array('default' => '');
+ $options['inherit_arguments'] = array('default' => FALSE, 'boolean' => TRUE);
+ 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);
+ $views = views_get_all_views();
+ foreach ($views as $view->name => $view) {
+ // Exclude the current view
+ if ($view->name != $this->view->name) {
+ foreach ($view->display as $display_id => $display) {
+ $options[$view->name . ':' . $display->id] = t('View: @view Display: @display', array('@view' => $view->name, '@display' => $display->id));
+ }
+ }
+ }
+
+ $form['view_to_insert'] = array(
+ '#type' => 'select',
+ '#title' => t('View to insert'),
+ '#default_value' => $this->options['view_to_insert'],
+ '#description' => t('The view to insert into this area.'),
+ '#options' => $options
+ );
+
+ $form['inherit_arguments'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Inherit arguments'),
+ '#default_value' => $this->options['inherit_arguments'],
+ '#description' => t('If checked, this view will recive the same arguments that his parent.'),
+ );
+ }
+
+ /**
+ * Render the area
+ */
+ function render($empty = FALSE) {
+ if (!empty($this->options['view_to_insert'])) {
+ list($view_name, $view_display) = explode(':', $this->options['view_to_insert']);
+
+ $view = views_get_view($view_name);
+ if (empty($view)) {
+ return;
+ }
+ $view->set_display($view_display);
+
+ // Avoid recursion
+ $view->parent_views += $this->view->parent_views;
+ $view->parent_views[] = "$view_name:$view_display";
+
+ // Check if the view is part of the parent views of this view
+ $search = "$view_name:$view_display";
+ if (in_array($search, $this->view->parent_views)) {
+ drupal_set_message(t("Recursion detected in view @view display @display.", array('@view' => $view_name, '@display' => $view_display)), 'error');
+ }
+ else {
+ if (!empty($this->options['inherit_arguments']) && !empty($this->view->args)) {
+ return $view->preview($view_display, $this->view->args);
+ }
+ else {
+ return $view->preview($view_display);
+ }
+ }
+ }
+ return '';
+ }
+}
diff --git a/handlers/views_handler_argument.inc b/handlers/views_handler_argument.inc
index 58c8aca..aa1c016 100644
--- a/handlers/views_handler_argument.inc
+++ b/handlers/views_handler_argument.inc
@@ -47,6 +47,51 @@ class views_handler_argument extends views_handler {
function init(&$view, &$options) {
parent::init($view, $options);
+
+ // Compatibility: The new UI changed several settings.
+ if (!empty($options['wildcard']) && !isset($options['exception']['value'])) {
+ $this->options['exception']['value'] = $options['wildcard'];
+ }
+ if (!empty($options['wildcard_substitution']) && !isset($options['exception']['title'])) {
+ // Enable the checkbox if the title is filled in.
+ $this->options['exception']['title_enable'] = 1;
+ $this->options['exception']['title'] = $options['wildcard_substitution'];
+ }
+
+ if (!isset($options['summary']['sort_order']) && !empty($options['default_action']) && $options['default_action'] == 'summary asc') {
+ $this->options['default_action'] = 'summary';
+ $this->options['summary']['sort_order'] = 'asc';
+ $this->options['summary']['number_of_records'] = 0;
+ }
+ elseif (!isset($options['summary']['sort_order']) && !empty($options['default_action']) && $options['default_action'] == 'summary desc') {
+ $this->options['default_action'] = 'summary';
+ $this->options['summary']['sort_order'] = 'desc';
+ $this->options['summary']['number_of_records'] = 0;
+ }
+ elseif (!isset($options['summary']['sort_order']) && !empty($options['default_action']) && $options['default_action'] == 'summary asc by count') {
+ $this->options['default_action'] = 'summary';
+ $this->options['summary']['sort_order'] = 'asc';
+ $this->options['summary']['number_of_records'] = 1;
+ }
+ elseif (!isset($options['summary']['sort_order']) && !empty($options['default_action']) && $options['default_action'] == 'summary desc by count') {
+ $this->options['default_action'] = 'summary';
+ $this->options['summary']['sort_order'] = 'desc';
+ $this->options['summary']['number_of_records'] = 1;
+ }
+
+ if (!empty($options['title']) && !isset($options['title_enable'])) {
+ $this->options['title_enable'] = 1;
+ }
+ if (!empty($options['breadcrumb']) && !isset($options['breadcrumb_enable'])) {
+ $this->options['breadcrumb_enable'] = 1;
+ }
+
+ if (!empty($options['validate_type']) && !isset($options['validate']['type'])) {
+ $options['validate']['type'] = $options['validate_type'];
+ }
+ if (!empty($options['validate_fail']) && !isset($options['validate']['fail'])) {
+ $options['validate']['fail'] = $options['validate_fail'];
+ }
}
/**
@@ -68,16 +113,19 @@ class views_handler_argument extends views_handler {
return !empty($info['breadcrumb']);
}
- function is_wildcard($arg = NULL) {
+ function is_exception($arg = NULL) {
if (!isset($arg)) {
- $arg = $this->argument;
+ $arg = isset($this->argument) ? $this->argument : NULL;
}
-
- return !empty($this->options['wildcard']) && $this->options['wildcard'] === $arg;
+ return !empty($this->options['exception']['value']) && $this->options['exception']['value'] === $arg;
}
- function wildcard_title() {
- return $this->options['wildcard_substitution'];
+ function exception_title() {
+ // If title overriding is off for the exception, return the normal title.
+ if (empty($this->options['exception']['title_enable'])) {
+ return $this->get_title();
+ }
+ return $this->options['exception']['title'];
}
/**
@@ -87,7 +135,7 @@ class views_handler_argument extends views_handler {
*/
function needs_style_plugin() {
$info = $this->default_actions($this->options['default_action']);
- $validate_info = $this->default_actions($this->options['validate_fail']);
+ $validate_info = $this->default_actions($this->options['validate']['fail']);
return !empty($info['style plugin']) || !empty($validate_info['style plugin']);
}
@@ -95,85 +143,95 @@ class views_handler_argument extends views_handler {
$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['exception'] = array(
+ 'contains' => array(
+ 'value' => array('default' => 'all'),
+ 'title_enable' => array('default' => 0),
+ 'title' => array('default' => t('All'), 'translatable' => TRUE),
+ ),
+ );
+ $options['title_enable'] = array('default' => 0);
$options['title'] = array('default' => '', 'translatable' => TRUE);
+ $options['breadcrumb_enable'] = array('default' => 0);
$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['summary_options'] = array('default' => array(), 'export' => FALSE);
+ $options['summary'] = array(
+ 'contains' => array(
+ 'sort_order' => array('default' => 'asc'),
+ 'number_of_records' => array('default' => 0),
+ 'format' => array('default' => 'default_summary', 'export' => 'export_summary'),
+ ),
+ );
+ $options['specify_validation'] = array('default' => 0);
+ $options['validate'] = array(
+ 'contains' => array(
+ 'type' => array('default' => 'none', 'export' => 'export_validation'),
+ 'fail' => array('default' => 'not found'),
+ ),
+ );
$options['validate_options'] = array('default' => array(), 'export' => FALSE);
- $options['validate_fail'] = array('default' => 'not found');
return $options;
}
function options_form(&$form, &$form_state) {
parent::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['#pre_render'][] = 'views_ui_pre_render_move_argument_options';
- $form['clear_start'] = array(
- '#markup' => '<div class="clearfix">',
+ $form['no_argument'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('When the argument value is <em>NOT</em> in the URL'),
);
-
- $form['defaults_start'] = array(
- '#markup' => '<div class="views-left-50">',
+ // Everything in the fieldset is floated, so the last element needs to
+ // clear those floats.
+ $form['no_argument']['clearfix'] = array(
+ '#weight' => 1000,
+ '#markup' => '<div class="clearfix"></div>',
);
-
$form['default_action'] = array(
'#type' => 'radios',
- '#title' => t('Action to take if argument is not present'),
+ '#process' => array('views_ui_process_container_radios'),
'#default_value' => $this->options['default_action'],
+ '#fieldset' => 'no_argument',
);
- $form['defaults_stop'] = array(
- '#markup' => '</div>',
+ $form['exception'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Exceptions'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ '#fieldset' => 'no_argument',
);
-
- $form['wildcard'] = array(
- '#prefix' => '<div class="views-right-50">',
- // prefix and no suffix means these two items will be grouped together.
+ $form['exception']['value'] = array(
'#type' => 'textfield',
- '#title' => t('Wildcard'),
+ '#title' => t('Exception value'),
'#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"'),
+ '#default_value' => $this->options['exception']['value'],
+ '#description' => t('If this value is received, the argument will be ignored; i.e, "all values"'),
);
-
- $form['wildcard_substitution'] = array(
- '#suffix' => '</div>',
+ $form['exception']['title_enable'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Override title'),
+ '#default_value' => $this->options['exception']['title_enable'],
+ );
+ $form['exception']['title'] = array(
'#type' => 'textfield',
- '#title' => t('Wildcard title'),
+ '#title' => t('Override title'),
+ '#title_display' => 'invisible',
'#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>',
+ '#default_value' => $this->options['exception']['title'],
+ '#description' => t('Override the view and other argument titles. Use "%1" for the first argument, "%2" for the second, etc.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-exception-title-enable' => array('1'),
+ ),
);
$options = array();
+ $defaults = $this->default_actions();
$validate_options = array();
foreach ($defaults as $id => $info) {
$options[$id] = $info['title'];
@@ -184,18 +242,71 @@ class views_handler_argument extends views_handler {
$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['argument_present'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('When the argument <em>IS</em> in the URL or a default is provided'),
+ );
+ $form['title_enable'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Override title'),
+ '#default_value' => $this->options['title_enable'],
+ '#fieldset' => 'argument_present',
+ );
+ $form['title'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Provide title'),
+ '#title_display' => 'invisible',
+ '#default_value' => $this->options['title'],
+ '#description' => t('Override the view and other argument titles. Use "%1" for the first argument, "%2" for the second, etc.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-title-enable' => array('1'),
+ ),
+ '#fieldset' => 'argument_present',
);
- $form['validate_type'] = array(
+ $form['breadcrumb_enable'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Override breadcrumb'),
+ '#default_value' => $this->options['breadcrumb_enable'],
+ '#fieldset' => 'argument_present',
+ );
+ $form['breadcrumb'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Provide breadcrumb'),
+ '#title_display' => 'invisible',
+ '#default_value' => $this->options['breadcrumb'],
+ '#description' => t('Enter a breadcrumb name you would like to use. See "Title" for percent substitutions.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-breadcrumb-enable' => array('1'),
+ ),
+ '#fieldset' => 'argument_present',
+ );
+
+ $form['specify_validation'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Specify validation criteria'),
+ '#default_value' => $this->options['specify_validation'],
+ '#fieldset' => 'argument_present',
+ );
+
+ $form['validate'] = array(
+ '#type' => 'container',
+ '#fieldset' => 'argument_present',
+ );
+ // @todo The mockup wanted to use "Validate using" here, but it doesn't
+ // work well with many options (they'd need to be changed as well)
+ $form['validate']['type'] = array(
'#type' => 'select',
'#title' => t('Validator'),
- '#default_value' => $this->options['validate_type'],
+ '#default_value' => $this->options['validate']['type'],
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-specify-validation' => array('1'),
+ ),
);
$validate_types = array('none' => t('- Basic validation -'));
@@ -223,19 +334,21 @@ class views_handler_argument extends views_handler {
if ($valid) {
$plugin = $this->get_plugin('argument validator', $id);
if ($plugin) {
- if ($plugin->access() || $this->options['validate_type'] == $id) {
- $form['argument_validate'][$id] = array(
+ if ($plugin->access() || $this->options['validate']['type'] == $id) {
+ $form['validate']['options'][$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)
+ 'edit-options-specify-validation' => array('1'),
+ 'edit-options-validate-type' => array($id),
),
+ '#dependency_count' => 2,
'#id' => 'edit-options-validate-options-' . $id,
);
- $plugin->options_form($form['argument_validate'][$id], $form_state);
+ $plugin->options_form($form['validate']['options'][$id], $form_state);
$validate_types[$id] = $info['title'];
}
}
@@ -243,17 +356,18 @@ class views_handler_argument extends views_handler {
}
asort($validate_types);
- $form['validate_type']['#options'] = $validate_types;
+ $form['validate']['type']['#options'] = $validate_types;
- $form['validate_fail'] = array(
+ $form['validate']['fail'] = array(
'#type' => 'select',
'#title' => t('Action to take if argument does not validate'),
- '#default_value' => $this->options['validate_fail'],
+ '#default_value' => $this->options['validate']['fail'],
'#options' => $validate_options,
- );
-
- $form['validate_options_div_suffix'] = array(
- '#markup' => '</fieldset>',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-specify-validation' => array('1'),
+ ),
+ '#fieldset' => 'argument_present',
);
}
@@ -269,10 +383,17 @@ class views_handler_argument extends views_handler {
$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'];
+ // summary plugin
+ $summary_id = $form_state['values']['options']['summary']['format'];
+ $plugin = $this->get_plugin('style', $summary_id);
+ if ($plugin) {
+ $plugin->options_validate($form['summary']['options'][$summary_id], $form_state, $form_state['values']['options']['summary']['options'][$summary_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]);
+ $plugin->options_validate($form['validate']['options'][$default_id], $form_state, $form_state['values']['options']['validate']['options'][$validate_id]);
}
}
@@ -292,11 +413,21 @@ class views_handler_argument extends views_handler {
$form_state['values']['options']['default_argument_options'] = $options;
}
- $validate_id = $form_state['values']['options']['validate_type'];
+ // summary plugin
+ $summary_id = $form_state['values']['options']['summary']['format'];
+ $plugin = $this->get_plugin('style', $summary_id);
+ if ($plugin) {
+ $options = &$form_state['values']['options']['summary']['options'][$summary_id];
+ $plugin->options_submit($form['summary']['options'][$summary_id], $form_state, $options);
+ // Copy the now submitted options to their final resting place so they get saved.
+ $form_state['values']['options']['summary_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);
+ $options = &$form_state['values']['options']['validate']['options'][$validate_id];
+ $plugin->options_submit($form['validate']['options'][$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;
}
@@ -311,55 +442,34 @@ class views_handler_argument extends views_handler {
function default_actions($which = NULL) {
$defaults = array(
'ignore' => array(
- 'title' => t('Display all values'),
+ 'title' => t('Display all results for the specified field'),
'method' => 'default_ignore',
'breadcrumb' => TRUE, // generate a breadcrumb to here
),
+ 'default' => array(
+ 'title' => t('Provide default value'),
+ '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
+ ),
'not found' => array(
- 'title' => t('Hide view / Page not found (404)'),
+ 'title' => t('Show "Page not found"'),
'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'),
+ 'summary' => array(
+ 'title' => t('Display a summary'),
'method' => 'default_summary',
- 'method args' => array('asc', 'num_records'),
+ 'form method' => 'default_summary_form',
'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,
+ 'empty' => array(
+ 'title' => t('Display contents of "No results found"'),
+ 'method' => 'default_empty',
'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) {
@@ -380,25 +490,18 @@ class views_handler_argument extends views_handler {
$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',
+ '#type' => 'select',
'#id' => 'edit-options-default-argument-type',
- '#title' => t('Default argument type'),
+ '#title' => t('Type'),
'#default_value' => $this->options['default_argument_type'],
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array('radio:options[default_action]' => array('default')),
+ // Views custom key, moves this element to the appropriate container
+ // under the radio button.
+ '#argument_option' => 'default',
);
foreach ($plugins as $id => $info) {
@@ -408,6 +511,7 @@ class views_handler_argument extends views_handler {
$plugin = $this->get_plugin('argument default', $id);
if ($plugin) {
if ($plugin->access() || $this->options['default_argument_type'] == $id) {
+ $form['argument_default']['#argument_option'] = 'default';
$form['argument_default'][$id] = array(
'#prefix' => '<div id="edit-options-argument-default-options-' . $id . '-wrapper">',
'#suffix' => '</div>',
@@ -417,7 +521,7 @@ class views_handler_argument extends views_handler {
'#process' => array('ctools_dependent_process'),
'#dependency' => array(
'radio:options[default_action]' => array('default'),
- 'radio:options[default_argument_type]' => array($id)
+ 'edit-options-default-argument-type' => array($id)
),
'#dependency_count' => 2,
);
@@ -427,15 +531,81 @@ class views_handler_argument extends views_handler {
}
}
- $form['default_options_div_suffix'] = array(
- '#markup' => '</fieldset></div>',
- );
-
asort($options);
$form['default_argument_type']['#options'] = $options;
}
/**
+ * Provide a form for selecting further summary options when the
+ * default action is set to display one.
+ */
+ function default_summary_form(&$form, &$form_state) {
+ $style_plugins = views_fetch_plugin_data('style');
+ $summary_plugins = array();
+ $format_options = array();
+ foreach ($style_plugins as $key => $plugin) {
+ if ($plugin['type'] == 'summary') {
+ $summary_plugins[$key] = $plugin;
+ $format_options[$key] = $plugin['title'];
+ }
+ }
+
+ $form['summary'] = array(
+ // Views custom key, moves this element to the appropriate container
+ // under the radio button.
+ '#argument_option' => 'summary',
+ );
+ $form['summary']['sort_order'] = array(
+ '#type' => 'radios',
+ '#title' => t('Sort order'),
+ '#options' => array('asc' => t('Ascending'), 'desc' => t('Descending')),
+ '#default_value' => $this->options['summary']['sort_order'],
+ '#process' => array('form_process_radios', 'ctools_dependent_process'),
+ '#dependency' => array('radio:options[default_action]' => array('summary')),
+ );
+ $form['summary']['number_of_records'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Number of records'),
+ '#default_value' => $this->options['summary']['number_of_records'],
+ '#process' => array('form_process_checkbox', 'ctools_dependent_process'),
+ '#dependency' => array('radio:options[default_action]' => array('summary')),
+ );
+
+ $form['summary']['format'] = array(
+ '#type' => 'radios',
+ '#title' => t('Format'),
+ '#options' => $format_options,
+ '#default_value' => $this->options['summary']['format'],
+ '#process' => array('form_process_radios', 'ctools_dependent_process'),
+ '#dependency' => array('radio:options[default_action]' => array('summary')),
+ );
+
+ foreach ($summary_plugins as $id => $info) {
+ if (empty($info['uses options'])) {
+ continue;
+ }
+ $plugin = $this->get_plugin('style', $id);
+ if ($plugin) {
+ $form['summary']['options'][$id] = array(
+ '#prefix' => '<div id="edit-options-summary-options-' . $id . '-wrapper">',
+ '#suffix' => '</div>',
+ '#id' => 'edit-options-summary-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('summary'),
+ 'radio:options[summary][format]' => array($id),
+ ),
+ '#dependency_count' => 2,
+ );
+ $options[$id] = $info['title'];
+ $plugin->options_form($form['summary']['options'][$id], $form_state);
+ }
+ }
+ }
+
+ /**
* Handle the default action, which means our argument wasn't present.
*
* Override this method only with extreme care.
@@ -465,7 +635,7 @@ class views_handler_argument extends views_handler {
* How to act if validation failes
*/
function validate_fail() {
- $info = $this->default_actions($this->options['validate_fail']);
+ $info = $this->default_actions($this->options['validate']['fail']);
return $this->default_action($info);
}
/**
@@ -536,21 +706,22 @@ class views_handler_argument extends views_handler {
* If an argument was expected and was not given, in this case, display
* a summary query.
*/
- function default_summary($order, $by = NULL) {
+ function default_summary() {
$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'];
+ $this->view->plugin_name = $this->options['summary']['format'];
+ $this->view->style_options = $this->options['summary_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);
+ $by = $this->options['summary']['number_of_records'] ? 'num_records' : NULL;
+ $this->summary_sort($this->options['summary']['sort_order'], $by);
// Summaries have their own sorting and fields, so tell the View not
// to build these.
@@ -676,7 +847,7 @@ class views_handler_argument extends views_handler {
*
* The argument sent may be found at $this->argument.
*/
- function query() {
+ function query($group_by = FALSE) {
$this->ensure_my_table();
$this->query->add_where(0, "$this->table_alias.$this->real_field", $this->argument);
}
@@ -713,11 +884,11 @@ class views_handler_argument extends views_handler {
return $this->argument_validated;
}
- if ($this->is_wildcard($arg)) {
+ if ($this->is_exception($arg)) {
return $this->argument_validated = TRUE;
}
- if ($this->options['validate_type'] == 'none') {
+ if ($this->options['validate']['type'] == 'none') {
return $this->argument_validated = $this->validate_argument_basic($arg);
}
@@ -738,7 +909,7 @@ class views_handler_argument extends views_handler {
* then validation cannot actually fail.
*/
function validate_argument($arg) {
- $validate_info = $this->default_actions($this->options['validate_fail']);
+ $validate_info = $this->default_actions($this->options['validate']['fail']);
if (empty($validate_info['hard fail'])) {
return TRUE;
}
@@ -747,7 +918,7 @@ class views_handler_argument extends views_handler {
// 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']);
+ $validate_info = $this->default_actions($this->options['validate']['fail']);
if (empty($validate_info['hard fail'])) {
return TRUE;
}
@@ -822,34 +993,58 @@ class views_handler_argument extends views_handler {
}
/**
- * Special handling for the style export.
+ * Export handler for summary 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) {
+ function export_summary($indent, $prefix, $storage, $option, $definition, $parents) {
$output = '';
- $name = $storage[$option];
- $options = $storage['style_options'];
+ $name = $this->options['summary'][$option];
+ $options = $this->options['summary_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";
+ $output .= $indent . $prefix . "['summary']['$option'] = '$name';\n";
// Pass off to the plugin to export itself.
- $output .= $plugin->export_options($indent, $prefix . "['style_options']");
+ $output .= $plugin->export_options($indent, $prefix . "['summary_options']");
}
return $output;
}
/**
- * Special handling for the style export.
+ * Export handler for validation export.
*
- * Arguments can have styles for the summary view. This special export
- * handler makes sure this works properly.
+ * Arguments use validation plugins. This special export handler makes sure
+ * this works properly.
+ */
+ function export_validation($indent, $prefix, $storage, $option, $definition, $parents) {
+ $output = '';
+ $name = $this->options['validate'][$option];
+ $options = $this->options['validate_options'];
+
+ $plugin = views_get_plugin('argument validator', $name);
+ if ($plugin) {
+ $plugin->init($this->view, $this->display, $options);
+ // Write which plugin to use.
+ $output .= $indent . $prefix . "['validate']['$option'] = '$name';\n";
+
+ // Pass off to the plugin to export itself.
+ $output .= $plugin->export_options($indent, $prefix . "['validate_options']");
+ }
+
+ return $output;
+ }
+
+ /**
+ * Generic plugin export handler.
+ *
+ * Since style and validation plugins have their own export handlers, this
+ * one is currently only used for default argument plugins.
*/
function export_plugin($indent, $prefix, $storage, $option, $definition, $parents) {
$output = '';
@@ -857,10 +1052,7 @@ class views_handler_argument extends views_handler {
$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];
@@ -882,21 +1074,25 @@ class views_handler_argument extends views_handler {
$options = array();
switch ($type) {
case 'argument default':
- $plugin_name = 'default_argument_type';
+ $plugin_name = $this->options['default_argument_type'];
$options_name = 'default_argument_options';
break;
case 'argument validator':
- $plugin_name = 'validate_type';
+ $plugin_name = $this->options['validate']['type'];
$options_name = 'validate_options';
+ break;
+ case 'style':
+ $plugin_name = $this->options['summary']['format'];
+ $options_name = 'summary_options';
}
if (!$name) {
- $name = $this->options[$plugin_name];
+ $name = $plugin_name;
}
// we only fetch the options if we're fetching the plugin actually
// in use.
- if ($name == $this->options[$plugin_name]) {
+ if ($name == $plugin_name) {
$options = $this->options[$options_name];
}
@@ -919,7 +1115,7 @@ class views_handler_argument_broken extends views_handler_argument {
}
function ensure_my_table() { /* No table to ensure! */ }
- function query() { /* No query to run */ }
+ function query($group_by = FALSE) { /* 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>',
diff --git a/handlers/views_handler_argument_date.inc b/handlers/views_handler_argument_date.inc
index 5f29eb4..10a7939 100644
--- a/handlers/views_handler_argument_date.inc
+++ b/handlers/views_handler_argument_date.inc
@@ -61,6 +61,5 @@ class views_handler_argument_date extends views_handler_argument_formula {
}
return parent::get_default_argument($raw);
-
}
}
diff --git a/handlers/views_handler_argument_formula.inc b/handlers/views_handler_argument_formula.inc
index 8187807..c4287be 100644
--- a/handlers/views_handler_argument_formula.inc
+++ b/handlers/views_handler_argument_formula.inc
@@ -44,7 +44,7 @@ class views_handler_argument_formula extends views_handler_argument {
/**
* Build the query based upon the formula
*/
- function query() {
+ function query($group_by = FALSE) {
$this->ensure_my_table();
// Now that our table is secure, get our formula.
$placeholder = $this->placeholder();
diff --git a/handlers/views_handler_argument_many_to_one.inc b/handlers/views_handler_argument_many_to_one.inc
index 8025973..bed823c 100644
--- a/handlers/views_handler_argument_many_to_one.inc
+++ b/handlers/views_handler_argument_many_to_one.inc
@@ -7,7 +7,7 @@
* - 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
+ * - 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
@@ -46,6 +46,7 @@ class views_handler_argument_many_to_one extends views_handler_argument {
'#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']),
+ '#fieldset' => 'more',
);
}
@@ -54,12 +55,14 @@ class views_handler_argument_many_to_one extends views_handler_argument {
'#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']),
+ '#fieldset' => 'more',
);
$form['require_value'] = array(
'#type' => 'checkbox',
'#title' => t('Do not display items with no value in summary'),
'#default_value' => !empty($this->options['require_value']),
+ '#fieldset' => 'more',
);
$this->helper->options_form($form, $form_state);
@@ -73,7 +76,7 @@ class views_handler_argument_many_to_one extends views_handler_argument {
$this->helper->ensure_my_table();
}
- function query() {
+ function query($group_by = FALSE) {
$empty = FALSE;
if (isset($this->definition['zero is null']) && $this->definition['zero is null']) {
if (empty($this->argument)) {
@@ -166,5 +169,4 @@ class views_handler_argument_many_to_one extends views_handler_argument {
function title_query() {
return $this->value;
}
-}
-
+} \ No newline at end of file
diff --git a/handlers/views_handler_argument_null.inc b/handlers/views_handler_argument_null.inc
index 4010b84..5914031 100644
--- a/handlers/views_handler_argument_null.inc
+++ b/handlers/views_handler_argument_null.inc
@@ -20,10 +20,10 @@ class views_handler_argument_null extends views_handler_argument {
'#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.'),
+ '#fieldset' => 'more',
);
- unset($form['wildcard']);
- unset($form['wildcard_substitution']);
+ unset($form['exception']);
}
/**
@@ -55,5 +55,5 @@ class views_handler_argument_null extends views_handler_argument {
* Override the behavior of query() to prevent the query
* from being changed in any way.
*/
- function query() {}
+ function query($group_by = FALSE) {}
}
diff --git a/handlers/views_handler_argument_numeric.inc b/handlers/views_handler_argument_numeric.inc
index 709b447..b6bdb06 100644
--- a/handlers/views_handler_argument_numeric.inc
+++ b/handlers/views_handler_argument_numeric.inc
@@ -29,6 +29,7 @@ class views_handler_argument_numeric extends views_handler_argument {
'#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']),
+ '#fieldset' => 'more',
);
$form['not'] = array(
@@ -36,6 +37,7 @@ class views_handler_argument_numeric extends views_handler_argument {
'#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']),
+ '#fieldset' => 'more',
);
}
@@ -70,7 +72,7 @@ class views_handler_argument_numeric extends views_handler_argument {
return $this->value;
}
- function query() {
+ function query($group_by = FALSE) {
$this->ensure_my_table();
if (!empty($this->options['break_phrase'])) {
diff --git a/handlers/views_handler_argument_string.inc b/handlers/views_handler_argument_string.inc
index 417ecf9..b1406d5 100644
--- a/handlers/views_handler_argument_string.inc
+++ b/handlers/views_handler_argument_string.inc
@@ -44,6 +44,7 @@ class views_handler_argument_string extends views_handler_argument {
'#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'],
+ '#fieldset' => 'more',
);
$form['limit'] = array(
@@ -53,6 +54,7 @@ class views_handler_argument_string extends views_handler_argument {
'#default_value' => $this->options['limit'],
'#process' => array('ctools_dependent_process'),
'#dependency' => array('edit-options-glossary' => array(TRUE)),
+ '#fieldset' => 'more',
);
$form['case'] = array(
@@ -67,6 +69,7 @@ class views_handler_argument_string extends views_handler_argument {
'ucwords' => t('Capitalize each word'),
),
'#default_value' => $this->options['case'],
+ '#fieldset' => 'more',
);
$form['path_case'] = array(
@@ -81,12 +84,14 @@ class views_handler_argument_string extends views_handler_argument {
'ucwords' => t('Capitalize each word'),
),
'#default_value' => $this->options['path_case'],
+ '#fieldset' => 'more',
);
$form['transform_dash'] = array(
'#type' => 'checkbox',
'#title' => t('Transform spaces to dashes in URL'),
'#default_value' => $this->options['transform_dash'],
+ '#fieldset' => 'more',
);
if (!empty($this->definition['many to one'])) {
@@ -95,21 +100,24 @@ class views_handler_argument_string extends views_handler_argument {
'#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']),
+ '#fieldset' => 'more',
);
$form['require_value'] = array(
'#type' => 'checkbox',
'#title' => t('Do not display items with no value in summary'),
'#default_value' => !empty($this->options['require_value']),
+ '#fieldset' => 'more',
);
}
-
+
// 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']),
+ '#fieldset' => 'more',
);
}
@@ -159,7 +167,7 @@ class views_handler_argument_string extends views_handler_argument {
/**
* Build the query based upon the formula
*/
- function query() {
+ function query($group_by = FALSE) {
$argument = $this->argument;
if (!empty($this->options['transform_dash'])) {
$argument = strtr($argument, '-', ' ');
@@ -276,7 +284,7 @@ class views_handler_argument_string extends views_handler_argument {
return implode($this->operator == 'or' ? ' + ' : ', ', $this->title_query());
}
-
+
/**
* Override for specific title lookups.
*/
@@ -288,5 +296,4 @@ class views_handler_argument_string extends views_handler_argument {
return $this->case_transform(parent::summary_name($data), 'case');
}
-}
-
+} \ No newline at end of file
diff --git a/handlers/views_handler_field.inc b/handlers/views_handler_field.inc
index fb5afcf..53fff20 100644
--- a/handlers/views_handler_field.inc
+++ b/handlers/views_handler_field.inc
@@ -340,38 +340,77 @@ class views_handler_field extends views_handler {
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
- // Use prefix and suffix to fake a fieldset because we use #tree.
- $form['style_prefix'] = array(
- '#markup' => '<fieldset class="form-wrapper" id="views-validator-options"><legend><span class="fieldset-legend">' . t('Style settings') . '</span></legend>',
- );
-
- $form['exclude'] = array(
+ $form['element_type_enable'] = 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, or when you want to use this field as a token in other fields.'),
+ '#title' => t('Wrap field in HTML'),
+ '#fieldset' => 'style_settings',
);
-
$form['element_type'] = array(
'#title' => t('HTML element'),
'#options' => $this->get_elements(),
'#type' => 'select',
'#default_value' => $this->options['element_type'],
- '#description' => t('Most styles provide wrappers for fields. If the chosen style supports wrappers, wrap the field in this HTML element. The default will usually be either DIV or SPAN.'),
+ '#description' => t('Choose the HTML element to wrap around this field, e.g. H1, H2, etc.'),
+ '#fieldset' => 'style_settings',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-element-type-enable' => array(1)
+ ),
+ );
+
+ $form['element_class_enable'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Create a CSS class'),
+ '#fieldset' => 'style_settings',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-element-type-enable' => array(1)
+ ),
);
$form['element_class'] = array(
- '#title' => t('Element class'),
- '#description' => t('The class to provide on the wrapper element. You may enter data from this view as per the "Replacement patterns" used in "Rewrite the output of this field".'),
+ '#title' => t('CSS class'),
+ '#description' => t('Provide a CSS class to...'),
'#type' => 'textfield',
'#default_value' => $this->options['element_class'],
+ '#fieldset' => 'style_settings',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-element-class-enable' => array(1)
+ ),
+ );
+
+ $form['custom_label'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Create a label'),
+ '#description' => t('Enable to create a custom label for this field.'),
+ '#default_value' => (bool) ($this->definition['title'] !== $this->label()),
);
$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.'),
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-custom-label' => array(1)
+ ),
+ );
+
+ $form['element_label_colon'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Place a colon after the label'),
+ '#default_value' => $this->options['element_label_colon'],
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-custom-label' => array(1)
+ ),
+ );
+
+ $form['element_label_type_enable'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Wrap label in HTML'),
+ '#fieldset' => 'style_settings',
);
$form['element_label_type'] = array(
@@ -379,21 +418,40 @@ class views_handler_field extends views_handler {
'#options' => $this->get_elements(FALSE),
'#type' => 'select',
'#default_value' => $this->options['element_label_type'],
- '#description' => t('What HTML Element type to use to wrap the label.'),
+ '#description' => t('Choose the HTML element to wrap around this label, e.g. H1, H2, etc.'),
+ '#fieldset' => 'style_settings',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-element-label-type-enable' => array(1)
+ ),
+ );
+
+ $form['element_label_class_enable'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Create a CSS class'),
+ '#fieldset' => 'style_settings',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-element-label-type-enable' => array(1)
+ ),
);
$form['element_label_class'] = array(
- '#title' => t('Label class'),
- '#description' => t('The class to provide on the label wrapper element.'),
+ '#title' => t('CSS class'),
+ '#description' => t('Provide a CSS class to...'),
'#type' => 'textfield',
'#default_value' => $this->options['element_label_class'],
+ '#fieldset' => 'style_settings',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-element-label-class-enable' => array(1)
+ ),
);
- $form['element_label_colon'] = array(
+ $form['element_wrapper_type_enable'] = array(
'#type' => 'checkbox',
- '#title' => t('Place a colon after the label'),
- '#default_value' => $this->options['element_label_colon'],
- '#description' => t('If the label is to be inline with the value, place a colon between them. Not valid for styles such as table where the label is not placed with the value.'),
+ '#title' => t('Wrap field and label in HTML'),
+ '#fieldset' => 'style_settings',
);
$form['element_wrapper_type'] = array(
@@ -401,14 +459,34 @@ class views_handler_field extends views_handler {
'#options' => $this->get_elements(FALSE),
'#type' => 'select',
'#default_value' => $this->options['element_wrapper_type'],
- '#description' => t('What HTML Element type to use to wrap the field (and the label). This is not supported by some styles such as tables.'),
+ '#description' => t('Choose the HTML element to wrap around this field and label, e.g. H1, H2, etc.'),
+ '#fieldset' => 'style_settings',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-element-wrapper-type-enable' => array(1)
+ ),
+ );
+
+ $form['element_wrapper_class_enable'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Create a CSS class'),
+ '#fieldset' => 'style_settings',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-element-wrapper-type-enable' => array(1)
+ ),
);
$form['element_wrapper_class'] = array(
- '#title' => t('Wrapper class'),
- '#description' => t('The class to provide on the wrapper element. Separate multiple classes with a space.'),
+ '#title' => t('CSS class'),
+ '#description' => t('Provide a CSS class to...'),
'#type' => 'textfield',
'#default_value' => $this->options['element_wrapper_class'],
+ '#fieldset' => 'style_settings',
+ '#process' => array('ctools_dependent_process'),
+ '#dependency' => array(
+ 'edit-options-element-wrapper-class-enable' => array(1)
+ ),
);
$form['element_default_classes'] = array(
@@ -416,15 +494,28 @@ class views_handler_field extends views_handler {
'#title' => t('Add default classes'),
'#default_value' => $this->options['element_default_classes'],
'#description' => t('Use default Views classes to identify the field, field label and field content.'),
+ '#fieldset' => 'style_settings',
);
- $form['style_suffix'] = array(
- '#markup' => '</fieldset>',
+ $form['exclude'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Exclude from display'),
+ '#default_value' => $this->options['exclude'],
+ '#description' => t('Enable to load this field as hidden. Often used to group fields, or to use as token in another field.'),
+ );
+
+ $form['style_settings'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Style settings'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
);
$form['alter'] = array(
- '#title' => t('Rewriting'),
+ '#title' => t('Rewrite results'),
'#type' => 'fieldset',
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
);
if ($this->allow_advanced_render()) {
@@ -432,7 +523,7 @@ class views_handler_field extends views_handler {
$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.'),
+ '#description' => t('Enable to override the output of this field with custom text or replacement tokens.'),
'#default_value' => $this->options['alter']['alter_text'],
);
@@ -601,7 +692,7 @@ If you would like to have the characters %5B and %5D please use the html entity
$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.'),
+ '#description' => t('Enable to trim the field to a maximum length of characters'),
'#default_value' => $this->options['alter']['trim'],
);
@@ -676,36 +767,36 @@ If you would like to have the characters %5B and %5D please use the html entity
);
}
- // Use prefix and suffix to fake a fieldset because we use #tree.
- $form['empty_prefix'] = array(
- '#markup' => '<fieldset class="form-wrapper" id="views-validator-options"><legend><span class="fieldset-legend">' . t('Empty field behavior') . '</span></legend>',
+ $form['empty_field_behavior'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('No results behavior'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
);
$form['empty'] = array(
'#type' => 'textfield',
- '#title' => t('Empty text'),
+ '#title' => t('No results text'),
'#default_value' => $this->options['empty'],
- '#description' => t('If the field is empty, display this text instead.'),
+ '#description' => t('Provide text to display if this field returns no results.'),
+ '#fieldset' => 'empty_field_behavior',
);
$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'),
+ '#description' => t('Enable to display the "no results text" if the field contains the number 0.'),
+ '#fieldset' => 'empty_field_behavior',
);
$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.'),
+ '#description' => t('Enable to hide 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.'),
+ '#fieldset' => 'empty_field_behavior',
);
-
- $form['empty_suffix'] = array(
- '#markup' => '</fieldset>',
- );
-
}
/**
@@ -1100,7 +1191,7 @@ class views_handler_field_broken extends views_handler_field {
}
function ensure_my_table() { /* No table to ensure! */ }
- function query() { /* No query to run */ }
+ function query($group_by = FALSE) { /* 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>',
diff --git a/handlers/views_handler_field_boolean.inc b/handlers/views_handler_field_boolean.inc
index f40ca5a..a9701a0 100644
--- a/handlers/views_handler_field_boolean.inc
+++ b/handlers/views_handler_field_boolean.inc
@@ -38,7 +38,6 @@ class views_handler_field_boolean extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
foreach ($this->formats as $key => $item) {
$options[$key] = implode('/', $item);
}
@@ -55,6 +54,7 @@ class views_handler_field_boolean extends views_handler_field {
'#description' => t('If checked, true will be displayed as false.'),
'#default_value' => $this->options['not'],
);
+ parent::options_form($form, $form_state);
}
function render($values) {
diff --git a/handlers/views_handler_field_counter.inc b/handlers/views_handler_field_counter.inc
index 28653b2..720a973 100644
--- a/handlers/views_handler_field_counter.inc
+++ b/handlers/views_handler_field_counter.inc
@@ -8,8 +8,6 @@ class views_handler_field_counter extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
-
$form['counter_start'] = array(
'#type' => 'textfield',
'#title' => t('Starting value'),
@@ -18,6 +16,8 @@ class views_handler_field_counter extends views_handler_field {
//'#process' => array('ctools_dependent_process'),
'#size' => 2,
);
+
+ parent::options_form($form, $form_state);
}
function query() {
diff --git a/handlers/views_handler_field_custom.inc b/handlers/views_handler_field_custom.inc
index 3f4a6de..0f482e9 100644
--- a/handlers/views_handler_field_custom.inc
+++ b/handlers/views_handler_field_custom.inc
@@ -25,6 +25,7 @@ class views_handler_field_custom extends views_handler_field {
unset($form['alter']['alter_text']);
unset($form['alter']['text']['#dependency']);
unset($form['alter']['text']['#process']);
+ $form['#pre_render'][] = 'views_handler_field_custom_pre_render_move_text';
}
function render($values) {
@@ -32,3 +33,13 @@ class views_handler_field_custom extends views_handler_field {
return '';
}
}
+
+/**
+ * Prerender function to move the textarea to the top.
+ */
+function views_handler_field_custom_pre_render_move_text($form) {
+ $form['text'] = $form['alter']['text'];
+ unset($form['alter']['text']);
+
+ return $form;
+} \ No newline at end of file
diff --git a/handlers/views_handler_field_date.inc b/handlers/views_handler_field_date.inc
index be5aeff..706a80d 100644
--- a/handlers/views_handler_field_date.inc
+++ b/handlers/views_handler_field_date.inc
@@ -15,8 +15,6 @@ class views_handler_field_date extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
-
$form['date_format'] = array(
'#type' => 'select',
'#title' => t('Date format'),
@@ -43,6 +41,8 @@ class views_handler_field_date extends views_handler_field {
'#process' => array('ctools_dependent_process'),
'#dependency' => array('edit-options-date-format' => array('custom', 'raw time ago', 'time ago', 'raw time span', 'time span', 'raw time span', 'inverse time span', 'time span')),
);
+
+ parent::options_form($form, $form_state);
}
function render($values) {
diff --git a/handlers/views_handler_field_numeric.inc b/handlers/views_handler_field_numeric.inc
index 698ec87..22c3425 100644
--- a/handlers/views_handler_field_numeric.inc
+++ b/handlers/views_handler_field_numeric.inc
@@ -26,8 +26,6 @@ class views_handler_field_numeric extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
-
if (!empty($this->definition['float'])) {
$form['set_precision'] = array(
'#type' => 'checkbox',
@@ -93,6 +91,8 @@ class views_handler_field_numeric extends views_handler_field {
'#default_value' => $this->options['suffix'],
'#description' => t('Text to put after the number, such as currency symbol.'),
);
+
+ parent::options_form($form, $form_state);
}
function render($values) {
diff --git a/handlers/views_handler_field_prerender_list.inc b/handlers/views_handler_field_prerender_list.inc
index 5b9d68b..7f6371d 100644
--- a/handlers/views_handler_field_prerender_list.inc
+++ b/handlers/views_handler_field_prerender_list.inc
@@ -21,7 +21,6 @@ class views_handler_field_prerender_list extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['type'] = array(
'#type' => 'radios',
'#title' => t('Display type'),
@@ -40,6 +39,7 @@ class views_handler_field_prerender_list extends views_handler_field {
'#process' => array('ctools_dependent_process'),
'#dependency' => array('radio:options[type]' => array('separator')),
);
+ parent::options_form($form, $form_state);
}
/**
diff --git a/handlers/views_handler_field_url.inc b/handlers/views_handler_field_url.inc
index 2eb765b..719e692 100644
--- a/handlers/views_handler_field_url.inc
+++ b/handlers/views_handler_field_url.inc
@@ -18,12 +18,12 @@ class views_handler_field_url extends views_handler_field {
* 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']),
);
+ parent::options_form($form, $form_state);
}
function render($values) {
diff --git a/handlers/views_handler_filter.inc b/handlers/views_handler_filter.inc
index fd0f68f..3000e97 100644
--- a/handlers/views_handler_filter.inc
+++ b/handlers/views_handler_filter.inc
@@ -12,11 +12,11 @@
* You can set some specific behavior by setting up the following flags on
* your custom class.
*
- * - no_single:
+ * - always_multiple:
* Disable the possibility to force a single value.
* - no_operator:
* Disable the possibility to use operators.
- * - no_optional:
+ * - always_required:
* Disable the possibility to allow a exposed input to be optional.
*/
@@ -36,9 +36,20 @@ class views_handler_filter extends views_handler {
$this->operator = $this->options['operator'];
$this->value = $this->options['value'];
+ // Compatibility: The new UI changed several settings.
+ if (!empty($options['exposed']) && !empty($options['expose']['optional']) && !isset($options['expose']['required'])) {
+ $this->options['expose']['required'] = !$options['expose']['optional'];
+ }
+ if (!empty($options['exposed']) && !empty($options['expose']['single']) && !isset($options['expose']['multiple'])) {
+ $this->options['expose']['multiple'] = !$options['expose']['single'];
+ }
+ if (!empty($options['exposed']) && !empty($options['expose']['operator']) && !isset($options['expose']['operator_id'])) {
+ $this->options['expose']['operator_id'] = $options['expose']['operator_id'] = $options['expose']['operator'];
+ }
+
// 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'])) {
+ if (!empty($options['exposed']) && !empty($options['expose']['operator_id']) && !isset($options['expose']['use_operator'])) {
$this->options['expose']['use_operator'] = TRUE;
}
@@ -59,14 +70,14 @@ class views_handler_filter extends views_handler {
$options['exposed'] = array('default' => FALSE);
$options['expose'] = array(
'contains' => array(
- 'operator' => array('default' => FALSE),
+ 'operator_id' => array('default' => FALSE),
'label' => array('default' => '', 'translatable' => TRUE),
'use_operator' => array('default' => 0),
'operator' => array('default' => ''),
'identifier' => array('default' => ''),
- 'optional' => array('default' => 1),
+ 'required' => array('default' => 0),
'remember' => array('default' => 0),
- 'single' => array('default' => 1),
+ 'multiple' => array('default' => 0),
),
);
@@ -96,10 +107,8 @@ class views_handler_filter extends views_handler {
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);
}
@@ -114,7 +123,6 @@ class views_handler_filter extends views_handler {
if (!empty($this->options['exposed'])) {
$this->expose_validate($form, $form_state);
}
-
}
/**
@@ -204,19 +212,78 @@ class views_handler_filter extends views_handler {
function value_submit($form, &$form_state) { }
/**
- * Handle the 'left' side fo the exposed options form.
+ * Shortcut to display the expose/hide button.
*/
- function expose_form_left(&$form, &$form_state) {
+ function show_expose_button(&$form, &$form_state) {
+ $form['expose_button'] = array(
+ '#prefix' => '<div class="views-expose clearfix">',
+ '#suffix' => '</div>',
+ // Should always come first
+ '#weight' => -1000,
+ );
+ if (empty($this->options['exposed'])) {
+ $form['expose_button']['markup'] = array(
+ '#markup' => '<div class="description exposed-description">' . t('This filter is not exposed. Expose it to allow the users to change it.') . '</div>',
+ );
+ $form['expose_button']['button'] = array(
+ '#limit_validation_errors' => array(),
+ '#type' => 'submit',
+ '#value' => t('Expose filter'),
+ '#submit' => array('views_ui_config_item_form_expose'),
+ );
+ }
+ else {
+ $form['expose_button']['markup'] = array(
+ '#markup' => '<div class="description exposed-description">' . t('This filter is exposed. If you hide it, users will not be able to change it.') . '</div>',
+ );
+ $form['expose_button']['button'] = array(
+ '#limit_validation_errors' => array(),
+ '#type' => 'submit',
+ '#value' => t('Hide filter'),
+ '#submit' => array('views_ui_config_item_form_expose'),
+ );
+ }
+ }
+
+ function expose_form(&$form, &$form_state) {
+ $form['#theme'] = 'views_ui_expose_filter_form';
+ // #flatten will move everything from $form['expose'][$key] to $form[$key]
+ // prior to rendering. That's why the pre_render for it needs to run first,
+ // so that when the next pre_render (the one for fieldsets) runs, it gets
+ // the flattened data.
+ array_unshift($form['#pre_render'], 'views_ui_pre_render_flatten_data');
+ $form['expose']['#flatten'] = TRUE;
+
+ if (empty($this->always_required)) {
+ $form['expose']['required'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Required'),
+ '#default_value' => $this->options['expose']['required'],
+ );
+ }
+ $form['expose']['label'] = array(
+ '#type' => 'textfield',
+ '#default_value' => $this->options['expose']['label'],
+ '#title' => t('Label'),
+ '#size' => 40,
+ );
+
if (!empty($form['operator']['#type'])) {
+ // Increase the width of the left (operator) column.
+ $form['operator']['#prefix'] = '<div class="views-left-40">';
+ $form['operator']['#suffix'] = '</div>';
+ $form['value']['#prefix'] = '<div class="views-right-60">';
+ $form['value']['#suffix'] = '</div>';
+
$form['expose']['use_operator'] = array(
'#type' => 'checkbox',
- '#title' => t('Unlock operator'),
- '#description' => t('When checked, the operator will be exposed to the user'),
+ '#title' => t('Expose operator'),
+ '#description' => t('Allow the user to choose the operator.'),
'#default_value' => !empty($this->options['expose']['use_operator']),
);
- $form['expose']['operator'] = array(
+ $form['expose']['operator_id'] = array(
'#type' => 'textfield',
- '#default_value' => $this->options['expose']['operator'],
+ '#default_value' => $this->options['expose']['operator_id'],
'#title' => t('Operator identifier'),
'#size' => 40,
'#description' => t('This will appear in the URL after the ? to identify this operator.'),
@@ -224,56 +291,39 @@ class views_handler_filter extends views_handler {
'#dependency' => array(
'edit-options-expose-use-operator' => array(1)
),
+ '#fieldset' => 'more',
);
}
else {
- $form['expose']['operator'] = array(
+ $form['expose']['operator_id'] = 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) {
- if (empty($this->no_optional)) {
- $form['expose']['optional'] = array(
+ if (empty($this->always_multiple)) {
+ $form['expose']['multiple'] = 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'],
+ '#title' => t('Allow multiple selections'),
+ '#description' => t('Enable to allow users to select multiple items.'),
+ '#default_value' => $this->options['expose']['multiple'],
);
}
$form['expose']['remember'] = array(
'#type' => 'checkbox',
- '#title' => t('Remember'),
- '#description' => t('Remember the last setting the user gave this filter.'),
+ '#title' => t('Remember the last selection'),
+ '#description' => t('Enable to remember the last selection made by the user.'),
'#default_value' => $this->options['expose']['remember'],
);
+
+ $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.'),
+ '#fieldset' => 'more',
+ );
}
/**
@@ -303,8 +353,8 @@ class views_handler_filter extends views_handler {
'identifier' => $this->options['id'],
'label' => $this->ui_name(),
'remember' => FALSE,
- 'single' => TRUE,
- 'optional' => TRUE,
+ 'multiple' => FALSE,
+ 'required' => FALSE,
);
}
@@ -319,8 +369,8 @@ class views_handler_filter extends views_handler {
}
// 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'];
+ if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id'])) {
+ $operator = $this->options['expose']['operator_id'];
$this->operator_form($form, $form_state);
$form[$operator] = $form['operator'];
@@ -373,19 +423,19 @@ class views_handler_filter extends views_handler {
}
// 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'])) {
+ if (empty($form['#no_convert']) || empty($this->options['expose']['multiple'])) {
$form['#type'] = 'select';
}
- if (empty($this->options['expose']['single'])) {
+ if (!empty($this->options['expose']['multiple'])) {
$form['#multiple'] = TRUE;
}
}
- if (!empty($this->options['expose']['single']) && isset($form['#multiple'])) {
+ if (empty($this->options['expose']['multiple']) && isset($form['#multiple'])) {
unset($form['#multiple']);
$form['#size'] = NULL;
}
- if ($type == 'value' && empty($this->no_optional) && !empty($this->options['expose']['optional']) && $form['#type'] == 'select' && empty($form['#multiple'])) {
+ if ($type == 'value' && empty($this->always_required) && empty($this->options['expose']['required']) && $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';
@@ -408,7 +458,7 @@ class views_handler_filter extends views_handler {
}
return array(
- 'operator' => $this->options['expose']['operator'],
+ 'operator' => $this->options['expose']['operator_id'],
'value' => $this->options['expose']['identifier'],
'label' => $this->options['expose']['label'],
);
@@ -424,16 +474,15 @@ class views_handler_filter extends views_handler {
}
- 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']['use_operator']) && !empty($this->options['expose']['operator_id']) && isset($input[$this->options['expose']['operator_id']])) {
+ $this->operator = $input[$this->options['expose']['operator_id']];
}
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->no_optional) && !empty($this->options['expose']['optional'])) {
-
+ // Various ways to check for the absence of non-required input.
+ if (empty($this->always_required) && empty($this->options['expose']['required'])) {
if (($this->operator == 'empty' || $this->operator == 'not empty') && $value === '') {
$value = ' ';
}
@@ -444,7 +493,7 @@ class views_handler_filter extends views_handler {
}
}
- if (!empty($this->no_single) && $value === '') {
+ if (!empty($this->always_multiple) && $value === '') {
return FALSE;
}
}
@@ -452,7 +501,7 @@ class views_handler_filter extends views_handler {
if (isset($value)) {
$this->value = $value;
- if (empty($this->no_single) && !empty($this->options['expose']['single'])) {
+ if (empty($this->always_multiple) && empty($this->options['expose']['multiple'])) {
$this->value = array($value);
}
}
@@ -478,14 +527,14 @@ class views_handler_filter extends views_handler {
$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']);
+ $operator = !empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id']);
// 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 ($operator && isset($session[$this->options['expose']['operator_id']])) {
+ unset($session[$this->options['expose']['operator_id']]);
}
if (isset($session[$this->options['expose']['identifier']])) {
@@ -500,8 +549,8 @@ class views_handler_filter extends views_handler {
$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']];
+ if ($operator && isset($input[$this->options['expose']['operator_id']])) {
+ $session[$this->options['expose']['operator_id']] = $input[$this->options['expose']['operator_id']];
}
$session[$this->options['expose']['identifier']] = $input[$this->options['expose']['identifier']];
@@ -543,7 +592,7 @@ class views_handler_filter_broken extends views_handler_filter {
}
function ensure_my_table() { /* No table to ensure! */ }
- function query() { /* No query to run */ }
+ function query($group_by = FALSE) { /* 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>',
diff --git a/handlers/views_handler_filter_boolean_operator.inc b/handlers/views_handler_filter_boolean_operator.inc
index f62bd37..f35d2e2 100644
--- a/handlers/views_handler_filter_boolean_operator.inc
+++ b/handlers/views_handler_filter_boolean_operator.inc
@@ -12,7 +12,7 @@
*/
class views_handler_filter_boolean_operator extends views_handler_filter {
// exposed filter options
- var $no_single = TRUE;
+ var $always_multiple = 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
@@ -98,7 +98,7 @@ class views_handler_filter_boolean_operator extends views_handler_filter {
$form_state['input'][$identifier] = $this->value;
}
// If we're configuring an exposed filter, add an <Any> option.
- if (empty($form_state['exposed']) || !empty($this->options['optional'])) {
+ if (empty($form_state['exposed']) || empty($this->options['required'])) {
$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);
@@ -109,8 +109,8 @@ class views_handler_filter_boolean_operator extends views_handler_filter {
}
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.'));
+ if ($form_state['values']['options']['value'] == 'All' && !empty($form_state['values']['options']['expose']['required'])) {
+ form_set_error('value', t('You must select a value unless this is an non-required exposed filter.'));
}
}
@@ -130,9 +130,9 @@ class views_handler_filter_boolean_operator extends views_handler_filter {
function expose_options() {
parent::expose_options();
- $this->options['expose']['operator'] = '';
+ $this->options['expose']['operator_id'] = '';
$this->options['expose']['label'] = $this->value_value;
- $this->options['expose']['optional'] = FALSE;
+ $this->options['expose']['required'] = TRUE;
}
function query() {
diff --git a/handlers/views_handler_filter_date.inc b/handlers/views_handler_filter_date.inc
index be9d97c..e519b68 100644
--- a/handlers/views_handler_filter_date.inc
+++ b/handlers/views_handler_filter_date.inc
@@ -34,8 +34,8 @@ class views_handler_filter_date extends views_handler_filter_numeric {
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.
+ if (!empty($form_state['values']['options']['expose']['required'])) {
+ // Who cares what the value is if it's exposed and non-required.
return;
}
@@ -47,14 +47,14 @@ class views_handler_filter_date extends views_handler_filter_numeric {
return;
}
- if (!empty($this->options['expose']['optional'])) {
- // Who cares what the value is if it's exposed and optional.
+ if (empty($this->options['expose']['required'])) {
+ // Who cares what the value is if it's exposed and non-required.
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']];
+ if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id'])) {
+ $operator = $form_state['values'][$this->options['expose']['operator_id']];
}
else {
$operator = $this->operator;
@@ -99,8 +99,8 @@ class views_handler_filter_date extends views_handler_filter_numeric {
// 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']];
+ if (!empty($this->options['expose']['use_operator']) && !empty($this->options['expose']['operator_id'])) {
+ $operator = $input[$this->options['expose']['operator_id']];
}
else {
$operator = $this->operator;
@@ -140,7 +140,8 @@ class views_handler_filter_date extends views_handler_filter_numeric {
// have a string if using offset.
$placeholder1 = $this->placeholder();
$placeholder2 = $this->placeholder();
- $this->query->add_where_expression($this->options['group'], "$field BETWEEN $placeholder1 AND $placeholder2", array($placeholder1 => $a, $placeholder2 => $b));
+ $operator = strtoupper($this->operator);
+ $this->query->add_where_expression($this->options['group'], "$field $operator $placeholder1 AND $placeholder2", array($placeholder1 => $a, $placeholder2 => $b));
}
function op_simple($field) {
diff --git a/handlers/views_handler_filter_equality.inc b/handlers/views_handler_filter_equality.inc
index 95ccaba..d0a9f07 100644
--- a/handlers/views_handler_filter_equality.inc
+++ b/handlers/views_handler_filter_equality.inc
@@ -4,7 +4,7 @@
*/
class views_handler_filter_equality extends views_handler_filter {
// exposed filter options
- var $no_single = TRUE;
+ var $always_multiple = TRUE;
/**
* Provide simple equality operator
@@ -34,5 +34,4 @@ class views_handler_filter_equality extends views_handler_filter {
}
}
}
-}
-
+} \ No newline at end of file
diff --git a/handlers/views_handler_filter_in_operator.inc b/handlers/views_handler_filter_in_operator.inc
index 4faa13d..a007300 100644
--- a/handlers/views_handler_filter_in_operator.inc
+++ b/handlers/views_handler_filter_in_operator.inc
@@ -48,8 +48,8 @@ class views_handler_filter_in_operator extends views_handler_filter {
$this->options['expose']['reduce'] = FALSE;
}
- function expose_form_right(&$form, &$form_state) {
- parent::expose_form_right($form, $form_state);
+ function expose_form(&$form, &$form_state) {
+ parent::expose_form($form, $form_state);
$form['expose']['reduce'] = array(
'#type' => 'checkbox',
'#title' => t('Limit list to selected items'),
@@ -136,9 +136,15 @@ class views_handler_filter_in_operator extends views_handler_filter {
function value_form(&$form, &$form_state) {
$form['value'] = array();
+ $options = array();
+
+ if (empty($form_state['exposed'])) {
+ // Add a select all option to the value form.
+ $options = array('all' => t('Select all'));
+ }
$this->get_value_options();
- $options = $this->value_options;
+ $options += $this->value_options;
$default_value = (array) $this->value;
$which = 'all';
@@ -148,24 +154,24 @@ class views_handler_filter_in_operator extends views_handler_filter {
if (!empty($form_state['exposed'])) {
$identifier = $this->options['expose']['identifier'];
- if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
+ if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
// exposed and locked.
$which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
}
else {
- $source = 'edit-' . drupal_html_id($this->options['expose']['operator']);
+ $source = 'edit-' . drupal_html_id($this->options['expose']['operator_id']);
}
if (!empty($this->options['expose']['reduce'])) {
$options = $this->reduce_value_options();
- if (empty($this->options['expose']['single']) && !empty($this->options['expose']['optional'])) {
+ if (!empty($this->options['expose']['multiple']) && empty($this->options['expose']['required'])) {
$default_value = array();
}
}
- if (!empty($this->options['expose']['single'])) {
- if (!empty($this->options['expose']['optional']) && (empty($default_value) || !empty($this->options['expose']['reduce']))) {
+ if (empty($this->options['expose']['multiple'])) {
+ if (empty($this->options['expose']['required']) && (empty($default_value) || !empty($this->options['expose']['reduce']))) {
$default_value = 'All';
}
elseif (empty($default_value)) {
@@ -256,9 +262,9 @@ class views_handler_filter_in_operator extends views_handler_filter {
return TRUE;
}
- // If this is single and optional, this says that yes this filter will
+ // If this is non-multiple and non-required, then 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'])) {
+ if (empty($this->options['expose']['multiple']) && empty($this->options['expose']['required']) && !empty($this->options['expose']['limit'])) {
$identifier = $this->options['expose']['identifier'];
if ($input[$identifier] == 'All') {
return TRUE;
diff --git a/handlers/views_handler_filter_numeric.inc b/handlers/views_handler_filter_numeric.inc
index f73121c..9ee47d7 100644
--- a/handlers/views_handler_filter_numeric.inc
+++ b/handlers/views_handler_filter_numeric.inc
@@ -4,7 +4,7 @@
* Simple filter to handle greater than/less than filters
*/
class views_handler_filter_numeric extends views_handler_filter {
- var $no_single = TRUE;
+ var $always_multiple = TRUE;
function option_definition() {
$options = parent::option_definition();
@@ -132,12 +132,12 @@ class views_handler_filter_numeric extends views_handler_filter {
if (!empty($form_state['exposed'])) {
$identifier = $this->options['expose']['identifier'];
- if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
+ if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
// exposed and locked.
$which = in_array($this->operator, $this->operator_values(2)) ? 'minmax' : 'value';
}
else {
- $source = 'edit-' . drupal_html_id($this->options['expose']['operator']);
+ $source = 'edit-' . drupal_html_id($this->options['expose']['operator_id']);
}
}
@@ -277,8 +277,8 @@ class views_handler_filter_numeric extends views_handler_filter {
$rc = parent::accept_exposed_input($input);
- if (!empty($this->options['expose']['optional'])) {
- // We have to do some of our own optional checking.
+ if (empty($this->options['expose']['required'])) {
+ // We have to do some of our own checking for non-required filters.
$info = $this->operators();
if (!empty($info[$this->operator]['values'])) {
switch ($info[$this->operator]['values']) {
diff --git a/handlers/views_handler_filter_string.inc b/handlers/views_handler_filter_string.inc
index a98d8e3..49927f8 100644
--- a/handlers/views_handler_filter_string.inc
+++ b/handlers/views_handler_filter_string.inc
@@ -6,13 +6,13 @@
*/
class views_handler_filter_string extends views_handler_filter {
// exposed filter options
- var $no_single = TRUE;
- var $no_optional = TRUE;
+ var $always_multiple = TRUE;
+ var $always_required = TRUE;
function option_defintion() {
$options = parent::option_defintion();
- $options['expose']['contains']['optional'] = array('default' => FALSE);
+ $options['expose']['contains']['required'] = array('default' => TRUE);
return $options;
}
@@ -169,12 +169,12 @@ class views_handler_filter_string extends views_handler_filter {
if (!empty($form_state['exposed'])) {
$identifier = $this->options['expose']['identifier'];
- if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
+ if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
// exposed and locked.
$which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
}
else {
- $source = 'edit-' . drupal_html_id($this->options['expose']['operator']);
+ $source = 'edit-' . drupal_html_id($this->options['expose']['operator_id']);
}
}
diff --git a/handlers/views_handler_relationship.inc b/handlers/views_handler_relationship.inc
index 245431f..9af9938 100644
--- a/handlers/views_handler_relationship.inc
+++ b/handlers/views_handler_relationship.inc
@@ -75,15 +75,15 @@ class views_handler_relationship extends views_handler {
parent::options_form($form, $form_state);
$form['label'] = array(
'#type' => 'textfield',
- '#title' => t('Label'),
+ '#title' => t('Identifier'),
'#default_value' => isset($this->options['label']) ? $this->options['label'] : '',
- '#description' => t('The label for this relationship that will be displayed only administratively.'),
+ '#description' => t('Edit the administrative label displayed when referencing this relationship form filters, etc.'),
);
$form['required'] = array(
'#type' => 'checkbox',
'#title' => t('Require this relationship'),
- '#description' => t('If required, items that do not contain this relationship will not appear.'),
+ '#description' => t('Enable to hide items that do not contain this relationship'),
'#default_value' => !empty($this->options['required']),
);
}
diff --git a/handlers/views_handler_sort.inc b/handlers/views_handler_sort.inc
index 7ece191..fe1d992 100644
--- a/handlers/views_handler_sort.inc
+++ b/handlers/views_handler_sort.inc
@@ -74,6 +74,40 @@ class views_handler_sort extends views_handler {
}
/**
+ * Shortcut to display the expose/hide button.
+ */
+ function show_expose_button(&$form, &$form_state) {
+ $form['expose_button'] = array(
+ '#prefix' => '<div class="views-expose clearfix">',
+ '#suffix' => '</div>',
+ // Should always come first
+ '#weight' => -1000,
+ );
+ if (empty($this->options['exposed'])) {
+ $form['expose_button']['markup'] = array(
+ '#markup' => '<div class="description exposed-description" style="float: left; margin-right:10px">' . t('This sort is not exposed. Expose it to allow the users to change it.') . '</div>',
+ );
+ $form['expose_button']['button'] = array(
+ '#limit_validation_errors' => array(),
+ '#type' => 'submit',
+ '#value' => t('Expose sort'),
+ '#submit' => array('views_ui_config_item_form_expose'),
+ );
+ }
+ else {
+ $form['expose_button']['markup'] = array(
+ '#markup' => '<div class="description exposed-description">' . t('This sort is exposed. If you hide it, users will not be able to change it.') . '</div>',
+ );
+ $form['expose_button']['button'] = array(
+ '#limit_validation_errors' => array(),
+ '#type' => 'submit',
+ '#value' => t('Hide sort'),
+ '#submit' => array('views_ui_config_item_form_expose'),
+ );
+ }
+ }
+
+ /**
* Simple validate handler
*/
function options_validate(&$form, &$form_state) {
@@ -117,41 +151,30 @@ class views_handler_sort extends views_handler {
* Provide a list of options for the default sort form.
* Should be overridden by classes that don't override sort_form
*/
- function sort_options() {
+ function sort_options() {
return array(
- 'ASC' => t('Sort ascending'),
+ '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) { }
+ function expose_form(&$form, &$form_state) {
+ // #flatten will move everything from $form['expose'][$key] to $form[$key]
+ // prior to rendering. That's why the pre_render for it needs to run first,
+ // so that when the next pre_render (the one for fieldsets) runs, it gets
+ // the flattened data.
+ array_unshift($form['#pre_render'], 'views_ui_pre_render_flatten_data');
+ $form['expose']['#flatten'] = TRUE;
- /**
- * 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,
+ '#weight' => -1,
);
}
-
- /**
- * 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.
@@ -173,7 +196,7 @@ class views_handler_sort_broken extends views_handler_sort {
}
function ensure_my_table() { /* No table to ensure! */ }
- function query() { /* No query to run */ }
+ function query($group_by = FALSE) { /* 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>',
diff --git a/help/api-tables.html b/help/api-tables.html
index 483337e..b101f18 100644
--- a/help/api-tables.html
+++ b/help/api-tables.html
@@ -232,3 +232,21 @@ The following items are allowed in the field definition:
</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.
+
+<h3>Support old tabledata</h3>
+If you need to rename some tables/fields you can create some references in the views data to be able to continue to work.
+Therefore you create the whole table structure of the current views data.
+
+If you have to rename a single table you need to specify
+<pre>
+$data['oldtable']['moved to'] = 'newtable';
+</pre>
+
+If you have to rename/move a single a field to another table you specify
+<pre>
+$data['oldtable']['oldfield']['field']['moved to'] = array('newtable', 'newfield');
+</pre>
+or
+<pre>
+$data['oldtable']['oldfield']['moved to'] = array('newtable', 'newfield');
+</pre> \ No newline at end of file
diff --git a/help/api-upgrading.html b/help/api-upgrading.html
index 1447b20..071cc9f 100644
--- a/help/api-upgrading.html
+++ b/help/api-upgrading.html
@@ -29,7 +29,7 @@ Everyone who used it can extend from views_handler_sort, too.
<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
+The only thing you have to do is to replace
<pre>
'#process' => array('views_process_dependency')
</pre>
@@ -61,3 +61,20 @@ placeholder() generates a automatic unique placeholder for you.
add_where with operator 'formula' can be converted to add_where_expression.
add_having with operator 'formula' can be converted to add_having_expression.
+<h3>Changed place for display specific settings</h3>
+In the new ui the new place for display settings is at the top of the second column.
+Therefore use something like this code in your display plugin:
+<code>
+$categories['block'] = array(
+ 'title' => t('Block settings'),
+ 'column' => 'second',
+ 'build' => array(
+ '#weight' => -10,
+ ),
+);
+</code>
+
+<h3>Changed filter settings and associated class variables</h3>
+'optional' and 'single' are now 'required' and 'multiple', the logic is now opposite.
+Also, the 'no_single' and 'no_optional' class variables (known as "object flags" in the API docs)
+are now 'always_multiple' and 'always_required'.
diff --git a/help/example-author-block.html b/help/example-author-block.html
index 1e802bc..0d39021 100644
--- a/help/example-author-block.html
+++ b/help/example-author-block.html
@@ -66,7 +66,7 @@
<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>Return to the <a target="_blank" href="/admin/structure/views/view/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>
diff --git a/images/sprites.png b/images/sprites.png
index 9083622..b7df250 100644
--- a/images/sprites.png
+++ b/images/sprites.png
Binary files differ
diff --git a/includes/admin.inc b/includes/admin.inc
index ae85dd4..5c512aa 100644
--- a/includes/admin.inc
+++ b/includes/admin.inc
@@ -5,16 +5,56 @@
*/
/**
- * Page callback to list views in the system.
+ * Create an array of Views admin CSS for adding or attaching.
+ *
+ * This returns an array of arrays. Each array represents a single
+ * file. The array format is:
+ * - file: The fully qualified name of the file to send to drupal_add_css
+ * - options: An array of options to pass to drupal_add_css.
*/
-function views_ui_list_views($arg = NULL) {
- if ($arg != NULL) {
- return drupal_not_found();
+function views_ui_get_admin_css() {
+ $module_path = drupal_get_path('module', 'views_ui');
+ $list = array();
+ $list[$module_path . '/css/views-admin.css'] = array();
+
+ $list[$module_path . '/css/ie/views-admin.ie7.css'] = array(
+ 'browsers' => array(
+ 'IE' => 'lte IE 7',
+ '!IE' => FALSE
+ ),
+ 'preprocess' => FALSE,
+ );
+
+ $list[$module_path . '/css/views-admin.theme.css'] = array();
+
+ // Add in any theme specific CSS files we have
+ $themes = list_themes();
+ $theme_key = $GLOBALS['theme'];
+ while ($theme_key) {
+ $list[$module_path . "/css/views-admin.$theme_key.css"] = array(
+ 'group' => CSS_THEME,
+ );
+ $theme_key = isset($themes[$theme_key]->base_theme) ? $themes[$theme_key]->base_theme : '';
+ }
+ // Views contains style overrides for the following modules
+ $module_list = array('contextual', 'advanced_help', 'ctools');
+ foreach ($module_list as $module) {
+ if (module_exists($module)) {
+ $list[$module_path . '/css/views-admin.' . $module . '.css'] = array();
+ }
}
- $output = theme('views_ui_list_views');
- views_ui_check_advanced_help();
- return $output;
+
+ return $list;
+}
+
+/**
+ * Adds standard Views administration CSS to the current page.
+ */
+function views_ui_add_admin_css() {
+ foreach (views_ui_get_admin_css() as $file => $options) {
+ drupal_add_css($file, $options);
+ }
}
/**
@@ -25,7 +65,7 @@ function views_ui_list_views($arg = NULL) {
* be useful.
*/
function views_ui_check_advanced_help() {
- if (variable_get('views_hide_help_message', FALSE)) {
+ if (!variable_get('views_ui_show_advanced_help_warning', TRUE)) {
return;
}
@@ -33,792 +73,1663 @@ function views_ui_check_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'))));
+ 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/settings'))));
}
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'))));
+ 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/settings'))));
}
}
}
/**
- * Preprocess the list views theme
+ * #pre_render callback for the live preview element.
+ *
+ * Delaying the preview generation until the rendering phase ensures that time
+ * isn't wasted generating a preview if it won't be displayed (for example, if
+ * after processing the Edit form, a redirect is issued).
*/
-function template_preprocess_views_ui_list_views(&$vars) {
- $items = array();
- $sorts = array();
+function views_ui_pre_render_preview($element) {
+ $element['#markup'] = views_ui_preview($element['#view'], $element['#display_id'], $element['#preview_args']);
+ return $element;
+}
- $views = views_get_all_views();
+/**
+ * Returns the results of the live preview.
+ */
+function views_ui_preview($view, $display_id, $args = array()) {
+ // When this function is invoked as a page callback, each Views argument is
+ // passed separately.
+ if (!is_array($args)) {
+ $args = array_slice(func_get_args(), 2);
+ }
- $token_enable = drupal_get_token('views-enable');
- $token_disable = drupal_get_token('views-disable');
+ // Save $_GET['q'] so it can be restored before returning from this function.
+ $q = $_GET['q'];
- // 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');
+ // Determine where the query and performance statistics should be output.
+ $show_query = variable_get('views_ui_show_sql_query', FALSE);
+ if ($show_query) {
+ $show_query = variable_get('views_ui_show_sql_query_where', 'above');
}
- if (count($_GET) <= 1) {
- if (isset($_SESSION['views']['#admin']) && is_array($_SESSION['views']['#admin'])) {
- $_GET += $_SESSION['views']['#admin'];
- }
+ $show_stats = variable_get('views_ui_show_performance_statistics', FALSE);
+ if ($show_stats) {
+ $show_stats = variable_get('views_ui_show_performance_statistics_where', 'above');
}
- 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']);
+ $combined = ($show_query === $show_stats);
- $vars['help_type_icon'] = '';
- if (module_exists('advanced_help')) {
- $vars['help_type_icon'] = theme('advanced_help_topic', array('module' => 'views', 'topic' => 'view-type'));
- }
+ $rows = array('query' => array(), 'statistics' => array());
+ $output = '';
- $base_tables = views_fetch_base_tables();
+ $errors = $view->validate();
+ if ($errors === TRUE) {
+ $view->ajax = TRUE;
+ $view->live_preview = TRUE;
- 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;
+ // AJAX happens via $_POST but everything expects exposed data to
+ // be in GET. Copy stuff but remove ajax-framework specific keys.
+ $exposed_input = $_POST;
+ foreach (array('view_name', 'view_display_id', 'view_args', 'view_path', 'view_dom_id', 'pager_element', 'view_base_path', 'ajax_html_ids', 'ajax_page_state') as $key) {
+ if (isset($exposed_input[$key])) {
+ unset($exposed_input[$key]);
}
}
- 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;
- }
+ $view->set_exposed_input($exposed_input);
- if ($form_state['values']['display'] != 'all' && empty($view->display[$form_state['values']['display']])) {
- continue;
- }
+ // Store the current view URL for later use:
+ $view->set_display($display_id);
+ $view->set_arguments($args);
- if ($form_state['values']['status'] != 'all' && (!empty($view->disabled) == $form_state['values']['status'])) {
- continue;
+ if ($view->display_handler->get_option('path')) {
+ $path = $view->get_url();
}
- $item = new stdClass();
- $item->ops = array();
+ // Make view links come back to preview.
+ $view->override_path = 'admin/structure/views/nojs/preview/' . $view->name . '/' . $display_id;
- 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");
+ // Also override $_GET['q'] so we get the pager.
+ $_GET['q'] = $view->override_path;
+ if ($args) {
+ $_GET['q'] .= '/' . implode('/', $args);
}
- if ($view->type != t('Default')) {
- $text = $view->type == t('Overridden') ? t('Revert') : t('Delete');
- $item->ops[] = l($text, "admin/structure/views/delete/$view->name");
+
+ // Suppress contextual links of entities within the result set during a
+ // Preview.
+ // @todo We'll want to add contextual links specific to editing the View, so
+ // the suppression may need to be moved deeper into the Preview pipeline.
+ views_ui_contextual_links_suppress_push();
+ try {
+ $preview = $view->preview($display_id, $args);
}
- else {
- if (empty($view->disabled)) {
- $item->ops[] = l(t('Disable'), "admin/structure/views/disable/$view->name", array('query' => drupal_get_destination() + array('token' => $token_disable)));
- }
- else {
- $item->ops[] = l(t('Enable'), "admin/structure/views/enable/$view->name", array('query' => drupal_get_destination() + array('token' => $token_enable)));
- }
+ catch (Exception $e) {
+ drupal_set_message($e->getMessage(), 'error');
}
+ views_ui_contextual_links_suppress_pop();
+
+ // Prepare the query information and statistics to show either above or
+ // below the view preview.
+ if ($show_query || $show_stats) {
+ // Get information from the preview for display.
+ if (!empty($view->build_info['query'])) {
+ if ($show_query) {
+ $query = $view->build_info['query'];
+ // Only the sql default class has a method getArguments.
+ $quoted = array();
+
+ if (get_class($view->query) == 'views_plugin_query_default') {
+ $arguments = $query->getArguments();
+ $connection = Database::getConnection();
+ foreach ((array)$query->arguments() as $key => $val) {
+ $quoted[$key] = $connection->quote($val);
+ }
+ }
+ $rows['query'][] = array('<strong>' . t('Query') . '</strong>', '<pre>' . check_plain(strtr($query, $quoted)) . '</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];
+ }
- $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);
+ $rows['query'][] = array('<strong>' . t('Other queries') . '</strong>', '<pre>' . $queries . '</pre>');
}
- if (empty($view->disabled) && strpos($one_path, '%') === FALSE) {
- $all_paths[] = l($one_path, $one_path);
+ $rows['query'][] = array('<strong>' . t('Title') . '</strong>', filter_xss_admin($view->get_title()));
+ if (isset($path)) {
+ $path = l($path, $path);
}
else {
- $all_paths[] = check_plain($one_path);
+ $path = t('This display has no path.');
}
+ $rows['query'][] = array('<strong>' . t('Path') . '</strong>', $path);
+ }
+
+ if ($show_stats) {
+ $rows['statistics'][] = array('<strong>' . t('Query build time') . '</strong>', t('@time ms', array('@time' => intval($view->build_time * 100000) / 100)));
+ $rows['statistics'][] = array('<strong>' . t('Query execute time') . '</strong>', t('@time ms', array('@time' => intval($view->execute_time * 100000) / 100)));
+ $rows['statistics'][] = 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);
}
- if (!empty($all_paths)) {
- $item->path = implode(', ', array_unique($all_paths));
+ else {
+ // No query was run. Display that information in place of either the
+ // query or the performance statistics, whichever comes first.
+ if ($combined || ($show_query === 'above')) {
+ $rows['query'] = array(array('<strong>' . t('Query') . '</strong>', t('No query was run')));
+ }
+ else {
+ $rows['statistics'] = 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.');
+ }
- $item->type = $view->type;
- $item->name = $view->name;
-
- if (!empty($view->tag)) {
- $item->tag = $view->tag;
+ // Assemble the preview, the query info, and the query statistics in the
+ // requested order.
+ if ($show_query === 'above') {
+ if ($combined) {
+ $output .= '<div class="views-query-info">' . theme('table', array('rows' => array_merge($rows['query'], $rows['statistics']))) . '</div>';
+ }
+ else {
+ $output .= '<div class="views-query-info">' . theme('table', array('rows' => $rows['query'])) . '</div>';
}
+ }
+ elseif ($show_stats === 'above') {
+ $output .= '<div class="views-query-info">' . theme('table', array('rows' => $rows['statistics'])) . '</div>';
+ }
- $item->title = $view->get_title();
- $item->base = !empty($base_tables[$view->base_table]['title']) ? $base_tables[$view->base_table]['title'] : t('Broken');
+ $output .= $preview;
- $item->displays = array();
- foreach ($view->display as $display) {
- if (!empty($display->handler->definition['admin'])) {
- $item->displays[$display->handler->definition['admin']] = TRUE;
- }
+ if ($show_query === 'below') {
+ if ($combined) {
+ $output .= '<div class="views-query-info">' . theme('table', array('rows' => array_merge($rows['query'], $rows['statistics']))) . '</div>';
}
-
- if ($item->displays) {
- ksort($item->displays);
- $item->displays = implode(', ', array_keys($item->displays));
+ else {
+ $output .= '<div class="views-query-info">' . theme('table', array('rows' => $rows['query'])) . '</div>';
}
+ }
+ elseif ($show_stats === 'below') {
+ $output .= '<div class="views-query-info">' . theme('table', array('rows' => $rows['statistics'])) . '</div>';
+ }
- $item->description = check_plain($view->description);
- $item->classes = empty($view->disabled) ? 'view-enabled' : 'view-disabled';
- $items[] = $item;
+ $_GET['q'] = $q;
+ return $output;
+}
- $sort = intval(empty($view->disabled) xor $form_state['values']['sort'] == 'asc');
+/**
+ * AJAX callback that returns the preview section of the edit form.
+ */
+function views_ui_preview_callback($form, $form_state) {
+ return $form['displays']['preview'];
+}
- 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;
- }
+/**
+ * Page callback to add a new view.
+ */
+function views_ui_add_page() {
+ views_ui_add_admin_css();
+ drupal_set_title(t('Add new view'));
+ return drupal_get_form('views_ui_add_form');
+}
- $sorts[] = $sort;
- }
+/**
+ * Form builder for the "add new view" page.
+ */
+function views_ui_add_form($form, &$form_state) {
+ ctools_include('dependent');
+ $form['#attached']['js'][] = drupal_get_path('module', 'views_ui') . '/js/views-admin.js';
+ $form['#attributes']['class'] = array('views-admin');
- if ($form_state['values']['sort'] == 'desc') {
- arsort($sorts);
- }
- else {
- asort($sorts);
+ $form['human_name'] = array(
+ '#type' => 'textfield',
+ '#title' => t('View name'),
+ '#required' => TRUE,
+ '#size' => 32,
+ '#default_value' => !empty($form_state['view']) ? $form_state['view']->human_name : '',
+ '#maxlength' => 255,
+ );
+ $form['name'] = array(
+ '#type' => 'machine_name',
+ '#maxlength' => 32,
+ '#machine_name' => array(
+ 'exists' => 'views_get_view',
+ 'source' => array('human_name'),
+ ),
+ '#description' => t('A unique machine-readable name for this View. It must only contain lowercase letters, numbers, and underscores.'),
+ );
+
+ $form['description_enable'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Description'),
+ );
+ $form['description'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Provide description'),
+ '#title_display' => 'invisible',
+ '#size' => 64,
+ '#default_value' => !empty($form_state['view']) ? $form_state['view']->description : '',
+ '#states' => array(
+ 'visible' => array( // action to take.
+ ':input[name="description_enable"]' => array('checked' => TRUE),
+ ),
+ ),
+ );
+
+ // Create a wrapper for the entire dynamic portion of the form. Everything
+ // that can be updated by AJAX goes somewhere inside here. For example, this
+ // is needed by "Show" dropdown (below); it changes the base table of the
+ // view and therefore potentially requires all options on the form to be
+ // dynamically updated.
+ $form['displays'] = array();
+
+ // Create the part of the form that allows the user to select the basic
+ // properties of what the view will display.
+ $form['displays']['show'] = array(
+ '#type' => 'fieldset',
+ '#tree' => TRUE,
+ '#attributes' => array('class' => array('container-inline')),
+ );
+
+ // Create the "Show" dropdown, which allows the base table of the view to be
+ // selected.
+ $wizard_plugins = views_ui_get_wizards();
+ $options = array();
+ foreach ($wizard_plugins as $key => $w) {
+ $options[$key] = $w['title'];
}
+ $form['displays']['show']['wizard_key'] = array(
+ '#type' => 'select',
+ '#title' => t('Show'),
+ '#options' => $options,
+ );
+ $show_form = &$form['displays']['show'];
+ $show_form['wizard_key']['#default_value'] = views_ui_get_selected($form_state, array('show', 'wizard_key'), 'node', $show_form['wizard_key']);
+ // Changing this dropdown updates the entire content of $form['displays'] via
+ // AJAX.
+ views_ui_add_ajax_trigger($show_form, 'wizard_key', array('displays'));
+
+ // Build the rest of the form based on the currently selected wizard plugin.
+ $wizard_key = $show_form['wizard_key']['#default_value'];
+ $get_instance = $wizard_plugins[$wizard_key]['get_instance'];
+ $wizard_instance = $get_instance($wizard_plugins[$wizard_key]);
+ $form = $wizard_instance->build_form($form, $form_state);
+
+ $form['save'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save & exit'),
+ '#validate' => array('views_ui_wizard_form_validate'),
+ '#submit' => array('views_ui_add_form_save_submit'),
+ );
+ $form['continue'] = array(
+ '#type' => 'submit',
+ '#value' => t('Continue & edit'),
+ '#validate' => array('views_ui_wizard_form_validate'),
+ '#submit' => array('views_ui_add_form_store_edit_submit'),
+ '#process' => array_merge(array('views_ui_default_button'), element_info_property('submit', '#process', array())),
+ );
+ $form['cancel'] = array(
+ '#type' => 'submit',
+ '#value' => t('Cancel'),
+ '#submit' => array('views_ui_add_form_cancel_submit'),
+ );
+
+ return $form;
+}
- $i = array();
- foreach ($sorts as $id => $title) {
- $i[] = $items[$id];
+/**
+ * Gets the current value of a #select element, from within a form constructor function.
+ *
+ * This function is intended for use in highly dynamic forms (in particular the
+ * add view wizard) which are rebuilt in different ways depending on which
+ * triggering element (AJAX or otherwise) was most recently fired. For example,
+ * sometimes it is necessary to decide how to build one dynamic form element
+ * based on the value of a different dynamic form element that may not have
+ * even been present on the form the last time it was submitted. This function
+ * takes care of resolving those conflicts and gives you the proper current
+ * value of the requested #select element.
+ *
+ * By necessity, this function sometimes uses non-validated user input from
+ * $form_state['input'] in making its determination. Although it performs some
+ * minor validation of its own, it is not complete. The intention is that the
+ * return value of this function should only be used to help decide how to
+ * build the current form the next time it is reloaded, not to be saved as if
+ * it had gone through the normal, final form validation process. Do NOT use
+ * the results of this function for any other purpose besides deciding how to
+ * build the next version of the form.
+ *
+ * @param $form_state
+ * The standard associative array containing the current state of the form.
+ * @param $parents
+ * An array of parent keys that point to the part of the submitted form
+ * values that are expected to contain the element's value (in the case where
+ * this form element was actually submitted). In a simple case (assuming
+ * #tree is TRUE throughout the form), if the select element is located in
+ * $form['wrapper']['select'], so that the submitted form values would
+ * normally be found in $form_state['values']['wrapper']['select'], you would
+ * pass array('wrapper', 'select') for this parameter.
+ * @param $default_value
+ * The default value to return if the #select element does not currently have
+ * a proper value set based on the submitted input.
+ * @param $element
+ * An array representing the current version of the #select element within
+ * the form.
+ *
+ * @return
+ * The current value of the #select element. A common use for this is to feed
+ * it back into $element['#default_value'] so that the form will be rendered
+ * with the correct value selected.
+ */
+function views_ui_get_selected($form_state, $parents, $default_value, $element) {
+ // For now, don't trust this to work on anything but a #select element.
+ if (!isset($element['#type']) || $element['#type'] != 'select' || !isset($element['#options'])) {
+ return $default_value;
+ }
+
+ // If there is a user-submitted value for this element that matches one of
+ // the currently available options attached to it, use that. We need to check
+ // $form_state['input'] rather than $form_state['values'] here because the
+ // triggering element often has the #limit_validation_errors property set to
+ // prevent unwanted errors elsewhere on the form. This means that the
+ // $form_state['values'] array won't be complete. We could make it complete
+ // by adding each required part of the form to the #limit_validation_errors
+ // property individually as the form is being built, but this is difficult to
+ // do for a highly dynamic and extensible form. This method is much simpler.
+ if (!empty($form_state['input'])) {
+ $key_exists = NULL;
+ $submitted = drupal_array_get_nested_value($form_state['input'], $parents, $key_exists);
+ // Check that the user-submitted value is one of the allowed options before
+ // returning it. This is not a substitute for actual form validation;
+ // rather it is necessary because, for example, the same select element
+ // might have #options A, B, and C under one set of conditions but #options
+ // D, E, F under a different set of conditions. So the form submission
+ // might have occurred with option A selected, but when the form is rebuilt
+ // option A is no longer one of the choices. In that case, we don't want to
+ // use the value that was submitted anymore but rather fall back to the
+ // default value.
+ if ($key_exists && in_array($submitted, array_keys($element['#options']))) {
+ return $submitted;
+ }
}
- views_add_css('views-list');
- $vars['views'] = $i;
+ // Fall back on returning the default value if nothing was returned above.
+ return $default_value;
+}
- $getting_started = '';
- if (module_exists('advanced_help')) {
- $getting_started = theme('advanced_help_topic', array('module' => 'views', 'topic' => 'getting-started', 'type' => 'title'));
+/**
+ * Converts a form element in the add view wizard to be AJAX-enabled.
+ *
+ * This function takes a form element and adds AJAX behaviors to it such that
+ * changing it triggers another part of the form to update automatically. It
+ * also adds a submit button to the form that appears next to the triggering
+ * element and that duplicates its functionality for users who do not have
+ * JavaScript enabled (the button is automatically hidden for users who do have
+ * JavaScript).
+ *
+ * To use this function, call it directly from your form builder function
+ * immediately after you have defined the form element that will serve as the
+ * JavaScript trigger. Calling it elsewhere (such as in hook_form_alter()) may
+ * mean that the non-JavaScript fallback button does not appear in the correct
+ * place in the form.
+ *
+ * @param $wrapping_element
+ * The element whose child will server as the AJAX trigger. For example, if
+ * $form['some_wrapper']['triggering_element'] represents the element which
+ * will trigger the AJAX behavior, you would pass $form['some_wrapper'] for
+ * this parameter.
+ * @param $trigger_key
+ * The key within the wrapping element that identifies which of its children
+ * serves as the AJAX trigger. In the above example, you would pass
+ * 'triggering_element' for this parameter.
+ * @param $refresh_parents
+ * An array of parent keys that point to the part of the form that will be
+ * refreshed by AJAX. For example, if triggering the AJAX behavior should
+ * cause $form['dynamic_content']['section'] to be refreshed, you would pass
+ * array('dynamic_content', 'section') for this parameter.
+ */
+function views_ui_add_ajax_trigger(&$wrapping_element, $trigger_key, $refresh_parents) {
+ $seen_ids = &drupal_static(__FUNCTION__, array());
+ $seen_buttons = &drupal_static(__FUNCTION__, array());
+
+ // Add the AJAX behavior to the triggering element.
+ $triggering_element = &$wrapping_element[$trigger_key];
+ $triggering_element['#ajax']['callback'] = 'views_ui_ajax_update_form';
+ // We do not use drupal_html_id() to get an ID for the AJAX wrapper, because
+ // it remembers IDs across AJAX requests (and won't reuse them), but in our
+ // case we need to use the same ID from request to request so that the
+ // wrapper can be recognized by the AJAX system and its content can be
+ // dynamically updated. So instead, we will keep track of duplicate IDs
+ // (within a single request) on our own, later in this function.
+ $triggering_element['#ajax']['wrapper'] = 'edit-view-' . implode('-', $refresh_parents) . '-wrapper';
+
+ // Add a submit button for users who do not have JavaScript enabled. It
+ // should be displayed next to the triggering element on the form.
+ $button_key = $trigger_key . '_trigger_update';
+ $wrapping_element[$button_key] = array(
+ '#type' => 'submit',
+ // Hide this button when JavaScript is enabled.
+ '#attributes' => array('class' => array('js-hide')),
+ '#submit' => array('views_ui_nojs_submit'),
+ // Add a process function to limit this button's validation errors to the
+ // triggering element only. We have to do this in #process since until the
+ // form API has added the #parents property to the triggering element for
+ // us, we don't have any (easy) way to find out where its submitted values
+ // will eventually appear in $form_state['values'].
+ '#process' => array_merge(array('views_ui_add_limited_validation'), element_info_property('submit', '#process', array())),
+ // Add an after-build function that inserts a wrapper around the region of
+ // the form that needs to be refreshed by AJAX (so that the AJAX system can
+ // detect and dynamically update it). This is done in #after_build because
+ // it's a convenient place where we have automatic access to the complete
+ // form array, but also to minimize the chance that the HTML we add will
+ // get clobbered by code that runs after we have added it.
+ '#after_build' => array_merge(element_info_property('submit', '#after_build', array()), array('views_ui_add_ajax_wrapper')),
+ );
+ // Copy #weight and #access from the triggering element to the button, so
+ // that the two elements will be displayed together.
+ foreach (array('#weight', '#access') as $property) {
+ if (isset($triggering_element[$property])) {
+ $wrapping_element[$button_key][$property] = $triggering_element[$property];
+ }
}
- if (!$getting_started) {
- $getting_started = t('Install the advanced help module for the getting started');
+ // For easiest integration with the form API and the testing framework, we
+ // always give the button a unique #value, rather than playing around with
+ // #name.
+ $button_title = !empty($triggering_element['#title']) ? $triggering_element['#title'] : $trigger_key;
+ if (empty($seen_buttons[$button_title])) {
+ $wrapping_element[$button_key]['#value'] = t('Update "@title" choice', array(
+ '@title' => $button_title,
+ ));
+ $seen_buttons[$button_title] = 1;
}
+ else {
+ $wrapping_element[$button_key]['#value'] = t('Update "@title" choice (@number)', array(
+ '@title' => $button_title,
+ '@number' => ++$seen_buttons[$button_title],
+ ));
+ }
+
+ // Attach custom data to the triggering element and submit button, so we can
+ // use it in both the process function and AJAX callback.
+ $ajax_data = array(
+ 'wrapper' => $triggering_element['#ajax']['wrapper'],
+ 'trigger_key' => $trigger_key,
+ 'refresh_parents' => $refresh_parents,
+ // Keep track of duplicate wrappers so we don't add the same wrapper to the
+ // page more than once.
+ 'duplicate_wrapper' => !empty($seen_ids[$triggering_element['#ajax']['wrapper']]),
+ );
+ $seen_ids[$triggering_element['#ajax']['wrapper']] = TRUE;
+ $triggering_element['#views_ui_ajax_data'] = $ajax_data;
+ $wrapping_element[$button_key]['#views_ui_ajax_data'] = $ajax_data;
+}
- $vars['help'] = t('Not sure what to do? Try the "!getting-started" page.', array('!getting-started' => $getting_started));
+/**
+ * Processes a non-JavaScript fallback submit button to limit its validation errors.
+ */
+function views_ui_add_limited_validation($element, &$form_state) {
+ // Retrieve the AJAX triggering element so we can determine its parents. (We
+ // know it's at the same level of the complete form array as the submit
+ // button, so all we have to do to find it is swap out the submit button's
+ // last array parent.)
+ $array_parents = $element['#array_parents'];
+ array_pop($array_parents);
+ $array_parents[] = $element['#views_ui_ajax_data']['trigger_key'];
+ $ajax_triggering_element = drupal_array_get_nested_value($form_state['complete form'], $array_parents);
+
+ // Limit this button's validation to the AJAX triggering element, so it can
+ // update the form for that change without requiring that the rest of the
+ // form be filled out properly yet.
+ $element['#limit_validation_errors'] = array($ajax_triggering_element['#parents']);
+
+ // If we are in the process of a form submission and this is the button that
+ // was clicked, the form API workflow in form_builder() will have already
+ // copied it to $form_state['triggering_element'] before our #process
+ // function is run. So we need to make the same modifications in $form_state
+ // as we did to the element itself, to ensure that #limit_validation_errors
+ // will actually be set in the correct place.
+ if (!empty($form_state['triggering_element'])) {
+ $clicked_button = &$form_state['triggering_element'];
+ if ($clicked_button['#name'] == $element['#name'] && $clicked_button['#value'] == $element['#value']) {
+ $clicked_button['#limit_validation_errors'] = $element['#limit_validation_errors'];
+ }
+ }
+
+ return $element;
}
/**
- * Provide a form for sorting and filtering the list of views.
+ * After-build function that adds a wrapper to a form region (for AJAX refreshes).
+ *
+ * This function inserts a wrapper around the region of the form that needs to
+ * be refreshed by AJAX, based on information stored in the corresponding
+ * submit button form element.
*/
-function views_ui_list_views_form($form, &$form_state) {
- if (!variable_get('clean_url', FALSE)) {
- $form['q'] = array(
- '#type' => 'hidden',
- '#value' => $_GET['q'],
+function views_ui_add_ajax_wrapper($element, &$form_state) {
+ // Don't add the wrapper <div> if the same one was already inserted on this
+ // form.
+ if (empty($element['#views_ui_ajax_data']['duplicate_wrapper'])) {
+ // Find the region of the complete form that needs to be refreshed by AJAX.
+ // This was earlier stored in a property on the element.
+ $complete_form = &$form_state['complete form'];
+ $refresh_parents = $element['#views_ui_ajax_data']['refresh_parents'];
+ $refresh_element = drupal_array_get_nested_value($complete_form, $refresh_parents);
+
+ // The HTML ID that AJAX expects was also stored in a property on the
+ // element, so use that information to insert the wrapper <div> here.
+ $id = $element['#views_ui_ajax_data']['wrapper'];
+ $refresh_element += array(
+ '#prefix' => '',
+ '#suffix' => '',
);
+ $refresh_element['#prefix'] = '<div id="' . $id . '">' . $refresh_element['#prefix'];
+ $refresh_element['#suffix'] .= '</div>';
+
+ // Copy the element that needs to be refreshed back into the form, with our
+ // modifications to it.
+ drupal_array_set_nested_value($complete_form, $refresh_parents, $refresh_element);
}
- $all = array('all' => t('- All -'));
- $none = array('none' => t('- None -'));
+ return $element;
+}
- $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',
- );
+/**
+ * Updates a part of the add view form via AJAX.
+ *
+ * @return
+ * The part of the form that has changed.
+ */
+function views_ui_ajax_update_form($form, $form_state) {
+ // The region that needs to be updated was stored in a property of the
+ // triggering element by views_ui_add_ajax_trigger(), so all we have to do is
+ // retrieve that here.
+ return drupal_array_get_nested_value($form, $form_state['triggering_element']['#views_ui_ajax_data']['refresh_parents']);
+}
- $status = array(
- '0' => t('Disabled'),
- '1' => t('Enabled'),
- );
- $form['status'] = array(
- '#type' => 'select',
- '#title' => t('Status'),
- '#options' => array_merge($all, $status),
- '#default_value' => 'all',
- );
+/**
+ * Non-Javascript fallback for updating the add view form.
+ */
+function views_ui_nojs_submit($form, &$form_state) {
+ $form_state['rebuild'] = TRUE;
+}
- $bases = array();
- foreach (views_fetch_base_tables() as $table => $info) {
- $bases[$table] = $info['title'];
+/**
+ * Validate the add view form.
+ */
+function views_ui_wizard_form_validate($form, &$form_state) {
+ $w = views_ui_get_wizard($form_state['values']['show']['wizard_key']);
+ $form_state['wizard'] = $w;
+ $get_instance = $w['get_instance'];
+ $form_state['wizard_instance'] = $get_instance($w);
+ $errors = $form_state['wizard_instance']->validate($form, $form_state);
+ foreach ($errors as $name => $message) {
+ form_set_error($name, $message);
}
+}
- $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;
+/**
+ * Process the add view form, 'save'.
+ */
+function views_ui_add_form_save_submit($form, &$form_state) {
+ try {
+ $view = $form_state['wizard_instance']->create_view($form, $form_state);
+ }
+ catch (ViewsWizardException $e) {
+ drupal_set_message($e->getMessage(), 'error');
+ $form_state['redirect'] = 'admin/structure/views';
+ }
+ $view->save();
+ menu_rebuild();
+ cache_clear_all('*', 'cache_views', TRUE);
+ cache_clear_all();
+ $form_state['redirect'] = 'admin/structure/views';
+ if (!empty($view->display['page'])) {
+ $display = $view->display['page'];
+ if ($display->handler->has_path()) {
+ $one_path = $display->handler->get_option('path');
+ if (strpos($one_path, '%') === FALSE) {
+ $form_state['redirect'] = $one_path; // PATH TO THE VIEW IF IT HAS ONE
+ return;
}
}
}
+ drupal_set_message(t('Your view was saved. You may edit it from the list below.'));
+}
- asort($tags);
+/**
+ * Process the add view form, 'continue'.
+ */
+function views_ui_add_form_store_edit_submit($form, &$form_state) {
+ try {
+ $view = $form_state['wizard_instance']->create_view($form, $form_state);
+ }
+ catch (ViewsWizardException $e) {
+ drupal_set_message($e->getMessage(), 'error');
+ $form_state['redirect'] = 'admin/structure/views';
+ }
+ // Just cache it temporarily to edit it.
+ views_ui_cache_set($view);
+ $form_state['redirect'] = 'admin/structure/views/view/' . $view->name;
+}
- $form['tag'] = array(
- '#type' => 'select',
- '#title' => t('Tag'),
- '#options' => array_merge($all, $none, $tags),
- '#default_value' => 'all',
- );
+/**
+ * Cancel the add view form.
+ */
+function views_ui_add_form_cancel_submit($form, &$form_state) {
+ $form_state['redirect'] = 'admin/structure/views';
+}
- $displays = array();
- foreach (views_fetch_plugin_data('display') as $id => $info) {
- if (!empty($info['admin'])) {
- $displays[$id] = $info['admin'];
+/**
+ * Form element validation handler for a taxonomy autocomplete field.
+ *
+ * This allows a taxonomy autocomplete field to be validated outside the
+ * standard Field API workflow, without passing in a complete field widget.
+ * Instead, all that is required is that $element['#field_name'] contain the
+ * name of the taxonomy autocomplete field that is being validated.
+ *
+ * This function is currently not used for validation directly, although it
+ * could be. Instead, it is only used to store the term IDs and vocabulary name
+ * in the element value, based on the tags that the user typed in.
+ *
+ * @see taxonomy_autocomplete_validate()
+ */
+function views_ui_taxonomy_autocomplete_validate($element, &$form_state) {
+ $value = array();
+ if ($tags = $element['#value']) {
+ // Get the machine names of the vocabularies we will search, keyed by the
+ // vocabulary IDs.
+ $field = field_info_field($element['#field_name']);
+ $vocabularies = array();
+ if (!empty($field['settings']['allowed_values'])) {
+ foreach ($field['settings']['allowed_values'] as $tree) {
+ if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
+ $vocabularies[$vocabulary->vid] = $tree['vocabulary'];
+ }
+ }
+ }
+ // Store the term ID of each (valid) tag that the user typed.
+ $typed_terms = drupal_explode_tags($tags);
+ foreach ($typed_terms as $typed_term) {
+ if ($terms = taxonomy_term_load_multiple(array(), array('name' => trim($typed_term), 'vid' => array_keys($vocabularies)))) {
+ $term = array_pop($terms);
+ $value['tids'][] = $term->tid;
+ }
+ }
+ // Store the term IDs along with the name of the vocabulary. Currently
+ // Views (as well as the Field UI) assumes that there will only be one
+ // vocabulary, although technically the API allows there to be more than
+ // one.
+ if (!empty($value['tids'])) {
+ $value['tids'] = array_unique($value['tids']);
+ $value['vocabulary'] = array_pop($vocabularies);
}
}
+ form_set_value($element, $value, $form_state);
+}
- asort($displays);
+/**
+ * Theme function; returns basic administrative information about a view.
+ *
+ * TODO: template + preprocess
+ */
+function theme_views_ui_view_info($variables) {
+ $view = $variables['view'];
+ $title = $view->get_human_name();
- $form['display'] = array(
- '#type' => 'select',
- '#title' => t('Displays'),
- '#options' => array_merge($all, $displays),
- '#default_value' => 'all',
- );
+ $displays = _views_ui_get_displays_list($view);
+ $displays = empty($displays) ? t('None') : format_plural(count($displays), 'Display', 'Displays') . ': ' . '<em>' . implode(', ', $displays) . '</em>';
- $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',
- );
+ switch ($view->type) {
+ case t('Default'):
+ default:
+ $type = t('In code');
+ break;
- $form['sort'] = array(
- '#type' => 'select',
- '#title' => t('Order'),
- '#options' => array(
- 'asc' => t('Up'),
- 'desc' => t('Down'),
- ),
- '#default_value' => 'asc',
- );
+ case t('Normal'):
+ $type = t('In database');
+ break;
- // Autosubmit all form elements.
- ctools_add_js('auto-submit');
- $form['#attributes']['class'][] = 'ctools-auto-submit-full-form';
+ case t('Overridden'):
+ $type = t('Database overriding code');
+ }
- $form['submit'] = array(
- '#name' => '', // so it won't in the $_GET args
- '#type' => 'submit',
- '#id' => 'edit-views-apply',
- '#value' => t('Apply'),
- '#attributes' => array('class' => array('ctools-use-ajax', 'ctools-auto-submit-click')),
- );
+ $output = '';
+ $output .= '<div class="views-ui-view-title">' . $title . "</div>\n";
+ $output .= '<div class="views-ui-view-displays">' . $displays . "</div>\n";
+ $output .= '<div class="views-ui-view-storage">'. $type . "</div>\n";
+ $output .= '<div class="views-ui-view-base">' . t('Type') . ': ' . $variables['base']. "</div>\n";
+ return $output;
+}
- if (!empty($_SESSION['views']['#admin'])) {
- $form['reset'] = array(
- '#type' => 'submit',
- '#id' => 'edit-views-reset',
- '#value' => t('Reset'),
- );
+/**
+ * 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));
}
- $form['#token'] = FALSE;
- return $form;
+ $cancel = 'admin/structure/views/view/' . $view->name . '/edit';
+ 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'));
}
/**
- * Page callback for the live preview.
- *
- * @todo make this use a template
+ * Submit handler to break_lock a view.
*/
-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(),
- ),
- );
+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/view/' . $form_state['view']->name . '/edit';
+ drupal_set_message(t('The lock has been broken and you may now edit this view.'));
+}
- $form = drupal_build_form('views_ui_preview_form', $form_state);
- $output = drupal_render($form);
- $args = array();
- if (isset($form_state['view_args']) && $form_state['view_args'] !== '') {
- $args = explode('/', $form_state['view_args']);
+/**
+ * Page title callback for the Edit View page.
+ */
+function views_ui_edit_page_title($view) {
+ $bases = views_fetch_base_tables();
+ $name = $view->get_human_name();
+ if (isset($bases[$view->base_table])) {
+ $name .= ' (' . $bases[$view->base_table]['title'] . ')';
}
- $errors = $view->validate();
- if ($errors === TRUE) {
- $view->ajax = $js;
- $view->live_preview = TRUE;
- $view->set_exposed_input($_POST);
+ return $name;
+}
- // Store the current view URL for later use:
- $view->set_display($form_state['display_id']);
- $view->set_arguments($args);
+/**
+ * Form builder callback for editing a View.
+ *
+ * @todo Remove as many #prefix/#suffix lines as possible. Use #theme_wrappers
+ * instead.
+ *
+ * @todo Rename to views_ui_edit_view_form(). See that function for the "old"
+ * version.
+ */
+function views_ui_edit_form($form, &$form_state, $view, $display_id = NULL) {
+ // Do not allow the form to be cached, because $form_state['view'] can become
+ // stale between page requests.
+ // @see views_ui_ajax_get_form() for how this affects #ajax.
+ // @todo To remove this and allow the form to be cacheable:
+ // - Change $form_state['view'] to $form_state['temporary']['view'].
+ // - Add a #process function to initialize $form_state['temporary']['view']
+ // on cached form submissions.
+ // - Update ctools_include() to support cached forms, or else use
+ // form_load_include().
+ $form_state['no_cache'] = TRUE;
- if ($view->display_handler->get_option('path')) {
- $path = $view->get_url();
- }
+ ctools_include('dependent');
+ $form['#attached']['js'][] = ctools_attach_js('dependent');
+ $form['#attached']['js'][] = ctools_attach_js('collapsible-div');
- // Make view links come back to preview.
- $view->override_path = 'admin/structure/views/nojs/preview/' . $view->name . '/' . $form_state['display_id'];
+ $form['#tree'] = TRUE;
+ // @todo When more functionality is added to this form, cloning here may be
+ // too soon. But some of what we do with $view later in this function
+ // results in making it unserializable due to PDO limitations.
+ $form_state['view'] = clone($view);
+
+ $form['#attached']['library'][] = array('system', 'ui.tabs');
+ $form['#attached']['library'][] = array('system', 'ui.dialog');
+ $form['#attached']['library'][] = array('system', 'drupal.ajax');
+ $form['#attached']['library'][] = array('system', 'jquery.form');
+ // TODO: This should be getting added to the page when an ajax popup calls
+ // for it, instead of having to add it manually here.
+ $form['#attached']['js'][] = 'misc/tabledrag.js';
+
+ $form['#attached']['css'] = views_ui_get_admin_css();
+ $module_path = drupal_get_path('module', 'views_ui');
+
+ $form['#attached']['js'][] = $module_path . '/js/views-admin.js';
+ $form['#attached']['js'][] = array(
+ 'data' => array('views' => array('ajax' => array(
+ 'id' => '#views-ajax-body',
+ 'title' => '#views-ajax-title',
+ 'popup' => '#views-ajax-popup',
+ 'defaultForm' => views_ui_get_default_ajax_message(),
+ ))),
+ 'type' => 'setting',
+ );
- // 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'];
- }
+ $form += array(
+ '#prefix' => '',
+ '#suffix' => '',
+ );
+ $form['#prefix'] = $form['#prefix'] . '<div class="views-edit-view views-admin clearfix">';
+ $form['#suffix'] = '</div>' . $form['#suffix'];
- $preview = $view->preview($form_state['display_id'], $args);
+ if (isset($view->locked) && is_object($view->locked)) {
+ $form['locked'] = array(
+ '#theme_wrappers' => array('container'),
+ '#attributes' => array('class' => array('view-locked', 'messages', 'warning')),
+ '#markup' => t('This view is being edited by user !user, and is therefore locked from editing by others. This lock is !age old. Click here to <a href="!break">break this lock</a>.', array('!user' => theme('username', array('account' => user_load($view->locked->uid))), '!age' => format_interval(REQUEST_TIME - $view->locked->updated), '!break' => url('admin/structure/views/view/' . $view->name . '/break-lock'))),
+ );
+ }
+ if (isset($view->vid) && $view->vid == 'new') {
+ $message = t('* All changes are stored temporarily. Click Save to make your changes permanent. Click Cancel to discard the view.');
+ }
+ else {
+ $message = t('* All changes are stored temporarily. Click Save to make your changes permanent. Click Cancel to discard your changes.');
+ }
- // Get information from the preview for display.
- if (!empty($view->build_info['query'])) {
- $rows = array();
- $query = $view->build_info['query'];
- // Only the sql default class has a method getArguments.
- $quoted = array();
+ $form['changed'] = array(
+ '#theme_wrappers' => array('container'),
+ '#attributes' => array('class' => array('view-changed', 'messages', 'warning')),
+ '#markup' => $message,
+ );
+ if (empty($view->changed)) {
+ $form['changed']['#attributes']['class'][] = 'js-hide';
+ }
- if (get_class($view->query) == 'views_plugin_query_default') {
- $arguments = $query->getArguments();
- $connection = Database::getConnection();
- foreach ((array)$query->arguments() as $key => $val) {
- $quoted[$key] = $connection->quote($val);
- }
- }
- $rows[] = array('<strong>' . t('Query') . '</strong>', '<pre>' . check_plain(strtr($query, $quoted)) . '</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];
- }
+ $form['help_text'] = array(
+ '#prefix' => '<div>',
+ '#suffix' => '</div>',
+ '#markup' => t('Modify the display(s) of your view below or add new displays.'),
+ );
- $rows[] = array('<strong>' . t('Other queries') . '</strong>', '<pre>' . $queries . '</pre>');
- }
+ $form['actions'] = array(
+ '#type' => 'actions',
+ '#weight' => 0,
+ );
- $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.');
- }
+ if (empty($view->changed)) {
+ $form['actions']['#attributes'] = array(
+ 'class' => array(
+ 'js-hide',
+ ),
+ );
+ }
- $rows[] = array('<strong>' . t('Path') . '</strong>', $path);
+ $form['actions']['save'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save'),
+ // Taken from the "old" UI. @TODO: Review and rename.
+ '#validate' => array('views_ui_edit_view_form_validate'),
+ '#submit' => array('views_ui_edit_view_form_submit'),
+ );
+ $form['actions']['cancel'] = array(
+ '#type' => 'submit',
+ '#value' => t('Cancel'),
+ '#submit' => array('views_ui_edit_view_form_cancel'),
+ );
- $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);
+ $form['displays'] = array(
+ '#prefix' => '<h1 class="unit-title clearfix">' . t('Displays') . '</h1>' . "\n" . '<div class="views-displays">',
+ '#suffix' => '</div>',
+ );
- $info = theme('table', array('rows' => $rows));
+ $form['displays']['top']['#theme_wrappers'] = array('views_container');
+ $form['displays']['top']['#attributes']['class'] = array('views-display-top');
+
+ // Extra actions for the display
+ $form['displays']['top']['extra_actions'] = array(
+ '#theme' => 'links__ctools_dropbutton',
+ '#attributes' => array(
+ 'id' => 'views-display-extra-actions',
+ 'class' => array(
+ 'horizontal', 'right', 'links', 'actions',
+ ),
+ ),
+ '#links' => array(
+ 'analyze' => array(
+ 'title' => t('analyze'),
+ 'href' => "admin/structure/views/view/$view->name/analyze",
+ ),
+ 'clone' => array(
+ 'title' => t('clone'),
+ 'href' => "admin/structure/views/view/$view->name/clone",
+ ),
+ 'export' => array(
+ 'title' => t('export'),
+ 'href' => "admin/structure/views/view/$view->name/export",
+ ),
+ ),
+ );
+ if (isset($view->type) && $view->type != t('Default')) {
+ if ($view->type == t('Overridden')) {
+ $form['displays']['top']['extra_actions']['#links']['revert'] = array(
+ 'title' => t('revert'),
+ 'href' => "admin/structure/views/view/$view->name/revert",
+ 'query' => drupal_get_destination(),
+ );
}
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');
+ $form['displays']['top']['extra_actions']['#links']['delete'] = array(
+ 'title' => t('delete'),
+ 'href' => "admin/structure/views/view/$view->name/delete",
+ );
}
- $preview = t('Unable to preview due to validation errors.');
- $info = '';
}
- $info = '<div class="views-query-info">' . $info . '</div>';
+ // Determine the displays available for editing.
+ if ($tabs = views_ui_edit_page_display_tabs($view)) {
+ // If a display isn't specified, use the first one.
+ if (empty($display_id)) {
+ foreach ($tabs as $id => $tab) {
+ if (!isset($tab['#access']) || $tab['#access']) {
+ $display_id = $id;
+ break;
+ }
+ }
+ }
+ // If a display is specified, but we don't have access to it, return
+ // an access denied page.
+ if ($display_id && (!isset($tabs[$display_id]) || (isset($tabs[$display_id]['#access']) && !$tabs[$display_id]['#access']))) {
+ // TODO: This doesn't work inside a form.
+ return MENU_ACCESS_DENIED;
+ }
- if (variable_get('views_ui_query_on_top', FALSE)) {
- $output .= $info . $preview;
+ if ($display_id) {
+ $tabs[$display_id]['#active'] = TRUE;
+ }
+ $tabs['#prefix'] = '<h2 class="element-invisible">' . t('Secondary tabs') . '</h2><ul class="tabs secondary">';
+ $tabs['#suffix'] = '</ul>';
+ $form['displays']['top']['tabs'] = $tabs;
+ }
+ elseif ($display_id) {
+ return MENU_ACCESS_DENIED;
}
else {
- $output .= $preview . $info;
+ $display_id = NULL;
}
- if (!$js) {
- views_add_css('views-admin');
- drupal_set_title($view->get_title());
- return $output;
+ // Buttons for adding a new display.
+ foreach (views_fetch_plugin_names('display') as $type => $label) {
+ $form['displays']['top']['add_display'][$type] = array(
+ '#type' => 'submit',
+ '#value' => t('Add !display', array('!display' => $label)),
+ '#limit_validation_errors' => array(),
+ '#submit' => array('views_ui_edit_form_submit_add_display', 'views_ui_edit_form_submit_delay_destination'),
+ '#attributes' => array('class' => array('add-display')),
+ // Allow JavaScript to remove the 'Add ' prefix from the button label when
+ // placing the button in a "Add" dropdown menu.
+ '#process' => array_merge(array('views_ui_form_button_was_clicked'), element_info_property('submit', '#process', array())),
+ '#values' => array(t('Add !display', array('!display' => $label)), $label),
+ );
}
- else {
- $commands = array();
- if (!empty($view->js_settings)) {
- $commands[] = ajax_command_settings($view->js_settings);
+
+ // The rest requires a display to be selected.
+ if ($display_id) {
+ $form_state['display_id'] = $display_id;
+
+ // The part of the page where editing will take place.
+ $view->set_display($display_id);
+ // This element is the ctools collapsible-div container for the display edit elements.
+ $form['displays']['settings'] = array(
+ '#theme_wrappers' => array('container'),
+ '#attributes' => array(
+ 'class' => array(
+ 'views-display-settings',
+ 'box-margin',
+ 'ctools-collapsible-container',
+ ),
+ ),
+ '#id' => 'edit-display-settings',
+ );
+ $display_title = views_ui_get_display_label($view, $display_id, FALSE);
+ // Add a handle for the ctools collapsible-div. The handle is the title of the display
+ $form['displays']['settings']['tab_title']['#markup'] = '<h2 id="edit-display-settings-title" class="ctools-collapsible-handle">'.t('@display_title details', array('@display_title' => ucwords($display_title))).'</h2>';
+ // The ctools collapsible-div content
+ $form['displays']['settings']['settings_content']= array(
+ '#theme_wrappers' => array('container'),
+ '#id' => 'edit-display-settings-content',
+ '#attributes' => array(
+ 'class' => array(
+ 'ctools-collapsible-content',
+ ),
+ ),
+ );
+ // Add the edit display content
+ $form['displays']['settings']['settings_content']['tab_content'] = views_ui_get_display_tab($view, $display_id);
+ $form['displays']['settings']['settings_content']['tab_content']['#theme_wrappers'] = array('container');
+ $form['displays']['settings']['settings_content']['tab_content']['#attributes'] = array('class' => array('views-display-tab'));
+ $form['displays']['settings']['settings_content']['tab_content']['#id'] = 'views-tab-' . $display_id;
+ // Mark deleted displays as such.
+ if (!empty($view->display[$display_id]->deleted)) {
+ $form['displays']['settings']['settings_content']['tab_content']['#attributes']['class'][] = 'views-display-deleted';
}
- $display = '';
- if ($messages = theme('status_messages')) {
- $display = '<div class="views-messages">' . $messages . '</div>';
+
+ // Add preview controls
+ $form['displays']['settings']['settings_content']['preview_controls'] = array(
+ '#theme_wrappers' => array('container'),
+ '#attributes' => array(
+ 'class' => array(
+ 'clearfix',
+ ),
+ ),
+ '#id' => 'edit-display-preview-controls',
+ );
+
+ // Add a checkbox controlling whether or not this display auto-previews.
+ $form['displays']['settings']['settings_content']['preview_controls']['live_preview'] = array(
+ '#type' => 'checkbox',
+ '#id' => 'edit-displays-live-preview',
+ '#title' => t('Auto preview'),
+ '#default_value' => !variable_get('views_ui_disable_live_preview', 0),
+ );
+
+ // Add the preview button
+ $form['displays']['settings']['settings_content']['preview_controls']['button'] = array(
+ '#type' => 'submit',
+ '#value' => t('Preview'),
+ '#attributes' => array('class' => array('arguments-preview')),
+ '#states' => array(
+ 'visible' => array( // action to take.
+ ':input[name="displays[settings][settings_content][preview_controls][live_preview]"]' => array('checked' => FALSE),
+ ),
+ ),
+ '#id' => 'preview-submit',
+ '#submit' => array('views_ui_edit_form_submit_preview'),
+ '#ajax' => array(
+ 'path' => 'admin/structure/views/view/' . $view->name . '/edit/ajax',
+ 'callback' => 'views_ui_preview_callback',
+ 'wrapper' => 'views-live-preview',
+ ),
+ // Make ENTER in arguments textfield (and other controls) submit the form
+ // as this button, not the Save button.
+ // @todo This only works for JS users. To make this work for nojs users,
+ // we may need to split Preview into a separate form.
+ '#process' => array_merge(array('views_ui_default_button'), element_info_property('submit', '#process', array())),
+ );
+
+ // Add the arguments textfield
+ $form['displays']['settings']['settings_content']['preview_controls']['view_args'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Arguments'),
+ '#description' => t('Separate arguments with a / as though they were a URL path.'),
+ '#id' => 'preview-args',
+ );
+
+ // The live preview.
+ // @todo: Figure out whether $view->preview and $view->editing might be enough already.
+ $view->views_ui_context = TRUE;
+
+ $form['displays']['preview'] = array(
+ '#theme_wrappers' => array('container'),
+ '#id' => 'views-live-preview',
+ );
+
+ $form['displays']['preview']['preview'] = array();
+ if (!variable_get('views_ui_disable_live_preview', 0) || !empty($form_state['show_preview']) || !empty($form_state['values']['displays']['settings']['settings_content']['preview_controls']['live_preview'])) {
+ $preview_args = isset($form_state['values']['displays']['settings']['settings_content']['preview_controls']['view_args']) ? $form_state['values']['displays']['settings']['settings_content']['preview_controls']['view_args'] : '';
+ $preview_args = ($preview_args !== '') ? explode('/', $preview_args) : array();
+ $form['displays']['preview']['preview'] += array(
+ '#type' => 'markup',
+ '#pre_render' => array_merge(array('views_ui_pre_render_preview'), element_info_property('markup', '#pre_render', array())),
+ '#view' => $view,
+ '#display_id' => $display_id,
+ '#preview_args' => $preview_args,
+ );
}
- $display .= $output;
- if ($display) {
- $commands[] = ajax_command_html('div#views-live-preview', $display);
+
+ // The content of the popup dialog.
+ $form['ajax-area'] = array(
+ '#theme_wrappers' => array('container'),
+ '#id' => 'views-ajax-popup',
+ );
+ $form['ajax-area']['ajax-title'] = array(
+ '#markup' => '<h2 id="views-ajax-title"></h2>',
+ );
+ $form['ajax-area']['ajax-body'] = array(
+ '#theme_wrappers' => array('container'),
+ '#id' => 'views-ajax-body',
+ '#markup' => views_ui_get_default_ajax_message(),
+ );
+
+ // WYSIWYG does not yet work on AJAX returned content unless the editor
+ // libraries are loaded on the base page (http://drupal.org/node/356480).
+ // @todo Remove this when that issue is resolved.
+ if (module_exists('wysiwyg')) {
+ $form['dummy_text_format'] = array('#type' => 'text_format', '#prefix' => '<div style="display:none">', '#suffix' => '</div>');
}
- return $js ? array('#type' => 'ajax', '#commands' => $commands) : $commands;
}
+
+ return $form;
+}
+
+function views_ui_get_default_ajax_message() {
+ return '<div class="message">' . t("Click on an item to edit that item's details.") . '</div>';
}
/**
- * Form for generating argument information for the live preview.
+ * Submit handler to add a display to a view.
*/
-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;
- }
+function views_ui_edit_form_submit_add_display($form, &$form_state) {
+ $view = $form_state['view'];
- $form['#attributes'] = array(
- 'class' => array('clearfix'),
- );
+ // Create the new display.
+ $parents = $form_state['triggering_element']['#parents'];
+ $display_type = array_pop($parents);
+ $display_id = $view->add_display($display_type);
+ views_ui_cache_set($view);
- $form['display_id'] = array(
- '#type' => 'select',
- '#title' => t('Display'),
- '#options' => $options,
- '#default_value' => $form_state['display_id'],
- '#id' => 'preview-display-id',
- );
+ // Redirect to the new display's edit page.
+ $form_state['redirect'] = 'admin/structure/views/view/' . $view->name . '/edit/' . $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',
- );
+/**
+ * Submit handler to duplicate a display for a view.
+ */
+function views_ui_edit_form_submit_duplicate_display($form, &$form_state) {
+ $view = $form_state['view'];
+ $display_id = $form_state['display_id'];
- $form['preview'] = array(
- '#type' => 'submit',
- '#value' => t('Preview'),
- '#id' => 'preview-submit',
- );
+ // Create the new display.
+ $display = $view->display[$display_id];
+ $new_display_id = $view->add_display($display->display_plugin);
+ $view->display[$new_display_id] = clone $display;
+ $view->display[$new_display_id]->id = $new_display_id;
+ views_ui_cache_set($view);
- $form['live_preview'] = array(
- '#type' => 'checkbox',
- '#title' => t('Automatic live preview'),
- '#default_value' => !variable_get('views_ui_disable_live_preview', 0),
- );
+ // Redirect to the new display's edit page.
+ $form_state['redirect'] = 'admin/structure/views/view/' . $view->name . '/edit/' . $new_display_id;
+}
- $form['#action'] = url("admin/structure/views/nojs/preview/$view->name");
- return $form;
+/**
+ * Submit handler to delete a display from a view.
+ */
+function views_ui_edit_form_submit_delete_display($form, &$form_state) {
+ $view = $form_state['view'];
+ $display_id = $form_state['display_id'];
+
+ // Mark the display for deletion.
+ $view->display[$display_id]->deleted = TRUE;
+ views_ui_cache_set($view);
+
+ // Redirect to the top-level edit page. The first remaining display will
+ // become the active display.
+ $form_state['redirect'] = 'admin/structure/views/view/' . $view->name;
}
/**
- * 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.
+ * Submit handler to add a restore a removed display to a view.
*/
-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'];
+function views_ui_edit_form_submit_undo_delete_display($form, &$form_state) {
+ // Create the new display
+ $id = $form_state['display_id'];
+ $form_state['view']->display[$id]->deleted = FALSE;
+
+ // Store in cache
+ views_ui_cache_set($form_state['view']);
+
+ // Redirect to the top-level edit page.
+ $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->name . '/edit/' . $id;
}
/**
- * Page callback to add a new view.
+ * Submit handler when Preview button is clicked.
*/
-function views_ui_add_page() {
- $form_state = array(
- 'view' => NULL,
- 'build_info' => array(
- 'args' => array(),
- ),
- );
+function views_ui_edit_form_submit_preview($form, &$form_state) {
+ // Rebuild the form with a pristine $view object.
+ $form_state['build_info']['args'][0] = views_ui_cache_load($form_state['view']->name);
+ $form_state['show_preview'] = TRUE;
+ $form_state['rebuild'] = TRUE;
+}
- $form = drupal_build_form('views_ui_add_form', $form_state);
- return drupal_render($form);
+/**
+ * Submit handler for form buttons that do not complete a form workflow.
+ *
+ * The Edit View form is a multistep form workflow, but with state managed by
+ * the CTools object cache rather than $form_state['rebuild']. Without this
+ * submit handler, buttons that add or remove displays would redirect to the
+ * destination parameter (e.g., when the Edit View form is linked to from a
+ * contextual link). This handler can be added to buttons whose form submission
+ * should not yet redirect to the destination.
+ */
+function views_ui_edit_form_submit_delay_destination($form, &$form_state) {
+ if (isset($_GET['destination']) && $form_state['redirect'] !== FALSE) {
+ if (!isset($form_state['redirect'])) {
+ $form_state['redirect'] = $_GET['q'];
+ }
+ if (is_string($form_state['redirect'])) {
+ $form_state['redirect'] = array($form_state['redirect']);
+ }
+ $options = isset($form_state['redirect'][1]) ? $form_state['redirect'][1] : array();
+ if (!isset($options['query']['destination'])) {
+ $options['query']['destination'] = $_GET['destination'];
+ }
+ $form_state['redirect'][1] = $options;
+ unset($_GET['destination']);
+ }
}
/**
- * Page callback to add a new view.
+ * Adds tabs for navigating across Displays when editing a View.
+ *
+ * This function can be called from hook_menu_local_tasks_alter() to implement
+ * these tabs as secondary local tasks, or it can be called from elsewhere if
+ * having them as secondary local tasks isn't desired. The caller is responsible
+ * for setting the active tab's #active property to TRUE.
*/
-function views_ui_clone_page($view) {
- $form_state = array(
- 'view' => $view->copy(),
- 'build_info' => array(
- 'args' => array(),
- ),
- );
+function views_ui_edit_page_display_tabs($view) {
+ $tabs = 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));
+ // Create a tab for each display.
+ foreach ($view->display as $id => $display) {
+ $tabs[$id] = array(
+ '#theme' => 'menu_local_task',
+ '#link' => array(
+ 'title' => views_ui_get_display_label($view, $id),
+ 'href' => 'admin/structure/views/view/' . $view->name . '/edit/' . $id,
+ 'localized_options' => array(),
+ ),
+ );
+ if (!empty($display->deleted)) {
+ $tabs[$id]['#link']['localized_options']['attributes']['class'][] = 'views-display-deleted-link';
+ }
+ }
+
+ // If the default display isn't supposed to be shown, don't display its tab.
+ if (!views_ui_show_default_display($view)) {
+ $tabs['default']['#access'] = FALSE;
+ }
+
+ return $tabs;
}
/**
- * Form constructor callback to create the views Add Form, phase 1.
+ * Controls whether or not the default display should have its own tab on edit.
*/
-function views_ui_add_form($form, &$form_state) {
- $view = $form_state['view'];
- $form = array();
+function views_ui_show_default_display($view) {
+ // Always show the default display for advanced users who prefer that mode.
+ $advanced_mode = variable_get('views_ui_show_master_display', FALSE);
+ // For other users, show the default display only if there are no others, and
+ // hide it if there's at least one "real" display.
+ $additional_displays = (count($view->display) == 1);
+
+ return $advanced_mode || $additional_displays;
+}
- $form['human_name'] = array(
- '#type' => 'textfield',
- '#title' => t('View name'),
- '#description' => t('A descriptive name for this view. Spaces are allowed.'),
- '#default_value' => $view ? $view->human_name : '',
- '#required' => TRUE,
- '#size' => 32,
- '#maxlength' => 255,
- );
+/**
+ * Returns a renderable array representing the edit page for one display.
+ */
+function views_ui_get_display_tab($view, $display_id) {
+ $build = array();
+ $display = $view->display[$display_id];
+ $plugin = $display->handler->definition;
+ // If the plugin doesn't exist, display an error message instead of an edit
+ // page.
+ if (empty($plugin)) {
+ $title = isset($display->display_title) ? $display->display_title : t('Invalid');
+ // @TODO: Improved UX for the case where a plugin is missing.
+ $build['#markup'] = t("Error: Display @display refers to a plugin named '@plugin', but that plugin is missing.", array('@display' => $display->id, '@plugin' => $display->display_plugin));
+ }
+ // Build the content of the edit page.
+ else {
+ $build['details'] = views_ui_get_display_tab_details($view, $display);
+ }
+ return $build;
+}
- $form['name'] = array(
- '#type' => 'machine_name',
- '#maxlength' => 32,
- '#machine_name' => array(
- 'exists' => 'views_get_view',
- 'source' => array('human_name'),
- ),
- '#description' => t('A unique machine-readable name for this View. It must only contain lowercase letters, numbers, and underscores.'),
+/**
+ * Helper function to get the display details section of the edit UI.
+ *
+ * @param $view
+ * @param $display
+ *
+ * @return array
+ * A renderable page build array.
+ */
+function views_ui_get_display_tab_details($view, $display) {
+ $display_title = views_ui_get_display_label($view, $display->id, FALSE);
+ $build = array(
+ '#theme_wrappers' => array('container'),
+ '#id' => 'edit-display-settings-details',
+ '#attributes' => array(),
);
- $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,
- );
+ $build['top']['#theme_wrappers'] = array('container');
+ $build['top']['#id'] = 'edit-display-settings-top';
+ $build['top']['#attributes']['class'] = array('views-ui-display-tab-actions', 'views-ui-display-tab-bucket', 'clearfix');
- $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',
- );
+ $plugin = views_fetch_plugin_data('display', $view->display[$display->id]->display_plugin);
+ // The following is for display purposes only. We need to determine if there is more than one button and wrap
+ // the buttons in a .ctools-dropbutton class if more than one is present. Otherwise, we'll just wrap the
+ // actions in the .ctools-button class.
+ $isDisplayDeleted = !empty($display->deleted);
+ $isDeletable = empty($plugin['no remove']);
+ // The master display cannot be cloned.
+ $isDefault = $display->id == 'default';
- $base_tables = array();
- foreach (views_fetch_base_tables() as $table => $info) {
- $base_tables[$table] = $info['title'] . '<div class="description">' . $info['description'] . '</div>';
+ if (!$isDisplayDeleted && $isDeletable && !$isDefault) {
+ $prefix = '<div class="ctools-button ctools-dropbutton"><div class="ctools-link"><a href="#" class="ctools-twisty ctools-text">open</a></div><div class="ctools-content"><ul class="horizontal right actions">';
+ $suffix = '</ul></div></div>';
+ $itemElement = 'li';
+ }
+ else {
+ $prefix = '<div class="ctools-button"><div class="ctools-content"><ul class="horizontal right actions">';
+ $suffix = '</ul></div></div>';
+ $itemElement = 'li';
}
- $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,
+ // The Delete, Duplicate and Undo Delete buttons.
+ $build['top']['actions'] = array(
+ '#prefix' => $prefix,
+ '#suffix' => $suffix,
);
- if ($view) {
- $form['base_table']['#disabled'] = TRUE;
+ if (!$isDisplayDeleted) {
+ if ($isDeletable) {
+ $build['top']['actions']['delete'] = array(
+ '#type' => 'submit',
+ '#value' => t('delete'),
+ '#limit_validation_errors' => array(),
+ '#submit' => array('views_ui_edit_form_submit_delete_display', 'views_ui_edit_form_submit_delay_destination'),
+ '#prefix' => '<' . $itemElement . ' class="delete">',
+ "#suffix" => '</' . $itemElement . '>',
+ );
+ }
+ if (!$isDefault) {
+ $build['top']['actions']['duplicate'] = array(
+ '#type' => 'submit',
+ '#value' => t('duplicate'),
+ '#limit_validation_errors' => array(),
+ '#submit' => array('views_ui_edit_form_submit_duplicate_display', 'views_ui_edit_form_submit_delay_destination'),
+ '#prefix' => '<' . $itemElement . ' class="duplicate">',
+ "#suffix" => '</' . $itemElement . '>',
+ );
+ }
+ }
+ else {
+ $build['top']['actions']['undo_delete'] = array(
+ '#type' => 'submit',
+ '#value' => t('undo delete'),
+ '#limit_validation_errors' => array(),
+ '#submit' => array('views_ui_edit_form_submit_undo_delete_display', 'views_ui_edit_form_submit_delay_destination'),
+ '#prefix' => '<' . $itemElement . ' class="undo-delete">',
+ "#suffix" => '</' . $itemElement . '>',
+ );
}
- $form['submit'] = array(
- '#type' => 'submit',
- '#value' => t('Next'),
- '#validate' => array('views_ui_add_form_validate'),
- '#submit' => array('views_ui_add_form_submit'),
+ // The area above the three columns.
+ $build['top']['display_title'] = array(
+ '#theme' => 'views_ui_display_tab_setting',
+ '#description' => t('Display name'),
+ '#link' => $display->handler->option_link(check_plain($display->display_title), 'display_title'),
);
- return $form;
-}
+ $build['columns'] = array();
+ $build['columns']['#theme_wrappers'] = array('container');
+ $build['columns']['#attributes'] = array('class' => array('clearfix', 'views-display-columns'));
+ $build['columns']['#id'] = 'edit-display-settings-main';
-/**
- * Validate the add view form.
- */
-function views_ui_add_form_validate($form, &$form_state) {
- $name = $form_state['values']['name'];
+ $build['columns']['first']['#theme_wrappers'] = array('container');
+ $build['columns']['first']['#attributes'] = array('class' => array('views-display-column', 'first'));
- // 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.'));
- }
+ $build['columns']['second']['#theme_wrappers'] = array('container');
+ $build['columns']['second']['#attributes'] = array('class' => array('views-display-column', 'second'));
- // 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.'));
+ $build['columns']['second']['settings'] = array();
+ $build['columns']['second']['header'] = array();
+ $build['columns']['second']['footer'] = array();
+ $build['columns']['second']['pager'] = array();
+
+ $build['columns']['third']['#theme_wrappers'] = array('container');
+ $build['columns']['third']['#attributes'] = array('class' => array('views-display-column', 'third'));
+
+ // Each option (e.g. title, access, display as grid/table/list) fits into one
+ // of several "buckets," or boxes (Format, Fields, Sort, and so on).
+ $buckets = array();
+
+ // Fetch options from the display plugin, with a list of buckets they go into.
+ $options = array();
+ $display->handler->options_summary($buckets, $options);
+
+ // Place each option into its bucket.
+ foreach ($options as $id => $option) {
+ // Each option self-identifies as belonging in a particular bucket.
+ $buckets[$option['category']]['build'][$id] = views_ui_edit_form_get_build_from_option($id, $option, $view, $display);
}
-}
-/**
- * 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->human_name = $form_state['values']['human_name'];
- $view->description = $form_state['values']['description'];
- $view->tag = $form_state['values']['tag'];
- $view->core = VERSION;
- if (empty($form['base_table']['#disabled'])) {
- $view->base_table = $form_state['values']['base_table'];
+ // Place each bucket into the proper column.
+ foreach ($buckets as $id => $bucket) {
+ // Let buckets identify themselves as belonging in a column.
+ if (isset($bucket['column']) && isset($build['columns'][$bucket['column']])) {
+ $column = $bucket['column'];
+ }
+ // If a bucket doesn't pick one of our predefined columns to belong to, put
+ // it in the last one.
+ else {
+ $column = 'third';
+ }
+ if (isset($bucket['build']) && is_array($bucket['build'])) {
+ $build['columns'][$column][$id] = $bucket['build'];
+ $build['columns'][$column][$id]['#theme_wrappers'][] = 'views_ui_display_tab_bucket';
+ $build['columns'][$column][$id]['#title'] = !empty($bucket['title']) ? $bucket['title'] : '';
+ }
}
- views_ui_cache_set($view);
- $form_state['redirect'] ='admin/structure/views/edit/' . $view->name;
+ // Fetch the style plugin info so we know whether to list fields or not.
+ $style_plugin = $display->handler->get_plugin();
+ $uses_fields = $style_plugin && $style_plugin->uses_fields();
+ if ($uses_fields) {
+ $build['columns']['first']['fields'] = views_ui_edit_form_get_bucket('field', $view, $display);
+ }
+ $build['columns']['first']['filters'] = views_ui_edit_form_get_bucket('filter', $view, $display);
+ $build['columns']['first']['sorts'] = views_ui_edit_form_get_bucket('sort', $view, $display);
+ $build['columns']['second']['header'] = views_ui_edit_form_get_bucket('header', $view, $display);
+ $build['columns']['second']['footer'] = views_ui_edit_form_get_bucket('footer', $view, $display);
+ $build['columns']['third']['arguments'] = views_ui_edit_form_get_bucket('argument', $view, $display);
+ $build['columns']['third']['relationships'] = views_ui_edit_form_get_bucket('relationship', $view, $display);
+ $build['columns']['third']['empty'] = views_ui_edit_form_get_bucket('empty', $view, $display);
+
+ return $build;
}
/**
- * Page to delete a view.
+ * Build a renderable array representing one option on the edit form.
+ *
+ * This function might be more logical as a method on an object, if a suitable
+ * object emerges out of refactoring.
*/
-function views_ui_delete_confirm($form, &$form_state, $view) {
- $form_state['view'] = &$view;
- $form = array();
+function views_ui_edit_form_get_build_from_option($id, $option, $view, $display) {
+ $option_build = array();
+ $option_build['#theme'] = 'views_ui_display_tab_setting';
- $cancel = 'admin/structure/views';
- if (!empty($_REQUEST['cancel'])) {
- $cancel = $_REQUEST['cancel'];
+ $option_build['#description'] = $option['title'];
+
+ $option_build['#link'] = $display->handler->option_link($option['value'], $id, '', empty($option['desc']) ? '' : $option['desc']);
+
+ $option_build['#links'] = array();
+ if (!empty($option['links']) && is_array($option['links'])) {
+ foreach ($option['links'] as $link_id => $link_value) {
+ $option_build['#settings_links'][] = $display->handler->option_link($option['setting'], $link_id, 'views-button-configure', $link_value);
+ }
}
- 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');
+ if (!empty($display->handler->options['defaults'][$id])) {
+ $display_id = 'default';
+ $option_build['#defaulted'] = TRUE;
}
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');
+ $display_id = $display->id;
+ if (!$display->handler->is_default_display()) {
+ if ($display->handler->defaultable_sections($id)) {
+ $option_build['#overridden'] = TRUE;
+ }
+ }
}
-
- return confirm_form($form,
- $title,
- $cancel,
- $desc,
- $button,
- t('Cancel'));
+ $option_build['#attributes']['class'][] = drupal_clean_css_identifier($display_id . '-' . $id);
+ if (!empty($view->changed_sections[$display_id . '-' . $id])) {
+ $option_build['#changed'] = TRUE;
+ }
+ return $option_build;
}
-/**
- * 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';
-}
+function template_preprocess_views_ui_display_tab_setting(&$variables) {
+ static $zebra = 0;
+ $variables['zebra'] = ($zebra % 2 === 0 ? 'odd' : 'even');
+ $zebra++;
-/**
- * Page to delete a view.
- */
-function views_ui_break_lock_confirm($form, &$form_state, $view) {
- $form_state['view'] = &$view;
- $form = array();
+ $variables['settings'] = implode($variables['settings_links']);
- if (empty($view->locked)) {
- return t('There is no lock on view %view to break.', array('%name' => $view->name));
+ // Add classes associated with this display tab to the overall list.
+ $variables['classes_array'] = array_merge($variables['classes_array'], $variables['class']);
+
+ // Append a colon to the description, if requested.
+ if ($variables['description'] && $variables['description_separator']) {
+ $variables['description'] .= t(':');
}
+}
- $cancel = 'admin/structure/views/edit/' . $view->name;
- if (!empty($_REQUEST['cancel'])) {
- $cancel = $_REQUEST['cancel'];
+function template_preprocess_views_ui_display_tab_bucket(&$variables) {
+ $element = $variables['element'];
+
+ $variables['item_help_icon'] = '';
+ if (!empty($element['#item_help_icon'])) {
+ $variables['item_help_icon'] = render($element['#item_help_icon']);
+ }
+ if (!empty($element['#name'])) {
+ $variables['classes_array'][] = drupal_clean_css_identifier(strtolower($element['#name']));
+ }
+ if (!empty($element['#overridden'])) {
+ $variables['classes_array'][] = 'overridden';
}
- $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'));
+ $variables['content'] = $element['#children'];
+ $variables['title'] = $element['#title'];
+ $variables['actions'] = !empty($element['#actions']) ? $element['#actions'] : '';
+}
+
+function template_preprocess_views_ui_display_tab_column(&$variables) {
+ $element = $variables['element'];
+
+ $variables['content'] = $element['#children'];
+ $variables['column'] = $element['#column'];
}
/**
- * Submit handler to break_lock a view.
+ * Move form elements into fieldsets for presentation purposes.
+ *
+ * Many views forms use #tree = TRUE to keep their values in a hierarchy for
+ * easier storage. Moving the form elements into fieldsets during form building
+ * would break up that hierarchy. Therefore, we wait until the pre_render stage,
+ * where any changes we make affect presentation only and aren't reflected in
+ * $form_state['values'].
*/
-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.'));
+function views_ui_pre_render_add_fieldset_markup($form) {
+ foreach (element_children($form) as $key) {
+ $element = $form[$key];
+ // In our form builder functions, we added an arbitrary #fieldset property
+ // to any element that belongs in a fieldset. If this form element has that
+ // property, move it into its fieldset.
+ if (isset($element['#fieldset']) && isset($form[$element['#fieldset']])) {
+ $form[$element['#fieldset']][$key] = $element;
+ // Remove the original element this duplicates.
+ unset($form[$key]);
+ }
+ }
+
+ return $form;
}
/**
- * The main view edit page
+ * Flattens the structure of an element containing the #flatten property.
+ *
+ * If a form element has #flatten = TRUE, then all of it's children
+ * get moved to the same level as the element itself.
+ * So $form['to_be_flattened'][$key] becomes $form[$key], and
+ * $form['to_be_flattened'] gets unset.
*/
-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;
+function views_ui_pre_render_flatten_data($form) {
+ foreach (element_children($form) as $key) {
+ $element = $form[$key];
+ if (!empty($element['#flatten'])) {
+ foreach (element_children($element) as $child_key) {
+ $form[$child_key] = $form[$key][$child_key];
+ }
+ // All done, remove the now-empty parent.
+ unset($form[$key]);
+ }
+ }
+
+ return $form;
}
/**
- * Export a view for cut & paste.
+ * Moves argument options into their place.
+ *
+ * When configuring the default argument behavior, almost each of the radio
+ * buttons has its own fieldset shown bellow it when the radio button is
+ * clicked. That fieldset is created through a custom form process callback.
+ * Each element that has #argument_option defined and pointing to a default
+ * behavior gets moved to the appropriate fieldset.
+ * So if #argument_option is specified as 'default', the element is moved
+ * to the 'default_options' fieldset.
*/
-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,
- );
+function views_ui_pre_render_move_argument_options($form) {
+ foreach (element_children($form) as $key) {
+ $element = $form[$key];
+ if (!empty($element['#argument_option'])) {
+ $container_name = $element['#argument_option'] . '_options';
+ if (isset($form['no_argument']['default_action'][$container_name])) {
+ $form['no_argument']['default_action'][$container_name][$key] = $element;
+ }
+ // Remove the original element this duplicates.
+ unset($form[$key]);
+ }
+ }
return $form;
}
/**
- * Import a view from cut & paste
+ * Custom form radios process function.
+ *
+ * Roll out a single radios element to a list of radios,
+ * using the options array as index.
+ * While doing that, create a container element underneath each option, which
+ * contains the settings related to that option.
+ *
+ * @see form_process_radios
+ */
+function views_ui_process_container_radios($element) {
+ if (count($element['#options']) > 0) {
+ foreach ($element['#options'] as $key => $choice) {
+ $element += array($key => array());
+ // Generate the parents as the autogenerator does, so we will have a
+ // unique id for each radio button.
+ $parents_for_id = array_merge($element['#parents'], array($key));
+
+ $element[$key] += array(
+ '#type' => 'radio',
+ '#title' => $choice,
+ // The key is sanitized in drupal_attributes() during output from the
+ // theme function.
+ '#return_value' => $key,
+ '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : NULL,
+ '#attributes' => $element['#attributes'],
+ '#parents' => $element['#parents'],
+ '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)),
+ '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
+ );
+ $element[$key . '_options'] = array(
+ '#type' => 'container',
+ '#attributes' => array('class' => array('views-admin-dependent')),
+ );
+ }
+ }
+ return $element;
+}
+
+/*
+ * Import a view from cut & paste.
*/
function views_ui_import_page($form, &$form_state) {
$form['name'] = array(
@@ -843,7 +1754,7 @@ function views_ui_import_page($form, &$form_state) {
}
/**
- * Validate handler to import a view
+ * Validate handler to import a view.
*/
function views_ui_import_validate($form, &$form_state) {
$view = '';
@@ -936,41 +1847,12 @@ function views_ui_import_validate($form, &$form_state) {
}
/**
- * Submit handler for view import
+ * 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;
+ $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->name . '/edit';
}
/**
@@ -1039,321 +1921,26 @@ function views_ui_edit_view_form_cancel($form, &$form_state) {
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);
- $form = drupal_get_form('views_ui_reorder_displays_button', $view);
- $reorder_button = drupal_render($form);
- $tabs->add_extra($display_button . $reorder_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(
- 'views-export' => array(
- 'title' => t('Export'),
- 'attributes' => array('title' => t("Export this view")),
- 'href' => "admin/structure/views/export/$view->name",
- ),
- 'views-clone' => array(
- 'title' => t('Clone'),
- 'attributes' => array('title' => 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']['views-view-' . $display->id] = array(
- 'title' => t('View "@display"', array('@display' => $display->display_title)),
- 'attributes' => array('title' => 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_library('system', 'jquery.form');
-
- // 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 this 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;
- }
-
- foreach (array('human_name', 'tag', 'description') as $property) {
- if (!empty($view->changed_sections[$property])) {
- $vars['details_changed'][$property] = TRUE;
- }
- switch ($property) {
- case 'human_name':
- $title = t('Human name');
- break;
- case 'tag':
- $title = t('Tag');
- break;
- case 'description':
- $title = t('Description');
- break;
- }
- $value = empty($view->{$property}) ? t('None') : check_plain($view->{$property});
- $vars['details'][$property] = $title . ': ' . l($value, "admin/structure/views/nojs/$property/$view->name", array('attributes' => array('class' => 'views-ajax-link')));
- }
-
- // 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', 'view' => $view, 'display' => $display, 'no_fields' => !($style_plugin && $style_plugin->uses_fields())));
- $vars['relationships'] = theme('views_ui_edit_item', array('type' => 'relationship', 'view' => $view, 'display' => $display));
- $vars['arguments'] = theme('views_ui_edit_item', array('type' => 'argument', 'view' => $view, 'display' => $display));
- $vars['filters'] = theme('views_ui_edit_item', array('type' => 'filter', 'view' => $view, 'display' => $display));
- $vars['sorts'] = theme('views_ui_edit_item', array('type' => 'sort', 'view' => $view, 'display' => $display));
-}
-
-/**
- * Generate the summary output for a single display to render in a tab.
- */
-function views_ui_display_tab($view, $display) {
- if (isset($display->handler)) {
- $plugin = $display->handler->definition;
- }
- if (empty($plugin)) {
- $title = isset($display->display_title) ? $display->display_title : t('Invalid');
- return array($title, t("Error: Display @display refers to a plugin named '@plugin', but that plugin doesn't exist!", array('@display' => $display->id, '@plugin' => $display->display_plugin)));
-
- // @todo We can do a better 'plugin does not exist' tab.
- }
-
- // The display should always be initialized prior to this call.
- if (empty($display->handler)) {
- return FALSE;
- }
-
- $body = theme('views_ui_edit_tab', array('view' => $view, 'display' => $display));
- return array($display->display_title, $body);
+ $form_state['redirect'] = array('admin/structure/views/view/' . $form_state['view']->name . '/delete', array('query' => drupal_get_destination() + array('cancel' => 'admin/structure/views/view/' . $form_state['view']->name . '/edit')));
}
/**
* Add information about a section to a display.
*/
-function template_preprocess_views_ui_edit_item(&$vars) {
- $type = $vars['type'];
- $view = $vars['view'];
- $display = $vars['display'];
-
+function views_ui_edit_form_get_bucket($type, $view, $display) {
+ $build = array(
+ '#theme_wrappers' => array('views_ui_display_tab_bucket'),
+ );
$types = views_object_types();
- $vars['overridden'] = FALSE;
- $vars['defaulted'] = FALSE;
- $vars['item_help_icon'] = module_exists('advanced_help') ? theme('advanced_help_topic', array('module' => 'views', 'topic' => $type)) : '';
-
- if ($vars['no_fields']) {
- $vars['title'] = $types[$type]['title'];
- $vars['rearrange'] = NULL;
- $vars['add'] = NULL;
- return;
+ $build['#overridden'] = FALSE;
+ $build['#defaulted'] = FALSE;
+ if (module_exists('advanced_help')) {
+ $build['#item_help_icon'] = array(
+ '#theme' => 'advanced_help_topic',
+ '#module' => 'views',
+ '#topic' => $type,
+ );
}
// Different types now have different rearrange forms, so we use this switch
@@ -1361,32 +1948,68 @@ function template_preprocess_views_ui_edit_item(&$vars) {
switch ($type) {
case 'filter':
$rearrange_url = "admin/structure/views/nojs/rearrange-$type/$view->name/$display->id/$type";
+ $rearrange_text = t('And/Or');
+ // TODO: Add another class to have another symbol for filter rearrange.
+ $class = 'icon compact rearrange';
break;
default:
$rearrange_url = "admin/structure/views/nojs/rearrange/$view->name/$display->id/$type";
+ $rearrange_text = t('Sort');
+ $class = 'icon compact rearrange';
+ }
+
+ // Create an array of actions to pass to theme_links
+ $actions = array();
+ $count_handlers = count($display->handler->get_handlers($type));
+ if ($count_handlers > 1) {
+ $actions['rearrange'] = array(
+ 'title' => $rearrange_text,
+ 'href' => $rearrange_url,
+ 'attributes' => array('class' => array($class, 'views-ajax-link'), 'title' => t('Rearrange'), 'id' => 'views-rearrange-' . $type),
+ 'html' => TRUE,
+ );
}
-
- $vars['rearrange'] = l('<span>' . t('Rearrange') . '</span>', $rearrange_url, array('attributes' => array('class' => array('views-button-rearrange', 'views-ajax-link'), 'title' => t('Rearrange')), 'html' => TRUE));
-
- $vars['add'] = l('<span>' . t('Add') . '</span>', "admin/structure/views/nojs/add-item/$view->name/$display->id/$type", array('attributes' => array('class' => array('views-button-add', 'views-ajax-link'), 'title' => t('Add'), 'id' => 'views-add-' . $type), 'html' => true));
+ $actions['add'] = array(
+ 'title' => t('Add'),
+ 'href' => "admin/structure/views/nojs/add-item/$view->name/$display->id/$type",
+ 'attributes'=> array('class' => array('icon compact add', 'views-ajax-link'), 'title' => t('Add'), 'id' => 'views-add-' . $type),
+ 'html' => TRUE,
+ );
+ if ($count_handlers > 0) {
+ $actions['delete'] = array(
+ 'title' => t('Delete'),
+ 'href' => "admin/structure/views/nojs/delete-item/$view->name/$display->id/$type",
+ 'attributes' => array('class' => array('icon compact delete', 'views-ajax-link'), 'title' => t('delete'), 'id' => 'views-delete-' . $type),
+ 'html' => TRUE,
+ );
+ }
+
+ // Render the array of links
+ $build['#actions'] = theme('links__ctools_dropbutton',
+ array(
+ 'links' => $actions,
+ 'attributes' => array(
+ 'class' => array('inline', 'links', 'actions', 'horizontal', 'right')
+ ),
+ 'class' => array('views-ui-settings-bucket-operations'),
+ )
+ );
if (!$display->handler->is_default_display()) {
if (!$display->handler->is_defaulted($types[$type]['plural'])) {
- $vars['overridden'] = TRUE;
+ $build['#overridden'] = TRUE;
}
else {
- $vars['defaulted'] = TRUE;
+ $build['#defaulted'] = TRUE;
}
}
- if ($display->display_plugin != 'default') {
- $vars['title'] = l($types[$type]['title'], "admin/structure/views/nojs/config-type/$view->name/$display->id/$type", array('attributes' => array('class' => array('views-ajax-link'), 'id' => 'views-title-' . $type)));
- }
- else {
- $vars['title'] = $types[$type]['title'];
- }
+ $build['#name'] = $build['#title'] = $types[$type]['title'];
- $fields = array();
+ // If there's an options form for the bucket, link to it.
+ if (!empty($types[$type]['options'])) {
+ $build['#title'] = l($build['#title'], "admin/structure/views/nojs/config-type/$view->name/$display->id/$type", array('attributes' => array('class' => array('views-ajax-link'), 'id' => 'views-title-' . $type)));
+ }
static $relationships = NULL;
if (!isset($relationships)) {
@@ -1407,21 +2030,27 @@ function template_preprocess_views_ui_edit_item(&$vars) {
$grouping = FALSE;
if ($type == 'filter') {
$group_info = $view->display_handler->get_option('filter_groups');
- if (!empty($group_info['groups']) && count($group_info['groups']) > 1) {
+ // If there is only one group but it is using the "OR" filter, we still
+ // treat it as a group for display purposes, since we want to display the
+ // "OR" label next to items within the group.
+ if (!empty($group_info['groups']) && (count($group_info['groups']) > 1 || current($group_info['groups']) == 'OR')) {
$grouping = TRUE;
$groups = array(0 => array());
}
}
+ $build['fields'] = array();
+
foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) {
- $fields[$id] = array();
+ // Build the option link for this handler ("Node: ID = article").
+ $build['fields'][$id] = array();
+ $build['fields'][$id]['#theme'] = 'views_ui_display_tab_setting';
$handler = $display->handler->get_handler($type, $id);
if (empty($handler)) {
- $fields[$id]['class'][] = 'broken';
+ $build['fields'][$id]['#class'][] = 'broken';
$field_name = t('Broken/missing handler: @table > @field', array('@table' => $field['table'], '@field' => $field['field']));
- $fields[$id]['title'] = l($field_name, "admin/structure/views/nojs/config-item/$view->name/$display->id/$type/$id", array('attributes' => array('class' => array('views-ajax-link')), 'html' => TRUE));
- $fields[$id]['info'] = '';
+ $build['fields'][$id]['#link'] = l($field_name, "admin/structure/views/nojs/config-item/$view->name/$display->id/$type/$id", array('attributes' => array('class' => array('views-ajax-link')), 'html' => TRUE));
continue;
}
@@ -1430,36 +2059,23 @@ function template_preprocess_views_ui_edit_item(&$vars) {
$field_name = '(' . $relationships[$field['relationship']] . ') ' . $field_name;
}
- $fields[$id]['title'] = l($field_name, "admin/structure/views/nojs/config-item/$view->name/$display->id/$type/$id", array('attributes' => array('class' => array('views-ajax-link')), 'html' => TRUE));
- $fields[$id]['class'][] = drupal_clean_css_identifier($display->id . '-' . $type . '-' . $id);
+ $description = $handler->admin_summary();
+ $link_text = $field_name . (empty($description) ? '' : " ($description)");
+ $build['fields'][$id]['#link'] = l($link_text, "admin/structure/views/nojs/config-item/$view->name/$display->id/$type/$id", array('attributes' => array('class' => array('views-ajax-link')), 'html' => TRUE));
+ $build['fields'][$id]['#class'][] = drupal_clean_css_identifier($display->id . '-' . $type . '-' . $id);
if (!empty($view->changed_sections[$display->id . '-' . $type . '-' . $id])) {
- $fields[$id]['changed'] = TRUE;
+ // @TODO: #changed is no longer being used?
+ $build['fields'][$id]['#changed'] = TRUE;
}
- $fields[$id]['info'] = $handler->admin_summary();
if ($display->handler->use_group_by()) {
- $fields[$id]['links'] = l('<span>' . t('Group settings') . '</span>', "admin/structure/views/nojs/config-item-group/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-button-configure views-ajax-link', 'title' => t('Group settings')), 'html' => true));
+ // @TODO: #links is no longer being used?
+ $build['fields'][$id]['#links'][] = l('<span>' . t('Group settings') . '</span>', "admin/structure/views/nojs/config-item-group/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-button-configure views-ajax-link', 'title' => t('Group settings')), 'html' => true));
}
if ($handler->has_extra_options()) {
- $fields[$id]['links'] = l('<span>' . t('Settings') . '</span>', "admin/structure/views/nojs/config-item-extra/$view->name/$display->id/$type/$id", array('attributes' => array('class' => array('views-button-configure', 'views-ajax-link'), 'title' => t('Settings')), 'html' => true));
- }
-
- if ($handler->needs_style_plugin()) {
- $style_plugin = views_fetch_plugin_data('style', $handler->options['style_plugin']);
- $style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin['title'];
- $pid = $id . '-style-plugin';
-
- if (!empty($style_plugin['uses options'])) {
- $fields[$pid]['links'] = l('<span>' . t('Change settings for this style') . '</span>', "admin/structure/views/nojs/config-style/$view->name/$display->id/$type/$id", array('attributes' => array('class' => array('views-button-configure', 'views-ajax-link'), 'title' => t('Settings')), 'html' => true));
- }
-
- $fields[$pid]['title'] = ' ' . t('&nbsp; Style: !style', array('!style' => l($style_title, "admin/structure/views/nojs/change-style/$view->name/$display->id/$type/$id", array('attributes' => array('class' => array('views-ajax-link'))))));
- $fields[$pid]['class'][] = drupal_clean_css_identifier($display->id . '-' . $type . '-' . $pid);
- if (!empty($view->changed_sections[$display->id . '-' . $type . '-' . $pid])) {
- $fields[$pid]['changed'] = TRUE;
- }
- $fields[$pid]['info'] = '';
+ // @TODO: #links is no longer being used?
+ $build['fields'][$id]['#links'][] = l('<span>' . t('Settings') . '</span>', "admin/structure/views/nojs/config-item-extra/$view->name/$display->id/$type/$id", array('attributes' => array('class' => array('views-button-configure', 'views-ajax-link'), 'title' => t('Settings')), 'html' => true));
}
if ($grouping) {
@@ -1475,73 +2091,51 @@ function template_preprocess_views_ui_edit_item(&$vars) {
// If using grouping, re-order fields so that they show up properly in the list.
if ($type == 'filter' && $grouping) {
- $store = $fields;
- $fields = array();
+ $store = $build['fields'];
+ $build['fields'] = array();
foreach ($groups as $gid => $contents) {
- if (!empty($fields)) {
- $operator = ') ' . ($group_info['operator'] == 'OR' ? t('OR') : t('AND')) . ' (';
- }
- else {
- $operator = '(';
+ // Display an operator between each group.
+ if (!empty($build['fields'])) {
+ $build['fields'][] = array(
+ '#theme' => 'views_ui_display_tab_setting',
+ '#class' => array('views-group-text'),
+ '#link' => ($group_info['operator'] == 'OR' ? t('OR') : t('AND')),
+ );
}
- $fields[] = array(
- 'class' => 'views-group-text',
- 'title' => $operator,
- 'info' => '',
- );
- $started = FALSE;
- foreach ($contents as $pid) {
- $operator = '&nbsp;&nbsp;';
- if ($started) {
- $operator .= ($group_info['groups'][$gid] == 'OR' ? t('OR') : t('AND')) . ' ';
+ // Display an operator between each pair of filters within the group.
+ $keys = array_keys($contents);
+ $last = end($keys);
+ foreach ($contents as $key => $pid) {
+ if ($key != $last) {
+ $store[$pid]['#link'] .= '&nbsp;&nbsp;' . ($group_info['groups'][$gid] == 'OR' ? t('OR') : t('AND'));
}
- $store[$pid]['title'] = $operator . $store[$pid]['title'];
- $started = TRUE;
- $fields[$pid] = $store[$pid];
+ $build['fields'][$pid] = $store[$pid];
}
}
- $fields[] = array(
- 'class' => 'views-group-text',
- 'title' => ')',
- 'info' => '',
- );
}
- $vars['fields'] = $fields;
+ return $build;
}
/**
- * Regenerate the tabs for AJAX updates.
+ * Regenerate the current tab for AJAX updates.
*/
-function views_ui_regenerate_tabs(&$view, &$output, $display_id = NULL) {
- if (empty($display_id)) {
- $displays = array_keys($view->display);
- }
- elseif (!is_array($display_id)) {
- $displays = array($display_id);
- if ($display_id != 'default') {
- $displays[] = 'default';
- }
- }
- else {
- $displays = $display_id;
- }
-
+function views_ui_regenerate_tab(&$view, &$output, $display_id) {
if (!$view->set_display('default')) {
return;
}
- foreach ($displays as $id) {
- list($title, $body) = views_ui_display_tab($view, $view->display[$id]);
- $output[] = ajax_command_html('#views-tab-' . $id, $body);
- $output[] = ajax_command_html('#views-tab-title-' . $id, check_plain($title));
- }
+ $build = views_ui_get_display_tab($view, $display_id);
+ $output[] = ajax_command_html('#views-tab-' . $display_id, drupal_render($build));
}
/**
- * Provide standard buttons for the forms to make it easy. Also provide
+ * Provide a standard set of Apply/Cancel/OK buttons for the forms. Also provide
* a hidden op operator because the forms plugin doesn't seem to properly
* provide which button was clicked.
+ *
+ * TODO: Is the hidden op operator still here somewhere, or is that part of the
+ * docblock outdated?
*/
function views_ui_standard_form_buttons(&$form, &$form_state, $form_id, $name = NULL, $third = NULL, $submit = NULL) {
$form['buttons'] = array(
@@ -1550,36 +2144,46 @@ function views_ui_standard_form_buttons(&$form, &$form_state, $form_id, $name =
);
if (empty($name)) {
- $name = t('Update');
- }
-
- // Add the override and update button
- if ($name == t('Update default display')) {
- $form['buttons']['override_update'] = array(
- '#type' => 'submit',
- '#value' => t('Update and override'),
- '#submit' => array(
- 'views_ui_edit_display_form_override_update_section',
- 'views_ui_standard_submit',
- 'views_ui_edit_display_form_override_update',
- ),
- );
+ $name = t('Apply');
+ $view = $form_state['view'];
+ if (!empty($view->stack) && count($view->stack) > 1) {
+ $name = t('Apply and continue');
+ }
+ $names = array(t('Apply'), t('Apply and continue'));
}
+ // Forms that are purely informational set an ok_button flag, so we know not
+ // to create an "Apply" button for them.
if (empty($form_state['ok_button'])) {
- // but be sure submit button validates!
$form['buttons']['submit'] = array(
'#type' => 'submit',
'#value' => $name,
- '#submit' => array('views_ui_standard_submit', $form_id . '_submit'),
+ // The regular submit handler ($form_id . '_submit') does not apply if
+ // we're updating the default display. It does apply if we're updating
+ // the current display. Since we have no way of knowing at this point
+ // which display the user wants to update, views_ui_standard_submit will
+ // take care of running the regular submit handler as appropriate.
+ '#submit' => array('views_ui_standard_submit'),
);
- // Take sure that the validation handler exists.
+ // Form API button click detection requires the button's #value to be the
+ // same between the form build of the initial page request, and the initial
+ // form build of the request processing the form submission. Ideally, the
+ // button's #value shouldn't change until the form rebuild step. However,
+ // views_ui_ajax_form() implements a different multistep form workflow than
+ // the Form API does, and adjusts $view->stack prior to form processing, so
+ // we compensate by extending button click detection code to support any of
+ // the possible button labels.
+ if (isset($names)) {
+ $form['buttons']['submit']['#values'] = $names;
+ $form['buttons']['submit']['#process'] = array_merge(array('views_ui_form_button_was_clicked'), element_info_property($form['buttons']['submit']['#type'], '#process', array()));
+ }
+ // If a validation handler exists for the form, assign it to this button.
if (function_exists($form_id . '_validate')) {
$form['buttons']['submit']['#validate'][] = $form_id . '_validate';
}
-
}
+ // Create a "Cancel" button. For purely informational forms, label it "OK".
$cancel_submit = function_exists($form_id . '_cancel') ? $form_id . '_cancel' : 'views_ui_standard_cancel';
$form['buttons']['cancel'] = array(
'#type' => 'submit',
@@ -1588,6 +2192,7 @@ function views_ui_standard_form_buttons(&$form, &$form_state, $form_id, $name =
'#validate' => array(),
);
+ // Some forms specify a third button, with a name and submit handler.
if ($third) {
if (empty($submit)) {
$submit = 'third';
@@ -1602,7 +2207,7 @@ function views_ui_standard_form_buttons(&$form, &$form_state, $form_id, $name =
);
}
- // Compatibility, to be removed later:
+ // Compatibility, to be removed later: // TODO: When is "later"?
// We used to set these items on the form, but now we want them on the $form_state:
if (isset($form['#title'])) {
$form_state['title'] = $form['#title'];
@@ -1634,18 +2239,79 @@ function views_ui_standard_form_buttons(&$form, &$form_state, $form_id, $name =
if (!empty($form['#title'])) {
drupal_set_title($form['#title']);
}
- $form['#attached']['css'] = array(
- drupal_get_path('module', 'views') . "/css/views-admin.css",
- );
}
/**
- * Basic submit handler applicable to all 'standard' forms
+ * Basic submit handler applicable to all 'standard' forms.
+ *
+ * This submit handler determines whether the user wants the submitted changes
+ * to apply to the default display or to the current display, and dispatches
+ * control appropriately.
*/
function views_ui_standard_submit($form, &$form_state) {
+ // Determine whether the values the user entered are intended to apply to
+ // the current display or the default display.
+
+ // Make sure the dropdown exists in the first place.
+ if (isset($form_state['values']['override']['dropdown'])) {
+ $was_defaulted = (bool) ($form['override']['dropdown']['#default_value'] === 'defaults');
+ $is_defaulted = (bool) ($form_state['values']['override']['dropdown'] === 'default');
+
+ if ($was_defaulted !== $is_defaulted && isset($form['#section'])) {
+ // We're changing which display these values apply to.
+ // Update the #section so it knows what to mark changed.
+ $form['#section'] = str_replace('default-', $form_state['display_id'] . '-', $form['#section']);
+ }
+ }
+ else {
+ // The user didn't get the dropdown for overriding the default display.
+ $was_defaulted = FALSE;
+ $is_defaulted = FALSE;
+ }
+
+ // Mark the changed section of the view as changed.
+ // TODO: Document why we are doing this, and see if we still need it.
if (!empty($form['#section'])) {
$form_state['view']->changed_sections[$form['#section']] = TRUE;
}
+
+ // Based on the user's choice in the display dropdown, determine which display
+ // these changes apply to.
+ if ($was_defaulted === $is_defaulted) {
+ // We're not changing which display these form values apply to.
+ // Run the regular submit handler for this form.
+ $submit_handler = $form['#form_id'] . '_submit';
+ if (function_exists($submit_handler)) {
+ $submit_handler($form, $form_state);
+ }
+ }
+ elseif ($was_defaulted && !$is_defaulted) {
+ // We were using the default display's values, but we're now overriding
+ // the default display and saving values specific to this display.
+ // TODO: Document why the regular form submit handler isn't necessary in
+ // this case.
+ $display = &$form_state['view']->display[$form_state['display_id']];
+ $display->handler->options_override($form, $form_state);
+ $display->handler->options_submit($form, $form_state);
+ views_ui_cache_set($form_state['view']);
+ }
+ elseif (!$was_defaulted && $is_defaulted) {
+ // We used to have an override for this display, but the user now wants
+ // to go back to the default display.
+ // Overwrite the default display with the current form values, and make
+ // the current display use the new default values.
+ $display = &$form_state['view']->display[$form_state['display_id']];
+ $display->handler->options_override($form, $form_state);
+ $display->handler->options_submit($form, $form_state);
+
+ // TODO: This is copy/paste code. Refactor.
+ $submit_handler = $form['#form_id'] . '_submit';
+ if (function_exists($submit_handler)) {
+ $submit_handler($form, $form_state);
+ }
+
+ views_ui_cache_set($form_state['view']);
+ }
}
/**
@@ -1657,9 +2323,99 @@ function views_ui_standard_cancel($form, &$form_state) {
views_ui_cache_set($form_state['view']);
}
- $form_state['redirect'] = 'admin/structure/views/edit/' . $form_state['view']->name;
+ $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->name . '/edit';
+}
+
+/**
+ * Add a <select> dropdown for a given section, allowing the user to
+ * change whether this info is stored on the default display or on
+ * the current display.
+ */
+function views_ui_standard_display_dropdown(&$form, &$form_state, $section) {
+ $view = &$form_state['view'];
+ $display_id = $form_state['display_id'];
+ $displays = $view->display;
+ $current_display = $view->display[$display_id];
+
+ // Add the "2 of 3" progress indicator.
+ // @TODO: Move this to a separate function if it's needed on any forms that
+ // don't have the display dropdown.
+ if ($form_progress = views_ui_get_form_progress($view)) {
+ $form['progress']['#markup'] = '<div id="views-progress-indicator">' . t('@current of @total', array('@current' => $form_progress['current'], '@total' => $form_progress['total'])) . '</div>';
+ $form['progress']['#weight'] = -1001;
+ }
+
+ if ($current_display->handler->is_default_display()) {
+ return;
+ }
+
+ // Determine whether any other displays have overrides for this section.
+ $section_overrides = FALSE;
+ foreach ($displays as $id => $display) {
+ if ($id === 'default' || $id === $display_id) {
+ continue;
+ }
+ if ($display->handler && !$display->handler->is_defaulted($section)) {
+ $section_overrides = TRUE;
+ }
+ }
+
+ $display_dropdown['default'] = ($section_overrides ? t('All displays (except overridden)') : t('All displays'));
+ $display_dropdown[$display_id] = t('This @display_type (override)', array('@display_type' => $current_display->display_plugin));
+
+ $form['override'] = array(
+ '#prefix' => '<div class="views-override clearfix container-inline">',
+ '#suffix' => '</div>',
+ '#weight' => -1000,
+ '#tree' => TRUE,
+ );
+ $form['override']['dropdown'] = array(
+ '#type' => 'select',
+ '#title' => t('For'), // @TODO: Translators may need more context than this.
+ '#options' => $display_dropdown,
+ );
+ if ($current_display->handler->is_defaulted($section)) {
+ $form['override']['dropdown']['#default_value'] = 'defaults';
+ }
+ else {
+ $form['override']['dropdown']['#default_value'] = $display_id;
+ }
+
+}
+
+/**
+ * Get the user's current progress through the form stack.
+ *
+ * @param $view
+ * The current view.
+ *
+ * @return
+ * FALSE if the user is not currently in a multiple-form stack. Otherwise,
+ * an associative array with the following keys:
+ * - current: The number of the current form on the stack.
+ * - total: The total number of forms originally on the stack.
+ */
+function views_ui_get_form_progress($view) {
+ $progress = FALSE;
+ if (!empty($view->stack)) {
+ $stack = $view->stack;
+ // The forms on the stack have integer keys that don't change as the forms
+ // are completed, so we can see which ones are still left.
+ $keys = array_keys($view->stack);
+ // Add 1 to the array keys for the benefit of humans, who start counting
+ // from 1 and not 0.
+ $current = reset($keys) + 1;
+ $total = end($keys) + 1;
+ if ($total > 1) {
+ $progress = array();
+ $progress['current'] = $current;
+ $progress['total'] = $total;
+ }
+ }
+ return $progress;
}
+
// --------------------------------------------------------------------------
// Various subforms for editing the pieces of a view.
@@ -1681,6 +2437,10 @@ function views_ui_ajax_forms($key = NULL) {
'form_id' => 'views_ui_rearrange_form',
'args' => array('type'),
),
+ 'delete-item' => array(
+ 'form_id' => 'views_ui_item_delete_form',
+ 'args' => array('type'),
+ ),
'rearrange-filter' => array(
'form_id' => 'views_ui_rearrange_filter_form',
'args' => array('type'),
@@ -1701,10 +2461,6 @@ function views_ui_ajax_forms($key = NULL) {
'form_id' => 'views_ui_config_item_group_form',
'args' => array('type', 'id'),
),
- 'change-style' => array(
- 'form_id' => 'views_ui_change_style_form',
- 'args' => array('type', 'id'),
- ),
'config-style' => array(
'form_id' => 'views_ui_config_style_form',
'args' => array('type', 'id'),
@@ -1721,7 +2477,7 @@ function views_ui_ajax_forms($key = NULL) {
/**
* Build a form identifier that we can use to see if one form
* is the same as another. Since the arguments differ slightly
- * we do a lot of spiffy concenation here.
+ * we do a lot of spiffy concatenation here.
*/
function views_ui_build_identifier($key, $view, $display_id, $args) {
$form = views_ui_ajax_forms($key);
@@ -1775,8 +2531,8 @@ function views_ui_build_form_url($form_state) {
}
/**
- * Add another form to the stack; clicking 'update' will go to this form
- * rather than closing the ajax pad.
+ * Add another form to the stack; clicking 'apply' will go to this form
+ * rather than closing the ajax popup.
*/
function views_ui_add_form_to_stack($key, &$view, $display_id, $args, $top = FALSE) {
if (empty($view->stack)) {
@@ -1784,11 +2540,30 @@ function views_ui_add_form_to_stack($key, &$view, $display_id, $args, $top = FAL
}
$stack = array(views_ui_build_identifier($key, $view, $display_id, $args), $key, &$view, $display_id, $args);
- if ($top) {
- array_unshift($view->stack, $stack);
+ // If we're being asked to add this form to the bottom of the stack, no
+ // special logic is required. Our work is equally easy if we were asked to add
+ // to the top of the stack, but there's nothing in it yet.
+ if (!$top || empty($view->stack)) {
+ $view->stack[] = $stack;
}
+ // If we're adding to the top of an existing stack, we have to maintain the
+ // existing integer keys, so they can be used for the "2 of 3" progress
+ // indicator (which will now read "2 of 4").
else {
- $view->stack[] = $stack;
+ $keys = array_keys($view->stack);
+ $first = current($keys);
+ $last = end($keys);
+ for ($i = $last; $i >= $first; $i--) {
+ if (!isset($view->stack[$i])) {
+ continue;
+ }
+ // Move form number $i to the next position in the stack.
+ $view->stack[$i + 1] = $view->stack[$i];
+ unset($view->stack[$i]);
+ }
+ // Now that the previously $first slot is free, move the new form into it.
+ $view->stack[$first] = $stack;
+ ksort($view->stack);
}
}
@@ -1823,7 +2598,12 @@ function views_ui_ajax_form($js, $key, $view, $display_id) {
// now irrelevant.
if (!empty($view->stack)) {
$identifier = views_ui_build_identifier($key, $view, $display_id, $args);
- $top = array_shift($view->stack);
+ // Retrieve the first form from the stack without changing the integer keys,
+ // as they're being used for the "2 of 3" progress indicator.
+ reset($view->stack);
+ list($key, $top) = each($view->stack);
+ unset($view->stack[$key]);
+
if (array_shift($top) != $identifier) {
$view->stack = array();
}
@@ -1836,11 +2616,19 @@ function views_ui_ajax_form($js, $key, $view, $display_id) {
unset($view->form_cache);
}
+ // With the below logic, we may end up rendering a form twice (or two forms
+ // each sharing the same element ids), potentially resulting in
+ // drupal_add_js() being called twice to add the same setting. drupal_get_js()
+ // is ok with that, but until ajax_render() is (http://drupal.org/node/208611),
+ // reset the drupal_add_js() static before rendering the second time.
+ $drupal_add_js_original = drupal_add_js();
+ $drupal_add_js = &drupal_static('drupal_add_js');
$output = views_ajax_form_wrapper($form_state['form_id'], $form_state);
if ($form_state['submitted'] && empty($form_state['rerender'])) {
// Sometimes we need to re-generate the form for multi-step type operations.
$object = NULL;
if (!empty($view->stack)) {
+ $drupal_add_js = $drupal_add_js_original;
$stack = $view->stack;
$top = array_shift($stack);
$top[0] = $js;
@@ -1854,232 +2642,21 @@ function views_ui_ajax_form($js, $key, $view, $display_id) {
}
elseif (!$js) {
// if nothing on the stack, non-js forms just go back to the main view editor.
- return drupal_goto("admin/structure/views/edit/$view->name");
+ return drupal_goto("admin/structure/views/view/$view->name/edit");
}
else {
$output = array();
- $output[] = views_ajax_command_enable_buttons();
$output[] = views_ajax_command_dismiss_form();
+ $output[] = views_ajax_command_show_buttons();
$output[] = views_ajax_command_trigger_preview();
}
- views_ui_regenerate_tabs($view, $output);
- }
- elseif ($js) {
- $output[] = views_ajax_command_disable_buttons();
+ views_ui_regenerate_tab($view, $output, $display_id);
}
return $js ? array('#type' => 'ajax', '#commands' => $output) : $output;
}
/**
- * AJAX callback to add a display.
- */
-function views_ui_add_display($js, $view) {
- views_include('ajax');
- $form_state = array(
- 'view' => &$view,
- 'ajax' => $js,
- );
-
- $output = views_ajax_form_wrapper('views_ui_add_display_form', $form_state);
-
- if ($js) {
- if ($form_state['submitted']) {
- $id = $form_state['id'];
-
- // Make sure the new display is active
- if (!$view->set_display('default')) {
- views_ajax_error(t('Unable to initialize default display'));
- }
-
- // Render the new display
- list($title, $body) = views_ui_display_tab($view, $view->display[$id]);
-
- // Instruct the javascript on the browser to render the new tab.
- $output = array();
- $output[] = views_ajax_command_add_tab($id, $title, $body);
- }
- $output = array('#type' => 'ajax', '#commands' => $output);
- }
-
- // But the non-js variant will return output if it didn't redirect us.
- return $output;
-}
-
-/**
- * Form to add a display to a view.
- */
-function views_ui_add_display_form($form, &$form_state) {
- $view = &$form_state['view'];
-
- $form['display']['display'] = array(
- '#type' => 'select',
- '#options' => views_fetch_plugin_names('display'),
- '#default_value' => 'page',
- );
-
- $form['display']['add_display'] = array(
- '#type' => 'submit',
- '#value' => t('Add display'),
- '#ajax' => array(
- 'path' => "admin/structure/views/ajax/add-display/$view->name",
- ),
- '#submit' => array('views_ui_add_display_form_submit'),
- );
-
- $form['#id'] = 'views-add-display-form';
- $form['#attributes'] = array('class' => array('views-ajax-form'));
- $form['#action'] = url("admin/structure/views/nojs/add-display/$view->name");
-
- return $form;
-}
-
-/**
- * Submit handler to add a display to a view.
- */
-function views_ui_add_display_form_submit($form, &$form_state) {
- // Create the new display
- $plugin = $form_state['values']['display'];
- $form_state['id'] = $form_state['view']->add_display($plugin);
-
- // Store in cache
- views_ui_cache_set($form_state['view']);
-
- // Send it back
- $form_state['redirect'] = array('admin/structure/views/edit/' . $form_state['view']->name, array('fragment' => 'views-tab-' . $form_state['id']));
-}
-
-/**
- * AJAX callback to add a display.
- */
-function views_ui_clone_display($js, $view, $id) {
- views_include('ajax');
- $form_state = array(
- 'view' => &$view,
- 'ajax' => $js,
- 'display_id' => $id,
- );
-
- $output = views_ajax_form_wrapper('views_ui_clone_display_form', $form_state);
-
- if ($js) {
- // If we don't have an output object, it was submitted. Set up the submission.
- if (empty($output)) {
- $id = $form_state['id'];
-
- // Make sure the new display is active
- if (!$view->set_display('default')) {
- views_ajax_render(t('Unable to initialize default display'));
- }
-
- // Render the new display
- list($title, $body) = views_ui_display_tab($view, $view->display[$id]);
-
- // Instruct the javascript on the browser to render the new tab.
- $output = new stdClass;
- $output->tab = array('#views-tab-' . $id => array('title' => $title, 'body' => $body));
- }
- // Render the command object. This automatically exits.
- views_ajax_render($output);
- }
-
- // But the non-js variant will return output if it didn't redirect us.
- return $output;
-}
-
-/**
- * From to clone a display from a view.
- */
-function views_ui_clone_display_form($form, &$form_state) {
- $view = &$form_state['view'];
- $display_id = $form_state['display_id'];
-
- $form['clone_display'] = array(
- '#type' => 'submit',
- '#value' => t('Clone display'),
- '#submit' => array('views_ui_clone_display_form_submit'),
- );
-
- $form['#id'] = 'views-clone-display-form';
- $form['#action'] = url("admin/build/views/nojs/clone-display/$view->name/$display_id");
- $form['#attributes'] = array('class' => 'views-ajax-form');
-
- return $form;
-}
-
-/**
- * Submit handler to add a clone to a display from a view.
- */
-function views_ui_clone_display_form_submit($form, &$form_state) {
- // Create the new display
- $id = $form_state['display_id'];
- $display = $form_state['view']->display[$id];
-
- $new_id = $form_state['view']->add_display($display->display_plugin);
- $form_state['id'] = $new_id;
-
- // Replace the new display by a copy of the old
- $form_state['view']->display[$new_id] = clone $display;
- $form_state['view']->display[$new_id]->id = $new_id;
-
- // Store in cache
- views_ui_cache_set($form_state['view']);
-
- // Send it back
- $form_state['redirect'] = array('admin/structure/views/edit/' . $form_state['view']->name, array('fragment' => 'views-tab-' . $new_id));
-}
-
-/**
- * Form to remove a display from a view.
- */
-function views_ui_remove_display_form($form, &$form_state) {
- $view = &$form_state['view'];
- $display_id = $form_state['display_id'];
-
- if (empty($view->display[$display_id]->deleted)) {
- $form['display'] = array(
- '#prefix' => '<div class="display-button remove-display">',
- '#suffix' => '</div>',
- );
- $form['remove_display'] = array(
- '#type' => 'submit',
- '#value' => t('Remove display'),
- '#submit' => array('views_ui_remove_display_form_submit'),
- );
- }
- else {
- $form['display'] = array(
- '#prefix' => '<div class="display-button restore-display">',
- '#suffix' => '</div>',
- );
- $form['restore_display'] = array(
- '#type' => 'submit',
- '#value' => t('Restore display'),
- '#submit' => array('views_ui_remove_display_form_restore'),
- );
- }
- $form['#action'] = url("admin/structure/views/nojs/remove-display/$view->name/$display_id");
- $form['#attributes'] = array('class' => array('views-ajax-form'));
-
- return $form;
-}
-
-/**
- * Submit handler to add a remove to a display from a view.
- */
-function views_ui_remove_display_form_submit($form, &$form_state) {
- // Create the new display
- $plugin = views_fetch_plugin_data('display', $form_state['view']->display[$form_state['display_id']]->display_plugin);
- if (empty($plugin['no remove'])) {
- $id = $form_state['display_id'];
- $form_state['view']->display[$id]->deleted = TRUE;
-
- // Store in cache
- views_ui_cache_set($form_state['view']);
- }
-}
-
-/**
* Submit handler to add a restore a removed display to a view.
*/
function views_ui_remove_display_form_restore($form, &$form_state) {
@@ -2095,26 +2672,11 @@ function views_ui_remove_display_form_restore($form, &$form_state) {
* Page callback to display analysis information on a view.
*/
function views_ui_analyze_view($js, $view) {
- views_include('ajax');
$form_state = array(
'view' => &$view,
- 'ajax' => $js,
);
- $output = views_ajax_form_wrapper('views_ui_analyze_view_form', $form_state);
-
- if ($js) {
- // If we don't have an output object, it was submitted. Set up the submission.
- if ($form_state['submitted'] && empty($form_state['rerender'])) {
- $output = array();
- $output[] = views_ajax_command_enable_buttons();
- $output[] = views_ajax_command_dismiss_form();
- views_ui_regenerate_tabs($view, $output);
- }
- $commands = $output;
- return $js ? array('#type' => 'ajax', '#commands' => $commands) : $commands;
- }
- return $output;
+ return drupal_build_form('views_ui_analyze_view_form', $form_state);
}
/**
@@ -2166,39 +2728,7 @@ function views_ui_analyze_view_form($form, &$form_state) {
* Submit handler for views_ui_analyze_view_form
*/
function views_ui_analyze_view_form_submit($form, &$form_state) {
- $form_state['redirect'] = 'admin/structure/views/edit/' . $form_state['view']->name;
-}
-
-/**
- * Page callback to display analysis information on a view.
- */
-function views_ui_reorder_view($js, $view) {
- views_include('ajax');
- $form_state = array(
- 'view' => &$view,
- 'ajax' => $js,
- );
-
- $output = views_ajax_form_wrapper('views_ui_reorder_displays_form', $form_state);
-
- if ($js) {
- if ($form_state['submitted'] && empty($form_state['rerender'])) {
- // I don't want preprocess to modify the views -> no references
- $vars = array('view' => $view);
- template_preprocess_views_ui_edit_view($vars);
- $output = array();
- $output[] = ajax_command_replace('.views-tabset', $vars['tabs']);
- // Not the right place to have html i know !
- $output[] = ajax_command_replace('.views-quick-links', '<div class="views-quick-links">'. $vars['quick_links'] .'</div>');
- $output[] = views_ajax_command_enable_buttons();
- $output[] = views_ajax_command_dismiss_form();
- // Doesn't work yet, maybe we should reload the page dunno
- views_ui_regenerate_tabs($view, $output);
- }
- $commands = $output;
- return $js ? array('#type' => 'ajax', '#commands' => $commands) : $commands;
- }
- return $output;
+ $form_state['redirect'] = 'admin/structure/views/view/' . $form_state['view']->name . '/edit';
}
/**
@@ -2316,7 +2846,7 @@ function views_ui_reorder_displays_form_submit($form, &$form_state) {
// Store in cache
views_ui_cache_set($form_state['view']);
- $form_state['redirect'] = array('admin/structure/views/edit/' . $form_state['view']->name, array('fragment' => 'views-tab-default'));
+ $form_state['redirect'] = array('admin/structure/views/view/' . $form_state['view']->name . '/edit', array('fragment' => 'views-tab-default'));
}
/**
@@ -2397,85 +2927,6 @@ function views_ui_reorder_displays_button($form, &$form_state, $view) {
}
/**
- * Page callback to edit details of a view.
- */
-function views_ui_edit_details($property, $js, $view) {
- views_include('ajax');
- $form_state = array(
- 'view' => &$view,
- 'ajax' => $js,
- 'property' => $property,
- );
-
- $output = views_ajax_form_wrapper('views_ui_edit_details_form', $form_state);
-
- if ($js) {
- // If we don't have an output object, it was submitted. Set up the submission.
- if ($form_state['submitted'] && empty($form_state['rerender'])) {
- $output = array();
- $output[] = views_ajax_command_enable_buttons();
- $output[] = views_ajax_command_dismiss_form();
- views_ui_regenerate_tabs($view, $output);
- }
- $commands = $output;
- return $js ? array('#type' => 'ajax', '#commands' => $commands) : $commands;
- }
- return $output;
-}
-
-/**
- * Form constructor callback to edit details of a view
- */
-function views_ui_edit_details_form($form, &$form_state) {
- $view = &$form_state['view'];
-
- $form['#title'] = t('View details');
- $form['#section'] = 'details';
-
- switch ($form_state['property']) {
- case 'human_name':
- $form['human_name'] = array(
- '#type' => 'textfield',
- '#title' => t('Human readable name'),
- '#description' => t('You can use a more descriptive name for this view here. Spaces are allowed'),
- '#default_value' => $view->human_name,
- );
- break;
-
- case 'tag':
- $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->tag,
- '#autocomplete_path' => 'admin/views/ajax/autocomplete/tag',
- );
- break;
-
- case 'description':
- $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->description,
- );
- break;
- }
-
- views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_details_form');
- return $form;
-}
-
-/**
- * Submit handler for views_ui_edit_details_form
- */
-function views_ui_edit_details_form_submit($form, &$form_state) {
- $form_state['view']->{$form_state['property']} = $form_state['values'][$form_state['property']];
- views_ui_cache_set($form_state['view']);
- $form_state['redirect'] = 'admin/structure/views/edit/' . $form_state['view']->name;
-}
-
-/**
* Form constructor callback to edit display of a view
*/
function views_ui_edit_display_form($form, &$form_state) {
@@ -2489,7 +2940,23 @@ function views_ui_edit_display_form($form, &$form_state) {
$display = &$view->display[$display_id];
// Get form from the handler.
- $display->handler->options_form($form, $form_state);
+ $form['options'] = array(
+ '#theme_wrappers' => array('container'),
+ '#attributes' => array('class' => array('scroll')),
+ );
+ $display->handler->options_form($form['options'], $form_state);
+
+ // The handler options form sets $form['#title'], which we need on the entire
+ // $form instead of just the ['options'] section.
+ $form['#title'] = $form['options']['#title'];
+ unset($form['options']['#title']);
+
+ // Move the override dropdown out of the scrollable section of the form.
+ if (isset($form['options']['override'])) {
+ $form['override'] = $form['options']['override'];
+ unset($form['options']['override']);
+ }
+
$name = NULL;
if (isset($form_state['update_name'])) {
$name = $form_state['update_name'];
@@ -2523,6 +2990,8 @@ function views_ui_edit_display_form_submit($form, &$form_state) {
/**
* Override handler for views_ui_edit_display_form
+ *
+ * @TODO: Not currently used. Remove unless we implement an override toggle.
*/
function views_ui_edit_display_form_override($form, &$form_state) {
$display = &$form_state['view']->display[$form_state['display_id']];
@@ -2532,23 +3001,6 @@ function views_ui_edit_display_form_override($form, &$form_state) {
$form_state['rerender'] = TRUE;
$form_state['rebuild'] = TRUE;
}
-/**
- * Override handler and submit views_ui_edit_display_form
- */
-function views_ui_edit_display_form_override_update(&$form, &$form_state) {
- $display = &$form_state['view']->display[$form_state['display_id']];
- $display->handler->options_override($form, $form_state);
- $display->handler->options_submit($form, $form_state);
- views_ui_cache_set($form_state['view']);
-}
-
-/**
- * Override handler and submit views_ui_edit_display_form
- */
-function views_ui_edit_display_form_override_update_section(&$form, &$form_state) {
- // Update the #section so it knows what to mark changed.
- $form['#section'] = str_replace('default-', $form_state['display_id'] . '-', $form['#section']);
-}
/**
* Form to config items in the views UI.
@@ -2563,13 +3015,12 @@ function views_ui_config_type_form($form, &$form_state) {
views_ajax_error(t('Invalid display id @display', array('@display' => $display_id)));
}
$display = &$view->display[$display_id];
- $form['#title'] = check_plain($display->display_title) . ': ';
- $form['#title'] .= t('Configure @type', array('@type' => $types[$type]['ltitle']));
+ $form['#title'] = t('Configure @type', array('@type' => $types[$type]['ltitle']));
$form['#section'] = $display_id . 'config-item';
if ($display->handler->defaultable_sections($types[$type]['plural'])) {
$form_state['section'] = $types[$type]['plural'];
- $display->handler->add_override_button($form, $form_state, $form_state['section']);
+ views_ui_standard_display_dropdown($form, $form_state, $form_state['section']);
}
if (!empty($types[$type]['options']) && function_exists($types[$type]['options'])) {
@@ -2599,13 +3050,6 @@ function views_ui_config_type_form_submit($form, &$form_state) {
}
/**
- * Configure settings particular to filters.
- */
-function views_ui_config_filters_form(&$form, &$form_state) {
-
-}
-
-/**
* Form to rearrange items in the views UI.
*/
function views_ui_rearrange_form($form, &$form_state) {
@@ -2618,13 +3062,12 @@ function views_ui_rearrange_form($form, &$form_state) {
views_ajax_error(t('Invalid display id @display', array('@display' => $display_id)));
}
$display = &$view->display[$display_id];
- $form['#title'] = check_plain($display->display_title) . ': ';
- $form['#title'] .= t('Rearrange @type', array('@type' => $types[$type]['ltitle']));
+ $form['#title'] = t('Rearrange @type', array('@type' => $types[$type]['ltitle']));
$form['#section'] = $display_id . 'rearrange-item';
if ($display->handler->defaultable_sections($types[$type]['plural'])) {
$form_state['section'] = $types[$type]['plural'];
- $display->handler->add_override_button($form, $form_state, $form_state['section']);
+ views_ui_standard_display_dropdown($form, $form_state, $form_state['section']);
}
$count = 0;
@@ -2633,6 +3076,24 @@ function views_ui_rearrange_form($form, &$form_state) {
$relationships = array();
foreach ($display->handler->get_handlers('relationship') as $id => $handler) {
$relationships[$id] = $handler->label();
+ $handlers = $display->handler->get_option('relationships');
+ if ($handlers) {
+ foreach ($handlers as $id => $info) {
+ $handler = $display->handler->get_handler('relationship', $id);
+ $relationships[$id] = $handler->label();
+ }
+ }
+ }
+
+ // Filters can now be grouped so we do a little bit extra:
+ $groups = array();
+ $grouping = FALSE;
+ if ($type == 'filter') {
+ $group_info = $view->display_handler->get_option('filter_groups');
+ if (!empty($group_info['groups']) && count($group_info['groups']) > 1) {
+ $grouping = TRUE;
+ $groups = array(0 => array());
+ }
}
foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) {
@@ -2705,7 +3166,9 @@ function theme_views_ui_rearrange_form($variables) {
$header = array('', t('Weight'), t('Remove'));
$output = drupal_render($form['override']);
+ $output .= '<div class="scroll">';
$output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'arrange')));
+ $output .= '</div>';
$output .= drupal_render_children($form);
drupal_add_tabledrag('arrange', 'order', 'sibling', 'weight');
@@ -2713,6 +3176,44 @@ function theme_views_ui_rearrange_form($variables) {
}
/**
+ * Theme the expose filter form.
+ */
+function theme_views_ui_expose_filter_form($variables) {
+ $form = $variables['form'];
+ $more = drupal_render($form['more']);
+
+ $output = drupal_render($form['form_description']);
+ $output .= drupal_render($form['expose_button']);
+ if (isset($form['required'])) {
+ $output .= drupal_render($form['required']);
+ }
+ $output .= drupal_render($form['label']);
+
+ $output .= drupal_render($form['operator']);
+ $output .= drupal_render($form['value']);
+
+ if (isset($form['use_operator'])) {
+ $output .= '<div class="views-left-40">';
+ $output .= drupal_render($form['use_operator']);
+ $output .= '</div>';
+ }
+
+ // Only output the right column markup if there's a left column to begin with
+ if (!empty($form['operator']['#type'])) {
+ $output .= '<div class="views-right-60">';
+ $output .= drupal_render_children($form);
+ $output .= '</div>';
+ }
+ else {
+ $output .= drupal_render_children($form);
+ }
+
+ $output .= $more;
+
+ return $output;
+}
+
+/**
* Submit handler for rearranging form
*/
function views_ui_rearrange_form_submit($form, &$form_state) {
@@ -2763,7 +3264,7 @@ function views_ui_rearrange_filter_form($form, &$form_state) {
if ($display->handler->defaultable_sections($types[$type]['plural'])) {
$form_state['section'] = $types[$type]['plural'];
- $display->handler->add_override_button($form, $form_state, $form_state['section']);
+ views_ui_standard_display_dropdown($form, $form_state, $form_state['section']);
}
if (!empty($view->form_cache)) {
@@ -2805,7 +3306,7 @@ function views_ui_rearrange_filter_form($form, &$form_state) {
),
'#default_value' => $groups['operator'],
'#attributes' => array(
- 'class' => 'warning-on-change',
+ 'class' => array('warning-on-change'),
),
'#title' => t('Operator to use on all groups'),
'#description' => t('Either "group 0 AND group 1 AND group 2" or "group 0 OR group 1 OR group 2", etc'),
@@ -2816,7 +3317,7 @@ function views_ui_rearrange_filter_form($form, &$form_state) {
foreach ($groups['groups'] as $id => $group) {
$form['filter_groups']['groups'][$id] = array(
- '#title' => t('Group operator'),
+ '#title' => t('Operator'),
'#type' => 'select',
'#options' => array(
'AND' => t('And'),
@@ -2833,6 +3334,10 @@ function views_ui_rearrange_filter_form($form, &$form_state) {
$form['remove_groups'][$id] = array(
'#type' => 'submit',
'#value' => t('Remove group @group', array('@group' => $id)),
+ '#id' => "views-remove-group-$id",
+ '#attributes' => array(
+ 'class' => array('views-remove-group'),
+ ),
'#group' => $id,
);
}
@@ -2869,6 +3374,7 @@ function views_ui_rearrange_filter_form($form, &$form_state) {
$form['filters'][$id]['weight'] = array(
'#type' => 'textfield',
'#default_value' => ++$count,
+ '#size' => 8,
);
$form['filters'][$id]['group'] = array(
'#type' => 'select',
@@ -2901,39 +3407,6 @@ function views_ui_rearrange_filter_form($form, &$form_state) {
);
}
- // Add javascript settings that will be added via $.extend for tabledragging
- // Equivalent: drupal_add_tabledrag('arrange', 'order', 'sibling', 'weight');
- $form['#js']['tableDrag']['arrange']['weight'][0] = array(
- 'target' => 'weight',
- 'source' => NULL,
- 'relationship' => 'sibling',
- 'action' => 'order',
- 'hidden' => TRUE,
- 'limit' => 0,
- );
-
- $form['#js']['tableDrag']['ungroupable_arrange']['weight'][0] = array(
- 'target' => 'weight',
- 'source' => NULL,
- 'relationship' => 'sibling',
- 'action' => 'order',
- 'hidden' => TRUE,
- 'limit' => 0,
- );
-
- foreach ($form['#group_renders'] as $group_id => $title) {
- // Add javascript settings that will be added via $.extend for tabledragging
- // Equivalent: drupal_add_tabledrag('arrange', 'match', 'sibling', 'views-group-select', 'views-group-' . $group_id);
- $form['#js']['tableDrag']['arrange']['views-group-select'][] = array(
- 'target' => 'views-group-' . $group_id,
- 'source' => 'views-group-' . $group_id,
- 'relationship' => 'sibling',
- 'action' => 'match',
- 'hidden' => FALSE,
- 'limit' => 0,
- );
- }
-
if (isset($form_state['update_name'])) {
$name = $form_state['update_name'];
}
@@ -2941,7 +3414,7 @@ function views_ui_rearrange_filter_form($form, &$form_state) {
views_ui_standard_form_buttons($form, $form_state, 'views_ui_rearrange_filter_form');
$form['buttons']['add_group'] = array(
'#type' => 'submit',
- '#value' => t('Add new group'),
+ '#value' => t('Create new filter group'),
'#id' => 'views-add-group',
'#group' => 'add',
);
@@ -2960,16 +3433,30 @@ function theme_views_ui_rearrange_filter_form(&$vars) {
foreach ($form['#group_renders'] as $group_id => $contents) {
// Header row for the group.
- if ($grouping && $group_id !== 'ungroupable') {
+ if ($group_id !== 'ungroupable') {
+ // Set up tabledrag so that it changes the group dropdown when rows are
+ // dragged between groups.
+ drupal_add_tabledrag('views-rearrange-filters', 'match', 'sibling', 'views-group-select', 'views-group-select-' . $group_id);
+
+ // Title row, spanning all columns.
$row = array();
- $row[] = array('class' => array('group', 'group-title'), 'data' => $form['#group_options'][$group_id]);
- $row[] = array('class' => array('group', 'container-inline'), 'data' => drupal_render($form['filter_groups']['groups'][$group_id]), 'colspan' => 3);
- $rows[] = array('class' => array('views-group'), 'data' => $row, 'id' => 'views-group-' . $group_id);
- // Row which will only appear if the group has nothing in it:
+ // Add a cell to the first row, containing the group operator.
+ $row[] = array('class' => array('group', 'group-operator', 'container-inline'), 'data' => drupal_render($form['filter_groups']['groups'][$group_id]), 'rowspan' => max(array(2, count($contents) + 1)));
+ // Title.
+ $row[] = array('class' => array('group', 'group-title'), 'data' => '<span>' . $form['#group_options'][$group_id] . '</span>', 'colspan' => 4);
+ $rows[] = array('class' => array('views-group-title'), 'data' => $row, 'id' => 'views-group-title-' . $group_id);
+
+ // Row which will only appear if the group has nothing in it.
$row = array();
$class = 'group-' . (count($contents) ? 'populated' : 'empty');
- $row[] = array('colspan' => 4, 'data' => '<span>' . t('This group is empty') . '</span> ' .
- drupal_render($form['remove_groups'][$group_id]));
+ $instructions = '<span>' . t('No filters have been added.') . '</span> <span class="js-only">' . t('Drag to add filters.') . '</span>';
+ // When JavaScript is enabled, the button for removing the group (if it's
+ // present) should be hidden, since it will be replaced by a link on the
+ // client side.
+ if (!empty($form['remove_groups'][$group_id]['#type']) && $form['remove_groups'][$group_id]['#type'] == 'submit') {
+ $form['remove_groups'][$group_id]['#attributes']['class'][] = 'js-hide';
+ }
+ $row[] = array('colspan' => 5, 'data' => $instructions . drupal_render($form['remove_groups'][$group_id]));
$rows[] = array('class' => array("group-message", "group-$group_id-message", $class), 'data' => $row, 'id' => 'views-group-' . $group_id);
}
@@ -2979,8 +3466,9 @@ function theme_views_ui_rearrange_filter_form(&$vars) {
$row[] = drupal_render($form['filters'][$id]['name']);
$form['filters'][$id]['weight']['#attributes']['class'] = array('weight');
$row[] = drupal_render($form['filters'][$id]['weight']);
- $form['filters'][$id]['group']['#attributes']['class'] = array('views-group-select views-group-' . $group_id);
+ $form['filters'][$id]['group']['#attributes']['class'] = array('views-group-select views-group-select-' . $group_id);
$row[] = drupal_render($form['filters'][$id]['group']);
+ $form['filters'][$id]['removed']['#attributes']['class'][] = 'js-hide';
$row[] = drupal_render($form['filters'][$id]['removed']) . l('<span>' . t('Remove') . '</span>', 'javascript:void()', array('attributes' => array('id' => 'views-remove-link-' . $id, 'class' => array('views-hidden', 'views-button-remove', 'views-groups-remove-link', 'views-remove-link'), 'alt' => t('Remove this item'), 'title' => t('Remove this item')), 'html' => true));
$row = array('data' => $row, 'class' => array('draggable'), 'id' => 'views-row-' . $id);
@@ -2998,6 +3486,7 @@ function theme_views_ui_rearrange_filter_form(&$vars) {
}
$output = drupal_render($form['override']);
+ $output .= '<div class="scroll">';
if ($grouping) {
$output .= drupal_render($form['filter_groups']['operator']);
}
@@ -3007,17 +3496,23 @@ function theme_views_ui_rearrange_filter_form(&$vars) {
}
if (!empty($ungroupable_rows)) {
- drupal_add_tabledrag('ungroupable_arrange', 'order', 'sibling', 'weight');
+ drupal_add_tabledrag('views-rearrange-filters-ungroupable', 'order', 'sibling', 'weight');
$header = array(t('Ungroupable filters'), t('Weight'), array('class' => array('views-hide-label'), 'data' => t('Group')), array('class' => array('views-hide-label'), 'data' => t('Remove')));
- $output .= theme('table', array('header' => $header, 'rows' => $ungroupable_rows, 'attributes' => array('id' => 'ungroupable_arrange', 'class' => array('arrange'))));
+ $output .= theme('table', array('header' => $header, 'rows' => $ungroupable_rows, 'attributes' => array('id' => 'views-rearrange-filters-ungroupable', 'class' => array('arrange'))));
}
- drupal_add_tabledrag('arrange', 'order', 'sibling', 'weight');
- $header = array('', t('Weight'), t('Group'), t('Remove'));
- $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'arrange', 'class' => array('arrange'))));
+ // Set up tabledrag so that the weights are changed when rows are dragged.
+ drupal_add_tabledrag('views-rearrange-filters', 'order', 'sibling', 'weight');
+ $output .= theme('table', array('rows' => $rows, 'attributes' => array('id' => 'views-rearrange-filters', 'class' => array('arrange'))));
+ $output .= '</div>';
+
+ // When JavaScript is enabled, the button for adding a new group should be
+ // hidden, since it will be replaced by a link on the client side.
+ $form['buttons']['add_group']['#attributes']['class'][] = 'js-hide';
+
+ // Render the rest of the form and return.
$output .= drupal_render_children($form);
return $output;
-
}
/**
@@ -3064,7 +3559,8 @@ function views_ui_rearrange_filter_form_submit($form, &$form_state) {
$new_fields[$field] = $old_fields[$field];
}
- // Save if the actual update button was clicked.
+ // If the #group property is set on the clicked button, that means we are
+ // either adding or removing a group, not actually updating the filters.
if (!empty($form_state['clicked_button']['#group'])) {
if ($form_state['clicked_button']['#group'] == 'add') {
// Add a new group
@@ -3102,7 +3598,19 @@ function views_ui_rearrange_filter_form_submit($form, &$form_state) {
views_ui_add_form_to_stack('rearrange-filter', $form_state['view'], $form_state['display_id'], array($form_state['type']));
}
else {
- // Actually write changed handler values.
+ // The actual update button was clicked. Remove the empty groups, and
+ // renumber them sequentially.
+ ksort($remember_groups);
+ $groups['groups'] = array_values(array_intersect_key($groups['groups'], $remember_groups));
+ // Change the 'group' key on each field to match. Here, $mapping is an
+ // array whose keys are the old group numbers and whose values are the new
+ // (sequentially numbered) ones.
+ $mapping = array_flip(array_keys($remember_groups));
+ foreach ($new_fields as &$new_field) {
+ $new_field['group'] = $mapping[$new_field['group']];
+ }
+
+ // Write the changed handler values.
$display->handler->set_option($types[$form_state['type']]['plural'], $new_fields);
$display->handler->set_option('filter_groups', $groups);
if (isset($form_state['view']->form_cache)) {
@@ -3110,11 +3618,155 @@ function views_ui_rearrange_filter_form_submit($form, &$form_state) {
}
}
+ // Store in cache.
+ views_ui_cache_set($form_state['view']);
+}
+
+/**
+ * Form to delete multiple items at once.
+ *
+ * @todo: All this relationship stuff is there three times. This should be abstracted out.
+ */
+function views_ui_item_delete_form($form, &$form_state) {
+ $view = &$form_state['view'];
+ $display_id = $form_state['display_id'];
+ $type = $form_state['type'];
+
+ $types = views_object_types();
+ if (!$view->set_display($display_id)) {
+ views_ajax_error(t('Invalid display id @display', array('@display' => $display_id)));
+ }
+ $display = &$view->display[$display_id];
+ $form['#title'] = t('Delete @type', array('@type' => $types[$type]['ltitle']));
+ $form['#section'] = $display_id . 'delete-item';
+
+ if ($display->handler->defaultable_sections($types[$type]['plural'])) {
+ $form_state['section'] = $types[$type]['plural'];
+ views_ui_standard_display_dropdown($form, $form_state, $form_state['section']);
+ }
+
+ $count = 0;
+
+ // Get relationship labels
+ $relationships = array();
+ foreach ($display->handler->get_handlers('relationship') as $id => $handler) {
+ $relationships[$id] = $handler->label();
+ $handlers = $display->handler->get_option('relationships');
+ if ($handlers) {
+ foreach ($handlers as $id => $info) {
+ $handler = $display->handler->get_handler('relationship', $id);
+ $relationships[$id] = $handler->label();
+ }
+ }
+ }
+
+ // Filters can now be grouped so we do a little bit extra:
+ $groups = array();
+ $grouping = FALSE;
+ if ($type == 'filter') {
+ $group_info = $view->display_handler->get_option('filter_groups');
+ if (!empty($group_info['groups']) && count($group_info['groups']) > 1) {
+ $grouping = TRUE;
+ $groups = array(0 => array());
+ }
+ }
+
+ foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) {
+ $form['fields'][$id] = array('#tree' => TRUE);
+ $handler = $display->handler->get_handler($type, $id);
+ if ($handler) {
+ $name = $handler->ui_name() . ' ' . $handler->admin_summary();
+ if (!empty($field['relationship']) && !empty($relationships[$field['relationship']])) {
+ $name = '(' . $relationships[$field['relationship']] . ') ' . $name;
+ }
+
+ $form['fields'][$id]['name'] = array(
+ '#markup' => $name,
+ );
+ }
+ else {
+ $form['fields'][$id]['name'] = array('#markup' => t('Broken field @id', array('@id' => $id)));
+ }
+ $form['fields'][$id]['removed'] = array(
+ '#type' => 'checkbox',
+ '#id' => 'views-removed-' . $id,
+ '#attributes' => array('class' => array('views-remove-checkbox')),
+ '#default_value' => 0,
+ );
+ }
+
+ $name = NULL;
+ if (isset($form_state['update_name'])) {
+ $name = $form_state['update_name'];
+ }
+
+ views_ui_standard_form_buttons($form, $form_state, 'views_ui_item_delete_form');
+ return $form;
+}
+
+/**
+ * Submit handler for delete form
+ */
+function views_ui_item_delete_form_submit($form, &$form_state) {
+ $types = views_object_types();
+ $display = &$form_state['view']->display[$form_state['display_id']];
+
+ $old_fields = $display->handler->get_option($types[$form_state['type']]['plural']);
+ $new_fields = $order = array();
+
+ // Make an array with the weights
+ foreach ($form_state['values'] as $field => $info) {
+ // add each value that is a field, but only if
+ // it has had its 'removed' checkbox checked.
+ if (is_array($info) && empty($info['removed'])) {
+ $order[$field] = $field;
+ }
+ }
+
+ // Sort the array
+ asort($order);
+
+ // Create a new list of fields in the new order.
+ foreach (array_keys($order) as $field) {
+ $new_fields[$field] = $old_fields[$field];
+ }
+ $display->handler->set_option($types[$form_state['type']]['plural'], $new_fields);
+
// Store in cache
views_ui_cache_set($form_state['view']);
}
/**
+ * Turn the rearrange form into a proper table
+ */
+function theme_views_ui_item_delete_form($variables) {
+ $form = $variables['form'];
+
+ $rows = array();
+ foreach (element_children($form['fields']) as $id) {
+ if (isset($form['fields'][$id]['name'])) {
+ $row = array();
+ $row[] = drupal_render($form['fields'][$id]['name']);
+ $row[] = drupal_render($form['fields'][$id]['removed']) . l('<span>' . t('Remove') . '</span>', 'javascript:void()', array('attributes' => array('id' => 'views-remove-link-' . $id, 'class' => array('views-hidden', 'views-button-remove', 'views-remove-link'), 'alt' => t('Remove this item'), 'title' => t('Remove this item')), 'html' => TRUE));
+ $rows[] = array('data' => $row, 'class' => array('draggable'), 'id' => 'views-row-' . $id);
+ }
+ }
+ if (empty($rows)) {
+ $rows[] = array(array('data' => t('No fields available.'), 'colspan' => '2'));
+ }
+
+ $header = array('', t('Remove'));
+ $output = drupal_render($form['override']);
+ $output .= '<div class="scroll">';
+ $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'arrange')));
+ $output .= '</div>';
+ $output .= drupal_render_children($form);
+
+ return $output;
+}
+
+
+/**
* Form to add_item items in the views UI.
*/
function views_ui_add_item_form($form, &$form_state) {
@@ -3122,6 +3774,13 @@ function views_ui_add_item_form($form, &$form_state) {
$display_id = $form_state['display_id'];
$type = $form_state['type'];
+ $form = array(
+ 'options' => array(
+ '#theme_wrappers' => array('container'),
+ '#attributes' => array('class' => array('scroll')),
+ ),
+ );
+
ctools_add_js('dependent');
if (!$view->set_display($display_id)) {
@@ -3136,8 +3795,7 @@ function views_ui_add_item_form($form, &$form_state) {
$type = $types[$type]['type'];
}
- $form['#title'] = check_plain($display->display_title) . ': ';
- $form['#title'] .= t('Add @type', array('@type' => $ltitle));
+ $form['#title'] = t('Add @type', array('@type' => $ltitle));
$form['#section'] = $display_id . 'add-item';
// Figure out all the base tables allowed based upon what the relationships provide.
@@ -3145,16 +3803,26 @@ function views_ui_add_item_form($form, &$form_state) {
$options = views_fetch_fields(array_keys($base_tables), $type, $display->handler->use_group_by());
if (!empty($options)) {
+ $form['options']['controls'] = array(
+ '#theme_wrappers' => array('container'),
+ '#id' => 'views-filterable-options-controls',
+ '#attributes' => array('class' => array('container-inline')),
+ );
+ $form['options']['controls']['options_search'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Search'),
+ );
+
$groups = array('all' => t('- All -'));
- $form['group'] = array(
+ $form['options']['controls']['group'] = array(
'#type' => 'select',
- '#title' => t('Groups'),
+ '#title' => t('Filter'),
'#options' => array(),
'#attributes' => array('class' => array('ctools-master-dependent')),
);
- $form['name'] = array(
- '#prefix' => '<div class="views-radio-box form-checkboxes">',
+ $form['options']['name'] = array(
+ '#prefix' => '<div class="views-radio-box form-checkboxes views-filterable-options">',
'#suffix' => '</div>',
'#tree' => TRUE,
'#default_value' => 'all',
@@ -3170,27 +3838,40 @@ function views_ui_add_item_form($form, &$form_state) {
}
foreach ($grouped_options as $group => $group_options) {
- $form['name'][$group . '_start']['#markup'] = '<div class="ctools-dependent-all ctools-dependent-' . $group . '">';
+ $form['options']['name'][$group . '_start']['#markup'] = '<div class="ctools-dependent-all ctools-dependent-' . $group . '">';
+ $zebra = 0;
foreach ($group_options as $key => $option) {
- $form['name'][$key] = array(
+ $zebra_class = ($zebra % 2) ? 'odd' : 'even';
+ $form['options']['name'][$key] = array(
'#type' => 'checkbox',
'#title' => t('!group: !field', array('!group' => $option['group'], '!field' => $option['title'])),
'#description' => $option['help'],
'#return_value' => $key,
+ '#prefix' => "<div class='$zebra_class filterable-option'>",
+ '#suffix' => '</div>',
);
+ $zebra++;
}
- $form['name'][$group . '_end']['#markup'] = '</div>';
+ $form['options']['name'][$group . '_end']['#markup'] = '</div>';
}
- $form['group']['#options'] = $groups;
+ $form['options']['controls']['group']['#options'] = $groups;
}
else {
- $form['markup'] = array(
+ $form['options']['markup'] = array(
'#markup' => '<div class="form-item">' . t('There are no @types available to add.', array('@types' => $types[$type]['ltitle'])) . '</div>',
);
}
+ // Add a div to show the selected items
+ $form['selected'] = array(
+ '#type' => 'item',
+ '#markup' => '<div class="views-selected-options"></div>',
+ '#title' => t('Selected') . ':',
+ '#theme_wrappers' => array('form_element', 'views_container'),
+ '#attributes' => array('class' => array('container-inline', 'views-add-form-selected')),
+ );
ctools_include('dependent');
- views_ui_standard_form_buttons($form, $form_state, 'views_ui_add_item_form', t('Add'));
+ views_ui_standard_form_buttons($form, $form_state, 'views_ui_add_item_form', t('Add and configure @types', array('@types' => $types[$type]['ltitle'])));
return $form;
}
@@ -3241,7 +3922,13 @@ function views_ui_config_item_form($form, &$form_state) {
$type = $form_state['type'];
$id = $form_state['id'];
- $form = array('options' => array('#tree' => TRUE));
+ $form = array(
+ 'options' => array(
+ '#tree' => TRUE,
+ '#theme_wrappers' => array('container'),
+ '#attributes' => array('class' => array('scroll')),
+ ),
+ );
if (!$view->set_display($display_id)) {
views_ajax_error(t('Invalid display id @display', array('@display' => $display_id)));
}
@@ -3255,9 +3942,11 @@ function views_ui_config_item_form($form, &$form_state) {
else {
$types = views_object_types();
+ // If this item can come from the default display, show a dropdown
+ // that lets the user choose which display the changes should apply to.
if ($view->display_handler->defaultable_sections($types[$type]['plural'])) {
$form_state['section'] = $types[$type]['plural'];
- $view->display_handler->add_override_button($form['options'], $form_state, $form_state['section']);
+ views_ui_standard_display_dropdown($form, $form_state, $form_state['section']);
}
// A whole bunch of code to figure out what relationships are valid for
@@ -3310,6 +3999,7 @@ function views_ui_config_item_form($form, &$form_state) {
'#title' => t('Relationship'),
'#options' => $relationship_options,
'#default_value' => $rel,
+ '#fieldset' => 'more',
);
}
else {
@@ -3319,16 +4009,16 @@ function views_ui_config_item_form($form, &$form_state) {
);
}
- $form['#title'] = check_plain($view->display[$display_id]->display_title) . ': ';
- $form['#title'] .= t('Configure @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
+ $form['#title'] = t('Configure @type: @item', array('@type' => $types[$type]['lstitle'], '@item' => $handler->ui_name()));
- $form['form_description'] = array(
- '#type' => 'markup',
- '#weight' => -1000,
- '#prefix' => '<div class="form-item description">',
- '#suffix' => '</div>',
- '#value' => $handler->definition['help'],
- );
+ if (!empty($handler->definition['help'])) {
+ $form['options']['form_description'] = array(
+ '#markup' => $handler->definition['help'],
+ '#theme_wrappers' => array('container'),
+ '#attributes' => array('class' => array('form-item description')),
+ '#weight' => -1000,
+ );
+ }
$form['#section'] = $display_id . '-' . $type . '-' . $id;
@@ -3388,9 +4078,6 @@ function views_ui_config_item_form_submit($form, &$form_state) {
// Store the item back on the view
$form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $handler->options);
- if ($form_state['handler'] && $form_state['handler']->needs_style_plugin()) {
- views_ui_add_form_to_stack('change-style', $form_state['view'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE);
- }
// Write to cache
views_ui_cache_set($form_state['view']);
@@ -3405,7 +4092,13 @@ function views_ui_config_item_group_form($type, &$form_state) {
$type = $form_state['type'];
$id = $form_state['id'];
- $form = array('options' => array('#tree' => TRUE));
+ $form = array(
+ 'options' => array(
+ '#tree' => TRUE,
+ '#theme_wrappers' => array('container'),
+ '#attributes' => array('class' => array('scroll')),
+ ),
+ );
if (!$view->set_display($display_id)) {
views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
}
@@ -3491,7 +4184,13 @@ function views_ui_config_item_extra_form($form, &$form_state) {
$type = $form_state['type'];
$id = $form_state['id'];
- $form = array('options' => array('#tree' => TRUE));
+ $form = array(
+ 'options' => array(
+ '#tree' => TRUE,
+ '#theme_wrappers' => array('container'),
+ '#attributes' => array('class' => array('scroll')),
+ ),
+ );
if (!$view->set_display($display_id)) {
views_ajax_error(t('Invalid display id @display', array('@display' => $display_id)));
}
@@ -3506,8 +4205,7 @@ function views_ui_config_item_extra_form($form, &$form_state) {
$handler->init($view, $item);
$types = views_object_types();
- $form['#title'] = check_plain($view->display[$display_id]->display_title) . ': ';
- $form['#title'] .= t('Configure extra settings for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
+ $form['#title'] = t('Configure extra settings for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
$form['#section'] = $display_id . '-' . $type . '-' . $id;
@@ -3549,91 +4247,6 @@ function views_ui_config_item_extra_form_submit($form, &$form_state) {
}
/**
- * Form to change_style items in the views UI.
- */
-function views_ui_change_style_form($form, &$form_state) {
- $view = &$form_state['view'];
- $display_id = $form_state['display_id'];
- $type = $form_state['type'];
- $id = $form_state['id'];
-
- $form = array('options' => array('#tree' => TRUE));
- if (!$view->set_display($display_id)) {
- views_ajax_error(t('Invalid display id @display', array('@display' => $display_id)));
- }
- $item = $view->get_item($display_id, $type, $id);
-
- if ($item) {
- $handler = views_get_handler($item['table'], $item['field'], $type);
- if (empty($handler)) {
- $form['markup'] = array('#markup' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
- }
- else {
- $handler->init($view, $item);
- $types = views_object_types();
- $form['#title'] = t('Change summary style for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
-
- $form['#section'] = $display_id . '-' . $type . '-' . $id . '-style-plugin';
-
- $form['style_plugin'] = array(
- '#type' => 'radios',
- '#options' => views_fetch_plugin_names('style', 'summary'),
- '#default_value' => $item['style_plugin'],
- );
-
- $form_state['handler'] = &$handler;
- }
- views_ui_standard_form_buttons($form, $form_state, 'views_ui_change_style_form');
- }
- return $form;
-}
-
-function views_ui_change_style_form_validate($form, &$form_state) {
- // Run it through the handler's submit function.
- $form_state['handler']->options_validate($form['options'], $form_state);
-
- $plugin = views_get_plugin('style', $form_state['values']['style_plugin']);
- if (!$plugin) {
- form_error($form['style_plugin'], t('Internal error: broken plugin.'));
- }
-}
-
-/**
- * Submit handler for configing new item(s) to a view.
- */
-function views_ui_change_style_form_submit($form, &$form_state) {
- // Run it through the handler's submit function.
- $form_state['handler']->options_submit($form['options'], $form_state);
- $item = $form_state['handler']->options;
-
- $plugin = views_get_plugin('style', $form_state['values']['style_plugin']);
- if (!$plugin) {
- drupal_set_message(t('Internal error: broken plugin.'), 'error');
- return;
- }
-
- $plugin->init($form_state['view'], $form_state['view']->display[$form_state['display_id']]);
-
- // If changing style plugin, reset options to defaults.
- if (empty($item['style_plugin']) || $item['style_plugin'] != $form_state['values']['style_plugin']) {
- $item['style_options'] = $plugin->options;
- }
-
- // Store the data we're given.
- $item['style_plugin'] = $form_state['values']['style_plugin'];
-
- // Store the item back on the view
- $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
-
- if (!empty($plugin->definition['uses options'])) {
- views_ui_add_form_to_stack('config-style', $form_state['view'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE);
- }
-
- // Write to cache
- views_ui_cache_set($form_state['view']);
-}
-
-/**
* Form to config_style items in the views UI.
*/
function views_ui_config_style_form($form, &$form_state) {
@@ -3642,7 +4255,13 @@ function views_ui_config_style_form($form, &$form_state) {
$type = $form_state['type'];
$id = $form_state['id'];
- $form = array('options' => array('#tree' => TRUE));
+ $form = array(
+ 'options' => array(
+ '#tree' => TRUE,
+ '#theme_wrappers' => array('container'),
+ '#attributes' => array('class' => array('scroll')),
+ ),
+ );
if (!$view->set_display($display_id)) {
views_ajax_error(t('Invalid display id @display', array('@display' => $display_id)));
}
@@ -3657,8 +4276,7 @@ function views_ui_config_style_form($form, &$form_state) {
$handler->init($view, $item);
$types = views_object_types();
- $form['#title'] = check_plain($view->display[$display_id]->display_title) . ': ';
- $form['#title'] .= t('Configure summary style for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
+ $form['#title'] = t('Configure summary style for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
$form['#section'] = $display_id . '-' . $type . '-style-options';
@@ -3715,43 +4333,109 @@ function views_ui_get_roles() {
}
/**
- * Page callback for the Views enable page.
+ * Form builder for the admin display settings page.
*/
-function views_ui_enable_page($view) {
- if (isset($_GET['token']) && drupal_valid_token($_GET['token'], 'views-enable')) {
- $views_status = variable_get('views_defaults', array());
- $views_status[$view->name] = FALSE; // FALSE is enabled
- variable_set('views_defaults', $views_status);
- views_invalidate_cache();
- menu_rebuild();
- drupal_goto('admin/structure/views');
- }
- else {
- return drupal_access_denied();
- }
+function views_ui_admin_settings_display() {
+ ctools_include('dependent');
+ drupal_add_css(drupal_get_path('module', 'views_ui') . '/css/views-admin.css');
+
+ $form = array();
+ $form['view_list'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('View list'),
+ );
+ $form['view_list']['views_ui_show_listing_filters'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Show filters on the list of views'),
+ '#default_value' => variable_get('views_ui_show_listing_filters', FALSE),
+ );
+ $form['edit_view_form'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Edit view form'),
+ );
+ $form['edit_view_form']['views_ui_show_sql_query'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Show the SQL query'),
+ '#default_value' => variable_get('views_ui_show_sql_query', FALSE),
+ );
+ $form['edit_view_form']['views_ui_show_sql_query_where'] = array(
+ '#type' => 'radios',
+ '#options' => array(
+ 'above' => t('Show the query above the automatic preview'),
+ 'below' => t('Show the query below the automatic preview'),
+ ),
+ '#default_value' => variable_get('views_ui_show_sql_query_where', 'above'),
+ '#process' => array('form_process_radios', 'ctools_dependent_process'),
+ '#dependency' => array('edit-views-ui-show-sql-query' => array(TRUE)),
+ '#prefix' => '<div id="edit-show-sql-wrapper" class="views-dependent"><div id="edit-show-sql">',
+ '#suffix' => '</div></div>',
+ );
+ $form['edit_view_form']['views_ui_show_performance_statistics'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Show performance statistics'),
+ '#default_value' => variable_get('views_ui_show_performance_statistics', FALSE),
+ );
+ $form['edit_view_form']['views_ui_show_performance_statistics_where'] = array(
+ '#type' => 'radios',
+ '#options' => array(
+ 'above' => t('Show the statistics above the automatic preview'),
+ 'below' => t('Show the statistics below the automatic preview'),
+ ),
+ '#default_value' => variable_get('views_ui_show_performance_statistics_where', 'above'),
+ '#process' => array('form_process_radios', 'ctools_dependent_process'),
+ '#dependency' => array('edit-views-ui-show-performance-statistics' => array(TRUE)),
+ '#prefix' => '<div id="edit-show-performance-wrapper" class="views-dependent"><div id="edit-show-performance">',
+ '#suffix' => '</div></div>',
+ );
+ $form['edit_view_form']['views_ui_show_advanced_help_warning'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Show advanced help warning'),
+ '#default_value' => variable_get('views_ui_show_advanced_help_warning', TRUE),
+ );
+
+ return system_settings_form($form);
}
/**
- * Page callback for the Views enable page
+ * Form builder for the admin display defaults page.
*/
-function views_ui_disable_page($view) {
- if (isset($_GET['token']) && drupal_valid_token($_GET['token'], 'views-disable')) {
- $views_status = variable_get('views_defaults', array());
- $views_status[$view->name] = TRUE; // True is disabled
- variable_set('views_defaults', $views_status);
- views_invalidate_cache();
- menu_rebuild();
- drupal_goto('admin/structure/views');
- }
- else {
- return drupal_access_denied();
- }
+function views_ui_admin_settings_defaults() {
+ $form = array();
+ $form['view_list'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('View list'),
+ );
+ $form['view_list']['views_ui_combine_templates'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Combine view templates and user-generated views'),
+ '#default_value' => variable_get('views_ui_combine_templates', FALSE),
+ );
+
+ $form['edit_view_form'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Edit view form'),
+ );
+ $form['edit_view_form']['views_ui_show_master_display'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Always show the master query'),
+ '#description' => t('Legacy users of views may choose to see the master (i.e. default) display.'),
+ '#default_value' => variable_get('views_ui_show_master_display', FALSE),
+ );
+ $form['edit_view_form']['views_exposed_filter_any_label'] = array(
+ '#type' => 'select',
+ '#title' => t('Label for "Any" value on non-required single-select exposed filters'),
+ '#options' => array('old_any' => '<Any>', 'new_any' => t('- Any -')),
+ '#default_value' => variable_get('views_exposed_filter_any_label', 'old_any'),
+ );
+
+ return system_settings_form($form);
}
/**
- * Page callback for the tools - other page
+ * Form builder for the advanced admin settings page.
*/
-function views_ui_admin_tools() {
+function views_ui_admin_settings_advanced() {
+ $form = array();
$form['clear_cache'] = array(
'#type' => 'submit',
'#value' => t("Clear Views' cache"),
@@ -3772,24 +4456,10 @@ function views_ui_admin_tools() {
'#default_value' => variable_get('views_skip_cache', FALSE),
);
- $form['views_hide_help_message'] = array(
- '#type' => 'checkbox',
- '#title' => t('Ignore missing advanced help module'),
- '#description' => t("Views uses the advanced help module to provide help text; if this module is not present Views will complain, unless this setting is checked."),
- '#default_value' => variable_get('views_hide_help_message', FALSE),
- );
-
- $form['views_ui_query_on_top'] = array(
- '#type' => 'checkbox',
- '#title' => t('Show query above live preview'),
- '#description' => t("The live preview feature will show you the output of the view you're creating, as well as the view. Check here to show the query and other information above the view; leave this unchecked to show that information below the view."),
- '#default_value' => variable_get('views_ui_query_on_top', FALSE),
- );
-
$form['views_ui_disable_live_preview'] = array(
'#type' => 'checkbox',
'#title' => t('Disable automatic live preview'),
- '#description' => t("Don't automatically update the preview. This can speed up the editing of views a bit.'"),
+ '#description' => t("Don't automatically update the preview. This can speed up the editing of views a bit."),
'#default_value' => variable_get('views_ui_disable_live_preview', 0),
);
@@ -3800,13 +4470,6 @@ function views_ui_admin_tools() {
'#default_value' => variable_get('views_show_additional_queries', FALSE),
);
- $form['views_no_hover_links'] = array(
- '#type' => 'checkbox',
- '#title' => t('Do not show hover links over views'),
- '#description' => t("To make it easier to administrate your views, Views provides 'hover' links to take you to the edit and export screen of a view whenever the view is used. This can be distracting on some themes, though; if it is problematic, you can turn it off here."),
- '#default_value' => variable_get('views_no_hover_links', FALSE),
- );
-
$form['views_devel_output'] = array(
'#type' => 'checkbox',
'#title' => t('Enable views performance statistics via the Devel module'),
@@ -3816,8 +4479,8 @@ function views_ui_admin_tools() {
$form['views_no_javascript'] = array(
'#type' => 'checkbox',
- '#title' => t('Disable javascript with Views'),
- '#description' => t("If you are having problems with the javascript, you can disable it here; the Views UI should degrade and still be usable without javascript, it just not as good."),
+ '#title' => t('Disable JavaScript with Views'),
+ '#description' => t("If you are having problems with the JavaScript, you can disable it here. The Views UI should degrade and still be usable without javascript; it's just not as good."),
'#default_value' => variable_get('views_no_javascript', FALSE),
);
@@ -3839,13 +4502,6 @@ function views_ui_admin_tools() {
'#options' => $regions,
);
- $form['views_exposed_filter_any_label'] = array(
- '#type' => 'select',
- '#title' => t('Label for "Any" value on optional single-select exposed filters'),
- '#options' => array('old_any' => '<Any>', 'new_any' => t('- Any -')),
- '#default_value' => variable_get('views_exposed_filter_any_label', 'old_any'),
- );
-
return system_settings_form($form);
}
@@ -3896,20 +4552,13 @@ function views_ui_autocomplete_tag($string = '') {
$matches = array();
// get matches from default views:
views_include('view');
- $views = views_discover_default_views();
+ $views = views_get_all_views();
foreach ($views as $view) {
if (!empty($view->tag) && strpos($view->tag, $string) === 0) {
$matches[$view->tag] = $view->tag;
- }
- }
-
- $count = 10 - count($matches);
- if ($string) {
- $result = db_query_range("SELECT DISTINCT tag FROM {views_view} WHERE LOWER(tag) LIKE LOWER(:tag)",
- 0, $count,
- array(':tag' => $string . '%'));
- foreach ($result as $view) {
- $matches[$view->tag] = check_plain($view->tag);
+ if (count($matches) >= 10) {
+ break;
+ }
}
}
@@ -3946,7 +4595,7 @@ function views_fetch_base_tables() {
if (!empty($info['table']['base'])) {
$tables[$table] = array(
'title' => $info['table']['base']['title'],
- 'description' => $info['table']['base']['help'],
+ 'description' => !empty($info['table']['base']['help']) ? $info['table']['base']['help'] : '',
'weight' => !empty($info['table']['base']['weight']) ? $info['table']['base']['weight'] : 0,
);
}
@@ -4181,3 +4830,79 @@ function theme_views_ui_style_plugin_table($variables) {
$output .= drupal_render_children($form);
return $output;
}
+
+/**
+ * Placeholder function for overriding $display->display_title.
+ *
+ * @todo Remove this function once editing the display title is possible.
+ */
+function views_ui_get_display_label($view, $display_id, $check_changed = TRUE) {
+ $title = $display_id == 'default' ? t('Master') : check_plain($view->display[$display_id]->display_title);
+
+ if ($check_changed && !empty($view->changed_display[$display_id])) {
+ $changed = '*';
+ $title = $title . $changed;
+ }
+
+ return $title;
+}
+
+function views_ui_add_template_page() {
+ $templates = views_get_all_templates();
+
+ if (empty($templates)) {
+ return t('There are no templates available.');
+ }
+
+ $header = array(
+ t('Name'),
+ t('Description'),
+ t('Operation'),
+ );
+
+ $rows = array();
+ foreach ($templates as $name => $template) {
+ $rows[] = array(
+ array('data' => check_plain($template->get_human_name())),
+ array('data' => check_plain($template->description)),
+ array('data' => l('add', 'admin/structure/views/template/' . $template->name . '/add')),
+ );
+ }
+
+ $output = theme('table', array('header' => $header, 'rows' => $rows));
+ return $output;
+}
+
+/**
+ * #process callback for a button; determines if a button is the form's triggering element.
+ *
+ * The Form API has logic to determine the form's triggering element based on
+ * the data in $_POST. However, it only checks buttons based on a single #value
+ * per button. This function may be added to a button's #process callbacks to
+ * extend button click detection to support multiple #values per button. If the
+ * data in $_POST matches any value in the button's #values array, then the
+ * button is detected as having been clicked. This can be used when the value
+ * (label) of the same logical button may be different based on context (e.g.,
+ * "Apply" vs. "Apply and continue").
+ *
+ * @see _form_builder_handle_input_element()
+ * @see _form_button_was_clicked()
+ */
+function views_ui_form_button_was_clicked($element, &$form_state) {
+ $process_input = empty($element['#disabled']) && ($form_state['programmed'] || ($form_state['process_input'] && (!isset($element['#access']) || $element['#access'])));
+ if ($process_input && !isset($form_state['triggering_element']) && isset($element['#button_type']) && isset($form_state['input'][$element['#name']]) && isset($element['#values']) && in_array($form_state['input'][$element['#name']], $element['#values'], TRUE)) {
+ $form_state['triggering_element'] = $element;
+ }
+ return $element;
+}
+
+/**
+ * #process callback for a button; makes implicit form submissions trigger as this button.
+ *
+ * @see Drupal.behaviors.viewsImplicitFormSubmission
+ */
+function views_ui_default_button($element, &$form_state, $form) {
+ $setting['viewsImplicitFormSubmission'][$form['#id']]['defaultButton'] = $element['#id'];
+ $element['#attached']['js'][] = array('type' => 'setting', 'data' => $setting);
+ return $element;
+}
diff --git a/includes/ajax.inc b/includes/ajax.inc
index dae2de9..ab9978b 100644
--- a/includes/ajax.inc
+++ b/includes/ajax.inc
@@ -25,6 +25,19 @@ function views_ajax() {
$arg = explode('/', $_REQUEST['view_path']);
+ // Remove all of this stuff from $_GET so it doesn't end up in pagers and tablesort URLs.
+ foreach (array('view_name', 'view_display_id', 'view_args', 'view_path', 'view_dom_id', 'pager_element', 'view_base_path', 'ajax_html_ids', 'ajax_page_state') as $key) {
+ if (isset($_GET[$key])) {
+ unset($_GET[$key]);
+ }
+ if (isset($_REQUEST[$key])) {
+ unset($_REQUEST[$key]);
+ }
+ if (isset($_POST[$key])) {
+ unset($_POST[$key]);
+ }
+ }
+
// Load the view.
$view = views_get_view($name);
if ($view && $view->access($display_id)) {
@@ -136,27 +149,14 @@ function views_ajax_command_add_tab($id, $title, $body) {
}
/**
- * Disables Save, Cancel, and Delete buttons.
- *
- * @return
- * An array suitable for use with the ajax_render() function.
- */
-function views_ajax_command_disable_buttons() {
- $command = array(
- 'command' => 'viewsDisableButtons',
- );
- return $command;
-}
-
-/**
- * Enables Save, Cancel, and Delete buttons.
+ * Shows Save and Cancel buttons.
*
* @return
* An array suitable for use with the ajax_render() function.
*/
-function views_ajax_command_enable_buttons() {
+function views_ajax_command_show_buttons() {
$command = array(
- 'command' => 'viewsEnableButtons',
+ 'command' => 'viewsShowButtons',
);
return $command;
}
@@ -206,6 +206,7 @@ function views_ajax_form_wrapper($form_id, &$form_state) {
// These forms have the title built in, so set the title here:
if (empty($form_state['ajax']) && !empty($form_state['title'])) {
drupal_set_title($form_state['title']);
+ drupal_add_css(drupal_get_path('module', 'views_ui') . '/css/views-admin.css');
}
if (!empty($form_state['ajax']) && (empty($form_state['executed']) || !empty($form_state['rerender']))) {
diff --git a/includes/cache.inc b/includes/cache.inc
index 3ab2ebc..aad8784 100644
--- a/includes/cache.inc
+++ b/includes/cache.inc
@@ -7,24 +7,15 @@
*/
/**
- * Load views files on behalf of modules.
- */
-function _views_include_handlers() {
- views_module_include('views.inc');
-}
-
-/**
- * Load default views files on behalf of modules.
- */
-function _views_include_default_views() {
- views_module_include('views_default.inc');
-}
-
-/**
* Fetch Views' data from the cache
+ *
+ * @param $move
+ * Under certain circumstances it makes sense to not get the moved table, but the old one.
+ * One example is views_get_handler.
*/
-function _views_fetch_data($table = NULL, $reset = FALSE) {
+function _views_fetch_data($table = NULL, $move = TRUE, $reset = FALSE) {
static $cache = NULL;
+ static $recursion_protection = array();
if (!isset($cache) || $reset) {
$start = microtime(TRUE);
// NOTE: This happens whether we retrieve them from cache or otherwise.
@@ -50,7 +41,21 @@ function _views_fetch_data($table = NULL, $reset = FALSE) {
return $cache;
}
if (isset($cache[$table])) {
- return $cache[$table];
+ // Support old views_data entries conversion.
+ if (isset($cache[$table]['moved to']) && $move) {
+ $moved_table = $cache[$table]['moved to'];
+ if (!empty($recursion_protection[$table])) {
+ // recursion detected!
+ return NULL;
+ }
+ $recursion_protection[$table] = TRUE;
+ $data = _views_fetch_data($moved_table);
+ $recursion_protection = array();
+ return $data;
+ }
+ else {
+ return $cache[$table];
+ }
}
// Return an empty array if there is no match.
@@ -89,68 +94,6 @@ function _views_fetch_plugin_data($type = NULL, $plugin = NULL, $reset = FALSE)
}
/**
- * Scan all modules for default views and rebuild the default views cache.
- *
- * @return An associative array of all known default views.
- */
-function _views_discover_default_views($reset = FALSE) {
- static $cache = NULL;
-
- if (!isset($cache) || $reset) {
- $index = views_cache_get('views_default_views_index', TRUE);
-
- // Retrieve each cached default view
- if (!$reset && isset($index->data) && is_array($index->data)) {
- $cache = array();
- foreach ($index->data as $view_name) {
- $data = views_cache_get('views_default:' . $view_name, TRUE);
- if (isset($data->data) && is_object($data->data)) {
- $cache[$view_name] = $data->data;
- }
- }
- }
- // If missing index, rebuild the cache
- else {
- views_include_default_views();
- $cache = array();
-
- foreach (module_implements('views_default_views') as $module) {
- $results = call_user_func($module . "_views_default_views");
- if (!empty($results) && is_array($results)) {
- foreach($results as $name => $view) {
- // Only views with a sufficiently high api version are eligible.
- if (!empty($view->api_version) && $view->api_version >= 2) {
- // Do not cache dead handlers.
- $view->destroy();
- if (!isset($cache[$name])) {
- $cache[$name] = $view;
- }
- else {
- watchdog('view', "View name '@name' is already taken", array('@name' => $name), WATCHDOG_ERROR);
- }
- }
- }
- }
- }
-
- // Allow modules to modify default views before they are cached.
- drupal_alter('views_default_views', $cache);
-
- // Cache the index
- $index = array_keys($cache);
- views_cache_set('views_default_views_index', $index, TRUE);
-
- // Cache each view
- foreach ($cache as $name => $view) {
- views_cache_set('views_default:' . $name, $view, TRUE);
- }
- }
- }
-
- return $cache;
-}
-
-/**
* Set a cached item in the views cache.
*
* This is just a convenience wrapper around cache_set().
diff --git a/includes/convert.inc b/includes/convert.inc
index 0635fef..4ad145f 100644
--- a/includes/convert.inc
+++ b/includes/convert.inc
@@ -366,7 +366,7 @@ function views1_import($imported) {
// Use the count to emulate the old, hardcoded filter naming.
$item['expose']['identifier'] = 'filter' . $count;
$item['expose']['label'] = $field['label'];
- $item['expose']['operator'] = $field['operator'] ? 'op' . $count : '';
+ $item['expose']['operator_id'] = $field['operator'] ? 'op' . $count : '';
$item['expose']['optional'] = $field['optional'];
$item['expose']['single'] = $field['single'];
$view->set_item('default', 'filter', $id, $item);
diff --git a/includes/handlers.inc b/includes/handlers.inc
index ff2a276..6963a50 100644
--- a/includes/handlers.inc
+++ b/includes/handlers.inc
@@ -132,7 +132,7 @@ function views_get_table_join($table, $base_table) {
class views_handler extends views_object {
/**
* The top object of a view.
- *
+ *
* @var view
*/
var $view = NULL;
@@ -257,12 +257,32 @@ class views_handler extends views_object {
*/
function options_validate(&$form, &$form_state) { }
+ /**
+ * Build the options form.
+ */
function options_form(&$form, &$form_state) {
+ // Some form elements belong in a fieldset for presentation, but can't
+ // be moved into one because of the form_state['values'] hierarchy. Those
+ // elements can add a #fieldset => 'fieldset_name' property, and they'll
+ // be moved to their fieldset during pre_render.
+ $form['#pre_render'][] = 'views_ui_pre_render_add_fieldset_markup';
+
$form['ui_name'] = array(
'#type' => 'textfield',
- '#title' => t('Administrative Title'),
+ '#title' => t('Administrative title'),
'#description' => t('This title will be displayed on the views edit page instead of the default one. This might be useful if you have the same item twice.'),
'#default_value' => $this->options['ui_name'],
+ '#fieldset' => 'more',
+ );
+
+ // This form is long and messy enough that the "Administrative title" option
+ // belongs in a "more options" fieldset at the bottom of the form.
+ $form['more'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('More'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ '#weight' => 50,
);
}
@@ -370,39 +390,9 @@ class views_handler extends views_object {
function exposed_submit(&$form, &$form_state) { }
/**
- * Overridable form for exposed handler options.
- *
- * If overridden, it is best to call the parent or re-implement
- * the stuff here.
- *
- * Many handlers will need to override this in order to provide options
- * that are nicely tailored to the given filter.
+ * Form for exposed handler options.
*/
- function expose_form(&$form, &$form_state) {
- $form['expose']['start_left'] = array(
- '#markup' => '<div class="views-left-50">',
- );
-
- $this->expose_form_left($form, $form_state);
-
- $form['expose']['end_left'] = array(
- '#markup' => '</div>',
- );
-
- $form['expose']['start_checkboxes'] = array(
- '#markup' => '<div class="form-checkboxes views-left-40 clearfix">',
- );
-
- $this->expose_form_right($form, $form_state);
-
- $form['expose']['end_checkboxes'] = array(
- '#markup' => '</div>',
- );
- }
-
- function expose_form_left(&$form, &$form_state) { }
-
- function expose_form_right(&$form, &$form_state){ }
+ function expose_form(&$form, &$form_state) { }
/**
* Validate the options form.
@@ -415,34 +405,10 @@ class views_handler extends views_object {
*/
function expose_submit($form, &$form_state) { }
- /**
+ /**
* Shortcut to display the expose/hide button.
*/
- function show_expose_button(&$form, &$form_state) {
- $form['expose_button'] = array(
- '#prefix' => '<div class="views-expose clearfix">',
- '#suffix' => '</div>',
- );
- if (empty($this->options['exposed'])) {
- $form['expose_button']['button'] = array(
- '#type' => 'submit',
- '#value' => t('Expose'),
- '#submit' => array('views_ui_config_item_form_expose'),
- );
- $form['expose_button']['markup'] = array(
- '#markup' => '<div class="description">' . t('This item is currently not exposed. If you <strong>expose</strong> it, users will be able to change the filter as they view it.') . '</div>',
- );
- }
- else {
- $form['expose_button']['button'] = array(
- '#type' => 'submit',
- '#value' => t('Hide'),
- '#submit' => array('views_ui_config_item_form_expose'),
- );
- $form['expose_button']['markup'] = array(
- '#markup' => '<div class="description">' . t('This item is currently exposed. If you <strong>hide</strong> it, users will not be able to change the filter as they view it.') . '</div>', );
- }
- }
+ function show_expose_button(&$form, &$form_state) { }
/**
* Shortcut to display the exposed options form.
@@ -452,10 +418,6 @@ class views_handler extends views_object {
return;
}
- $form['expose'] = array(
- '#prefix' => '<div class="views-expose-options clearfix">',
- '#suffix' => '</div>',
- );
$this->expose_form($form, $form_state);
// When we click the expose button, we add new gadgets to the form but they
@@ -638,7 +600,7 @@ class views_many_to_one_helper {
$this->handler = &$handler;
}
- function option_definition(&$options) {
+ static function option_definition(&$options) {
$options['reduce_duplicates'] = array('default' => FALSE);
}
@@ -1425,53 +1387,4 @@ class views_join {
/**
* @}
- */
-
-// Declare API compatibility on behalf of core modules:
-
-/**
- * Implements hook_views_api().
- *
- * This one is used as the base to reduce errors when updating.
- */
-function views_views_api() {
- return array(
- // in your modules do *not* use views_api_version()!!!
- 'api' => views_api_version(),
- 'path' => drupal_get_path('module', 'views') . '/modules',
- );
-}
-
-function aggregator_views_api() { return views_views_api(); }
-
-function book_views_api() { return views_views_api(); }
-
-function comment_views_api() { return views_views_api(); }
-
-function locale_views_api() { return views_views_api(); }
-
-function field_views_api() { return views_views_api(); }
-
-function filter_views_api() { return views_views_api(); }
-
-function node_views_api() { return views_views_api(); }
-
-function poll_views_api() { return views_views_api(); }
-
-function profile_views_api() { return views_views_api(); }
-
-function search_views_api() { return views_views_api(); }
-
-function statistics_views_api() { return views_views_api(); }
-
-function system_views_api() { return views_views_api(); }
-
-function taxonomy_views_api() { return views_views_api(); }
-
-function translation_views_api() { return views_views_api(); }
-
-function upload_views_api() { return views_views_api(); }
-
-function user_views_api() { return views_views_api(); }
-
-function contact_views_api() { return views_views_api(); }
+ */ \ No newline at end of file
diff --git a/includes/plugins.inc b/includes/plugins.inc
index 19bac33..11883ce 100644
--- a/includes/plugins.inc
+++ b/includes/plugins.inc
@@ -18,7 +18,7 @@ function views_views_plugins() {
'display' => array(
// Default settings for all display plugins.
'default' => array(
- 'title' => t('Defaults'),
+ 'title' => t('Master'),
'help' => t('Default settings for this view.'),
'handler' => 'views_plugin_display_default',
'theme' => 'views_view',
@@ -37,6 +37,7 @@ function views_views_plugins() {
'handler' => 'views_plugin_display_page',
'theme' => 'views_view',
'uses hook menu' => TRUE,
+ 'contextual links locations' => array('page'),
'use ajax' => TRUE,
'use pager' => TRUE,
'accept attachments' => TRUE,
@@ -49,6 +50,7 @@ function views_views_plugins() {
'handler' => 'views_plugin_display_block',
'theme' => 'views_view',
'uses hook block' => TRUE,
+ 'contextual links locations' => array('block'),
'use ajax' => TRUE,
'use pager' => TRUE,
'use more' => TRUE,
@@ -175,7 +177,7 @@ function views_views_plugins() {
'parent' => '',
),
'fixed' => array(
- 'title' => t('Fixed entry'),
+ 'title' => t('Fixed value'),
'handler' => 'views_plugin_argument_default_fixed',
),
'php' => array(
@@ -292,6 +294,7 @@ function views_views_plugins() {
),
'full' => array(
'title' => t('Paged output, full pager'),
+ 'short title' => t('Full'),
'help' => t('Paged output, full Drupal style'),
'handler' => 'views_plugin_pager_full',
'help topic' => 'pager-full',
@@ -299,6 +302,7 @@ function views_views_plugins() {
),
'mini' => array(
'title' => t('Paged output, mini pager'),
+ 'short title' => t('Mini'),
'help' => t('Use the mini pager output.'),
'handler' => 'views_plugin_pager_mini',
'help topic' => 'pager-mini',
@@ -422,11 +426,11 @@ function views_discover_plugins() {
class views_plugin extends views_object {
/**
* The top object of a view.
- *
+ *
* @var view
*/
var $view = NULL;
-
+
/**
* The current used display plugin.
*
@@ -487,5 +491,22 @@ class views_plugin extends views_object {
* plugin.
*/
function validate() { return array(); }
-}
+ /**
+ * Returns the summary of the settings in the display.
+ */
+ function summary_title() {
+ return t('Settings');
+ }
+ /**
+ * Return the human readable name of the display.
+ *
+ * This appears on the ui beside each plugin and beside the settings link.
+ */
+ function plugin_title() {
+ if (isset($this->definition['short title'])) {
+ return check_plain($this->definition['short title']);
+ }
+ return check_plain($this->definition['title']);
+ }
+} \ No newline at end of file
diff --git a/includes/view.inc b/includes/view.inc
index 9e0f44f..046a378 100644
--- a/includes/view.inc
+++ b/includes/view.inc
@@ -50,6 +50,9 @@ class view extends views_db_object {
// Used to store views that were previously running if we recurse.
var $old_view = array();
+ // To avoid recursion in views embebed into areas
+ var $parent_views = array();
+
/**
* Where the $query object will reside:
*
@@ -494,8 +497,8 @@ class view extends views_db_object {
break;
}
- if ($argument->is_wildcard()) {
- $arg_title = $argument->wildcard_title();
+ if ($argument->is_exception()) {
+ $arg_title = $argument->exception_title();
}
else {
$arg_title = $argument->get_title();
@@ -510,7 +513,12 @@ class view extends views_db_object {
if ($this->display_handler->uses_breadcrumb() && $argument->uses_breadcrumb()) {
$path = $this->get_url($breadcrumb_args);
if (strpos($path, '%') === FALSE) {
- $breadcrumb = !empty($argument->options['breadcrumb'])? $argument->options['breadcrumb'] : $title;
+ if (!empty($argument->options['breadcrumb_enable']) && !empty($argument->options['breadcrumb'])) {
+ $breadcrumb = $argument->options['breadcrumb'];
+ }
+ else {
+ $breadcrumb = $title;
+ }
$this->build_info['breadcrumb'][$path] = str_replace(array_keys($substitutions), $substitutions, $breadcrumb);
}
}
@@ -519,7 +527,7 @@ class view extends views_db_object {
$argument->set_breadcrumb($this->build_info['breadcrumb']);
// Test to see if we should use this argument's title
- if (!empty($argument->options['title'])) {
+ if (!empty($argument->options['title_enable']) && !empty($argument->options['title'])) {
$title = $argument->options['title'];
}
@@ -1105,6 +1113,24 @@ class view extends views_db_object {
}
/**
+ * Return the human readable name for a view.
+ *
+ * When a certain view doesn't have a human readable name return the machine readable name.
+ */
+ function get_human_name() {
+ if (!empty($this->human_name)) {
+ $human_name = $this->human_name;
+ }
+ else {
+ $human_name = $this->get_title();
+ if (empty($human_name)) {
+ $human_name = $this->name;
+ }
+ }
+ return $human_name;
+ }
+
+ /**
* Force the view to build a title.
*/
function build_title() {
@@ -1359,7 +1385,6 @@ class view extends views_db_object {
static function load_views() {
$result = db_query("SELECT DISTINCT v.* FROM {views_view} v");
$views = array();
- $vids = array();
// Load all the views.
foreach ($result as $data) {
@@ -1376,7 +1401,6 @@ class view extends views_db_object {
return array();
}
- $vids = implode(', ', array_keys($names));
// Now load all the subtables:
foreach (view::db_objects() as $key) {
$object_name = "views_$key";
@@ -1486,7 +1510,7 @@ class view extends views_db_object {
foreach ($this->display as $id => $display) {
$output .= "\n" . $indent . "/* Display: $display->display_title */\n";
- $output .= $indent . '$handler = $view->new_display(' . views_var_export($display->display_plugin, $indent) . ', ' . views_var_export($display->display_title, $indent) . ', \'' . $id . "');\n";
+ $output .= $indent . '$handler = $view->new_display(' . ctools_var_export($display->display_plugin, $indent) . ', ' . ctools_var_export($display->display_title, $indent) . ', \'' . $id . "');\n";
if (empty($display->handler)) {
// @todo -- probably need a method of exporting broken displays as
// they may simply be broken because a module is not installed. That
@@ -1826,6 +1850,8 @@ class views_db_object {
* An optional indentation for prettifying nested code.
*/
function export_row($identifier = NULL, $indent = '') {
+ ctools_include('export');
+
if (!$identifier) {
$identifier = $this->db_table;
}
@@ -1860,7 +1886,7 @@ class views_db_object {
}
}
- $output .= $indent . '$' . $identifier . '->' . $field . ' = ' . views_var_export($value, $indent) . ";\n";
+ $output .= $indent . '$' . $identifier . '->' . $field . ' = ' . ctools_var_export($value, $indent) . ";\n";
}
return $output;
}
@@ -1890,12 +1916,22 @@ class views_db_object {
if (empty($id)) {
- $title = $plugin['title'];
-
$id = $this->generate_display_id($type);
- $count = str_replace($type . '_', '', $id);
+ if ($id !== 'default') {
+ preg_match("/[0-9]/", $id, $count);
+ $count = $count[0];
+ }
+ else {
+ $count = '';
+ }
+
if (empty($title)) {
- $title = $plugin['title'] . ' ' . $count;
+ if ($count > 1) {
+ $title = $plugin['title'] . ' ' . $count;
+ }
+ else {
+ $title = $plugin['title'];
+ }
}
}
@@ -2128,12 +2164,11 @@ function views_object_types() {
'plural' => 'sorts',
),
'filter' => array(
- 'title' => t('Filters'),
- 'ltitle' => t('filters'),
- 'stitle' => t('Filter'),
- 'lstitle' => t('filter'),
+ 'title' => t('Filter criteria'),
+ 'ltitle' => t('filter criteria'),
+ 'stitle' => t('Filter criterion'),
+ 'lstitle' => t('filter criterion'),
'plural' => 'filters',
- 'options' => 'views_ui_config_filters_form',
),
'relationship' => array(
'title' => t('Relationships'),
@@ -2159,10 +2194,10 @@ function views_object_types() {
'type' => 'area',
),
'empty' => array(
- 'title' => t('Empty text'),
- 'ltitle' => t('empty text'),
- 'stitle' => t('Empty text'),
- 'lstitle' => t('Empty text'),
+ 'title' => t('No results behavior'),
+ 'ltitle' => t('no results behavior'),
+ 'stitle' => t('No results behavior'),
+ 'lstitle' => t('No results behavior'),
'plural' => 'empty',
'type' => 'area',
),
diff --git a/js/ajax.js b/js/ajax.js
index c44b628..2d02e49 100644
--- a/js/ajax.js
+++ b/js/ajax.js
@@ -5,28 +5,39 @@
*/
(function ($) {
- Drupal.ajax.prototype.commands.viewsSetForm = function(ajax, response, status) {
+ Drupal.ajax.prototype.commands.viewsSetForm = function (ajax, response, status) {
var ajax_title = Drupal.settings.views.ajax.title;
- var ajax_area = Drupal.settings.views.ajax.id;
+ var ajax_body = Drupal.settings.views.ajax.id;
+ var ajax_popup = Drupal.settings.views.ajax.popup;
$(ajax_title).html(response.title);
- $(ajax_area).html(response.output);
- Drupal.attachBehaviors($(ajax_area).add($(ajax_title)), ajax.settings);
+ $(ajax_body).html(response.output);
+ $(ajax_popup).dialog('open');
+ Drupal.attachBehaviors($(ajax_popup), ajax.settings);
if (response.url) {
- var submit = $('input[type=submit]', ajax_area).unbind('click').click(function() {
- $('form', ajax_area).append('<input type="hidden" name="' + $(this).attr('name') + '" value="' + $(this).val() + '">');
- $(this).after('<span class="views-throbbing">&nbsp</span>');
- })
- $('form', ajax_area).once('views-ajax-submit-processed').each(function() {
+ // Identify the button that was clicked so that .ajaxSubmit() can use it.
+ // We need to do this for both .click() and .mousedown() since JavaScript
+ // code might trigger either behavior.
+ var $submit_buttons = $('input[type=submit], button', ajax_body);
+ $submit_buttons.click(function(event) {
+ this.form.clk = this;
+ });
+ $submit_buttons.mousedown(function(event) {
+ this.form.clk = this;
+ });
+
+ $('form', ajax_body).once('views-ajax-submit-processed').each(function() {
var element_settings = { 'url': response.url, 'event': 'submit', 'progress': { 'type': 'throbber' } };
- var form = $(this)[0];
- form.form = form;
- Drupal.ajax[$(this).attr('id')] = new Drupal.ajax($(this).attr('id'), form, element_settings);
+ var $form = $(this);
+ var id = $form.attr('id');
+ Drupal.ajax[id] = new Drupal.ajax(id, this, element_settings);
+ Drupal.ajax[id].form = $form;
});
}
};
Drupal.ajax.prototype.commands.viewsDismissForm = function(ajax, response, status) {
Drupal.ajax.prototype.commands.viewsSetForm({}, {'title': '', 'output': Drupal.settings.views.ajax.defaultForm});
+ $(Drupal.settings.views.ajax.popup).dialog('close');
}
Drupal.ajax.prototype.commands.viewsHilite = function(ajax, response, status) {
@@ -48,17 +59,14 @@
$('#views-tabset').viewsClickTab(instance.$tabs.length);
};
- Drupal.ajax.prototype.commands.viewsDisableButtons = function(ajax, response, status) {
- $('#views-ui-edit-view-form input').attr('disabled', 'disabled');
- }
-
- Drupal.ajax.prototype.commands.viewsEnableButtons = function(ajax, response, status) {
- $('#views-ui-edit-view-form input').removeAttr('disabled');
+ Drupal.ajax.prototype.commands.viewsShowButtons = function(ajax, response, status) {
+ $('div.views-edit-view div.form-actions').removeClass('js-hide');
+ $('div.views-edit-view div.view-changed.messages').removeClass('js-hide');
}
Drupal.ajax.prototype.commands.viewsTriggerPreview = function(ajax, response, status) {
- if ($('#views-live-preview div.form-item-live-preview input').is(':checked')) {
- $('#views-live-preview input[type=submit]').trigger('click');
+ if ($('input#edit-displays-live-preview').is(':checked')) {
+ $('#preview-submit').trigger('mousedown');
}
}
@@ -70,10 +78,26 @@
}
/**
+ * Trigger preview when the "live preview" checkbox is checked.
+ */
+ Drupal.behaviors.livePreview = {
+ attach: function (context) {
+ $('input#edit-displays-live-preview', context).once('views-ajax-processed').click(function() {
+ if ($(this).is(':checked')) {
+ $('#preview-submit').trigger('mousedown');
+ }
+ else {
+ $('#views-live-preview').empty();
+ }
+ });
+ }
+ }
+
+ /**
* Sync preview display.
*/
Drupal.behaviors.syncPreviewDisplay = {
- attach: function(context) {
+ attach: function (context) {
$("#views-tabset a").once('views-ajax-processed').click(function() {
var href = $(this).attr('href');
// Cut of #views-tabset.
@@ -85,7 +109,21 @@
}
Drupal.behaviors.viewsAjax = {
- attach: function(context) {
+ attach: function (context, settings) {
+ if (!settings.views) {
+ return;
+ }
+ // Create a jQuery UI dialog, but leave it closed.
+ var dialog_area = $(settings.views.ajax.popup, context);
+ dialog_area.dialog({
+ 'autoOpen': false,
+ 'dialogClass': 'views-ui-dialog',
+ 'modal': true,
+ 'position': 'center',
+ 'resizable': false,
+ 'width': 750
+ });
+
var base_element_settings = {
'event': 'click',
'progress': { 'type': 'throbber' }
@@ -101,7 +139,7 @@
Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
});
- $('div#views-live-preview form input[type=submit], div#views-live-preview a')
+ $('div#views-live-preview a')
.once('views-ajax-processed').each(function () {
var element_settings = base_element_settings;
// Set the URL to go to the anchor.
@@ -111,13 +149,9 @@
return true;
}
}
- else if ($(this).attr('action')) {
- element_settings.url = $(this).attr('action');
- }
- else if (this.form && $(this.form).attr('action')) {
- element_settings.url = $(this.form).attr('action');
- }
+ element_settings.wrapper = 'views-live-preview';
+ element_settings.method = 'html';
var base = $(this).attr('id');
Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
});
diff --git a/js/ajax_view.js b/js/ajax_view.js
index 64ab7af..76a58b9 100644
--- a/js/ajax_view.js
+++ b/js/ajax_view.js
@@ -1,4 +1,3 @@
-
/**
* @file ajaxView.js
*
diff --git a/js/base.js b/js/base.js
index 734c81d..3e40d89 100644
--- a/js/base.js
+++ b/js/base.js
@@ -18,11 +18,11 @@ Drupal.behaviors.viewsTabs = {
});
}
- $('a.views-remove-link').once('views-processed').click(function() {
+ $('a.views-remove-link').once('views-processed').click(function(event) {
var id = $(this).attr('id').replace('views-remove-link-', '');
$('#views-row-' + id).hide();
$('#views-removed-' + id).attr('checked', true);
- return false;
+ event.preventDefault();
});
/**
* Here is to handle display deletion
@@ -40,34 +40,6 @@ Drupal.behaviors.viewsTabs = {
};
/**
- * For IE, attach some javascript so that our hovers do what they're supposed
- * to do.
- */
-Drupal.behaviors.viewsHoverlinks = function() {
- if ($.browser.msie) {
- // If IE, attach a hover event so we can see our admin links.
- $("div.view:not(.views-hover-processed)").addClass('views-hover-processed').hover(
- function() {
- $('div.views-hide', this).addClass("views-hide-hover"); return true;
- },
- function(){
- $('div.views-hide', this).removeClass("views-hide-hover"); return true;
- }
- );
- $("div.views-admin-links:not(.views-hover-processed)")
- .addClass('views-hover-processed')
- .hover(
- function() {
- $(this).addClass("views-admin-links-hover"); return true;
- },
- function(){
- $(this).removeClass("views-admin-links-hover"); return true;
- }
- );
- }
-}
-
-/**
* Helper function to parse a querystring.
*/
Drupal.Views.parseQueryString = function (query) {
diff --git a/js/tabs.js b/js/tabs.js
index a51f7b7..97edcf7 100644
--- a/js/tabs.js
+++ b/js/tabs.js
@@ -1,4 +1,3 @@
-
/**
* @file tabs.js
* jQuery UI Tabs (Tabs 3)
diff --git a/js/views-admin.js b/js/views-admin.js
new file mode 100644
index 0000000..ff51e5d
--- /dev/null
+++ b/js/views-admin.js
@@ -0,0 +1,797 @@
+// $Id$
+
+Drupal.viewsUi = {};
+
+
+Drupal.behaviors.viewsUiAddView = {};
+
+/**
+ * In the add view wizard, use the view name to prepopulate form fields such as
+ * page title and menu link.
+ */
+Drupal.behaviors.viewsUiAddView.attach = function (context, settings) {
+ var $ = jQuery;
+ var exclude, replace, suffix;
+ // Set up regular expressions to allow only numbers, letters, and dashes.
+ exclude = new RegExp('[^a-z0-9\\-]+', 'g');
+ replace = '-';
+
+ // The page title, block title, and menu link fields can all be prepopulated
+ // with the view name - no regular expression needed.
+ var $fields = $(context).find('[id^="edit-page-title"], [id^="edit-block-title"], [id^="edit-page-link-properties-title"]');
+ if ($fields.length) {
+ if (!this.fieldsFiller) {
+ this.fieldsFiller = new Drupal.viewsUi.FormFieldFiller($fields);
+ }
+ else {
+ // After an AJAX response, this.fieldsFiller will still have event
+ // handlers bound to the old version of the form fields (which don't exist
+ // anymore). The event handlers need to be unbound and then rebound to the
+ // new markup. Note that jQuery.live is difficult to make work in this
+ // case because the IDs of the form fields change on every AJAX response.
+ this.fieldsFiller.rebind($fields);
+ }
+ }
+
+ // Prepopulate the path field with a URLified version of the view name.
+ var $pathField = $(context).find('[id^="edit-page-path"]');
+ if ($pathField.length) {
+ if (!this.pathFiller) {
+ this.pathFiller = new Drupal.viewsUi.FormFieldFiller($pathField, exclude, replace);
+ }
+ else {
+ this.pathFiller.rebind($pathField);
+ }
+ }
+
+ // Populate the RSS feed field with a URLified version of the view name, and
+ // an .xml suffix (to make it unique).
+ var $feedField = $(context).find('[id^="edit-page-feed-properties-path"]');
+ if ($feedField.length) {
+ if (!this.feedFiller) {
+ suffix = '.xml';
+ this.feedFiller = new Drupal.viewsUi.FormFieldFiller($feedField, exclude, replace, suffix);
+ }
+ else {
+ this.feedFiller.rebind($feedField);
+ }
+ }
+};
+
+/**
+ * Constructor for the Drupal.viewsUi.FormFieldFiller object.
+ *
+ * Prepopulates a form field based on the view name.
+ *
+ * @param $target
+ * A jQuery object representing the form field to prepopulate.
+ * @param exclude
+ * Optional. A regular expression representing characters to exclude from the
+ * target field.
+ * @param replace
+ * Optional. A string to use as the replacement value for disallowed
+ * characters.
+ * @param suffix
+ * Optional. A suffix to append at the end of the target field content.
+ */
+Drupal.viewsUi.FormFieldFiller = function ($target, exclude, replace, suffix) {
+ var $ = jQuery;
+ this.source = $('#edit-human-name');
+ this.target = $target;
+ this.exclude = exclude || false;
+ this.replace = replace || '';
+ this.suffix = suffix || '';
+
+ // Create bound versions of this instance's object methods to use as event
+ // handlers. This will let us easily unbind those specific handlers later on.
+ // NOTE: jQuery.proxy will not work for this because it assumes we want only
+ // one bound version of an object method, whereas we need one version per
+ // object instance.
+ var self = this;
+ this.populate = function () {return self._populate.call(self);};
+ this.unbind = function () {return self._unbind.call(self);};
+
+ this.bind();
+ // Object constructor; no return value.
+};
+
+/**
+ * Bind the form-filling behavior.
+ */
+Drupal.viewsUi.FormFieldFiller.prototype.bind = function () {
+ this.unbind();
+ // Populate the form field when the source changes.
+ this.source.bind('keyup.viewsUi change.viewsUi', this.populate);
+ // Quit populating the field as soon as it gets focus.
+ this.target.bind('focus.viewsUi', this.unbind);
+};
+
+/**
+ * Get the source form field value as altered by the passed-in parameters.
+ */
+Drupal.viewsUi.FormFieldFiller.prototype.getTransliterated = function () {
+ var from = this.source.val();
+ if (this.exclude) {
+ from = from.toLowerCase().replace(this.exclude, this.replace);
+ }
+ return from + this.suffix;
+};
+
+/**
+ * Populate the target form field with the altered source field value.
+ */
+Drupal.viewsUi.FormFieldFiller.prototype._populate = function () {
+ var transliterated = this.getTransliterated();
+ this.target.val(transliterated);
+};
+
+/**
+ * Stop prepopulating the form fields.
+ */
+Drupal.viewsUi.FormFieldFiller.prototype._unbind = function () {
+ this.source.unbind('keyup.viewsUi change.viewsUi', this.populate);
+ this.target.unbind('focus.viewsUi', this.unbind);
+};
+
+/**
+ * Bind event handlers to the new form fields, after they're replaced via AJAX.
+ */
+Drupal.viewsUi.FormFieldFiller.prototype.rebind = function ($fields) {
+ this.target = $fields;
+ this.bind();
+}
+
+Drupal.behaviors.addItemForm = {};
+Drupal.behaviors.addItemForm.attach = function (context) {
+ var $ = jQuery;
+ // The add item form may have an id of views-ui-add-item-form--n.
+ var $form = $(context).find('form[id^="views-ui-add-item-form"]').first();
+ // Make sure we don't add more than one event handler to the same form.
+ $form = $form.once('views-ui-add-item-form');
+ if ($form.length) {
+ new Drupal.viewsUi.addItemForm($form);
+ }
+}
+
+Drupal.viewsUi.addItemForm = function($form) {
+ this.$form = $form;
+ this.$form.find('.views-filterable-options :checkbox').click(jQuery.proxy(this.handleCheck, this));
+ // Find the wrapper of the displayed text.
+ this.$selected_div = this.$form.find('.views-selected-options').parent();
+ this.$selected_div.hide();
+ this.checkedItems = [];
+}
+
+Drupal.viewsUi.addItemForm.prototype.handleCheck = function (event) {
+ var $target = jQuery(event.target);
+ var label = jQuery.trim($target.next().text());
+ // Add/remove the checked item to the list.
+ if ($target.is(':checked')) {
+ this.$selected_div.show();
+ this.checkedItems.push(label);
+ }
+ else {
+ var length = this.checkedItems.length;
+ var position = jQuery.inArray(label, this.checkedItems);
+ // Delete the item from the list and take sure that the list doesn't have undefined items left.
+ for (var i = 0; i < this.checkedItems.length; i++) {
+ if (i == position) {
+ this.checkedItems.splice(i, 1);
+ i--;
+ }
+ }
+ // Hide it again if none item is selected.
+ if (this.checkedItems.length == 0) {
+ this.$selected_div.hide();
+ }
+ }
+ this.refreshCheckedItems();
+}
+
+
+/**
+ * Refresh the display of the checked items.
+ */
+Drupal.viewsUi.addItemForm.prototype.refreshCheckedItems = function() {
+ // Perhaps we should precache the text div, too.
+ this.$selected_div.find('.views-selected-options').html(this.checkedItems.join(', '));
+}
+
+
+/**
+ * The input field items that add displays must be rendered as <input> elements.
+ * The following behavior detaches the <input> elements from the DOM, wraps them
+ * in an unordered list, then appends them to the list of tabs.
+ */
+Drupal.behaviors.viewsUiRenderAddViewButton = {};
+
+Drupal.behaviors.viewsUiRenderAddViewButton.attach = function (context, settings) {
+ var $ = jQuery;
+ // Build the add display menu and pull the display input buttons into it.
+ var $menu = $('#views-ui-edit-form .secondary', context).once('views-ui-render-add-view-button-processed');
+ if (!$menu.length) {
+ return;
+ }
+ var $addDisplayDropdown = $('<li class="add"><a href="#"><span class="icon add"></span>Add</a><ul class="action-list" style="display:none;"></ul></li>');
+ var $displayButtons = $menu.nextAll('input.add-display').detach();
+ $displayButtons.appendTo($addDisplayDropdown.find('.action-list')).wrap('<li>')
+ .parent().first().addClass('first').end().last().addClass('last');
+ // Remove the 'Add ' prefix from the button labels since they're being palced
+ // in an 'Add' dropdown.
+ // @todo This assumes English, but so does $addDisplayDropdown above. Add
+ // support for translation.
+ $displayButtons.each(function () {
+ var label = $(this).val();
+ if (label.substr(0, 4) == 'Add ') {
+ $(this).val(label.substr(4));
+ }
+ });
+ $addDisplayDropdown.appendTo($menu);
+
+ // Add the click handler for the add display button
+ $('li.add > a', $menu).bind('click', function (event) {
+ event.preventDefault();
+ var $trigger = $(this);
+ Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
+ });
+ // Add a mouseleave handler to close the dropdown when the user mouses
+ // away from the item. We use mouseleave instead of mouseout because
+ // the user is going to trigger mouseout when she moves from the trigger
+ // link to the sub menu items.
+ // We use the live binder because the open class on this item will be
+ // toggled on and off and we want the handler to take effect in the cases
+ // that the class is present, but not when it isn't.
+ $('li.add', $menu).live('mouseleave', function (event) {
+ var $this = $(this);
+ var $trigger = $this.children('a[href="#"]');
+ if ($this.children('.action-list').is(':visible')) {
+ Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu($trigger);
+ }
+ });
+};
+
+/**
+ * @note [@jessebeach] I feel like the following should be a more generic function and
+ * not written specifically for this UI, but I'm not sure where to put it.
+ */
+Drupal.behaviors.viewsUiRenderAddViewButton.toggleMenu = function ($trigger) {
+ $trigger.parent().toggleClass('open');
+ $trigger.next().slideToggle('fast');
+}
+
+
+Drupal.behaviors.viewsUiSearchOptions = {};
+
+Drupal.behaviors.viewsUiSearchOptions.attach = function (context) {
+ var $ = jQuery;
+ // The add item form may have an id of views-ui-add-item-form--n.
+ var $form = $(context).find('form[id^="views-ui-add-item-form"]').first();
+ // Make sure we don't add more than one event handler to the same form.
+ $form = $form.once('views-ui-filter-options');
+ if ($form.length) {
+ new Drupal.viewsUi.OptionsSearch($form);
+ }
+};
+
+/**
+ * Constructor for the viewsUi.OptionsSearch object.
+ *
+ * The OptionsSearch object filters the available options on a form according
+ * to the user's search term. Typing in "taxonomy" will show only those options
+ * containing "taxonomy" in their label.
+ */
+Drupal.viewsUi.OptionsSearch = function ($form) {
+ this.$form = $form;
+ // Add a keyup handler to the search box.
+ this.$searchBox = this.$form.find('#edit-options-search');
+ this.$searchBox.keyup(jQuery.proxy(this.handleKeyup, this));
+ // Get a list of option labels and their corresponding divs and maintain it
+ // in memory, so we have as little overhead as possible at keyup time.
+ this.options = this.getOptions(this.$form.find('.filterable-option'));
+ // Restripe on initial loading.
+ this.handleKeyup();
+ // Trap the ENTER key in the search box so that it doesn't submit the form.
+ this.$searchBox.keypress(function(event) {
+ if (event.which == 13) {
+ event.preventDefault();
+ }
+ });
+};
+
+/**
+ * Assemble a list of all the filterable options on the form.
+ *
+ * @param $allOptions
+ * A jQuery object representing the rows of filterable options to be
+ * shown and hidden depending on the user's search terms.
+ */
+Drupal.viewsUi.OptionsSearch.prototype.getOptions = function ($allOptions) {
+ var $ = jQuery;
+ var i, $label, $option;
+ var options = [];
+ var length = $allOptions.length;
+ for (i = 0; i < length; i++) {
+ $option = $($allOptions[i]);
+ $label = $option.find('label');
+ options[i] = {
+ // Search on the lowercase version of the label text.
+ 'labelText': $label.text().toLowerCase(),
+ // Maintain a reference to the jQuery object for each row, so we don't
+ // have to create a new object inside the performance-sensitive keyup
+ // handler.
+ '$div': $option
+ }
+ }
+ return options;
+};
+
+/**
+ * Keyup handler for the search box that hides or shows the relevant options.
+ */
+Drupal.viewsUi.OptionsSearch.prototype.handleKeyup = function (event) {
+ var found, i, j, option, search, words, wordsLength, zebraClass, zebraCounter;
+
+ // Determine the user's search query. The label text has been converted to
+ // lowercase.
+ search = this.$searchBox.val().toLowerCase();
+ words = search.split(' ');
+ wordsLength = words.length;
+
+ // Start the counter for restriping rows.
+ zebraCounter = 0;
+
+ // Search through the labels in the form for matching text.
+ var length = this.options.length;
+ for (i = 0; i < length; i++) {
+ // Use a local variable for the option being searched, for performance.
+ option = this.options[i];
+ found = true;
+ // Each word in the search string has to match the label in order for the
+ // label to be shown.
+ for (j = 0; j < wordsLength; j++) {
+ if (option.labelText.indexOf(words[j]) === -1) {
+ found = false;
+ }
+ }
+ if (found) {
+ // Show the checkbox row, and restripe it.
+ zebraClass = (zebraCounter % 2) ? 'odd' : 'even';
+ option.$div.show();
+ option.$div.removeClass('even odd');
+ option.$div.addClass(zebraClass);
+ zebraCounter++;
+ }
+ else {
+ // The search string wasn't found; hide this item.
+ option.$div.hide();
+ }
+ }
+};
+
+Drupal.behaviors.viewsUiPreview = {};
+Drupal.behaviors.viewsUiPreview.attach = function (context, settings) {
+ var $ = jQuery;
+ var argumentsBucket = $('.views-display-column .arguments', context);
+
+ // Only act on the edit view form.
+ if (argumentsBucket.length == 0) {
+ return;
+ }
+
+ // If the display has no arguments, hide the form where you enter arguments
+ // for the live preview.
+ var arguments = $('.views-display-column .arguments .views-display-setting a', context);
+ if (arguments.length) {
+ $('.form-item-displays-preview-form-view-args').show();
+ }
+ else {
+ $('.form-item-displays-preview-form-view-args').hide();
+ }
+};
+
+
+Drupal.behaviors.viewsUiRearrangeFilter = {};
+Drupal.behaviors.viewsUiRearrangeFilter.attach = function (context, settings) {
+ var $ = jQuery;
+ // Only act on the rearrange filter form.
+ if (typeof Drupal.tableDrag == 'undefined' || typeof Drupal.tableDrag['views-rearrange-filters'] == 'undefined') {
+ return;
+ }
+
+ var table = $('#views-rearrange-filters', context).once('views-rearrange-filters');
+ var operator = $('.form-item-filter-groups-operator', context).once('views-rearrange-filters');
+ if (table.length) {
+ new Drupal.viewsUi.rearrangeFilterHandler(table, operator);
+ }
+};
+
+/**
+ * Improve the UI of the rearrange filters dialog box.
+ */
+Drupal.viewsUi.rearrangeFilterHandler = function (table, operator) {
+ var $ = jQuery;
+ // Keep a reference to the <table> being altered and to the div containing
+ // the filter groups operator dropdown (if it exists).
+ this.table = table;
+ this.operator = operator;
+ this.hasGroupOperator = this.operator.length > 0;
+
+ // Keep a reference to all draggable rows within the table.
+ this.draggableRows = $('.draggable', table);
+
+ // Keep a reference to the buttons for adding and removing filter groups.
+ this.addGroupButton = $('input#views-add-group');
+ this.removeGroupButtons = $('input.views-remove-group', table);
+
+ // Add links that duplicate the functionality of the (hidden) add and remove
+ // buttons.
+ this.insertAddRemoveFilterGroupLinks();
+
+ // When there is a filter groups operator dropdown on the page, create
+ // duplicates of the dropdown between each pair of filter groups.
+ if (this.hasGroupOperator) {
+ this.dropdowns = this.duplicateGroupsOperator();
+ this.syncGroupsOperators();
+ }
+
+ // Add methods to the tableDrag instance to account for operator cells (which
+ // span multiple rows), the operator labels next to each filter (e.g., "And"
+ // or "Or"), the filter groups, and other special aspects of this tableDrag
+ // instance.
+ this.modifyTableDrag();
+
+ // Initialize the operator labels (e.g., "And" or "Or") that are displayed
+ // next to the filters in each group, and bind a handler so that they change
+ // based on the values of the operator dropdown within that group.
+ this.redrawOperatorLabels();
+ $('.views-group-title select', table)
+ .once('views-rearrange-filter-handler')
+ .bind('change.views-rearrange-filter-handler', $.proxy(this, 'redrawOperatorLabels'));
+
+ // Bind handlers so that when a "Remove" link is clicked, we:
+ // - Update the rowspans of cells containing an operator dropdown (since they
+ // need to change to reflect the number of rows in each group).
+ // - Redraw the operator labels next to the filters in the group (since the
+ // filter that is currently displayed last in each group is not supposed to
+ // have a label display next to it).
+ $('a.views-groups-remove-link', this.table)
+ .once('views-rearrange-filter-handler')
+ .bind('click.views-rearrange-filter-handler', $.proxy(this, 'updateRowspans'))
+ .bind('click.views-rearrange-filter-handler', $.proxy(this, 'redrawOperatorLabels'));
+};
+
+/**
+ * Insert links that allow filter groups to be added and removed.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.insertAddRemoveFilterGroupLinks = function () {
+ var $ = jQuery;
+
+ // Insert a link for adding a new group at the top of the page, and make it
+ // match the action links styling used in a typical page.tpl.php. Note that
+ // Drupal does not provide a theme function for this markup, so this is the
+ // best we can do.
+ $('<ul class="action-links"><li><a id="views-add-group-link" href="#">' + this.addGroupButton.val() + '</a></li></ul>')
+ .prependTo(this.table.parent())
+ // When the link is clicked, dynamically click the hidden form button for
+ // adding a new filter group.
+ .once('views-rearrange-filter-handler')
+ .bind('click.views-rearrange-filter-handler', $.proxy(this, 'clickAddGroupButton'));
+
+ // Find each (visually hidden) button for removing a filter group and insert
+ // a link next to it.
+ var length = this.removeGroupButtons.length;
+ for (i = 0; i < length; i++) {
+ var $removeGroupButton = $(this.removeGroupButtons[i]);
+ var buttonId = $removeGroupButton.attr('id');
+ $('<a href="#" class="views-remove-group-link">' + Drupal.t('Remove group') + '</a>')
+ .insertBefore($removeGroupButton)
+ // When the link is clicked, dynamically click the corresponding form
+ // button.
+ .once('views-rearrange-filter-handler')
+ .bind('click.views-rearrange-filter-handler', {buttonId: buttonId}, $.proxy(this, 'clickRemoveGroupButton'));
+ }
+};
+
+/**
+ * Dynamically click the button that adds a new filter group.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.clickAddGroupButton = function () {
+ // Due to conflicts between Drupal core's AJAX system and the Views AJAX
+ // system, the only way to get this to work seems to be to trigger both the
+ // .mousedown() and .submit() events.
+ this.addGroupButton.mousedown();
+ this.addGroupButton.submit();
+ return false;
+};
+
+/**
+ * Dynamically click a button for removing a filter group.
+ *
+ * @param event
+ * Event being triggered, with event.data.buttonId set to the ID of the
+ * form button that should be clicked.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.clickRemoveGroupButton = function (event) {
+ // For some reason, here we only need to trigger .submit(), unlike for
+ // Drupal.viewsUi.rearrangeFilterHandler.prototype.clickAddGroupButton()
+ // where we had to trigger .mousedown() also.
+ jQuery('input#' + event.data.buttonId, this.table).submit();
+ return false;
+};
+
+/**
+ * Move the groups operator so that it's between the first two groups, and
+ * duplicate it between any subsequent groups.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.duplicateGroupsOperator = function () {
+ var $ = jQuery;
+ var dropdowns, newRow;
+
+ var titleRows = $('tr.views-group-title'), titleRow;
+
+ // Get rid of the explanatory text around the operator; its placement is
+ // explanatory enough.
+ this.operator.find('label').add('div.description').addClass('element-invisible');
+ this.operator.find('select').addClass('form-select');
+
+ // Keep a list of the operator dropdowns, so we can sync their behavior later.
+ dropdowns = this.operator;
+
+ // Move the operator to a new row just above the second group.
+ titleRow = $('tr#views-group-title-1');
+ newRow = $('<tr class="filter-group-operator-row"><td colspan="5"></td></tr>');
+ newRow.find('td').append(this.operator);
+ newRow.insertBefore(titleRow);
+ var i, length = titleRows.length;
+ // Starting with the third group, copy the operator to a new row above the
+ // group title.
+ for (i = 2; i < length; i++) {
+ titleRow = $(titleRows[i]);
+ // Make a copy of the operator dropdown and put it in a new table row.
+ var fakeOperator = this.operator.clone();
+ fakeOperator.attr('id', '');
+ newRow = $('<tr class="filter-group-operator-row"><td colspan="5"></td></tr>');
+ newRow.find('td').append(fakeOperator);
+ newRow.insertBefore(titleRow);
+ dropdowns = dropdowns.add(fakeOperator);
+ }
+
+ return dropdowns;
+};
+
+/**
+ * Make the duplicated groups operators change in sync with each other.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.syncGroupsOperators = function () {
+ if (this.dropdowns.length < 2) {
+ // We only have one dropdown (or none at all), so there's nothing to sync.
+ return;
+ }
+
+ this.dropdowns.change(jQuery.proxy(this, 'operatorChangeHandler'));
+};
+
+/**
+ * Click handler for the operators that appear between filter groups.
+ *
+ * Forces all operator dropdowns to have the same value.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.operatorChangeHandler = function (event) {
+ var $ = jQuery;
+ var $target = $(event.target);
+ var operators = this.dropdowns.find('select').not($target);
+
+ // Change the other operators to match this new value.
+ operators.val($target.val());
+};
+
+Drupal.viewsUi.rearrangeFilterHandler.prototype.modifyTableDrag = function () {
+ var tableDrag = Drupal.tableDrag['views-rearrange-filters'];
+ var filterHandler = this;
+
+ /**
+ * Override the row.onSwap method from tabledrag.js.
+ *
+ * When a row is dragged to another place in the table, several things need
+ * to occur.
+ * - The row needs to be moved so that it's within one of the filter groups.
+ * - The operator cells that span multiple rows need their rowspan attributes
+ * updated to reflect the number of rows in each group.
+ * - The operator labels that are displayed next to each filter need to be
+ * redrawn, to account for the row's new location.
+ */
+ tableDrag.row.prototype.onSwap = function () {
+ if (filterHandler.hasGroupOperator) {
+ // Make sure the row that just got moved (this.group) is inside one of
+ // the filter groups (i.e. below an empty marker row or a draggable). If
+ // it isn't, move it down one.
+ var thisRow = jQuery(this.group);
+ var previousRow = thisRow.prev('tr');
+ if (previousRow.length && !previousRow.hasClass('group-message') && !previousRow.hasClass('draggable')) {
+ // Move the dragged row down one.
+ var next = thisRow.next();
+ if (next.is('tr')) {
+ this.swap('after', next);
+ }
+ }
+ filterHandler.updateRowspans();
+ }
+ // Redraw the operator labels that are displayed next to each filter, to
+ // account for the row's new location.
+ filterHandler.redrawOperatorLabels();
+ };
+
+ /**
+ * Override the onDrop method from tabledrag.js.
+ */
+ tableDrag.onDrop = function () {
+ var $ = jQuery;
+
+ // If the tabledrag change marker (i.e., the "*") has been inserted inside
+ // a row after the operator label (i.e., "And" or "Or") rearrange the items
+ // so the operator label continues to appear last.
+ var changeMarker = $(this.oldRowElement).find('.tabledrag-changed');
+ if (changeMarker.length) {
+ // Search for occurrences of the operator label before the change marker,
+ // and reverse them.
+ var operatorLabel = changeMarker.prevAll('.views-operator-label');
+ if (operatorLabel.length) {
+ operatorLabel.insertAfter(changeMarker);
+ }
+ }
+
+ // Make sure the "group" dropdown is properly updated when rows are dragged
+ // into an empty filter group. This is borrowed heavily from the block.js
+ // implementation of tableDrag.onDrop().
+ var groupRow = $(this.rowObject.element).prevAll('tr.group-message').get(0);
+ var groupName = groupRow.className.replace(/([^ ]+[ ]+)*group-([^ ]+)-message([ ]+[^ ]+)*/, '$2');
+ var groupField = $('select.views-group-select', this.rowObject.element);
+ if ($(this.rowObject.element).prev('tr').is('.group-message') && !groupField.is('.views-group-select-' + groupName)) {
+ var oldGroupName = groupField.attr('class').replace(/([^ ]+[ ]+)*views-group-select-([^ ]+)([ ]+[^ ]+)*/, '$2');
+ groupField.removeClass('views-group-select-' + oldGroupName).addClass('views-group-select-' + groupName);
+ groupField.val(groupName);
+ }
+ };
+};
+
+
+/**
+ * Redraw the operator labels that are displayed next to each filter.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.redrawOperatorLabels = function () {
+ var $ = jQuery;
+ for (i = 0; i < this.draggableRows.length; i++) {
+ // Within the row, the operator labels are displayed inside the first table
+ // cell (next to the filter name).
+ var $draggableRow = $(this.draggableRows[i]);
+ var $firstCell = $('td:first', $draggableRow);
+ if ($firstCell.length) {
+ // The value of the operator label ("And" or "Or") is taken from the
+ // first operator dropdown we encounter, going backwards from the current
+ // row. This dropdown is the one associated with the current row's filter
+ // group.
+ var operatorValue = $draggableRow.prevAll('.views-group-title').find('option:selected').html();
+ var operatorLabel = '<span class="views-operator-label">' + operatorValue + '</span>';
+ // If the next visible row after this one is a draggable filter row,
+ // display the operator label next to the current row. (Checking for
+ // visibility is necessary here since the "Remove" links hide the removed
+ // row but don't actually remove it from the document).
+ var $nextRow = $draggableRow.nextAll(':visible').eq(0);
+ var $existingOperatorLabel = $firstCell.find('.views-operator-label');
+ if ($nextRow.hasClass('draggable')) {
+ // If an operator label was already there, replace it with the new one.
+ if ($existingOperatorLabel.length) {
+ $existingOperatorLabel.replaceWith(operatorLabel);
+ }
+ // Otherwise, append the operator label to the end of the table cell.
+ else {
+ $firstCell.append(operatorLabel);
+ }
+ }
+ // If the next row doesn't contain a filter, then this is the last row
+ // in the group. We don't want to display the operator there (since
+ // operators should only display between two related filters, e.g.
+ // "filter1 AND filter2 AND filter3"). So we remove any existing label
+ // that this row has.
+ else {
+ $existingOperatorLabel.remove();
+ }
+ }
+ }
+};
+
+/**
+ * Update the rowspan attribute of each cell containing an operator dropdown.
+ */
+Drupal.viewsUi.rearrangeFilterHandler.prototype.updateRowspans = function () {
+ var $ = jQuery;
+ var i, $row, $currentEmptyRow, draggableCount, $operatorCell;
+ var rows = $(this.table).find('tr');
+ var length = rows.length;
+ for (i = 0; i < length; i++) {
+ $row = $(rows[i]);
+ if ($row.hasClass('views-group-title')) {
+ // This row is a title row.
+ // Keep a reference to the cell containing the dropdown operator.
+ $operatorCell = $($row.find('td.group-operator'));
+ // Assume this filter group is empty, until we find otherwise.
+ draggableCount = 0;
+ $currentEmptyRow = $row.next('tr');
+ $currentEmptyRow.removeClass('group-populated').addClass('group-empty');
+ // The cell with the dropdown operator should span the title row and
+ // the "this group is empty" row.
+ $operatorCell.attr('rowspan', 2);
+ }
+ else if (($row).hasClass('draggable') && $row.is(':visible')) {
+ // We've found a visible filter row, so we now know the group isn't empty.
+ draggableCount++;
+ $currentEmptyRow.removeClass('group-empty').addClass('group-populated');
+ // The operator cell should span all draggable rows, plus the title.
+ $operatorCell.attr('rowspan', draggableCount + 1);
+ }
+ }
+};
+
+Drupal.behaviors.viewsFilterConfigSelectAll = {};
+
+/**
+ * Add a select all checkbox, which checks each checkbox at once.
+ */
+Drupal.behaviors.viewsFilterConfigSelectAll.attach = function(context) {
+ var $ = jQuery;
+ // Show the select all checkbox.
+ $('#views-ui-config-item-form div.form-item-options-value-all', context).once(function() {
+ $(this).show();
+ })
+ .find('input[type=checkbox]')
+ .click(function() {
+ var checked = $(this).is(':checked');
+ // Update all checkbox beside the select all checkbox.
+ $(this).parents('.form-checkboxes').find('input[type=checkbox]').each(function() {
+ $(this).attr('checked', checked);
+ });
+ });
+};
+
+/**
+ * Ensure the desired default button is used when a form is implcitly submitted via an ENTER press on textfields, radios, and checkboxes.
+ *
+ * @see http://www.w3.org/TR/html5/association-of-controls-and-forms.html#implicit-submission
+ */
+Drupal.behaviors.viewsImplicitFormSubmission = {};
+Drupal.behaviors.viewsImplicitFormSubmission.attach = function (context, settings) {
+ var $ = jQuery;
+ $(':text, :password, :radio, :checkbox', context).once('viewsImplicitFormSubmission', function() {
+ $(this).keypress(function(event) {
+ if (event.which == 13) {
+ var formId = this.form.id;
+ if (formId && settings.viewsImplicitFormSubmission && settings.viewsImplicitFormSubmission[formId] && settings.viewsImplicitFormSubmission[formId].defaultButton) {
+ event.preventDefault();
+ var buttonId = settings.viewsImplicitFormSubmission[formId].defaultButton;
+ var $button = $('#' + buttonId, this.form);
+ if ($button.length == 1 && $button.is(':enabled')) {
+ if (Drupal.ajax && Drupal.ajax[buttonId]) {
+ $button.trigger(Drupal.ajax[buttonId].element_settings.event);
+ }
+ else {
+ $button.click();
+ }
+ }
+ }
+ }
+ });
+ });
+};
+
+/**
+ * Remove icon class from elements that are themed as buttons or dropbuttons
+ */
+Drupal.behaviors.viewsRemoveIconClass = {};
+Drupal.behaviors.viewsRemoveIconClass.attach = function (context, settings) {
+ var $ = jQuery;
+ $('.ctools-button', context).once('RemoveIconClass', function () {
+ $this = $(this);
+ $('.icon', $this).removeClass('icon');
+ $('.horizontal', $this).removeClass('horizontal');
+ });
+}
diff --git a/js/views-contextual.js b/js/views-contextual.js
new file mode 100644
index 0000000..8dd6cf2
--- /dev/null
+++ b/js/views-contextual.js
@@ -0,0 +1,18 @@
+// $Id$
+
+/**
+ * @file
+ * Javascript related to contextual links.
+ */
+(function ($) {
+
+Drupal.behaviors.viewsContextualLinks = {
+ attach: function (context) {
+ // If there are views-related contextual links attached to the main page
+ // content, find the smallest region that encloses both the links and the
+ // view, and display it as a contextual links region.
+ $('.views-contextual-links-page', context).closest(':has(.view)').addClass('contextual-links-region');
+ }
+};
+
+})(jQuery);
diff --git a/js/views-list.js b/js/views-list.js
new file mode 100644
index 0000000..727eb50
--- /dev/null
+++ b/js/views-list.js
@@ -0,0 +1,23 @@
+// $Id: $
+
+/**
+ * @file
+ * Javascript related to the main view list.
+ */
+(function ($) {
+
+Drupal.behaviors.viewsUIList = {
+ attach: function (context) {
+ $('#ctools-export-ui-list-items thead a').once('views-ajax-processed').each(function() {
+ $(this).click(function() {
+ var query = $.deparam.querystring(this.href);
+ $('#ctools-export-ui-list-form select[name=order]').val(query['order']);
+ $('#ctools-export-ui-list-form select[name=sort]').val(query['sort']);
+ $('#ctools-export-ui-list-form input.ctools-auto-submit-click').trigger('click');
+ return false;
+ });
+ });
+ }
+};
+
+})(jQuery);
diff --git a/modules/aggregator/views_handler_field_aggregator_category.inc b/modules/aggregator/views_handler_field_aggregator_category.inc
index b1f5a01..a8a8ad2 100644
--- a/modules/aggregator/views_handler_field_aggregator_category.inc
+++ b/modules/aggregator/views_handler_field_aggregator_category.inc
@@ -23,13 +23,13 @@ class views_handler_field_aggregator_category extends views_handler_field {
* Provide link to category option
*/
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['link_to_category'] = array(
'#title' => t('Link this field to its aggregator category page'),
'#description' => t('This will override any other link you have set.'),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['link_to_category']),
);
+ parent::options_form($form, $form_state);
}
/**
diff --git a/modules/aggregator/views_handler_field_aggregator_title_link.inc b/modules/aggregator/views_handler_field_aggregator_title_link.inc
index 6eb0c64..28598dc 100644
--- a/modules/aggregator/views_handler_field_aggregator_title_link.inc
+++ b/modules/aggregator/views_handler_field_aggregator_title_link.inc
@@ -22,12 +22,12 @@ class views_handler_field_aggregator_title_link extends views_handler_field {
* 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']),
);
+ parent::options_form($form, $form_state);
}
function render($values) {
diff --git a/modules/aggregator/views_handler_filter_aggregator_category_cid.inc b/modules/aggregator/views_handler_filter_aggregator_category_cid.inc
index 73c22c0..2f797a8 100644
--- a/modules/aggregator/views_handler_filter_aggregator_category_cid.inc
+++ b/modules/aggregator/views_handler_filter_aggregator_category_cid.inc
@@ -1,5 +1,4 @@
<?php
-
/**
* Filter by aggregator category cid
*/
diff --git a/modules/book.views_convert.inc b/modules/book.views_convert.inc
index c14feb8..8cf37fc 100644
--- a/modules/book.views_convert.inc
+++ b/modules/book.views_convert.inc
@@ -1,5 +1,4 @@
<?php
-
/**
* @file
* Field conversion for fields handled by this module.
diff --git a/modules/comment.views.inc b/modules/comment.views.inc
index fe12c55..9cfdaf4 100644
--- a/modules/comment.views.inc
+++ b/modules/comment.views.inc
@@ -16,6 +16,7 @@
*/
function comment_views_data() {
+ $data['comments']['moved to'] = 'comment';
// Define the base group of this table. Fields that don't
// have a group defined will go into this field by default.
$data['comment']['table']['group'] = t('Comment');
@@ -168,6 +169,7 @@ function comment_views_data() {
),
);
+ $data['comments']['timestamp']['moved to'] = array('comment', 'changed');
// changed (when comment was last updated)
$data['comment']['changed'] = array(
'title' => t('Post date'),
@@ -183,57 +185,63 @@ function comment_views_data() {
'handler' => 'views_handler_filter_date',
),
);
-
- $data['comments']['timestamp_fulldate'] = array(
+
+ $data['comments']['timestamp_fulldate']['moved to'] = array('comment', 'changed_fulldata');
+ $data['comment']['changed_fulldata'] = array(
'title' => t('Created date'),
'help' => t('In the form of CCYYMMDD.'),
'argument' => array(
- 'field' => 'timestamp',
+ 'field' => 'changed',
'handler' => 'views_handler_argument_node_created_fulldate',
),
);
- $data['comments']['timestamp_year_month'] = array(
+ $data['comments']['timestamp_year_month']['moved to'] = array('comment', 'changed_year_month');
+ $data['comment']['changed_year_month'] = array(
'title' => t('Created year + month'),
'help' => t('In the form of YYYYMM.'),
'argument' => array(
- 'field' => 'timestamp',
+ 'field' => 'changed',
'handler' => 'views_handler_argument_node_created_year_month',
),
);
- $data['comments']['timestamp_year'] = array(
+ $data['comments']['timestamp_year']['moved to'] = array('comment', 'changed_year');
+ $data['comment']['changed_year'] = array(
'title' => t('Created year'),
'help' => t('In the form of YYYY.'),
'argument' => array(
- 'field' => 'timestamp',
+ 'field' => 'changed',
'handler' => 'views_handler_argument_node_created_year',
),
);
- $data['comments']['timestamp_month'] = array(
+ $data['comments']['timestamp_month']['moved to'] = array('comment', 'changed_month');
+ $data['comment']['changed_month'] = array(
'title' => t('Created month'),
'help' => t('In the form of MM (01 - 12).'),
'argument' => array(
- 'field' => 'timestamp',
+ 'field' => 'changed',
'handler' => 'views_handler_argument_node_created_month',
),
);
- $data['comments']['timestamp_day'] = array(
+ $data['comments']['timestamp_day']['moved to'] = array('comment', 'changed_day');
+ $data['comment']['changed_day'] = array(
'title' => t('Created day'),
'help' => t('In the form of DD (01 - 31).'),
'argument' => array(
- 'field' => 'timestamp',
+ 'field' => 'changed',
'handler' => 'views_handler_argument_node_created_day',
),
);
- $data['comments']['timestamp_week'] = array(
+ $data['comments']['timestamp_week']['moved to'] = array('comment', 'changed_week');
+ $data['comment']['changed_week'] = array(
'title' => t('Created week'),
'help' => t('In the form of WW (01 - 53).'),
'argument' => array(
- 'field' => 'timestamp',
+ 'field' => 'changed',
'handler' => 'views_handler_argument_node_created_week',
),
);
@@ -306,13 +314,13 @@ function comment_views_data() {
);
$data['comment']['nid'] = array(
- 'title' => t('Node'),
- 'help' => t('The node the comment is a reply to.'),
+ 'title' => t('Content'),
+ 'help' => t('The content to which the comment is a reply to.'),
'relationship' => array(
'base' => 'node',
'base field' => 'nid',
'handler' => 'views_handler_relationship',
- 'label' => t('Node'),
+ 'label' => t('Content'),
),
);
@@ -347,7 +355,7 @@ function comment_views_data() {
// node_comment_statistics table
// define the group
- $data['node_comment_statistics']['table']['group'] = t('Node');
+ $data['node_comment_statistics']['table']['group'] = t('Content');
// joins
$data['node_comment_statistics']['table']['join'] = array(
diff --git a/modules/comment.views_convert.inc b/modules/comment.views_convert.inc
index 1e7cc3b..f4f8d0f 100644
--- a/modules/comment.views_convert.inc
+++ b/modules/comment.views_convert.inc
@@ -1,5 +1,4 @@
<?php
-
/**
* @file
* Field conversion for fields handled by this module.
diff --git a/modules/comment.views_default.inc b/modules/comment.views_default.inc
index 23f03b6..41ce8b3 100644
--- a/modules/comment.views_default.inc
+++ b/modules/comment.views_default.inc
@@ -13,12 +13,13 @@ function comment_views_default_views() {
$view->description = 'Contains a block and a page to list recent comments; the block will automatically link to the page, which displays the comment body as well as a link to the node.';
$view->tag = 'default';
$view->base_table = 'comment';
+ $view->human_name = 'Recent comments';
$view->api_version = 2;
$view->version = 7;
$view->disabled = TRUE; /* Edit this to true to make a default view disabled initially */
- /* Display: Defaults */
- $handler = $view->new_display('default', 'Defaults', 'default');
+ /* Display: Master */
+ $handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['title'] = 'Recent comments';
$handler->display->display_options['use_more'] = TRUE;
$handler->display->display_options['access']['type'] = 'none';
@@ -49,7 +50,7 @@ function comment_views_default_views() {
$handler->display->display_options['sorts']['timestamp']['table'] = 'comment';
$handler->display->display_options['sorts']['timestamp']['field'] = 'changed';
$handler->display->display_options['sorts']['timestamp']['order'] = 'DESC';
- /* Filter: Node: Published or admin */
+ /* Filter: Content: Published or admin */
$handler->display->display_options['filters']['status_extra']['id'] = 'status_extra';
$handler->display->display_options['filters']['status_extra']['table'] = 'node';
$handler->display->display_options['filters']['status_extra']['field'] = 'status_extra';
@@ -71,7 +72,7 @@ function comment_views_default_views() {
$handler->display->display_options['row_options']['separator'] = '&nbsp;';
$handler->display->display_options['defaults']['row_options'] = FALSE;
$handler->display->display_options['defaults']['fields'] = FALSE;
- /* Field: Node: Title */
+ /* Field: Content: Title */
$handler->display->display_options['fields']['title']['id'] = 'title';
$handler->display->display_options['fields']['title']['table'] = 'node';
$handler->display->display_options['fields']['title']['field'] = 'title';
@@ -107,10 +108,11 @@ function comment_views_default_views() {
$view->description = 'Shows all new activity on system.';
$view->tag = 'default';
$view->base_table = 'node';
+ $view->human_name = 'Tracker';
$view->api_version = 2;
$view->version = 7;
$view->disabled = TRUE; /* Edit this to true to make a default view disabled initially */
- $handler = $view->new_display('default', 'Defaults', 'default');
+ $handler = $view->new_display('default', 'Master', 'default');
$handler->override_option('fields', array(
'type' => array(
'id' => 'type',
diff --git a/modules/comment/views_handler_argument_comment_user_uid.inc b/modules/comment/views_handler_argument_comment_user_uid.inc
index 45631cf..fc8eb87 100644
--- a/modules/comment/views_handler_argument_comment_user_uid.inc
+++ b/modules/comment/views_handler_argument_comment_user_uid.inc
@@ -33,7 +33,7 @@ class views_handler_argument_comment_user_uid extends views_handler_argument {
}
}
- function query() {
+ function query($group_by = FALSE) {
$this->ensure_my_table();
$nid_alias = $this->query->add_field('node', 'nid');
diff --git a/modules/comment/views_handler_field_comment.inc b/modules/comment/views_handler_field_comment.inc
index 6755b14..778bee9 100644
--- a/modules/comment/views_handler_field_comment.inc
+++ b/modules/comment/views_handler_field_comment.inc
@@ -24,13 +24,13 @@ class views_handler_field_comment extends views_handler_field {
* Provide link-to-comment option
*/
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['link_to_comment'] = array(
'#title' => t('Link this field to its comment'),
- '#description' => t('This will override any other link you have set.'),
+ '#description' => t("Enable to override this field's links."),
'#type' => 'checkbox',
'#default_value' => $this->options['link_to_comment'],
);
+ parent::options_form($form, $form_state);
}
function render_link($data, $values) {
diff --git a/modules/comment/views_handler_field_comment_link.inc b/modules/comment/views_handler_field_comment_link.inc
index d4ab8cb..68e2971 100644
--- a/modules/comment/views_handler_field_comment_link.inc
+++ b/modules/comment/views_handler_field_comment_link.inc
@@ -16,12 +16,12 @@ class views_handler_field_comment_link extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['text'] = array(
'#type' => 'textfield',
'#title' => t('Text to display'),
'#default_value' => $this->options['text'],
);
+ parent::options_form($form, $form_state);
}
function query() {
diff --git a/modules/comment/views_handler_field_comment_link_edit.inc b/modules/comment/views_handler_field_comment_link_edit.inc
index f9f1b40..7653026 100644
--- a/modules/comment/views_handler_field_comment_link_edit.inc
+++ b/modules/comment/views_handler_field_comment_link_edit.inc
@@ -23,6 +23,7 @@ class views_handler_field_comment_link_edit extends views_handler_field_comment_
'#title' => t('Use destination'),
'#description' => t('Add destination to the link'),
'#default_value' => $this->options['destination'],
+ '#fieldset' => 'more',
);
}
diff --git a/modules/comment/views_handler_field_comment_node_link.inc b/modules/comment/views_handler_field_comment_node_link.inc
index 8a21f2c..4a4ae24 100644
--- a/modules/comment/views_handler_field_comment_node_link.inc
+++ b/modules/comment/views_handler_field_comment_node_link.inc
@@ -25,15 +25,15 @@ class views_handler_field_comment_node_link extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
-
$form['teaser'] = array(
'#type' => 'checkbox',
'#title' => t('Show teaser-style link'),
'#default_value' => $this->options['teaser'],
'#description' => t('Show the comment link in the form used on standard node teasers, rather than the full node form.'),
+ '#fieldset' => 'more',
);
+ parent::options_form($form, $form_state);
}
function query() {
diff --git a/modules/comment/views_handler_field_comment_username.inc b/modules/comment/views_handler_field_comment_username.inc
index dccdf49..f97cd90 100644
--- a/modules/comment/views_handler_field_comment_username.inc
+++ b/modules/comment/views_handler_field_comment_username.inc
@@ -19,12 +19,12 @@ class views_handler_field_comment_username extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['link_to_user'] = array(
'#title' => t("Link this field to its user or an author's homepage"),
'#type' => 'checkbox',
'#default_value' => $this->options['link_to_user'],
);
+ parent::options_form($form, $form_state);
}
function render_link($data, $values) {
diff --git a/modules/comment/views_handler_field_node_new_comments.inc b/modules/comment/views_handler_field_node_new_comments.inc
index 932f852..32bd38d 100644
--- a/modules/comment/views_handler_field_node_new_comments.inc
+++ b/modules/comment/views_handler_field_node_new_comments.inc
@@ -30,13 +30,14 @@ class views_handler_field_node_new_comments extends views_handler_field_numeric
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['link_to_comment'] = array(
'#title' => t('Link this field to new comments'),
- '#description' => t('This will override any other link you have set.'),
+ '#description' => t("Enable to override this field's links."),
'#type' => 'checkbox',
'#default_value' => $this->options['link_to_comment'],
);
+
+ parent::options_form($form, $form_state);
}
function query() {
diff --git a/modules/contact/views_handler_field_contact_link.inc b/modules/contact/views_handler_field_contact_link.inc
index de03ddb..e6f2d5e 100644
--- a/modules/contact/views_handler_field_contact_link.inc
+++ b/modules/contact/views_handler_field_contact_link.inc
@@ -11,7 +11,6 @@ class views_handler_field_contact_link extends views_handler_field_user_link {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['link_display'] = array(
'#title' => t('Type of link'),
'#default_value' => $this->options['link_display'],
@@ -24,6 +23,7 @@ class views_handler_field_contact_link extends views_handler_field_user_link {
$form['text']['#title'] = t('Link label');
$form['text']['#required'] = TRUE;
$form['text']['#default_value'] = empty($this->options['text']) ? t('contact') : $this->options['text'];
+ parent::options_form($form, $form_state);
}
// An example of field level access control.
diff --git a/modules/field/views_handler_field_field.inc b/modules/field/views_handler_field_field.inc
index bc51d50..795ebae 100644
--- a/modules/field/views_handler_field_field.inc
+++ b/modules/field/views_handler_field_field.inc
@@ -257,8 +257,6 @@ class views_handler_field_field extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
-
$field = $this->field_info;
$formatters = _field_view_formatter_options($field['type']);
$column_names = array_keys($field['columns']);
@@ -282,6 +280,7 @@ class views_handler_field_field extends views_handler_field {
'#options' => drupal_map_assoc($column_names),
'#default_value' => $this->options['click_sort_column'],
'#description' => t('Used by Style: Table to determine the actual column to click sort the field on. The default is usually fine.'),
+ '#fieldset' => 'more',
);
}
@@ -300,6 +299,7 @@ class views_handler_field_field extends views_handler_field {
'#type' => 'checkbox',
'#default_value' => $this->options['field_api_classes'],
'#description' => t('If checked, field api classes will be added using field.tpl.php (or equivalent). This is not recommended unless your CSS depends upon these classes. If not checked, template will not be used.'),
+ '#fieldset' => 'more',
);
if ($this->multiple) {
@@ -333,6 +333,8 @@ class views_handler_field_field extends views_handler_field {
$settings_form = $function($field, $instance, '_dummy', $form, $form_state);
}
$form['settings'] = $settings_form;
+
+ parent::options_form($form, $form_state);
}
/**
@@ -341,8 +343,12 @@ class views_handler_field_field extends views_handler_field {
function multiple_options_form(&$form, &$form_state) {
$field = $this->field_info;
- $form['multiple_prefix'] = array(
- '#markup' => '<fieldset class="form-wrapper" id="views-multiple-options"><legend><span class="fieldset-legend">' . t('Multiple field settings') . '</span></legend>',
+ $form['multiple_field_settings'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Multiple field settings'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ '#weight' => 5,
);
$form['group_rows'] = array(
@@ -350,6 +356,7 @@ class views_handler_field_field extends views_handler_field {
'#type' => 'checkbox',
'#default_value' => $this->options['group_rows'],
'#description' => t('If checked, multiple values for this field will be shown in the same row. If not checked, each value in this field will create a new row.'),
+ '#fieldset' => 'multiple_field_settings',
);
// Make the string translatable by keeping it as a whole rather than
@@ -379,6 +386,7 @@ class views_handler_field_field extends views_handler_field {
'#process' => array('form_process_radios', 'ctools_dependent_process'),
'#dependency' => array('edit-options-group-rows' => array(TRUE)),
'#default_value' => $this->options['multi_type'],
+ '#fieldset' => 'multiple_field_settings',
);
$form['separator'] = array(
@@ -391,6 +399,7 @@ class views_handler_field_field extends views_handler_field {
'edit-options-group-rows' => array(TRUE),
),
'#dependency_count' => 2,
+ '#fieldset' => 'multiple_field_settings',
);
$form['delta_limit'] = array(
@@ -403,6 +412,7 @@ class views_handler_field_field extends views_handler_field {
'#prefix' => '<div class="container-inline">',
'#process' => $process + array('ctools_dependent_process'),
'#dependency' => array('edit-options-group-rows' => array(TRUE)),
+ '#fieldset' => 'multiple_field_settings',
);
list($prefix, $suffix) = explode('@count', t('starting from @count'));
@@ -415,6 +425,7 @@ class views_handler_field_field extends views_handler_field {
'#process' => array('ctools_dependent_process'),
'#dependency' => array('edit-options-group-rows' => array(TRUE)),
'#description' => t('(first item is 0)'),
+ '#fieldset' => 'multiple_field_settings',
);
$form['delta_reversed'] = array(
'#title' => t('Reversed'),
@@ -424,12 +435,8 @@ class views_handler_field_field extends views_handler_field {
'#process' => array('form_process_checkbox', 'ctools_dependent_process'),
'#dependency' => array('edit-options-group-rows' => array(TRUE)),
'#description' => t('(start from last values)'),
+ '#fieldset' => 'multiple_field_settings',
);
-
- $form['multiple_suffix'] = array(
- '#markup' => '</fieldset>',
- );
-
}
/**
diff --git a/modules/filter.views.inc b/modules/filter.views.inc
index 3434944..ff6156f 100644
--- a/modules/filter.views.inc
+++ b/modules/filter.views.inc
@@ -16,11 +16,12 @@
*/
function filter_views_data() {
// ----------------------------------------------------------------------
- // filter_formats table
+ // filter_format table
// Have not defined $data['filter_formats']['table']['group'] since
// no fields are defined here yet.
- $data['filter_formats']['table']['join'] = array(
+ $data['filter_formats']['moved to'] = 'filter_format';
+ $data['filter_format']['table']['join'] = array(
'node_revisions' => array(
'left_field' => 'format',
'field' => 'format',
diff --git a/modules/locale/views_handler_field_locale_link_edit.inc b/modules/locale/views_handler_field_locale_link_edit.inc
index 9b1224d..b129ca1 100644
--- a/modules/locale/views_handler_field_locale_link_edit.inc
+++ b/modules/locale/views_handler_field_locale_link_edit.inc
@@ -18,12 +18,12 @@ class views_handler_field_locale_link_edit extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['text'] = array(
'#type' => 'textfield',
'#title' => t('Text to display'),
'#default_value' => $this->options['text'],
);
+ parent::options_form($form, $form_state);
}
function query() {
diff --git a/modules/node.views.inc b/modules/node.views.inc
index 3b62de8..8add0d2 100644
--- a/modules/node.views.inc
+++ b/modules/node.views.inc
@@ -20,15 +20,17 @@ function node_views_data() {
// Define the base group of this table. Fields that don't
// have a group defined will go into this field by default.
- $data['node']['table']['group'] = t('Node');
+ $data['node']['table']['group'] = t('Content');
// Advertise this table as a possible base table
$data['node']['table']['base'] = array(
'field' => 'nid',
- 'title' => t('Node'),
- 'help' => t("Nodes are a Drupal site's primary content."),
+ 'title' => t('Content'),
'weight' => -10,
'access query tag' => 'node_access',
+ 'defaults' => array(
+ 'field' => 'title',
+ ),
);
// For other base tables, explain how we join
@@ -55,7 +57,7 @@ function node_views_data() {
// nid
$data['node']['nid'] = array(
'title' => t('Nid'),
- 'help' => t('The node ID of the node.'), // The help that appears on the UI,
+ 'help' => t('The node ID.'), // The help that appears on the UI,
// Information for displaying the nid
'field' => array(
'handler' => 'views_handler_field_node',
@@ -82,11 +84,11 @@ function node_views_data() {
// This definition has more items in it than it needs to as an example.
$data['node']['title'] = array(
'title' => t('Title'), // The item it appears as on the UI,
- 'help' => t('The title of the node.'), // The help that appears on the UI,
+ 'help' => t('The content title.'), // The help that appears on the UI,
// Information for displaying a title as a field
'field' => array(
'field' => 'title', // the real field. This could be left out since it is the same.
- 'group' => t('Node'), // The group it appears in on the UI. Could be left out.
+ 'group' => t('Content'), // The group it appears in on the UI. Could be left out.
'handler' => 'views_handler_field_node',
'click sortable' => TRUE,
),
@@ -105,7 +107,7 @@ function node_views_data() {
// created field
$data['node']['created'] = array(
'title' => t('Post date'), // The item it appears as on the UI,
- 'help' => t('The date the node was posted.'), // The help that appears on the UI,
+ 'help' => t('The date the content was posted.'), // The help that appears on the UI,
'field' => array(
'handler' => 'views_handler_field_date',
'click sortable' => TRUE,
@@ -121,7 +123,7 @@ function node_views_data() {
// changed field
$data['node']['changed'] = array(
'title' => t('Updated date'), // The item it appears as on the UI,
- 'help' => t('The date the node was last updated.'), // The help that appears on the UI,
+ 'help' => t('The date the content was last updated.'), // The help that appears on the UI,
'field' => array(
'handler' => 'views_handler_field_date',
'click sortable' => TRUE,
@@ -134,10 +136,10 @@ function node_views_data() {
),
);
- // Node type
+ // Content type
$data['node']['type'] = array(
'title' => t('Type'), // The item it appears as on the UI,
- 'help' => t('The type of a node (for example, "blog entry", "forum post", "story", etc).'), // The help that appears on the UI,
+ 'help' => t('The content type (for example, "blog entry", "forum post", "story", etc).'), // The help that appears on the UI,
'field' => array(
'handler' => 'views_handler_field_node_type',
'click sortable' => TRUE,
@@ -156,7 +158,7 @@ function node_views_data() {
// published status
$data['node']['status'] = array(
'title' => t('Published'),
- 'help' => t('Whether or not the node is published.'),
+ 'help' => t('Whether or not the content is published.'),
'field' => array(
'handler' => 'views_handler_field_boolean',
'click sortable' => TRUE,
@@ -178,7 +180,7 @@ function node_views_data() {
// published status + extra
$data['node']['status_extra'] = array(
'title' => t('Published or admin'),
- 'help' => t('Filters out unpublished nodes if the current user cannot view them.'),
+ 'help' => t('Filters out unpublished content if the current user cannot view it.'),
'filter' => array(
'field' => 'status',
'handler' => 'views_handler_filter_node_status',
@@ -189,7 +191,7 @@ function node_views_data() {
// promote status
$data['node']['promote'] = array(
'title' => t('Promoted to front page'),
- 'help' => t('Whether or not the node is promoted to the front page.'),
+ 'help' => t('Whether or not the content is promoted to the front page.'),
'field' => array(
'handler' => 'views_handler_field_boolean',
'click sortable' => TRUE,
@@ -207,7 +209,7 @@ function node_views_data() {
// sticky
$data['node']['sticky'] = array(
'title' => t('Sticky'), // The item it appears as on the UI,
- 'help' => t('Whether or not the node is sticky.'), // The help that appears on the UI,
+ 'help' => t('Whether or not the content is sticky.'), // The help that appears on the UI,
// Information for displaying a title as a field
'field' => array(
'handler' => 'views_handler_field_boolean',
@@ -223,7 +225,7 @@ function node_views_data() {
),
'sort' => array(
'handler' => 'views_handler_sort',
- 'help' => t('Whether or not the node is sticky. To list sticky nodes first, set this to descending.'),
+ 'help' => t('Whether or not the content is sticky. To list sticky content first, set this to descending.'),
),
);
@@ -232,7 +234,7 @@ function node_views_data() {
$data['node']['view_node'] = array(
'field' => array(
'title' => t('Link'),
- 'help' => t('Provide a simple link to the node.'),
+ 'help' => t('Provide a simple link to the content.'),
'handler' => 'views_handler_field_node_link',
),
);
@@ -240,7 +242,7 @@ function node_views_data() {
$data['node']['edit_node'] = array(
'field' => array(
'title' => t('Edit link'),
- 'help' => t('Provide a simple link to edit the node.'),
+ 'help' => t('Provide a simple link to edit the content.'),
'handler' => 'views_handler_field_node_link_edit',
),
);
@@ -248,7 +250,7 @@ function node_views_data() {
$data['node']['delete_node'] = array(
'field' => array(
'title' => t('Delete link'),
- 'help' => t('Provide a simple link to delete the node.'),
+ 'help' => t('Provide a simple link to delete the content.'),
'handler' => 'views_handler_field_node_link_delete',
),
);
@@ -256,7 +258,7 @@ function node_views_data() {
$data['node']['path'] = array(
'field' => array(
'title' => t('Path'),
- 'help' => t('The aliased path to this node.'),
+ 'help' => t('The aliased path to this content.'),
'handler' => 'views_handler_field_node_path',
),
);
@@ -375,7 +377,7 @@ function node_views_data() {
// uid field
$data['node']['uid'] = array(
'title' => t('Author'),
- 'help' => t('Relate a node to the user who created it.'),
+ 'help' => t('Relate content to the user who created it.'),
'relationship' => array(
'handler' => 'views_handler_relationship',
'base' => 'users',
@@ -385,17 +387,21 @@ function node_views_data() {
);
// ----------------------------------------------------------------------
- // Node revision table
+ // Content revision table
// Define the base group of this table. Fields that don't
// have a group defined will go into this field by default.
- $data['node_revision']['table']['group'] = t('Node revision');
+ $data['node_revisions']['moved to'] = 'node_revision';
+ $data['node_revision']['table']['group'] = t('Content revision');
// Advertise this table as a possible base table
$data['node_revision']['table']['base'] = array(
'field' => 'vid',
- 'title' => t('Node revision'),
- 'help' => t('Node revision are a history of changes to nodes.'),
+ 'title' => t('Content revision'),
+ 'help' => t('Content revision is a history of changes to content.'),
+ 'defaults' => array(
+ 'field' => 'title',
+ ),
);
// For other base tables, explain how we join
@@ -410,7 +416,7 @@ function node_views_data() {
// uid field for node revision
$data['node_revision']['uid'] = array(
'title' => t('User'),
- 'help' => t('Relate a node revision to the user who created the revision.'),
+ 'help' => t('Relate a content revision to the user who created the revision.'),
'relationship' => array(
'handler' => 'views_handler_relationship',
'base' => 'users',
@@ -422,7 +428,7 @@ function node_views_data() {
// nid
$data['node_revision']['vid'] = array(
'title' => t('Vid'),
- 'help' => t('The revision ID of the node revision.'), // The help that appears on the UI,
+ 'help' => t('The revision ID of the content revision.'), // The help that appears on the UI,
// Information for displaying the nid
'field' => array(
'click sortable' => TRUE,
@@ -445,15 +451,15 @@ function node_views_data() {
'handler' => 'views_handler_relationship',
'base' => 'node',
'base field' => 'nid',
- 'title' => t('Node'),
- 'label' => t('Get the actual node from a node revision.'),
+ 'title' => t('Content'),
+ 'label' => t('Get the actual content from a content revision.'),
),
);
// title
$data['node_revision']['title'] = array(
'title' => t('Title'), // The item it appears as on the UI,
- 'help' => t('The title of the node.'), // The help that appears on the UI,
+ 'help' => t('The content title.'), // The help that appears on the UI,
// Information for displaying a title as a field
'field' => array(
'field' => 'title', // the real field
@@ -488,7 +494,7 @@ function node_views_data() {
// changed field
$data['node_revision']['timestamp'] = array(
'title' => t('Created date'), // The item it appears as on the UI,
- 'help' => t('The date the node revision was created.'), // The help that appears on the UI,
+ 'help' => t('The date the content revision was created.'), // The help that appears on the UI,
'field' => array(
'handler' => 'views_handler_field_date',
'click sortable' => TRUE,
@@ -512,7 +518,7 @@ function node_views_data() {
$data['node_revision']['delete_revision'] = array(
'field' => array(
'title' => t('Delete link'),
- 'help' => t('Provide a simple link to delete the node revision.'),
+ 'help' => t('Provide a simple link to delete the content revision.'),
'handler' => 'views_handler_field_node_revision_link_delete',
),
);
@@ -522,7 +528,7 @@ function node_views_data() {
// Define the base group of this table. Fields that don't
// have a group defined will go into this field by default.
- $data['node_access']['table']['group'] = t('Node access');
+ $data['node_access']['table']['group'] = t('Content access');
// For other base tables, explain how we join
$data['node_access']['table']['join'] = array(
@@ -538,7 +544,7 @@ function node_views_data() {
'help' => t('Filter by access.'),
'filter' => array(
'handler' => 'views_handler_filter_node_access',
- 'help' => t('Filter for nodes by view access. <strong>Not necessary if you are using node as your base table.</strong>'),
+ 'help' => t('Filter for content by view access. <strong>Not necessary if you are using node as your base table.</strong>'),
),
);
@@ -548,7 +554,8 @@ function node_views_data() {
// We're actually defining a specific instance of the table, so let's
// alias it so that we can later add the real table for other purposes if we
// need it.
- $data['history']['table']['group'] = t('Node');
+ $data['history_user']['moved to'] = 'history';
+ $data['history']['table']['group'] = t('Content');
// Explain how this table joins to others.
$data['history']['table']['join'] = array(
@@ -567,10 +574,10 @@ function node_views_data() {
'title' => t('Has new content'),
'field' => array(
'handler' => 'views_handler_field_history_user_timestamp',
- 'help' => t('Show a marker if the node has new or updated content.'),
+ 'help' => t('Show a marker if the content is new or updated.'),
),
'filter' => array(
- 'help' => t('Show only nodes that have new content.'),
+ 'help' => t('Show only content that is new or updated.'),
'handler' => 'views_handler_filter_history_user_timestamp',
),
);
@@ -585,8 +592,8 @@ function node_views_plugins() {
'module' => 'views', // This just tells our themes are elsewhere.
'row' => array(
'node' => array(
- 'title' => t('Node'),
- 'help' => t('Display the node with standard node view.'),
+ 'title' => t('Content'),
+ 'help' => t('Display the content with standard node view.'),
'handler' => 'views_plugin_row_node_view',
'path' => drupal_get_path('module', 'views') . '/modules/node', // not necessary for most modules
'theme' => 'views_view_row_node',
@@ -596,8 +603,8 @@ function node_views_plugins() {
'help topic' => 'style-node',
),
'node_rss' => array(
- 'title' => t('Node'),
- 'help' => t('Display the node with standard node view.'),
+ 'title' => t('Content'),
+ 'help' => t('Display the content with standard node view.'),
'handler' => 'views_plugin_row_node_rss',
'path' => drupal_get_path('module', 'views') . '/modules/node', // not necessary for most modules
'theme' => 'views_view_row_rss',
@@ -609,13 +616,13 @@ function node_views_plugins() {
),
'argument validator' => array(
'node' => array(
- 'title' => t('Node'),
+ 'title' => t('Content'),
'handler' => 'views_plugin_argument_validate_node',
),
),
'argument default' => array(
'node' => array(
- 'title' => t('Node ID from URL'),
+ 'title' => t('Content ID from URL'),
'handler' => 'views_plugin_argument_default_node'
),
),
@@ -656,7 +663,8 @@ function template_preprocess_views_view_row_node(&$vars) {
}
if (!empty($options['comments']) && user_access('access comments') && $node->comment) {
- $vars['comments'] = drupal_render(comment_node_page_additions($node));
+ $build = comment_node_page_additions($node);
+ $vars['comments'] = drupal_render($build);
}
$vars['node'] = drupal_render($content);
@@ -692,7 +700,7 @@ function node_views_analyze($view) {
->condition('r.name', array('anonymous user', 'authenticated user'), 'IN')
->condition('p.permission', 'access content')
->execute();
-
+
foreach ($result as $role) {
$role->safe = TRUE;
$roles[$role->name] = $role;
diff --git a/modules/node.views_default.inc b/modules/node.views_default.inc
index 62bb45f..ab71d62 100644
--- a/modules/node.views_default.inc
+++ b/modules/node.views_default.inc
@@ -13,10 +13,11 @@ function node_views_default_views() {
$view->description = '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 = 'default';
$view->base_table = 'node';
+ $view->human_name = 'Front page';
$view->api_version = 2;
$view->version = 7;
$view->disabled = TRUE; /* Edit this to true to make a default view disabled initially */
- $handler = $view->new_display('default', 'Defaults', 'default');
+ $handler = $view->new_display('default', 'Master', 'default');
$handler->override_option('sorts', array(
'sticky' => array(
'id' => 'sticky',
@@ -119,10 +120,11 @@ function node_views_default_views() {
$view->description = 'A list of all content, by letter.';
$view->tag = 'default';
$view->base_table = 'node';
+ $view->human_name = 'Glossary';
$view->api_version = 2;
$view->version = 7;
$view->disabled = TRUE; /* Edit this to true to make a default view disabled initially */
- $handler = $view->new_display('default', 'Defaults', 'default');
+ $handler = $view->new_display('default', 'Master', 'default');
$handler->override_option('fields', array(
'title' => array(
'label' => 'Title',
@@ -275,10 +277,11 @@ function node_views_default_views() {
$view->description = 'Display a list of months that link to content for that month.';
$view->tag = 'default';
$view->base_table = 'node';
+ $view->human_name = 'Archive';
$view->api_version = 2;
$view->version = 7;
$view->disabled = TRUE; /* Edit this to true to make a default view disabled initially */
- $handler = $view->new_display('default', 'Defaults', 'default');
+ $handler = $view->new_display('default', 'Master', 'default');
$handler->override_option('title', 'Monthly archive');
$handler->override_option('sorts', array(
'created' => array(
diff --git a/modules/node/views_handler_argument_node_type.inc b/modules/node/views_handler_argument_node_type.inc
index 624af8a..638973d 100644
--- a/modules/node/views_handler_argument_node_type.inc
+++ b/modules/node/views_handler_argument_node_type.inc
@@ -26,7 +26,7 @@ class views_handler_argument_node_type extends views_handler_argument {
function node_type($type) {
$output = node_type_get_name($type);
if (empty($output)) {
- $output = t('Unknown node type');
+ $output = t('Unknown content type');
}
return check_plain($output);
}
diff --git a/modules/node/views_handler_field_history_user_timestamp.inc b/modules/node/views_handler_field_history_user_timestamp.inc
index fb6ff47..4d6d365 100644
--- a/modules/node/views_handler_field_history_user_timestamp.inc
+++ b/modules/node/views_handler_field_history_user_timestamp.inc
@@ -32,6 +32,7 @@ class views_handler_field_history_user_timestamp extends views_handler_field_nod
'#type' => 'checkbox',
'#title' => t('Check for new comments as well'),
'#default_value' => !empty($this->options['comments']),
+ '#fieldset' => 'more',
);
}
}
diff --git a/modules/node/views_handler_field_node.inc b/modules/node/views_handler_field_node.inc
index 48bb0b8..c575ea4 100644
--- a/modules/node/views_handler_field_node.inc
+++ b/modules/node/views_handler_field_node.inc
@@ -29,13 +29,14 @@ class views_handler_field_node extends views_handler_field {
* Provide link to node option
*/
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['link_to_node'] = array(
- '#title' => t('Link this field to its node'),
- '#description' => t('This will override any other link you have set.'),
+ '#title' => t('Link this field to the original piece of content'),
+ '#description' => t("Enable to override this field's links."),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['link_to_node']),
);
+
+ parent::options_form($form, $form_state);
}
/**
diff --git a/modules/node/views_handler_field_node_link.inc b/modules/node/views_handler_field_node_link.inc
index db79081..0125ea8 100644
--- a/modules/node/views_handler_field_node_link.inc
+++ b/modules/node/views_handler_field_node_link.inc
@@ -17,12 +17,12 @@ class views_handler_field_node_link extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['text'] = array(
'#type' => 'textfield',
'#title' => t('Text to display'),
'#default_value' => $this->options['text'],
);
+ parent::options_form($form, $form_state);
}
function query() {
diff --git a/modules/node/views_handler_field_node_path.inc b/modules/node/views_handler_field_node_path.inc
index 3924d27..b75dc6e 100644
--- a/modules/node/views_handler_field_node_path.inc
+++ b/modules/node/views_handler_field_node_path.inc
@@ -23,7 +23,8 @@ class views_handler_field_node_path extends views_handler_field {
'#type' => 'checkbox',
'#title' => t('Use absolute link (begins with "http://")'),
'#default_value' => $this->options['absolute'],
- '#description' => t('If you want to use this as in "output this field as link" in "link path", you have to enabled this option.'),
+ '#description' => t('Enable this option to output an absolute link. Required if you want to use the path as a link destination (as in "output this field as a link" above).'),
+ '#fieldset' => 'alter',
);
}
diff --git a/modules/node/views_handler_field_node_revision.inc b/modules/node/views_handler_field_node_revision.inc
index 3966cf7..c91bfd4 100644
--- a/modules/node/views_handler_field_node_revision.inc
+++ b/modules/node/views_handler_field_node_revision.inc
@@ -25,13 +25,13 @@ class views_handler_field_node_revision extends views_handler_field_node {
* Provide link to revision option.
*/
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['link_to_node_revision'] = array(
- '#title' => t('Link this field to its node revision'),
+ '#title' => t('Link this field to its content revision'),
'#description' => t('This will override any other link you have set.'),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['link_to_node_revision']),
);
+ parent::options_form($form, $form_state);
}
/**
@@ -55,5 +55,4 @@ class views_handler_field_node_revision extends views_handler_field_node {
}
return $data;
}
-}
-
+} \ No newline at end of file
diff --git a/modules/node/views_handler_field_node_type.inc b/modules/node/views_handler_field_node_type.inc
index f6212a9..a1e7992 100644
--- a/modules/node/views_handler_field_node_type.inc
+++ b/modules/node/views_handler_field_node_type.inc
@@ -16,11 +16,13 @@ class views_handler_field_node_type extends views_handler_field_node {
*/
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
+
$form['machine_name'] = array(
'#title' => t('Output machine name'),
- '#description' => t('Display field as the node type machine name.'),
+ '#description' => t('Display field as the content type machine name.'),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['machine_name']),
+ '#fieldset' => 'more',
);
}
@@ -37,5 +39,4 @@ class views_handler_field_node_type extends views_handler_field_node {
function render($values) {
return $this->render_link($this->render_name($values->{$this->field_alias}, $values), $values);
}
-}
-
+} \ No newline at end of file
diff --git a/modules/node/views_handler_filter_history_user_timestamp.inc b/modules/node/views_handler_filter_history_user_timestamp.inc
index 7192c87..f725b4c 100644
--- a/modules/node/views_handler_filter_history_user_timestamp.inc
+++ b/modules/node/views_handler_filter_history_user_timestamp.inc
@@ -8,8 +8,12 @@ class views_handler_filter_history_user_timestamp extends views_handler_filter {
// Don't display empty space where the operator would be.
var $no_operator = TRUE;
- function expose_form_right(&$form, &$form_state) {
- // We don't want any of the usual options for exposed filters.
+ function expose_form(&$form, &$form_state) {
+ parent::expose_form($form, $form_state);
+ // @todo There are better ways of excluding required and multiple (object flags)
+ unset($form['expose']['required']);
+ unset($form['expose']['multiple']);
+ unset($form['expose']['remember']);
}
function value_form(&$form, &$form_state) {
diff --git a/modules/node/views_handler_filter_node_status.inc b/modules/node/views_handler_filter_node_status.inc
index b33982d..2b79b9e 100644
--- a/modules/node/views_handler_filter_node_status.inc
+++ b/modules/node/views_handler_filter_node_status.inc
@@ -5,6 +5,7 @@
class views_handler_filter_node_status extends views_handler_filter {
function admin_summary() { }
function operator_form(&$form, &$form_state) { }
+ function can_expose() { return FALSE; }
function query() {
$table = $this->ensure_my_table();
diff --git a/modules/node/views_handler_filter_node_type.inc b/modules/node/views_handler_filter_node_type.inc
index c451443..8232c99 100644
--- a/modules/node/views_handler_filter_node_type.inc
+++ b/modules/node/views_handler_filter_node_type.inc
@@ -5,7 +5,7 @@
class views_handler_filter_node_type extends views_handler_filter_in_operator {
function get_value_options() {
if (!isset($this->value_options)) {
- $this->value_title = t('Node type');
+ $this->value_title = t('Content types');
$types = node_type_get_types();
foreach ($types as $type => $info) {
$options[$type] = t($info->name);
diff --git a/modules/node/views_plugin_argument_validate_node.inc b/modules/node/views_plugin_argument_validate_node.inc
index 379d52a..df3c479 100644
--- a/modules/node/views_plugin_argument_validate_node.inc
+++ b/modules/node/views_plugin_argument_validate_node.inc
@@ -26,15 +26,15 @@ class views_plugin_argument_validate_node extends views_plugin_argument_validate
$form['types'] = array(
'#type' => 'checkboxes',
- '#title' => t('Types'),
+ '#title' => t('Content types'),
'#options' => $options,
'#default_value' => $this->options['types'],
- '#description' => t('If you wish to validate for specific node types, check them; if none are checked, all nodes will pass.'),
+ '#description' => t('Choose one or more content types to validate with.'),
);
$form['access'] = array(
'#type' => 'checkbox',
- '#title' => t('Validate user has access to the node'),
+ '#title' => t('Validate user has access to the content'),
'#default_value' => $this->options['access'],
);
$form['access_op'] = array(
@@ -46,7 +46,7 @@ class views_plugin_argument_validate_node extends views_plugin_argument_validate
$form['nid_type'] = array(
'#type' => 'select',
- '#title' => t('Argument type'),
+ '#title' => t('Argument format'),
'#options' => array(
'nid' => t('Node ID'),
'nids' => t('Node IDs separated by , or +'),
@@ -129,5 +129,4 @@ class views_plugin_argument_validate_node extends views_plugin_argument_validate
return empty($test);
}
}
-}
-
+} \ No newline at end of file
diff --git a/modules/node/views_plugin_row_node_rss.inc b/modules/node/views_plugin_row_node_rss.inc
index a8efd98..ac589b0 100644
--- a/modules/node/views_plugin_row_node_rss.inc
+++ b/modules/node/views_plugin_row_node_rss.inc
@@ -30,16 +30,29 @@ class views_plugin_row_node_rss extends views_plugin_row {
$form['item_length'] = array(
'#type' => 'select',
'#title' => t('Display type'),
- '#options' => array(
- 'fulltext' => t('Full text'),
- 'teaser' => t('Title plus teaser'),
- 'title' => t('Title only'),
- 'default' => t('Use default RSS settings'),
- ),
+ '#options' => $this->options_form_summary_options(),
'#default_value' => $this->options['item_length'],
);
}
+ /**
+ * Return the main options, which are shown in the summary title.
+ */
+ function options_form_summary_options() {
+ return array(
+ 'fulltext' => t('Full text'),
+ 'teaser' => t('Title plus teaser'),
+ 'title' => t('Title only'),
+ 'default' => t('Use default RSS settings'),
+ );
+ }
+
+ function summary_title() {
+ $options = $this->options_form_summary_options();
+ return check_plain($options[$this->options['item_length']]);
+ }
+
+
function pre_render($values) {
foreach ($values as $row) {
$nids[] = $row->{$this->field_alias};
@@ -88,6 +101,7 @@ class views_plugin_row_node_rss extends views_plugin_row {
$item_text .= drupal_render($node->content) . $links;
}
+ $item = new stdClass;
$item->description = $item_text;
$item->title = $node->title;
$item->link = url("node/$node->nid", array('absolute' => TRUE));
diff --git a/modules/node/views_plugin_row_node_view.inc b/modules/node/views_plugin_row_node_view.inc
index a66dc7c..3b9e249 100644
--- a/modules/node/views_plugin_row_node_view.inc
+++ b/modules/node/views_plugin_row_node_view.inc
@@ -38,20 +38,7 @@ class views_plugin_row_node_view extends views_plugin_row {
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
- $entity_info = entity_get_info('node');
- $options = array();
- if (!empty($entity_info['view modes'])) {
- foreach ($entity_info['view modes'] as $mode => $settings) {
- $options[$mode] = $settings['label'];
- }
- }
- if (empty($options)) {
- $options = array(
- 'teaser' => t('Teaser'),
- 'full' => t('Full node')
- );
- }
-
+ $options = $this->options_form_summary_options();
$form['build_mode'] = array(
'#type' => 'select',
'#options' => $options,
@@ -65,11 +52,37 @@ class views_plugin_row_node_view extends views_plugin_row {
);
$form['comments'] = array(
'#type' => 'checkbox',
- '#title' => t('Display node comments'),
+ '#title' => t('Display comments'),
'#default_value' => $this->options['comments'],
);
}
+ /**
+ * Return the main options, which are shown in the summary title.
+ */
+ function options_form_summary_options() {
+ $entity_info = entity_get_info('node');
+ $options = array();
+ if (!empty($entity_info['view modes'])) {
+ foreach ($entity_info['view modes'] as $mode => $settings) {
+ $options[$mode] = $settings['label'];
+ }
+ }
+ if (empty($options)) {
+ $options = array(
+ 'teaser' => t('Teaser'),
+ 'full' => t('Full content')
+ );
+ }
+
+ return $options;
+ }
+
+ function summary_title() {
+ $options = $this->options_form_summary_options();
+ return check_plain($options[$this->options['build_mode']]);
+ }
+
function pre_render($values) {
$nids = array();
foreach ($values as $row) {
diff --git a/modules/profile.views.inc b/modules/profile.views.inc
index fb26dac..65ad71d 100644
--- a/modules/profile.views.inc
+++ b/modules/profile.views.inc
@@ -14,6 +14,7 @@
* Implements hook_views_data()
*/
function profile_views_data() {
+ $data['profile_values']['moved to'] = 'profile_value';
// Define the base group of this table. Fields that don't
// have a group defined will go into this field by default.
$data['profile_value']['table']['group'] = t('Profile');
diff --git a/modules/search.views_convert.inc b/modules/search.views_convert.inc
index ef8c456..08fd297 100644
--- a/modules/search.views_convert.inc
+++ b/modules/search.views_convert.inc
@@ -1,5 +1,4 @@
<?php
-
/**
* @file
* Field conversion for fields handled by this module.
diff --git a/modules/search.views_default.inc b/modules/search.views_default.inc
index ff231f4..f10f376 100644
--- a/modules/search.views_default.inc
+++ b/modules/search.views_default.inc
@@ -13,10 +13,11 @@ function search_views_default_views() {
$view->description = 'Displays a list of nodes that link to the node, using the search backlinks table.';
$view->tag = 'default';
$view->base_table = 'node';
+ $view->human_name = 'Backlinks';
$view->api_version = 2;
$view->version = 7;
$view->disabled = TRUE; /* Edit this to true to make a default view disabled initially */
- $handler = $view->new_display('default', 'Defaults', 'default');
+ $handler = $view->new_display('default', 'Master', 'default');
$handler->override_option('fields', array(
'title' => array(
'id' => 'title',
diff --git a/modules/search/views_handler_argument_search.inc b/modules/search/views_handler_argument_search.inc
index e4bca34..fd1372f 100644
--- a/modules/search/views_handler_argument_search.inc
+++ b/modules/search/views_handler_argument_search.inc
@@ -22,7 +22,7 @@ class views_handler_argument_search extends views_handler_argument {
/**
* Add this argument to the query.
*/
- function query() {
+ function query($group_by = FALSE) {
$required = FALSE;
$this->query_parse_search_expression($this->argument);
if (!isset($this->search_query)) {
diff --git a/modules/search/views_handler_field_search_score.inc b/modules/search/views_handler_field_search_score.inc
index bbc6a07..b3d6fe3 100644
--- a/modules/search/views_handler_field_search_score.inc
+++ b/modules/search/views_handler_field_search_score.inc
@@ -1,5 +1,4 @@
<?php
-
/**
* Field handler to provide simple renderer that allows linking to a node.
*/
diff --git a/modules/search/views_handler_filter_search.inc b/modules/search/views_handler_filter_search.inc
index 6485dc4..f0f1b71 100644
--- a/modules/search/views_handler_filter_search.inc
+++ b/modules/search/views_handler_filter_search.inc
@@ -4,7 +4,7 @@
* Field handler to provide simple renderer that allows linking to a node.
*/
class views_handler_filter_search extends views_handler_filter {
- var $no_single = TRUE;
+ var $always_multiple = TRUE;
/**
* Stores a viewsSearchQuery object to be able to use the search.module "api".
diff --git a/modules/statistics.views.inc b/modules/statistics.views.inc
index 9560075..78ef793 100644
--- a/modules/statistics.views.inc
+++ b/modules/statistics.views.inc
@@ -20,7 +20,7 @@ function statistics_views_data() {
// ----------------------------------------------------------------
// node_counter table
- $data['node_counter']['table']['group'] = t('Node statistics');
+ $data['node_counter']['table']['group'] = t('Content statistics');
$data['node_counter']['table']['join'] = array(
// ...to the node table
diff --git a/modules/statistics.views_default.inc b/modules/statistics.views_default.inc
index df83edd..c6bbd62 100644
--- a/modules/statistics.views_default.inc
+++ b/modules/statistics.views_default.inc
@@ -13,10 +13,11 @@ function statistics_views_default_views() {
$view->description = 'Shows the most-viewed nodes on the site. This requires the statistics to be enabled at administer >> reports >> access log settings.';
$view->tag = 'default';
$view->base_table = 'node';
+ $view->human_name = 'Popular content';
$view->api_version = 2;
$view->version = 7;
$view->disabled = TRUE; /* Edit this to true to make a default view disabled initially */
- $handler = $view->new_display('default', 'Defaults', 'default');
+ $handler = $view->new_display('default', 'Master', 'default');
$handler->override_option('fields', array(
'type' => array(
'id' => 'type',
diff --git a/modules/statistics/views_handler_field_accesslog_path.inc b/modules/statistics/views_handler_field_accesslog_path.inc
index 50d62da..5d571b4 100644
--- a/modules/statistics/views_handler_field_accesslog_path.inc
+++ b/modules/statistics/views_handler_field_accesslog_path.inc
@@ -25,12 +25,12 @@ class views_handler_field_accesslog_path extends views_handler_field {
* 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']),
);
+ parent::options_form($form, $form_state);
}
function render($values) {
diff --git a/modules/system.views.inc b/modules/system.views.inc
index 4809c6d..6e2c72a 100644
--- a/modules/system.views.inc
+++ b/modules/system.views.inc
@@ -21,6 +21,7 @@ function system_views_data() {
// ----------------------------------------------------------------------
// file_managed table
+ $data['files']['moved to'] = 'file_managed';
$data['file_managed']['table']['group'] = t('File');
// Advertise this table as a possible base table
@@ -28,6 +29,9 @@ function system_views_data() {
'field' => 'fid',
'title' => t('File'),
'help' => t("Files maintained by Drupal and various modules."),
+ 'defaults' => array(
+ 'field' => 'filename'
+ ),
);
// The file table does not inherently join to the node table,
@@ -232,14 +236,14 @@ function system_views_data() {
// Relationships between files and nodes.
$data['file_usage']['file_to_node'] = array(
- 'title' => t('Node'),
- 'help' => t('A node that is associated with this file, usually because this file is in a field on the node.'),
+ 'title' => t('Content'),
+ 'help' => t('Content that is associated with this file, usually because this file is in a field on the content.'),
// Only provide this field/relationship/etc. when the 'file_managed' base table is present.
'skip base' => array('node', 'node_revision', 'users', 'comment', 'taxonomy_term_data', 'taxonomy_vocabulary'),
'real field' => 'id',
'relationship' => array(
- 'title' => t('Node'),
- 'label' => t('Node'),
+ 'title' => t('Content'),
+ 'label' => t('Content'),
'base' => 'node',
'base field' => 'nid',
'relationship field' => 'id',
diff --git a/modules/system/views_handler_field_file.inc b/modules/system/views_handler_field_file.inc
index c19d28a..71dba7e 100644
--- a/modules/system/views_handler_field_file.inc
+++ b/modules/system/views_handler_field_file.inc
@@ -23,13 +23,13 @@ class views_handler_field_file extends views_handler_field {
* Provide link to file option
*/
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['link_to_file'] = array(
'#title' => t('Link this field to download the file'),
- '#description' => t('This will override any other link you have set.'),
+ '#description' => t("Enable to override this field's links."),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['link_to_file']),
);
+ parent::options_form($form, $form_state);
}
/**
diff --git a/modules/system/views_handler_field_file_filemime.inc b/modules/system/views_handler_field_file_filemime.inc
index 433f130..9a06639 100644
--- a/modules/system/views_handler_field_file_filemime.inc
+++ b/modules/system/views_handler_field_file_filemime.inc
@@ -11,12 +11,12 @@ class views_handler_field_file_filemime extends views_handler_field_file {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['filemime_image'] = array(
- '#title' => t('Display an image representing the MIME type instead of the MIME text.'),
+ '#title' => t('Display an icon representing the file type, instead of the MIME text (such as "image/jpeg").'),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['filemime_image']),
);
+ parent::options_form($form, $form_state);
}
function render($values) {
diff --git a/modules/system/views_handler_field_file_uri.inc b/modules/system/views_handler_field_file_uri.inc
index cb29a20..d36aba3 100644
--- a/modules/system/views_handler_field_file_uri.inc
+++ b/modules/system/views_handler_field_file_uri.inc
@@ -11,13 +11,13 @@ class views_handler_field_file_uri extends views_handler_field_file {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['file_download_path'] = array(
'#title' => t('Display download path instead of file storage URI'),
'#description' => t('This will provide the full download URL rather than the internal filestream address.'),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['file_download_path']),
);
+ parent::options_form($form, $form_state);
}
function render($values) {
diff --git a/modules/taxonomy.views.inc b/modules/taxonomy.views.inc
index 3812cd4..23a1248 100644
--- a/modules/taxonomy.views.inc
+++ b/modules/taxonomy.views.inc
@@ -20,6 +20,7 @@ function taxonomy_views_data() {
// ----------------------------------------------------------------------
// taxonomy_vocabulary table
+ $data['vocabulary']['moved to'] = 'taxonomy_vocabulary';
$data['taxonomy_vocabulary']['table']['group'] = t('Taxonomy');
$data['taxonomy_vocabulary']['table']['join'] = array(
@@ -76,6 +77,7 @@ function taxonomy_views_data() {
// ----------------------------------------------------------------------
// taxonomy_term_data table
+ $data['term_data']['moved to'] = 'taxonomy_term_data';
$data['taxonomy_term_data']['table']['group'] = t('Taxonomy');
$data['taxonomy_term_data']['table']['base'] = array(
'field' => 'tid',
@@ -200,6 +202,7 @@ function taxonomy_views_data() {
// ----------------------------------------------------------------------
// taxonomy_index table
+ $data['term_node']['moved to'] = 'taxonomy_index';
$data['taxonomy_index']['table']['group'] = t('Taxonomy');
$data['taxonomy_index']['table']['join'] = array(
@@ -220,8 +223,8 @@ function taxonomy_views_data() {
);
$data['taxonomy_index']['nid'] = array(
- 'title' => t('Node'),
- 'help' => t('Get all nodes tagged with a term.'),
+ 'title' => t('Content'),
+ 'help' => t('Get all content tagged with a term.'),
'relationship' => array(
'handler' => 'views_handler_relationship',
'base' => 'node',
@@ -264,6 +267,7 @@ function taxonomy_views_data() {
$data['taxonomy_term_hierarchy']['table']['group'] = t('Taxonomy');
+ $data['term_hierarchy']['moved to'] = 'taxonomy_term_hierarchy';
$data['taxonomy_term_hierarchy']['table']['join'] = array(
'taxonomy_term_hierarchy' => array(
// links to self through left.parent = right.tid (going down in depth)
@@ -298,11 +302,12 @@ function taxonomy_views_data() {
);
// ----------------------------------------------------------------------
- // term_synonym table
+ // taxonomy_term_synonym table
- $data['term_synonym']['table']['group'] = t('Taxonomy');
+ $data['term_synonym']['moved to'] = 'taxonomy_term_synonym';
+ $data['taxonomy_term_synonym']['table']['group'] = t('Taxonomy');
- $data['term_synonym']['table']['join'] = array(
+ $data['taxonomy_term_synonym']['table']['join'] = array(
'taxonomy_term_data' => array(
// links directly to taxonomy_term_data via tid
'left_field' => 'tid',
@@ -315,7 +320,7 @@ function taxonomy_views_data() {
),
);
- $data['term_synonym']['name'] = array(
+ $data['taxonomy_term_synonym']['name'] = array(
'title' => t('Term synonym'),
'help' => t('Term synonyms may be used to find terms by alternate names.'),
'argument' => array(
diff --git a/modules/taxonomy.views_default.inc b/modules/taxonomy.views_default.inc
index 9564c0f..d03a1d3 100644
--- a/modules/taxonomy.views_default.inc
+++ b/modules/taxonomy.views_default.inc
@@ -13,10 +13,11 @@ function taxonomy_views_default_views() {
$view->description = 'A view to emulate Drupal core\'s handling of taxonomy/term; it also emulates Views 1\'s handling by having two possible feeds.';
$view->tag = 'default';
$view->base_table = 'node';
+ $view->human_name = 'Taxonomy term';
$view->api_version = 2;
$view->version = 7;
$view->disabled = TRUE; /* Edit this to true to make a default view disabled initially */
- $handler = $view->new_display('default', 'Defaults', 'default');
+ $handler = $view->new_display('default', 'Master', 'default');
$handler->override_option('sorts', array(
'sticky' => array(
'id' => 'sticky',
diff --git a/modules/taxonomy/views_handler_argument_term_node_tid_depth.inc b/modules/taxonomy/views_handler_argument_term_node_tid_depth.inc
index 6ed8f5f..863bad8 100644
--- a/modules/taxonomy/views_handler_argument_term_node_tid_depth.inc
+++ b/modules/taxonomy/views_handler_argument_term_node_tid_depth.inc
@@ -18,7 +18,6 @@ class views_handler_argument_term_node_tid_depth extends views_handler_argument
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['depth'] = array(
'#type' => 'weight',
'#title' => t('Depth'),
@@ -48,6 +47,7 @@ class views_handler_argument_term_node_tid_depth extends views_handler_argument
'#process' => array('form_process_checkbox', 'ctools_dependent_process'),
'#dependency' => array('edit-options-set-breadcrumb' => array(TRUE)),
);
+ parent::options_form($form, $form_state);
}
function set_breadcrumb(&$breadcrumb) {
@@ -74,7 +74,7 @@ class views_handler_argument_term_node_tid_depth extends views_handler_argument
return $actions;
}
- function query() {
+ function query($group_by = FALSE) {
$this->ensure_my_table();
if (!empty($this->options['break_phrase'])) {
diff --git a/modules/taxonomy/views_handler_argument_term_node_tid_depth_modifier.inc b/modules/taxonomy/views_handler_argument_term_node_tid_depth_modifier.inc
index 139bae2..e28b9eb 100644
--- a/modules/taxonomy/views_handler_argument_term_node_tid_depth_modifier.inc
+++ b/modules/taxonomy/views_handler_argument_term_node_tid_depth_modifier.inc
@@ -8,7 +8,7 @@
*/
class views_handler_argument_term_node_tid_depth_modifier extends views_handler_argument {
function options_form(&$form, &$form_state) { }
- function query() { }
+ function query($group_by = FALSE) { }
function pre_query() {
// We don't know our argument yet, but it's based upon our position:
$argument = isset($this->view->args[$this->position]) ? $this->view->args[$this->position] : NULL;
diff --git a/modules/taxonomy/views_handler_field_taxonomy.inc b/modules/taxonomy/views_handler_field_taxonomy.inc
index bff0f8c..c8e804d 100644
--- a/modules/taxonomy/views_handler_field_taxonomy.inc
+++ b/modules/taxonomy/views_handler_field_taxonomy.inc
@@ -31,13 +31,13 @@ class views_handler_field_taxonomy extends views_handler_field {
* Provide link to taxonomy option
*/
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['link_to_taxonomy'] = array(
'#title' => t('Link this field to its taxonomy term page'),
- '#description' => t('This will override any other link you have set.'),
+ '#description' => t("Enable to override this field's links."),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['link_to_taxonomy']),
);
+ parent::options_form($form, $form_state);
}
/**
diff --git a/modules/taxonomy/views_handler_field_term_link_edit.inc b/modules/taxonomy/views_handler_field_term_link_edit.inc
index 7203f59..95c2248 100644
--- a/modules/taxonomy/views_handler_field_term_link_edit.inc
+++ b/modules/taxonomy/views_handler_field_term_link_edit.inc
@@ -23,12 +23,12 @@ class views_handler_field_term_link_edit extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['text'] = array(
'#type' => 'textfield',
'#title' => t('Text to display'),
'#default_value' => $this->options['text'],
);
+ parent::options_form($form, $form_state);
}
function query() {
diff --git a/modules/taxonomy/views_handler_field_term_node_tid.inc b/modules/taxonomy/views_handler_field_term_node_tid.inc
index b096c6d..7e63f2f 100644
--- a/modules/taxonomy/views_handler_field_term_node_tid.inc
+++ b/modules/taxonomy/views_handler_field_term_node_tid.inc
@@ -38,7 +38,6 @@ class views_handler_field_term_node_tid extends views_handler_field_prerender_li
* Provide "link to term" option.
*/
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['link_to_taxonomy'] = array(
'#title' => t('Link this field to its term page'),
'#type' => 'checkbox',
@@ -49,6 +48,7 @@ class views_handler_field_term_node_tid extends views_handler_field_prerender_li
'#type' => 'checkbox',
'#title' => t('Limit terms by vocabulary'),
'#default_value'=> $this->options['limit'],
+ '#fieldset' => 'more',
);
$options = array();
@@ -66,7 +66,10 @@ class views_handler_field_term_node_tid extends views_handler_field_prerender_li
'#default_value' => $this->options['vocabularies'],
'#process' => array('form_process_checkboxes', 'ctools_dependent_process'),
'#dependency' => array('edit-options-limit' => array(TRUE)),
+ '#fieldset' => 'more',
);
+
+ parent::options_form($form, $form_state);
}
/**
diff --git a/modules/taxonomy/views_handler_filter_term_node_tid.inc b/modules/taxonomy/views_handler_filter_term_node_tid.inc
index 61f9651..5ffe2f1 100644
--- a/modules/taxonomy/views_handler_filter_term_node_tid.inc
+++ b/modules/taxonomy/views_handler_filter_term_node_tid.inc
@@ -155,13 +155,13 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
if (!empty($this->options['expose']['reduce'])) {
$options = $this->reduce_value_options($options);
- if (empty($this->options['expose']['single']) && !empty($this->options['expose']['optional'])) {
+ if (!empty($this->options['expose']['multiple']) && empty($this->options['expose']['required'])) {
$default_value = array();
}
}
- if (!empty($this->options['expose']['single'])) {
- if (!empty($this->options['expose']['optional']) && (empty($default_value) || !empty($this->options['expose']['reduce']))) {
+ if (empty($this->options['expose']['multiple'])) {
+ if (empty($this->options['expose']['required']) && (empty($default_value) || !empty($this->options['expose']['reduce']))) {
$default_value = 'All';
}
elseif (empty($default_value)) {
@@ -195,7 +195,7 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
}
}
- function value_validate(&$form, &$form_state) {
+ function value_validate($form, &$form_state) {
// We only validate if they've chosen the text field style.
if ($this->options['type'] != 'textfield') {
return;
@@ -214,8 +214,8 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
return TRUE;
}
- // If it's optional and there's no value don't bother filtering.
- if ($this->options['expose']['optional'] && empty($this->validated_exposed_input)) {
+ // If it's non-required and there's no value don't bother filtering.
+ if (!$this->options['expose']['required'] && empty($this->validated_exposed_input)) {
return FALSE;
}
@@ -306,8 +306,8 @@ class views_handler_filter_term_node_tid extends views_handler_filter_many_to_on
// prevent array_filter from messing up our arrays in parent submit.
}
- function expose_form_right(&$form, &$form_state) {
- parent::expose_form_right($form, $form_state);
+ function expose_form(&$form, &$form_state) {
+ parent::expose_form($form, $form_state);
if ($this->options['type'] != 'select') {
unset($form['expose']['reduce']);
}
diff --git a/modules/taxonomy/views_handler_relationship_node_term_data.inc b/modules/taxonomy/views_handler_relationship_node_term_data.inc
index e097716..2f013da 100644
--- a/modules/taxonomy/views_handler_relationship_node_term_data.inc
+++ b/modules/taxonomy/views_handler_relationship_node_term_data.inc
@@ -25,12 +25,7 @@ class views_handler_relationship_node_term_data extends views_handler_relationsh
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);
$vocabularies = taxonomy_get_vocabularies();
$options = array();
foreach ($vocabularies as $voc) {
@@ -44,6 +39,7 @@ class views_handler_relationship_node_term_data extends views_handler_relationsh
'#default_value' => $this->options['vocabularies'],
'#description' => t('Choose which vocabularies you wish to relate. Remember that every term found will create a new record, so this relationship is best used on just one vocabulary that has only one term per node.'),
);
+ parent::options_form($form, $form_state);
}
/**
diff --git a/modules/translation.views.inc b/modules/translation.views.inc
index cbb32b3..8189faa 100644
--- a/modules/translation.views.inc
+++ b/modules/translation.views.inc
@@ -27,7 +27,7 @@ function translation_views_data_alter(&$data) {
// Language field
$data['node']['language'] = array(
- 'group' => t('Node translation'),
+ 'group' => t('Content translation'),
'title' => t('Language'),
'help' => t('The language the content is in.'),
'field' => array(
@@ -47,7 +47,7 @@ function translation_views_data_alter(&$data) {
// The translation ID (nid of the "source" translation)
$data['node']['tnid'] = array(
- 'group' => t('Node translation'),
+ 'group' => t('Content translation'),
'title' => t('Translation set node ID'),
'help' => t('The ID of the translation set the content belongs to.'),
'field' => array(
@@ -78,7 +78,7 @@ function translation_views_data_alter(&$data) {
// The source translation.
$data['node']['translation'] = array(
- 'group' => t('Node translation'),
+ 'group' => t('Content translation'),
'title' => t('Translations'),
'help' => t('Versions of content in different languages.'),
'relationship' => array(
@@ -95,9 +95,9 @@ function translation_views_data_alter(&$data) {
// The source translation.
$data['node']['source_translation'] = array(
- 'group' => t('Node translation'),
+ 'group' => t('Content translation'),
'title' => t('Source translation'),
- 'help' => t('Nodes that are either untranslated or are the original versions of a translation set.'),
+ 'help' => t('Content that is either untranslated or is the original version of a translation set.'),
'filter' => array(
'handler' => 'views_handler_filter_node_tnid',
),
@@ -107,7 +107,7 @@ function translation_views_data_alter(&$data) {
$data['node']['child_translation'] = array(
'group' => t('Node translation'),
'title' => t('Child translation'),
- 'help' => t('Nodes that are translations of a source translation.'),
+ 'help' => t('Content that is a translation of a source translation.'),
'filter' => array(
'handler' => 'views_handler_filter_node_tnid_child',
),
@@ -115,9 +115,9 @@ function translation_views_data_alter(&$data) {
// Translation status
$data['node']['translate'] = array(
- 'group' => t('Node translation'),
+ 'group' => t('Content translation'),
'title' => t('Translation status'),
- 'help' => t('The translation status of the node--whether or not the translation needs to be updated.'),
+ 'help' => t('The translation status of the content - whether or not the translation needs to be updated.'),
'field' => array(
'handler' => 'views_handler_field_boolean',
'click sortable' => TRUE,
@@ -134,7 +134,7 @@ function translation_views_data_alter(&$data) {
// Translate node link.
$data['node']['translate_node'] = array(
- 'group' => t('Node translation'),
+ 'group' => t('Content translation'),
'title' => t('Translate link'),
'help' => t('Provide a simple link to translate the node.'),
'field' => array(
diff --git a/modules/translation/views_handler_filter_node_tnid.inc b/modules/translation/views_handler_filter_node_tnid.inc
index b06dbd0..b47847b 100644
--- a/modules/translation/views_handler_filter_node_tnid.inc
+++ b/modules/translation/views_handler_filter_node_tnid.inc
@@ -18,7 +18,7 @@ class views_handler_filter_node_tnid extends views_handler_filter {
function operator_form(&$form, &$form_state) {
$form['operator'] = array(
'#type' => 'radios',
- '#title' => t('Include untranslated nodes'),
+ '#title' => t('Include untranslated content'),
'#default_value' => $this->operator,
'#options' => array(
1 => t('Yes'),
@@ -34,5 +34,4 @@ class views_handler_filter_node_tnid extends views_handler_filter {
// Select for source translations (tnid = nid). Conditionally, also accept either untranslated nodes (tnid = 0).
$this->query->add_where($this->options['group'], "$table.tnid = $table.nid" . ($this->operator ? " OR $table.tnid = 0" : ''));
}
-}
-
+} \ No newline at end of file
diff --git a/modules/upload.views.inc b/modules/upload.views.inc
index 2d55e21..198b64e 100644
--- a/modules/upload.views.inc
+++ b/modules/upload.views.inc
@@ -39,8 +39,8 @@ function upload_views_data() {
);
$data['upload']['vid'] = array(
- 'title' => t('Node'),
- 'help' => t('The node the uploaded file is attached to'),
+ 'title' => t('Content'),
+ 'help' => t('The content the uploaded file is attached to'),
'relationship' => array(
'label' => t('upload'),
'base' => 'node',
diff --git a/modules/user.views.inc b/modules/user.views.inc
index da63160..4a9cf0e 100644
--- a/modules/user.views.inc
+++ b/modules/user.views.inc
@@ -63,8 +63,8 @@ function user_views_data() {
'handler' => 'views_handler_sort',
),
'relationship' => array(
- 'title' => t('Nodes authored'),
- 'help' => t('Relate nodes to the user who created it. This relationship will create one record for every node created by the user.'),
+ 'title' => t('Content authored'),
+ 'help' => t('Relate content to the user who created it. This relationship will create one record for each content item created by the user.'),
'handler' => 'views_handler_relationship',
'base' => 'node',
'base field' => 'uid',
@@ -145,6 +145,7 @@ function user_views_data() {
);
// picture
+ $data['users']['picture_fid']['moved to'] = array('users', 'picture');
$data['users']['picture'] = array(
'title' => t('Picture'),
'help' => t("The user's picture, if allowed."), // The help that appears on the UI,
diff --git a/modules/user/views_handler_field_user.inc b/modules/user/views_handler_field_user.inc
index de8c6e6..626cf93 100644
--- a/modules/user/views_handler_field_user.inc
+++ b/modules/user/views_handler_field_user.inc
@@ -24,13 +24,13 @@ class views_handler_field_user extends views_handler_field {
* Provide link to node option
*/
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['link_to_user'] = array(
'#title' => t('Link this field to its user'),
- '#description' => t('This will override any other link you have set.'),
+ '#description' => t("Enable to override this field's links."),
'#type' => 'checkbox',
'#default_value' => $this->options['link_to_user'],
);
+ parent::options_form($form, $form_state);
}
function render_link($data, $values) {
diff --git a/modules/user/views_handler_field_user_link.inc b/modules/user/views_handler_field_user_link.inc
index 0f8ed7f..900d7ac 100644
--- a/modules/user/views_handler_field_user_link.inc
+++ b/modules/user/views_handler_field_user_link.inc
@@ -15,12 +15,12 @@ class views_handler_field_user_link extends views_handler_field {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['text'] = array(
'#type' => 'textfield',
'#title' => t('Text to display'),
'#default_value' => $this->options['text'],
);
+ parent::options_form($form, $form_state);
}
// An example of field level access control.
diff --git a/modules/user/views_handler_field_user_mail.inc b/modules/user/views_handler_field_user_mail.inc
index a67778d..045fa4f 100644
--- a/modules/user/views_handler_field_user_mail.inc
+++ b/modules/user/views_handler_field_user_mail.inc
@@ -10,7 +10,6 @@ class views_handler_field_user_mail extends views_handler_field_user {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
$form['link_to_user'] = array(
'#title' => t('Link this field'),
'#type' => 'radios',
@@ -21,6 +20,7 @@ class views_handler_field_user_mail extends views_handler_field_user {
),
'#default_value' => $this->options['link_to_user'],
);
+ parent::options_form($form, $form_state);
}
function render_link($data, $values) {
diff --git a/modules/user/views_handler_field_user_name.inc b/modules/user/views_handler_field_user_name.inc
index 4258021..2fbb715 100644
--- a/modules/user/views_handler_field_user_name.inc
+++ b/modules/user/views_handler_field_user_name.inc
@@ -23,13 +23,12 @@ class views_handler_field_user_name extends views_handler_field_user {
}
function options_form(&$form, &$form_state) {
- parent::options_form($form, $form_state);
-
$form['overwrite_anonymous'] = array(
'#title' => t('Overwrite the value to display for anonymous users'),
'#type' => 'checkbox',
'#default_value' => !empty($this->options['overwrite_anonymous']),
- '#description' => t('If selected, you will see a field to enter the text to use for anonymous users.'),
+ '#description' => t('Enable to display different text for anonymous users.'),
+ '#fieldset' => 'more',
);
$form['anonymous_text'] = array(
'#title' => t('Text to display for anonymous users'),
@@ -39,7 +38,10 @@ class views_handler_field_user_name extends views_handler_field_user {
'#dependency' => array(
'edit-options-overwrite-anonymous' => array(1),
),
+ '#fieldset' => 'more',
);
+
+ parent::options_form($form, $form_state);
}
function render_link($data, $values) {
diff --git a/modules/user/views_handler_filter_user_name.inc b/modules/user/views_handler_filter_user_name.inc
index 12d6df4..2fce71a 100644
--- a/modules/user/views_handler_filter_user_name.inc
+++ b/modules/user/views_handler_filter_user_name.inc
@@ -4,7 +4,7 @@
* Filter handler for usernames
*/
class views_handler_filter_user_name extends views_handler_filter_in_operator {
- var $no_single = TRUE;
+ var $always_multiple = TRUE;
function value_form(&$form, &$form_state) {
$values = array();
diff --git a/modules/user/views_plugin_argument_validate_user.inc b/modules/user/views_plugin_argument_validate_user.inc
index 2ab055e..68de9ab 100644
--- a/modules/user/views_plugin_argument_validate_user.inc
+++ b/modules/user/views_plugin_argument_validate_user.inc
@@ -50,7 +50,7 @@ class views_plugin_argument_validate_user extends views_plugin_argument_validate
);
}
- function options_submit(&$form, &$form_state, &$options) {
+ function options_submit(&$form, &$form_state, &$options = array()) {
// filter trash out of the options so we don't store giant unnecessary arrays
$options['roles'] = array_filter($options['roles']);
}
diff --git a/modules/views.views.inc b/modules/views.views.inc
index b1382b2..21ef9c1 100644
--- a/modules/views.views.inc
+++ b/modules/views.views.inc
@@ -59,6 +59,14 @@ function views_views_data() {
),
);
+ $data['views']['view'] = array(
+ 'title' => t('View area'),
+ 'help' => t('Insert a view inside an area.'),
+ 'area' => array(
+ 'handler' => 'views_handler_area_view',
+ ),
+ );
+
if (module_invoke('ctools', 'api_version', '1.7.1')) {
$data['views']['expression'] = array(
'title' => t('Math expression'),
diff --git a/plugins/export_ui/views_ui.class.php b/plugins/export_ui/views_ui.class.php
new file mode 100644
index 0000000..53facd6
--- /dev/null
+++ b/plugins/export_ui/views_ui.class.php
@@ -0,0 +1,373 @@
+<?php
+// $Id: $
+
+class views_ui extends ctools_export_ui {
+
+ function init($plugin) {
+ // We modify the plugin info here so that we take the defaults and
+ // twiddle, rather than completely override them.
+
+ // Reset the edit path to match what we're really using.
+ $plugin['menu']['items']['edit']['path'] = 'view/%ctools_export_ui/edit';
+ $plugin['menu']['items']['clone']['path'] = 'view/%ctools_export_ui/clone';
+ $plugin['menu']['items']['clone']['type'] = MENU_CALLBACK;
+ $plugin['menu']['items']['export']['path'] = 'view/%ctools_export_ui/export';
+ $plugin['menu']['items']['export']['type'] = MENU_CALLBACK;
+ $plugin['menu']['items']['enable']['path'] = 'view/%ctools_export_ui/enable';
+ $plugin['menu']['items']['disable']['path'] = 'view/%ctools_export_ui/disable';
+ $plugin['menu']['items']['delete']['path'] = 'view/%ctools_export_ui/delete';
+ $plugin['menu']['items']['revert']['path'] = 'view/%ctools_export_ui/revert';
+
+ $prefix_count = count(explode('/', $plugin['menu']['menu prefix']));
+ $plugin['menu']['items']['add-template'] = array(
+ 'path' => 'template/%/add',
+ 'title' => 'Add from template',
+ 'page callback' => 'ctools_export_ui_switcher_page',
+ 'page arguments' => array($plugin['name'], 'add_template', $prefix_count + 2),
+ 'load arguments' => array($plugin['name']),
+ 'access callback' => 'ctools_export_ui_task_access',
+ 'access arguments' => array($plugin['name'], 'add_template', $prefix_count + 2),
+ 'type' => MENU_CALLBACK,
+ );
+
+ return parent::init($plugin);
+ }
+
+ function hook_menu(&$items) {
+ // We are using our own 'edit' still, rather than having edit on this
+ // object (maybe in the future) so unset the edit callbacks:
+
+ // We leave these to make sure the operations still exist in the plugin so
+ // that the path finder.
+ unset($this->plugin['menu']['items']['edit']);
+ unset($this->plugin['menu']['items']['add']);
+ unset($this->plugin['menu']['items']['import']);
+ unset($this->plugin['menu']['items']['edit callback']);
+
+ parent::hook_menu($items);
+ }
+
+ function list_form(&$form, &$form_state) {
+ $row_class = 'container-inline';
+ if (!variable_get('views_ui_show_listing_filters', FALSE)) {
+ $row_class .= " element-invisible";
+ }
+
+ views_include('admin');
+
+ parent::list_form($form, $form_state);
+
+ // ctools only has two rows. We want four.
+ // That's why we create our own structure.
+ $form['first row'] = array(
+ '#prefix' => '<div class="' . $row_class . ' ctools-export-ui-row ctools-export-ui-first-row clearfix">',
+ '#suffix' => '</div>',
+ 'search' => $form['top row']['search'],
+ );
+ $form['second row'] = array(
+ '#prefix' => '<div class="' . $row_class . ' ctools-export-ui-row ctools-export-ui-second-row clearfix">',
+ '#suffix' => '</div>',
+ 'storage' => $form['top row']['storage'],
+ 'disabled' => $form['top row']['disabled'],
+ );
+ $form['third row'] = array(
+ '#prefix' => '<div class="' . $row_class . ' ctools-export-ui-row ctools-export-ui-third-row clearfix">',
+ '#suffix' => '</div>',
+ 'order' => $form['bottom row']['order'],
+ 'sort' => $form['bottom row']['sort'],
+ );
+ $form['fourth row'] = array(
+ '#prefix' => '<div class="' . $row_class . ' ctools-export-ui-row ctools-export-ui-fourth-row clearfix">',
+ '#suffix' => '</div>',
+ 'submit' => $form['bottom row']['submit'],
+ 'reset' => $form['bottom row']['reset'],
+ );
+ unset($form['top row']);
+ unset($form['bottom row']);
+
+ // Modify the look and contents of existing form elements.
+ $form['second row']['storage']['#title'] = '';
+ $form['second row']['storage']['#options'] = array(
+ 'all' => t('All storage'),
+ t('Normal') => t('In database'),
+ t('Default') => t('In code'),
+ t('Overridden') => t('Database overriding code'),
+ );
+ $form['second row']['disabled']['#title'] = '';
+ $form['second row']['disabled']['#options']['all'] = t('All status');
+ $form['third row']['sort']['#title'] = '';
+
+ // And finally, add our own.
+ $this->bases = array();
+ foreach (views_fetch_base_tables() as $table => $info) {
+ $this->bases[$table] = $info['title'];
+ }
+
+ $form['second row']['base'] = array(
+ '#type' => 'select',
+ '#options' => array_merge(array('all' => t('All types')), $this->bases),
+ '#default_value' => 'all',
+ '#weight' => -1,
+ );
+
+ $tags = 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['second row']['tag'] = array(
+ '#type' => 'select',
+ '#title' => t('Filter'),
+ '#options' => array_merge(array('all' => t('All tags')), array('none' => t('No tags')), $tags),
+ '#default_value' => 'all',
+ '#weight' => -9,
+ );
+
+ $displays = array();
+ foreach (views_fetch_plugin_data('display') as $id => $info) {
+ if (!empty($info['admin'])) {
+ $displays[$id] = $info['admin'];
+ }
+ }
+ asort($displays);
+
+ $form['second row']['display'] = array(
+ '#type' => 'select',
+ '#options' => array_merge(array('all' => t('All displays')), $displays),
+ '#default_value' => 'all',
+ '#weight' => -1,
+ );
+ }
+
+ function list_filter($form_state, $view) {
+ if ($form_state['values']['base'] != 'all' && $form_state['values']['base'] != $view->base_table) {
+ return TRUE;
+ }
+
+ return parent::list_filter($form_state, $view);
+ }
+
+ function list_sort_options() {
+ return array(
+ 'disabled' => t('Enabled, name'),
+ 'name' => t('Name'),
+ 'path' => t('Path'),
+ 'tag' => t('Tag'),
+ 'storage' => t('Storage'),
+ );
+ }
+
+
+ function list_build_row($view, &$form_state, $operations) {
+ if (!empty($view->human_name)) {
+ $title = $view->human_name;
+ }
+ else {
+ $title = $view->get_title();
+ if (empty($title)) {
+ $title = $view->name;
+ }
+ }
+
+ $paths = _views_ui_get_paths($view);
+ $paths = implode(", ", $paths);
+
+ $base = !empty($this->bases[$view->base_table]) ? $this->bases[$view->base_table] : t('Broken');
+
+ $info = theme('views_ui_view_info', array('view' => $view, 'base' => $base));
+
+ // Set up sorting
+ switch ($form_state['values']['order']) {
+ case 'disabled':
+ $this->sorts[$view->name] = strtolower(empty($view->disabled) . $title);
+ break;
+ case 'name':
+ $this->sorts[$view->name] = strtolower($title);
+ break;
+ case 'path':
+ $this->sorts[$view->name] = strtolower($paths);
+ break;
+ case 'tag':
+ $this->sorts[$view->name] = strtolower($view->tag);
+ break;
+ case 'storage':
+ $this->sorts[$view->name] = strtolower($view->type . $title);
+ break;
+ }
+
+ $this->rows[$view->name] = array(
+ 'data' => array(
+ array('data' => $info, 'class' => array('views-ui-name')),
+ array('data' => check_plain($view->description), 'class' => array('views-ui-description')),
+ array('data' => check_plain($view->tag), 'class' => array('views-ui-tag')),
+ array('data' => $paths, 'class' => array('views-ui-path')),
+ array('data' => theme('links__ctools_dropbutton', array('links' => $operations, 'attributes' => array('class' => array('links', 'inline')), 'class' => array('views-ui-operations'))),),
+ ),
+ 'title' => t('Machine name: ') . check_plain($view->name),
+ 'class' => array(!empty($view->disabled) ? 'ctools-export-ui-disabled' : 'ctools-export-ui-enabled'),
+ );
+ }
+
+ function list_render(&$form_state) {
+ views_include('admin');
+ views_ui_add_admin_css();
+ if (empty($_REQUEST['js'])) {
+ views_ui_check_advanced_help();
+ }
+ drupal_add_library('system', 'jquery.bbq');
+ views_add_js('views-list');
+
+ $this->active = $form_state['values']['order'];
+ $this->order = $form_state['values']['sort'];
+
+ $query = tablesort_get_query_parameters();
+
+ $header = array(
+ $this->tablesort_link(t('View name'), 'name', 'views-ui-name'),
+ array('data' => t('Description'), 'class' => array('views-ui-description')),
+ $this->tablesort_link(t('Tag'), 'tag', 'views-ui-tag'),
+ $this->tablesort_link(t('Path'), 'path', 'views-ui-path'),
+ array('data' => t('Operations'), 'class' => array('views-ui-operations')),
+ );
+
+ $table = array(
+ 'header' => $header,
+ 'rows' => $this->rows,
+ 'attributes' => array('id' => 'ctools-export-ui-list-items'),
+ );
+ return theme('table', $table);
+ }
+
+ function tablesort_link($label, $field, $class) {
+ $title = t('sort by @s', array('@s' => $label));
+ $initial = 'asc';
+
+ if ($this->active == $field) {
+ $initial = ($this->order == 'asc') ? 'desc' : 'asc';
+ $label .= theme('tablesort_indicator', array('style' => $initial));
+ }
+
+ $query['order'] = $field;
+ $query['sort'] = $initial;
+ $link_options = array(
+ 'html' => TRUE,
+ 'attributes' => array('title' => $title),
+ 'query' => $query,
+ );
+ $link = l($label, $_GET['q'], $link_options);
+ if ($this->active == $field) {
+ $class .= ' active';
+ }
+
+ return array('data' => $link, 'class' => $class);
+ }
+
+ function clone_page($js, $input, $item, $step = NULL) {
+ drupal_set_title($this->get_page_title('clone', $item));
+
+ $name = $item->{$this->plugin['export']['key']};
+
+ $form_state = array(
+ 'plugin' => $this->plugin,
+ 'object' => &$this,
+ 'ajax' => $js,
+ 'item' => $item,
+ 'op' => 'add',
+ 'form type' => 'clone',
+ 'original name' => $name,
+ 'rerender' => TRUE,
+ 'no_redirect' => TRUE,
+ 'step' => $step,
+ // Store these in case additional args are needed.
+ 'function args' => func_get_args(),
+ );
+
+ $output = drupal_build_form('views_ui_clone_form', $form_state);
+ if (!empty($form_state['executed'])) {
+ $item->name = $form_state['values']['name'];
+ $item->human_name = $form_state['values']['human_name'];
+ views_ui_cache_set($item);
+
+ drupal_goto(ctools_export_ui_plugin_menu_path($this->plugin, 'edit', $item->name));
+ }
+
+ return $output;
+ }
+
+ function add_template_page($js, $input, $name, $step = NULL) {
+ $templates = views_get_all_templates();
+
+ if (empty($templates[$name])) {
+ return MENU_NOT_FOUND;
+ }
+
+ $template = $templates[$name];
+
+ // The template description probably describes the template, not the
+ // view that will be created from it, but users aren't that likely to
+ // touch it.
+ if (!empty($template->description)) {
+ unset($template->description);
+ }
+
+ $template->is_template = TRUE;
+ $template->type = t('Default');
+
+ $output = $this->clone_page($js, $input, $template, $step);
+ drupal_set_title(t('Create view from template @template', array('@template' => $template->get_human_name())));
+ return $output;
+ }
+}
+
+/**
+ * Form callback to edit an exportable item using the wizard
+ *
+ * This simply loads the object defined in the plugin and hands it off.
+ */
+function views_ui_clone_form($form, &$form_state) {
+ $counter = 1;
+ do {
+ if (empty($form_state['item']->is_template)) {
+ $name = format_plural($counter, 'Clone of', 'Clone @count of') . ' ' . $form_state['original name'];
+ }
+ else {
+ $name = $form_state['original name'];
+ if ($counter > 1) {
+ $name .= ' ' . $counter;
+ }
+ }
+ $counter++;
+ $machine_name = preg_replace('/[^a-z0-9_]+/', '_', drupal_strtolower($name));
+ } while (ctools_export_crud_load($form_state['plugin']['schema'], $machine_name));
+
+ $form['human_name'] = array(
+ '#type' => 'textfield',
+ '#title' => t('View name'),
+ '#default_value' => $name,
+ );
+
+ $form['name'] = array(
+ '#title' => t('View name'),
+ '#type' => 'machine_name',
+ '#required' => TRUE,
+ '#maxlength' => 255,
+ '#machine_name' => array(
+ 'exists' => 'ctools_export_ui_edit_name_exists',
+ 'source' => array('human_name'),
+ ),
+ );
+
+ $form['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Continue'),
+ );
+
+ return $form;
+}
+
+
diff --git a/plugins/export_ui/views_ui.inc b/plugins/export_ui/views_ui.inc
new file mode 100644
index 0000000..ff24394
--- /dev/null
+++ b/plugins/export_ui/views_ui.inc
@@ -0,0 +1,34 @@
+<?php
+// $Id: ctools_custom_content.inc,v 1.2 2010/10/11 22:18:23 sdboyer Exp $
+
+$plugin = array(
+ 'schema' => 'views_view',
+ 'access' => 'administer views',
+
+ 'menu' => array(
+ 'menu item' => 'views',
+ 'menu title' => 'Views',
+ 'menu description' => 'Manage customized lists of content.',
+ ),
+
+ 'title singular' => t('view'),
+ 'title singular proper' => t('View'),
+ 'title plural' => t('views'),
+ 'title plural proper' => t('Views'),
+
+ 'handler' => 'views_ui',
+
+ 'strings' => array(
+ 'confirmation' => array(
+ 'revert' => array(
+ 'information' => t('This action will permanently remove any customizations made to this view.'),
+ 'success' => t('The view has been reverted.'),
+ ),
+ 'delete' => array(
+ 'information' => t('This action will permanently remove the view from your database.'),
+ 'success' => t('The view has been deleted.'),
+ ),
+ ),
+ ),
+);
+
diff --git a/plugins/views_plugin_argument_default_fixed.inc b/plugins/views_plugin_argument_default_fixed.inc
index ef11dc3..86afd9e 100644
--- a/plugins/views_plugin_argument_default_fixed.inc
+++ b/plugins/views_plugin_argument_default_fixed.inc
@@ -18,7 +18,7 @@ class views_plugin_argument_default_fixed extends views_plugin_argument_default
function options_form(&$form, &$form_state) {
$form['argument'] = array(
'#type' => 'textfield',
- '#title' => t('Default argument'),
+ '#title' => t('Fixed value'),
'#default_value' => $this->options['argument'],
);
}
@@ -39,5 +39,4 @@ class views_plugin_argument_default_fixed extends views_plugin_argument_default
/**
* @}
- */
-
+ */ \ No newline at end of file
diff --git a/plugins/views_plugin_argument_validate.inc b/plugins/views_plugin_argument_validate.inc
index 135e149..643f630 100644
--- a/plugins/views_plugin_argument_validate.inc
+++ b/plugins/views_plugin_argument_validate.inc
@@ -51,7 +51,7 @@ class views_plugin_argument_validate extends views_plugin {
/**
* Provide the default form form for submitting options
*/
- function options_submit(&$form, &$form_state) { }
+ function options_submit(&$form, &$form_state, &$options = array()) { }
/**
* Convert options from the older style.
diff --git a/plugins/views_plugin_display.inc b/plugins/views_plugin_display.inc
index 3f16270..692553c 100644
--- a/plugins/views_plugin_display.inc
+++ b/plugins/views_plugin_display.inc
@@ -26,7 +26,7 @@
class views_plugin_display extends views_plugin {
/**
* The top object of a view.
- *
+ *
* @var view
*/
var $view = NULL;
@@ -866,39 +866,61 @@ class views_plugin_display extends views_plugin {
*/
function options_summary(&$categories, &$options) {
$categories = array(
- 'basic' => array(
- 'title' => t('Basic settings'),
+ 'title' => array(
+ 'title' => t('Title'),
+ 'column' => 'first',
+ ),
+ 'format' => array(
+ 'title' => t('Format'),
+ 'column' => 'first',
+ ),
+ 'filters' => array(
+ 'title' => t('Filters'),
+ 'column' => 'first',
),
- 'advanced' => array(
- 'title' => t('Advanced settings'),
+ 'fields' => array(
+ 'title' => t('Fields'),
+ 'column' => 'first',
),
- 'style' => array(
- 'title' => t('Style settings'),
+ 'pager' => array(
+ 'title' => t('Pager'),
+ 'column' => 'second',
),
'exposed' => array(
'title' => t('Exposed form'),
+ 'column' => 'third',
+ 'build' => array(
+ '#weight' => 1,
+ ),
+ ),
+ 'access' => array(
+ 'title' => '',
+ 'column' => 'second',
+ 'build' => array(
+ '#weight' => -5,
+ ),
+ ),
+ 'other' => array(
+ 'title' => t('Other'),
+ 'column' => 'third',
+ 'build' => array(
+ '#weight' => 2,
+ ),
),
);
if ($this->display->id != 'default') {
$options['display_id'] = array(
- 'category' => 'basic',
+ 'category' => 'other',
'title' => t('Machine Name'),
'value' => !empty($this->display->new_id) ? check_plain($this->display->new_id) : check_plain($this->display->id),
'desc' => t('Change the machine name of this display.'),
);
}
- $options['display_title'] = array(
- 'category' => 'basic',
- 'title' => t('Name'),
- 'value' => check_plain($this->display->display_title),
- 'desc' => t('Change the name of this display.'),
- );
-
$display_comment = drupal_substr($this->get_option('display_comment'), 0, 10);
$options['display_comment'] = array(
- 'category' => 'basic',
+ 'category' => 'other',
'title' => t('Comment'),
'value' => !empty($display_comment) ? $display_comment : t('No comment'),
'desc' => t('Comment or document this display.'),
@@ -910,45 +932,51 @@ class views_plugin_display extends views_plugin {
}
$options['title'] = array(
- 'category' => 'basic',
+ 'category' => 'title',
'title' => t('Title'),
'value' => $title,
'desc' => t('Change the title that this display will use.'),
);
$options['enabled'] = array(
- 'category' => 'basic',
+ 'category' => 'other',
'title' => t('Display status'),
'value' => $this->get_option('enabled') ? t('Enabled') : t('Disabled'),
'desc' => t('Define if this display is or is not enabled.'),
);
$style_plugin = views_fetch_plugin_data('style', $this->get_option('style_plugin'));
- $style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin['title'];
+ $style_plugin_instance = $this->get_plugin('style');
+ $style_summary = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin_instance->summary_title();
+ $style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin_instance->plugin_title();
$style = '';
$options['style_plugin'] = array(
- 'category' => 'style',
- 'title' => t('Style'),
+ 'category' => 'format',
+ 'title' => t('Format'),
'value' => $style_title,
- 'desc' => t('Change the style plugin.'),
+ 'setting' => $style_summary,
+ 'desc' => t('Change the way content is formatted.'),
);
// This adds a 'Settings' link to the style_options setting if the style has options.
if (!empty($style_plugin['uses options'])) {
- $options['style_plugin']['links']['style_options'] = t('Change settings for this style');
+ $options['style_plugin']['links']['style_options'] = t('Change settings for this format');
}
if (!empty($style_plugin['uses row plugin'])) {
$row_plugin = views_fetch_plugin_data('row', $this->get_option('row_plugin'));
- $row_title = empty($row_plugin['title']) ? t('Missing style plugin') : $row_plugin['title'];
+ $row_plugin_instance = $this->get_plugin('row');
+ $row_summary = empty($row_plugin['title']) ? t('Missing style plugin') : $row_plugin_instance->summary_title();
+ $row_title = empty($row_plugin['title']) ? t('Missing style plugin') : $row_plugin_instance->plugin_title();
$options['row_plugin'] = array(
- 'category' => 'style',
- 'title' => t('Row style'),
+ 'category' => 'format',
+ 'title' => t('Show'),
'value' => $row_title,
- 'desc' => t('Change the row plugin.'),
+ 'setting' => $row_summary,
+ 'desc' => t('Change the way each row in the view is styled.'),
);
// This adds a 'Settings' link to the row_options setting if the row style has options.
if (!empty($row_plugin['uses options'])) {
@@ -957,7 +985,7 @@ class views_plugin_display extends views_plugin {
}
if (!empty($this->definition['use ajax'])) {
$options['use_ajax'] = array(
- 'category' => 'advanced',
+ 'category' => 'other',
'title' => t('Use AJAX'),
'value' => $this->get_option('use_ajax') ? t('Yes') : t('No'),
'desc' => t('Change whether or not this display will use AJAX.'),
@@ -965,7 +993,7 @@ class views_plugin_display extends views_plugin {
}
if (!empty($this->definition['accept attachments'])) {
$options['hide_attachment_summary'] = array(
- 'category' => 'advanced',
+ 'category' => 'other',
'title' => t('Hide attachments in summary'),
'value' => $this->get_option('hide_attachment_summary') ? t('Yes') : t('No'),
'desc' => t('Change whether or not to display attachments when displaying an argument summary.'),
@@ -981,9 +1009,10 @@ class views_plugin_display extends views_plugin {
$pager_str = $pager_plugin->summary_title();
$options['pager'] = array(
- 'category' => 'basic',
+ 'category' => 'pager',
'title' => t('Use pager'),
- 'value' => $pager_str,
+ 'value' => $pager_plugin->plugin_title(),
+ 'setting' => $pager_str,
'desc' => t("Change this display's pager setting."),
);
@@ -998,7 +1027,7 @@ class views_plugin_display extends views_plugin {
if (!empty($this->definition['use more'])) {
$options['use_more'] = array(
- 'category' => 'basic',
+ 'category' => 'pager',
'title' => t('More link'),
'value' => $this->get_option('use_more') ? t('Yes') : t('No'),
'desc' => t('Specify whether this display will provide a "more" link.'),
@@ -1008,7 +1037,7 @@ class views_plugin_display extends views_plugin {
$this->view->init_query();
if ($this->view->query->get_aggregation_info()) {
$options['group_by'] = array(
- 'category' => 'advanced',
+ 'category' => 'other',
'title' => t('Use grouping'),
'value' => $this->get_option('group_by') ? t('Yes') : t('No'),
'desc' => t('Allow grouping and aggregation (calculation) of fields.'),
@@ -1016,7 +1045,7 @@ class views_plugin_display extends views_plugin {
}
$options['query'] = array(
- 'category' => 'advanced',
+ 'category' => 'other',
'title' => t('Query settings'),
'value' => t('Settings'),
'desc' => t('Allow to set some advanced settings for the query plugin'),
@@ -1031,9 +1060,10 @@ class views_plugin_display extends views_plugin {
$access_str = $access_plugin->summary_title();
$options['access'] = array(
- 'category' => 'basic',
+ 'category' => 'access',
'title' => t('Access'),
- 'value' => $access_str,
+ 'value' => $access_plugin->plugin_title(),
+ 'setting' => $access_str,
'desc' => t('Specify access control type for this display.'),
);
@@ -1050,9 +1080,10 @@ class views_plugin_display extends views_plugin {
$cache_str = $cache_plugin->summary_title();
$options['cache'] = array(
- 'category' => 'advanced',
+ 'category' => 'other',
'title' => t('Caching'),
- 'value' => $cache_str,
+ 'value' => $cache_plugin->plugin_title(),
+ 'setting' => $cache_str,
'desc' => t('Specify caching type for this display.'),
);
@@ -1080,7 +1111,7 @@ class views_plugin_display extends views_plugin {
$display_id = $this->get_link_display();
$link_display = empty($this->view->display[$display_id]) ? t('None') : check_plain($this->view->display[$display_id]->display_title);
$options['link_display'] = array(
- 'category' => 'basic',
+ 'category' => 'other',
'title' => t('Link display'),
'value' => $link_display,
'desc' => t('Specify which display this display will link to.'),
@@ -1106,7 +1137,8 @@ class views_plugin_display extends views_plugin {
$options['exposed_form'] = array(
'category' => 'exposed',
'title' => t('Exposed form style'),
- 'value' => $exposed_form_str,
+ 'value' => $exposed_form_plugin->plugin_title(),
+ 'setting' => $exposed_form_str,
'desc' => t('Select the kind of exposed filter to use.'),
);
@@ -1120,14 +1152,14 @@ class views_plugin_display extends views_plugin {
}
$options['css_class'] = array(
- 'category' => 'style',
+ 'category' => 'other',
'title' => t('CSS class'),
'value' => $css_class,
'desc' => t('Change the CSS class name(s) that will be added to this display.'),
);
$options['analyze-theme'] = array(
- 'category' => 'style',
+ 'category' => 'other',
'title' => t('Theme'),
'value' => t('Information'),
'desc' => t('Get information on how to theme this display'),
@@ -1139,7 +1171,7 @@ class views_plugin_display extends views_plugin {
*/
function options_form(&$form, &$form_state) {
if ($this->defaultable_sections($form_state['section'])) {
- $this->add_override_button($form, $form_state, $form_state['section']);
+ views_ui_standard_display_dropdown($form, $form_state, $form_state['section']);
}
$form['#title'] = check_plain($this->display->display_title) . ': ';
@@ -1282,7 +1314,7 @@ class views_plugin_display extends views_plugin {
if (!empty($access_plugin['uses options'])) {
$form['markup'] = array(
'#prefix' => '<div class="form-item description">',
- '#markup' => t('You may also adjust the !settings for the currently selected access restriction by clicking on the icon.', array('!settings' => $this->option_link(t('settings'), 'access_options'))),
+ '#markup' => t('You may also adjust the !settings for the currently selected access restriction.', array('!settings' => $this->option_link(t('settings'), 'access_options'))),
'#suffix' => '</div>',
);
}
@@ -1326,7 +1358,7 @@ class views_plugin_display extends views_plugin {
$form['markup'] = array(
'#prefix' => '<div class="form-item description">',
'#suffix' => '</div>',
- '#markup' => t('You may also adjust the !settings for the currently selected cache mechanism by clicking on the icon.', array('!settings' => $this->option_link(t('settings'), 'cache_options'))),
+ '#markup' => t('You may also adjust the !settings for the currently selected cache mechanism.', array('!settings' => $this->option_link(t('settings'), 'cache_options'))),
);
}
break;
@@ -1390,7 +1422,7 @@ class views_plugin_display extends views_plugin {
$style_plugin = views_fetch_plugin_data('style', $this->get_option('style_plugin'));
if (!empty($style_plugin['uses options'])) {
$form['markup'] = array(
- '#markup' => '<div class="form-item description">' . t('You may also adjust the !settings for the currently selected style by clicking on the icon.', array('!settings' => $this->option_link(t('settings'), 'style_options'))) . '</div>',
+ '#markup' => '<div class="form-item description">' . t('You may also adjust the !settings for the currently selected style.', array('!settings' => $this->option_link(t('settings'), 'style_options'))) . '</div>',
);
}
@@ -1434,7 +1466,7 @@ class views_plugin_display extends views_plugin {
$row_plugin = views_fetch_plugin_data('row', $this->get_option('row_plugin'));
if (!empty($row_plugin['uses options'])) {
$form['markup'] = array(
- '#markup' => '<div class="form-item description">' . t('You may also adjust the !settings for the currently selected row style by clicking on the icon.', array('!settings' => $this->option_link(t('settings'), 'row_options'))) . '</div>',
+ '#markup' => '<div class="form-item description">' . t('You may also adjust the !settings for the currently selected row style.', array('!settings' => $this->option_link(t('settings'), 'row_options'))) . '</div>',
);
}
@@ -1746,7 +1778,7 @@ class views_plugin_display extends views_plugin {
$form['markup'] = array(
'#prefix' => '<div class="form-item description">',
'#suffix' => '</div>',
- '#markup' => t('You may also adjust the !settings for the currently selected style by clicking on the icon.', array('!settings' => $this->option_link(t('settings'), 'exposed_form_options'))),
+ '#markup' => t('You may also adjust the !settings for the currently selected style.', array('!settings' => $this->option_link(t('settings'), 'exposed_form_options'))),
);
}
break;
@@ -1782,7 +1814,7 @@ class views_plugin_display extends views_plugin {
$form['markup'] = array(
'#prefix' => '<div class="form-item description">',
'#suffix' => '</div>',
- '#markup' => t('You may also adjust the !settings for the currently selected pager by clicking on the icon.', array('!settings' => $this->option_link(t('settings'), 'pager_options'))),
+ '#markup' => t('You may also adjust the !settings for the currently selected pager.', array('!settings' => $this->option_link(t('settings'), 'pager_options'))),
);
}
@@ -2087,54 +2119,6 @@ class views_plugin_display extends views_plugin {
}
/**
- * Add an override button for a given section, allowing the user to
- * change whether this info is stored on the default display or on
- * the current display.
- */
- function add_override_button(&$form, &$form_state, $section) {
- if ($this->is_default_display()) {
- return;
- }
-
- $form['override'] = array(
- '#prefix' => '<div class="views-override clearfix">',
- '#suffix' => '</div>',
- );
- if ($this->is_defaulted($section)) {
- $form['override']['button'] = array(
- '#type' => 'submit',
- '#value' => t('Override'),
- '#submit' => array('views_ui_edit_display_form_override'),
- );
- $help = '';
- if (module_exists('advanced_help')) {
- $help = theme('advanced_help_topic', array('module' => 'views', 'topic' => 'overrides'));
- }
- $form['override']['markup'] = array(
- '#markup' => '<div class="description">' . $help . t('Status: using default values.') . '</div>',
- );
-
- $form_state['update_name'] = t('Update default display');
- }
- else {
- $form['override']['button'] = array(
- '#type' => 'submit',
- '#value' => t('Use default'),
- '#submit' => array('views_ui_edit_display_form_override'),
- );
- $help = '';
- if (module_exists('advanced_help')) {
- $help = theme('advanced_help_topic', array('module' => 'views', 'topic' => 'overrides'));
- }
- $form['override']['markup'] = array(
- '#markup' => '<div class="description">' . $help . t('Status: using overridden values.') . '</div>',
- );
-
- $form_state['update_name'] = NULL;
- }
- }
-
- /**
* If override/revert was clicked, perform the proper toggle.
*/
function options_override($form, &$form_state) {
@@ -2414,7 +2398,7 @@ class views_plugin_display extends views_plugin {
function view_special_blocks($type) {
if ($type == '-exp') {
// avoid interfering with the admin forms.
- if (arg(0) == 'admin' && arg(1) == 'build' && arg(2) == 'views') {
+ if (arg(0) == 'admin' && arg(1) == 'structure' && arg(2) == 'views') {
return;
}
$this->view->init_handlers();
@@ -2643,5 +2627,4 @@ class views_plugin_display extends views_plugin {
/**
* @}
- */
-
+ */ \ No newline at end of file
diff --git a/plugins/views_plugin_display_attachment.inc b/plugins/views_plugin_display_attachment.inc
index 5ba92b3..cd5b1bf 100644
--- a/plugins/views_plugin_display_attachment.inc
+++ b/plugins/views_plugin_display_attachment.inc
@@ -17,12 +17,12 @@ class views_plugin_display_attachment extends views_plugin_display {
function option_definition () {
$options = parent::option_definition();
+ $options['displays'] = array('default' => array());
$options['attachment_position'] = array('default' => 'before');
$options['inherit_arguments'] = array('default' => TRUE);
$options['inherit_exposed_filters'] = array('default' => FALSE);
$options['inherit_pager'] = array('default' => FALSE);
$options['render_pager'] = array('default' => FALSE);
- $options['displays'] = array('default' => array());
return $options;
}
@@ -56,6 +56,37 @@ class views_plugin_display_attachment extends views_plugin_display {
$categories['attachment'] = array(
'title' => t('Attachment settings'),
+ 'column' => 'second',
+ 'build' => array(
+ '#weight' => -10,
+ ),
+ );
+
+ $displays = array_filter($this->get_option('displays'));
+ if (count($displays) > 1) {
+ $attach_to = t('Multiple displays');
+ }
+ elseif (count($displays) == 1) {
+ $display = array_shift($displays);
+ if (!empty($this->view->display[$display])) {
+ $attach_to = check_plain($this->view->display[$display]->display_title);
+ }
+ }
+
+ if (!isset($attach_to)) {
+ $attach_to = t('Not defined');
+ }
+
+ $options['displays'] = array(
+ 'category' => 'attachment',
+ 'title' => t('Attach to'),
+ 'value' => $attach_to,
+ );
+
+ $options['attachment_position'] = array(
+ 'category' => 'attachment',
+ 'title' => t('Attachment position'),
+ 'value' => $this->attachment_positions($this->get_option('attachment_position')),
);
$options['inherit_arguments'] = array(
@@ -71,43 +102,17 @@ class views_plugin_display_attachment extends views_plugin_display {
);
$options['inherit_pager'] = array(
- 'category' => 'attachment',
+ 'category' => 'pager',
'title' => t('Inherit pager'),
'value' => $this->get_option('inherit_pager') ? t('Yes') : t('No'),
);
$options['render_pager'] = array(
- 'category' => 'attachment',
+ 'category' => 'pager',
'title' => t('Render pager'),
'value' => $this->get_option('render_pager') ? t('Yes') : t('No'),
);
- $options['attachment_position'] = array(
- 'category' => 'attachment',
- 'title' => t('Position'),
- 'value' => $this->attachment_positions($this->get_option('attachment_position')),
- );
-
- $displays = array_filter($this->get_option('displays'));
- if (count($displays) > 1) {
- $attach_to = t('Multiple displays');
- }
- elseif (count($displays) == 1) {
- $display = array_shift($displays);
- if (!empty($this->view->display[$display])) {
- $attach_to = check_plain($this->view->display[$display]->display_title);
- }
- }
-
- if (!isset($attach_to)) {
- $attach_to = t('None');
- }
-
- $options['displays'] = array(
- 'category' => 'attachment',
- 'title' => t('Attach to'),
- 'value' => $attach_to,
- );
}
/**
diff --git a/plugins/views_plugin_display_block.inc b/plugins/views_plugin_display_block.inc
index 5f78696..0d796bf 100644
--- a/plugins/views_plugin_display_block.inc
+++ b/plugins/views_plugin_display_block.inc
@@ -63,6 +63,10 @@ class views_plugin_display_block extends views_plugin_display {
$categories['block'] = array(
'title' => t('Block settings'),
+ 'column' => 'second',
+ 'build' => array(
+ '#weight' => -10,
+ ),
);
$block_description = strip_tags($this->get_option('block_description'));
@@ -76,7 +80,7 @@ class views_plugin_display_block extends views_plugin_display {
$options['block_description'] = array(
'category' => 'block',
- 'title' => t('Admin'),
+ 'title' => t('Block name'),
'value' => $block_description,
);
@@ -87,8 +91,8 @@ class views_plugin_display_block extends views_plugin_display {
$types = $this->block_caching_modes();
$options['block_caching'] = array(
- 'category' => 'block',
- 'title' => t('Caching'),
+ 'category' => 'other',
+ 'title' => t('Block caching'),
'value' => $types[$this->get_cache_type()],
);
}
diff --git a/plugins/views_plugin_display_feed.inc b/plugins/views_plugin_display_feed.inc
index 2b0b7f4..d00a0e7 100644
--- a/plugins/views_plugin_display_feed.inc
+++ b/plugins/views_plugin_display_feed.inc
@@ -86,6 +86,10 @@ class views_plugin_display_feed extends views_plugin_display_page {
// category 'page' but let's override it so it says feed settings.
$categories['page'] = array(
'title' => t('Feed settings'),
+ 'column' => 'second',
+ 'build' => array(
+ '#weight' => -10,
+ ),
);
if ($this->get_option('sitename_title')) {
diff --git a/plugins/views_plugin_display_page.inc b/plugins/views_plugin_display_page.inc
index 418d069..b50a089 100644
--- a/plugins/views_plugin_display_page.inc
+++ b/plugins/views_plugin_display_page.inc
@@ -229,6 +229,10 @@ class views_plugin_display_page extends views_plugin_display {
$categories['page'] = array(
'title' => t('Page settings'),
+ 'column' => 'second',
+ 'build' => array(
+ '#weight' => -10,
+ ),
);
$path = strip_tags($this->get_option('path'));
diff --git a/plugins/views_plugin_exposed_form.inc b/plugins/views_plugin_exposed_form.inc
index 3303fed..b4be8cf 100644
--- a/plugins/views_plugin_exposed_form.inc
+++ b/plugins/views_plugin_exposed_form.inc
@@ -20,14 +20,6 @@ class views_plugin_exposed_form extends views_plugin {
$this->unpack_options($this->options, $options);
}
- /**
- * Return a string to display as the clickable title for the
- * control.
- */
- function summary_title() {
- return t('Unknown');
- }
-
function option_definition() {
$options = parent::option_definition();
$options['submit_button'] = array('default' => t('Apply'), 'translatable' => TRUE);
diff --git a/plugins/views_plugin_exposed_form_basic.inc b/plugins/views_plugin_exposed_form_basic.inc
index fb3306d..71d4224 100644
--- a/plugins/views_plugin_exposed_form_basic.inc
+++ b/plugins/views_plugin_exposed_form_basic.inc
@@ -3,10 +3,4 @@
/**
* Exposed form plugin that provides basic exposed form
*/
-class views_plugin_exposed_form_basic extends views_plugin_exposed_form {
-
- function summary_title() {
- return t('Basic');
- }
-
-}
+class views_plugin_exposed_form_basic extends views_plugin_exposed_form { }
diff --git a/plugins/views_plugin_exposed_form_input_required.inc b/plugins/views_plugin_exposed_form_input_required.inc
index f26f3a8..3774b40 100644
--- a/plugins/views_plugin_exposed_form_input_required.inc
+++ b/plugins/views_plugin_exposed_form_input_required.inc
@@ -5,10 +5,6 @@
*/
class views_plugin_exposed_form_input_required extends views_plugin_exposed_form {
- function summary_title() {
- return t('Input required');
- }
-
function option_definition() {
$options = parent::option_definition();
diff --git a/plugins/views_plugin_pager_full.inc b/plugins/views_plugin_pager_full.inc
index aa2f7b6..54e8f03 100644
--- a/plugins/views_plugin_pager_full.inc
+++ b/plugins/views_plugin_pager_full.inc
@@ -8,9 +8,9 @@
class views_plugin_pager_full extends views_plugin_pager {
function summary_title() {
if (!empty($this->options['offset'])) {
- return format_plural($this->options['items_per_page'], 'Paged, @count item, skip @skip', 'Paged, @count items, skip @skip', array('@count' => $this->options['items_per_page'], '@skip' => $this->options['offset']));
+ return format_plural($this->options['items_per_page'], '@count item, skip @skip', 'Paged, @count items, skip @skip', array('@count' => $this->options['items_per_page'], '@skip' => $this->options['offset']));
}
- return format_plural($this->options['items_per_page'], 'Paged, @count item', 'Paged, @count items', array('@count' => $this->options['items_per_page']));
+ return format_plural($this->options['items_per_page'], '@count item', 'Paged, @count items', array('@count' => $this->options['items_per_page']));
}
function option_definition() {
diff --git a/plugins/views_wizard/comment.inc b/plugins/views_wizard/comment.inc
new file mode 100644
index 0000000..7351fc2
--- /dev/null
+++ b/plugins/views_wizard/comment.inc
@@ -0,0 +1,29 @@
+<?php
+// $Id$
+
+// Parent plugin.
+if (module_exists('comment')) {
+ $plugin = array(
+ 'name' => 'comment',
+ 'base_table' => 'comment',
+ 'created_column' => 'created',
+ 'form_wizard_class' => array(
+ 'file' => 'views_ui_comment_views_wizard.class.php',
+ 'class' => 'ViewsUiCommentViewsWizard',
+ ),
+ 'title' => t('Comments'),
+ 'filters' => array(
+ 'status' => array(
+ 'value' => COMMENT_PUBLISHED,
+ 'table' => 'comment',
+ 'field' => 'status',
+ ),
+ 'status_node' => array(
+ 'value' => NODE_PUBLISHED,
+ 'table' => 'node',
+ 'field' => 'status',
+ 'relationship' => 'nid',
+ ),
+ ),
+ );
+}
diff --git a/plugins/views_wizard/file_managed.inc b/plugins/views_wizard/file_managed.inc
new file mode 100644
index 0000000..f6c116f
--- /dev/null
+++ b/plugins/views_wizard/file_managed.inc
@@ -0,0 +1,15 @@
+<?php
+// $Id$
+
+$plugin = array(
+ 'name' => 'file_managed',
+ 'base_table' => 'file_managed',
+ 'created_column' => 'timestamp',
+ 'form_wizard_class' => array(
+ 'file' => 'views_ui_file_managed_views_wizard.class.php',
+ 'class' => 'ViewsUiFileManagedViewsWizard',
+ ),
+ 'title' => t('Files'),
+ 'filters' => array(
+ ),
+);
diff --git a/plugins/views_wizard/node.inc b/plugins/views_wizard/node.inc
new file mode 100644
index 0000000..ce18096
--- /dev/null
+++ b/plugins/views_wizard/node.inc
@@ -0,0 +1,28 @@
+<?php
+// $Id$
+
+// Parent plugin.
+$plugin = array(
+ 'name' => 'node',
+ 'base_table' => 'node',
+ 'created_column' => 'created',
+ 'available_sorts' => array(
+ 'title:DESC' => t('Title')
+ ),
+ 'form_wizard_class' => array(
+ 'file' => 'views_ui_node_views_wizard.class.php',
+ 'class' => 'ViewsUiNodeViewsWizard',
+ ),
+ 'title' => t('Content'),
+ 'filters' => array(
+ 'status' => array(
+ 'value' => NODE_PUBLISHED,
+ 'table' => 'node',
+ 'field' => 'status',
+ ),
+ ),
+);
+
+if (module_exists('statistics')) {
+ $plugin['available_sorts']['node_counter-totalcount:DESC'] = t('Number of hits');
+}
diff --git a/plugins/views_wizard/node_revision.inc b/plugins/views_wizard/node_revision.inc
new file mode 100644
index 0000000..bbb2c85
--- /dev/null
+++ b/plugins/views_wizard/node_revision.inc
@@ -0,0 +1,21 @@
+<?php
+// $Id$
+
+// Parent plugin.
+$plugin = array(
+ 'name' => 'node_revision',
+ 'base_table' => 'node_revision',
+ 'created_column' => 'timestamp',
+ 'form_wizard_class' => array(
+ 'file' => 'views_ui_node_revision_views_wizard.class.php',
+ 'class' => 'ViewsUiNodeRevisionViewsWizard',
+ ),
+ 'title' => t('Content revisions'),
+ 'filters' => array(
+ 'status' => array(
+ 'value' => '1',
+ 'table' => 'node', // @todo - unclear if this should be node or node_revision
+ 'field' => 'status',
+ ),
+ ),
+);
diff --git a/plugins/views_wizard/taxonomy_term.inc b/plugins/views_wizard/taxonomy_term.inc
new file mode 100644
index 0000000..e8546b9
--- /dev/null
+++ b/plugins/views_wizard/taxonomy_term.inc
@@ -0,0 +1,16 @@
+<?php
+// $Id$
+
+if (module_exists('taxonomy')) {
+ $plugin = array(
+ 'name' => 'taxonomy_term',
+ 'base_table' => 'taxonomy_term_data',
+ 'form_wizard_class' => array(
+ 'file' => 'views_ui_taxonomy_term_views_wizard.class.php',
+ 'class' => 'ViewsUiTaxonomyTermViewsWizard',
+ ),
+ 'title' => t('Taxonomy terms'),
+ 'filters' => array(
+ ),
+ );
+}
diff --git a/plugins/views_wizard/users.inc b/plugins/views_wizard/users.inc
new file mode 100644
index 0000000..35fe06b
--- /dev/null
+++ b/plugins/views_wizard/users.inc
@@ -0,0 +1,22 @@
+<?php
+// $Id$
+
+// Parent plugin.
+$plugin = array(
+ 'name' => 'users',
+ 'base_table' => 'users',
+ 'created_column' => 'created',
+ 'form_wizard_class' => array(
+ 'file' => 'views_ui_users_views_wizard.class.php',
+ 'class' => 'ViewsUiUsersViewsWizard',
+ ),
+ 'title' => t('Users'),
+ 'filters' => array(
+ 'status' => array(
+ 'value' => '1',
+ 'table' => 'users',
+ 'field' => 'status',
+ ),
+ ),
+);
+
diff --git a/plugins/views_wizard/views_ui_base_views_wizard.class.php b/plugins/views_wizard/views_ui_base_views_wizard.class.php
new file mode 100644
index 0000000..0e23f78
--- /dev/null
+++ b/plugins/views_wizard/views_ui_base_views_wizard.class.php
@@ -0,0 +1,761 @@
+<?php
+
+interface ViewsWizardInterface {
+ function __construct($plugin);
+
+ /**
+ * For AJAX callbacks to build other elements in the "show" form.
+ */
+ function build_form($form, &$form_state);
+
+ /**
+ * Validate form and values.
+ *
+ * @return an array of form errors.
+ */
+ function validate($form, &$form_state);
+
+ /**
+ * Create a new View from form values.
+ *
+ * @return a view object.
+ *
+ * @throws ViewsWizardException in the event of a problem.
+ */
+ function create_view($form, &$form_state);
+}
+
+/**
+ * A custom exception class for our errors.
+ */
+class ViewsWizardException extends Exception {
+}
+
+/**
+ * A very generic Views Wizard class - can be constructed for any base table.
+ */
+class ViewsUiBaseViewsWizard implements ViewsWizardInterface {
+ protected $base_table;
+ protected $entity_type;
+ protected $entity_info = array();
+ protected $validated_views = array();
+ protected $plugin = array();
+ protected $filter_defaults = array(
+ 'id' => NULL,
+ 'expose' => array('operator' => FALSE),
+ 'group' => 0,
+ );
+
+ function __construct($plugin) {
+ $this->base_table = $plugin['base_table'];
+ $default = $this->filter_defaults;
+
+ if (isset($plugin['filters'])) {
+ foreach ($plugin['filters'] as $name => $info) {
+ $default['id'] = $name;
+ $plugin['filters'][$name] = $info + $default;
+ }
+ }
+
+ $this->plugin = $plugin;
+
+ $entities = entity_get_info();
+ foreach ($entities as $entity_type => $entity_info) {
+ if ($this->base_table == $entity_info['base table']) {
+ $this->entity_info = $entity_info;
+ $this->entity_type = $entity_type;
+ }
+ }
+ }
+
+ function build_form($form, &$form_state) {
+ $style_options = views_fetch_plugin_names('style', 'normal', array($this->base_table));
+ $feed_row_options = views_fetch_plugin_names('row', 'feed', array($this->base_table));
+ $path_prefix = url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=');
+
+ // Add filters and sorts which apply to the view as a whole.
+ $this->build_filters($form, $form_state);
+ $this->build_sorts($form, $form_state);
+
+ $form['displays']['page'] = array(
+ '#type' => 'fieldset',
+ '#tree' => TRUE,
+ );
+ $form['displays']['page']['create'] = array(
+ '#title' => t('Create a page'),
+ '#type' => 'checkbox',
+ '#attributes' => array('class' => array('strong')),
+ '#default_value' => TRUE,
+ );
+
+ // All options for the page display are included in this container so they
+ // can be hidden en masse when the "Create a page" checkbox is unchecked.
+ $form['displays']['page']['options'] = array(
+ '#type' => 'container',
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="page[create]"]' => array('checked' => TRUE),
+ ),
+ ),
+ '#parents' => array('page'),
+ );
+
+ $form['displays']['page']['options']['title'] = array(
+ '#title' => t('Page title'),
+ '#type' => 'textfield',
+ );
+ $form['displays']['page']['options']['path'] = array(
+ '#title' => t('Path'),
+ '#type' => 'textfield',
+ '#field_prefix' => $path_prefix,
+ );
+ $form['displays']['page']['options']['style'] = array(
+ '#type' => 'fieldset',
+ '#attributes' => array('class' => array('container-inline')),
+ );
+
+ // Create the dropdown for choosing the display format.
+ $form['displays']['page']['options']['style']['style_plugin'] = array(
+ '#title' => t('Display format'),
+ '#help_topic' => 'style',
+ '#type' => 'select',
+ '#options' => $style_options,
+ );
+ $style_form = &$form['displays']['page']['options']['style'];
+ $style_form['style_plugin']['#default_value'] = views_ui_get_selected($form_state, array('page', 'style', 'style_plugin'), 'default', $style_form['style_plugin']);
+ // Changing this dropdown updates $form['displays']['page']['options'] via
+ // AJAX.
+ views_ui_add_ajax_trigger($style_form, 'style_plugin', array('displays', 'page', 'options'));
+
+ $this->build_form_style($form, $form_state, 'page');
+ $form['displays']['page']['options']['items_per_page'] = array(
+ '#title' => t('Items per page'),
+ '#type' => 'textfield',
+ '#default_value' => '10',
+ '#size' => 5,
+ '#element_validate' => array('_element_validate_integer_positive'),
+ );
+ $form['displays']['page']['options']['link'] = array(
+ '#title' => t('Create a menu link'),
+ '#type' => 'checkbox',
+ );
+ $form['displays']['page']['options']['link_properties'] = array(
+ '#type' => 'container',
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="page[link]"]' => array('checked' => TRUE),
+ ),
+ ),
+ );
+ if (module_exists('menu')) {
+ $menu_options = menu_get_menus();
+ }
+ else {
+ // These are not yet translated.
+ $menu_options = menu_list_system_menus();
+ foreach ($menu_options as $name => $title) {
+ $menu_options[$name] = t($title);
+ }
+ }
+ $form['displays']['page']['options']['link_properties']['menu_name'] = array(
+ '#title' => t('Menu'),
+ '#type' => 'select',
+ '#options' => $menu_options,
+ );
+ $form['displays']['page']['options']['link_properties']['title'] = array(
+ '#title' => t('Link text'),
+ '#type' => 'textfield',
+ );
+ // Only offer a feed if we have at least one available feed row style.
+ if ($feed_row_options) {
+ $form['displays']['page']['options']['feed'] = array(
+ '#title' => t('Include an RSS feed'),
+ '#type' => 'checkbox',
+ );
+ $form['displays']['page']['options']['feed_properties'] = array(
+ '#type' => 'container',
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="page[feed]"]' => array('checked' => TRUE),
+ ),
+ ),
+ );
+ $form['displays']['page']['options']['feed_properties']['path'] = array(
+ '#title' => t('Feed path'),
+ '#type' => 'textfield',
+ '#field_prefix' => $path_prefix,
+ );
+ // This will almost never be visible.
+ $form['displays']['page']['options']['feed_properties']['row_plugin'] = array(
+ '#title' => t('Feed row style'),
+ '#type' => 'select',
+ '#options' => $feed_row_options,
+ '#default_value' => key($feed_row_options),
+ '#access' => (count($feed_row_options) > 1),
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="page[feed]"]' => array('checked' => TRUE),
+ ),
+ ),
+ );
+ }
+
+ $form['displays']['block'] = array(
+ '#type' => 'fieldset',
+ '#tree' => TRUE,
+ );
+ $form['displays']['block']['create'] = array(
+ '#title' => t('Create a block'),
+ '#type' => 'checkbox',
+ '#attributes' => array('class' => array('strong')),
+ );
+
+ // All options for the block display are included in this container so they
+ // can be hidden en masse when the "Create a block" checkbox is unchecked.
+ $form['displays']['block']['options'] = array(
+ '#type' => 'container',
+ '#states' => array(
+ 'visible' => array(
+ ':input[name="block[create]"]' => array('checked' => TRUE),
+ ),
+ ),
+ '#parents' => array('block'),
+ );
+
+ $form['displays']['block']['options']['title'] = array(
+ '#title' => t('Block title'),
+ '#type' => 'textfield',
+ );
+ $form['displays']['block']['options']['style'] = array(
+ '#type' => 'fieldset',
+ '#attributes' => array('class' => array('container-inline')),
+ );
+
+ // Create the dropdown for choosing the display format.
+ $form['displays']['block']['options']['style']['style_plugin'] = array(
+ '#title' => t('Display format'),
+ '#help_topic' => 'style',
+ '#type' => 'select',
+ '#options' => $style_options,
+ );
+ $style_form = &$form['displays']['block']['options']['style'];
+ $style_form['style_plugin']['#default_value'] = views_ui_get_selected($form_state, array('block', 'style', 'style_plugin'), 'default', $style_form['style_plugin']);
+ // Changing this dropdown updates $form['displays']['block']['options'] via
+ // AJAX.
+ views_ui_add_ajax_trigger($style_form, 'style_plugin', array('displays', 'block', 'options'));
+
+ $this->build_form_style($form, $form_state, 'block');
+ $form['displays']['block']['options']['items_per_page'] = array(
+ '#title' => t('Items per page'),
+ '#type' => 'textfield',
+ '#default_value' => '5',
+ '#size' => 5,
+ '#element_validate' => array('_element_validate_integer_positive'),
+ );
+
+ return $form;
+ }
+
+ /**
+ * Build the part of the form that builds the display format options.
+ */
+ protected function build_form_style(&$form, &$form_state, $type) {
+ $style_form =& $form['displays'][$type]['options']['style'];
+ $style = $style_form['style_plugin']['#default_value'];
+ $style_plugin = views_get_plugin('style', $style);
+ if (isset($style_plugin) && $style_plugin->uses_row_plugin()) {
+ $options = $this->row_style_options($type);
+ $style_form['row_plugin'] = array(
+ '#type' => 'select',
+ '#title' => t('of'),
+ '#options' => $options,
+ '#access' => count($options) > 1,
+ );
+ $style_form['row_plugin']['#default_value'] = views_ui_get_selected($form_state, array($type, 'style', 'row_plugin'), key($options), $style_form['row_plugin']);
+ // Changing this dropdown updates the individual row options via AJAX.
+ views_ui_add_ajax_trigger($style_form, 'row_plugin', array('displays', $type, 'options', 'style', 'row_options'));
+
+ // This is the region that can be updated by AJAX. The base class doesn't
+ // add anything here, but child classes can.
+ $style_form['row_options'] = array(
+ '#theme_wrappers' => array('container'),
+ );
+ }
+ }
+
+ /**
+ * Add possible row style options.
+ *
+ * Per default use fields with base field.
+ */
+ protected function row_style_options($type) {
+ $data = views_fetch_data($this->base_table);
+ // Get all available row plugins by default.
+ $options = views_fetch_plugin_names('row', 'normal', array($this->base_table));
+ return $options;
+ }
+
+ /**
+ * Build the part of the form that allows the user to select the view's filters.
+ *
+ * By default, this adds "of type" and "tagged with" filters (when they are
+ * available).
+ */
+ protected function build_filters(&$form, &$form_state) {
+ // Find all the fields we are allowed to filter by.
+ $fields = views_fetch_fields($this->base_table, 'filter');
+
+ $entity_info = $this->entity_info;
+ // If the current base table support bundles and has more than one (like user).
+ if (isset($entity_info['bundle keys']) && isset($entity_info['bundles'])) {
+ // Get all bundles and their human readable names.
+ $options = array('all' => t('All'));
+ foreach ($entity_info['bundles'] as $type => $bundle) {
+ $options[$type] = $bundle['label'];
+ }
+ $form['displays']['show']['type'] = array(
+ '#type' => 'select',
+ '#title' => t('of type'),
+ '#options' => $options,
+ );
+ $selected_bundle = views_ui_get_selected($form_state, array('show', 'type'), 'all', $form['displays']['show']['type']);
+ $form['displays']['show']['type']['#default_value'] = $selected_bundle;
+ // Changing this dropdown updates the entire content of $form['displays']
+ // via AJAX, since each bundle might have entirely different fields
+ // attached to it, etc.
+ views_ui_add_ajax_trigger($form['displays']['show'], 'type', array('displays'));
+ }
+
+ // Check if we are allowed to filter by taxonomy, and if so, add the
+ // "tagged with" filter to the view.
+ //
+ // We construct this filter using taxonomy_index.tid (which limits the
+ // filtering to a specific vocabulary) rather than taxonomy_term_data.name
+ // (which matches terms in any vocabulary). This is because it is a more
+ // commonly-used filter that works better with the autocomplete UI, and
+ // also to avoid confusion with other vocabularies on the site that may
+ // have terms with the same name but are not used for free tagging.
+ //
+ // The downside is that if there *is* more than one vocabulary on the site
+ // that is used for free tagging, the wizard will only be able to make the
+ // "tagged with" filter apply to one of them (see below for the method it
+ // uses to choose).
+ if (isset($fields['taxonomy_index.tid'])) {
+ // Check if this view will be displaying fieldable entities.
+ if (!empty($entity_info['fieldable'])) {
+ // Find all "tag-like" taxonomy fields associated with the view's
+ // entities. If a particular entity type (i.e., bundle) has been
+ // selected above, then we only search for taxonomy fields associated
+ // with that bundle. Otherwise, we use all bundles.
+ $bundles = array_keys($entity_info['bundles']);
+ // Double check that this is a real bundle before using it (since above
+ // we added a dummy option 'all' to the bundle list on the form).
+ if (isset($selected_bundle) && in_array($selected_bundle, $bundles)) {
+ $bundles = array($selected_bundle);
+ }
+ $tag_fields = array();
+ foreach ($bundles as $bundle) {
+ foreach (field_info_instances($this->entity_type, $bundle) as $instance) {
+ // We define "tag-like" taxonomy fields as ones that use the
+ // "Autocomplete term widget (tagging)" widget.
+ if ($instance['widget']['type'] == 'taxonomy_autocomplete') {
+ $tag_fields[] = $instance['field_name'];
+ }
+ }
+ }
+ $tag_fields = array_unique($tag_fields);
+ if (!empty($tag_fields)) {
+ // If there is more than one "tag-like" taxonomy field available to
+ // the view, we can only make our filter apply to one of them (as
+ // described above). We choose 'field_tags' if it is available, since
+ // that is created by the Standard install profile in core and also
+ // commonly used by contrib modules; thus, it is most likely to be
+ // associated with the "main" free-tagging vocabulary on the site.
+ if (in_array('field_tags', $tag_fields)) {
+ $tag_field_name = 'field_tags';
+ }
+ else {
+ $tag_field_name = reset($tag_fields);
+ }
+ // Add the autocomplete textfield to the wizard.
+ $form['displays']['show']['tagged_with'] = array(
+ '#type' => 'textfield',
+ '#title' => t('tagged with'),
+ '#autocomplete_path' => 'taxonomy/autocomplete/' . $tag_field_name,
+ '#size' => 30,
+ '#maxlength' => 1024,
+ '#field_name' => $tag_field_name,
+ '#element_validate' => array('views_ui_taxonomy_autocomplete_validate'),
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ * Build the part of the form that allows the user to select the view's sort order.
+ *
+ * By default, this adds a "sorted by [date]" filter (when it is available).
+ */
+ protected function build_sorts(&$form, &$form_state) {
+ // Check if we are allowed to sort by creation date.
+ $sorts = array();
+ if (!empty($this->plugin['created_column'])) {
+ $sorts = array(
+ $this->plugin['created_column'] . ':DESC' => t('Newest first'),
+ $this->plugin['created_column'] . ':ASC' => t('Oldest first'),
+ );
+ if (isset($this->plugin['available_sorts'])) {
+ $sorts += $this->plugin['available_sorts'];
+ }
+ }
+ if (!empty($sorts)) {
+ $form['displays']['show']['sort'] = array(
+ '#type' => 'select',
+ '#title' => t('sorted by'),
+ '#options' => $sorts,
+ '#default_value' => isset($this->plugin['created_column']) ? $this->plugin['created_column'] . ':DESC' : NULL,
+ );
+ }
+ }
+
+ protected function instantiate_view($form, &$form_state) {
+ $view = views_new_view();
+ $view->name = $form_state['values']['name'];
+ $view->human_name = $form_state['values']['human_name'];
+ $view->description = $form_state['values']['description'];
+ $view->tag = 'default';
+ $view->core = VERSION;
+ $view->base_table = $this->base_table;
+
+ // Display: Master
+ $default_display = $view->new_display('default', 'Master', 'default');
+ $options = $this->default_display_options($form, $form_state);
+ if (!isset($options['filters'])) {
+ $options['filters'] = array();
+ }
+ $options['filters'] += $this->default_display_filters($form, $form_state);
+ if (!isset($options['sorts'])) {
+ $options['sorts'] = array();
+ }
+ $options['sorts'] += $this->default_display_sorts($form, $form_state);
+ foreach ($options as $option => $value) {
+ $default_display->set_option($option, $value);
+ }
+
+ // Display: Page
+ if (!empty($form_state['values']['page']['create'])) {
+ $display = $view->new_display('page', 'Page', 'page');
+ $options = $this->page_display_options($form, $form_state);
+ // The page display is usually the main one (from the user's point of
+ // view). Its options should therefore become the overall view defaults,
+ // so that new displays which are added later automatically inherit them.
+
+ $this->set_default_options($options, $display, $default_display);
+ // Display: Feed (attached to the page)
+ if (!empty($form_state['values']['page']['feed'])) {
+ $display = $view->new_display('feed', 'Feed', 'feed');
+ $options = $this->page_feed_display_options($form, $form_state);
+ $this->set_override_options($options, $display, $default_display);
+ }
+ }
+
+ // Display: Block
+ if (!empty($form_state['values']['block']['create'])) {
+ $display = $view->new_display('block', 'Block', 'block');
+ $options = $this->block_display_options($form, $form_state);
+ // When there is no page, the block display options should become the
+ // overall view defaults.
+ if (empty($form_state['values']['page']['create'])) {
+ $this->set_default_options($options, $display, $default_display);
+ }
+ else {
+ $this->set_override_options($options, $display, $default_display);
+ }
+ }
+
+ return $view;
+ }
+
+ /**
+ * Most subclasses will need to override this method to provide some fields
+ * or a different row plugin.
+ */
+ protected function default_display_options($form, $form_state) {
+ $display_options = array();
+ $display_options['access']['type'] = 'none';
+ $display_options['cache'][