From 9344a61b6185f8d15130c1ea752441ab40d14e5c Mon Sep 17 00:00:00 2001 From: Bachir Soussi Chiadmi Date: Fri, 20 Apr 2018 23:48:40 +0200 Subject: [PATCH] updated core to 7.58 (right after the site was hacked) --- CHANGELOG.txt | 8 + includes/bootstrap.inc | 6 +- includes/common.inc | 5 +- includes/request-sanitizer.inc | 82 + misc/drupal.js | 38 +- modules/aggregator/aggregator.info | 6 +- modules/aggregator/tests/aggregator_test.info | 6 +- modules/block/block.info | 6 +- modules/block/tests/block_test.info | 6 +- .../block_test_theme/block_test_theme.info | 6 +- modules/blog/blog.info | 6 +- modules/book/book.info | 6 +- modules/color/color.info | 6 +- modules/comment/comment.info | 6 +- modules/contact/contact.info | 6 +- modules/contextual/contextual.info | 6 +- modules/dashboard/dashboard.info | 6 +- modules/dblog/dblog.info | 6 +- modules/field/field.info | 6 +- .../field_sql_storage/field_sql_storage.info | 6 +- modules/field/modules/list/list.info | 6 +- .../field/modules/list/tests/list_test.info | 6 +- modules/field/modules/number/number.info | 6 +- modules/field/modules/options/options.info | 6 +- modules/field/modules/text/text.info | 6 +- modules/field/tests/field_test.info | 6 +- modules/field_ui/field_ui.info | 6 +- modules/file/file.info | 6 +- modules/file/file.module | 16 +- modules/file/tests/file.test | 73 + modules/file/tests/file_module_test.info | 6 +- modules/file/tests/file_module_test.module | 15 + modules/filter/filter.info | 6 +- modules/forum/forum.info | 6 +- modules/help/help.info | 6 +- modules/image/image.info | 6 +- modules/image/tests/image_module_test.info | 6 +- modules/locale/locale.info | 6 +- modules/locale/tests/locale_test.info | 6 +- modules/menu/menu.info | 6 +- modules/node/node.info | 6 +- modules/node/tests/node_access_test.info | 6 +- modules/node/tests/node_test.info | 6 +- modules/node/tests/node_test_exception.info | 6 +- modules/openid/openid.info | 6 +- modules/openid/tests/openid_test.info | 6 +- modules/overlay/overlay.info | 6 +- modules/path/path.info | 6 +- modules/php/php.info | 6 +- modules/poll/poll.info | 6 +- modules/profile/profile.info | 6 +- modules/rdf/rdf.info | 6 +- modules/rdf/tests/rdf_test.info | 6 +- modules/search/search.info | 6 +- .../search/tests/search_embedded_form.info | 6 +- modules/search/tests/search_extra_type.info | 6 +- modules/search/tests/search_node_tags.info | 6 +- modules/shortcut/shortcut.info | 6 +- modules/simpletest/simpletest.info | 6 +- .../simpletest/tests/actions_loop_test.info | 6 +- modules/simpletest/tests/ajax_forms_test.info | 6 +- modules/simpletest/tests/ajax_test.info | 6 +- modules/simpletest/tests/batch_test.info | 6 +- modules/simpletest/tests/boot_test_1.info | 6 +- modules/simpletest/tests/boot_test_2.info | 6 +- modules/simpletest/tests/common.test | 34 +- modules/simpletest/tests/common_test.info | 6 +- modules/simpletest/tests/common_test.module | 3 + .../tests/common_test_cron_helper.info | 6 +- modules/simpletest/tests/database_test.info | 6 +- .../drupal_autoload_test.info | 6 +- ...drupal_system_listing_compatible_test.info | 6 +- ...upal_system_listing_incompatible_test.info | 6 +- .../simpletest/tests/entity_cache_test.info | 6 +- .../tests/entity_cache_test_dependency.info | 6 +- .../tests/entity_crud_hook_test.info | 6 +- .../tests/entity_query_access_test.info | 6 +- modules/simpletest/tests/error_test.info | 6 +- modules/simpletest/tests/file_test.info | 6 +- modules/simpletest/tests/filter_test.info | 6 +- modules/simpletest/tests/form_test.info | 6 +- modules/simpletest/tests/image_test.info | 6 +- modules/simpletest/tests/menu_test.info | 6 +- modules/simpletest/tests/module_test.info | 6 +- modules/simpletest/tests/path_test.info | 6 +- .../tests/psr_0_test/psr_0_test.info | 6 +- .../tests/psr_4_test/psr_4_test.info | 6 +- .../simpletest/tests/requirements1_test.info | 6 +- .../simpletest/tests/requirements2_test.info | 6 +- modules/simpletest/tests/session_test.info | 6 +- .../tests/system_dependencies_test.info | 6 +- ...atible_core_version_dependencies_test.info | 6 +- ...system_incompatible_core_version_test.info | 6 +- ...ible_module_version_dependencies_test.info | 6 +- ...stem_incompatible_module_version_test.info | 6 +- .../tests/system_project_namespace_test.info | 6 +- modules/simpletest/tests/system_test.info | 6 +- modules/simpletest/tests/taxonomy_test.info | 6 +- modules/simpletest/tests/theme_test.info | 6 +- .../themes/test_basetheme/test_basetheme.info | 6 +- .../themes/test_subtheme/test_subtheme.info | 6 +- .../tests/themes/test_theme/test_theme.info | 6 +- .../test_theme_nyan_cat.info | 6 +- .../simpletest/tests/update_script_test.info | 6 +- modules/simpletest/tests/update_test_1.info | 6 +- modules/simpletest/tests/update_test_2.info | 6 +- modules/simpletest/tests/update_test_3.info | 6 +- modules/simpletest/tests/url_alter_test.info | 6 +- modules/simpletest/tests/xmlrpc_test.info | 6 +- modules/statistics/statistics.info | 6 +- modules/syslog/syslog.info | 6 +- modules/system/system.info | 6 +- modules/system/tests/cron_queue_test.info | 6 +- modules/system/tests/system_cron_test.info | 6 +- modules/taxonomy/taxonomy.info | 6 +- modules/toolbar/toolbar.info | 6 +- modules/tracker/tracker.info | 6 +- .../translation/tests/translation_test.info | 6 +- modules/translation/translation.info | 6 +- modules/trigger/tests/trigger_test.info | 6 +- modules/trigger/trigger.info | 6 +- modules/update/tests/aaa_update_test.info | 6 +- modules/update/tests/bbb_update_test.info | 6 +- modules/update/tests/ccc_update_test.info | 6 +- .../update_test_admintheme.info | 6 +- .../update_test_basetheme.info | 6 +- .../update_test_subtheme.info | 6 +- modules/update/tests/update_test.info | 6 +- modules/update/update.info | 6 +- modules/user/tests/user_form_test.info | 6 +- modules/user/user.info | 6 +- modules/user/user.module | 38 +- modules/user/user.test | 53 - profiles/minimal/minimal.info | 6 +- profiles/standard/standard.info | 6 +- ...drupal_system_listing_compatible_test.info | 6 +- ...upal_system_listing_incompatible_test.info | 6 +- profiles/testing/testing.info | 6 +- .../all/modules/contrib/admin/adb/LICENSE.txt | 339 +++ sites/all/modules/contrib/admin/adb/adb.info | 12 + .../all/modules/contrib/admin/adb/adb.install | 83 + .../all/modules/contrib/admin/adb/adb.module | 430 +++ .../contrib/admin/modules_weight/LICENSE.txt | 339 +++ .../contrib/admin/modules_weight/README.txt | 9 + .../admin/modules_weight/modules_weight.info | 10 + .../modules_weight/modules_weight.module | 186 ++ .../admin/permission_report/LICENSE.txt | 339 +++ .../permission_report/permission_report.info | 10 + .../permission_report.module | 342 +++ .../modules/contrib/dev/examples/LICENSE.txt | 339 +++ .../modules/contrib/dev/examples/README.txt | 62 + .../action_example/action_example.info | 13 + .../action_example/action_example.module | 375 +++ .../action_example/action_example.test | 111 + .../examples/ajax_example/ajax_example.css | 17 + .../examples/ajax_example/ajax_example.info | 12 + .../ajax_example/ajax_example.install | 56 + .../dev/examples/ajax_example/ajax_example.js | 29 + .../examples/ajax_example/ajax_example.module | 693 +++++ .../examples/ajax_example/ajax_example.test | 75 + .../ajax_example/ajax_example_advanced.inc | 400 +++ .../ajax_example_autocomplete.inc | 458 ++++ .../ajax_example_graceful_degradation.inc | 668 +++++ .../ajax_example/ajax_example_misc.inc | 116 + .../ajax_example_node_form_alter.inc | 149 ++ .../ajax_example/ajax_example_progressbar.inc | 116 + .../examples/batch_example/batch_example.info | 12 + .../batch_example/batch_example.install | 85 + .../batch_example/batch_example.module | 318 +++ .../examples/batch_example/batch_example.test | 60 + .../examples/block_example/block_example.info | 13 + .../block_example/block_example.install | 14 + .../block_example/block_example.module | 248 ++ .../examples/block_example/block_example.test | 114 + .../examples/cache_example/cache_example.info | 13 + .../cache_example/cache_example.module | 246 ++ .../examples/cache_example/cache_example.test | 81 + .../contextual-links-example-object.tpl.php | 36 + .../contextual_links_example.info | 12 + .../contextual_links_example.module | 388 +++ .../contextual_links_example.test | 62 + .../examples/cron_example/cron_example.info | 12 + .../examples/cron_example/cron_example.module | 266 ++ .../examples/cron_example/cron_example.test | 84 + .../examples/dbtng_example/dbtng_example.info | 12 + .../dbtng_example/dbtng_example.install | 102 + .../dbtng_example/dbtng_example.module | 579 ++++ .../examples/dbtng_example/dbtng_example.test | 191 ++ .../examples/email_example/email_example.info | 12 + .../email_example/email_example.module | 212 ++ .../examples/email_example/email_example.test | 103 + .../entity_example/entity_example.info | 14 + .../entity_example/entity_example.install | 71 + .../entity_example/entity_example.module | 635 +++++ .../entity_example/entity_example.test | 162 ++ .../contrib/dev/examples/examples.index.php | 40 + .../contrib/dev/examples/examples.info | 11 + .../contrib/dev/examples/examples.module | 42 + .../examples/field_example/field_example.css | 8 + .../examples/field_example/field_example.info | 12 + .../field_example/field_example.install | 35 + .../examples/field_example/field_example.js | 25 + .../field_example/field_example.module | 389 +++ .../examples/field_example/field_example.test | 184 ++ .../field_permission_example.css | 22 + .../field_permission_example.info | 12 + .../field_permission_example.install | 32 + .../field_permission_example.module | 329 +++ .../tests/field_permission_example.test | 572 ++++ .../examples/file_example/file_example.info | 13 + .../examples/file_example/file_example.module | 570 ++++ .../examples/file_example/file_example.test | 149 ++ .../file_example_session_streams.inc | 698 +++++ .../filter_example/filter_example.info | 12 + .../filter_example/filter_example.module | 203 ++ .../filter_example/filter_example.test | 109 + .../examples/form_example/form_example.info | 12 + .../examples/form_example/form_example.module | 234 ++ .../examples/form_example/form_example.test | 275 ++ .../form_example/form_example_elements.inc | 531 ++++ .../form_example/form_example_states.inc | 296 +++ .../form_example/form_example_tutorial.inc | 934 +++++++ .../form_example/form_example_wizard.inc | 325 +++ .../examples/image_example/image_example.info | 13 + .../image_example/image_example.install | 54 + .../image_example/image_example.module | 378 +++ .../image_example/image_example.pages.inc | 166 ++ .../examples/image_example/image_example.test | 111 + .../dev/examples/js_example/accordion.tpl.php | 59 + .../dev/examples/js_example/css/jsweights.css | 5 + .../dev/examples/js_example/js/black.js | 9 + .../dev/examples/js_example/js/blue.js | 9 + .../dev/examples/js_example/js/brown.js | 9 + .../dev/examples/js_example/js/green.js | 9 + .../dev/examples/js_example/js/purple.js | 9 + .../contrib/dev/examples/js_example/js/red.js | 9 + .../dev/examples/js_example/js_example.info | 12 + .../dev/examples/js_example/js_example.module | 122 + .../dev/examples/js_example/js_example.test | 46 + .../examples/menu_example/menu_example.info | 12 + .../examples/menu_example/menu_example.module | 546 ++++ .../examples/menu_example/menu_example.test | 116 + .../node_access_example.info | 12 + .../node_access_example.install | 31 + .../node_access_example.module | 482 ++++ .../node_access_example.test | 338 +++ .../examples/node_example/node_example.info | 13 + .../examples/node_example/node_example.module | 377 +++ .../examples/node_example/node_example.test | 117 + .../nodeapi_example/nodeapi_example.info | 12 + .../nodeapi_example/nodeapi_example.install | 80 + .../nodeapi_example/nodeapi_example.module | 282 ++ .../nodeapi_example/nodeapi_example.test | 222 ++ .../examples/page_example/page_example.info | 12 + .../examples/page_example/page_example.module | 213 ++ .../examples/page_example/page_example.test | 126 + .../examples/pager_example/pager_example.info | 12 + .../pager_example/pager_example.module | 98 + .../examples/pager_example/pager_example.test | 57 + .../examples/queue_example/queue_example.css | 3 + .../examples/queue_example/queue_example.info | 12 + .../queue_example/queue_example.module | 351 +++ .../examples/queue_example/queue_example.test | 75 + .../dev/examples/rdf_example/rdf_example.info | 12 + .../examples/rdf_example/rdf_example.install | 129 + .../examples/rdf_example/rdf_example.module | 86 + .../dev/examples/rdf_example/rdf_example.test | 55 + .../render_example/render_example.css | 20 + .../render_example/render_example.info | 14 + .../render_example/render_example.install | 17 + .../render_example/render_example.module | 557 ++++ .../render_example/render_example.test | 150 ++ .../simpletest_example.info | 13 + .../simpletest_example.install | 29 + .../simpletest_example.module | 132 + .../simpletest_example.test | 265 ++ .../tests/simpletest_example_test.info | 13 + .../tests/simpletest_example_test.module | 31 + .../tabledrag_example/tabledrag_example.info | 12 + .../tabledrag_example.install | 151 ++ .../tabledrag_example.module | 84 + .../tabledrag_example/tabledrag_example.test | 46 + .../tabledrag_example_parent_form.inc | 333 +++ .../tabledrag_example_simple_form.inc | 177 ++ .../tablesort_example/tablesort_example.info | 12 + .../tablesort_example.install | 78 + .../tablesort_example.module | 93 + .../tablesort_example/tablesort_example.test | 66 + .../theming-example-text-form.tpl.php | 29 + .../theming_example/theming_example.css | 11 + .../theming_example/theming_example.info | 12 + .../theming_example/theming_example.module | 386 +++ .../theming_example/theming_example.test | 66 + .../examples/token_example/token_example.info | 13 + .../token_example/token_example.module | 228 ++ .../examples/token_example/token_example.test | 76 + .../token_example/token_example.tokens.inc | 142 + .../trigger_example/trigger_example.info | 13 + .../trigger_example/trigger_example.module | 318 +++ .../trigger_example/trigger_example.test | 89 + .../vertical_tabs_example.info | 12 + .../vertical_tabs_example.js | 23 + .../vertical_tabs_example.module | 114 + .../vertical_tabs_example.test | 45 + .../xmlrpc_example/xmlrpc_example.info | 12 + .../xmlrpc_example/xmlrpc_example.module | 707 +++++ .../xmlrpc_example/xmlrpc_example.test | 139 + .../editor/wysiwyg/editors/css/tinymce-4.css | 4 + .../editor/wysiwyg/editors/css/wymeditor.css | 6 + .../editor/wysiwyg/editors/js/tinymce-4.js | 245 ++ .../editor/wysiwyg/editors/js/wymeditor-1.js | 63 + .../editor/wysiwyg/includes/styling.inc | 130 + .../fields/hierarchical_select/API.txt | 693 +++++ .../fields/hierarchical_select/LICENSE.txt | 339 +++ .../fields/hierarchical_select/README.txt | 200 ++ .../fields/hierarchical_select/TODO.txt | 44 + .../fields/hierarchical_select/UPGRADE.txt | 20 + .../hierarchical_select-rtl.css | 57 + .../hierarchical_select.admin.inc | 313 +++ .../hierarchical_select.css | 226 ++ .../hierarchical_select.features.inc | 99 + .../hierarchical_select.info | 14 + .../hierarchical_select.install | 84 + .../hierarchical_select.js | 702 +++++ .../hierarchical_select.module | 2367 ++++++++++++++++ .../hierarchical_select_cache.js | 229 ++ .../hierarchical_select_formtoarray.js | 95 + .../hierarchical_select/images/arrow-rtl.png | Bin 0 -> 139 bytes .../hierarchical_select/images/arrow.png | Bin 0 -> 172 bytes .../hierarchical_select/images/grippie.png | Bin 0 -> 162 bytes .../hierarchical_select/includes/common.inc | 441 +++ .../includes/common_config_form.css | 11 + .../includes/common_config_form.js | 148 ++ .../hierarchical_select/includes/theme.inc | 413 +++ .../hierarchical_select/includes/views.js | 29 + .../modules/hs_flatlist.info | 12 + .../modules/hs_flatlist.module | 66 + .../hierarchical_select/modules/hs_menu.info | 13 + .../modules/hs_menu.install | 27 + .../modules/hs_menu.module | 326 +++ .../modules/hs_smallhierarchy.info | 12 + .../modules/hs_smallhierarchy.module | 214 ++ .../modules/hs_taxonomy.info | 14 + .../modules/hs_taxonomy.install | 123 + .../modules/hs_taxonomy.module | 1277 +++++++++ .../modules/hser/README.txt | 8 + .../modules/hser/hser.info | 18 + .../modules/hser/hser.module | 132 + .../hierarchical_select/tests/internals.test | 433 +++ .../contrib/fields/prepopulate/LICENSE.txt | 339 +++ .../contrib/fields/prepopulate/README.txt | 23 + .../fields/prepopulate/prepopulate.info | 10 + .../fields/prepopulate/prepopulate.install | 12 + .../fields/prepopulate/prepopulate.module | 98 + .../entity_translation_tabs/LICENSE.txt | 339 +++ .../entity_translation_tabs/README.txt | 34 + .../entity_translation_tabs.info | 14 + .../entity_translation_tabs.module | 82 + .../localisation/i18n_access/LICENSE.txt | 339 +++ .../entity_translation-2211649-5.patch | 288 ++ .../i18n_access/i18n_access.2298475-6.patch | 619 +++++ .../localisation/i18n_access/i18n_access.info | 14 + .../i18n_access/i18n_access.info.orig | 14 + .../i18n_access/i18n_access.info.rej | 12 + .../i18n_access/i18n_access.install | 46 + .../i18n_access/i18n_access.module | 405 +++ .../localisation/i18n_access/i18n_access.test | 332 +++ .../contrib/localisation/tmgmt/LICENSE.txt | 339 +++ .../contrib/localisation/tmgmt/README.txt | 180 ++ .../tmgmt/controller/tmgmt.controller.job.inc | 60 + .../controller/tmgmt.controller.job_item.inc | 71 + .../controller/tmgmt.controller.remote.inc | 97 + .../tmgmt.controller.translator.inc | 62 + .../localisation/tmgmt/demo/tmgmt_demo.info | 18 + .../tmgmt/demo/tmgmt_demo.install | 89 + .../localisation/tmgmt/demo/tmgmt_demo.module | 1 + .../tmgmt/entity/tmgmt.entity.job.inc | 880 ++++++ .../tmgmt/entity/tmgmt.entity.job_item.inc | 1000 +++++++ .../tmgmt/entity/tmgmt.entity.message.inc | 143 + .../tmgmt/entity/tmgmt.entity.remote.inc | 155 ++ .../tmgmt/entity/tmgmt.entity.translator.inc | 299 +++ .../tmgmt/includes/tmgmt.exception.inc | 17 + .../tmgmt/includes/tmgmt.info.inc | 174 ++ .../tmgmt/plugin/tmgmt.plugin.base.inc | 38 + .../plugin/tmgmt.plugin.interface.base.inc | 35 + .../plugin/tmgmt.plugin.interface.reject.inc | 56 + .../plugin/tmgmt.plugin.interface.source.inc | 103 + .../tmgmt.plugin.interface.translator.inc | 258 ++ .../tmgmt/plugin/tmgmt.plugin.source.inc | 64 + .../tmgmt/plugin/tmgmt.plugin.translator.inc | 246 ++ .../plugin/tmgmt.ui.interface.source.inc | 52 + .../plugin/tmgmt.ui.interface.translator.inc | 51 + .../tmgmt/plugin/tmgmt.ui.source.inc | 111 + .../tmgmt/plugin/tmgmt.ui.translator.inc | 128 + ...entity.admin.entity_source_search_form.css | 8 + .../entity/tests/tmgmt_entity_test.info | 12 + .../entity/tests/tmgmt_entity_test.module | 20 + .../tmgmt/sources/entity/tmgmt_entity.api.php | 25 + .../tmgmt/sources/entity/tmgmt_entity.info | 27 + .../tmgmt/sources/entity/tmgmt_entity.module | 332 +++ .../sources/entity/tmgmt_entity.pathauto.test | 55 + .../sources/entity/tmgmt_entity.plugin.inc | 110 + .../entity/tmgmt_entity.source.none.test | 101 + .../sources/entity/tmgmt_entity.source.test | 212 ++ .../entity/tmgmt_entity.suggestions.test | 274 ++ .../tmgmt/sources/entity/tmgmt_entity.ui.inc | 257 ++ .../sources/entity/ui/tmgmt_entity_ui.info | 20 + .../entity/ui/tmgmt_entity_ui.list.test | 268 ++ .../sources/entity/ui/tmgmt_entity_ui.module | 42 + .../entity/ui/tmgmt_entity_ui.pages.inc | 135 + .../sources/entity/ui/tmgmt_entity_ui.test | 328 +++ .../sources/entity/ui/tmgmt_entity_ui.ui.inc | 174 ++ .../tmgmt/sources/field/tmgmt_field.api.php | 106 + .../tmgmt/sources/field/tmgmt_field.info | 12 + .../tmgmt/sources/field/tmgmt_field.module | 140 + .../i18n_string/tmgmt_i18n_string.info | 20 + .../i18n_string/tmgmt_i18n_string.module | 342 +++ .../i18n_string/tmgmt_i18n_string.plugin.inc | 157 ++ .../i18n_string/tmgmt_i18n_string.test | 496 ++++ .../i18n_string/tmgmt_i18n_string.ui.inc | 295 ++ .../tmgmt/sources/locale/tests/test.xx.po | 13 + .../tmgmt/sources/locale/tmgmt_locale.info | 17 + .../tmgmt/sources/locale/tmgmt_locale.install | 28 + .../tmgmt/sources/locale/tmgmt_locale.module | 25 + .../sources/locale/tmgmt_locale.plugin.inc | 245 ++ .../tmgmt/sources/locale/tmgmt_locale.test | 231 ++ .../tmgmt/sources/locale/tmgmt_locale.ui.inc | 316 +++ .../tmgmt/sources/locale/tmgmt_locale.ui.test | 105 + .../tmgmt/sources/node/tmgmt_node.api.php | 21 + .../tmgmt/sources/node/tmgmt_node.info | 26 + .../tmgmt/sources/node/tmgmt_node.module | 35 + .../tmgmt/sources/node/tmgmt_node.plugin.inc | 152 ++ .../tmgmt/sources/node/tmgmt_node.test | 147 + .../tmgmt/sources/node/tmgmt_node.ui.inc | 35 + .../tmgmt/sources/node/ui/tmgmt_node_ui.info | 22 + .../sources/node/ui/tmgmt_node_ui.module | 93 + .../node/ui/tmgmt_node_ui.overview.test | 160 ++ .../sources/node/ui/tmgmt_node_ui.pages.inc | 116 + .../node/ui/tmgmt_node_ui.rules_defaults.inc | 49 + .../node/ui/tmgmt_node_ui.source_overview.css | 15 + .../tmgmt/sources/node/ui/tmgmt_node_ui.test | 450 ++++ .../tmgmt_node_handler_field_jobs.inc | 26 + ...dler_field_translation_language_status.inc | 80 + ...eld_translation_language_status_single.inc | 62 + ...ode_handler_filter_missing_translation.inc | 108 + ...handler_filter_node_translatable_types.inc | 32 + .../sources/node/views/tmgmt_node.views.inc | 140 + .../views/tmgmt_node_source_overview.view.inc | 340 +++ .../tmgmt/tests/testing_html/sample.html | 6 + .../tmgmt/tests/tmgmt.base.entity.test | 245 ++ .../localisation/tmgmt/tests/tmgmt.base.test | 219 ++ .../localisation/tmgmt/tests/tmgmt.crud.test | 532 ++++ .../tmgmt/tests/tmgmt.helper.test | 123 + .../tmgmt/tests/tmgmt.plugin.test | 230 ++ .../tmgmt/tests/tmgmt.upgrade.alpha1.test | 159 ++ .../tmgmt/tests/tmgmt_alpha1_dump.sql.inc | 463 ++++ .../localisation/tmgmt/tests/tmgmt_test.info | 16 + .../tmgmt/tests/tmgmt_test.module | 93 + .../tests/tmgmt_test.plugin.html_source.inc | 23 + .../tmgmt/tests/tmgmt_test.plugin.source.inc | 111 + .../tests/tmgmt_test.plugin.translator.inc | 108 + .../tmgmt/tests/tmgmt_test.ui.translator.inc | 66 + .../contrib/localisation/tmgmt/tmgmt.api.php | 272 ++ .../contrib/localisation/tmgmt/tmgmt.info | 58 + .../contrib/localisation/tmgmt/tmgmt.install | 877 ++++++ .../contrib/localisation/tmgmt/tmgmt.module | 1550 +++++++++++ .../localisation/tmgmt/tmgmt.rules.inc | 247 ++ .../tmgmt_file_html_template.tpl.php | 20 + .../tmgmt/translators/file/tmgmt_file.api.php | 58 + .../translators/file/tmgmt_file.drush.inc | 80 + .../file/tmgmt_file.format.html.inc | 103 + .../file/tmgmt_file.format.interface.inc | 48 + .../file/tmgmt_file.format.xliff.inc | 635 +++++ .../tmgmt/translators/file/tmgmt_file.info | 20 + .../tmgmt/translators/file/tmgmt_file.module | 195 ++ .../translators/file/tmgmt_file.plugin.inc | 60 + .../file/tmgmt_file.recursive_iterator.inc | 99 + .../tmgmt/translators/file/tmgmt_file.test | 536 ++++ .../tmgmt/translators/file/tmgmt_file.ui.inc | 115 + .../file/xliff-core-1.2-strict.xsd | 2223 ++++++++++++++++ .../tmgmt/translators/tmgmt_local/README.txt | 59 + .../tmgmt_local.controller.task.inc | 39 + .../tmgmt_local.controller.task_item.inc | 77 + .../tmgmt_local.ui_controller.task.inc | 76 + .../tmgmt_local.ui_controller.task_item.inc | 27 + .../entity/tmgmt_local.entity.task.inc | 387 +++ .../entity/tmgmt_local.entity.task_item.inc | 252 ++ .../tmgmt_local/includes/tmgmt_local.info.inc | 91 + .../includes/tmgmt_local.pages.inc | 515 ++++ .../includes/tmgmt_local.plugin.inc | 91 + .../includes/tmgmt_local.plugin.ui.inc | 78 + .../includes/tmgmt_local.theme.inc | 56 + .../skills/tmgmt_language_combination.info | 11 + .../skills/tmgmt_language_combination.module | 288 ++ .../tmgmt_local/tmgmt_local.api.php | 7 + .../translators/tmgmt_local/tmgmt_local.info | 37 + .../tmgmt_local/tmgmt_local.install | 387 +++ .../tmgmt_local/tmgmt_local.module | 903 +++++++ .../tmgmt_local/tmgmt_local.rules.inc | 65 + .../tmgmt_local.rules_defaults.inc | 57 + .../translators/tmgmt_local/tmgmt_local.test | 614 +++++ ...cal_task_handler_field_item_operations.inc | 33 + ...ocal_task_handler_field_job_item_count.inc | 66 + ...mt_local_task_handler_field_loop_count.inc | 17 + ...mt_local_task_handler_field_operations.inc | 79 + ...mgmt_local_task_handler_field_progress.inc | 83 + ...gmt_local_task_handler_field_wordcount.inc | 34 + ...gmt_local_task_handler_filter_eligible.inc | 28 + .../tmgmt_local/views/tmgmt_local.views.inc | 95 + ...tmgmt_local_manage_translate_task.view.inc | 1696 ++++++++++++ .../views/tmgmt_local_task_items.view.inc | 81 + .../views/tmgmt_local_task_overview.view.inc | 2368 +++++++++++++++++ .../tmgmt/ui/css/tmgmt_ui.admin.css | 196 ++ .../tmgmt/ui/css/tmgmt_ui.admin.seven.css | 9 + .../tmgmt/ui/includes/tmgmt_ui.cart.inc | 156 ++ .../ui/includes/tmgmt_ui.controller.job.inc | 139 + .../includes/tmgmt_ui.controller.job_item.inc | 99 + .../tmgmt_ui.controller.translator.inc | 164 ++ .../tmgmt/ui/includes/tmgmt_ui.pages.inc | 1058 ++++++++ .../tmgmt/ui/includes/tmgmt_ui.theme.inc | 315 +++ .../localisation/tmgmt/ui/tmgmt_ui.api.php | 40 + .../localisation/tmgmt/ui/tmgmt_ui.info | 24 + .../localisation/tmgmt/ui/tmgmt_ui.module | 1196 +++++++++ .../localisation/tmgmt/ui/tmgmt_ui.rules.inc | 42 + .../tmgmt/ui/tmgmt_ui.rules_defaults.inc | 67 + .../localisation/tmgmt/ui/tmgmt_ui.test | 619 +++++ .../localisation/tmgmt/ui/tmgmt_ui_job.test | 78 + .../views/tmgmt_ui_job_item_messages.view.inc | 115 + .../ui/views/tmgmt_ui_job_items.view.inc | 167 ++ .../ui/views/tmgmt_ui_job_messages.view.inc | 143 + .../ui/views/tmgmt_ui_job_overview.view.inc | 321 +++ ...tmgmt_handler_field_tmgmt_entity_label.inc | 18 + ...gmt_handler_field_tmgmt_job_item_count.inc | 71 + ...andler_field_tmgmt_job_item_operations.inc | 43 + ...mgmt_handler_field_tmgmt_job_item_type.inc | 16 + ...gmt_handler_field_tmgmt_job_operations.inc | 48 + ...mt_handler_field_tmgmt_message_message.inc | 47 + .../tmgmt_handler_field_tmgmt_progress.inc | 105 + .../tmgmt_handler_field_tmgmt_translator.inc | 21 + .../tmgmt_handler_field_tmgmt_wordcount.inc | 34 + .../views/plugins/tmgmt_views_job_access.inc | 33 + .../localisation/tmgmt/views/tmgmt.views.inc | 171 ++ .../contrib/taxonomy/tac_lite/LICENSE.txt | 339 +++ .../contrib/taxonomy/tac_lite/README.txt | 124 + .../contrib/taxonomy/tac_lite/tac_lite.info | 11 + .../taxonomy/tac_lite/tac_lite.install | 118 + .../contrib/taxonomy/tac_lite/tac_lite.module | 735 +++++ .../taxonomy/tac_lite/tac_lite_create.info | 12 + .../taxonomy/tac_lite/tac_lite_create.module | 128 + sites/all/modules/examples/LICENSE.txt | 339 +++ sites/all/modules/examples/README.txt | 62 + .../action_example/action_example.info | 19 + .../action_example/action_example.module | 375 +++ .../action_example/action_example.test | 111 + .../examples/ajax_example/ajax_example.css | 17 + .../examples/ajax_example/ajax_example.info | 12 + .../ajax_example/ajax_example.install | 56 + .../examples/ajax_example/ajax_example.js | 29 + .../examples/ajax_example/ajax_example.module | 693 +++++ .../examples/ajax_example/ajax_example.test | 75 + .../ajax_example/ajax_example_advanced.inc | 400 +++ .../ajax_example_autocomplete.inc | 458 ++++ .../ajax_example_graceful_degradation.inc | 668 +++++ .../ajax_example/ajax_example_misc.inc | 116 + .../ajax_example_node_form_alter.inc | 149 ++ .../ajax_example/ajax_example_progressbar.inc | 116 + .../examples/batch_example/batch_example.info | 12 + .../batch_example/batch_example.install | 85 + .../batch_example/batch_example.module | 319 +++ .../examples/batch_example/batch_example.test | 60 + .../examples/block_example/block_example.info | 19 + .../block_example/block_example.install | 14 + .../block_example/block_example.module | 248 ++ .../examples/block_example/block_example.test | 114 + .../examples/cache_example/cache_example.info | 13 + .../cache_example/cache_example.module | 246 ++ .../examples/cache_example/cache_example.test | 81 + .../contextual-links-example-object.tpl.php | 36 + .../contextual_links_example.info | 12 + .../contextual_links_example.module | 388 +++ .../contextual_links_example.test | 62 + .../examples/cron_example/cron_example.info | 12 + .../examples/cron_example/cron_example.module | 266 ++ .../examples/cron_example/cron_example.test | 84 + .../examples/dbtng_example/dbtng_example.info | 12 + .../dbtng_example/dbtng_example.install | 102 + .../dbtng_example/dbtng_example.module | 579 ++++ .../examples/dbtng_example/dbtng_example.test | 191 ++ .../examples/email_example/email_example.info | 12 + .../email_example/email_example.module | 212 ++ .../examples/email_example/email_example.test | 103 + .../entity_example/entity_example.info | 20 + .../entity_example/entity_example.install | 71 + .../entity_example/entity_example.module | 635 +++++ .../entity_example/entity_example.test | 162 ++ sites/all/modules/examples/examples.index.php | 40 + sites/all/modules/examples/examples.info | 11 + sites/all/modules/examples/examples.module | 42 + .../examples/field_example/field_example.css | 8 + .../examples/field_example/field_example.info | 12 + .../field_example/field_example.install | 35 + .../examples/field_example/field_example.js | 25 + .../field_example/field_example.module | 389 +++ .../examples/field_example/field_example.test | 184 ++ .../field_permission_example.css | 22 + .../field_permission_example.info | 12 + .../field_permission_example.install | 32 + .../field_permission_example.module | 329 +++ .../tests/field_permission_example.test | 572 ++++ .../examples/file_example/file_example.info | 13 + .../examples/file_example/file_example.module | 570 ++++ .../examples/file_example/file_example.test | 149 ++ .../file_example_session_streams.inc | 698 +++++ .../filter_example/filter_example.info | 12 + .../filter_example/filter_example.module | 203 ++ .../filter_example/filter_example.test | 109 + .../examples/form_example/form_example.info | 12 + .../examples/form_example/form_example.module | 234 ++ .../examples/form_example/form_example.test | 288 ++ .../form_example/form_example_elements.inc | 531 ++++ .../form_example/form_example_states.inc | 296 +++ .../form_example/form_example_tutorial.inc | 934 +++++++ .../form_example/form_example_wizard.inc | 325 +++ .../examples/image_example/image_example.info | 19 + .../image_example/image_example.install | 54 + .../image_example/image_example.module | 378 +++ .../image_example/image_example.pages.inc | 166 ++ .../examples/image_example/image_example.test | 111 + .../examples/js_example/accordion.tpl.php | 59 + .../examples/js_example/css/jsweights.css | 5 + .../modules/examples/js_example/js/black.js | 9 + .../modules/examples/js_example/js/blue.js | 9 + .../modules/examples/js_example/js/brown.js | 9 + .../modules/examples/js_example/js/green.js | 9 + .../modules/examples/js_example/js/purple.js | 9 + .../all/modules/examples/js_example/js/red.js | 9 + .../examples/js_example/js_example.info | 12 + .../examples/js_example/js_example.module | 122 + .../examples/js_example/js_example.test | 46 + .../examples/menu_example/menu_example.info | 12 + .../examples/menu_example/menu_example.module | 546 ++++ .../examples/menu_example/menu_example.test | 116 + .../node_access_example.info | 12 + .../node_access_example.install | 31 + .../node_access_example.module | 482 ++++ .../node_access_example.test | 338 +++ .../examples/node_example/node_example.info | 19 + .../examples/node_example/node_example.module | 377 +++ .../examples/node_example/node_example.test | 117 + .../nodeapi_example/nodeapi_example.info | 12 + .../nodeapi_example/nodeapi_example.install | 80 + .../nodeapi_example/nodeapi_example.module | 282 ++ .../nodeapi_example/nodeapi_example.test | 222 ++ .../examples/page_example/page_example.info | 12 + .../examples/page_example/page_example.module | 213 ++ .../examples/page_example/page_example.test | 126 + .../examples/pager_example/pager_example.info | 12 + .../pager_example/pager_example.module | 98 + .../examples/pager_example/pager_example.test | 57 + .../examples/queue_example/queue_example.css | 3 + .../examples/queue_example/queue_example.info | 12 + .../queue_example/queue_example.module | 351 +++ .../examples/queue_example/queue_example.test | 75 + .../examples/rdf_example/rdf_example.info | 12 + .../examples/rdf_example/rdf_example.install | 129 + .../examples/rdf_example/rdf_example.module | 86 + .../examples/rdf_example/rdf_example.test | 55 + .../render_example/render_example.css | 20 + .../render_example/render_example.info | 14 + .../render_example/render_example.install | 17 + .../render_example/render_example.module | 557 ++++ .../render_example/render_example.test | 150 ++ .../simpletest_example.info | 19 + .../simpletest_example.install | 29 + .../simpletest_example.module | 132 + .../simpletest_example.test | 265 ++ .../tests/simpletest_example_test.info | 13 + .../tests/simpletest_example_test.module | 31 + .../tabledrag_example/tabledrag_example.info | 12 + .../tabledrag_example.install | 151 ++ .../tabledrag_example.module | 84 + .../tabledrag_example/tabledrag_example.test | 46 + .../tabledrag_example_parent_form.inc | 333 +++ .../tabledrag_example_simple_form.inc | 177 ++ .../tablesort_example/tablesort_example.info | 12 + .../tablesort_example.install | 78 + .../tablesort_example.module | 93 + .../tablesort_example/tablesort_example.test | 66 + .../theming-example-text-form.tpl.php | 29 + .../theming_example/theming_example.css | 11 + .../theming_example/theming_example.info | 12 + .../theming_example/theming_example.module | 385 +++ .../theming_example/theming_example.test | 66 + .../examples/token_example/token_example.info | 20 + .../token_example/token_example.module | 228 ++ .../examples/token_example/token_example.test | 76 + .../token_example/token_example.tokens.inc | 142 + .../trigger_example/trigger_example.info | 19 + .../trigger_example/trigger_example.module | 318 +++ .../trigger_example/trigger_example.test | 89 + .../vertical_tabs_example.info | 12 + .../vertical_tabs_example.js | 23 + .../vertical_tabs_example.module | 114 + .../vertical_tabs_example.test | 45 + .../xmlrpc_example/xmlrpc_example.info | 12 + .../xmlrpc_example/xmlrpc_example.module | 707 +++++ .../xmlrpc_example/xmlrpc_example.test | 139 + themes/bartik/bartik.info | 6 +- themes/garland/garland.info | 6 +- themes/seven/seven.info | 6 +- themes/stark/stark.info | 6 +- 711 files changed, 99690 insertions(+), 480 deletions(-) create mode 100644 includes/request-sanitizer.inc create mode 100644 sites/all/modules/contrib/admin/adb/LICENSE.txt create mode 100644 sites/all/modules/contrib/admin/adb/adb.info create mode 100644 sites/all/modules/contrib/admin/adb/adb.install create mode 100644 sites/all/modules/contrib/admin/adb/adb.module create mode 100644 sites/all/modules/contrib/admin/modules_weight/LICENSE.txt create mode 100644 sites/all/modules/contrib/admin/modules_weight/README.txt create mode 100644 sites/all/modules/contrib/admin/modules_weight/modules_weight.info create mode 100644 sites/all/modules/contrib/admin/modules_weight/modules_weight.module create mode 100644 sites/all/modules/contrib/admin/permission_report/LICENSE.txt create mode 100644 sites/all/modules/contrib/admin/permission_report/permission_report.info create mode 100644 sites/all/modules/contrib/admin/permission_report/permission_report.module create mode 100644 sites/all/modules/contrib/dev/examples/LICENSE.txt create mode 100644 sites/all/modules/contrib/dev/examples/README.txt create mode 100644 sites/all/modules/contrib/dev/examples/action_example/action_example.info create mode 100644 sites/all/modules/contrib/dev/examples/action_example/action_example.module create mode 100644 sites/all/modules/contrib/dev/examples/action_example/action_example.test create mode 100644 sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.css create mode 100644 sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.info create mode 100644 sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.install create mode 100644 sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.js create mode 100644 sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.module create mode 100644 sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.test create mode 100644 sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_advanced.inc create mode 100644 sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_autocomplete.inc create mode 100644 sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_graceful_degradation.inc create mode 100644 sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_misc.inc create mode 100644 sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_node_form_alter.inc create mode 100644 sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_progressbar.inc create mode 100644 sites/all/modules/contrib/dev/examples/batch_example/batch_example.info create mode 100644 sites/all/modules/contrib/dev/examples/batch_example/batch_example.install create mode 100644 sites/all/modules/contrib/dev/examples/batch_example/batch_example.module create mode 100644 sites/all/modules/contrib/dev/examples/batch_example/batch_example.test create mode 100644 sites/all/modules/contrib/dev/examples/block_example/block_example.info create mode 100644 sites/all/modules/contrib/dev/examples/block_example/block_example.install create mode 100644 sites/all/modules/contrib/dev/examples/block_example/block_example.module create mode 100644 sites/all/modules/contrib/dev/examples/block_example/block_example.test create mode 100644 sites/all/modules/contrib/dev/examples/cache_example/cache_example.info create mode 100644 sites/all/modules/contrib/dev/examples/cache_example/cache_example.module create mode 100644 sites/all/modules/contrib/dev/examples/cache_example/cache_example.test create mode 100644 sites/all/modules/contrib/dev/examples/contextual_links_example/contextual-links-example-object.tpl.php create mode 100644 sites/all/modules/contrib/dev/examples/contextual_links_example/contextual_links_example.info create mode 100644 sites/all/modules/contrib/dev/examples/contextual_links_example/contextual_links_example.module create mode 100644 sites/all/modules/contrib/dev/examples/contextual_links_example/contextual_links_example.test create mode 100644 sites/all/modules/contrib/dev/examples/cron_example/cron_example.info create mode 100644 sites/all/modules/contrib/dev/examples/cron_example/cron_example.module create mode 100644 sites/all/modules/contrib/dev/examples/cron_example/cron_example.test create mode 100644 sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.info create mode 100644 sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.install create mode 100644 sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.module create mode 100644 sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.test create mode 100644 sites/all/modules/contrib/dev/examples/email_example/email_example.info create mode 100644 sites/all/modules/contrib/dev/examples/email_example/email_example.module create mode 100644 sites/all/modules/contrib/dev/examples/email_example/email_example.test create mode 100644 sites/all/modules/contrib/dev/examples/entity_example/entity_example.info create mode 100644 sites/all/modules/contrib/dev/examples/entity_example/entity_example.install create mode 100644 sites/all/modules/contrib/dev/examples/entity_example/entity_example.module create mode 100644 sites/all/modules/contrib/dev/examples/entity_example/entity_example.test create mode 100644 sites/all/modules/contrib/dev/examples/examples.index.php create mode 100644 sites/all/modules/contrib/dev/examples/examples.info create mode 100644 sites/all/modules/contrib/dev/examples/examples.module create mode 100644 sites/all/modules/contrib/dev/examples/field_example/field_example.css create mode 100644 sites/all/modules/contrib/dev/examples/field_example/field_example.info create mode 100644 sites/all/modules/contrib/dev/examples/field_example/field_example.install create mode 100644 sites/all/modules/contrib/dev/examples/field_example/field_example.js create mode 100644 sites/all/modules/contrib/dev/examples/field_example/field_example.module create mode 100644 sites/all/modules/contrib/dev/examples/field_example/field_example.test create mode 100644 sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.css create mode 100644 sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.info create mode 100644 sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.install create mode 100644 sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.module create mode 100644 sites/all/modules/contrib/dev/examples/field_permission_example/tests/field_permission_example.test create mode 100644 sites/all/modules/contrib/dev/examples/file_example/file_example.info create mode 100644 sites/all/modules/contrib/dev/examples/file_example/file_example.module create mode 100644 sites/all/modules/contrib/dev/examples/file_example/file_example.test create mode 100644 sites/all/modules/contrib/dev/examples/file_example/file_example_session_streams.inc create mode 100644 sites/all/modules/contrib/dev/examples/filter_example/filter_example.info create mode 100644 sites/all/modules/contrib/dev/examples/filter_example/filter_example.module create mode 100644 sites/all/modules/contrib/dev/examples/filter_example/filter_example.test create mode 100644 sites/all/modules/contrib/dev/examples/form_example/form_example.info create mode 100644 sites/all/modules/contrib/dev/examples/form_example/form_example.module create mode 100644 sites/all/modules/contrib/dev/examples/form_example/form_example.test create mode 100644 sites/all/modules/contrib/dev/examples/form_example/form_example_elements.inc create mode 100644 sites/all/modules/contrib/dev/examples/form_example/form_example_states.inc create mode 100644 sites/all/modules/contrib/dev/examples/form_example/form_example_tutorial.inc create mode 100644 sites/all/modules/contrib/dev/examples/form_example/form_example_wizard.inc create mode 100644 sites/all/modules/contrib/dev/examples/image_example/image_example.info create mode 100644 sites/all/modules/contrib/dev/examples/image_example/image_example.install create mode 100644 sites/all/modules/contrib/dev/examples/image_example/image_example.module create mode 100644 sites/all/modules/contrib/dev/examples/image_example/image_example.pages.inc create mode 100644 sites/all/modules/contrib/dev/examples/image_example/image_example.test create mode 100644 sites/all/modules/contrib/dev/examples/js_example/accordion.tpl.php create mode 100644 sites/all/modules/contrib/dev/examples/js_example/css/jsweights.css create mode 100644 sites/all/modules/contrib/dev/examples/js_example/js/black.js create mode 100644 sites/all/modules/contrib/dev/examples/js_example/js/blue.js create mode 100644 sites/all/modules/contrib/dev/examples/js_example/js/brown.js create mode 100644 sites/all/modules/contrib/dev/examples/js_example/js/green.js create mode 100644 sites/all/modules/contrib/dev/examples/js_example/js/purple.js create mode 100644 sites/all/modules/contrib/dev/examples/js_example/js/red.js create mode 100644 sites/all/modules/contrib/dev/examples/js_example/js_example.info create mode 100644 sites/all/modules/contrib/dev/examples/js_example/js_example.module create mode 100644 sites/all/modules/contrib/dev/examples/js_example/js_example.test create mode 100644 sites/all/modules/contrib/dev/examples/menu_example/menu_example.info create mode 100644 sites/all/modules/contrib/dev/examples/menu_example/menu_example.module create mode 100644 sites/all/modules/contrib/dev/examples/menu_example/menu_example.test create mode 100644 sites/all/modules/contrib/dev/examples/node_access_example/node_access_example.info create mode 100644 sites/all/modules/contrib/dev/examples/node_access_example/node_access_example.install create mode 100644 sites/all/modules/contrib/dev/examples/node_access_example/node_access_example.module create mode 100644 sites/all/modules/contrib/dev/examples/node_access_example/node_access_example.test create mode 100644 sites/all/modules/contrib/dev/examples/node_example/node_example.info create mode 100644 sites/all/modules/contrib/dev/examples/node_example/node_example.module create mode 100644 sites/all/modules/contrib/dev/examples/node_example/node_example.test create mode 100644 sites/all/modules/contrib/dev/examples/nodeapi_example/nodeapi_example.info create mode 100644 sites/all/modules/contrib/dev/examples/nodeapi_example/nodeapi_example.install create mode 100644 sites/all/modules/contrib/dev/examples/nodeapi_example/nodeapi_example.module create mode 100644 sites/all/modules/contrib/dev/examples/nodeapi_example/nodeapi_example.test create mode 100644 sites/all/modules/contrib/dev/examples/page_example/page_example.info create mode 100644 sites/all/modules/contrib/dev/examples/page_example/page_example.module create mode 100644 sites/all/modules/contrib/dev/examples/page_example/page_example.test create mode 100644 sites/all/modules/contrib/dev/examples/pager_example/pager_example.info create mode 100644 sites/all/modules/contrib/dev/examples/pager_example/pager_example.module create mode 100644 sites/all/modules/contrib/dev/examples/pager_example/pager_example.test create mode 100644 sites/all/modules/contrib/dev/examples/queue_example/queue_example.css create mode 100644 sites/all/modules/contrib/dev/examples/queue_example/queue_example.info create mode 100644 sites/all/modules/contrib/dev/examples/queue_example/queue_example.module create mode 100644 sites/all/modules/contrib/dev/examples/queue_example/queue_example.test create mode 100644 sites/all/modules/contrib/dev/examples/rdf_example/rdf_example.info create mode 100644 sites/all/modules/contrib/dev/examples/rdf_example/rdf_example.install create mode 100644 sites/all/modules/contrib/dev/examples/rdf_example/rdf_example.module create mode 100644 sites/all/modules/contrib/dev/examples/rdf_example/rdf_example.test create mode 100644 sites/all/modules/contrib/dev/examples/render_example/render_example.css create mode 100644 sites/all/modules/contrib/dev/examples/render_example/render_example.info create mode 100644 sites/all/modules/contrib/dev/examples/render_example/render_example.install create mode 100644 sites/all/modules/contrib/dev/examples/render_example/render_example.module create mode 100644 sites/all/modules/contrib/dev/examples/render_example/render_example.test create mode 100644 sites/all/modules/contrib/dev/examples/simpletest_example/simpletest_example.info create mode 100644 sites/all/modules/contrib/dev/examples/simpletest_example/simpletest_example.install create mode 100644 sites/all/modules/contrib/dev/examples/simpletest_example/simpletest_example.module create mode 100644 sites/all/modules/contrib/dev/examples/simpletest_example/simpletest_example.test create mode 100644 sites/all/modules/contrib/dev/examples/simpletest_example/tests/simpletest_example_test.info create mode 100644 sites/all/modules/contrib/dev/examples/simpletest_example/tests/simpletest_example_test.module create mode 100644 sites/all/modules/contrib/dev/examples/tabledrag_example/tabledrag_example.info create mode 100644 sites/all/modules/contrib/dev/examples/tabledrag_example/tabledrag_example.install create mode 100644 sites/all/modules/contrib/dev/examples/tabledrag_example/tabledrag_example.module create mode 100644 sites/all/modules/contrib/dev/examples/tabledrag_example/tabledrag_example.test create mode 100644 sites/all/modules/contrib/dev/examples/tabledrag_example/tabledrag_example_parent_form.inc create mode 100644 sites/all/modules/contrib/dev/examples/tabledrag_example/tabledrag_example_simple_form.inc create mode 100644 sites/all/modules/contrib/dev/examples/tablesort_example/tablesort_example.info create mode 100644 sites/all/modules/contrib/dev/examples/tablesort_example/tablesort_example.install create mode 100644 sites/all/modules/contrib/dev/examples/tablesort_example/tablesort_example.module create mode 100644 sites/all/modules/contrib/dev/examples/tablesort_example/tablesort_example.test create mode 100644 sites/all/modules/contrib/dev/examples/theming_example/theming-example-text-form.tpl.php create mode 100644 sites/all/modules/contrib/dev/examples/theming_example/theming_example.css create mode 100644 sites/all/modules/contrib/dev/examples/theming_example/theming_example.info create mode 100644 sites/all/modules/contrib/dev/examples/theming_example/theming_example.module create mode 100644 sites/all/modules/contrib/dev/examples/theming_example/theming_example.test create mode 100644 sites/all/modules/contrib/dev/examples/token_example/token_example.info create mode 100644 sites/all/modules/contrib/dev/examples/token_example/token_example.module create mode 100644 sites/all/modules/contrib/dev/examples/token_example/token_example.test create mode 100644 sites/all/modules/contrib/dev/examples/token_example/token_example.tokens.inc create mode 100644 sites/all/modules/contrib/dev/examples/trigger_example/trigger_example.info create mode 100644 sites/all/modules/contrib/dev/examples/trigger_example/trigger_example.module create mode 100644 sites/all/modules/contrib/dev/examples/trigger_example/trigger_example.test create mode 100644 sites/all/modules/contrib/dev/examples/vertical_tabs_example/vertical_tabs_example.info create mode 100644 sites/all/modules/contrib/dev/examples/vertical_tabs_example/vertical_tabs_example.js create mode 100644 sites/all/modules/contrib/dev/examples/vertical_tabs_example/vertical_tabs_example.module create mode 100644 sites/all/modules/contrib/dev/examples/vertical_tabs_example/vertical_tabs_example.test create mode 100644 sites/all/modules/contrib/dev/examples/xmlrpc_example/xmlrpc_example.info create mode 100644 sites/all/modules/contrib/dev/examples/xmlrpc_example/xmlrpc_example.module create mode 100644 sites/all/modules/contrib/dev/examples/xmlrpc_example/xmlrpc_example.test create mode 100644 sites/all/modules/contrib/editor/wysiwyg/editors/css/tinymce-4.css create mode 100644 sites/all/modules/contrib/editor/wysiwyg/editors/css/wymeditor.css create mode 100644 sites/all/modules/contrib/editor/wysiwyg/editors/js/tinymce-4.js create mode 100644 sites/all/modules/contrib/editor/wysiwyg/editors/js/wymeditor-1.js create mode 100644 sites/all/modules/contrib/editor/wysiwyg/includes/styling.inc create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/API.txt create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/LICENSE.txt create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/README.txt create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/TODO.txt create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/UPGRADE.txt create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/hierarchical_select-rtl.css create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/hierarchical_select.admin.inc create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/hierarchical_select.css create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/hierarchical_select.features.inc create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/hierarchical_select.info create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/hierarchical_select.install create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/hierarchical_select.js create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/hierarchical_select.module create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/hierarchical_select_cache.js create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/hierarchical_select_formtoarray.js create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/images/arrow-rtl.png create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/images/arrow.png create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/images/grippie.png create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/includes/common.inc create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/includes/common_config_form.css create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/includes/common_config_form.js create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/includes/theme.inc create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/includes/views.js create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hs_flatlist.info create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hs_flatlist.module create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hs_menu.info create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hs_menu.install create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hs_menu.module create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hs_smallhierarchy.info create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hs_smallhierarchy.module create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hs_taxonomy.info create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hs_taxonomy.install create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hs_taxonomy.module create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hser/README.txt create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hser/hser.info create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/modules/hser/hser.module create mode 100644 sites/all/modules/contrib/fields/hierarchical_select/tests/internals.test create mode 100644 sites/all/modules/contrib/fields/prepopulate/LICENSE.txt create mode 100644 sites/all/modules/contrib/fields/prepopulate/README.txt create mode 100644 sites/all/modules/contrib/fields/prepopulate/prepopulate.info create mode 100644 sites/all/modules/contrib/fields/prepopulate/prepopulate.install create mode 100644 sites/all/modules/contrib/fields/prepopulate/prepopulate.module create mode 100644 sites/all/modules/contrib/localisation/entity_translation_tabs/LICENSE.txt create mode 100644 sites/all/modules/contrib/localisation/entity_translation_tabs/README.txt create mode 100644 sites/all/modules/contrib/localisation/entity_translation_tabs/entity_translation_tabs.info create mode 100644 sites/all/modules/contrib/localisation/entity_translation_tabs/entity_translation_tabs.module create mode 100644 sites/all/modules/contrib/localisation/i18n_access/LICENSE.txt create mode 100644 sites/all/modules/contrib/localisation/i18n_access/entity_translation-2211649-5.patch create mode 100644 sites/all/modules/contrib/localisation/i18n_access/i18n_access.2298475-6.patch create mode 100644 sites/all/modules/contrib/localisation/i18n_access/i18n_access.info create mode 100644 sites/all/modules/contrib/localisation/i18n_access/i18n_access.info.orig create mode 100644 sites/all/modules/contrib/localisation/i18n_access/i18n_access.info.rej create mode 100644 sites/all/modules/contrib/localisation/i18n_access/i18n_access.install create mode 100644 sites/all/modules/contrib/localisation/i18n_access/i18n_access.module create mode 100644 sites/all/modules/contrib/localisation/i18n_access/i18n_access.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/LICENSE.txt create mode 100644 sites/all/modules/contrib/localisation/tmgmt/README.txt create mode 100644 sites/all/modules/contrib/localisation/tmgmt/controller/tmgmt.controller.job.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/controller/tmgmt.controller.job_item.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/controller/tmgmt.controller.remote.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/controller/tmgmt.controller.translator.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/demo/tmgmt_demo.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/demo/tmgmt_demo.install create mode 100644 sites/all/modules/contrib/localisation/tmgmt/demo/tmgmt_demo.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/entity/tmgmt.entity.job.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/entity/tmgmt.entity.job_item.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/entity/tmgmt.entity.message.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/entity/tmgmt.entity.remote.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/entity/tmgmt.entity.translator.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/includes/tmgmt.exception.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/includes/tmgmt.info.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/plugin/tmgmt.plugin.base.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/plugin/tmgmt.plugin.interface.base.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/plugin/tmgmt.plugin.interface.reject.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/plugin/tmgmt.plugin.interface.source.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/plugin/tmgmt.plugin.interface.translator.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/plugin/tmgmt.plugin.source.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/plugin/tmgmt.plugin.translator.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/plugin/tmgmt.ui.interface.source.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/plugin/tmgmt.ui.interface.translator.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/plugin/tmgmt.ui.source.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/plugin/tmgmt.ui.translator.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/css/tmgmt_entity.admin.entity_source_search_form.css create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/tests/tmgmt_entity_test.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/tests/tmgmt_entity_test.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/tmgmt_entity.api.php create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/tmgmt_entity.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/tmgmt_entity.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/tmgmt_entity.pathauto.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/tmgmt_entity.plugin.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/tmgmt_entity.source.none.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/tmgmt_entity.source.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/tmgmt_entity.suggestions.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/tmgmt_entity.ui.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/ui/tmgmt_entity_ui.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/ui/tmgmt_entity_ui.list.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/ui/tmgmt_entity_ui.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/ui/tmgmt_entity_ui.pages.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/ui/tmgmt_entity_ui.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/entity/ui/tmgmt_entity_ui.ui.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/field/tmgmt_field.api.php create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/field/tmgmt_field.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/field/tmgmt_field.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/i18n_string/tmgmt_i18n_string.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/i18n_string/tmgmt_i18n_string.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/i18n_string/tmgmt_i18n_string.plugin.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/i18n_string/tmgmt_i18n_string.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/i18n_string/tmgmt_i18n_string.ui.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/locale/tests/test.xx.po create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/locale/tmgmt_locale.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/locale/tmgmt_locale.install create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/locale/tmgmt_locale.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/locale/tmgmt_locale.plugin.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/locale/tmgmt_locale.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/locale/tmgmt_locale.ui.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/locale/tmgmt_locale.ui.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/tmgmt_node.api.php create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/tmgmt_node.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/tmgmt_node.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/tmgmt_node.plugin.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/tmgmt_node.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/tmgmt_node.ui.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/ui/tmgmt_node_ui.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/ui/tmgmt_node_ui.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/ui/tmgmt_node_ui.overview.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/ui/tmgmt_node_ui.pages.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/ui/tmgmt_node_ui.rules_defaults.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/ui/tmgmt_node_ui.source_overview.css create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/ui/tmgmt_node_ui.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/views/handlers/tmgmt_node_handler_field_jobs.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/views/handlers/tmgmt_node_handler_field_translation_language_status.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/views/handlers/tmgmt_node_handler_field_translation_language_status_single.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/views/handlers/tmgmt_node_handler_filter_missing_translation.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/views/handlers/tmgmt_node_handler_filter_node_translatable_types.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/views/tmgmt_node.views.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/sources/node/views/tmgmt_node_source_overview.view.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/testing_html/sample.html create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt.base.entity.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt.base.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt.crud.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt.helper.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt.plugin.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt.upgrade.alpha1.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt_alpha1_dump.sql.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt_test.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt_test.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt_test.plugin.html_source.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt_test.plugin.source.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt_test.plugin.translator.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tests/tmgmt_test.ui.translator.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tmgmt.api.php create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tmgmt.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tmgmt.install create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tmgmt.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/tmgmt.rules.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/templates/tmgmt_file_html_template.tpl.php create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/tmgmt_file.api.php create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/tmgmt_file.drush.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/tmgmt_file.format.html.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/tmgmt_file.format.interface.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/tmgmt_file.format.xliff.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/tmgmt_file.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/tmgmt_file.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/tmgmt_file.plugin.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/tmgmt_file.recursive_iterator.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/tmgmt_file.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/tmgmt_file.ui.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/file/xliff-core-1.2-strict.xsd create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/README.txt create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/controller/tmgmt_local.controller.task.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/controller/tmgmt_local.controller.task_item.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/controller/tmgmt_local.ui_controller.task.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/controller/tmgmt_local.ui_controller.task_item.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/entity/tmgmt_local.entity.task.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/entity/tmgmt_local.entity.task_item.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/includes/tmgmt_local.info.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/includes/tmgmt_local.pages.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/includes/tmgmt_local.plugin.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/includes/tmgmt_local.plugin.ui.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/includes/tmgmt_local.theme.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/skills/tmgmt_language_combination.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/skills/tmgmt_language_combination.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/tmgmt_local.api.php create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/tmgmt_local.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/tmgmt_local.install create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/tmgmt_local.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/tmgmt_local.rules.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/tmgmt_local.rules_defaults.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/tmgmt_local.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_item_operations.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_job_item_count.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_loop_count.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_operations.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_progress.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_field_wordcount.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/views/handlers/tmgmt_local_task_handler_filter_eligible.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/views/tmgmt_local.views.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/views/tmgmt_local_manage_translate_task.view.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/views/tmgmt_local_task_items.view.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/translators/tmgmt_local/views/tmgmt_local_task_overview.view.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/css/tmgmt_ui.admin.css create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/css/tmgmt_ui.admin.seven.css create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/includes/tmgmt_ui.cart.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/includes/tmgmt_ui.controller.job.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/includes/tmgmt_ui.controller.job_item.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/includes/tmgmt_ui.controller.translator.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/includes/tmgmt_ui.pages.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/includes/tmgmt_ui.theme.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/tmgmt_ui.api.php create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/tmgmt_ui.info create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/tmgmt_ui.module create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/tmgmt_ui.rules.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/tmgmt_ui.rules_defaults.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/tmgmt_ui.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/tmgmt_ui_job.test create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/views/tmgmt_ui_job_item_messages.view.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/views/tmgmt_ui_job_items.view.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/views/tmgmt_ui_job_messages.view.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/ui/views/tmgmt_ui_job_overview.view.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/views/handlers/tmgmt_handler_field_tmgmt_entity_label.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/views/handlers/tmgmt_handler_field_tmgmt_job_item_count.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/views/handlers/tmgmt_handler_field_tmgmt_job_item_operations.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/views/handlers/tmgmt_handler_field_tmgmt_job_item_type.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/views/handlers/tmgmt_handler_field_tmgmt_job_operations.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/views/handlers/tmgmt_handler_field_tmgmt_message_message.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/views/handlers/tmgmt_handler_field_tmgmt_progress.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/views/handlers/tmgmt_handler_field_tmgmt_translator.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/views/handlers/tmgmt_handler_field_tmgmt_wordcount.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/views/plugins/tmgmt_views_job_access.inc create mode 100644 sites/all/modules/contrib/localisation/tmgmt/views/tmgmt.views.inc create mode 100644 sites/all/modules/contrib/taxonomy/tac_lite/LICENSE.txt create mode 100644 sites/all/modules/contrib/taxonomy/tac_lite/README.txt create mode 100644 sites/all/modules/contrib/taxonomy/tac_lite/tac_lite.info create mode 100644 sites/all/modules/contrib/taxonomy/tac_lite/tac_lite.install create mode 100644 sites/all/modules/contrib/taxonomy/tac_lite/tac_lite.module create mode 100644 sites/all/modules/contrib/taxonomy/tac_lite/tac_lite_create.info create mode 100644 sites/all/modules/contrib/taxonomy/tac_lite/tac_lite_create.module create mode 100644 sites/all/modules/examples/LICENSE.txt create mode 100644 sites/all/modules/examples/README.txt create mode 100644 sites/all/modules/examples/action_example/action_example.info create mode 100644 sites/all/modules/examples/action_example/action_example.module create mode 100644 sites/all/modules/examples/action_example/action_example.test create mode 100644 sites/all/modules/examples/ajax_example/ajax_example.css create mode 100644 sites/all/modules/examples/ajax_example/ajax_example.info create mode 100644 sites/all/modules/examples/ajax_example/ajax_example.install create mode 100644 sites/all/modules/examples/ajax_example/ajax_example.js create mode 100644 sites/all/modules/examples/ajax_example/ajax_example.module create mode 100644 sites/all/modules/examples/ajax_example/ajax_example.test create mode 100644 sites/all/modules/examples/ajax_example/ajax_example_advanced.inc create mode 100644 sites/all/modules/examples/ajax_example/ajax_example_autocomplete.inc create mode 100644 sites/all/modules/examples/ajax_example/ajax_example_graceful_degradation.inc create mode 100644 sites/all/modules/examples/ajax_example/ajax_example_misc.inc create mode 100644 sites/all/modules/examples/ajax_example/ajax_example_node_form_alter.inc create mode 100644 sites/all/modules/examples/ajax_example/ajax_example_progressbar.inc create mode 100644 sites/all/modules/examples/batch_example/batch_example.info create mode 100644 sites/all/modules/examples/batch_example/batch_example.install create mode 100644 sites/all/modules/examples/batch_example/batch_example.module create mode 100644 sites/all/modules/examples/batch_example/batch_example.test create mode 100644 sites/all/modules/examples/block_example/block_example.info create mode 100644 sites/all/modules/examples/block_example/block_example.install create mode 100644 sites/all/modules/examples/block_example/block_example.module create mode 100644 sites/all/modules/examples/block_example/block_example.test create mode 100644 sites/all/modules/examples/cache_example/cache_example.info create mode 100644 sites/all/modules/examples/cache_example/cache_example.module create mode 100644 sites/all/modules/examples/cache_example/cache_example.test create mode 100644 sites/all/modules/examples/contextual_links_example/contextual-links-example-object.tpl.php create mode 100644 sites/all/modules/examples/contextual_links_example/contextual_links_example.info create mode 100644 sites/all/modules/examples/contextual_links_example/contextual_links_example.module create mode 100644 sites/all/modules/examples/contextual_links_example/contextual_links_example.test create mode 100644 sites/all/modules/examples/cron_example/cron_example.info create mode 100644 sites/all/modules/examples/cron_example/cron_example.module create mode 100644 sites/all/modules/examples/cron_example/cron_example.test create mode 100644 sites/all/modules/examples/dbtng_example/dbtng_example.info create mode 100644 sites/all/modules/examples/dbtng_example/dbtng_example.install create mode 100644 sites/all/modules/examples/dbtng_example/dbtng_example.module create mode 100644 sites/all/modules/examples/dbtng_example/dbtng_example.test create mode 100644 sites/all/modules/examples/email_example/email_example.info create mode 100644 sites/all/modules/examples/email_example/email_example.module create mode 100644 sites/all/modules/examples/email_example/email_example.test create mode 100644 sites/all/modules/examples/entity_example/entity_example.info create mode 100644 sites/all/modules/examples/entity_example/entity_example.install create mode 100644 sites/all/modules/examples/entity_example/entity_example.module create mode 100644 sites/all/modules/examples/entity_example/entity_example.test create mode 100644 sites/all/modules/examples/examples.index.php create mode 100644 sites/all/modules/examples/examples.info create mode 100644 sites/all/modules/examples/examples.module create mode 100644 sites/all/modules/examples/field_example/field_example.css create mode 100644 sites/all/modules/examples/field_example/field_example.info create mode 100644 sites/all/modules/examples/field_example/field_example.install create mode 100644 sites/all/modules/examples/field_example/field_example.js create mode 100644 sites/all/modules/examples/field_example/field_example.module create mode 100644 sites/all/modules/examples/field_example/field_example.test create mode 100644 sites/all/modules/examples/field_permission_example/field_permission_example.css create mode 100644 sites/all/modules/examples/field_permission_example/field_permission_example.info create mode 100644 sites/all/modules/examples/field_permission_example/field_permission_example.install create mode 100644 sites/all/modules/examples/field_permission_example/field_permission_example.module create mode 100644 sites/all/modules/examples/field_permission_example/tests/field_permission_example.test create mode 100644 sites/all/modules/examples/file_example/file_example.info create mode 100644 sites/all/modules/examples/file_example/file_example.module create mode 100644 sites/all/modules/examples/file_example/file_example.test create mode 100644 sites/all/modules/examples/file_example/file_example_session_streams.inc create mode 100644 sites/all/modules/examples/filter_example/filter_example.info create mode 100644 sites/all/modules/examples/filter_example/filter_example.module create mode 100644 sites/all/modules/examples/filter_example/filter_example.test create mode 100644 sites/all/modules/examples/form_example/form_example.info create mode 100644 sites/all/modules/examples/form_example/form_example.module create mode 100644 sites/all/modules/examples/form_example/form_example.test create mode 100644 sites/all/modules/examples/form_example/form_example_elements.inc create mode 100644 sites/all/modules/examples/form_example/form_example_states.inc create mode 100644 sites/all/modules/examples/form_example/form_example_tutorial.inc create mode 100644 sites/all/modules/examples/form_example/form_example_wizard.inc create mode 100644 sites/all/modules/examples/image_example/image_example.info create mode 100644 sites/all/modules/examples/image_example/image_example.install create mode 100644 sites/all/modules/examples/image_example/image_example.module create mode 100644 sites/all/modules/examples/image_example/image_example.pages.inc create mode 100644 sites/all/modules/examples/image_example/image_example.test create mode 100644 sites/all/modules/examples/js_example/accordion.tpl.php create mode 100644 sites/all/modules/examples/js_example/css/jsweights.css create mode 100644 sites/all/modules/examples/js_example/js/black.js create mode 100644 sites/all/modules/examples/js_example/js/blue.js create mode 100644 sites/all/modules/examples/js_example/js/brown.js create mode 100644 sites/all/modules/examples/js_example/js/green.js create mode 100644 sites/all/modules/examples/js_example/js/purple.js create mode 100644 sites/all/modules/examples/js_example/js/red.js create mode 100644 sites/all/modules/examples/js_example/js_example.info create mode 100644 sites/all/modules/examples/js_example/js_example.module create mode 100644 sites/all/modules/examples/js_example/js_example.test create mode 100644 sites/all/modules/examples/menu_example/menu_example.info create mode 100644 sites/all/modules/examples/menu_example/menu_example.module create mode 100644 sites/all/modules/examples/menu_example/menu_example.test create mode 100644 sites/all/modules/examples/node_access_example/node_access_example.info create mode 100644 sites/all/modules/examples/node_access_example/node_access_example.install create mode 100644 sites/all/modules/examples/node_access_example/node_access_example.module create mode 100644 sites/all/modules/examples/node_access_example/node_access_example.test create mode 100644 sites/all/modules/examples/node_example/node_example.info create mode 100644 sites/all/modules/examples/node_example/node_example.module create mode 100644 sites/all/modules/examples/node_example/node_example.test create mode 100644 sites/all/modules/examples/nodeapi_example/nodeapi_example.info create mode 100644 sites/all/modules/examples/nodeapi_example/nodeapi_example.install create mode 100644 sites/all/modules/examples/nodeapi_example/nodeapi_example.module create mode 100644 sites/all/modules/examples/nodeapi_example/nodeapi_example.test create mode 100644 sites/all/modules/examples/page_example/page_example.info create mode 100644 sites/all/modules/examples/page_example/page_example.module create mode 100644 sites/all/modules/examples/page_example/page_example.test create mode 100644 sites/all/modules/examples/pager_example/pager_example.info create mode 100644 sites/all/modules/examples/pager_example/pager_example.module create mode 100644 sites/all/modules/examples/pager_example/pager_example.test create mode 100644 sites/all/modules/examples/queue_example/queue_example.css create mode 100644 sites/all/modules/examples/queue_example/queue_example.info create mode 100644 sites/all/modules/examples/queue_example/queue_example.module create mode 100644 sites/all/modules/examples/queue_example/queue_example.test create mode 100644 sites/all/modules/examples/rdf_example/rdf_example.info create mode 100644 sites/all/modules/examples/rdf_example/rdf_example.install create mode 100644 sites/all/modules/examples/rdf_example/rdf_example.module create mode 100644 sites/all/modules/examples/rdf_example/rdf_example.test create mode 100644 sites/all/modules/examples/render_example/render_example.css create mode 100644 sites/all/modules/examples/render_example/render_example.info create mode 100644 sites/all/modules/examples/render_example/render_example.install create mode 100644 sites/all/modules/examples/render_example/render_example.module create mode 100644 sites/all/modules/examples/render_example/render_example.test create mode 100644 sites/all/modules/examples/simpletest_example/simpletest_example.info create mode 100644 sites/all/modules/examples/simpletest_example/simpletest_example.install create mode 100644 sites/all/modules/examples/simpletest_example/simpletest_example.module create mode 100644 sites/all/modules/examples/simpletest_example/simpletest_example.test create mode 100644 sites/all/modules/examples/simpletest_example/tests/simpletest_example_test.info create mode 100644 sites/all/modules/examples/simpletest_example/tests/simpletest_example_test.module create mode 100644 sites/all/modules/examples/tabledrag_example/tabledrag_example.info create mode 100644 sites/all/modules/examples/tabledrag_example/tabledrag_example.install create mode 100644 sites/all/modules/examples/tabledrag_example/tabledrag_example.module create mode 100644 sites/all/modules/examples/tabledrag_example/tabledrag_example.test create mode 100644 sites/all/modules/examples/tabledrag_example/tabledrag_example_parent_form.inc create mode 100644 sites/all/modules/examples/tabledrag_example/tabledrag_example_simple_form.inc create mode 100644 sites/all/modules/examples/tablesort_example/tablesort_example.info create mode 100644 sites/all/modules/examples/tablesort_example/tablesort_example.install create mode 100644 sites/all/modules/examples/tablesort_example/tablesort_example.module create mode 100644 sites/all/modules/examples/tablesort_example/tablesort_example.test create mode 100644 sites/all/modules/examples/theming_example/theming-example-text-form.tpl.php create mode 100644 sites/all/modules/examples/theming_example/theming_example.css create mode 100644 sites/all/modules/examples/theming_example/theming_example.info create mode 100644 sites/all/modules/examples/theming_example/theming_example.module create mode 100644 sites/all/modules/examples/theming_example/theming_example.test create mode 100644 sites/all/modules/examples/token_example/token_example.info create mode 100644 sites/all/modules/examples/token_example/token_example.module create mode 100644 sites/all/modules/examples/token_example/token_example.test create mode 100644 sites/all/modules/examples/token_example/token_example.tokens.inc create mode 100644 sites/all/modules/examples/trigger_example/trigger_example.info create mode 100644 sites/all/modules/examples/trigger_example/trigger_example.module create mode 100644 sites/all/modules/examples/trigger_example/trigger_example.test create mode 100644 sites/all/modules/examples/vertical_tabs_example/vertical_tabs_example.info create mode 100644 sites/all/modules/examples/vertical_tabs_example/vertical_tabs_example.js create mode 100644 sites/all/modules/examples/vertical_tabs_example/vertical_tabs_example.module create mode 100644 sites/all/modules/examples/vertical_tabs_example/vertical_tabs_example.test create mode 100644 sites/all/modules/examples/xmlrpc_example/xmlrpc_example.info create mode 100644 sites/all/modules/examples/xmlrpc_example/xmlrpc_example.module create mode 100644 sites/all/modules/examples/xmlrpc_example/xmlrpc_example.test diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 5ebbf211..799b8003 100755 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,4 +1,12 @@ +Drupal 7.58, 2018-03-28 +----------------------- +- Fixed security issues (multiple vulnerabilities). See SA-CORE-2018-002. + +Drupal 7.57, 2018-02-21 +----------------------- +- Fixed security issues (multiple vulnerabilities). See SA-CORE-2018-001. + Drupal 7.56, 2017-06-21 ----------------------- - Fixed security issues (access bypass). See SA-CORE-2017-003. diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index c06055ed..06acf935 100755 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -8,7 +8,7 @@ /** * The current system version. */ -define('VERSION', '7.56'); +define('VERSION', '7.58'); /** * Core API compatibility. @@ -2632,6 +2632,10 @@ function _drupal_bootstrap_configuration() { timer_start('page'); // Initialize the configuration, including variables from settings.php. drupal_settings_initialize(); + + // Sanitize unsafe keys from the request. + require_once DRUPAL_ROOT . '/includes/request-sanitizer.inc'; + DrupalRequestSanitizer::sanitize(); } /** diff --git a/includes/common.inc b/includes/common.inc index a32930a5..d7dc47f2 100755 --- a/includes/common.inc +++ b/includes/common.inc @@ -2236,8 +2236,11 @@ function url($path = NULL, array $options = array()) { 'prefix' => '' ); + // Determine whether this is an external link, but ensure that the current + // path is always treated as internal by default (to prevent external link + // injection vulnerabilities). if (!isset($options['external'])) { - $options['external'] = url_is_external($path); + $options['external'] = $path === $_GET['q'] ? FALSE : url_is_external($path); } // Preserve the original path before altering or aliasing. diff --git a/includes/request-sanitizer.inc b/includes/request-sanitizer.inc new file mode 100644 index 00000000..1daa6b53 --- /dev/null +++ b/includes/request-sanitizer.inc @@ -0,0 +1,82 @@ + implode(', ', $get_sanitized_keys))), E_USER_NOTICE); + } + + // Process request body parameters. + $post_sanitized_keys = array(); + $_POST = self::stripDangerousValues($_POST, $whitelist, $post_sanitized_keys); + if ($log_sanitized_keys && $post_sanitized_keys) { + _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from request body parameters (POST): @keys', array('@keys' => implode(', ', $post_sanitized_keys))), E_USER_NOTICE); + } + + // Process cookie parameters. + $cookie_sanitized_keys = array(); + $_COOKIE = self::stripDangerousValues($_COOKIE, $whitelist, $cookie_sanitized_keys); + if ($log_sanitized_keys && $cookie_sanitized_keys) { + _drupal_trigger_error_with_delayed_logging(format_string('Potentially unsafe keys removed from cookie parameters (COOKIE): @keys', array('@keys' => implode(', ', $cookie_sanitized_keys))), E_USER_NOTICE); + } + + $request_sanitized_keys = array(); + $_REQUEST = self::stripDangerousValues($_REQUEST, $whitelist, $request_sanitized_keys); + + self::$sanitized = TRUE; + } + } + + /** + * Strips dangerous keys from the provided input. + * + * @param mixed $input + * The input to sanitize. + * @param string[] $whitelist + * An array of keys to whitelist as safe. + * @param string[] $sanitized_keys + * An array of keys that have been removed. + * + * @return mixed + * The sanitized input. + */ + protected static function stripDangerousValues($input, array $whitelist, array &$sanitized_keys) { + if (is_array($input)) { + foreach ($input as $key => $value) { + if ($key !== '' && $key[0] === '#' && !in_array($key, $whitelist, TRUE)) { + unset($input[$key]); + $sanitized_keys[] = $key; + } + else { + $input[$key] = self::stripDangerousValues($input[$key], $whitelist, $sanitized_keys); + } + } + } + return $input; + } + +} diff --git a/misc/drupal.js b/misc/drupal.js index d86ea1fa..19fbc712 100755 --- a/misc/drupal.js +++ b/misc/drupal.js @@ -27,6 +27,42 @@ $.fn.init = function (selector, context, rootjQuery) { }; $.fn.init.prototype = jquery_init.prototype; +/** + * Pre-filter Ajax requests to guard against XSS attacks. + * + * See https://github.com/jquery/jquery/issues/2432 + */ +if ($.ajaxPrefilter) { + // For newer versions of jQuery, use an Ajax prefilter to prevent + // auto-executing script tags from untrusted domains. This is similar to the + // fix that is built in to jQuery 3.0 and higher. + $.ajaxPrefilter(function (s) { + if (s.crossDomain) { + s.contents.script = false; + } + }); +} +else if ($.httpData) { + // For the version of jQuery that ships with Drupal core, override + // jQuery.httpData to prevent auto-detecting "script" data types from + // untrusted domains. + var jquery_httpData = $.httpData; + $.httpData = function (xhr, type, s) { + // @todo Consider backporting code from newer jQuery versions to check for + // a cross-domain request here, rather than using Drupal.urlIsLocal() to + // block scripts from all URLs that are not on the same site. + if (!type && !Drupal.urlIsLocal(s.url)) { + var content_type = xhr.getResponseHeader('content-type') || ''; + if (content_type.indexOf('javascript') >= 0) { + // Default to a safe data type. + type = 'text'; + } + } + return jquery_httpData.call(this, xhr, type, s); + }; + $.httpData.prototype = jquery_httpData.prototype; +} + /** * Attach all registered behaviors to a page element. * @@ -137,7 +173,7 @@ Drupal.detachBehaviors = function (context, settings, trigger) { */ Drupal.checkPlain = function (str) { var character, regex, - replace = { '&': '&', '"': '"', '<': '<', '>': '>' }; + replace = { '&': '&', "'": ''', '"': '"', '<': '<', '>': '>' }; str = String(str); for (character in replace) { if (replace.hasOwnProperty(character)) { diff --git a/modules/aggregator/aggregator.info b/modules/aggregator/aggregator.info index 09caa008..e8645d1f 100755 --- a/modules/aggregator/aggregator.info +++ b/modules/aggregator/aggregator.info @@ -7,8 +7,8 @@ files[] = aggregator.test configure = admin/config/services/aggregator/settings stylesheets[all][] = aggregator.css -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/aggregator/tests/aggregator_test.info b/modules/aggregator/tests/aggregator_test.info index 575be566..e6d5a0a7 100755 --- a/modules/aggregator/tests/aggregator_test.info +++ b/modules/aggregator/tests/aggregator_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/block/block.info b/modules/block/block.info index a0ff83f0..934bfdea 100755 --- a/modules/block/block.info +++ b/modules/block/block.info @@ -6,8 +6,8 @@ core = 7.x files[] = block.test configure = admin/structure/block -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/block/tests/block_test.info b/modules/block/tests/block_test.info index beff5962..d7e22203 100755 --- a/modules/block/tests/block_test.info +++ b/modules/block/tests/block_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/block/tests/themes/block_test_theme/block_test_theme.info b/modules/block/tests/themes/block_test_theme/block_test_theme.info index 6e7b9c96..31b43824 100755 --- a/modules/block/tests/themes/block_test_theme/block_test_theme.info +++ b/modules/block/tests/themes/block_test_theme/block_test_theme.info @@ -13,8 +13,8 @@ regions[footer] = Footer regions[highlighted] = Highlighted regions[help] = Help -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/blog/blog.info b/modules/blog/blog.info index d241eca2..84ad946d 100755 --- a/modules/blog/blog.info +++ b/modules/blog/blog.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = blog.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/book/book.info b/modules/book/book.info index 164043df..53e454bf 100755 --- a/modules/book/book.info +++ b/modules/book/book.info @@ -7,8 +7,8 @@ files[] = book.test configure = admin/content/book/settings stylesheets[all][] = book.css -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/color/color.info b/modules/color/color.info index 086f8cf1..0d17ce11 100755 --- a/modules/color/color.info +++ b/modules/color/color.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = color.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/comment/comment.info b/modules/comment/comment.info index 3dbf6e60..5d5abbf4 100755 --- a/modules/comment/comment.info +++ b/modules/comment/comment.info @@ -9,8 +9,8 @@ files[] = comment.test configure = admin/content/comment stylesheets[all][] = comment.css -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/contact/contact.info b/modules/contact/contact.info index 466e9417..b365daf9 100755 --- a/modules/contact/contact.info +++ b/modules/contact/contact.info @@ -6,8 +6,8 @@ core = 7.x files[] = contact.test configure = admin/structure/contact -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/contextual/contextual.info b/modules/contextual/contextual.info index fd73edd5..ba47a4cb 100755 --- a/modules/contextual/contextual.info +++ b/modules/contextual/contextual.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = contextual.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/dashboard/dashboard.info b/modules/dashboard/dashboard.info index bc9c98a9..d6e98660 100755 --- a/modules/dashboard/dashboard.info +++ b/modules/dashboard/dashboard.info @@ -7,8 +7,8 @@ files[] = dashboard.test dependencies[] = block configure = admin/dashboard/customize -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/dblog/dblog.info b/modules/dblog/dblog.info index dc39510e..cb85f811 100755 --- a/modules/dblog/dblog.info +++ b/modules/dblog/dblog.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = dblog.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/field/field.info b/modules/field/field.info index 241c2971..e05108ec 100755 --- a/modules/field/field.info +++ b/modules/field/field.info @@ -11,8 +11,8 @@ dependencies[] = field_sql_storage required = TRUE stylesheets[all][] = theme/field.css -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/field/modules/field_sql_storage/field_sql_storage.info b/modules/field/modules/field_sql_storage/field_sql_storage.info index 48881e26..05434613 100755 --- a/modules/field/modules/field_sql_storage/field_sql_storage.info +++ b/modules/field/modules/field_sql_storage/field_sql_storage.info @@ -7,8 +7,8 @@ dependencies[] = field files[] = field_sql_storage.test required = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/field/modules/list/list.info b/modules/field/modules/list/list.info index e7427bcc..bef7e4a2 100755 --- a/modules/field/modules/list/list.info +++ b/modules/field/modules/list/list.info @@ -7,8 +7,8 @@ dependencies[] = field dependencies[] = options files[] = tests/list.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/field/modules/list/tests/list_test.info b/modules/field/modules/list/tests/list_test.info index ce3ca4c9..2d4d6cce 100755 --- a/modules/field/modules/list/tests/list_test.info +++ b/modules/field/modules/list/tests/list_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/field/modules/number/number.info b/modules/field/modules/number/number.info index 39a33641..c65d94ae 100755 --- a/modules/field/modules/number/number.info +++ b/modules/field/modules/number/number.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = number.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/field/modules/options/options.info b/modules/field/modules/options/options.info index bb212833..632ca24f 100755 --- a/modules/field/modules/options/options.info +++ b/modules/field/modules/options/options.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = options.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/field/modules/text/text.info b/modules/field/modules/text/text.info index 86dcdc77..fe93a35a 100755 --- a/modules/field/modules/text/text.info +++ b/modules/field/modules/text/text.info @@ -7,8 +7,8 @@ dependencies[] = field files[] = text.test required = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/field/tests/field_test.info b/modules/field/tests/field_test.info index 54ea80f3..ce3c7251 100755 --- a/modules/field/tests/field_test.info +++ b/modules/field/tests/field_test.info @@ -6,8 +6,8 @@ files[] = field_test.entity.inc version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/field_ui/field_ui.info b/modules/field_ui/field_ui.info index c46a4bf7..a415ae99 100755 --- a/modules/field_ui/field_ui.info +++ b/modules/field_ui/field_ui.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = field_ui.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/file/file.info b/modules/file/file.info index 722e3a7f..7269b4ad 100755 --- a/modules/file/file.info +++ b/modules/file/file.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = field files[] = tests/file.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/file/file.module b/modules/file/file.module index fb5e9b94..1e98f11b 100755 --- a/modules/file/file.module +++ b/modules/file/file.module @@ -140,7 +140,7 @@ function file_file_download($uri, $field_type = 'file') { } // Find out which (if any) fields of this type contain the file. - $references = file_get_file_references($file, NULL, FIELD_LOAD_CURRENT, $field_type); + $references = file_get_file_references($file, NULL, FIELD_LOAD_CURRENT, $field_type, FALSE); // Stop processing if there are no references in order to avoid returning // headers for files controlled by other modules. Make an exception for @@ -1067,11 +1067,18 @@ function file_icon_map($file) { * @param $field_type * (optional) The name of a field type. If given, limits the reference check * to fields of the given type. + * @param $check_access + * (optional) A boolean that specifies whether the permissions of the current + * user should be checked when retrieving references. If FALSE, all + * references to the file are returned. If TRUE, only references from + * entities that the current user has access to are returned. Defaults to + * TRUE for backwards compatibility reasons, but FALSE is recommended for + * most situations. * * @return * An integer value. */ -function file_get_file_references($file, $field = NULL, $age = FIELD_LOAD_REVISION, $field_type = 'file') { +function file_get_file_references($file, $field = NULL, $age = FIELD_LOAD_REVISION, $field_type = 'file', $check_access = TRUE) { $references = drupal_static(__FUNCTION__, array()); $fields = isset($field) ? array($field['field_name'] => $field) : field_info_fields(); @@ -1082,6 +1089,11 @@ function file_get_file_references($file, $field = NULL, $age = FIELD_LOAD_REVISI $query ->fieldCondition($file_field, 'fid', $file->fid) ->age($age); + if (!$check_access) { + // Neutralize the 'entity_field_access' query tag added by + // field_sql_storage_field_storage_query(). + $query->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT'); + } $references[$field_name] = $query->execute(); } } diff --git a/modules/file/tests/file.test b/modules/file/tests/file.test index b3a1424d..f764a903 100755 --- a/modules/file/tests/file.test +++ b/modules/file/tests/file.test @@ -1626,6 +1626,79 @@ class FilePrivateTestCase extends FileFieldTestCase { $this->drupalGet($file_url); $this->assertResponse(403, 'Confirmed that another anonymous user cannot access the permanent file when it is referenced by an unpublished node.'); } + + /** + * Tests file access for private nodes when file download access is granted. + */ + function testPrivateFileDownloadAccessGranted() { + // Tell file_module_test to attempt to grant access to all private files, + // and ensure that it is doing so correctly. + $test_file = $this->getTestFile('text'); + $uri = file_unmanaged_move($test_file->uri, 'private://'); + $file_url = file_create_url($uri); + $this->drupalGet($file_url); + $this->assertResponse(403, 'Access is not granted to an arbitrary private file by default.'); + variable_set('file_module_test_grant_download_access', TRUE); + $this->drupalGet($file_url); + $this->assertResponse(200, 'Access is granted to an arbitrary private file after a module grants access to all private files in hook_file_download().'); + + // Create a public node with a file attached. + $type_name = 'page'; + $field_name = strtolower($this->randomName()); + $this->createFileField($field_name, $type_name, array('uri_scheme' => 'private')); + $test_file = $this->getTestFile('text'); + $nid = $this->uploadNodeFile($test_file, $field_name, $type_name, TRUE, array('private' => FALSE)); + $node = node_load($nid, NULL, TRUE); + $file_url = file_create_url($node->{$field_name}[LANGUAGE_NONE][0]['uri']); + + // Unpublish the node and ensure that only administrators (not anonymous + // users) can access the node and download the file; the expectation is + // that the File module's hook_file_download() implementation will deny + // access and thereby override the file_module_test module's access grant. + $node->status = NODE_NOT_PUBLISHED; + node_save($node); + $this->drupalLogin($this->admin_user); + $this->drupalGet("node/$nid"); + $this->assertResponse(200, 'Administrator can access the unpublished node.'); + $this->drupalGet($file_url); + $this->assertResponse(200, 'Administrator can download the file attached to the unpublished node.'); + $this->drupalLogOut(); + $this->drupalGet("node/$nid"); + $this->assertResponse(403, 'Anonymous user cannot access the unpublished node.'); + $this->drupalGet($file_url); + $this->assertResponse(403, 'Anonymous user cannot download the file attached to the unpublished node.'); + + // Re-publish the node and ensure that the node and file can be accessed by + // everyone. + $node->status = NODE_PUBLISHED; + node_save($node); + $this->drupalLogin($this->admin_user); + $this->drupalGet("node/$nid"); + $this->assertResponse(200, 'Administrator can access the published node.'); + $this->drupalGet($file_url); + $this->assertResponse(200, 'Administrator can download the file attached to the published node.'); + $this->drupalLogOut(); + $this->drupalGet("node/$nid"); + $this->assertResponse(200, 'Anonymous user can access the published node.'); + $this->drupalGet($file_url); + $this->assertResponse(200, 'Anonymous user can download the file attached to the published node.'); + + // Make the node private via the node access system and test that only + // administrators (not anonymous users) can access the node and download + // the file. + $node->private = TRUE; + node_save($node); + $this->drupalLogin($this->admin_user); + $this->drupalGet("node/$nid"); + $this->assertResponse(200, 'Administrator can access the private node.'); + $this->drupalGet($file_url); + $this->assertResponse(200, 'Administrator can download the file attached to the private node.'); + $this->drupalLogOut(); + $this->drupalGet("node/$nid"); + $this->assertResponse(403, 'Anonymous user cannot access the private node.'); + $this->drupalGet($file_url); + $this->assertResponse(403, 'Anonymous user cannot download the file attached to the private node.'); + } } /** diff --git a/modules/file/tests/file_module_test.info b/modules/file/tests/file_module_test.info index 47f4abce..958bf660 100755 --- a/modules/file/tests/file_module_test.info +++ b/modules/file/tests/file_module_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/file/tests/file_module_test.module b/modules/file/tests/file_module_test.module index f66c749d..1acfacab 100755 --- a/modules/file/tests/file_module_test.module +++ b/modules/file/tests/file_module_test.module @@ -67,3 +67,18 @@ function file_module_test_form_submit($form, &$form_state) { } drupal_set_message(t('The file id is %fid.', array('%fid' => $fid))); } + +/** + * Implements hook_file_download(). + */ +function file_module_test_file_download($uri) { + if (variable_get('file_module_test_grant_download_access')) { + // Mimic what file_get_content_headers() would do if we had a full $file + // object to pass to it. + return array( + 'Content-Type' => mime_header_encode(file_get_mimetype($uri)), + 'Content-Length' => filesize($uri), + 'Cache-Control' => 'private', + ); + } +} diff --git a/modules/filter/filter.info b/modules/filter/filter.info index 71af77d4..4a46c85c 100755 --- a/modules/filter/filter.info +++ b/modules/filter/filter.info @@ -7,8 +7,8 @@ files[] = filter.test required = TRUE configure = admin/config/content/formats -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/forum/forum.info b/modules/forum/forum.info index 031ffd25..d5b1c769 100755 --- a/modules/forum/forum.info +++ b/modules/forum/forum.info @@ -9,8 +9,8 @@ files[] = forum.test configure = admin/structure/forum stylesheets[all][] = forum.css -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/help/help.info b/modules/help/help.info index 2e825571..2c851ea9 100755 --- a/modules/help/help.info +++ b/modules/help/help.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = help.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/image/image.info b/modules/image/image.info index 57988719..dd1200c6 100755 --- a/modules/image/image.info +++ b/modules/image/image.info @@ -7,8 +7,8 @@ dependencies[] = file files[] = image.test configure = admin/config/media/image-styles -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/image/tests/image_module_test.info b/modules/image/tests/image_module_test.info index 6139caaf..c6b3a6ab 100755 --- a/modules/image/tests/image_module_test.info +++ b/modules/image/tests/image_module_test.info @@ -6,8 +6,8 @@ core = 7.x files[] = image_module_test.module hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/locale/locale.info b/modules/locale/locale.info index 0d3585b3..674d1f56 100755 --- a/modules/locale/locale.info +++ b/modules/locale/locale.info @@ -6,8 +6,8 @@ core = 7.x files[] = locale.test configure = admin/config/regional/language -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/locale/tests/locale_test.info b/modules/locale/tests/locale_test.info index b957dfc5..49da5e51 100755 --- a/modules/locale/tests/locale_test.info +++ b/modules/locale/tests/locale_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/menu/menu.info b/modules/menu/menu.info index 72ed9bbe..9b7ef57b 100755 --- a/modules/menu/menu.info +++ b/modules/menu/menu.info @@ -6,8 +6,8 @@ core = 7.x files[] = menu.test configure = admin/structure/menu -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/node/node.info b/modules/node/node.info index 98b85321..11ae2cd3 100755 --- a/modules/node/node.info +++ b/modules/node/node.info @@ -9,8 +9,8 @@ required = TRUE configure = admin/structure/types stylesheets[all][] = node.css -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/node/tests/node_access_test.info b/modules/node/tests/node_access_test.info index 66125d4d..00792901 100755 --- a/modules/node/tests/node_access_test.info +++ b/modules/node/tests/node_access_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/node/tests/node_test.info b/modules/node/tests/node_test.info index 17820690..f56e2e51 100755 --- a/modules/node/tests/node_test.info +++ b/modules/node/tests/node_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/node/tests/node_test_exception.info b/modules/node/tests/node_test_exception.info index 3588e373..a4c11859 100755 --- a/modules/node/tests/node_test_exception.info +++ b/modules/node/tests/node_test_exception.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/openid/openid.info b/modules/openid/openid.info index 67a1cd04..69d26632 100755 --- a/modules/openid/openid.info +++ b/modules/openid/openid.info @@ -5,8 +5,8 @@ package = Core core = 7.x files[] = openid.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/openid/tests/openid_test.info b/modules/openid/tests/openid_test.info index 6caed214..7186198b 100755 --- a/modules/openid/tests/openid_test.info +++ b/modules/openid/tests/openid_test.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = openid hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/overlay/overlay.info b/modules/overlay/overlay.info index fb576ce8..1bf7e9ef 100755 --- a/modules/overlay/overlay.info +++ b/modules/overlay/overlay.info @@ -4,8 +4,8 @@ package = Core version = VERSION core = 7.x -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/path/path.info b/modules/path/path.info index f9b50f74..b5b0eb9b 100755 --- a/modules/path/path.info +++ b/modules/path/path.info @@ -6,8 +6,8 @@ core = 7.x files[] = path.test configure = admin/config/search/path -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/php/php.info b/modules/php/php.info index eb82a497..236f9310 100755 --- a/modules/php/php.info +++ b/modules/php/php.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = php.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/poll/poll.info b/modules/poll/poll.info index f981ce86..eeed31d5 100755 --- a/modules/poll/poll.info +++ b/modules/poll/poll.info @@ -6,8 +6,8 @@ core = 7.x files[] = poll.test stylesheets[all][] = poll.css -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/profile/profile.info b/modules/profile/profile.info index d6ee35a7..1480c618 100755 --- a/modules/profile/profile.info +++ b/modules/profile/profile.info @@ -11,8 +11,8 @@ configure = admin/config/people/profile ; See user_system_info_alter(). hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/rdf/rdf.info b/modules/rdf/rdf.info index c7271c2c..18e62970 100755 --- a/modules/rdf/rdf.info +++ b/modules/rdf/rdf.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x files[] = rdf.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/rdf/tests/rdf_test.info b/modules/rdf/tests/rdf_test.info index 90aacd10..a302a7b5 100755 --- a/modules/rdf/tests/rdf_test.info +++ b/modules/rdf/tests/rdf_test.info @@ -6,8 +6,8 @@ core = 7.x hidden = TRUE dependencies[] = blog -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/search/search.info b/modules/search/search.info index c66fcfdd..248f476c 100755 --- a/modules/search/search.info +++ b/modules/search/search.info @@ -8,8 +8,8 @@ files[] = search.test configure = admin/config/search/settings stylesheets[all][] = search.css -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/search/tests/search_embedded_form.info b/modules/search/tests/search_embedded_form.info index acf8f528..7e1b7367 100755 --- a/modules/search/tests/search_embedded_form.info +++ b/modules/search/tests/search_embedded_form.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/search/tests/search_extra_type.info b/modules/search/tests/search_extra_type.info index ac996e56..534edade 100755 --- a/modules/search/tests/search_extra_type.info +++ b/modules/search/tests/search_extra_type.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/search/tests/search_node_tags.info b/modules/search/tests/search_node_tags.info index 2df10960..16438984 100644 --- a/modules/search/tests/search_node_tags.info +++ b/modules/search/tests/search_node_tags.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/shortcut/shortcut.info b/modules/shortcut/shortcut.info index f4956cf0..c490374e 100755 --- a/modules/shortcut/shortcut.info +++ b/modules/shortcut/shortcut.info @@ -6,8 +6,8 @@ core = 7.x files[] = shortcut.test configure = admin/config/user-interface/shortcut -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/simpletest.info b/modules/simpletest/simpletest.info index 7d1747a0..26b3485a 100755 --- a/modules/simpletest/simpletest.info +++ b/modules/simpletest/simpletest.info @@ -57,8 +57,8 @@ files[] = tests/upgrade/update.trigger.test files[] = tests/upgrade/update.field.test files[] = tests/upgrade/update.user.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/actions_loop_test.info b/modules/simpletest/tests/actions_loop_test.info index c3c44697..2edf253d 100755 --- a/modules/simpletest/tests/actions_loop_test.info +++ b/modules/simpletest/tests/actions_loop_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/ajax_forms_test.info b/modules/simpletest/tests/ajax_forms_test.info index 3d8d13f9..9736647e 100755 --- a/modules/simpletest/tests/ajax_forms_test.info +++ b/modules/simpletest/tests/ajax_forms_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/ajax_test.info b/modules/simpletest/tests/ajax_test.info index a2dd2b10..fe2f90b0 100755 --- a/modules/simpletest/tests/ajax_test.info +++ b/modules/simpletest/tests/ajax_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/batch_test.info b/modules/simpletest/tests/batch_test.info index 42a87d30..a53e2159 100755 --- a/modules/simpletest/tests/batch_test.info +++ b/modules/simpletest/tests/batch_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/boot_test_1.info b/modules/simpletest/tests/boot_test_1.info index ed218005..873825da 100644 --- a/modules/simpletest/tests/boot_test_1.info +++ b/modules/simpletest/tests/boot_test_1.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/boot_test_2.info b/modules/simpletest/tests/boot_test_2.info index f2164d52..e8529ba9 100644 --- a/modules/simpletest/tests/boot_test_2.info +++ b/modules/simpletest/tests/boot_test_2.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/common.test b/modules/simpletest/tests/common.test index 83161fad..0490dd53 100755 --- a/modules/simpletest/tests/common.test +++ b/modules/simpletest/tests/common.test @@ -76,7 +76,7 @@ class DrupalAlterTestCase extends DrupalWebTestCase { class CommonURLUnitTest extends DrupalWebTestCase { public static function getInfo() { return array( - 'name' => 'URL generation tests', + 'name' => 'URL generation unit tests', 'description' => 'Confirm that url(), drupal_get_query_parameters(), drupal_http_build_query(), and l() work correctly with various input.', 'group' => 'System', ); @@ -372,6 +372,38 @@ class CommonURLUnitTest extends DrupalWebTestCase { } } +/** + * Web tests for URL generation functions. + */ +class CommonURLWebTest extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'URL generation web tests', + 'description' => 'Confirm that URL-generating functions work correctly on specific site paths.', + 'group' => 'System', + ); + } + + function setUp() { + parent::setUp('common_test'); + } + + /** + * Tests the url() function on internal paths which mimic external URLs. + */ + function testInternalPathMimicsExternal() { + // Ensure that calling url(current_path()) on "/http://example.com" (an + // internal path which mimics an external URL) always links to the internal + // path, not the external URL. This helps protect against external URL link + // injection vulnerabilities. + variable_set('common_test_link_to_current_path', TRUE); + $this->drupalGet('/http://example.com'); + $this->clickLink('link which should point to the current path'); + $this->assertUrl('/http://example.com'); + $this->assertText('link which should point to the current path'); + } +} + /** * Tests url_is_external(). */ diff --git a/modules/simpletest/tests/common_test.info b/modules/simpletest/tests/common_test.info index 6087d7b8..8c56f80c 100755 --- a/modules/simpletest/tests/common_test.info +++ b/modules/simpletest/tests/common_test.info @@ -7,8 +7,8 @@ stylesheets[all][] = common_test.css stylesheets[print][] = common_test.print.css hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/common_test.module b/modules/simpletest/tests/common_test.module index 2eb8cd5d..d092c924 100755 --- a/modules/simpletest/tests/common_test.module +++ b/modules/simpletest/tests/common_test.module @@ -99,6 +99,9 @@ function common_test_init() { if (variable_get('common_test_redirect_current_path', FALSE)) { drupal_goto(current_path()); } + if (variable_get('common_test_link_to_current_path', FALSE)) { + drupal_set_message(l('link which should point to the current path', current_path())); + } } /** diff --git a/modules/simpletest/tests/common_test_cron_helper.info b/modules/simpletest/tests/common_test_cron_helper.info index 6e6d36ce..bf8a7290 100755 --- a/modules/simpletest/tests/common_test_cron_helper.info +++ b/modules/simpletest/tests/common_test_cron_helper.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/database_test.info b/modules/simpletest/tests/database_test.info index 46a5da8a..3ff31eda 100755 --- a/modules/simpletest/tests/database_test.info +++ b/modules/simpletest/tests/database_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info index 1895e95f..b9715351 100644 --- a/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info +++ b/modules/simpletest/tests/drupal_autoload_test/drupal_autoload_test.info @@ -7,8 +7,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info index 1fce8044..f918fdc2 100755 --- a/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info +++ b/modules/simpletest/tests/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info index 8acc0cd4..9edaf9f6 100755 --- a/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info +++ b/modules/simpletest/tests/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/entity_cache_test.info b/modules/simpletest/tests/entity_cache_test.info index b9f1c703..212ce833 100755 --- a/modules/simpletest/tests/entity_cache_test.info +++ b/modules/simpletest/tests/entity_cache_test.info @@ -6,8 +6,8 @@ core = 7.x dependencies[] = entity_cache_test_dependency hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/entity_cache_test_dependency.info b/modules/simpletest/tests/entity_cache_test_dependency.info index 4f5f45d8..58049876 100755 --- a/modules/simpletest/tests/entity_cache_test_dependency.info +++ b/modules/simpletest/tests/entity_cache_test_dependency.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/entity_crud_hook_test.info b/modules/simpletest/tests/entity_crud_hook_test.info index 320b3c91..9f5f3ead 100755 --- a/modules/simpletest/tests/entity_crud_hook_test.info +++ b/modules/simpletest/tests/entity_crud_hook_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/entity_query_access_test.info b/modules/simpletest/tests/entity_query_access_test.info index 94da93ed..328e5d9c 100755 --- a/modules/simpletest/tests/entity_query_access_test.info +++ b/modules/simpletest/tests/entity_query_access_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/error_test.info b/modules/simpletest/tests/error_test.info index 3f06c833..bf6e044b 100755 --- a/modules/simpletest/tests/error_test.info +++ b/modules/simpletest/tests/error_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/file_test.info b/modules/simpletest/tests/file_test.info index 57cabc21..3ceb3ebe 100755 --- a/modules/simpletest/tests/file_test.info +++ b/modules/simpletest/tests/file_test.info @@ -6,8 +6,8 @@ core = 7.x files[] = file_test.module hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/filter_test.info b/modules/simpletest/tests/filter_test.info index b4853f87..96c6c4b5 100755 --- a/modules/simpletest/tests/filter_test.info +++ b/modules/simpletest/tests/filter_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/form_test.info b/modules/simpletest/tests/form_test.info index f3c910ec..7706be2b 100755 --- a/modules/simpletest/tests/form_test.info +++ b/modules/simpletest/tests/form_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/image_test.info b/modules/simpletest/tests/image_test.info index 0c86fb8d..82d2a3ba 100755 --- a/modules/simpletest/tests/image_test.info +++ b/modules/simpletest/tests/image_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/menu_test.info b/modules/simpletest/tests/menu_test.info index e5301a78..26d70dc6 100755 --- a/modules/simpletest/tests/menu_test.info +++ b/modules/simpletest/tests/menu_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/module_test.info b/modules/simpletest/tests/module_test.info index 5aab1282..1ebdd859 100755 --- a/modules/simpletest/tests/module_test.info +++ b/modules/simpletest/tests/module_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/path_test.info b/modules/simpletest/tests/path_test.info index 61ba3525..43ecd96d 100755 --- a/modules/simpletest/tests/path_test.info +++ b/modules/simpletest/tests/path_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/psr_0_test/psr_0_test.info b/modules/simpletest/tests/psr_0_test/psr_0_test.info index 3658d3ce..ca69f5c2 100755 --- a/modules/simpletest/tests/psr_0_test/psr_0_test.info +++ b/modules/simpletest/tests/psr_0_test/psr_0_test.info @@ -5,8 +5,8 @@ core = 7.x hidden = TRUE package = Testing -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/psr_4_test/psr_4_test.info b/modules/simpletest/tests/psr_4_test/psr_4_test.info index 6a66365f..75e5b0cd 100644 --- a/modules/simpletest/tests/psr_4_test/psr_4_test.info +++ b/modules/simpletest/tests/psr_4_test/psr_4_test.info @@ -5,8 +5,8 @@ core = 7.x hidden = TRUE package = Testing -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/requirements1_test.info b/modules/simpletest/tests/requirements1_test.info index 1fba9cac..c5b3a606 100755 --- a/modules/simpletest/tests/requirements1_test.info +++ b/modules/simpletest/tests/requirements1_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/requirements2_test.info b/modules/simpletest/tests/requirements2_test.info index 1a992fd0..b12197e8 100755 --- a/modules/simpletest/tests/requirements2_test.info +++ b/modules/simpletest/tests/requirements2_test.info @@ -7,8 +7,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/session_test.info b/modules/simpletest/tests/session_test.info index a89aa897..4987deae 100755 --- a/modules/simpletest/tests/session_test.info +++ b/modules/simpletest/tests/session_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/system_dependencies_test.info b/modules/simpletest/tests/system_dependencies_test.info index a714682d..4b03f292 100755 --- a/modules/simpletest/tests/system_dependencies_test.info +++ b/modules/simpletest/tests/system_dependencies_test.info @@ -6,8 +6,8 @@ core = 7.x hidden = TRUE dependencies[] = _missing_dependency -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info b/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info index a7cd470c..cb2749e3 100755 --- a/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info +++ b/modules/simpletest/tests/system_incompatible_core_version_dependencies_test.info @@ -6,8 +6,8 @@ core = 7.x hidden = TRUE dependencies[] = system_incompatible_core_version_test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/system_incompatible_core_version_test.info b/modules/simpletest/tests/system_incompatible_core_version_test.info index e01a7ac7..338521f6 100755 --- a/modules/simpletest/tests/system_incompatible_core_version_test.info +++ b/modules/simpletest/tests/system_incompatible_core_version_test.info @@ -5,8 +5,8 @@ version = VERSION core = 5.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info index 2b23dd50..edf6dd12 100755 --- a/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info +++ b/modules/simpletest/tests/system_incompatible_module_version_dependencies_test.info @@ -7,8 +7,8 @@ hidden = TRUE ; system_incompatible_module_version_test declares version 1.0 dependencies[] = system_incompatible_module_version_test (>2.0) -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/system_incompatible_module_version_test.info b/modules/simpletest/tests/system_incompatible_module_version_test.info index 89ba10b3..51f3efc5 100755 --- a/modules/simpletest/tests/system_incompatible_module_version_test.info +++ b/modules/simpletest/tests/system_incompatible_module_version_test.info @@ -5,8 +5,8 @@ version = 1.0 core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/system_project_namespace_test.info b/modules/simpletest/tests/system_project_namespace_test.info index 63f1cabc..1507739b 100644 --- a/modules/simpletest/tests/system_project_namespace_test.info +++ b/modules/simpletest/tests/system_project_namespace_test.info @@ -6,8 +6,8 @@ core = 7.x hidden = TRUE dependencies[] = drupal:filter -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/system_test.info b/modules/simpletest/tests/system_test.info index adbea26a..4b6175b5 100755 --- a/modules/simpletest/tests/system_test.info +++ b/modules/simpletest/tests/system_test.info @@ -6,8 +6,8 @@ core = 7.x files[] = system_test.module hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/taxonomy_test.info b/modules/simpletest/tests/taxonomy_test.info index 1ca57175..3ccf2299 100755 --- a/modules/simpletest/tests/taxonomy_test.info +++ b/modules/simpletest/tests/taxonomy_test.info @@ -6,8 +6,8 @@ core = 7.x hidden = TRUE dependencies[] = taxonomy -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/theme_test.info b/modules/simpletest/tests/theme_test.info index 58a10a73..f5cb1eaf 100755 --- a/modules/simpletest/tests/theme_test.info +++ b/modules/simpletest/tests/theme_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info b/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info index 508de704..ed247b7e 100755 --- a/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info +++ b/modules/simpletest/tests/themes/test_basetheme/test_basetheme.info @@ -6,8 +6,8 @@ hidden = TRUE settings[basetheme_only] = base theme value settings[subtheme_override] = base theme value -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info b/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info index 0e378310..dfd8bd8a 100755 --- a/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info +++ b/modules/simpletest/tests/themes/test_subtheme/test_subtheme.info @@ -6,8 +6,8 @@ hidden = TRUE settings[subtheme_override] = subtheme value -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/themes/test_theme/test_theme.info b/modules/simpletest/tests/themes/test_theme/test_theme.info index edb2b8b8..c132c910 100755 --- a/modules/simpletest/tests/themes/test_theme/test_theme.info +++ b/modules/simpletest/tests/themes/test_theme/test_theme.info @@ -17,8 +17,8 @@ stylesheets[all][] = system.base.css settings[theme_test_setting] = default value -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info b/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info index af1fd912..a4f5649e 100644 --- a/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info +++ b/modules/simpletest/tests/themes/test_theme_nyan_cat/test_theme_nyan_cat.info @@ -4,8 +4,8 @@ core = 7.x hidden = TRUE engine = nyan_cat -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/update_script_test.info b/modules/simpletest/tests/update_script_test.info index 321b2c3d..f3bfc50b 100755 --- a/modules/simpletest/tests/update_script_test.info +++ b/modules/simpletest/tests/update_script_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/update_test_1.info b/modules/simpletest/tests/update_test_1.info index b8b69569..a7431d5d 100755 --- a/modules/simpletest/tests/update_test_1.info +++ b/modules/simpletest/tests/update_test_1.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/update_test_2.info b/modules/simpletest/tests/update_test_2.info index b8b69569..a7431d5d 100755 --- a/modules/simpletest/tests/update_test_2.info +++ b/modules/simpletest/tests/update_test_2.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/update_test_3.info b/modules/simpletest/tests/update_test_3.info index b8b69569..a7431d5d 100755 --- a/modules/simpletest/tests/update_test_3.info +++ b/modules/simpletest/tests/update_test_3.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/url_alter_test.info b/modules/simpletest/tests/url_alter_test.info index 5f969dff..23676af5 100755 --- a/modules/simpletest/tests/url_alter_test.info +++ b/modules/simpletest/tests/url_alter_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/simpletest/tests/xmlrpc_test.info b/modules/simpletest/tests/xmlrpc_test.info index c7d3ca44..ab787cc3 100755 --- a/modules/simpletest/tests/xmlrpc_test.info +++ b/modules/simpletest/tests/xmlrpc_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/statistics/statistics.info b/modules/statistics/statistics.info index 9147bc48..26c1794e 100755 --- a/modules/statistics/statistics.info +++ b/modules/statistics/statistics.info @@ -6,8 +6,8 @@ core = 7.x files[] = statistics.test configure = admin/config/system/statistics -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/syslog/syslog.info b/modules/syslog/syslog.info index 6d00c449..3f8b6ca4 100755 --- a/modules/syslog/syslog.info +++ b/modules/syslog/syslog.info @@ -6,8 +6,8 @@ core = 7.x files[] = syslog.test configure = admin/config/development/logging -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/system/system.info b/modules/system/system.info index f765e17d..da08a99e 100755 --- a/modules/system/system.info +++ b/modules/system/system.info @@ -12,8 +12,8 @@ files[] = system.test required = TRUE configure = admin/config/system -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/system/tests/cron_queue_test.info b/modules/system/tests/cron_queue_test.info index 8d694daf..86d9e089 100644 --- a/modules/system/tests/cron_queue_test.info +++ b/modules/system/tests/cron_queue_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/system/tests/system_cron_test.info b/modules/system/tests/system_cron_test.info index a4986beb..662c7c45 100644 --- a/modules/system/tests/system_cron_test.info +++ b/modules/system/tests/system_cron_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/taxonomy/taxonomy.info b/modules/taxonomy/taxonomy.info index dc9aa777..1f2fec80 100755 --- a/modules/taxonomy/taxonomy.info +++ b/modules/taxonomy/taxonomy.info @@ -8,8 +8,8 @@ files[] = taxonomy.module files[] = taxonomy.test configure = admin/structure/taxonomy -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/toolbar/toolbar.info b/modules/toolbar/toolbar.info index 31278e86..f0257612 100755 --- a/modules/toolbar/toolbar.info +++ b/modules/toolbar/toolbar.info @@ -4,8 +4,8 @@ core = 7.x package = Core version = VERSION -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/tracker/tracker.info b/modules/tracker/tracker.info index fd5ec6fa..d7cb61b6 100755 --- a/modules/tracker/tracker.info +++ b/modules/tracker/tracker.info @@ -6,8 +6,8 @@ version = VERSION core = 7.x files[] = tracker.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/translation/tests/translation_test.info b/modules/translation/tests/translation_test.info index 4dcb554c..9b597a0e 100755 --- a/modules/translation/tests/translation_test.info +++ b/modules/translation/tests/translation_test.info @@ -5,8 +5,8 @@ package = Testing version = VERSION hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/translation/translation.info b/modules/translation/translation.info index c75554a6..3e6513f0 100755 --- a/modules/translation/translation.info +++ b/modules/translation/translation.info @@ -6,8 +6,8 @@ version = VERSION core = 7.x files[] = translation.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/trigger/tests/trigger_test.info b/modules/trigger/tests/trigger_test.info index 599bf6ff..13e0698d 100755 --- a/modules/trigger/tests/trigger_test.info +++ b/modules/trigger/tests/trigger_test.info @@ -4,8 +4,8 @@ package = Testing core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/trigger/trigger.info b/modules/trigger/trigger.info index 1b12e9a4..4c21ba8f 100755 --- a/modules/trigger/trigger.info +++ b/modules/trigger/trigger.info @@ -6,8 +6,8 @@ core = 7.x files[] = trigger.test configure = admin/structure/trigger -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/update/tests/aaa_update_test.info b/modules/update/tests/aaa_update_test.info index 746224b1..96ac28aa 100755 --- a/modules/update/tests/aaa_update_test.info +++ b/modules/update/tests/aaa_update_test.info @@ -4,8 +4,8 @@ package = Testing core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/update/tests/bbb_update_test.info b/modules/update/tests/bbb_update_test.info index da5444c5..954fb75b 100755 --- a/modules/update/tests/bbb_update_test.info +++ b/modules/update/tests/bbb_update_test.info @@ -4,8 +4,8 @@ package = Testing core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/update/tests/ccc_update_test.info b/modules/update/tests/ccc_update_test.info index 8e77f3f7..f3b7d043 100755 --- a/modules/update/tests/ccc_update_test.info +++ b/modules/update/tests/ccc_update_test.info @@ -4,8 +4,8 @@ package = Testing core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info b/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info index f1bab4f8..d21dd9ca 100644 --- a/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info +++ b/modules/update/tests/themes/update_test_admintheme/update_test_admintheme.info @@ -3,8 +3,8 @@ description = Test theme which is used as admin theme. core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info b/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info index 19bd9c45..07eb50ff 100755 --- a/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info +++ b/modules/update/tests/themes/update_test_basetheme/update_test_basetheme.info @@ -3,8 +3,8 @@ description = Test theme which acts as a base theme for other test subthemes. core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info b/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info index 2edb6410..26b480c5 100755 --- a/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info +++ b/modules/update/tests/themes/update_test_subtheme/update_test_subtheme.info @@ -4,8 +4,8 @@ core = 7.x base theme = update_test_basetheme hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/update/tests/update_test.info b/modules/update/tests/update_test.info index 9271156c..7b42bc2e 100755 --- a/modules/update/tests/update_test.info +++ b/modules/update/tests/update_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/update/update.info b/modules/update/update.info index 109ed2b8..4d9c3691 100755 --- a/modules/update/update.info +++ b/modules/update/update.info @@ -6,8 +6,8 @@ core = 7.x files[] = update.test configure = admin/reports/updates/settings -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/user/tests/user_form_test.info b/modules/user/tests/user_form_test.info index 52b2068f..17ce34a5 100755 --- a/modules/user/tests/user_form_test.info +++ b/modules/user/tests/user_form_test.info @@ -5,8 +5,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/user/user.info b/modules/user/user.info index 1e318c24..83e2b8e3 100755 --- a/modules/user/user.info +++ b/modules/user/user.info @@ -9,8 +9,8 @@ required = TRUE configure = admin/config/people stylesheets[all][] = user.css -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/modules/user/user.module b/modules/user/user.module index cfcd10ba..12ca2800 100644 --- a/modules/user/user.module +++ b/modules/user/user.module @@ -2359,26 +2359,14 @@ function user_external_login_register($name, $module) { * following properties: * - uid: The user ID number. * - login: The UNIX timestamp of the user's last login. - * @param array $options - * (optional) A keyed array of settings. Supported options are: - * - langcode: A language code to be used when generating locale-sensitive - * urls. If langcode is NULL the users preferred language is used. * * @return * A unique URL that provides a one-time log in for the user, from which * they can change their password. */ -function user_pass_reset_url($account, $options = array()) { +function user_pass_reset_url($account) { $timestamp = REQUEST_TIME; - $url_options = array('absolute' => TRUE); - if (isset($options['langcode'])) { - $languages = language_list(); - $url_options['language'] = $languages[$options['langcode']]; - } - else { - $url_options['language'] = user_preferred_language($account); - } - return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid), $url_options); + return url("user/reset/$account->uid/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid), array('absolute' => TRUE)); } /** @@ -2390,10 +2378,6 @@ function user_pass_reset_url($account, $options = array()) { * - uid: The user ID number. * - pass: The hashed user password string. * - login: The UNIX timestamp of the user's last login. - * @param array $options - * (optional) A keyed array of settings. Supported options are: - * - langcode: A language code to be used when generating locale-sensitive - * urls. If langcode is NULL the users preferred language is used. * * @return * A unique URL that may be used to confirm the cancellation of the user @@ -2402,17 +2386,9 @@ function user_pass_reset_url($account, $options = array()) { * @see user_mail_tokens() * @see user_cancel_confirm() */ -function user_cancel_url($account, $options = array()) { +function user_cancel_url($account) { $timestamp = REQUEST_TIME; - $url_options = array('absolute' => TRUE); - if (isset($options['langcode'])) { - $languages = language_list(); - $url_options['language'] = $languages[$options['langcode']]; - } - else { - $url_options['language'] = user_preferred_language($account); - } - return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid), $url_options); + return url("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid), array('absolute' => TRUE)); } /** @@ -2902,7 +2878,7 @@ Your account on [site:name] has been canceled. if ($replace) { // We do not sanitize the token replacement, since the output of this // replacement is intended for an e-mail message, not a web browser. - return token_replace($text, $variables, array('language' => $language, 'langcode' => $langcode, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE)); + return token_replace($text, $variables, array('language' => $language, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE)); } return $text; @@ -2929,8 +2905,8 @@ Your account on [site:name] has been canceled. */ function user_mail_tokens(&$replacements, $data, $options) { if (isset($data['user'])) { - $replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user'], $options); - $replacements['[user:cancel-url]'] = user_cancel_url($data['user'], $options); + $replacements['[user:one-time-login-url]'] = user_pass_reset_url($data['user']); + $replacements['[user:cancel-url]'] = user_cancel_url($data['user']); } } diff --git a/modules/user/user.test b/modules/user/user.test index f26cf260..0875e0ac 100644 --- a/modules/user/user.test +++ b/modules/user/user.test @@ -2320,26 +2320,6 @@ class UserTokenReplaceTestCase extends DrupalWebTestCase { ); } - public function setUp() { - parent::setUp('locale'); - - $account = $this->drupalCreateUser(array('access administration pages', 'administer languages')); - $this->drupalLogin($account); - - // Add language. - $edit = array('langcode' => 'de'); - $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language')); - - // Enable URL language detection and selection. - $edit = array('language[enabled][locale-url]' => 1); - $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings')); - - // Reset static caching. - drupal_static_reset('language_list'); - drupal_static_reset('locale_url_outbound_alter'); - drupal_static_reset('locale_language_url_rewrite_url'); - } - /** * Creates a user, then tests the tokens generated from it. */ @@ -2390,39 +2370,6 @@ class UserTokenReplaceTestCase extends DrupalWebTestCase { $output = token_replace($input, array('user' => $account), array('language' => $language, 'sanitize' => FALSE)); $this->assertEqual($output, $expected, format_string('Unsanitized user token %token replaced.', array('%token' => $input))); } - - $languages = language_list(); - - // Generate login and cancel link. - $tests = array(); - $tests['[user:one-time-login-url]'] = user_pass_reset_url($account); - $tests['[user:cancel-url]'] = user_cancel_url($account); - - // Generate tokens with interface language. - $link = url('user', array('absolute' => TRUE)); - foreach ($tests as $input => $expected) { - $output = token_replace($input, array('user' => $account), array('langcode' => $language->language, 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE)); - $this->assertTrue(strpos($output, $link) === 0, 'Generated URL is in interface language.'); - } - - // Generate tokens with the user's preferred language. - $edit['language'] = 'de'; - $account = user_save($account, $edit); - $link = url('user', array('language' => $languages[$account->language], 'absolute' => TRUE)); - foreach ($tests as $input => $expected) { - $output = token_replace($input, array('user' => $account), array('callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE)); - $this->assertTrue(strpos($output, $link) === 0, "Generated URL is in the user's preferred language."); - } - - // Generate tokens with one specific language. - $link = url('user', array('language' => $languages['de'], 'absolute' => TRUE)); - foreach ($tests as $input => $expected) { - foreach (array($user1, $user2) as $account) { - $output = token_replace($input, array('user' => $account), array('langcode' => 'de', 'callback' => 'user_mail_tokens', 'sanitize' => FALSE, 'clear' => TRUE)); - $this->assertTrue(strpos($output, $link) === 0, "Generated URL in in the requested language."); - } - } - } } diff --git a/profiles/minimal/minimal.info b/profiles/minimal/minimal.info index 99535ae8..1b363abd 100755 --- a/profiles/minimal/minimal.info +++ b/profiles/minimal/minimal.info @@ -5,8 +5,8 @@ core = 7.x dependencies[] = block dependencies[] = dblog -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/profiles/standard/standard.info b/profiles/standard/standard.info index d687764d..a3fd9e29 100755 --- a/profiles/standard/standard.info +++ b/profiles/standard/standard.info @@ -24,8 +24,8 @@ dependencies[] = field_ui dependencies[] = file dependencies[] = rdf -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info index d7db04ed..7a11e329 100755 --- a/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info +++ b/profiles/testing/modules/drupal_system_listing_compatible_test/drupal_system_listing_compatible_test.info @@ -6,8 +6,8 @@ core = 7.x hidden = TRUE files[] = drupal_system_listing_compatible_test.test -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info index eb63b745..d2bd9479 100755 --- a/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info +++ b/profiles/testing/modules/drupal_system_listing_incompatible_test/drupal_system_listing_incompatible_test.info @@ -8,8 +8,8 @@ version = VERSION core = 6.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/profiles/testing/testing.info b/profiles/testing/testing.info index 81282d98..e9fec6dc 100755 --- a/profiles/testing/testing.info +++ b/profiles/testing/testing.info @@ -4,8 +4,8 @@ version = VERSION core = 7.x hidden = TRUE -; Information added by Drupal.org packaging script on 2017-06-21 -version = "7.56" +; Information added by Drupal.org packaging script on 2018-03-28 +version = "7.58" project = "drupal" -datestamp = "1498069849" +datestamp = "1522264019" diff --git a/sites/all/modules/contrib/admin/adb/LICENSE.txt b/sites/all/modules/contrib/admin/adb/LICENSE.txt new file mode 100644 index 00000000..d159169d --- /dev/null +++ b/sites/all/modules/contrib/admin/adb/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/sites/all/modules/contrib/admin/adb/adb.info b/sites/all/modules/contrib/admin/adb/adb.info new file mode 100644 index 00000000..a7f3a367 --- /dev/null +++ b/sites/all/modules/contrib/admin/adb/adb.info @@ -0,0 +1,12 @@ +name = Access denied backtrace +description = Enable backtrace for Access Denied to get details about why was triggered +package = Development +core = 7.x +configure = admin/config/development/access-denied-backtrace/configure + +; Information added by drupal.org packaging script on 2013-07-14 +version = "7.x-1.6" +core = "7.x" +project = "adb" +datestamp = "1373817378" + diff --git a/sites/all/modules/contrib/admin/adb/adb.install b/sites/all/modules/contrib/admin/adb/adb.install new file mode 100644 index 00000000..179596c4 --- /dev/null +++ b/sites/all/modules/contrib/admin/adb/adb.install @@ -0,0 +1,83 @@ + 'Table that contains logs of all system events.', + 'fields' => array( + 'adbid' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Primary Key: Unique access deneid backtrace event ID.', + ), + 'uid' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'description' => 'The {users}.uid of the user who triggered the event.', + ), + 'location' => array( + 'type' => 'text', + 'not null' => TRUE, + 'description' => 'URL of the origin of the event.', + ), + 'node_access_denied' => array( + 'type' => 'text', + 'not null' => FALSE, + 'size' => 'medium', + 'description' => 'User permissions.', + ), + 'permissions' => array( + 'type' => 'text', + 'not null' => FALSE, + 'size' => 'medium', + 'description' => 'User permissions.', + ), + 'role_permissions' => array( + 'type' => 'text', + 'not null' => FALSE, + 'size' => 'medium', + 'description' => 'role permissions.', + ), + 'backtrace' => array( + 'type' => 'text', + 'not null' => TRUE, + 'size' => 'big', + 'description' => 'Text of backtrace log execution.', + ), + 'timestamp' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'description' => 'Unix timestamp of when event occurred.', + ), + ), +'primary key' => array('adbid'), +'indexes' => array( + 'uid' => array('uid'), + ), +); + +return $schema; +} + +/** + * Add field permissions in table adb. + */ +function adb_update_7150() { + + db_add_field('adb', 'permissions', array('type' => 'text', 'not null' => FALSE, 'size' => 'medium')); + return t('Added permissions column to adb table.'); +} + +/** + * Add fields role_permissiones and node_access_denied in table adb. + */ +function adb_update_7160() { + + db_add_field('adb', 'role_permissions', array('type' => 'text', 'not null' => FALSE, 'size' => 'medium')); + db_add_field('adb', 'node_access_denied', array('type' => 'text', 'not null' => FALSE, 'size' => 'medium')); + return t('Added role_permissions and node_access_denied columns to adb table.'); +} diff --git a/sites/all/modules/contrib/admin/adb/adb.module b/sites/all/modules/contrib/admin/adb/adb.module new file mode 100644 index 00000000..9598c289 --- /dev/null +++ b/sites/all/modules/contrib/admin/adb/adb.module @@ -0,0 +1,430 @@ + "Last access denied errors backtrace", + 'description' => "View 'access denied' errors backtrace (403s).", + 'page callback' => 'adb_last', + 'access arguments' => array('access site reports'), + ); + + $items['admin/reports/event/backtrace/%'] = array( + 'title' => 'Details', + 'page callback' => 'adb_event', + 'page arguments' => array(4), + 'access arguments' => array('access site reports'), + ); + + $items['admin/config/development/access-denied-backtrace/configure'] = array( + 'title' => 'Access denied backtrace settings', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('adb_settings'), + 'access arguments' => array('administer access denied backtrace'), + ); + + return $items; +} + +/** + * Implements hook_permission(). + */ +function adb_permission() { + + return array( + 'administer access denied backtrace' => array( + 'title' => t('administer access denied backtrace'), + 'description' => t('Change which roles are enabled to record access denied backtrace using the admin interface.'), + ), + ); + +} // fontyourface_perm + +/** + * Generate a adb settings form. + * + * @ingroup forms + * @see filter_admin_format_form_validate() + * @see filter_admin_format_form_submit() + */ +function adb_settings($form, &$form_state) { + + // Add user role access selection. + $form['adb_roles'] = array( + '#type' => 'checkboxes', + '#title' => t('Roles'), + '#options' => array_map('check_plain', user_roles()), + '#default_value' => variable_get('adb_roles',array()), + '#description' => t('Configure what roles will be able to record access denied backtrace'), + ); + + return system_settings_form($form); +} + +/** + * Menu callback; displays details about access denied backtrace log message. + */ +function adb_event($id) { + $severity = watchdog_severity_levels(); + $result = db_query('SELECT adb.*, u.name, u.uid FROM {adb} adb INNER JOIN {users} u ON adb.uid = u.uid WHERE adb.adbid = :id', array(':id' => $id))->fetchObject(); + + if ($dblog = $result) { + $rows = array( + array( + array('data' => t('Date'), 'header' => TRUE), + format_date($dblog->timestamp, 'long'), + ), + array( + array('data' => t('User'), 'header' => TRUE), + theme('username', array('account' => $dblog)), + ), + array( + array('data' => t('Location'), 'header' => TRUE), + l($dblog->location, $dblog->location), + ), + array( + array('data' => t('User permissions'), 'header' => TRUE), + $dblog->permissions, + ), + array( + array('data' => t('User role permissions'), 'header' => TRUE), + $dblog->role_permissions, + ), + array( + array('data' => t('Node access denied'), 'header' => TRUE), + $dblog->node_access_denied, + ), + array( + array('data' => t('Backtrace'), 'header' => TRUE), + theme('adb_message', array('event' => $dblog)), + ), + ); + $build['dblog_table'] = array( + '#theme' => 'table', + '#rows' => $rows, + '#attributes' => array('class' => array('dblog-event')), + ); + return $build; + } + else { + return ''; + } +} +/** + * Implements hook_theme(). + */ +function adb_theme() { + return array( + 'adb_message' => array( + 'variables' => array('event' => NULL), + ), + ); +} + +/** + * Returns HTML for a log message. + * + * @param $variables + * An associative array containing: + * - event: An object with at least the message and variables properties. + * - link: (optional) Format message as link, event->wid is required. + * + * @ingroup themeable + */ +function theme_adb_message($variables) { + $event = $variables['event']; + $link = (isset($variables['link']))?$variables['link']:FALSE; + + $output = $event->backtrace; + // Truncate message to 56 chars. + + if($link) { + $output = truncate_utf8(filter_xss($output, array()), 56, TRUE, TRUE); + $output = l($output, 'admin/reports/event/backtrace/' . $event->adbid, array('html' => TRUE)); + } + + return $output; +} + +/** + * Menu callback; generic function to display a page of the last access denied + * backtrace. + * + * Messages are not truncated because events from this page have no detail view. + * + */ +function adb_last() { + $rows = array(); + + $build['dblog_clear_log_form'] = drupal_get_form('adb_clear_log_form'); + + $header = array( + array('data' => t('Date'), 'field' => 'adb.adbid', 'sort' => 'desc'), + t('Backtrace'), + array('data' => t('User'), 'field' => 'u.name'), + ); + + $query = db_select('adb', 'adb')->extend('PagerDefault')->extend('TableSort'); + $query->leftJoin('users', 'u', 'adb.uid = u.uid'); + $query + ->fields('adb', array('adbid', 'uid', 'timestamp', 'backtrace')) + ->addField('u', 'name'); + + $result = $query + ->limit(50) + ->orderByHeader($header) + ->execute(); + + foreach ($result as $dblog) { + $rows[] = array('data' => + array( + // Cells + format_date($dblog->timestamp, 'short'), + theme('adb_message', array('event' => $dblog, 'link' => TRUE)), + theme('username', array('account' => $dblog)), + ), + // Attributes for tr + 'class' => array(drupal_html_class('adb')), + ); + } + + $build['dblog_table'] = array( + '#theme' => 'table', + '#header' => $header, + '#rows' => $rows, + '#attributes' => array('id' => 'admin-dblog'), + '#empty' => t('No access denied bractrace log available.'), + ); + $build['dblog_pager'] = array('#theme' => 'pager'); + + return $build; +} + +/** + * Invokes a hook in all enabled modules that implement it. + * + * @param $hook + * The name of the hook to invoke. + * @param ... + * Arguments to pass to the hook. + * + * @return + * An array of return values of the hook implementations. If modules return + * arrays from their implementations, those are merged into one array. + */ +function adb_validate_module_access($node, $op, $account) { + $args = array($node, $op, $account); + + $hook = 'node_access'; + $return = array(); + foreach (module_implements($hook) as $module) { + $function = $module . '_' . $hook; + if (function_exists($function)) { + $result = call_user_func_array($function, $args); + if (isset($result) && is_array($result)) { + foreach ($result as $subaccess) { + if ($subaccess == NODE_ACCESS_DENY) { + $return[] = $module; + break; + } + } + $return = array_merge_recursive($return, $result); + } elseif (isset($result) && $result == NODE_ACCESS_DENY) { + $return[] = $module; + } + } + } + + return t('Modules denying') . " " . implode(',', $return); +} + +/** + * Implements hook_watchdog(). + * + * If an 'access denied' error is logged and user role is enabled for debug, the + * execution trace is stored to try to fix what is wrong. + */ +function adb_watchdog($log_entry) { + $account = user_load($log_entry['uid']); + + $adb_roles = array_filter(variable_get('adb_roles',array())); + $valid_role = array_intersect_key($adb_roles,$log_entry['user']->roles); + + $account_rights = ''; + $rights = drupal_static('node_access', array()); + + $permissions_denied = ''; + if (isset($rights[$log_entry['uid']])) { + $account_rights = $rights[$log_entry['uid']]; + + foreach ($account_rights as $node => $rights) { + foreach ($rights as $action => $access) { + if (!$access) { + $permissions_denied .= $action . ' ' . $node . ". "; + $permissions_denied .= adb_validate_module_access($node, $action, $log_entry['user']) . ".
"; + } + } + } + } + else { + // Common message for annonymous users. + $permissions_denied = t('There are not explicit access denied for this user'); + } + + $user_access = drupal_static('user_access', array()); + $role_permissions = user_role_permissions($account->roles); + + //Validate if entry is access denied and current user belog to enabled role to + //record backtrace + if (!empty($valid_role) && $log_entry['type'] == 'access denied' ) { + + $backtrace = _ddebug_backtrace(TRUE); + // Pop the stack up to the drupal_access_denied() call. + for ($i = 0; $i < 5; ++$i) { + array_shift($backtrace); + } + + $user_role_permissions = (isset($role_permissions[$log_entry['uid']])?$role_permissions[$log_entry['uid']]:array()); + $user_access_permissions = (isset($user_access[$log_entry['uid']]))?$user_access[$log_entry['uid']]:array(); + + + /* print_r($user_access[$log_entry['uid']]); + print_r($user_role_permissions);*/ + Database::getConnection('default', 'default')->insert('adb') + ->fields(array( + 'uid' => $log_entry['uid'], + 'node_access_denied' => $permissions_denied, + 'permissions' => _dprint_r($user_access_permissions, TRUE), + 'role_permissions' => _dprint_r($user_role_permissions, TRUE), + 'backtrace' => _dprint_r($backtrace, TRUE), + 'location' => $log_entry['request_uri'], + 'timestamp' => $log_entry['timestamp'], + )) + ->execute(); + } +} + +/** + * Return form for dblog clear button. + * + * @ingroup forms + * @see dblog_clear_log_submit() + */ +function adb_clear_log_form($form) { + $form['adb_clear'] = array( + '#type' => 'fieldset', + '#title' => t('Clear access denied backtraces'), + '#description' => t('This will permanently remove the access denied backtraces from the database.'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + $form['adb_clear']['clear'] = array( + '#type' => 'submit', + '#value' => t('Clear access denied backtraces'), + '#submit' => array('adb_clear_log_submit'), + ); + + return $form; +} + +/** + * Submit callback: clear database with log messages. + */ +function adb_clear_log_submit() { + db_delete('adb')->execute(); + drupal_set_message(t('Database access denied backtrace cleared.')); +} + +/** + * Pretty-print a variable to the browser (no krumo). + * Displays only for users with proper permissions. If + * you want a string returned instead of a print, use the 2nd param. + * based in devel function dprint_r + */ +function _dprint_r($input, $return = FALSE, $name = NULL, $function = 'print_r', $check = TRUE) { + if ($name) { + $name .= ' => '; + } + if ($function == 'drupal_var_export') { + include_once DRUPAL_ROOT . '/includes/utility.inc'; + $output = drupal_var_export($input); + } else { + ob_start(); + $function($input); + $output = ob_get_clean(); + } + + if ($check) { + $output = check_plain($output); + } + if (count($input, COUNT_RECURSIVE) > ADB_DEVEL_MIN_TEXTAREA) { + // don't use fapi here because sometimes fapi will not be loaded + $printed_value = "'; + } else { + $printed_value = '
' . $name . $output . '
'; + } + + if ($return) { + return $printed_value; + } else { + print $printed_value; + } +} + +/** + * Print the function call stack. + * copied from devel module but with access for all roles + */ +function _ddebug_backtrace($return = FALSE, $pop = 0) { + + $backtrace = debug_backtrace(); + while ($pop-- > 0) { + array_shift($backtrace); + } + $counter = count($backtrace); + $path = $backtrace[$counter - 1]['file']; + $path = substr($path, 0, strlen($path) - 10); + $paths[$path] = strlen($path) + 1; + $paths[DRUPAL_ROOT] = strlen(DRUPAL_ROOT) + 1; + $nbsp = "\xC2\xA0"; + + // Show message if error_level is ERROR_REPORTING_DISPLAY_SOME or higher. + // (This is Drupal's error_level, which is different from $error_level, + // and we purposely ignore the difference between _SOME and _ALL, + // see #970688!) + if (variable_get('error_level', 1) >= 1) { + while (!empty($backtrace)) { + $call = array(); + if (isset($backtrace[0]['file'])) { + $call['file'] = $backtrace[0]['file']; + foreach ($paths as $path => $len) { + if (strpos($backtrace[0]['file'], $path) === 0) { + $call['file'] = substr($backtrace[0]['file'], $len); + } + } + $call['file'] .= ':' . $backtrace[0]['line']; + } + if (isset($backtrace[1])) { + if (isset($backtrace[1]['class'])) { + $function = $backtrace[1]['class'] . $backtrace[1]['type'] . $backtrace[1]['function'] . '()'; + } else { + $function = $backtrace[1]['function'] . '()'; + } + $call['args'] = $backtrace[1]['args']; + } else { + $function = 'main()'; + $call['args'] = $_GET; + } + $nicetrace[($counter <= 10 ? $nbsp : '') . --$counter . ': ' . $function] = $call; + array_shift($backtrace); + } + if ($return) { + return $nicetrace; + } + kprint_r($nicetrace); + } +} diff --git a/sites/all/modules/contrib/admin/modules_weight/LICENSE.txt b/sites/all/modules/contrib/admin/modules_weight/LICENSE.txt new file mode 100644 index 00000000..d159169d --- /dev/null +++ b/sites/all/modules/contrib/admin/modules_weight/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/sites/all/modules/contrib/admin/modules_weight/README.txt b/sites/all/modules/contrib/admin/modules_weight/README.txt new file mode 100644 index 00000000..b1e3740e --- /dev/null +++ b/sites/all/modules/contrib/admin/modules_weight/README.txt @@ -0,0 +1,9 @@ +This module provide admin interface for users/admins has the access to modules +page to reorder the module weights as they want. + +INSTALLATION : +1. download the module and uncompresse it to sites/all/module and enable it +2. go to admin/config/system/modules-weight and reorder the modules weight :) + +This module just display non-core module, that's because displaying core module in the configuration form will reorder the system core modules execution even if you didn't change them and as some might notice all core modules has 0 weight value by default. +Downloads \ No newline at end of file diff --git a/sites/all/modules/contrib/admin/modules_weight/modules_weight.info b/sites/all/modules/contrib/admin/modules_weight/modules_weight.info new file mode 100644 index 00000000..ee382190 --- /dev/null +++ b/sites/all/modules/contrib/admin/modules_weight/modules_weight.info @@ -0,0 +1,10 @@ +name = Modules Weight +description = This module provide admin interface to order the modules execution order. +core = 7.x +configure = admin/config/system/modules-weight +; Information added by Drupal.org packaging script on 2015-07-31 +version = "7.x-1.4+4-dev" +core = "7.x" +project = "modules_weight" +datestamp = "1438365840" + diff --git a/sites/all/modules/contrib/admin/modules_weight/modules_weight.module b/sites/all/modules/contrib/admin/modules_weight/modules_weight.module new file mode 100644 index 00000000..42af1470 --- /dev/null +++ b/sites/all/modules/contrib/admin/modules_weight/modules_weight.module @@ -0,0 +1,186 @@ + 'Modules Weight', + 'description' => 'Provide admin interface to order the modules execution.', + 'type' => MENU_NORMAL_ITEM, + 'page callback' => 'drupal_get_form', + 'page arguments' => array('modules_weight_admin_config_page_form'), + 'access arguments' => array('administer site configuration'), + ); + $items['admin/config/system/modules-weight/default'] = array( + 'title' => 'Modules Weight', + 'description' => 'jQuery twitter search block config', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => 2, + ); + + $items['admin/config/system/modules-weight/configration'] = array( + 'title' => 'Modules Weight configurations', + 'description' => 'Configure Modules Weight.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('modules_weight_configuration_form'), + 'access arguments' => array('administer system'), + 'type' => MENU_LOCAL_TASK, + 'weight' => 2, + ); + return $items; +} + +function modules_weight_admin_config_page_form($form, &$form_state) { + + $form['modules_weight']['#tree'] = TRUE; + + $result = db_select('system', 's') + ->condition('s.type', 'module') + ->condition('s.status', 1) + ->fields('s', array('weight', 'info', 'name')) + ->orderBy('weight', 'ASC') + ->execute(); + + $show_system_module = variable_get('show_system_modules', 0); + + foreach ($result as $module) { + $info = unserialize($module->info); + if ($info['package'] != 'Core' || $show_system_module) { + $delta = modules_weight_prepare_delta($module->weight); + $form['modules_weight'][$module->name] = array( + 'name' => array( + '#markup' => t($info['name']), + ), + 'description' => array( + '#markup' => t($info['description']), + ), + 'weight' => array( + '#type' => 'weight', + '#title' => t('Weight'), + '#default_value' => $module->weight, + '#delta' => $delta, + '#title-display' => 'invisible', + ), + 'package' => array( + '#markup' => t($info['package']), + ), + 'old_weight_value' => array( + '#type' => 'hidden', + '#value' => $module->weight, + ), + ); + } + } + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save Changes')); + return $form; +} + +/** + * Implements hook_theme(). + */ +function modules_weight_theme() { + return array( + 'modules_weight_admin_config_page_form' => array( + 'render element' => 'form', + ), + ); +} + +function theme_modules_weight_admin_config_page_form($variables) { + $form = $variables['form']; + + $rows = array(); + + foreach (element_children($form['modules_weight']) as $id) { + + $form['modules_weight'][$id]['weight']['#attributes']['class'] = array('module-weight'); + + $rows[] = array( + 'data' => array( + drupal_render($form['modules_weight'][$id]['name']), + drupal_render($form['modules_weight'][$id]['description']), + drupal_render($form['modules_weight'][$id]['weight']), + drupal_render($form['modules_weight'][$id]['package']), + ), + 'class' => array('draggable'), + ); + } + + $header = array(t('Name'), t('Description'), t('Weight'), t('Package')); + + $table_id = 'module-items-table'; + + $output = theme('table', array( + 'header' => $header, + 'rows' => $rows, + 'attributes' => array('id' => $table_id), + )); + + $output .= drupal_render_children($form); + //Remove tabledrage functionlity due to issue related to re-weight all module + // for more info : https://www.drupal.org/node/2205787 + + //drupal_add_tabledrag($table_id, 'order', 'self', 'module-weight'); + + return $output; +} + +/** + * Submit callback for the modules_weight_admin_config_page_form form. + * + * Updates the 'weight' column for each module in our table, taking into + * account that item's new order after the drag and drop actions have been + * performed. + */ +function modules_weight_admin_config_page_form_submit($form, $form_state) { + foreach ($form_state['values']['modules_weight'] as $name => $weight) { + if($weight['weight'] != $weight['old_weight_value']) { + db_query( + "UPDATE {system} SET weight = :weight WHERE name = :name", + array(':weight' => $weight['weight'], ':name' => $name) + ); + } + } +} + +function modules_weight_configuration_form() { + $form = array(); + $form['show_system_modules'] = array( + '#type' => 'checkbox', + '#title' => t('Show system modules'), + '#return_value' => 1, + '#default_value' => variable_get('show_system_modules', 0), + ); + $form['notice'] = array( + '#markup' => '' . t("cautions: This module just display non-core module by, if you check this option it will cause unexpected behavior in system, (USE IT ON YOUR OWN RISCK) that's because displaying core module in the configuration form will reorder the system core modules execution even if you didn't change them and as you might notice all core modules has 0 weight value by default.") . '', + ); + return system_settings_form($form); +} + +/** + * Prepares the delta for the weight field on the administration form. + * If a module has a weight higher then 100 (or lower than 100), it will use that + * value as delta and the '#weight' field will turn into a textfield most likely + * + * @param $weight + * @return int + */ +function modules_weight_prepare_delta($weight) { + $delta = 100; + if ((int) $weight > $delta) { + return (int) $weight; + } + if ((int) $weight < -100) { + return (int) $weight * -1; + } + + return $delta; +} \ No newline at end of file diff --git a/sites/all/modules/contrib/admin/permission_report/LICENSE.txt b/sites/all/modules/contrib/admin/permission_report/LICENSE.txt new file mode 100644 index 00000000..d159169d --- /dev/null +++ b/sites/all/modules/contrib/admin/permission_report/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/sites/all/modules/contrib/admin/permission_report/permission_report.info b/sites/all/modules/contrib/admin/permission_report/permission_report.info new file mode 100644 index 00000000..dfee5c88 --- /dev/null +++ b/sites/all/modules/contrib/admin/permission_report/permission_report.info @@ -0,0 +1,10 @@ +name = Permission report +description = Calculates and displays the a permission report for a user and shows which roles grant what permission for a given user. Also provides ability to list users in a role, and dig down into complicated role and permission problems. +core = 7.x +package = Permissions +; Information added by Drupal.org packaging script on 2017-03-19 +version = "7.x-1.1" +core = "7.x" +project = "permission_report" +datestamp = "1489907285" + diff --git a/sites/all/modules/contrib/admin/permission_report/permission_report.module b/sites/all/modules/contrib/admin/permission_report/permission_report.module new file mode 100644 index 00000000..295aee9c --- /dev/null +++ b/sites/all/modules/contrib/admin/permission_report/permission_report.module @@ -0,0 +1,342 @@ + + * @copyright Nicholas Vahalik 2013 + * @package permission_report + **/ + +/** + * Implements hook_menu(). + */ +function permission_report_menu() { + $items = array(); + + $items['admin/reports/permissions'] = array( + 'title' => 'Permissions (role report)', + 'page callback' => 'permission_report_role_list', + 'access arguments' => array('view permission report'), + 'description' => 'View roles and the users in them.', + ); + + $items['admin/reports/permissions/roles'] = array( + 'title' => 'Roles', + 'page callback' => 'permission_report_role_list', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'access arguments' => array('view permission report'), + 'weight' => -5, + ); + + $items['admin/reports/permissions/perms'] = array( + 'title' => 'Permissions', + 'page callback' => 'permission_report_permission_list', + 'type' => MENU_LOCAL_TASK, + 'access arguments' => array('view permission report'), + ); + + $items['admin/reports/permissions/perms/%'] = array( + 'title' => 'Permissions', + 'type' => MENU_CALLBACK, + 'page arguments' => array(4), + 'page callback' => 'permission_report_user_having_perm', + 'access arguments' => array('view permission report'), + ); + + $items['admin/reports/permissions/roles/%'] = array( + 'title' => 'Roles', + 'type' => MENU_CALLBACK, + 'page callback' => 'permission_report_users_having_role', + 'page arguments' => array(4), + 'access arguments' => array('view permission report'), + ); + + $items['user/%user/permission_report'] = array( + 'title' => 'Permission Report', + 'page callback' => 'permission_report_user_report', + 'page arguments' => array(1), + 'type' => MENU_LOCAL_TASK, + 'access arguments' => array('view permission report'), + 'weight' => 2, + ); + + return $items; +} + +/** + * Implements hook_admin_paths(). + */ +function permission_report_admin_paths() { + $paths = array( + 'user/*/permission_report' => TRUE, + ); + return $paths; +} + +/** + * Implements hook_user_view(). + */ +function permission_report_user_view($account, $view_mode, $langcode) { + if (user_access('view permission report', $account)) { + $account->content['summary']['rsop'] = array( + '#type' => 'user_profile_item', + '#title' => t('Resultant Set of Permissions'), + '#markup' => l(t('View permission report report for !s', array('!s' => $account->name)), "user/$account->uid/permission_report"), + '#attributes' => array('class' => 'permission_report'), + ); + } +} + +/** + * Displays a permission report for a given user. + * + * @param $user User object. + * + * @return string + */ +function permission_report_user_report($user) { + + // Render role/permission overview: + $options = array(); + $row = array(); + $can_admin_access = user_access('administer access control'); + + foreach (module_implements('permission') as $module) { + if ($permissions = module_invoke($module, 'permission')) { + $rows[] = array(array( + 'data' => t('@module module', array('@module' => $module)), + 'class' => 'module', + 'id' => 'module-' . $module, + 'colspan' => 3, + )); + asort($permissions); + foreach ($permissions as $perm => $meta) { + $options = array(); + $display_roles = array(); + + $roles = _permission_report_roles_having_perm($perm, $user); + + if (array_key_exists('description', $meta)) { + $options = array('attributes' => array('alt' => $meta['description'])); + } + + foreach ($roles as $rid => $name) { + $display_roles[] = $can_admin_access ? l($name, "admin/reports/permissions/roles/$rid") : t($name); + } + $rows[] = array( + array('data' => l(strip_tags($meta['title']), "admin/reports/permissions/perms/$perm", $options)), + array('data' => user_access($perm, $user) ? 'Yes' : 'No'), + array('data' => implode(', ', $display_roles)), + ); + } + } + } + + return theme('table', array('header' => array('Permission', 'Access', 'Roles'), 'rows' => $rows, 'attributes' => array('id' => 'permissions'))); +} + +/** + * Return an array of users keyed by IDs that have access to a specific permission. + * + * @param $permission Permission string. + * + * @return array + **/ +function _permission_report_users_having_perm($permission) { + $roles = _permission_report_roles_having_perm($permission); + + if (count($roles) > 0) { + $query = db_select('users', 'u'); + $query->innerJoin('users_roles', 'ur', 'ur.uid = u.uid'); + $query->addField('u', 'uid'); + $query->addField('u', 'name'); + $query->condition('ur.rid', array_keys($roles), 'IN'); + $users = $query->execute()->fetchAllKeyed(); + return $users; + } + + return array(); +} + +/** + * Gets a list of roles that have a permission, optionally limited + * to a specific role. + */ +function _permission_report_roles_having_perm($permission, $user = NULL) { + $query = db_select('role', 'r'); + $query->addField('r', 'rid'); + $query->addField('r', 'name'); + $query->innerJoin('role_permission', 'p', 'r.rid = p.rid'); + $query->condition('p.permission', $permission); + + if ($user) { + $query->innerJoin('users_roles', 'ur', 'r.rid = ur.rid'); + $query->condition('ur.uid', $user->uid); + } + + return $query->execute()->fetchAllKeyed(); +} + +/** + * Generates a report of users having a particular role. + **/ +function permission_report_users_having_role($rid) { + $users_having_roles = $rows = array(); + + $query = db_select('users', 'u'); + $query->addField('u', 'uid'); + $query->addField('u', 'name'); + $query->innerJoin('users_roles', 'ur', 'ur.uid = u.uid'); + $query->condition('ur.rid', $rid); + $query->condition('u.status', 1); + + $users_having_role = $query->execute()->fetchAll(); + + $query = db_select('role', 'r'); + $query->addField('r', 'name'); + $query->condition('rid', $rid); + + $role_name = $query->execute()->fetchField(); + + $view_users = user_access('access user profiles'); + drupal_set_title(t('Users in "!name" role', array('!name' => $role_name))); + + $users_header = array(array( + 'data' => 'User', + 'colspan' => 2, + )); + + foreach ($users_having_role as $user) { + $rows[] = array( + array('data' => ($user->uid !== 0) ? ($view_users ? l($user->name, "user/$user->uid") : $user->name) : variable_get('anonymous', t('Anonymous'))) + , + array('data' => l('Permission report', "user/$user->uid/permission_report")), + ); + } + + return theme('table', array('header' => $users_header, 'rows' => $rows)); +} + +/** + * List of roles with the number of users in each role. + */ +function permission_report_role_list() { + $user_in_roles = db_query('SELECT r.rid rid, r.name name, COUNT(ur.uid) as user_count FROM {role} r INNER JOIN {users_roles} ur USING (rid) INNER JOIN {users} u USING(uid) WHERE u.status = :u_status GROUP BY r.rid ORDER BY r.name', array(':u_status' => 1))->fetchAllAssoc('rid'); + $can_admin_access = user_access('administer access control'); + $all_users = user_roles(); + // Remove 'authenticated user' and 'anonymous user'. + unset($all_users[1], $all_users[2]); + $rows = array(); + foreach ($all_users as $rid => $name) { + $count = (isset($user_in_roles[$rid])) ? $user_in_roles[$rid]->user_count : 0; + $rows[] = array( + $can_admin_access ? l($name, "admin/people/permissions/$rid") : t($name), + l(format_plural($count, '1 user', '@count users'), "admin/reports/permissions/roles/$rid"), + ); + } + + $roles_header = array( + array( + 'data' => 'Role', + 'colspan' => 2, + ), + ); + + return theme('table', array('header' => $roles_header, 'rows' => $rows)); +} + +/** + * Creates a report showing which users have a specific permission. + */ +function permission_report_user_having_perm($permission) { + + $view_users = user_access('access user profiles'); + $can_admin_access = user_access('administer access control'); + $output = ''; + + drupal_set_title(t('Permissions report for "!permission"', array('!permission' => $permission))); + + foreach (_permission_report_users_having_perm($permission) as $uid => $name) { + $users_rows[] = array( + array('data' => ($uid !== 0) ? ($view_users ? l($name, "user/$uid") : $name) : variable_get('anonymous', t('Anonymous'))), + array('data' => l('Permission report', 'user/' . $uid . '/permission_report')), + ); + } + + $users_header = array( + array( + 'data' => 'User', + 'colspan' => 2, + ), + ); + + foreach (_permission_report_roles_having_perm($permission) as $rid => $name) { + $roles_rows[] = array( + array('data' => $can_admin_access ? l($name, "admin/reports/permissions/roles/$rid") : t($name)), + array('data' => l('Permission report', "admin/reports/permissions/roles/$rid")), + ); + } + + $roles_header = array( + array( + 'data' => 'Role', + 'colspan' => 2, + ), + ); + + $output .= '

Users

'; + $output .= theme('table', array('header' => $users_header, 'rows' => $users_rows)); + $output .= '

Roles

'; + $output .= theme('table', array('header' => $roles_header, 'rows' => $roles_rows)); + + return $output; +} + +/** + * Creates a report which lists all permissions and the number of users which + * have those permissions. + */ +function permission_report_permission_list() { + $can_admin_access = user_access('administer access control'); + + foreach (module_implements('permission') as $module) { + if ($permissions = module_invoke($module, 'permission')) { + $rows[] = array(array( + 'data' => t('@module module', array('@module' => $module)), + 'class' => 'module', + 'id' => 'module-' . $module, + 'colspan' => 3, + )); + + asort($permissions); + + foreach ($permissions as $perm => $meta) { + $display_roles = array(); + + $roles = _permission_report_roles_having_perm($perm); + foreach ($roles as $rid => $name) { + $display_roles[] = $can_admin_access ? l($name, "admin/reports/permissions/roles/$rid") : t($name); + } + $rows[] = array( + array('data' => $meta['title']), + array('data' => l(format_plural(count(_permission_report_users_having_perm($perm)), '1 user', '@count users'), "admin/reports/permissions/perms/$perm")), + ); + } + } + } + return theme('table', array('header' => array('Permission', 'Users'), 'rows' => $rows, 'attributes' => array('id' => 'permissions', 'sticky' => TRUE))); +} + +/** + * Implements hook_permission(). + */ +function permission_report_permission() { + return array( + 'view permission report' => array( + 'title' => t('View permission report'), + 'description' => t('Allows a user to view permission reports.'), + ), + ); +} + diff --git a/sites/all/modules/contrib/dev/examples/LICENSE.txt b/sites/all/modules/contrib/dev/examples/LICENSE.txt new file mode 100644 index 00000000..d159169d --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/LICENSE.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/sites/all/modules/contrib/dev/examples/README.txt b/sites/all/modules/contrib/dev/examples/README.txt new file mode 100644 index 00000000..5904fefe --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/README.txt @@ -0,0 +1,62 @@ +Examples for Developers +======================= + +http://drupal.org/project/examples + +What Is This? +------------- + +This set of modules is intended to provide working examples of Drupal's +features and APIs. The modules strive to be simple, well documented and +modification friendly, in order to help developers quickly learn their inner +workings. + +These examples are meant to teach you about code-level development for Drupal +7. Some solutions might be better served using a contributed module, so that +you don't end up having to re-invent the wheel in PHP. + + +How To Use The Examples +----------------------- + +There are three main ways to interact with the examples in this project: + +1. Enable the modules and use them within Drupal. Not all modules will have +obvious things to see within Drupal. For instance, while the Page and Form API +examples will show you forms, the Database API example will not show you much +within Drupal itself. + +2. Read the code. Much effort has gone into making the example code readable, +not only in terms of the code itself, but also the extensive inline comments +and documentation blocks. + +3. Browse the code and documentation on the web. There are two main places to +do this: + +* https://api.drupal.org/api/examples is the main API site for all of Drupal. +It has all manner of cross-linked references between the example code and the +APIs being demonstrated. + +* http://drupalcode.org/project/examples.git allows you to browse the git +repository for the Examples project. + + +How To Install The Modules +-------------------------- + +1. Install Examples for Developers (unpacking it to your Drupal +/sites/all/modules directory if you're installing by hand, for example). + +2. Enable any Example modules in Admin menu > Site building > Modules. + +3. Rebuild access permissions if you are prompted to. + +4. Profit! The examples will appear in your Navigation menu (on the left +sidebar by default; you'll need to reenable it if you removed it). + +Now you can read the code and its comments and see the result, experiment with +it, and hopefully quickly grasp how things work. + +If you find a problem, incorrect comment, obsolete or improper code or such, +please search for an issue about it at http://drupal.org/project/issues/examples +If there isn't already an issue for it, please create a new one. diff --git a/sites/all/modules/contrib/dev/examples/action_example/action_example.info b/sites/all/modules/contrib/dev/examples/action_example/action_example.info new file mode 100644 index 00000000..05dd5e0e --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/action_example/action_example.info @@ -0,0 +1,13 @@ +name = Action example +description = Demonstrates providing actions that can be associated to triggers. +package = Example modules +core = 7.x +dependencies[] = trigger +files[] = action_example.test + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/action_example/action_example.module b/sites/all/modules/contrib/dev/examples/action_example/action_example.module new file mode 100644 index 00000000..993106e0 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/action_example/action_example.module @@ -0,0 +1,375 @@ + array( + 'label' => t('Action Example: A basic example action that does nothing'), + 'type' => 'system', + 'configurable' => FALSE, + 'triggers' => array('any'), + ), + 'action_example_unblock_user_action' => array( + 'label' => t('Action Example: Unblock a user'), + 'type' => 'user', + 'configurable' => FALSE, + 'triggers' => array('any'), + ), + 'action_example_node_sticky_action' => array( + 'type' => 'node', + 'label' => t('Action Example: Promote to frontpage and sticky on top any content created by :'), + 'configurable' => TRUE, + 'behavior' => array('changes_property'), + 'triggers' => array('node_presave', 'node_insert', 'node_update'), + ), + ); +} + +/** + * Implements hook_menu(). + * + * Provides a menu entry which explains what the module does. + */ +function action_example_menu() { + $items['examples/action_example'] = array( + 'title' => 'Action Example', + 'description' => 'Provides a basic information page.', + 'page callback' => '_action_example_page', + 'access callback' => TRUE, + ); + return $items; +} + + +/** + * A simple page to explain to the developer what to do. + */ +function _action_example_page() { + return t("The Action Example provides three example actions which can be configured on the Actions configuration page and assigned to triggers on the Triggers configuration page.", array('@actions_url' => url('admin/config/system/actions'), '@triggers_url' => url('admin/structure/trigger/node'))); +} + +/** + * Action function for action_example_basic_action. + * + * This action is not expecting any type of entity object, and can be used with + * any trigger type or any event. + * + * @param object $entity + * An optional entity object. + * @param array $context + * Array with parameters for this action: depends on the trigger. + * + * @see action_example_action_info() + */ +function action_example_basic_action(&$entity, $context = array()) { + // In this case we are ignoring the entity and the context. This case of + // action is useful when your action does not depend on the context, and + // the function must do something regardless the scope of the trigger. + // Simply announces that the action was executed using a message. + drupal_set_message(t('action_example_basic_action fired')); + watchdog('action_example', 'action_example_basic_action fired.'); +} + +/** + * Action function for action_example_unblock_user_action. + * + * This action is expecting an entity object user, node or comment. If none of + * the above is provided (because it was not called from an user/node/comment + * trigger event), then the action will be taken on the current logged in user. + * + * Unblock an user. This action can be fired from different trigger types: + * - User trigger: this user will be unblocked. + * - Node/Comment trigger: the author of the node or comment will be unblocked. + * - Other: (including system or custom defined types), current user will be + * unblocked. (Yes, this seems like an incomprehensible use-case.) + * + * @param object $entity + * An optional user object (could be a user, or an author if context is + * node or comment) + * @param array $context + * Array with parameters for this action: depends on the trigger. The context + * is not used in this example. + */ +function action_example_unblock_user_action(&$entity, $context = array()) { + + // First we check that entity is a user object. If this is the case, then this + // is a user-type trigger. + if (isset($entity->uid)) { + $uid = $entity->uid; + } + elseif (isset($context['uid'])) { + $uid = $context['uid']; + } + // If neither of those are valid, then block the current user. + else { + $uid = $GLOBALS['user']->uid; + } + $account = user_load($uid); + $account = user_save($account, array('status' => 1)); + watchdog('action_example', 'Unblocked user %name.', array('%name' => $account->name)); + drupal_set_message(t('Unblocked user %name', array('%name' => $account->name))); +} + +/** + * Form function for action_example_node_sticky_action. + * + * Since we defined action_example_node_sticky_action as 'configurable' => TRUE, + * this action requires a configuration form to create/configure the action. + * In this circumstance, Drupal will attempt to call a function named by + * combining the action name (action_example_node_sticky_action) and _form, in + * this case yielding action_example_node_sticky_action_form. + * + * In Drupal, actions requiring creation and configuration are called 'advanced + * actions', because they must be customized to define their functionality. + * + * The 'action_example_node_sticky_action' allows creating rules to promote and + * set sticky content created by selected users on certain events. A form is + * used to configure which user is affected by this action, and this form + * includes the standard _validate and _submit hooks. + */ + + +/** + * Generates settings form for action_example_node_sticky_action(). + * + * @param array $context + * An array of options of this action (in case it is being edited) + * + * @return array + * Settings form as Form API array. + * + * @see action_example_action_info() + */ +function action_example_node_sticky_action_form($context) { + /* + * We return a configuration form to set the requirements that will + * match this action before being executed. This is a regular Drupal form and + * may include any type of information you want, but all the fields of the + * form will be saved into the $context variable. + * + * In this case we are promoting all content types submitted by this user, but + * it is possible to extend these conditions providing more options in the + * settings form. + */ + $form['author'] = array( + '#title' => t('Author name'), + '#type' => 'textfield', + '#description' => t('Any content created, presaved or updated by this user will be promoted to front page and set as sticky.'), + '#default_value' => isset($context['author']) ? $context['author'] : '', + ); + // Verify user permissions and provide an easier way to fill this field. + if (user_access('access user profiles')) { + $form['author']['#autocomplete_path'] = 'user/autocomplete'; + } + // No more options, return the form. + return $form; +} + +/** + * Validates settings form for action_example_node_sticky_action(). + * + * Verifies that user exists before continuing. + */ +function action_example_node_sticky_action_validate($form, $form_state) { + if (!$account = user_load_by_name($form_state['values']['author'])) { + form_set_error('author', t('Please, provide a valid username')); + } +} + +/** + * Submit handler for action_example_node_sticky_action. + * + * Returns an associative array of values which will be available in the + * $context when an action is executed. + */ +function action_example_node_sticky_action_submit($form, $form_state) { + return array('author' => $form_state['values']['author']); +} + +/** + * Action function for action_example_node_sticky_action. + * + * Promote and set sticky flag. This is the special action that has been + * customized using the configuration form, validated with the validation + * function, and submitted with the submit function. + * + * @param object $node + * A node object provided by the associated trigger. + * @param array $context + * Array with the following elements: + * - 'author': username of the author's content this function will promote and + * set as sticky. + */ +function action_example_node_sticky_action($node, $context) { + if (function_exists('dsm')) { + dsm($node, 'action_example_node_sticky_action is firing. Here is the $node'); + dsm($context, 'action_example_node_sticky_action is firing. Here is the $context'); + } + // Get the user configured for this special action. + $account = user_load_by_name($context['author']); + // Is the node created by this user? then promote and set as sticky. + if ($account->uid == $node->uid) { + $node->promote = NODE_PROMOTED; + $node->sticky = NODE_STICKY; + watchdog('action', + 'Set @type %title to sticky and promoted by special action for user %username.', + array( + '@type' => node_type_get_name($node), + '%title' => $node->title, + '%username' => $account->name, + ) + ); + drupal_set_message( + t('Set @type %title to sticky and promoted by special action for user %username.', + array( + '@type' => node_type_get_name($node), + '%title' => $node->title, + '%username' => $account->name, + ) + ) + ); + } +} +/** + * @} End of "defgroup action_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/action_example/action_example.test b/sites/all/modules/contrib/dev/examples/action_example/action_example.test new file mode 100644 index 00000000..c6686ab9 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/action_example/action_example.test @@ -0,0 +1,111 @@ + 'Action example', + 'description' => 'Perform various tests on action_example module.' , + 'group' => 'Examples', + ); + } + + /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp('trigger', 'action_example'); + } + + /** + * Test Action Example. + * + * 1. action_example_basic_action: Configure a action_example_basic_action to + * happen when user logs in. + * 2. action_example_unblock_user_action: When a user's profile is being + * viewed, unblock that user. + * 3. action_example_node_sticky_action: Create a user, configure that user + * to always be stickied using advanced configuration. Have the user + * create content; verify that it gets stickied. + */ + public function testActionExample() { + // Create an administrative user. + $admin_user = $this->drupalCreateUser( + array( + 'administer actions', + 'access comments', + 'access content', + 'post comments', + 'skip comment approval', + 'create article content', + 'access user profiles', + 'administer users', + ) + ); + $this->drupalLogin($admin_user); + + // 1. Assign basic action; then logout and login user and see if it puts + // the message on the screen. + $hash = drupal_hash_base64('action_example_basic_action'); + $edit = array('aid' => $hash); + $this->drupalPost('admin/structure/trigger/user', $edit, t('Assign'), array(), array(), 'trigger-user-login-assign-form'); + + $this->drupalLogout(); + $this->drupalLogin($admin_user); + $this->assertText(t('action_example_basic_action fired')); + + // 2. Unblock: When a user's profile is being viewed, unblock. + $normal_user = $this->drupalCreateUser(); + // Create blocked user. + user_save($normal_user, array('status' => 0)); + $normal_user = user_load($normal_user->uid, TRUE); + $this->assertFalse($normal_user->status, 'Normal user status has been set to blocked'); + + $hash = drupal_hash_base64('action_example_unblock_user_action'); + $edit = array('aid' => $hash); + $this->drupalPost('admin/structure/trigger/user', $edit, t('Assign'), array(), array(), 'trigger-user-view-assign-form'); + + $this->drupalGet("user/$normal_user->uid"); + $normal_user = user_load($normal_user->uid, TRUE); + $this->assertTrue($normal_user->status, 'Normal user status has been set to unblocked'); + $this->assertRaw(t('Unblocked user %name', array('%name' => $normal_user->name))); + + // 3. Create a user whose posts are always to be stickied. + $sticky_user = $this->drupalCreateUser( + array( + 'access comments', + 'access content', + 'post comments', + 'skip comment approval', + 'create article content', + ) + ); + + $action_label = $this->randomName(); + $edit = array( + 'actions_label' => $action_label, + 'author' => $sticky_user->name, + ); + $aid = $this->configureAdvancedAction('action_example_node_sticky_action', $edit); + $edit = array('aid' => drupal_hash_base64($aid)); + $this->drupalPost('admin/structure/trigger/node', $edit, t('Assign'), array(), array(), 'trigger-node-insert-assign-form'); + // Now create a node and verify that it gets stickied. + $this->drupalLogout(); + $this->drupalLogin($sticky_user); + $node = $this->drupalCreateNode(); + $this->assertTrue($node->sticky, 'Node was set to sticky on creation'); + } +} diff --git a/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.css b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.css new file mode 100644 index 00000000..e1cdc694 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.css @@ -0,0 +1,17 @@ +/* + * @file + * CSS for ajax_example. + * + * See @link ajax_example_dependent_dropdown_degrades @endlink for + * details on what this file does. It is not used in any other example. + */ + +/* Hides the next button when not degrading to non-javascript browser */ +html.js .next-button { + display: none; +} + +/* Makes the next/choose button align to the right of the select control */ +.form-item-dropdown-first, .form-item-question-type-select { + display: inline-block; +} diff --git a/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.info b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.info new file mode 100644 index 00000000..2dc5b590 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.info @@ -0,0 +1,12 @@ +name = AJAX Example +description = An example module showing how to use Drupal AJAX forms +package = Example modules +core = 7.x +files[] = ajax_example.test + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.install b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.install new file mode 100644 index 00000000..6d3d2130 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.install @@ -0,0 +1,56 @@ + 'Stores example settings for nodes.', + 'fields' => array( + 'nid' => array( + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + 'description' => 'The {node}.nid to store settings.', + ), + 'example_1' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'description' => 'Node Form Example 1 checkbox', + ), + 'example_2' => array( + 'type' => 'varchar', + 'length' => 256, + 'not null' => FALSE, + 'default' => '', + 'description' => 'Node Form Example 2 textfield', + ), + ), + 'primary key' => array('nid'), + 'foreign keys' => array( + 'dnv_node' => array( + 'table' => 'node', + 'columns' => array('nid' => 'nid'), + ), + ), + ); + return $schema; +} + +/** + * Add the new ajax_example_node_form_alter table. + */ +function ajax_example_update_7100() { + if (!db_table_exists('ajax_example_node_form_alter')) { + $schema = ajax_example_schema(); + db_create_table('ajax_example_node_form_alter', $schema['ajax_example_node_form_alter']); + return st('Created table ajax_example_node_form_alter'); + } +} diff --git a/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.js b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.js new file mode 100644 index 00000000..2d06038c --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.js @@ -0,0 +1,29 @@ +/* + * @file + * JavaScript for ajax_example. + * + * See @link ajax_example_dependent_dropdown_degrades @endlink for + * details on what this file does. It is not used in any other example. + */ + +(function($) { + + // Re-enable form elements that are disabled for non-ajax situations. + Drupal.behaviors.enableFormItemsForAjaxForms = { + attach: function() { + // If ajax is enabled. + if (Drupal.ajax) { + $('.enabled-for-ajax').removeAttr('disabled'); + } + + // Below is only for the demo case of showing with js turned off. + // It overrides the behavior of the CSS that would normally turn off + // the 'ok' button when JS is enabled. Here, for demonstration purposes, + // we have AJAX disabled but JS turned on, so use this to simulate. + if (!Drupal.ajax) { + $('html.js .next-button').show(); + } + } + }; + +})(jQuery); diff --git a/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.module b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.module new file mode 100644 index 00000000..4bfa26c2 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.module @@ -0,0 +1,693 @@ + 'AJAX Example', + 'page callback' => 'ajax_example_intro', + 'access callback' => TRUE, + 'expanded' => TRUE, + ); + + // Change the description of a form element. + $items['examples/ajax_example/simplest'] = array( + 'title' => 'Simplest AJAX Example', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_simplest'), + 'access callback' => TRUE, + 'weight' => 0, + ); + // Generate a changing number of checkboxes. + $items['examples/ajax_example/autocheckboxes'] = array( + 'title' => 'Generate checkboxes', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_autocheckboxes'), + 'access callback' => TRUE, + 'weight' => 1, + ); + // Generate different textfields based on form state. + $items['examples/ajax_example/autotextfields'] = array( + 'title' => 'Generate textfields', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_autotextfields'), + 'access callback' => TRUE, + 'weight' => 2, + ); + + // Submit a form without a page reload. + $items['examples/ajax_example/submit_driven_ajax'] = array( + 'title' => 'Submit-driven AJAX', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_submit_driven_ajax'), + 'access callback' => TRUE, + 'weight' => 3, + ); + + // Repopulate a dropdown based on form state. + $items['examples/ajax_example/dependent_dropdown'] = array( + 'title' => 'Dependent dropdown', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_dependent_dropdown'), + 'access callback' => TRUE, + 'weight' => 4, + ); + // Repopulate a dropdown, but this time with graceful degredation. + // See ajax_example_graceful_degradation.inc. + $items['examples/ajax_example/dependent_dropdown_degrades'] = array( + 'title' => 'Dependent dropdown (with graceful degradation)', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_dependent_dropdown_degrades'), + 'access callback' => TRUE, + 'weight' => 5, + 'file' => 'ajax_example_graceful_degradation.inc', + ); + // The above example as it appears to users with no javascript. + $items['examples/ajax_example/dependent_dropdown_degrades_no_js'] = array( + 'title' => 'Dependent dropdown with javascript off', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_dependent_dropdown_degrades', TRUE), + 'access callback' => TRUE, + 'file' => 'ajax_example_graceful_degradation.inc', + 'weight' => 5, + ); + + // Populate a form section based on input in another element. + $items['examples/ajax_example/dynamic_sections'] = array( + 'title' => 'Dynamic Sections (with graceful degradation)', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_dynamic_sections'), + 'access callback' => TRUE, + 'weight' => 6, + 'file' => 'ajax_example_graceful_degradation.inc', + ); + // The above example as it appears to users with no javascript. + $items['examples/ajax_example/dynamic_sections_no_js'] = array( + 'title' => 'Dynamic Sections w/JS turned off', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_dynamic_sections', TRUE), + 'access callback' => TRUE, + 'weight' => 6, + 'file' => 'ajax_example_graceful_degradation.inc', + ); + + // A classic multi-step wizard, but with no page reloads. + // See ajax_example_graceful_degradation.inc. + $items['examples/ajax_example/wizard'] = array( + 'title' => 'Wizard (with graceful degradation)', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_wizard'), + 'access callback' => TRUE, + 'file' => 'ajax_example_graceful_degradation.inc', + 'weight' => 7, + ); + // The above example as it appears to users with no javascript. + $items['examples/ajax_example/wizard_no_js'] = array( + 'title' => 'Wizard w/JS turned off', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_wizard', TRUE), + 'access callback' => TRUE, + 'file' => 'ajax_example_graceful_degradation.inc', + 'weight' => 7, + ); + + // Add-more button that creates additional form elements. + // See ajax_example_graceful_degradation.inc. + $items['examples/ajax_example/add_more'] = array( + 'title' => 'Add-more button (with graceful degradation)', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_add_more'), + 'access callback' => TRUE, + 'file' => 'ajax_example_graceful_degradation.inc', + 'weight' => 8, + ); + // The above example as it appears to users with no javascript. + $items['examples/ajax_example/add_more_no_js'] = array( + 'title' => 'Add-more button w/JS turned off', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_add_more', TRUE), + 'access callback' => TRUE, + 'file' => 'ajax_example_graceful_degradation.inc', + 'weight' => 8, + ); + + // Use the AJAX framework outside the context of a form using the use-ajax + // class. See ajax_example_misc.inc. + $items['examples/ajax_example/ajax_link'] = array( + 'title' => 'Ajax Link ("use-ajax" class)', + 'page callback' => 'ajax_example_render_link', + 'access callback' => TRUE, + 'file' => 'ajax_example_misc.inc', + 'weight' => 9, + ); + // Use the AJAX framework outside the context of a form using a renderable + // array of type link with the #ajax property. See ajax_example_misc.inc. + $items['examples/ajax_example/ajax_link_renderable'] = array( + 'title' => 'Ajax Link (Renderable Array)', + 'page callback' => 'ajax_example_render_link_ra', + 'access callback' => TRUE, + 'file' => 'ajax_example_misc.inc', + 'weight' => 9, + ); + // A menu callback is required when using ajax outside of the Form API. + $items['ajax_link_callback'] = array( + 'page callback' => 'ajax_link_response', + 'access callback' => 'user_access', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + 'file' => 'ajax_example_misc.inc', + ); + + // Use AJAX framework commands outside of the #ajax form property. + // See ajax_example_advanced.inc. + $items['examples/ajax_example/advanced_commands'] = array( + 'title' => 'AJAX framework commands', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_advanced_commands'), + 'access callback' => TRUE, + 'file' => 'ajax_example_advanced.inc', + 'weight' => 100, + ); + + // Autocomplete examples. + $items['examples/ajax_example/simple_autocomplete'] = array( + 'title' => 'Autocomplete (simple)', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_simple_autocomplete'), + 'access arguments' => array('access user profiles'), + 'file' => 'ajax_example_autocomplete.inc', + 'weight' => 10, + ); + $items['examples/ajax_example/simple_user_autocomplete_callback'] = array( + 'page callback' => 'ajax_example_simple_user_autocomplete_callback', + 'file' => 'ajax_example_autocomplete.inc', + 'type' => MENU_CALLBACK, + 'access arguments' => array('access user profiles'), + ); + $items['examples/ajax_example/node_autocomplete'] = array( + 'title' => 'Autocomplete (node with nid)', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_unique_autocomplete'), + 'access arguments' => array('access content'), + 'file' => 'ajax_example_autocomplete.inc', + 'weight' => 11, + ); + $items['examples/ajax_example/unique_node_autocomplete_callback'] = array( + 'page callback' => 'ajax_example_unique_node_autocomplete_callback', + 'file' => 'ajax_example_autocomplete.inc', + 'type' => MENU_CALLBACK, + 'access arguments' => array('access content'), + ); + $items['examples/ajax_example/node_by_author'] = array( + 'title' => 'Autocomplete (node limited by author)', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_node_by_author_autocomplete'), + 'access callback' => TRUE, + 'file' => 'ajax_example_autocomplete.inc', + 'weight' => 12, + ); + $items['examples/ajax_example/node_by_author_autocomplete'] = array( + 'page callback' => 'ajax_example_node_by_author_node_autocomplete_callback', + 'file' => 'ajax_example_autocomplete.inc', + 'type' => MENU_CALLBACK, + 'access arguments' => array('access content'), + ); + // This is the landing page for the progress bar example. It uses + // drupal_get_form() in order to build the form. + $items['examples/ajax_example/progressbar'] = array( + 'title' => 'Progress bar example', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ajax_example_progressbar_form'), + 'access arguments' => array('access content'), + 'file' => 'ajax_example_progressbar.inc', + ); + // This is the callback route for the AJAX-based progress bar. + $items['examples/ajax_example/progressbar/progress/%'] = array( + 'title' => 'Progress bar progress', + 'page callback' => 'ajax_example_progressbar_progress', + 'page arguments' => array(4), + 'type' => MENU_CALLBACK, + 'access arguments' => array('access content'), + 'file' => 'ajax_example_progressbar.inc', + ); + + return $items; +} + +/** + * A basic introduction page for the ajax_example module. + */ +function ajax_example_intro() { + $markup = t('The AJAX example module provides many examples of AJAX including forms, links, and AJAX commands.'); + + $list[] = l(t('Simplest AJAX Example'), 'examples/ajax_example/simplest'); + $list[] = l(t('Generate checkboxes'), 'examples/ajax_example/autocheckboxes'); + $list[] = l(t('Generate textfields'), 'examples/ajax_example/autotextfields'); + $list[] = l(t('Submit-driven AJAX'), 'examples/ajax_example/submit_driven_ajax'); + $list[] = l(t('Dependent dropdown'), 'examples/ajax_example/dependent_dropdown'); + $list[] = l(t('Dependent dropdown (with graceful degradation)'), 'examples/ajax_example/dependent_dropdown_degrades'); + $list[] = l(t('Dynamic Sections w/JS turned off'), 'examples/ajax_example/dependent_dropdown_degrades_no_js'); + $list[] = l(t('Wizard (with graceful degradation)'), 'examples/ajax_example/wizard'); + $list[] = l(t('Wizard w/JS turned off'), 'examples/ajax_example/wizard_no_js'); + $list[] = l(t('Add-more button (with graceful degradation)'), 'examples/ajax_example/add_more'); + $list[] = l(t('Add-more button w/JS turned off'), 'examples/ajax_example/add_more_no_js'); + $list[] = l(t('Ajax Link ("use-ajax" class)'), 'examples/ajax_example/ajax_link'); + $list[] = l(t('Ajax Link (Renderable Array)'), 'examples/ajax_example/ajax_link_renderable'); + $list[] = l(t('AJAX framework commands'), 'examples/ajax_example/advanced_commands'); + $list[] = l(t('Autocomplete (simple)'), 'examples/ajax_example/simple_autocomplete'); + $list[] = l(t('Autocomplete (node with nid)'), 'examples/ajax_example/node_autocomplete'); + $list[] = l(t('Autocomplete (node limited by author)'), 'examples/ajax_example/node_by_author'); + + $variables['items'] = $list; + $variables['type'] = 'ul'; + $markup .= theme('item_list', $variables); + + return $markup; +} + +/** + * Basic AJAX callback example. + * + * Simple form whose ajax-enabled 'changethis' member causes a text change + * in the description of the 'replace_textfield' member. + * + * See @link http://drupal.org/node/262422 Form API Tutorial @endlink + */ +function ajax_example_simplest($form, &$form_state) { + $form = array(); + $form['changethis'] = array( + '#title' => t("Choose something and explain why"), + '#type' => 'select', + '#options' => array( + 'one' => 'one', + 'two' => 'two', + 'three' => 'three', + ), + '#ajax' => array( + // #ajax has two required keys: callback and wrapper. + // 'callback' is a function that will be called when this element changes. + 'callback' => 'ajax_example_simplest_callback', + // 'wrapper' is the HTML id of the page element that will be replaced. + 'wrapper' => 'replace_textfield_div', + // There are also several optional keys - see ajax_example_autocheckboxes + // below for details on 'method', 'effect' and 'speed' and + // ajax_example_dependent_dropdown for 'event'. + ), + ); + + // This entire form element will be replaced whenever 'changethis' is updated. + $form['replace_textfield'] = array( + '#type' => 'textfield', + '#title' => t("Why"), + // The prefix/suffix provide the div that we're replacing, named by + // #ajax['wrapper'] above. + '#prefix' => '
', + '#suffix' => '
', + ); + + // An AJAX request calls the form builder function for every change. + // We can change how we build the form based on $form_state. + if (!empty($form_state['values']['changethis'])) { + $form['replace_textfield']['#description'] = t("Say why you chose '@value'", array('@value' => $form_state['values']['changethis'])); + } + return $form; +} + +/** + * Callback for ajax_example_simplest. + * + * On an ajax submit, the form builder function is called again, then the $form + * and $form_state are passed to this callback function so it can select which + * portion of the form to send on to the client. + * + * @return array + * Renderable array (the textfield element) + */ +function ajax_example_simplest_callback($form, $form_state) { + // The form has already been submitted and updated. We can return the replaced + // item as it is. + return $form['replace_textfield']; +} + +/** + * Form manipulation through AJAX. + * + * AJAX-enabled select element causes replacement of a set of checkboxes + * based on the selection. + */ +function ajax_example_autocheckboxes($form, &$form_state) { + // Since the form builder is called after every AJAX request, we rebuild + // the form based on $form_state. + $num_checkboxes = !empty($form_state['values']['howmany_select']) ? $form_state['values']['howmany_select'] : 1; + + $form['howmany_select'] = array( + '#title' => t('How many checkboxes do you want?'), + '#type' => 'select', + '#options' => array(1 => 1, 2 => 2, 3 => 3, 4 => 4), + '#default_value' => $num_checkboxes, + '#ajax' => array( + 'callback' => 'ajax_example_autocheckboxes_callback', + 'wrapper' => 'checkboxes-div', + // 'method' defaults to replaceWith, but valid values also include + // append, prepend, before and after. + // 'method' => 'replaceWith', + // 'effect' defaults to none. Other valid values are 'fade' and 'slide'. + // See ajax_example_autotextfields for an example of 'fade'. + 'effect' => 'slide', + // 'speed' defaults to 'slow'. You can also use 'fast' + // or a number of milliseconds for the animation to last. + // 'speed' => 'slow', + // Don't show any throbber... + 'progress' => array('type' => 'none'), + ), + ); + + $form['checkboxes_fieldset'] = array( + '#title' => t("Generated Checkboxes"), + // The prefix/suffix provide the div that we're replacing, named by + // #ajax['wrapper'] above. + '#prefix' => '
', + '#suffix' => '
', + '#type' => 'fieldset', + '#description' => t('This is where we get automatically generated checkboxes'), + ); + + for ($i = 1; $i <= $num_checkboxes; $i++) { + $form['checkboxes_fieldset']["checkbox$i"] = array( + '#type' => 'checkbox', + '#title' => "Checkbox $i", + ); + } + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + + return $form; +} + +/** + * Callback for autocheckboxes. + * + * Callback element needs only select the portion of the form to be updated. + * Since #ajax['callback'] return can be HTML or a renderable array (or an + * array of commands), we can just return a piece of the form. + * See @link ajax_example_advanced.inc AJAX Advanced Commands for more details + * on AJAX framework commands. + * + * @return array + * Renderable array (the checkboxes fieldset) + */ +function ajax_example_autocheckboxes_callback($form, $form_state) { + return $form['checkboxes_fieldset']; +} + + +/** + * Show/hide textfields based on AJAX-enabled checkbox clicks. + */ +function ajax_example_autotextfields($form, &$form_state) { + + $form['ask_first_name'] = array( + '#type' => 'checkbox', + '#title' => t('Ask me my first name'), + '#ajax' => array( + 'callback' => 'ajax_example_autotextfields_callback', + 'wrapper' => 'textfields', + 'effect' => 'fade', + ), + ); + $form['ask_last_name'] = array( + '#type' => 'checkbox', + '#title' => t('Ask me my last name'), + '#ajax' => array( + 'callback' => 'ajax_example_autotextfields_callback', + 'wrapper' => 'textfields', + 'effect' => 'fade', + ), + ); + + $form['textfields'] = array( + '#title' => t("Generated text fields for first and last name"), + '#prefix' => '
', + '#suffix' => '
', + '#type' => 'fieldset', + '#description' => t('This is where we put automatically generated textfields'), + ); + + // Since checkboxes return TRUE or FALSE, we have to check that + // $form_state has been filled as well as what it contains. + if (!empty($form_state['values']['ask_first_name']) && $form_state['values']['ask_first_name']) { + $form['textfields']['first_name'] = array( + '#type' => 'textfield', + '#title' => t('First Name'), + ); + } + if (!empty($form_state['values']['ask_last_name']) && $form_state['values']['ask_last_name']) { + $form['textfields']['last_name'] = array( + '#type' => 'textfield', + '#title' => t('Last Name'), + ); + } + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Click Me'), + ); + + return $form; +} + +/** + * Callback for autotextfields. + * + * Selects the piece of the form we want to use as replacement text and returns + * it as a form (renderable array). + * + * @return array + * Renderable array (the textfields element) + */ +function ajax_example_autotextfields_callback($form, $form_state) { + return $form['textfields']; +} + + +/** + * A very basic form which with an AJAX-enabled submit. + * + * On submit, the markup in the #markup element is updated. + */ +function ajax_example_submit_driven_ajax($form, &$form_state) { + $form['box'] = array( + '#type' => 'markup', + '#prefix' => '
', + '#suffix' => '
', + '#markup' => '

Initial markup for box

', + ); + + $form['submit'] = array( + '#type' => 'submit', + '#ajax' => array( + 'callback' => 'ajax_example_submit_driven_callback', + 'wrapper' => 'box', + ), + '#value' => t('Submit'), + ); + + return $form; +} + +/** + * Callback for submit_driven example. + * + * Select the 'box' element, change the markup in it, and return it as a + * renderable array. + * + * @return array + * Renderable array (the box element) + */ +function ajax_example_submit_driven_callback($form, $form_state) { + // In most cases, it is recommended that you put this logic in form generation + // rather than the callback. Submit driven forms are an exception, because + // you may not want to return the form at all. + $element = $form['box']; + $element['#markup'] = "Clicked submit ({$form_state['values']['op']}): " . date('c'); + return $element; +} + + +/** + * AJAX-based dropdown example form. + * + * A form with a dropdown whose options are dependent on a + * choice made in a previous dropdown. + * + * On changing the first dropdown, the options in the second + * are updated. + */ +function ajax_example_dependent_dropdown($form, &$form_state) { + // Get the list of options to populate the first dropdown. + $options_first = _ajax_example_get_first_dropdown_options(); + // If we have a value for the first dropdown from $form_state['values'] we use + // this both as the default value for the first dropdown and also as a + // parameter to pass to the function that retrieves the options for the + // second dropdown. + $selected = isset($form_state['values']['dropdown_first']) ? $form_state['values']['dropdown_first'] : key($options_first); + + $form['dropdown_first'] = array( + '#type' => 'select', + '#title' => 'Instrument Type', + '#options' => $options_first, + '#default_value' => $selected, + // Bind an ajax callback to the change event (which is the default for the + // select form type) of the first dropdown. It will replace the second + // dropdown when rebuilt. + '#ajax' => array( + // When 'event' occurs, Drupal will perform an ajax request in the + // background. Usually the default value is sufficient (eg. change for + // select elements), but valid values include any jQuery event, + // most notably 'mousedown', 'blur', and 'submit'. + // 'event' => 'change', + 'callback' => 'ajax_example_dependent_dropdown_callback', + 'wrapper' => 'dropdown-second-replace', + ), + ); + + $form['dropdown_second'] = array( + '#type' => 'select', + '#title' => $options_first[$selected] . ' ' . t('Instruments'), + // The entire enclosing div created here gets replaced when dropdown_first + // is changed. + '#prefix' => '', + // When the form is rebuilt during ajax processing, the $selected variable + // will now have the new value and so the options will change. + '#options' => _ajax_example_get_second_dropdown_options($selected), + '#default_value' => isset($form_state['values']['dropdown_second']) ? $form_state['values']['dropdown_second'] : '', + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + return $form; +} + +/** + * Selects just the second dropdown to be returned for re-rendering. + * + * Since the controlling logic for populating the form is in the form builder + * function, all we do here is select the element and return it to be updated. + * + * @return array + * Renderable array (the second dropdown) + */ +function ajax_example_dependent_dropdown_callback($form, $form_state) { + return $form['dropdown_second']; +} + +/** + * Helper function to populate the first dropdown. + * + * This would normally be pulling data from the database. + * + * @return array + * Dropdown options. + */ +function _ajax_example_get_first_dropdown_options() { + // drupal_map_assoc() just makes an array('String' => 'String'...). + return drupal_map_assoc( + array( + t('String'), + t('Woodwind'), + t('Brass'), + t('Percussion'), + ) + ); +} + +/** + * Helper function to populate the second dropdown. + * + * This would normally be pulling data from the database. + * + * @param string $key + * This will determine which set of options is returned. + * + * @return array + * Dropdown options + */ +function _ajax_example_get_second_dropdown_options($key = '') { + $options = array( + t('String') => drupal_map_assoc( + array( + t('Violin'), + t('Viola'), + t('Cello'), + t('Double Bass'), + ) + ), + t('Woodwind') => drupal_map_assoc( + array( + t('Flute'), + t('Clarinet'), + t('Oboe'), + t('Bassoon'), + ) + ), + t('Brass') => drupal_map_assoc( + array( + t('Trumpet'), + t('Trombone'), + t('French Horn'), + t('Euphonium'), + ) + ), + t('Percussion') => drupal_map_assoc( + array( + t('Bass Drum'), + t('Timpani'), + t('Snare Drum'), + t('Tambourine'), + ) + ), + ); + if (isset($options[$key])) { + return $options[$key]; + } + else { + return array(); + } +} +/** + * @} End of "defgroup ajax_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.test b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.test new file mode 100644 index 00000000..9e72f0f5 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example.test @@ -0,0 +1,75 @@ + 'Ajax example', + 'description' => 'Checks behavior of the Ajax Example', + 'group' => 'Examples', + ); + } + + /** + * Enable module. + */ + public function setUp() { + parent::setUp('ajax_example'); + } + + /** + * Check the non-JS version of the "Dynamic Sections" example. + */ + public function testDynamicSectionsNoJs() { + // The path to the example form. + $path = 'examples/ajax_example/dynamic_sections_no_js'; + // Confirmation text for right and wrong answers. + $wrong = t('Wrong answer. Try again. (Hint: The right answer is "George Washington".)'); + $right = t('You got the right answer: George Washington'); + // For each question style, choose some parameters. + $params = array( + t('Multiple Choice') => array( + 'value' => t('Abraham Lincoln'), + 'answer' => t('Abraham Lincoln'), + 'response' => $wrong, + ), + t('True/False') => array( + 'value' => t('George Washington'), + 'answer' => t('George Washington'), + 'response' => $right, + ), + t('Fill-in-the-blanks') => array( + 'value' => NULL, + 'answer' => t('George Washington'), + 'response' => $right, + ), + ); + foreach ($params as $style => $q_and_a) { + // Submit the initial form. + $edit = array('question_type_select' => $style); + $this->drupalPost($path, $edit, t('Choose')); + $this->assertResponse(200, format_string('Question style "@style" selected.', array('@style' => $style))); + // For convenience, make variables out of the entries in $QandA. + extract($q_and_a); + // Check for the expected input field. + $this->assertFieldByName('question', $value); + // Now, submit the dynamically generated form. + $edit = array('question' => $answer); + $this->drupalPost(NULL, $edit, t('Submit your answer')); + $this->assertRaw($response, 'Dynamic form has been submitted.'); + } + } + +} diff --git a/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_advanced.inc b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_advanced.inc new file mode 100644 index 00000000..7c61d36c --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_advanced.inc @@ -0,0 +1,400 @@ + 'markup', + '#markup' => t("
Demonstrates how AJAX commands can be used.
"), + ); + + // Shows the 'after' command with a callback generating commands. + $form['after_command_example_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t("This shows the Ajax 'after' command. Click to put something below the div that says 'Something can be inserted after this'"), + ); + + $form['after_command_example_fieldset']['after_command_example'] = array( + '#value' => t("AJAX 'After': Click to put something after the div"), + '#type' => 'submit', + '#ajax' => array( + 'callback' => 'ajax_example_advanced_commands_after_callback', + ), + '#suffix' => "
Something can be inserted after this
+
'After' Command Status: Unknown
", + ); + + // Shows the 'alert' command. + $form['alert_command_example_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t("Demonstrates the AJAX 'alert' command. Click the button."), + ); + $form['alert_command_example_fieldset']['alert_command_example'] = array( + '#value' => t("AJAX 'Alert': Click to alert"), + '#type' => 'submit', + '#ajax' => array( + 'callback' => 'ajax_example_advanced_commands_alert_callback', + ), + ); + + // Shows the 'append' command. + $form['append_command_example_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t("This shows the Ajax 'append' command. Click to put something below the div that says 'Something can be inserted after this'"), + ); + + $form['append_command_example_fieldset']['append_command_example'] = array( + '#value' => t("AJAX 'Append': Click to append something"), + '#type' => 'submit', + '#ajax' => array( + 'callback' => 'ajax_example_advanced_commands_append_callback', + ), + '#suffix' => "
Something can be appended inside this div...
+
'After' Command Status: Unknown
", + ); + + // Shows the 'before' command. + $form['before_command_example_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t("This shows the Ajax 'before' command."), + ); + + $form['before_command_example_fieldset']['before_command_example'] = array( + '#value' => t("AJAX 'before': Click to put something before the div"), + '#type' => 'submit', + '#ajax' => array( + 'callback' => 'ajax_example_advanced_commands_before_callback', + ), + '#suffix' => "
Something can be inserted before this
+
'before' Command Status: Unknown
", + ); + + // Shows the 'changed' command. + $form['changed_command_example_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t("Demonstrates the AJAX 'changed' command. If region is 'changed', it is marked with CSS. This example also puts an asterisk by changed content."), + ); + + $form['changed_command_example_fieldset']['changed_command_example'] = array( + '#title' => t("AJAX changed: If checked, div is marked as changed."), + '#type' => 'checkbox', + '#default_value' => FALSE, + '#ajax' => array( + 'callback' => 'ajax_example_advanced_commands_changed_callback', + ), + '#suffix' => "
This div can be marked as changed or not.
+
Status: Unknown
", + ); + + // Shows the AJAX 'css' command. + $form['css_command_example_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t("Demonstrates the AJAX 'css' command."), + ); + + $form['css_command_example_fieldset']['css_command_example'] = array( + '#title' => t("AJAX CSS: Choose the color you'd like the '#box' div to be."), + '#type' => 'select', + // '#default_value' => 'green', + '#options' => array('green' => 'green', 'blue' => 'blue'), + '#ajax' => array( + 'callback' => 'ajax_example_advanced_commands_css_callback', + ), + '#suffix' => "
box
+
Status: Unknown
", + ); + + // Shows the AJAX 'data' command. But there is no use of this information, + // as this would require a javascript client to use the data. + $form['data_command_example_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t("Demonstrates the AJAX 'data' command."), + ); + + $form['data_command_example_fieldset']['data_command_example'] = array( + '#title' => t("AJAX data: Set a key/value pair on a selector."), + '#type' => 'textfield', + '#default_value' => 'color=green', + '#ajax' => array( + 'callback' => 'ajax_example_advanced_commands_data_callback', + ), + '#suffix' => "
This div should have key='time'/value='a time string' attached.
+
Status: Unknown
", + ); + + // Shows the AJAX 'html' command. + $form['html_command_example_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t("Demonstrates the AJAX 'html' command."), + ); + + $form['html_command_example_fieldset']['html_command_example'] = array( + '#title' => t("AJAX html: Replace the HTML in a selector."), + '#type' => 'textfield', + '#default_value' => 'new value', + '#ajax' => array( + 'callback' => 'ajax_example_advanced_commands_html_callback', + ), + '#suffix' => "
Original contents
+
Status: Unknown
", + ); + + // Shows the AJAX 'prepend' command. + $form['prepend_command_example_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t("This shows the AJAX 'prepend' command. Click to put something below the div that says 'Something can be inserted after this'"), + ); + + $form['prepend_command_example_fieldset']['prepend_command_example'] = array( + '#value' => t("AJAX 'prepend': Click to prepend something"), + '#type' => 'submit', + '#ajax' => array( + 'callback' => 'ajax_example_advanced_commands_prepend_callback', + ), + '#suffix' => "
Something can be prepended to this div...
+
'After' Command Status: Unknown
", + ); + + // Shows the AJAX 'remove' command. + $form['remove_command_example_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t("Shows the Ajax 'remove' command."), + ); + + $form['remove_command_example_fieldset']['remove_command_example'] = array( + '#title' => t("AJAX 'remove': Check to remove text. Uncheck to add it back."), + '#type' => 'checkbox', + '#default_value' => FALSE, + '#ajax' => array( + 'callback' => 'ajax_example_advanced_commands_remove_callback', + ), + '#suffix' => "
text to be removed
+
'After' Command Status: Unknown
", + ); + + // Show off the AJAX 'restripe' command. Also shows classic AJAX replacement + // on the "how many rows" processing. + $form['restripe_command_example_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t("Demonstrates the Ajax 'restripe' command."), + ); + + $form['restripe_command_example_fieldset']['restripe_num_rows'] = array( + '#type' => 'select', + '#default_value' => !empty($form_state['values']['restripe_num_rows']) ? $form_state['values']['restripe_num_rows'] : 1, + '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)), + '#ajax' => array( + 'callback' => 'ajax_example_advanced_commands_restripe_num_rows', + 'method' => 'replace', + 'wrapper' => 'restripe_table', + ), + ); + $form['restripe_command_example_fieldset']['restripe_restripe'] = array( + '#type' => 'submit', + '#value' => t("Restripe the table"), + '#ajax' => array( + 'callback' => 'ajax_example_advanced_commands_restripe_callback', + ), + '#suffix' => "
+ + +
first row
+
+
'Restripe' Command Status: Unknown
", + + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + + return $form; +} + +/** + * Callback for 'after'. + * + * @see ajax_command_after() + */ +function ajax_example_advanced_commands_after_callback($form, $form_state) { + $selector = '#after_div'; + + $commands = array(); + $commands[] = ajax_command_after($selector, "New 'after'..."); + $commands[] = ajax_command_replace("#after_status", "
Updated after_command_example " . date('r') . "
"); + return array('#type' => 'ajax', '#commands' => $commands); +} + +/** + * Callback for 'alert'. + * + * @see ajax_command_alert() + */ +function ajax_example_advanced_commands_alert_callback($form, $form_state) { + $commands = array(); + $commands[] = ajax_command_alert("Alert requested at " . date('r')); + return array('#type' => 'ajax', '#commands' => $commands); +} + +/** + * Callback for 'append'. + * + * @see ajax_command_append() + */ +function ajax_example_advanced_commands_append_callback($form, $form_state) { + $selector = '#append_div'; + + $commands = array(); + $commands[] = ajax_command_append($selector, "Stuff..."); + $commands[] = ajax_command_replace("#append_status", "
Updated append_command_example " . date('r') . "
"); + return array('#type' => 'ajax', '#commands' => $commands); +} + +/** + * Callback for 'before'. + * + * @see ajax_command_before() + */ +function ajax_example_advanced_commands_before_callback($form, $form_state) { + $selector = '#before_div'; + + $commands = array(); + $commands[] = ajax_command_before($selector, "New 'before'..."); + $commands[] = ajax_command_replace("#before_status", "
Updated before_command_example " . date('r') . "
"); + return array('#type' => 'ajax', '#commands' => $commands); +} + +/** + * Callback for 'changed'. + * + * @see ajax_command_changed() + */ +function ajax_example_advanced_commands_changed_callback($form, $form_state) { + $checkbox_value = $form_state['values']['changed_command_example']; + $checkbox_value_string = $checkbox_value ? "TRUE" : "FALSE"; + $commands = array(); + if ($checkbox_value) { + $commands[] = ajax_command_changed('#changed_div', '#changed_div_mark_this'); + } + else { + $commands[] = ajax_command_replace('#changed_div', "
This div can be marked as changed or not.
"); + } + $commands[] = ajax_command_replace("#changed_status", "
Updated changed_command_example to $checkbox_value_string: " . date('r') . "
"); + return array('#type' => 'ajax', '#commands' => $commands); +} + +/** + * Callback for 'css'. + * + * @see ajax_command_css() + */ +function ajax_example_advanced_commands_css_callback($form, $form_state) { + $selector = '#css_div'; + $color = $form_state['values']['css_command_example']; + + $commands = array(); + $commands[] = ajax_command_css($selector, array('background-color' => $color)); + $commands[] = ajax_command_replace("#css_status", "
Updated css_command_example to '{$color}' " . date('r') . "
"); + return array('#type' => 'ajax', '#commands' => $commands); +} + +/** + * Callback for 'data'. + * + * @see ajax_command_data() + */ +function ajax_example_advanced_commands_data_callback($form, $form_state) { + $selector = '#data_div'; + $text = $form_state['values']['data_command_example']; + list($key, $value) = preg_split('/=/', $text); + + $commands = array(); + $commands[] = ajax_command_data($selector, $key, $value); + $commands[] = ajax_command_replace("#data_status", "
Updated data_command_example with key=$key, value=$value; " . date('r') . "
"); + return array('#type' => 'ajax', '#commands' => $commands); +} + +/** + * Callback for 'html'. + * + * @see ajax_command_html() + */ +function ajax_example_advanced_commands_html_callback($form, $form_state) { + $text = $form_state['values']['html_command_example']; + + $commands = array(); + $commands[] = ajax_command_html('#html_div', $text); + $commands[] = ajax_command_replace("#html_status", "
Updated html_command_example with text=$text; " . date('r') . "
"); + return array('#type' => 'ajax', '#commands' => $commands); +} + +/** + * Callback for 'prepend'. + * + * @see ajax_command_prepend() + */ +function ajax_example_advanced_commands_prepend_callback($form, $form_state) { + $commands = array(); + $commands[] = ajax_command_prepend('#prepend_div', "Prepended Stuff..."); + $commands[] = ajax_command_replace("#prepend_status", "
Updated prepend_command_example " . date('r') . "
"); + return array('#type' => 'ajax', '#commands' => $commands); +} + +/** + * Callback for 'remove'. + * + * @see ajax_command_remove() + */ +function ajax_example_advanced_commands_remove_callback($form, $form_state) { + $commands = array(); + $should_remove = $form_state['values']['remove_command_example']; + $should_remove_string = $should_remove ? 'TRUE' : 'FALSE'; + if ($should_remove) { + $commands[] = ajax_command_remove('#remove_text'); + } + else { + $commands[] = ajax_command_html('#remove_div', "
text to be removed
"); + } + $commands[] = ajax_command_replace("#remove_status", "
Updated remove_command_example (value={$should_remove_string} " . date('r') . "
"); + return array('#type' => 'ajax', '#commands' => $commands); +} + +/** + * Callback for 'restripe'. + * + * Rebuilds the table with the selected number of rows. + */ +function ajax_example_advanced_commands_restripe_num_rows($form, $form_state) { + $num_rows = $form_state['values']['restripe_num_rows']; + $output = ""; + for ($i = 1; $i <= $num_rows; $i++) { + $output .= ""; + } + $output .= "
Row $i
"; + return $output; +} + +/** + * Callback for 'restripe'. + * + * @see ajax_command_restripe() + */ +function ajax_example_advanced_commands_restripe_callback($form, $form_state) { + $commands = array(); + $commands[] = ajax_command_restripe('#restripe_table'); + $commands[] = ajax_command_replace("#restripe_status", "
Restriped table " . date('r') . "
"); + return array('#type' => 'ajax', '#commands' => $commands); +} diff --git a/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_autocomplete.inc b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_autocomplete.inc new file mode 100644 index 00000000..90bbf0d5 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_autocomplete.inc @@ -0,0 +1,458 @@ + '
' . t("This example does a simplest possible autocomplete by username. You'll need a few users on your system for it to make sense.") . '
', + ); + + $form['user'] = array( + '#type' => 'textfield', + '#title' => t('Choose a user (or a people, depending on your usage preference)'), + // The autocomplete path is provided in hook_menu in ajax_example.module. + '#autocomplete_path' => 'examples/ajax_example/simple_user_autocomplete_callback', + ); + + return $form; +} + +/** + * This is just a copy of user_autocomplete(). + * + * It works simply by searching usernames (and of course in Drupal usernames + * are unique, so can be used for identifying a record.) + * + * The returned $matches array has + * * key: string which will be displayed once the autocomplete is selected + * * value: the value which will is displayed in the autocomplete pulldown. + * + * In the simplest cases (see user_autocomplete()) these are the same, and + * nothing needs to be done. However, more more complicated autocompletes + * require more work. Here we demonstrate the difference by displaying the UID + * along with the username in the dropdown. + * + * In the end, though, we'll be doing something with the value that ends up in + * the textfield, so it needs to uniquely identify the record we want to access. + * This is demonstrated in ajax_example_unique_autocomplete(). + * + * @param string $string + * The string that will be searched. + */ +function ajax_example_simple_user_autocomplete_callback($string = "") { + $matches = array(); + if ($string) { + $result = db_select('users') + ->fields('users', array('name', 'uid')) + ->condition('name', db_like($string) . '%', 'LIKE') + ->range(0, 10) + ->execute(); + foreach ($result as $user) { + // In the simplest case (see user_autocomplete), the key and the value are + // the same. Here we'll display the uid along with the username in the + // dropdown. + $matches[$user->name] = check_plain($user->name) . " (uid=$user->uid)"; + } + } + + drupal_json_output($matches); +} + +/** + * An autocomplete form to look up nodes by title. + * + * An autocomplete form which looks up nodes by title in the node table, + * but must keep track of the nid, because titles are certainly not guaranteed + * to be unique. + * + * @param array $form + * Form API form. + * @param array $form_state + * Form API form state. + * + * * @return array + * Form array. + */ +function ajax_example_unique_autocomplete($form, &$form_state) { + + $form['info'] = array( + '#markup' => '
' . t("This example does a node autocomplete by title. The difference between this and a username autocomplete is that the node title may not be unique, so we have to use the nid for uniqueness, placing it in a parseable location in the textfield.") . '
', + ); + + $form['node'] = array( + '#type' => 'textfield', + '#title' => t('Choose a node by title'), + // The autocomplete path is provided in hook_menu in ajax_example.module. + '#autocomplete_path' => 'examples/ajax_example/unique_node_autocomplete_callback', + ); + + $form['actions'] = array( + '#type' => 'actions', + ); + + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + + return $form; +} + +/** + * Node title validation handler. + * + * Validate handler to convert our string like "Some node title [3325]" into a + * nid. + * + * In case the user did not actually use the autocomplete or have a valid string + * there, we'll try to look up a result anyway giving it our best guess. + * + * Since the user chose a unique node, we must now use the same one in our + * submit handler, which means we need to look in the string for the nid. + * + * @param array $form + * Form API form. + * @param array $form_state + * Form API form state. + */ +function ajax_example_unique_autocomplete_validate($form, &$form_state) { + $title = $form_state['values']['node']; + $matches = array(); + + // This preg_match() looks for the last pattern like [33334] and if found + // extracts the numeric portion. + $result = preg_match('/\[([0-9]+)\]$/', $title, $matches); + if ($result > 0) { + // If $result is nonzero, we found a match and can use it as the index into + // $matches. + $nid = $matches[$result]; + // Verify that it's a valid nid. + $node = node_load($nid); + if (empty($node)) { + form_error($form['node'], t('Sorry, no node with nid %nid can be found', array('%nid' => $nid))); + return; + } + } + // BUT: Not everybody will have javascript turned on, or they might hit ESC + // and not use the autocomplete values offered. In that case, we can attempt + // to come up with a useful value. This is not absolutely necessary, and we + // *could* just emit a form_error() as below. + else { + $nid = db_select('node') + ->fields('node', array('nid')) + ->condition('title', db_like($title) . '%', 'LIKE') + ->range(0, 1) + ->execute() + ->fetchField(); + } + + // Now, if we somehow found a nid, assign it to the node. If we failed, emit + // an error. + if (!empty($nid)) { + $form_state['values']['node'] = $nid; + } + else { + form_error($form['node'], t('Sorry, no node starting with %title can be found', array('%title' => $title))); + } +} + +/** + * Submit handler for node lookup unique autocomplete example. + * + * Here the nid has already been placed in $form_state['values']['node'] by the + * validation handler. + * + * @param array $form + * Form API form. + * @param array $form_state + * Form API form state. + */ +function ajax_example_unique_autocomplete_submit($form, &$form_state) { + $node = node_load($form_state['values']['node']); + drupal_set_message(t('You found node %nid with title %title', array('%nid' => $node->nid, '%title' => $node->title))); +} + +/** + * Autocomplete callback for nodes by title. + * + * Searches for a node by title, but then identifies it by nid, so the actual + * returned value can be used later by the form. + * + * The returned $matches array has + * - key: The title, with the identifying nid in brackets, like "Some node + * title [3325]" + * - value: the title which will is displayed in the autocomplete pulldown. + * + * Note that we must use a key style that can be parsed successfully and + * unambiguously. For example, if we might have node titles that could have + * [3325] in them, then we'd have to use a more restrictive token. + * + * @param string $string + * The string that will be searched. + */ +function ajax_example_unique_node_autocomplete_callback($string = "") { + $matches = array(); + if ($string) { + $result = db_select('node') + ->fields('node', array('nid', 'title')) + ->condition('title', db_like($string) . '%', 'LIKE') + ->range(0, 10) + ->execute(); + foreach ($result as $node) { + $matches[$node->title . " [$node->nid]"] = check_plain($node->title); + } + } + + drupal_json_output($matches); +} + +/** + * Search by title and author. + * + * In this example, we'll look up nodes by title, but we want only nodes that + * have been authored by a particular user. That means that we'll have to make + * an autocomplete function which takes a username as an argument, and use + * #ajax to change the #autocomplete_path based on the selected user. + * + * Although the implementation of the validate handler may look complex, it's + * just ambitious. The idea here is: + * 1. Autcomplete to get a valid username. + * 2. Use #ajax to update the node element with a #autocomplete_callback that + * gives the context for the username. + * 3. Do an autcomplete on the node field that is limited by the username. + * + * @param array $form + * Form API form. + * @param array $form_state + * Form API form state. + * + * @return array + * Form API array. + */ +function ajax_example_node_by_author_autocomplete($form, &$form_state) { + + $form['intro'] = array( + '#markup' => '
' . t("This example uses a user autocomplete to dynamically change a node title autocomplete using #ajax. + This is a way to get past the fact that we have no other way to provide context to the autocomplete function. + It won't work very well unless you have a few users who have created some content that you can search for.") . '
', + ); + + $form['author'] = array( + '#type' => 'textfield', + '#title' => t('Choose the username that authored nodes you are interested in'), + // Since we just need simple user lookup, we can use the simplest function + // of them all, user_autocomplete(). + '#autocomplete_path' => 'user/autocomplete', + '#ajax' => array( + 'callback' => 'ajax_example_node_by_author_ajax_callback', + 'wrapper' => 'autocomplete-by-node-ajax-replace', + ), + ); + + // This form element with autocomplete will be replaced by #ajax whenever the + // author changes, allowing the search to be limited by user. + $form['node'] = array( + '#type' => 'textfield', + '#title' => t('Choose a node by title'), + '#prefix' => '
', + '#suffix' => '
', + '#disabled' => TRUE, + ); + + // When the author changes in the author field, we'll change the + // autocomplete_path to match. + if (!empty($form_state['values']['author'])) { + $author = user_load_by_name($form_state['values']['author']); + if (!empty($author)) { + $autocomplete_path = 'examples/ajax_example/node_by_author_autocomplete/' . $author->uid; + $form['node']['#autocomplete_path'] = $autocomplete_path; + $form['node']['#title'] = t('Choose a node title authored by %author', array('%author' => $author->name)); + $form['node']['#disabled'] = FALSE; + } + } + + $form['actions'] = array( + '#type' => 'actions', + ); + + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + + return $form; +} + +/** + * AJAX callback for author form element. + * + * @param array $form + * Form API form. + * @param array $form_state + * Form API form state. + * + * @return array + * Form API array. + */ +function ajax_example_node_by_author_ajax_callback($form, $form_state) { + return $form['node']; +} + +/** + * Validate handler to convert our title string into a nid. + * + * In case the user did not actually use the autocomplete or have a valid string + * there, we'll try to look up a result anyway giving it our best guess. + * + * Since the user chose a unique node, we must now use the same one in our + * submit handler, which means we need to look in the string for the nid. + * + * This handler looks complex because it's ambitious (and tries to punt and + * find a node if they've entered a valid username and part of a title), but + * you *could* just do a form_error() if nothing were found, forcing people to + * use the autocomplete to look up the relevant items. + * + * @param array $form + * Form API form. + * @param array $form_state + * Form API form state. + * + * @return array + * Form API array. + */ +function ajax_example_node_by_author_autocomplete_validate($form, &$form_state) { + $title = $form_state['values']['node']; + $author = $form_state['values']['author']; + $matches = array(); + + // We must have a valid user. + $account = user_load_by_name($author); + if (empty($account)) { + form_error($form['author'], t('You must choose a valid author username')); + return; + } + // This preg_match() looks for the last pattern like [33334] and if found + // extracts the numeric portion. + $result = preg_match('/\[([0-9]+)\]$/', $title, $matches); + if ($result > 0) { + // If $result is nonzero, we found a match and can use it as the index into + // $matches. + $nid = $matches[$result]; + // Verify that it's a valid nid. + $node = node_load($nid); + if (empty($node)) { + form_error($form['node'], t('Sorry, no node with nid %nid can be found', array('%nid' => $nid))); + return; + } + } + // BUT: Not everybody will have javascript turned on, or they might hit ESC + // and not use the autocomplete values offered. In that case, we can attempt + // to come up with a useful value. This is not absolutely necessary, and we + // *could* just emit a form_error() as below. Here we'll find the *first* + // matching title and assume that is adequate. + else { + $nid = db_select('node') + ->fields('node', array('nid')) + ->condition('uid', $account->uid) + ->condition('title', db_like($title) . '%', 'LIKE') + ->range(0, 1) + ->execute() + ->fetchField(); + } + + // Now, if we somehow found a nid, assign it to the node. If we failed, emit + // an error. + if (!empty($nid)) { + $form_state['values']['node'] = $nid; + } + else { + form_error($form['node'], t('Sorry, no node starting with %title can be found', array('%title' => $title))); + } +} + +/** + * Submit handler for node lookup unique autocomplete example. + * + * Here the nid has already been placed in $form_state['values']['node'] by the + * validation handler. + * + * @param array $form + * Form API form. + * @param array $form_state + * Form API form state. + * + * @return array + * Form API array. + */ +function ajax_example_node_by_author_autocomplete_submit($form, &$form_state) { + $node = node_load($form_state['values']['node']); + $account = user_load($node->uid); + drupal_set_message(t('You found node %nid with title !title_link, authored by !user_link', + array( + '%nid' => $node->nid, + '!title_link' => l($node->title, 'node/' . $node->nid), + '!user_link' => theme('username', array('account' => $account)), + ) + )); +} + +/** + * Autocomplete callback for nodes by title but limited by author. + * + * Searches for a node by title given the passed-in author username. + * + * The returned $matches array has + * - key: The title, with the identifying nid in brackets, like "Some node + * title [3325]" + * - value: the title which will is displayed in the autocomplete pulldown. + * + * Note that we must use a key style that can be parsed successfully and + * unambiguously. For example, if we might have node titles that could have + * [3325] in them, then we'd have to use a more restrictive token. + * + * @param int $author_uid + * The author username to limit the search. + * @param string $string + * The string that will be searched. + */ +function ajax_example_node_by_author_node_autocomplete_callback($author_uid, $string = "") { + $matches = array(); + if ($author_uid > 0 && trim($string)) { + $result = db_select('node') + ->fields('node', array('nid', 'title')) + ->condition('uid', $author_uid) + ->condition('title', db_like($string) . '%', 'LIKE') + ->range(0, 10) + ->execute(); + foreach ($result as $node) { + $matches[$node->title . " [$node->nid]"] = check_plain($node->title); + } + } + + drupal_json_output($matches); +} diff --git a/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_graceful_degradation.inc b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_graceful_degradation.inc new file mode 100644 index 00000000..fe7cfb8d --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_graceful_degradation.inc @@ -0,0 +1,668 @@ + 'fieldset', + ); + $form['dropdown_first_fieldset']['dropdown_first'] = array( + '#type' => 'select', + '#title' => 'Instrument Type', + '#options' => $options_first, + '#attributes' => array('class' => array('enabled-for-ajax')), + + // The '#ajax' property allows us to bind a callback to the server whenever + // this form element changes. See ajax_example_autocheckboxes and + // ajax_example_dependent_dropdown in ajax_example.module for more details. + '#ajax' => array( + 'callback' => 'ajax_example_dependent_dropdown_degrades_first_callback', + 'wrapper' => 'dropdown-second-replace', + ), + ); + + // This simply allows us to demonstrate no-javascript use without + // actually turning off javascript in the browser. Removing the #ajax + // element turns off AJAX behaviors on that element and as a result + // ajax.js doesn't get loaded. This is for demonstration purposes only. + if ($no_js_use) { + unset($form['dropdown_first_fieldset']['dropdown_first']['#ajax']); + } + + // Since we don't know if the user has js or not, we always need to output + // this element, then hide it with with css if javascript is enabled. + $form['dropdown_first_fieldset']['continue_to_second'] = array( + '#type' => 'submit', + '#value' => t('Choose'), + '#attributes' => array('class' => array('next-button')), + ); + + $form['dropdown_second_fieldset'] = array( + '#type' => 'fieldset', + ); + $form['dropdown_second_fieldset']['dropdown_second'] = array( + '#type' => 'select', + '#title' => $options_first[$selected] . ' ' . t('Instruments'), + '#prefix' => '', + '#attributes' => array('class' => array('enabled-for-ajax')), + // When the form is rebuilt during processing (either AJAX or multistep), + // the $selected variable will now have the new value and so the options + // will change. + '#options' => _ajax_example_get_second_dropdown_options($selected), + ); + $form['dropdown_second_fieldset']['submit'] = array( + '#type' => 'submit', + '#value' => t('OK'), + // This class allows attached js file to override the disabled attribute, + // since it's not necessary in ajax-enabled form. + '#attributes' => array('class' => array('enabled-for-ajax')), + ); + + // Disable dropdown_second if a selection has not been made on dropdown_first. + if (empty($form_state['values']['dropdown_first'])) { + $form['dropdown_second_fieldset']['dropdown_second']['#disabled'] = TRUE; + $form['dropdown_second_fieldset']['dropdown_second']['#description'] = t('You must make your choice on the first dropdown before changing this second one.'); + $form['dropdown_second_fieldset']['submit']['#disabled'] = TRUE; + } + + return $form; +} + +/** + * Submit function for ajax_example_dependent_dropdown_degrades(). + */ +function ajax_example_dependent_dropdown_degrades_submit($form, &$form_state) { + + // Now handle the case of the next, previous, and submit buttons. + // only submit will result in actual submission, all others rebuild. + switch ($form_state['triggering_element']['#value']) { + case t('OK'): + // Submit: We're done. + drupal_set_message(t('Your values have been submitted. dropdown_first=@first, dropdown_second=@second', array('@first' => $form_state['values']['dropdown_first'], '@second' => $form_state['values']['dropdown_second']))); + return; + } + // 'Choose' or anything else will cause rebuild of the form and present + // it again. + $form_state['rebuild'] = TRUE; +} + +/** + * Selects just the second dropdown to be returned for re-rendering. + * + * @return array + * Renderable array (the second dropdown). + */ +function ajax_example_dependent_dropdown_degrades_first_callback($form, $form_state) { + return $form['dropdown_second_fieldset']['dropdown_second']; +} + + +/** + * Dynamically-enabled form with graceful no-JS degradation. + * + * Example of a form with portions dynamically enabled or disabled, but + * with graceful degradation in the case of no javascript. + * + * The idea here is that certain parts of the form don't need to be displayed + * unless a given option is selected, but then they should be displayed and + * configured. + * + * The third $no_js_use argument is strictly for demonstrating operation + * without javascript, without making the user/developer turn off javascript. + */ +function ajax_example_dynamic_sections($form, &$form_state, $no_js_use = FALSE) { + + // Attach the CSS and JS we need to show this with and without javascript. + // Without javascript we need an extra "Choose" button, and this is + // hidden when we have javascript enabled. + $form['#attached']['css'] = array( + drupal_get_path('module', 'ajax_example') . '/ajax_example.css', + ); + $form['#attached']['js'] = array( + drupal_get_path('module', 'ajax_example') . '/ajax_example.js', + ); + $form['description'] = array( + '#type' => 'markup', + '#markup' => '
' . t('This example demonstrates a form which dynamically creates various sections based on the configuration in the form. + It deliberately allows graceful degradation to a non-javascript environment. + In a non-javascript environment, the "Choose" button next to the select control + is displayed; in a javascript environment it is hidden by the module CSS. +

The basic idea here is that the form is built up based on + the selection in the question_type_select field, and it is built the same + whether we are in a javascript/AJAX environment or not. +

+ Try the AJAX version and the simulated-non-AJAX version. + ', array('!ajax_link' => url('examples/ajax_example/dynamic_sections'), '!non_ajax_link' => url('examples/ajax_example/dynamic_sections_no_js'))) . '
', + ); + $form['question_type_select'] = array( + '#type' => 'select', + '#title' => t('Question style'), + '#options' => drupal_map_assoc( + array( + t('Choose question style'), + t('Multiple Choice'), + t('True/False'), + t('Fill-in-the-blanks'), + ) + ), + '#ajax' => array( + 'wrapper' => 'questions-fieldset-wrapper', + 'callback' => 'ajax_example_dynamic_sections_select_callback', + ), + ); + // The CSS for this module hides this next button if JS is enabled. + $form['question_type_submit'] = array( + '#type' => 'submit', + '#value' => t('Choose'), + '#attributes' => array('class' => array('next-button')), + // No need to validate when submitting this. + '#limit_validation_errors' => array(), + '#validate' => array(), + ); + + // This simply allows us to demonstrate no-javascript use without + // actually turning off javascript in the browser. Removing the #ajax + // element turns off AJAX behaviors on that element and as a result + // ajax.js doesn't get loaded. + if ($no_js_use) { + // Remove the #ajax from the above, so ajax.js won't be loaded. + unset($form['question_type_select']['#ajax']); + } + + // This fieldset just serves as a container for the part of the form + // that gets rebuilt. + $form['questions_fieldset'] = array( + '#type' => 'fieldset', + // These provide the wrapper referred to in #ajax['wrapper'] above. + '#prefix' => '
', + '#suffix' => '
', + ); + if (!empty($form_state['values']['question_type_select'])) { + + $form['questions_fieldset']['question'] = array( + '#markup' => t('Who was the first president of the U.S.?'), + ); + $question_type = $form_state['values']['question_type_select']; + + switch ($question_type) { + case t('Multiple Choice'): + $form['questions_fieldset']['question'] = array( + '#type' => 'radios', + '#title' => t('Who was the first president of the United States'), + '#options' => drupal_map_assoc( + array( + t('George Bush'), + t('Adam McGuire'), + t('Abraham Lincoln'), + t('George Washington'), + ) + ), + ); + break; + + case t('True/False'): + $form['questions_fieldset']['question'] = array( + '#type' => 'radios', + '#title' => t('Was George Washington the first president of the United States?'), + '#options' => array(t('George Washington') => t("True"), 0 => t("False")), + '#description' => t('Click "True" if you think George Washington was the first president of the United States.'), + ); + break; + + case t('Fill-in-the-blanks'): + $form['questions_fieldset']['question'] = array( + '#type' => 'textfield', + '#title' => t('Who was the first president of the United States'), + '#description' => t('Please type the correct answer to the question.'), + ); + break; + } + + $form['questions_fieldset']['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit your answer'), + ); + } + return $form; +} + +/** + * Validation function for ajax_example_dynamic_sections(). + */ +function ajax_example_dynamic_sections_validate($form, &$form_state) { + $answer = $form_state['values']['question']; + if ($answer !== t('George Washington')) { + form_set_error('question', t('Wrong answer. Try again. (Hint: The right answer is "George Washington".)')); + } +} + +/** + * Submit function for ajax_example_dynamic_sections(). + */ +function ajax_example_dynamic_sections_submit($form, &$form_state) { + // This is only executed when a button is pressed, not when the AJAXified + // select is changed. + // Now handle the case of the next, previous, and submit buttons. + // Only submit will result in actual submission, all others rebuild. + switch ($form_state['triggering_element']['#value']) { + case t('Submit your answer'): + // Submit: We're done. + $form_state['rebuild'] = FALSE; + $answer = $form_state['values']['question']; + + // Special handling for the checkbox. + if ($answer == 1 && $form['questions_fieldset']['question']['#type'] == 'checkbox') { + $answer = $form['questions_fieldset']['question']['#title']; + } + if ($answer === t('George Washington')) { + drupal_set_message(t('You got the right answer: @answer', array('@answer' => $answer))); + } + else { + drupal_set_message(t('Sorry, your answer (@answer) is wrong', array('@answer' => $answer))); + } + return; + + // Any other form element will cause rebuild of the form and present + // it again. + case t('Choose'): + $form_state['values']['question_type_select'] = $form_state['input']['question_type_select']; + // Fall through. + default: + $form_state['rebuild'] = TRUE; + } +} + +/** + * Callback for the select element. + * + * This just selects and returns the questions_fieldset. + */ +function ajax_example_dynamic_sections_select_callback($form, $form_state) { + return $form['questions_fieldset']; +} + +/** + * Wizard form. + * + * This example is a classic wizard, where a different and sequential form + * is presented on each step of the form. + * + * In the AJAX version, the form is replaced for each wizard section. In the + * multistep version, it causes a new page load. + * + * @param array $form + * Form API form. + * @param array $form_state + * Form API form. + * @param bool $no_js_use + * Used for this demonstration only. If true means that the form should be + * built using a simulated no-javascript approach (ajax.js will not be + * loaded.) + * + * @return array + * Form array. + */ +function ajax_example_wizard($form, &$form_state, $no_js_use = FALSE) { + + // Provide a wrapper around the entire form, since we'll replace the whole + // thing with each submit. + $form['#prefix'] = '
'; + $form['#suffix'] = '
'; + // We want to deal with hierarchical form values. + $form['#tree'] = TRUE; + $form['description'] = array( + '#markup' => '
' . t('This example is a step-by-step wizard. The AJAX version does it without page reloads; the multistep version is the same code but simulates a non-javascript environment, showing it with page reloads.', + array('!ajax' => url('examples/ajax_example/wizard'), '!multistep' => url('examples/ajax_example/wizard_no_js'))) + . '
', + ); + + // $form_state['storage'] has no specific drupal meaning, but it is + // traditional to keep variables for multistep forms there. + $step = empty($form_state['storage']['step']) ? 1 : $form_state['storage']['step']; + $form_state['storage']['step'] = $step; + + switch ($step) { + case 1: + $form['step1'] = array( + '#type' => 'fieldset', + '#title' => t('Step 1: Personal details'), + ); + $form['step1']['name'] = array( + '#type' => 'textfield', + '#title' => t('Your name'), + '#default_value' => empty($form_state['values']['step1']['name']) ? '' : $form_state['values']['step1']['name'], + '#required' => TRUE, + ); + break; + + case 2: + $form['step2'] = array( + '#type' => 'fieldset', + '#title' => t('Step 2: Street address info'), + ); + $form['step2']['address'] = array( + '#type' => 'textfield', + '#title' => t('Your street address'), + '#default_value' => empty($form_state['values']['step2']['address']) ? '' : $form_state['values']['step2']['address'], + '#required' => TRUE, + ); + break; + + case 3: + $form['step3'] = array( + '#type' => 'fieldset', + '#title' => t('Step 3: City info'), + ); + $form['step3']['city'] = array( + '#type' => 'textfield', + '#title' => t('Your city'), + '#default_value' => empty($form_state['values']['step3']['city']) ? '' : $form_state['values']['step3']['city'], + '#required' => TRUE, + ); + break; + } + if ($step == 3) { + $form['submit'] = array( + '#type' => 'submit', + '#value' => t("Submit your information"), + ); + } + if ($step < 3) { + $form['next'] = array( + '#type' => 'submit', + '#value' => t('Next step'), + '#ajax' => array( + 'wrapper' => 'wizard-form-wrapper', + 'callback' => 'ajax_example_wizard_callback', + ), + ); + } + if ($step > 1) { + $form['prev'] = array( + '#type' => 'submit', + '#value' => t("Previous step"), + + // Since all info will be discarded, don't validate on 'prev'. + '#limit_validation_errors' => array(), + // #submit is required to use #limit_validation_errors + '#submit' => array('ajax_example_wizard_submit'), + '#ajax' => array( + 'wrapper' => 'wizard-form-wrapper', + 'callback' => 'ajax_example_wizard_callback', + ), + ); + } + + // This simply allows us to demonstrate no-javascript use without + // actually turning off javascript in the browser. Removing the #ajax + // element turns off AJAX behaviors on that element and as a result + // ajax.js doesn't get loaded. + // For demonstration only! You don't need this. + if ($no_js_use) { + // Remove the #ajax from the above, so ajax.js won't be loaded. + // For demonstration only. + unset($form['next']['#ajax']); + unset($form['prev']['#ajax']); + } + + return $form; +} + +/** + * Wizard callback function. + * + * @param array $form + * Form API form. + * @param array $form_state + * Form API form. + * + * @return array + * Form array. + */ +function ajax_example_wizard_callback($form, $form_state) { + return $form; +} + +/** + * Submit function for ajax_example_wizard. + * + * In AJAX this is only submitted when the final submit button is clicked, + * but in the non-javascript situation, it is submitted with every + * button click. + */ +function ajax_example_wizard_submit($form, &$form_state) { + + // Save away the current information. + $current_step = 'step' . $form_state['storage']['step']; + if (!empty($form_state['values'][$current_step])) { + $form_state['storage']['values'][$current_step] = $form_state['values'][$current_step]; + } + + // Increment or decrement the step as needed. Recover values if they exist. + if ($form_state['triggering_element']['#value'] == t('Next step')) { + $form_state['storage']['step']++; + // If values have already been entered for this step, recover them from + // $form_state['storage'] to pre-populate them. + $step_name = 'step' . $form_state['storage']['step']; + if (!empty($form_state['storage']['values'][$step_name])) { + $form_state['values'][$step_name] = $form_state['storage']['values'][$step_name]; + } + } + if ($form_state['triggering_element']['#value'] == t('Previous step')) { + $form_state['storage']['step']--; + // Recover our values from $form_state['storage'] to pre-populate them. + $step_name = 'step' . $form_state['storage']['step']; + $form_state['values'][$step_name] = $form_state['storage']['values'][$step_name]; + } + + // If they're done, submit. + if ($form_state['triggering_element']['#value'] == t('Submit your information')) { + $value_message = t('Your information has been submitted:') . ' '; + foreach ($form_state['storage']['values'] as $step => $values) { + $value_message .= "$step: "; + foreach ($values as $key => $value) { + $value_message .= "$key=$value, "; + } + } + drupal_set_message($value_message); + $form_state['rebuild'] = FALSE; + return; + } + + // Otherwise, we still have work to do. + $form_state['rebuild'] = TRUE; +} + + +/** + * Form with 'add more' and 'remove' buttons. + * + * This example shows a button to "add more" - add another textfield, and + * the corresponding "remove" button. + * + * It works equivalently with javascript or not, and does the same basic steps + * either way. + * + * The basic idea is that we build the form based on the setting of + * $form_state['num_names']. The custom submit functions for the "add-one" + * and "remove-one" buttons increment and decrement $form_state['num_names'] + * and then force a rebuild of the form. + * + * The $no_js_use argument is simply for demonstration: When set, it prevents + * '#ajax' from being set, thus making the example behave as if javascript + * were disabled in the browser. + */ +function ajax_example_add_more($form, &$form_state, $no_js_use = FALSE) { + $form['description'] = array( + '#markup' => '
' . t('This example shows an add-more and a remove-last button. The AJAX version does it without page reloads; the non-js version is the same code but simulates a non-javascript environment, showing it with page reloads.', + array('!ajax' => url('examples/ajax_example/add_more'), '!multistep' => url('examples/ajax_example/add_more_no_js'))) + . '
', + ); + + // Because we have many fields with the same values, we have to set + // #tree to be able to access them. + $form['#tree'] = TRUE; + $form['names_fieldset'] = array( + '#type' => 'fieldset', + '#title' => t('People coming to the picnic'), + // Set up the wrapper so that AJAX will be able to replace the fieldset. + '#prefix' => '
', + '#suffix' => '
', + ); + + // Build the fieldset with the proper number of names. We'll use + // $form_state['num_names'] to determine the number of textfields to build. + if (empty($form_state['num_names'])) { + $form_state['num_names'] = 1; + } + for ($i = 0; $i < $form_state['num_names']; $i++) { + $form['names_fieldset']['name'][$i] = array( + '#type' => 'textfield', + '#title' => t('Name'), + ); + } + $form['names_fieldset']['add_name'] = array( + '#type' => 'submit', + '#value' => t('Add one more'), + '#submit' => array('ajax_example_add_more_add_one'), + // See the examples in ajax_example.module for more details on the + // properties of #ajax. + '#ajax' => array( + 'callback' => 'ajax_example_add_more_callback', + 'wrapper' => 'names-fieldset-wrapper', + ), + ); + if ($form_state['num_names'] > 1) { + $form['names_fieldset']['remove_name'] = array( + '#type' => 'submit', + '#value' => t('Remove one'), + '#submit' => array('ajax_example_add_more_remove_one'), + '#ajax' => array( + 'callback' => 'ajax_example_add_more_callback', + 'wrapper' => 'names-fieldset-wrapper', + ), + ); + } + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + + // This simply allows us to demonstrate no-javascript use without + // actually turning off javascript in the browser. Removing the #ajax + // element turns off AJAX behaviors on that element and as a result + // ajax.js doesn't get loaded. + // For demonstration only! You don't need this. + if ($no_js_use) { + // Remove the #ajax from the above, so ajax.js won't be loaded. + if (!empty($form['names_fieldset']['remove_name']['#ajax'])) { + unset($form['names_fieldset']['remove_name']['#ajax']); + } + unset($form['names_fieldset']['add_name']['#ajax']); + } + + return $form; +} + +/** + * Callback for both ajax-enabled buttons. + * + * Selects and returns the fieldset with the names in it. + */ +function ajax_example_add_more_callback($form, $form_state) { + return $form['names_fieldset']; +} + +/** + * Submit handler for the "add-one-more" button. + * + * Increments the max counter and causes a rebuild. + */ +function ajax_example_add_more_add_one($form, &$form_state) { + $form_state['num_names']++; + $form_state['rebuild'] = TRUE; +} + +/** + * Submit handler for the "remove one" button. + * + * Decrements the max counter and causes a form rebuild. + */ +function ajax_example_add_more_remove_one($form, &$form_state) { + if ($form_state['num_names'] > 1) { + $form_state['num_names']--; + } + $form_state['rebuild'] = TRUE; +} + +/** + * Final submit handler. + * + * Reports what values were finally set. + */ +function ajax_example_add_more_submit($form, &$form_state) { + $output = t('These people are coming to the picnic: @names', + array( + '@names' => implode(', ', $form_state['values']['names_fieldset']['name']), + ) + ); + drupal_set_message($output); +} +/** + * @} End of "defgroup ajax_degradation_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_misc.inc b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_misc.inc new file mode 100644 index 00000000..0b8084bb --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_misc.inc @@ -0,0 +1,116 @@ +use-ajax class applied to it, so if +javascript is enabled, ajax.js will try to submit it via an AJAX call instead +of a normal page load. The URL also contains the '/nojs/' magic string, which +is stripped if javascript is enabled, allowing the server code to tell by the +URL whether JS was enabled or not, letting it do different things based on that."); + $output = "
" . $explanation . "
"; + // The use-ajax class is special, so that the link will call without causing + // a page reload. Note the /nojs portion of the path - if javascript is + // enabled, this part will be stripped from the path before it is called. + $link = l(t('Click here'), 'ajax_link_callback/nojs/', array('attributes' => array('class' => array('use-ajax')))); + $output .= "
$link
"; + return $output; +} + +/** + * AJAX-enabled link in a renderable array. + * + * Demonstrates a clickable AJAX-enabled link using a renderable array with the + * #ajax property. + * + * A link that is constructed as a renderable array can have the #ajax property, + * which ensures that the link submission is done without a page refresh. The + * href of the link is used as the ajax callback, but it degrades gracefully + * without JavaScript because if the 'nojs' portion of the href is not stripped + * out by js, the callback will return content as required for a full page + * reload. + * + * The necessary JavaScript file, ajax.js, will be included on the page + * automatically. + * + * @return array + * Form API array. + */ +function ajax_example_render_link_ra() { + $explanation = " +The link below has been rendered as an element with the #ajax property, so if +javascript is enabled, ajax.js will try to submit it via an AJAX call instead +of a normal page load. The URL also contains the '/nojs/' magic string, which +is stripped if javascript is enabled, allowing the server code to tell by the +URL whether JS was enabled or not, letting it do different things based on that."; + $build['my_div'] = array( + '#markup' => $explanation . '
', + ); + $build['ajax_link'] = array( + '#type' => 'link', + '#title' => t('Click here'), + // Note the /nojs portion of the href - if javascript is enabled, + // this part will be stripped from the path before it is called. + '#href' => 'ajax_link_callback/nojs/', + '#id' => 'ajax_link', + '#ajax' => array( + 'wrapper' => 'myDiv', + 'method' => 'html', + ), + ); + return $build; +} + +/** + * Callback for link example. + * + * Takes different logic paths based on whether Javascript was enabled. + * If $type == 'ajax', it tells this function that ajax.js has rewritten + * the URL and thus we are doing an AJAX and can return an array of commands. + * + * @param string $type + * Either 'ajax' or 'nojs. Type is simply the normal URL argument to this URL. + * + * @return string|array + * If $type == 'ajax', returns an array of AJAX Commands. + * Otherwise, just returns the content, which will end up being a page. + * + * @ingroup ajax_example + */ +function ajax_link_response($type = 'ajax') { + if ($type == 'ajax') { + $output = t("This is some content delivered via AJAX"); + $commands = array(); + // See ajax_example_advanced.inc for more details on the available commands + // and how to use them. + $commands[] = ajax_command_append('#myDiv', $output); + $page = array('#type' => 'ajax', '#commands' => $commands); + ajax_deliver($page); + } + else { + $output = t("This is some content delivered via a page load."); + return $output; + } +} diff --git a/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_node_form_alter.inc b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_node_form_alter.inc new file mode 100644 index 00000000..3dd073bd --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_node_form_alter.inc @@ -0,0 +1,149 @@ + 'checkbox', + '#title' => t('AJAX Example 1'), + '#description' => t('Enable to show second field.'), + '#default_value' => $node->ajax_example['example_1'], + '#ajax' => array( + 'callback' => 'ajax_example_form_node_callback', + 'wrapper' => 'ajax-example-form-node', + 'effect' => 'fade', + ), + ); + $form['container'] = array( + '#prefix' => '
', + '#suffix' => '
', + ); + + // If the state values exist and 'ajax_example_1' state value is 1 or + // if the state values don't exist and 'example1' variable is 1 then + // display the ajax_example_2 field. + if (!empty($form_state['values']['ajax_example_1']) && $form_state['values']['ajax_example_1'] == 1 + || empty($form_state['values']) && $node->ajax_example['example_1']) { + + $form['container']['ajax_example_2'] = array( + '#type' => 'textfield', + '#title' => t('AJAX Example 2'), + '#description' => t('AJAX Example 2'), + '#default_value' => empty($form_state['values']['ajax_example_2']) ? $node->ajax_example['example_2'] : $form_state['values']['ajax_example_2'], + ); + } +} + +/** + * Returns changed part of the form. + * + * @return array + * Form API array. + * + * @see ajax_example_form_node_form_alter() + */ +function ajax_example_form_node_callback($form, $form_state) { + return $form['container']; +} + +/** + * Implements hook_node_submit(). + * @see ajax_example_form_node_form_alter() + */ +function ajax_example_node_submit($node, $form, &$form_state) { + $values = $form_state['values']; + // Move the new data into the node object. + $node->ajax_example['example_1'] = $values['ajax_example_1']; + // Depending on the state of ajax_example_1; it may not exist. + $node->ajax_example['example_2'] = isset($values['ajax_example_2']) ? $values['ajax_example_2'] : ''; +} + +/** + * Implements hook_node_prepare(). + * + * @see ajax_example_form_node_form_alter() + */ +function ajax_example_node_prepare($node) { + if (empty($node->ajax_example)) { + // Set default values, since this only runs when adding a new node. + $node->ajax_example['example_1'] = 0; + $node->ajax_example['example_2'] = ''; + } +} + +/** + * Implements hook_node_load(). + * + * @see ajax_example_form_node_form_alter() + */ +function ajax_example_node_load($nodes, $types) { + $result = db_query('SELECT * FROM {ajax_example_node_form_alter} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes)))->fetchAllAssoc('nid'); + + foreach ($nodes as &$node) { + $node->ajax_example['example_1'] + = isset($result[$node->nid]->example_1) ? + $result[$node->nid]->example_1 : 0; + $node->ajax_example['example_2'] + = isset($result[$node->nid]->example_2) ? + $result[$node->nid]->example_2 : ''; + } +} + +/** + * Implements hook_node_insert(). + * + * @see ajax_example_form_node_form_alter() + */ +function ajax_example_node_insert($node) { + if (isset($node->ajax_example)) { + db_insert('ajax_example_node_form_alter') + ->fields(array( + 'nid' => $node->nid, + 'example_1' => $node->ajax_example['example_1'], + 'example_2' => $node->ajax_example['example_2'], + )) + ->execute(); + } +} + +/** + * Implements hook_node_update(). + * @see ajax_example_form_node_form_alter() + */ +function ajax_example_node_update($node) { + if (db_select('ajax_example_node_form_alter', 'a')->fields('a')->condition('nid', $node->nid, '=')->execute()->fetchAssoc()) { + db_update('ajax_example_node_form_alter') + ->fields(array( + 'example_1' => $node->ajax_example['example_1'], + 'example_2' => $node->ajax_example['example_2'], + )) + ->condition('nid', $node->nid) + ->execute(); + } + else { + // Cleaner than doing it again. + ajax_example_node_insert($node); + } +} + +/** + * Implements hook_node_delete(). + * @see ajax_example_form_node_form_alter() + */ +function ajax_example_node_delete($node) { + db_delete('ajax_example_node_form_alter') + ->condition('nid', $node->nid) + ->execute(); +} diff --git a/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_progressbar.inc b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_progressbar.inc new file mode 100644 index 00000000..b611150c --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/ajax_example/ajax_example_progressbar.inc @@ -0,0 +1,116 @@ + '
', + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + '#ajax' => array( + // Here we set up our AJAX callback handler. + 'callback' => 'ajax_example_progressbar_callback', + // Tell FormAPI about our progress bar. + 'progress' => array( + 'type' => 'bar', + 'message' => t('Execute..'), + // Have the progress bar access this URL path. + 'url' => url('examples/ajax_example/progressbar/progress/' . $form_state['time']), + // The time interval for the progress bar to check for updates. + 'interval' => 1000, + ), + ), + ); + + return $form; +} + +/** + * Get the progress bar execution status, as JSON. + * + * This is the menu handler for + * examples/ajax_example/progressbar/progress/$time. + * + * This function is our wholly arbitrary job that we're checking the status for. + * In this case, we're reading a system variable that is being updated by + * ajax_example_progressbar_callback(). + * + * We set up the AJAX progress bar to check the status every second, so this + * will execute about once every second. + * + * The progress bar JavaScript accepts two values: message and percentage. We + * set those in an array and in the end convert it JSON for sending back to the + * client-side JavaScript. + * + * @param int $time + * Timestamp. + * + * @see ajax_example_progressbar_callback() + */ +function ajax_example_progressbar_progress($time) { + $progress = array( + 'message' => t('Starting execute...'), + 'percentage' => -1, + ); + + $completed_percentage = variable_get('example_progressbar_' . $time, 0); + + if ($completed_percentage) { + $progress['message'] = t('Executing...'); + $progress['percentage'] = $completed_percentage; + } + + drupal_json_output($progress); +} + +/** + * Our submit handler. + * + * This handler spends some time changing a variable and sleeping, and then + * finally returns a form element which marks the #progress-status DIV as + * completed. + * + * While this is occurring, ajax_example_progressbar_progress() will be called + * a number of times by the client-sid JavaScript, which will poll the variable + * being set here. + * + * @see ajax_example_progressbar_progress() + */ +function ajax_example_progressbar_callback($form, &$form_state) { + $variable_name = 'example_progressbar_' . $form_state['time']; + $commands = array(); + + variable_set($variable_name, 10); + sleep(2); + variable_set($variable_name, 40); + sleep(2); + variable_set($variable_name, 70); + sleep(2); + variable_set($variable_name, 90); + sleep(2); + variable_del($variable_name); + + $commands[] = ajax_command_html('#progress-status', t('Executed.')); + + return array( + '#type' => 'ajax', + '#commands' => $commands, + ); +} diff --git a/sites/all/modules/contrib/dev/examples/batch_example/batch_example.info b/sites/all/modules/contrib/dev/examples/batch_example/batch_example.info new file mode 100644 index 00000000..64760ff7 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/batch_example/batch_example.info @@ -0,0 +1,12 @@ +name = Batch example +description = An example outlining how a module can define batch operations. +package = Example modules +core = 7.x +files[] = batch_example.test + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/batch_example/batch_example.install b/sites/all/modules/contrib/dev/examples/batch_example/batch_example.install new file mode 100644 index 00000000..4ce14503 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/batch_example/batch_example.install @@ -0,0 +1,85 @@ +fetchField(); + // A place to store messages during the run. + $sandbox['messages'] = array(); + // Last node read via the query. + $sandbox['current_node'] = -1; + } + + // Process nodes by groups of 10 (arbitrary value). + // When a group is processed, the batch update engine determines + // whether it should continue processing in the same request or provide + // progress feedback to the user and wait for the next request. + $limit = 10; + + // Retrieve the next group of nids. + $result = db_select('node', 'n') + ->fields('n', array('nid')) + ->orderBy('n.nid', 'ASC') + ->where('n.nid > :nid', array(':nid' => $sandbox['current_node'])) + ->extend('PagerDefault') + ->limit($limit) + ->execute(); + foreach ($result as $row) { + // Here we actually perform a dummy 'update' on the current node. + $node = db_query('SELECT nid FROM {node} WHERE nid = :nid', array(':nid' => $row->nid))->fetchField(); + + // Update our progress information. + $sandbox['progress']++; + $sandbox['current_node'] = $row->nid; + } + + // Set the "finished" status, to tell batch engine whether this function + // needs to run again. If you set a float, this will indicate the progress + // of the batch so the progress bar will update. + $sandbox['#finished'] = ($sandbox['progress'] >= $sandbox['max']) ? TRUE : ($sandbox['progress'] / $sandbox['max']); + + // Set up a per-run message; Make a copy of $sandbox so we can change it. + // This is simply a debugging stanza to illustrate how to capture status + // from each pass through hook_update_N(). + $sandbox_status = $sandbox; + // Don't want them in the output. + unset($sandbox_status['messages']); + $sandbox['messages'][] = t('$sandbox=') . print_r($sandbox_status, TRUE); + + if ($sandbox['#finished']) { + // hook_update_N() may optionally return a string which will be displayed + // to the user. + $final_message = '
  • ' . implode('
  • ', $sandbox['messages']) . "
"; + return t('The batch_example demonstration update did what it was supposed to do: @message', array('@message' => $final_message)); + } +} diff --git a/sites/all/modules/contrib/dev/examples/batch_example/batch_example.module b/sites/all/modules/contrib/dev/examples/batch_example/batch_example.module new file mode 100644 index 00000000..f16509e9 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/batch_example/batch_example.module @@ -0,0 +1,318 @@ + 'Batch example', + 'description' => 'Example of Drupal batch processing', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('batch_example_simple_form'), + 'access callback' => TRUE, + ); + + return $items; +} + +/** + * Form builder function to allow choice of which batch to run. + */ +function batch_example_simple_form() { + $form['description'] = array( + '#type' => 'markup', + '#markup' => t('This example offers two different batches. The first does 1000 identical operations, each completed in on run; the second does 20 operations, but each takes more than one run to operate if there are more than 5 nodes.'), + ); + $form['batch'] = array( + '#type' => 'select', + '#title' => 'Choose batch', + '#options' => array( + 'batch_1' => t('batch 1 - 1000 operations, each loading the same node'), + 'batch_2' => t('batch 2 - 20 operations. each one loads all nodes 5 at a time'), + ), + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => 'Go', + ); + + // If no nodes, prevent submission. + // Find out if we have a node to work with. Otherwise it won't work. + $nid = batch_example_lowest_nid(); + if (empty($nid)) { + drupal_set_message(t("You don't currently have any nodes, and this example requires a node to work with. As a result, this form is disabled.")); + $form['submit']['#disabled'] = TRUE; + } + return $form; +} + +/** + * Submit handler. + * + * @param array $form + * Form API form. + * @param array $form_state + * Form API form. + */ +function batch_example_simple_form_submit($form, &$form_state) { + $function = 'batch_example_' . $form_state['values']['batch']; + + // Reset counter for debug information. + $_SESSION['http_request_count'] = 0; + + // Execute the function named batch_example_1 or batch_example_2. + $batch = $function(); + batch_set($batch); +} + + +/** + * Batch 1 definition: Load the node with the lowest nid 1000 times. + * + * This creates an operations array defining what batch 1 should do, including + * what it should do when it's finished. In this case, each operation is the + * same and by chance even has the same $nid to operate on, but we could have + * a mix of different types of operations in the operations array. + */ +function batch_example_batch_1() { + $nid = batch_example_lowest_nid(); + $num_operations = 1000; + drupal_set_message(t('Creating an array of @num operations', array('@num' => $num_operations))); + + $operations = array(); + // Set up an operations array with 1000 elements, each doing function + // batch_example_op_1. + // Each operation in the operations array means at least one new HTTP request, + // running Drupal from scratch to accomplish the operation. If the operation + // returns with $context['finished'] != TRUE, then it will be called again. + // In this example, $context['finished'] is always TRUE. + for ($i = 0; $i < $num_operations; $i++) { + // Each operation is an array consisting of + // - The function to call. + // - An array of arguments to that function. + $operations[] = array( + 'batch_example_op_1', + array( + $nid, + t('(Operation @operation)', array('@operation' => $i)), + ), + ); + } + $batch = array( + 'operations' => $operations, + 'finished' => 'batch_example_finished', + ); + return $batch; +} + +/** + * Batch operation for batch 1: load a node. + * + * This is the function that is called on each operation in batch 1. + */ +function batch_example_op_1($nid, $operation_details, &$context) { + $node = node_load($nid, NULL, TRUE); + + // Store some results for post-processing in the 'finished' callback. + // The contents of 'results' will be available as $results in the + // 'finished' function (in this example, batch_example_finished()). + $context['results'][] = $node->nid . ' : ' . check_plain($node->title); + + // Optional message displayed under the progressbar. + $context['message'] = t('Loading node "@title"', array('@title' => $node->title)) . ' ' . $operation_details; + + _batch_example_update_http_requests(); +} + +/** + * Batch 2 : Prepare a batch definition that will load all nodes 20 times. + */ +function batch_example_batch_2() { + $num_operations = 20; + + // Give helpful information about how many nodes are being operated on. + $node_count = db_query('SELECT COUNT(DISTINCT nid) FROM {node}')->fetchField(); + drupal_set_message( + t('There are @node_count nodes so each of the @num operations will require @count HTTP requests.', + array( + '@node_count' => $node_count, + '@num' => $num_operations, + '@count' => ceil($node_count / 5), + ) + ) + ); + + $operations = array(); + // 20 operations, each one loads all nodes. + for ($i = 0; $i < $num_operations; $i++) { + $operations[] = array( + 'batch_example_op_2', + array(t('(Operation @operation)', array('@operation' => $i))), + ); + } + $batch = array( + 'operations' => $operations, + 'finished' => 'batch_example_finished', + // Message displayed while processing the batch. Available placeholders are: + // @current, @remaining, @total, @percentage, @estimate and @elapsed. + // These placeholders are replaced with actual values in _batch_process(), + // using strtr() instead of t(). The values are determined based on the + // number of operations in the 'operations' array (above), NOT by the number + // of nodes that will be processed. In this example, there are 20 + // operations, so @total will always be 20, even though there are multiple + // nodes per operation. + // Defaults to t('Completed @current of @total.'). + 'title' => t('Processing batch 2'), + 'init_message' => t('Batch 2 is starting.'), + 'progress_message' => t('Processed @current out of @total.'), + 'error_message' => t('Batch 2 has encountered an error.'), + ); + return $batch; +} + +/** + * Batch operation for batch 2 : load all nodes, 5 by five. + * + * After each group of 5 control is returned to the batch API for later + * continuation. + */ +function batch_example_op_2($operation_details, &$context) { + // Use the $context['sandbox'] at your convenience to store the + // information needed to track progression between successive calls. + if (empty($context['sandbox'])) { + $context['sandbox'] = array(); + $context['sandbox']['progress'] = 0; + $context['sandbox']['current_node'] = 0; + + // Save node count for the termination message. + $context['sandbox']['max'] = db_query('SELECT COUNT(DISTINCT nid) FROM {node}')->fetchField(); + } + + // Process nodes by groups of 5 (arbitrary value). + // When a group of five is processed, the batch update engine determines + // whether it should continue processing in the same request or provide + // progress feedback to the user and wait for the next request. + // That way even though we're already processing at the operation level + // the operation itself is interruptible. + $limit = 5; + + // Retrieve the next group of nids. + $result = db_select('node', 'n') + ->fields('n', array('nid')) + ->orderBy('n.nid', 'ASC') + ->where('n.nid > :nid', array(':nid' => $context['sandbox']['current_node'])) + ->extend('PagerDefault') + ->limit($limit) + ->execute(); + foreach ($result as $row) { + // Here we actually perform our dummy 'processing' on the current node. + $node = node_load($row->nid, NULL, TRUE); + + // Store some results for post-processing in the 'finished' callback. + // The contents of 'results' will be available as $results in the + // 'finished' function (in this example, batch_example_finished()). + $context['results'][] = $node->nid . ' : ' . check_plain($node->title) . ' ' . $operation_details; + + // Update our progress information. + $context['sandbox']['progress']++; + $context['sandbox']['current_node'] = $node->nid; + $context['message'] = check_plain($node->title); + } + + // Inform the batch engine that we are not finished, + // and provide an estimation of the completion level we reached. + if ($context['sandbox']['progress'] != $context['sandbox']['max']) { + $context['finished'] = ($context['sandbox']['progress'] >= $context['sandbox']['max']); + } + _batch_example_update_http_requests(); +} + +/** + * Batch 'finished' callback used by both batch 1 and batch 2. + */ +function batch_example_finished($success, $results, $operations) { + if ($success) { + // Here we could do something meaningful with the results. + // We just display the number of nodes we processed... + drupal_set_message(t('@count results processed in @requests HTTP requests.', array('@count' => count($results), '@requests' => _batch_example_get_http_requests()))); + drupal_set_message(t('The final result was "%final"', array('%final' => end($results)))); + } + else { + // An error occurred. + // $operations contains the operations that remained unprocessed. + $error_operation = reset($operations); + drupal_set_message( + t('An error occurred while processing @operation with arguments : @args', + array( + '@operation' => $error_operation[0], + '@args' => print_r($error_operation[0], TRUE), + ) + ), + 'error' + ); + } +} + +/** + * Utility function - simply queries and loads the lowest nid. + * + * @return int|NULL + * A nid or NULL if there are no nodes. + */ +function batch_example_lowest_nid() { + $select = db_select('node', 'n') + ->fields('n', array('nid')) + ->orderBy('n.nid', 'ASC') + ->extend('PagerDefault') + ->limit(1); + $nid = $select->execute()->fetchField(); + return $nid; +} + +/** + * Utility function to increment HTTP requests in a session variable. + */ +function _batch_example_update_http_requests() { + $_SESSION['http_request_count']++; +} + +/** + * Utility function to count the HTTP requests in a session variable. + * + * @return int + * Number of requests. + */ +function _batch_example_get_http_requests() { + return !empty($_SESSION['http_request_count']) ? $_SESSION['http_request_count'] : 0; +} +/** + * @} End of "defgroup batch_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/batch_example/batch_example.test b/sites/all/modules/contrib/dev/examples/batch_example/batch_example.test new file mode 100644 index 00000000..cc93f5aa --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/batch_example/batch_example.test @@ -0,0 +1,60 @@ + 'Batch example functionality', + 'description' => 'Verify the defined batches.', + 'group' => 'Examples', + ); + } + + /** + * Enable modules and create user with specific permissions. + */ + public function setUp() { + parent::setUp('batch_example'); + // Create user. + $this->webUser = $this->drupalCreateUser(); + } + + /** + * Login user, create 30 nodes and test both batch examples. + */ + public function testBatchExampleBasic() { + // Login the admin user. + $this->drupalLogin($this->webUser); + + // Create 30 nodes. + for ($count = 0; $count < 30; $count++) { + $node = $this->drupalCreateNode(); + } + + // Launch Batch 1 + $result = $this->drupalPost('examples/batch_example', array('batch' => 'batch_1'), t('Go')); + // Check that 1000 operations were performed. + $this->assertText('1000 results processed'); + + // Launch Batch 2 + $result = $this->drupalPost('examples/batch_example', array('batch' => 'batch_2'), t('Go')); + // Check that 600 operations were performed. + $this->assertText('600 results processed'); + } +} diff --git a/sites/all/modules/contrib/dev/examples/block_example/block_example.info b/sites/all/modules/contrib/dev/examples/block_example/block_example.info new file mode 100644 index 00000000..8008a378 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/block_example/block_example.info @@ -0,0 +1,13 @@ +name = Block Example +description = An example outlining how a module can define blocks. +package = Example modules +core = 7.x +dependencies[] = block +files[] = block_example.test + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/block_example/block_example.install b/sites/all/modules/contrib/dev/examples/block_example/block_example.install new file mode 100644 index 00000000..50541823 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/block_example/block_example.install @@ -0,0 +1,14 @@ + 'block_example_page', + 'access callback' => TRUE, + 'title' => 'Block Example', + ); + return $items; +} + +/** + * Simple page function to explain what the block example is about. + */ +function block_example_page() { + $page = array( + '#type' => 'markup', + '#markup' => t('The Block Example provides three sample blocks which demonstrate the various block APIs. To experiment with the blocks, enable and configure them on the block admin page.', array('@url' => url('admin/structure/block'))), + ); + return $page; +} +/** + * Implements hook_block_info(). + * + * This hook declares what blocks are provided by the module. + */ +function block_example_block_info() { + // This hook returns an array, each component of which is an array of block + // information. The array keys are the 'delta' values used in other block + // hooks. + // + // The required block information is a block description, which is shown + // to the site administrator in the list of possible blocks. You can also + // provide initial settings for block weight, status, etc. + // + // Many options are defined in hook_block_info(): + $blocks['example_configurable_text'] = array( + // info: The name of the block. + 'info' => t('Example: configurable text string'), + // Block caching options (per role, per user, etc.) + // DRUPAL_CACHE_PER_ROLE is the default. + 'cache' => DRUPAL_CACHE_PER_ROLE, + ); + + // This sample shows how to provide default settings. In this case we'll + // enable the block in the first sidebar and make it visible only on + // 'node/*' pages. See the hook_block_info() documentation for these. + $blocks['example_empty'] = array( + 'info' => t('Example: empty block'), + 'status' => TRUE, + 'region' => 'sidebar_first', + 'visibility' => BLOCK_VISIBILITY_LISTED, + 'pages' => 'node/*', + ); + + $blocks['example_uppercase'] = array( + // info: The name of the block. + 'info' => t('Example: uppercase this please'), + 'status' => TRUE, + 'region' => 'sidebar_first', + ); + + return $blocks; +} + +/** + * Implements hook_block_configure(). + * + * This hook declares configuration options for blocks provided by this module. + */ +function block_example_block_configure($delta = '') { + $form = array(); + // The $delta parameter tells us which block is being configured. + // In this example, we'll allow the administrator to customize + // the text of the 'configurable text string' block defined in this module. + if ($delta == 'example_configurable_text') { + // All we need to provide is the specific configuration options for our + // block. Drupal will take care of the standard block configuration options + // (block title, page visibility, etc.) and the save button. + $form['block_example_string'] = array( + '#type' => 'textfield', + '#title' => t('Block contents'), + '#size' => 60, + '#description' => t('This text will appear in the example block.'), + '#default_value' => variable_get('block_example_string', t('Some example content.')), + ); + } + return $form; +} + +/** + * Implements hook_block_save(). + * + * This hook declares how the configured options for a block + * provided by this module are saved. + */ +function block_example_block_save($delta = '', $edit = array()) { + // We need to save settings from the configuration form. + // We need to check $delta to make sure we are saving the right block. + if ($delta == 'example_configurable_text') { + // Have Drupal save the string to the database. + variable_set('block_example_string', $edit['block_example_string']); + } +} + +/** + * Implements hook_block_view(). + * + * This hook generates the contents of the blocks themselves. + */ +function block_example_block_view($delta = '') { + // The $delta parameter tells us which block is being requested. + switch ($delta) { + case 'example_configurable_text': + // The subject is displayed at the top of the block. Note that it + // should be passed through t() for translation. The title configured + // for the block using Drupal UI supercedes this one. + $block['subject'] = t('Title of first block (example_configurable_text)'); + // The content of the block is typically generated by calling a custom + // function. + $block['content'] = block_example_contents($delta); + break; + + case 'example_empty': + $block['subject'] = t('Title of second block (example_empty)'); + $block['content'] = block_example_contents($delta); + break; + + case 'example_uppercase': + $block['subject'] = t("uppercase this please"); + $block['content'] = t("This block's title will be changed to uppercase. Any other block with 'uppercase' in the subject or title will also be altered. If you change this block's title through the UI to omit the word 'uppercase', it will still be altered to uppercase as the subject key has not been changed."); + break; + } + return $block; +} + +/** + * A module-defined block content function. + */ +function block_example_contents($which_block) { + switch ($which_block) { + case 'example_configurable_text': + // Modules would typically perform some database queries to fetch the + // content for their blocks. Here, we'll just use the variable set in the + // block configuration or, if none has set, a default value. + // Block content can be returned in two formats: renderable arrays + // (as here) are preferred though a simple string will work as well. + // Block content created through the UI defaults to a string. + $result = array( + '#markup' => variable_get('block_example_string', + t('A default value. This block was created at %time', + array('%time' => date('c')) + ) + ), + ); + return $result; + + case 'example_empty': + // It is possible that a block not have any content, since it is + // probably dynamically constructed. In this case, Drupal will not display + // the block at all. This block will not be displayed. + return; + } +} + +/* + * The following hooks can be used to alter blocks + * provided by your own or other modules. + */ + +/** + * Implements hook_block_list_alter(). + * + * This hook allows you to add, remove or modify blocks in the block list. The + * block list contains the block definitions. This example requires + * search module and the search block enabled + * to see how this hook implementation works. + * + * You may also be interested in hook_block_info_alter(), which allows changes + * to the behavior of blocks. + */ +function block_example_block_list_alter(&$blocks) { + // We are going to make the search block sticky on bottom of regions. For + // this example, we will modify the block list and append the search block at + // the end of the list, so even if the administrator configures the block to + // be on the top of the region, it will demote to bottom again. + foreach ($blocks as $bid => $block) { + if (($block->module == 'search') && ($block->delta == 'form')) { + // Remove the block from the list and append to the end. + unset($blocks[$bid]); + $blocks[$bid] = $block; + break; + } + } +} + +/** + * Implements hook_block_view_alter(). + * + * This hook allows you to modify the output of any block in the system. + * + * In addition, instead of hook_block_view_alter(), which is called for all + * blocks, you can also use hook_block_view_MODULE_DELTA_alter() to alter a + * specific block. To change only our block using + * hook_block_view_MODULE_DELTA_alter, we would use the function: + * block_example_block_view_block_example_example_configurable_text_alter() + * + * We are going to uppercase the subject (the title of the block as shown to the + * user) of any block if the string "uppercase" appears in the block title or + * subject. Default block titles are set programmatically in the subject key; + * titles created through the UI are saved in the title key. This module creates + * an example block to demonstrate this effect (default title set + * programmatically as subject). You can also demonstrate the effect of this + * hook by creating a new block whose title has the string 'uppercase' in it + * (set as title through the UI). + */ +function block_example_block_view_alter(&$data, $block) { + // We'll search for the string 'uppercase'. + if ((!empty($block->title) && stristr($block->title, 'uppercase')) || (!empty($data['subject']) && stristr($data['subject'], 'uppercase'))) { + // This will uppercase the default title. + $data['subject'] = isset($data['subject']) ? drupal_strtoupper($data['subject']) : ''; + // This will uppercase a title set in the UI. + $block->title = isset($block->title) ? drupal_strtoupper($block->title) : ''; + } +} +/** + * @} End of "defgroup block_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/block_example/block_example.test b/sites/all/modules/contrib/dev/examples/block_example/block_example.test new file mode 100644 index 00000000..6698a11f --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/block_example/block_example.test @@ -0,0 +1,114 @@ + 'Block example functionality', + 'description' => 'Test the configuration options and block created by Block Example module.', + 'group' => 'Examples', + ); + } + + /** + * Enable modules and create user with specific permissions. + */ + public function setUp() { + parent::setUp('block_example', 'search'); + // Create user. Search content permission granted for the search block to + // be shown. + $this->webUser = $this->drupalCreateUser( + array( + 'administer blocks', + 'search content', + 'access contextual links', + ) + ); + } + + /** + * Functional test for our block example. + * + * Login user, create an example node, and test block functionality through + * the admin and user interfaces. + */ + public function testBlockExampleBasic() { + // Login the admin user. + $this->drupalLogin($this->webUser); + + // Find the blocks in the settings page. + $this->drupalGet('admin/structure/block'); + $this->assertRaw(t('Example: configurable text string'), 'Block configurable-string found.'); + $this->assertRaw(t('Example: empty block'), 'Block empty-block found.'); + + // Verify the default settings for block are processed. + $this->assertFieldByName('blocks[block_example_example_empty][region]', 'sidebar_first', 'Empty block is enabled in first sidebar successfully verified.'); + $this->assertFieldByName('blocks[block_example_example_configurable_text][region]', -1, 'Configurable text block is disabled in first sidebar successfully verified.'); + + // Verify that blocks are not shown. + $this->drupalGet('/'); + $this->assertNoRaw(t('Title of first block (example_configurable_text)'), 'Block configurable test not found.'); + $this->assertNoRaw(t('Title of second block (example_empty)'), 'Block empty not found.'); + + // Enable the Configurable text block and verify. + $this->drupalPost('admin/structure/block', array('blocks[block_example_example_configurable_text][region]' => 'sidebar_first'), t('Save blocks')); + $this->assertFieldByName('blocks[block_example_example_configurable_text][region]', 'sidebar_first', 'Configurable text block is enabled in first sidebar successfully verified.'); + + // Verify that blocks are there. Empty block will not be shown, because it + // is empty. + $this->drupalGet('/'); + $this->assertRaw(t('Title of first block (example_configurable_text)'), 'Block configurable text found.'); + + // Change content of configurable text block. + $string = $this->randomName(); + $this->drupalPost('admin/structure/block/manage/block_example/example_configurable_text/configure', array('block_example_string' => $string), t('Save block')); + + // Verify that new content is shown. + $this->drupalGet('/'); + $this->assertRaw($string, 'Content of configurable text block successfully verified.'); + + // Make sure our example uppercased block is shown as altered by the + // hook_block_view_alter(). + $this->assertRaw(t('UPPERCASE THIS PLEASE')); + + // Create a new block and make sure it gets uppercased. + $post = array( + 'title' => t('configurable block to be uppercased'), + 'info' => t('configurable block to be uppercased'), + 'body[value]' => t('body of new block'), + 'regions[bartik]' => 'sidebar_first', + ); + $this->drupalPost('admin/structure/block/add', $post, t('Save block')); + $this->drupalGet('/'); + $this->assertRaw(('CONFIGURABLE BLOCK TO BE UPPERCASED')); + + // Verify that search block is at the bottom of the region. + // Enable the search block on top of sidebar_first. + $block_options = array( + 'blocks[search_form][region]' => 'sidebar_first', + 'blocks[search_form][weight]' => -9, + ); + $this->drupalPost('admin/structure/block', $block_options, t('Save blocks')); + + // The first 'configure block' link should be from our configurable block, + // the second from the Navigation menu, and the fifth (#4) from + // search block if it was successfully pushed to the bottom. + $this->drupalGet('/'); + $this->clickLink('Configure block', 4); + $this->assertText(t("'@search' block", array('@search' => t('Search form'))), 'hook_block_info_alter successfully verified.'); + } +} diff --git a/sites/all/modules/contrib/dev/examples/cache_example/cache_example.info b/sites/all/modules/contrib/dev/examples/cache_example/cache_example.info new file mode 100644 index 00000000..d7e406dd --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/cache_example/cache_example.info @@ -0,0 +1,13 @@ +name = Cache Example +description = An example outlining how to use Cache API. +package = Example modules +core = 7.x + +files[] = cache_example.test + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/cache_example/cache_example.module b/sites/all/modules/contrib/dev/examples/cache_example/cache_example.module new file mode 100644 index 00000000..8e2d8732 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/cache_example/cache_example.module @@ -0,0 +1,246 @@ + 'Cache example', + 'description' => 'Example of Drupal Cache API', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('cache_example_page_form'), + 'access callback' => TRUE, + ); + + return $items; +} + +/** + * Main page for cache_example. + * + * Displays a page/form which outlines how Drupal's cache works. + */ +function cache_example_page_form($form, &$form_state) { + // Log execution time. + $start_time = microtime(TRUE); + + // Try to load the files count from cache. This function will accept two + // arguments: + // - cache object name (cid) + // - cache bin, the (optional) cache bin (most often a database table) where + // the object is to be saved. + // + // cache_get() returns the cached object or FALSE if object does not exist. + if ($cache = cache_get('cache_example_files_count')) { + /* + * Get cached data. Complex data types will be unserialized automatically. + */ + $files_count = $cache->data; + } + else { + // If there was no cached data available we have to search filesystem. + // Recursively get all files from Drupal's folder. + $files_count = count(file_scan_directory('.', '/.*/')); + + // Since we have recalculated, we now need to store the new data into cache. + // Complex data types will be automatically serialized before being saved + // into cache. + // Here we use the default setting and create an unexpiring cache item. + // See below for an example that creates an expiring cache item. + cache_set('cache_example_files_count', $files_count); + } + + $end_time = microtime(TRUE); + $duration = $end_time - $start_time; + + // Format intro message. + $intro_message = '

' . t('This example will search the entire drupal folder and display a count of the files in it.') . ' '; + $intro_message .= t('This can take a while, since there are a lot of files to be searched.') . ' '; + $intro_message .= t('We will search filesystem just once and save output to the cache. We will use cached data for later requests.') . '

'; + $intro_message .= '

' . t('Reload this page to see cache in action.', array('@url' => request_uri())) . ' '; + $intro_message .= t('You can use the button below to remove cached data.') . '

'; + + $form['file_search'] = array( + '#type' => 'fieldset', + '#title' => t('File search caching'), + ); + $form['file_search']['introduction'] = array( + '#markup' => $intro_message, + ); + + $color = empty($cache) ? 'red' : 'green'; + $retrieval = empty($cache) ? t('calculated by traversing the filesystem') : t('retrieved from cache'); + + $form['file_search']['statistics'] = array( + '#type' => 'item', + '#markup' => t('%count files exist in this Drupal installation; @retrieval in @time ms.
(Source: @source)', + array( + '%count' => $files_count, + '@retrieval' => $retrieval, + '@time' => number_format($duration * 1000, 2), + '@color' => $color, + '@source' => empty($cache) ? t('actual file search') : t('cached'), + ) + ), + ); + $form['file_search']['remove_file_count'] = array( + '#type' => 'submit', + '#submit' => array('cache_example_form_expire_files'), + '#value' => t('Explicitly remove cached file count'), + ); + + $form['expiration_demo'] = array( + '#type' => 'fieldset', + '#title' => t('Cache expiration settings'), + ); + $form['expiration_demo']['explanation'] = array( + '#markup' => t('A cache item can be set as CACHE_PERMANENT, meaning that it will only be removed when explicitly cleared, or it can have an expiration time (a Unix timestamp).'), + ); + $expiring_item = cache_get('cache_example_expiring_item'); + $item_status = $expiring_item ? + t('Cache item exists and is set to expire at %time', array('%time' => $expiring_item->data)) : + t('Cache item does not exist'); + $form['expiration_demo']['current_status'] = array( + '#type' => 'item', + '#title' => t('Current status of cache item "cache_example_expiring_item"'), + '#markup' => $item_status, + ); + $form['expiration_demo']['expiration'] = array( + '#type' => 'select', + '#title' => t('Time before cache expiration'), + '#options' => array( + 'never_remove' => t('CACHE_PERMANENT'), + -10 => t('Immediate expiration'), + 10 => t('10 seconds from form submission'), + 60 => t('1 minute from form submission'), + 300 => t('5 minutes from form submission'), + ), + '#default_value' => -10, + '#description' => t('Any cache item can be set to only expire when explicitly cleared, or to expire at a given time.'), + ); + $form['expiration_demo']['create_cache_item'] = array( + '#type' => 'submit', + '#value' => t('Create a cache item with this expiration'), + '#submit' => array('cache_example_form_create_expiring_item'), + ); + + $form['cache_clearing'] = array( + '#type' => 'fieldset', + '#title' => t('Expire and remove options'), + '#description' => t("We have APIs to expire cached items and also to just remove them. Unfortunately, they're all the same API, cache_clear_all"), + ); + $form['cache_clearing']['cache_clear_type'] = array( + '#type' => 'radios', + '#title' => t('Type of cache clearing to do'), + '#options' => array( + 'expire' => t('Remove items from the "cache" bin that have expired'), + 'remove_all' => t('Remove all items from the "cache" bin regardless of expiration (super-wildcard)'), + 'remove_wildcard' => t('Remove all items from the "cache" bin that match the pattern "cache_example"'), + ), + '#default_value' => 'expire', + ); + // Submit button to clear cached data. + $form['cache_clearing']['clear_expired'] = array( + '#type' => 'submit', + '#value' => t('Clear or expire cache'), + '#submit' => array('cache_example_form_cache_clearing'), + '#access' => user_access('administer site configuration'), + ); + return $form; +} + +/** + * Submit handler that explicitly clears cache_example_files_count from cache. + */ +function cache_example_form_expire_files($form, &$form_state) { + // Clear cached data. This function will delete cached object from cache bin. + // + // The first argument is cache id to be deleted. Since we've provided it + // explicitly, it will be removed whether or not it has an associated + // expiration time. The second argument (required here) is the cache bin. + // Using cache_clear_all() explicitly in this way + // forces removal of the cached item. + cache_clear_all('cache_example_files_count', 'cache'); + + // Display message to the user. + drupal_set_message(t('Cached data key "cache_example_files_count" was cleared.'), 'status'); +} + +/** + * Submit handler to create a new cache item with specified expiration. + */ +function cache_example_form_create_expiring_item($form, &$form_state) { + $interval = $form_state['values']['expiration']; + if ($interval == 'never_remove') { + $expiration = CACHE_PERMANENT; + $expiration_friendly = t('Never expires'); + } + else { + $expiration = time() + $interval; + $expiration_friendly = format_date($expiration); + } + // Set the expiration to the actual Unix timestamp of the end of the required + // interval. + cache_set('cache_example_expiring_item', $expiration_friendly, 'cache', $expiration); + drupal_set_message(t('cache_example_expiring_item was set to expire at %time', array('%time' => $expiration_friendly))); +} + +/** + * Submit handler to demonstrate the various uses of cache_clear_all(). + */ +function cache_example_form_cache_clearing($form, &$form_state) { + switch ($form_state['values']['cache_clear_type']) { + case 'expire': + // Here we'll remove all cache keys in the 'cache' bin that have expired. + cache_clear_all(NULL, 'cache'); + drupal_set_message(t('cache_clear_all(NULL, "cache") was called, removing any expired cache items.')); + break; + + case 'remove_all': + // This removes all keys in a bin using a super-wildcard. This + // has nothing to do with expiration. It's just brute-force removal. + cache_clear_all('*', 'cache', TRUE); + drupal_set_message(t('ALL entries in the "cache" bin were removed with cache_clear_all("*", "cache", TRUE).')); + break; + + case 'remove_wildcard': + // We can also explicitly remove all cache items whose cid begins with + // 'cache_example' by using a wildcard. This again is brute-force + // removal, not expiration. + cache_clear_all('cache_example', 'cache', TRUE); + drupal_set_message(t('Cache entries whose cid began with "cache_example" in the "cache" bin were removed with cache_clear_all("cache_example", "cache", TRUE).')); + break; + } +} + +/** + * @} End of "defgroup cache_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/cache_example/cache_example.test b/sites/all/modules/contrib/dev/examples/cache_example/cache_example.test new file mode 100644 index 00000000..a445efaa --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/cache_example/cache_example.test @@ -0,0 +1,81 @@ + 'Cache example functionality', + 'description' => 'Test the Cache Example module.', + 'group' => 'Examples', + ); + } + + /** + * Enable module. + */ + public function setUp() { + parent::setUp('cache_example'); + } + + /** + * Functional tests for cache_example. + * + * Load cache example page and test if displaying uncached version. Reload + * once again and test if displaying cached version. Find reload link and + * click on it. Clear cache at the end and test if displaying uncached + * version again. + */ + public function testCacheExampleBasic() { + // We need administrative privileges to clear the cache. + $admin_user = $this->drupalCreateUser(array('administer site configuration')); + $this->drupalLogin($admin_user); + + // Get uncached output of cache example page and assert some things to be + // sure. + $this->drupalGet('examples/cache_example'); + $this->assertText('Source: actual file search'); + // Reload the page; the number should be cached. + $this->drupalGet('examples/cache_example'); + $this->assertText('Source: cached'); + + // Now push the button to remove the count. + $this->drupalPost('examples/cache_example', array(), t('Explicitly remove cached file count')); + $this->assertText('Source: actual file search'); + + // Create a cached item. First make sure it doesn't already exist. + $this->assertText('Cache item does not exist'); + $this->drupalPost('examples/cache_example', array('expiration' => -10), t('Create a cache item with this expiration')); + // We should now have an already-expired item. + $this->assertText('Cache item exists and is set to expire'); + // Now do the expiration operation. + $this->drupalPost('examples/cache_example', array('cache_clear_type' => 'expire'), t('Clear or expire cache')); + // And verify that it was removed. + $this->assertText('Cache item does not exist'); + + // Create a cached item. This time we'll make it not expire. + $this->drupalPost('examples/cache_example', array('expiration' => 'never_remove'), t('Create a cache item with this expiration')); + // We should now have an never-remove item. + $this->assertText('Cache item exists and is set to expire at Never expires'); + // Now do the expiration operation. + $this->drupalPost('examples/cache_example', array('cache_clear_type' => 'expire'), t('Clear or expire cache')); + // And verify that it was not removed. + $this->assertText('Cache item exists and is set to expire at Never expires'); + // Now do full removal. + $this->drupalPost('examples/cache_example', array('cache_clear_type' => 'remove_wildcard'), t('Clear or expire cache')); + // And verify that it was removed. + $this->assertText('Cache item does not exist'); + } + +} diff --git a/sites/all/modules/contrib/dev/examples/contextual_links_example/contextual-links-example-object.tpl.php b/sites/all/modules/contrib/dev/examples/contextual_links_example/contextual-links-example-object.tpl.php new file mode 100644 index 00000000..4a073d46 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/contextual_links_example/contextual-links-example-object.tpl.php @@ -0,0 +1,36 @@ + +
+ +

+ + +
diff --git a/sites/all/modules/contrib/dev/examples/contextual_links_example/contextual_links_example.info b/sites/all/modules/contrib/dev/examples/contextual_links_example/contextual_links_example.info new file mode 100644 index 00000000..04a7f775 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/contextual_links_example/contextual_links_example.info @@ -0,0 +1,12 @@ +name = Contextual links example +description = Demonstrates how to use contextual links for enhancing the user experience. +package = Example modules +core = 7.x +files[] = contextual_links_example.test + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/contextual_links_example/contextual_links_example.module b/sites/all/modules/contrib/dev/examples/contextual_links_example/contextual_links_example.module new file mode 100644 index 00000000..e80c79a7 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/contextual_links_example/contextual_links_example.module @@ -0,0 +1,388 @@ + path. If the path + // you are adding corresponds to a commonly performed action on the node, you + // can choose to expose it as a contextual link. Since the Node module + // already has code to display all contextual links underneath the node/ + // path (such as "Edit" and "Delete") when a node is being rendered outside + // of its own page (for example, when a teaser of the node is being displayed + // on the front page of the site), you only need to inform Drupal's menu + // system that your path is a contextual link also, and it will automatically + // appear with the others. In the example below, we add a contextual link + // named "Example action" to the list. + $items['node/%node/example-action'] = array( + 'title' => 'Example action', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('contextual_links_example_node_action_form', 1), + 'access callback' => TRUE, + // To be displayed as a contextual link, a menu item should be defined as + // one of the node's local tasks. + 'type' => MENU_LOCAL_TASK, + // To make the local task display as a contextual link, specify the + // optional 'context' argument. The most common method is to set both + // MENU_CONTEXT_PAGE and MENU_CONTEXT_INLINE (shown below), which causes + // the link to display as both a tab on the node page and as an entry in + // the contextual links dropdown. This is recommended for most cases + // because not all users who have permission to visit the "Example action" + // page will necessarily have access to contextual links, and they still + // need a way to get to the page via the user interface. + 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE, + // If we give the item a large weight, we can make it display as the last + // tab on the page, as well as the last item inside the contextual links + // dropdown. + 'weight' => 80, + ); + + // Second example (attaching contextual links to a block): + // + // If your module provides content that is displayed in a block, you can + // attach contextual links to the block that allow actions to be performed on + // it. This is useful for administrative pages that affect the content + // wherever it is displayed or used on the site. For configuration options + // that only affect the appearance of the content in the block itself, it is + // better to implement hook_block_configure() rather than creating a separate + // administrative page (this allows your options to appear when an + // administrator clicks the existing "Configure block" contextual link + // already provided by the Block module). + // + // In the code below, we assume that your module has a type of object + // ("contextual links example object") that will be displayed in a block. The + // code below defines menu items for this object using a standard pattern, + // with "View" and "Edit object" as the object's local tasks, and makes the + // "Edit object" item display as a contextual link in addition to a tab. Once + // the contextual links are defined here, additional steps are required to + // actually display the content in a block and attach the contextual links to + // the block itself. This occurs in contextual_links_example_block_info() and + // contextual_links_example_block_view(). + $items['examples/contextual-links/%contextual_links_example_object'] = array( + 'title' => 'Contextual links example object', + 'page callback' => 'contextual_links_example_object_page', + 'page arguments' => array(2), + 'access callback' => TRUE, + ); + $items['examples/contextual-links/%contextual_links_example_object/view'] = array( + 'title' => 'View', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -10, + ); + $items['examples/contextual-links/%contextual_links_example_object/edit'] = array( + 'title' => 'Edit object', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('contextual_links_example_object_edit_form', 2), + 'access callback' => TRUE, + 'type' => MENU_LOCAL_TASK, + // As in our first example, this is the line of code that makes "Edit + // "object" display as a contextual link in addition to as a tab. + 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE, + ); + + // Third example (attaching contextual links directly to your module's + // content): + // + // Sometimes your module may want to display its content in an arbitrary + // location and attach contextual links there. For example, you might + // display your content in a listing on its own page and then attach the + // contextual links directly to each piece of content in the listing. Here, + // we will reuse the menu items and contextual links that were defined for + // our example object above, and display them in a listing in + // contextual_links_overview_page(). + $items['examples/contextual-links'] = array( + 'title' => 'Contextual Links Example', + 'page callback' => 'contextual_links_overview_page', + 'access callback' => TRUE, + ); + + return $items; +} + +/** + * Menu loader callback for the object defined by this module. + * + * @param int $id + * The ID of the object to load. + * + * @return object|FALSE + * A fully loaded object, or FALSE if the object does not exist. + */ +function contextual_links_example_object_load($id) { + // In a real use case, this function might load an object from the database. + // For the sake of this example, we just define a stub object with a basic + // title and content for any numeric ID that is passed in. + if (is_numeric($id)) { + $object = new stdClass(); + $object->id = $id; + $object->title = t('Title for example object @id', array('@id' => $id)); + $object->content = t('This is the content of example object @id.', array('@id' => $id)); + return $object; + } + else { + return FALSE; + } +} + +/** + * Implements hook_block_info(). + */ +function contextual_links_example_block_info() { + // Define the block that will display our module's content. + $blocks['example']['info'] = t('Contextual links example block'); + return $blocks; +} + +/** + * Implements hook_block_view(). + */ +function contextual_links_example_block_view($delta = '') { + if ($delta == 'example') { + // Display our module's content inside a block. In a real use case, we + // might define a new block for each object that exists. For the sake of + // this example, though, we only define one block and hardcode it to always + // display object #1. + $id = 1; + $object = contextual_links_example_object_load($id); + $block['subject'] = t('Contextual links example block for object @id', array('@id' => $id)); + $block['content'] = array( + // In order to attach contextual links, the block's content must be a + // renderable array. (Normally this would involve themed output using + // #theme, but for simplicity we just use HTML markup directly here.) + '#type' => 'markup', + '#markup' => filter_xss($object->content), + // Contextual links are attached to the block array using the special + // #contextual_links property. The #contextual_links property contains an + // array, keyed by the name of each module that is attaching contextual + // links to it. + '#contextual_links' => array( + 'contextual_links_example' => array( + // Each element is itself an array, containing two elements which are + // combined together to form the base path whose contextual links + // should be attached. The two elements are split such that the first + // is the static part of the path and the second is the dynamic part. + // (This split is for performance reasons.) For example, the code + // below tells Drupal to load the menu item corresponding to the path + // "examples/contextual-links/$id" and attach all this item's + // contextual links (which were defined in hook_menu()) to the object + // when it is rendered. If the contextual links you are attaching + // don't have any dynamic elements in their path, you can pass an + // empty array as the second element. + 'examples/contextual-links', + array($id), + ), + ), + ); + // Since we are attaching our contextual links to a block, and the Block + // module takes care of rendering the block in such a way that contextual + // links are supported, we do not need to do anything else here. When the + // appropriate conditions are met, the contextual links we have defined + // will automatically appear attached to the block, next to the "Configure + // block" link that the Block module itself provides. + return $block; + } +} + +/** + * Menu callback; displays a listing of objects defined by this module. + * + * @see contextual_links_example_theme() + * @see contextual-links-example-object.tpl.php + * @see contextual_links_example_block_view() + */ +function contextual_links_overview_page() { + $build = array(); + + // For simplicity, we will hardcode this example page to list five of our + // module's objects. + for ($id = 1; $id <= 5; $id++) { + $object = contextual_links_example_object_load($id); + $build[$id] = array( + // To support attaching contextual links to an object that we are + // displaying on our own, the object must be themed in a particular way. + // See contextual_links_example_theme() and + // contextual-links-example-object.tpl.php for more discussion. + '#theme' => 'contextual_links_example_object', + '#object' => $object, + // Contextual links are attached to the block using the special + // #contextual_links property. See contextual_links_example_block_view() + // for discussion of the syntax used here. + '#contextual_links' => array( + 'contextual_links_example' => array( + 'examples/contextual-links', + array($id), + ), + ), + ); + } + + return $build; +} + +/** + * Implements hook_theme(). + * + * @see template_preprocess_contextual_links_example_object() + */ +function contextual_links_example_theme() { + // The core Contextual Links module imposes two restrictions on how an object + // must be themed in order for it to display the object's contextual links in + // the user interface: + // - The object must use a template file rather than a theme function. See + // contextual-links-example-object.tpl.php for more information on how the + // template file should be structured. + // - The first variable passed to the template must be a renderable array. In + // this case, we accomplish that via the most common method, by passing a + // single renderable element. + return array( + 'contextual_links_example_object' => array( + 'template' => 'contextual-links-example-object', + 'render element' => 'element', + ), + ); +} + +/** + * Process variables for contextual-links-example-object.tpl.php. + * + * @see contextual_links_overview_page() + */ +function template_preprocess_contextual_links_example_object(&$variables) { + // Here we take the object that is being themed and define some useful + // variables that we will print in the template file. + $variables['title'] = filter_xss($variables['element']['#object']->title); + $variables['content'] = filter_xss($variables['element']['#object']->content); +} + +/** + * Menu callback; displays an object defined by this module on its own page. + * + * @see contextual_links_overview_page() + */ +function contextual_links_example_object_page($object) { + // Here we render the object but without the #contextual_links property, + // since we don't want contextual links to appear when the object is already + // being displayed on its own page. + $build = array( + '#theme' => 'contextual_links_example_object', + '#object' => $object, + ); + + return $build; +} + +/** + * Form callback; display the form for editing our module's content. + * + * @ingroup forms + * @see contextual_links_example_object_edit_form_submit() + */ +function contextual_links_example_object_edit_form($form, &$form_state, $object) { + $form['text'] = array( + '#markup' => t('This is the page that would allow you to edit object @id.', array('@id' => $object->id)), + '#prefix' => '

', + '#suffix' => '

', + ); + $form['object_id'] = array( + '#type' => 'value', + '#value' => $object->id, + ); + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + + return $form; +} + +/** + * Submit handler for contextual_links_example_object_edit_form(). + */ +function contextual_links_example_object_edit_form_submit($form, &$form_state) { + drupal_set_message(t('Object @id was edited.', array('@id' => $form_state['values']['object_id']))); +} + +/** + * Form callback; display the form for performing an example action on a node. + * + * @ingroup forms + * @see contextual_links_example_node_action_form_submit() + */ +function contextual_links_example_node_action_form($form, &$form_state, $node) { + $form['text'] = array( + '#markup' => t('This is the page that would allow you to perform an example action on node @nid.', array('@nid' => $node->nid)), + '#prefix' => '

', + '#suffix' => '

', + ); + $form['nid'] = array( + '#type' => 'value', + '#value' => $node->nid, + ); + + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + + return $form; +} + +/** + * Submit handler for contextual_links_example_node_action_form(). + */ +function contextual_links_example_node_action_form_submit($form, &$form_state) { + drupal_set_message(t('The example action was performed on node @nid.', array('@nid' => $form_state['values']['nid']))); +} +/** + * @} End of "defgroup contextual_links_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/contextual_links_example/contextual_links_example.test b/sites/all/modules/contrib/dev/examples/contextual_links_example/contextual_links_example.test new file mode 100644 index 00000000..a7abc0ed --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/contextual_links_example/contextual_links_example.test @@ -0,0 +1,62 @@ + 'Contextual links example functionality', + 'description' => 'Tests the behavior of the contextual links provided by the Contextual links example module.', + 'group' => 'Examples', + ); + } + + /** + * Enable modules and create user with specific permissions. + */ + public function setUp() { + parent::setUp('contextual', 'contextual_links_example'); + $this->webUser = $this->drupalCreateUser(array('access contextual links', 'administer blocks')); + $this->drupalLogin($this->webUser); + } + + /** + * Test the various contextual links that this module defines and displays. + */ + public function testContextualLinksExample() { + // Create a node and promote it to the front page. Then view the front page + // and verify that the "Example action" contextual link works. + $node = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1)); + $this->drupalGet(''); + $this->clickLink(t('Example action')); + $this->assertUrl('node/' . $node->nid . '/example-action', array('query' => array('destination' => 'node'))); + + // Visit our example overview page and click the third contextual link. + // This should take us to a page for editing the third object we defined. + $this->drupalGet('examples/contextual-links'); + $this->clickLink('Edit object', 2); + $this->assertUrl('examples/contextual-links/3/edit', array('query' => array('destination' => 'examples/contextual-links'))); + + // Enable our module's block, go back to the front page, and click the + // "Edit object" contextual link that we expect to be there. + $edit['blocks[contextual_links_example_example][region]'] = 'sidebar_first'; + $this->drupalPost('admin/structure/block', $edit, t('Save blocks')); + $this->drupalGet(''); + $this->clickLink('Edit object'); + $this->assertUrl('examples/contextual-links/1/edit', array('query' => array('destination' => 'node'))); + } +} diff --git a/sites/all/modules/contrib/dev/examples/cron_example/cron_example.info b/sites/all/modules/contrib/dev/examples/cron_example/cron_example.info new file mode 100644 index 00000000..d96563fd --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/cron_example/cron_example.info @@ -0,0 +1,12 @@ +name = Cron example +description = Demonstrates hook_cron() and related features +package = Example modules +core = 7.x +files[] = cron_example.test + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/cron_example/cron_example.module b/sites/all/modules/contrib/dev/examples/cron_example/cron_example.module new file mode 100644 index 00000000..6e9c2bd4 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/cron_example/cron_example.module @@ -0,0 +1,266 @@ + 'Cron Example', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('cron_example_form'), + 'access callback' => TRUE, + ); + + return $items; +} + +/** + * The form to provide a link to cron.php. + */ +function cron_example_form($form, &$form_state) { + $form['status'] = array( + '#type' => 'fieldset', + '#title' => t('Cron status information'), + ); + $form['status']['intro'] = array( + '#markup' => '
' . t('The cron example demonstrates hook_cron() and hook_cron_queue_info() processing. If you have administrative privileges you can run cron from this page and see the results.') . '
', + ); + $form['status']['last'] = array( + '#markup' => '
' . t('cron_example_cron() will next execute the first time cron runs after %time (%seconds seconds from now)', + array( + '%time' => date_iso8601(variable_get('cron_example_next_execution', time())), + '%seconds' => variable_get('cron_example_next_execution', time()) - time(), + ) + ) . '
', + ); + + if (user_access('administer site configuration')) { + $form['cron_run'] = array( + '#type' => 'fieldset', + '#title' => t('Run cron manually'), + ); + $form['cron_run']['cron_reset'] = array( + '#type' => 'checkbox', + '#title' => t("Run cron_example's cron regardless of whether interval has expired."), + '#default_value' => FALSE, + ); + $form['cron_run']['cron_trigger'] = array( + '#type' => 'submit', + '#value' => t('Run cron now'), + '#submit' => array('cron_example_form_cron_run_submit'), + ); + } + + $form['cron_queue_setup'] = array( + '#type' => 'fieldset', + '#title' => t('Cron queue setup (for hook_cron_queue_info(), etc.)'), + ); + $queue_1 = DrupalQueue::get('cron_example_queue_1'); + $queue_2 = DrupalQueue::get('cron_example_queue_2'); + $form['cron_queue_setup']['current_cron_queue_status'] = array( + '#markup' => '
' . t('There are currently %queue_1 items in queue 1 and %queue_2 items in queue 2', + array( + '%queue_1' => $queue_1->numberOfItems(), + '%queue_2' => $queue_2->numberOfItems(), + )) . '
', + ); + $form['cron_queue_setup']['num_items'] = array( + '#type' => 'select', + '#title' => t('Number of items to add to queue'), + '#options' => drupal_map_assoc(array(1, 5, 10, 100, 1000)), + '#default_value' => 5, + ); + $form['cron_queue_setup']['queue'] = array( + '#type' => 'radios', + '#title' => t('Queue to add items to'), + '#options' => array( + 'cron_example_queue_1' => t('Queue 1'), + 'cron_example_queue_2' => t('Queue 2'), + ), + '#default_value' => 'cron_example_queue_1', + ); + $form['cron_queue_setup']['submit'] = array( + '#type' => 'submit', + '#value' => t('Add jobs to queue'), + '#submit' => array('cron_example_add_jobs_to_queue'), + ); + + $form['configuration'] = array( + '#type' => 'fieldset', + '#title' => t('Configuration of cron_example_cron()'), + ); + $form['configuration']['cron_example_interval'] = array( + '#type' => 'select', + '#title' => t('Cron interval'), + '#description' => t('Time after which cron_example_cron will respond to a processing request.'), + '#default_value' => variable_get('cron_example_interval', 60 * 60), + '#options' => array( + 60 => t('1 minute'), + 300 => t('5 minutes'), + 3600 => t('1 hour'), + 60 * 60 * 24 => t('1 day'), + ), + ); + + return system_settings_form($form); +} + +/** + * Allow user to directly execute cron, optionally forcing it. + */ +function cron_example_form_cron_run_submit($form, &$form_state) { + if (!empty($form_state['values']['cron_reset'])) { + variable_set('cron_example_next_execution', 0); + } + + // We don't usually use globals in this way. This is used here only to + // make it easy to tell if cron was run by this form. + $GLOBALS['cron_example_show_status_message'] = TRUE; + if (drupal_cron_run()) { + drupal_set_message(t('Cron ran successfully.')); + } + else { + drupal_set_message(t('Cron run failed.'), 'error'); + } +} + +/** + * Submit function used to add the items to the queue. + */ +function cron_example_add_jobs_to_queue($form, &$form_state) { + $queue = $form_state['values']['queue']; + $num_items = $form_state['values']['num_items']; + + $queue = DrupalQueue::get($queue); + for ($i = 1; $i <= $num_items; $i++) { + $item = new stdClass(); + $item->created = time(); + $item->sequence = $i; + $queue->createItem($item); + } +} +/** + * Implements hook_cron(). + * + * hook_cron() is the traditional (pre-Drupal 7) hook for doing "background" + * processing. It gets called every time the Drupal cron runs and must decide + * what it will do. + * + * In this example, it does a watchdog() call after the time named in + * the variable 'cron_example_next_execution' has arrived, and then it + * resets that variable to a time in the future. + */ +function cron_example_cron() { + // Default to an hourly interval. Of course, cron has to be running at least + // hourly for this to work. + $interval = variable_get('cron_example_interval', 60 * 60); + // We usually don't want to act every time cron runs (which could be every + // minute) so keep a time for the next run in a variable. + if (time() >= variable_get('cron_example_next_execution', 0)) { + // This is a silly example of a cron job. + // It just makes it obvious that the job has run without + // making any changes to your database. + watchdog('cron_example', 'cron_example ran'); + if (!empty($GLOBALS['cron_example_show_status_message'])) { + drupal_set_message(t('cron_example executed at %time', array('%time' => date_iso8601(time(0))))); + } + variable_set('cron_example_next_execution', time() + $interval); + } +} + + +/** + * Implements hook_cron_queue_info(). + * + * hook_cron_queue_info() and family are new since Drupal 7, and allow any + * process to add work to the queue to be acted on when cron runs. Queues are + * described and worker callbacks are provided, and then only the worker + * callback needs to be implemented. + * + * All the details of queue use are done by the cron_queue implementation, so + * one doesn't need to know much about DrupalQueue(). + * + * @see queue_example.module + */ +function cron_example_cron_queue_info() { + $queues['cron_example_queue_1'] = array( + 'worker callback' => 'cron_example_queue_1_worker', + // One second max runtime per cron run. + 'time' => 1, + ); + $queues['cron_example_queue_2'] = array( + 'worker callback' => 'cron_example_queue_2_worker', + 'time' => 10, + ); + return $queues; +} + +/** + * Simple worker for our queues. + * + * @param object $item + * Any object to be worked on. + */ +function cron_example_queue_1_worker($item) { + cron_example_queue_report_work(1, $item); +} + +/** + * Simple worker for our queues. + * + * @param object $item + * Any object to be worked on. + */ +function cron_example_queue_2_worker($item) { + cron_example_queue_report_work(2, $item); +} + +/** + * Simple reporter for the workers. + * + * @param int $worker + * Worker number. + * @param object $item + * The $item which was stored in the cron queue. + */ +function cron_example_queue_report_work($worker, $item) { + if (!empty($GLOBALS['cron_example_show_status_message'])) { + drupal_set_message( + t('Queue @worker worker processed item with sequence @sequence created at @time', + array( + '@worker' => $worker, + '@sequence' => $item->sequence, + '@time' => date_iso8601($item->created), + ) + ) + ); + } + watchdog('cron_example', 'Queue @worker worker processed item with sequence @sequence created at @time', + array( + '@worker' => $worker, + '@sequence' => $item->sequence, + '@time' => date_iso8601($item->created), + ) + ); +} + +/** + * @} End of "defgroup cron_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/cron_example/cron_example.test b/sites/all/modules/contrib/dev/examples/cron_example/cron_example.test new file mode 100644 index 00000000..8dc8104e --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/cron_example/cron_example.test @@ -0,0 +1,84 @@ + 'Cron example functionality', + 'description' => 'Test the functionality of the Cron Example.', + 'group' => 'Examples', + ); + } + + /** + * Enable modules and create user with specific permissions. + */ + public function setUp() { + parent::setUp('cron_example'); + // Create user. Search content permission granted for the search block to + // be shown. + $this->webUser = $this->drupalCreateUser(array('administer site configuration')); + $this->drupalLogin($this->webUser); + } + + /** + * Test running cron through the user interface. + */ + public function testCronExampleBasic() { + // Pretend that cron has never been run (even though simpletest seems to + // run it once...) + variable_set('cron_example_next_execution', 0); + $this->drupalGet('examples/cron_example'); + + // Initial run should cause cron_example_cron() to fire. + $post = array(); + $this->drupalPost('examples/cron_example', $post, t('Run cron now')); + $this->assertText(t('cron_example executed at')); + + // Forcing should also cause cron_example_cron() to fire. + $post['cron_reset'] = TRUE; + $this->drupalPost(NULL, $post, t('Run cron now')); + $this->assertText(t('cron_example executed at')); + + // But if followed immediately and not forced, it should not fire. + $post['cron_reset'] = FALSE; + $this->drupalPost(NULL, $post, t('Run cron now')); + $this->assertNoText(t('cron_example executed at')); + + $this->assertText(t('There are currently 0 items in queue 1 and 0 items in queue 2')); + $post = array( + 'num_items' => 5, + 'queue' => 'cron_example_queue_1', + ); + $this->drupalPost(NULL, $post, t('Add jobs to queue')); + $this->assertText('There are currently 5 items in queue 1 and 0 items in queue 2'); + $post = array( + 'num_items' => 100, + 'queue' => 'cron_example_queue_2', + ); + $this->drupalPost(NULL, $post, t('Add jobs to queue')); + $this->assertText('There are currently 5 items in queue 1 and 100 items in queue 2'); + + $post = array(); + $this->drupalPost('examples/cron_example', $post, t('Run cron now')); + $this->assertPattern('/Queue 1 worker processed item with sequence 5 /'); + $this->assertPattern('/Queue 2 worker processed item with sequence 100 /'); + } +} + +/** + * @} End of "addtogroup cron_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.info b/sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.info new file mode 100644 index 00000000..50505607 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.info @@ -0,0 +1,12 @@ +name = DBTNG example +description = An example module showing how use the database API: DBTNG. +package = Example modules +core = 7.x +files[] = dbtng_example.test + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.install b/sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.install new file mode 100644 index 00000000..46f4a6d7 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.install @@ -0,0 +1,102 @@ + 'John', + 'surname' => 'Doe', + 'age' => 0, + ); + db_insert('dbtng_example') + ->fields($fields) + ->execute(); + + // Add another entry. + $fields = array( + 'name' => 'John', + 'surname' => 'Roe', + 'age' => 100, + 'uid' => 1, + ); + db_insert('dbtng_example') + ->fields($fields) + ->execute(); +} + +/** + * Implements hook_schema(). + * + * Defines the database tables used by this module. + * Remember that the easiest way to create the code for hook_schema is with + * the @link http://drupal.org/project/schema schema module @endlink + * + * @see hook_schema() + * @ingroup dbtng_example + */ +function dbtng_example_schema() { + + $schema['dbtng_example'] = array( + 'description' => 'Stores example person entries for demonstration purposes.', + 'fields' => array( + 'pid' => array( + 'type' => 'serial', + 'not null' => TRUE, + 'description' => 'Primary Key: Unique person ID.', + ), + 'uid' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'description' => "Creator user's {users}.uid", + ), + 'name' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => 'Name of the person.', + ), + 'surname' => array( + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + 'description' => 'Surname of the person.', + ), + 'age' => array( + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + 'size' => 'tiny', + 'description' => 'The age of the person in years.', + ), + ), + 'primary key' => array('pid'), + 'indexes' => array( + 'name' => array('name'), + 'surname' => array('surname'), + 'age' => array('age'), + ), + ); + + return $schema; +} diff --git a/sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.module b/sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.module new file mode 100644 index 00000000..f468dc48 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.module @@ -0,0 +1,579 @@ +fields(array('name' => 'John', 'surname' => 'Doe')) + * ->execute(); + * @endcode + * + * db_update() example: + * @code + * // UPDATE {dbtng_example} SET name = 'Jane' WHERE name = 'John' + * db_update('dbtng_example') + * ->fields(array('name' => 'Jane')) + * ->condition('name', 'John') + * ->execute(); + * @endcode + * + * db_delete() example: + * @code + * // DELETE FROM {dbtng_example} WHERE name = 'Jane' + * db_delete('dbtng_example') + * ->condition('name', 'Jane') + * ->execute(); + * @endcode + * + * See @link database Database Abstraction Layer @endlink + * @see db_insert() + * @see db_update() + * @see db_delete() + * @see drupal_write_record() + */ + +/** + * Save an entry in the database. + * + * The underlying DBTNG function is db_insert(). + * + * In Drupal 6, this would have been: + * @code + * db_query( + * "INSERT INTO {dbtng_example} (name, surname, age) + * VALUES ('%s', '%s', '%d')", + * $entry['name'], + * $entry['surname'], + * $entry['age'] + * ); + * @endcode + * + * Exception handling is shown in this example. It could be simplified + * without the try/catch blocks, but since an insert will throw an exception + * and terminate your application if the exception is not handled, it is best + * to employ try/catch. + * + * @param array $entry + * An array containing all the fields of the database record. + * + * @see db_insert() + */ +function dbtng_example_entry_insert($entry) { + $return_value = NULL; + try { + $return_value = db_insert('dbtng_example') + ->fields($entry) + ->execute(); + } + catch (Exception $e) { + drupal_set_message(t('db_insert failed. Message = %message, query= %query', + array('%message' => $e->getMessage(), '%query' => $e->query_string)), 'error'); + } + return $return_value; +} + +/** + * Update an entry in the database. + * + * The former, deprecated techniques used db_query() or drupal_write_record(): + * @code + * drupal_write_record('dbtng_example', $entry, $entry['pid']); + * @endcode + * + * @code + * db_query( + * "UPDATE {dbtng_example} + * SET name = '%s', surname = '%s', age = '%d' + * WHERE pid = %d", + * $entry['pid'] + * ); + * @endcode + * + * @param array $entry + * An array containing all the fields of the item to be updated. + * + * @see db_update() + */ +function dbtng_example_entry_update($entry) { + try { + // db_update()...->execute() returns the number of rows updated. + $count = db_update('dbtng_example') + ->fields($entry) + ->condition('pid', $entry['pid']) + ->execute(); + } + catch (Exception $e) { + drupal_set_message(t('db_update failed. Message = %message, query= %query', + array('%message' => $e->getMessage(), '%query' => $e->query_string)), 'error'); + } + return $count; +} + +/** + * Delete an entry from the database. + * + * The usage of db_query is deprecated except for static queries. + * Formerly, a deletion might have been accomplished like this: + * @code + * db_query("DELETE FROM {dbtng_example} WHERE pid = %d", $entry['pid]); + * @endcode + * + * @param array $entry + * An array containing at least the person identifier 'pid' element of the + * entry to delete. + * + * @see db_delete() + */ +function dbtng_example_entry_delete($entry) { + db_delete('dbtng_example') + ->condition('pid', $entry['pid']) + ->execute(); + +} + + +/** + * Read from the database using a filter array. + * + * In Drupal 6, the standard function to perform reads was db_query(), and + * for static queries, it still is. + * + * db_query() used an SQL query with placeholders and arguments as parameters. + * + * @code + * // Old way + * $query = "SELECT * FROM {dbtng_example} n WHERE n.uid = %d AND name = '%s'"; + * $result = db_query($query, $uid, $name); + * @endcode + * + * Drupal 7 DBTNG provides an abstracted interface that will work with a wide + * variety of database engines. + * + * db_query() is deprecated except when doing a static query. The following is + * perfectly acceptable in Drupal 7. See + * @link http://drupal.org/node/310072 the handbook page on static queries @endlink + * + * @code + * // SELECT * FROM {dbtng_example} WHERE uid = 0 AND name = 'John' + * db_query( + * "SELECT * FROM {dbtng_example} WHERE uid = :uid and name = :name", + * array(':uid' => 0, ':name' => 'John') + * )->execute(); + * @endcode + * + * But for more dynamic queries, Drupal provides the db_select() API method, so + * there are several ways to perform the same SQL query. See the + * @link http://drupal.org/node/310075 handbook page on dynamic queries. @endlink + * + * @code + * // SELECT * FROM {dbtng_example} WHERE uid = 0 AND name = 'John' + * db_select('dbtng_example') + * ->fields('dbtng_example') + * ->condition('uid', 0) + * ->condition('name', 'John') + * ->execute(); + * @endcode + * + * Here is db_select with named placeholders: + * @code + * // SELECT * FROM {dbtng_example} WHERE uid = 0 AND name = 'John' + * $arguments = array(':name' => 'John', ':uid' => 0); + * db_select('dbtng_example') + * ->fields('dbtng_example') + * ->where('uid = :uid AND name = :name', $arguments) + * ->execute(); + * @endcode + * + * Conditions are stacked and evaluated as AND and OR depending on the type of + * query. For more information, read the conditional queries handbook page at: + * http://drupal.org/node/310086 + * + * The condition argument is an 'equal' evaluation by default, but this can be + * altered: + * @code + * // SELECT * FROM {dbtng_example} WHERE age > 18 + * db_select('dbtng_example') + * ->fields('dbtng_example') + * ->condition('age', 18, '>') + * ->execute(); + * @endcode + * + * @param array $entry + * An array containing all the fields used to search the entries in the table. + * + * @return object + * An object containing the loaded entries if found. + * + * @see db_select() + * @see db_query() + * @see http://drupal.org/node/310072 + * @see http://drupal.org/node/310075 + */ +function dbtng_example_entry_load($entry = array()) { + // Read all fields from the dbtng_example table. + $select = db_select('dbtng_example', 'example'); + $select->fields('example'); + + // Add each field and value as a condition to this query. + foreach ($entry as $field => $value) { + $select->condition($field, $value); + } + // Return the result in object format. + return $select->execute()->fetchAll(); +} + +/** + * Render a filtered list of entries in the database. + * + * DBTNG also helps processing queries that return several rows, providing the + * found objects in the same query execution call. + * + * This function queries the database using a JOIN between users table and the + * example entries, to provide the username that created the entry, and creates + * a table with the results, processing each row. + * + * SELECT + * e.pid as pid, e.name as name, e.surname as surname, e.age as age + * u.name as username + * FROM + * {dbtng_example} e + * JOIN + * users u ON e.uid = u.uid + * WHERE + * e.name = 'John' AND e.age > 18 + * + * @see db_select() + * @see http://drupal.org/node/310075 + */ +function dbtng_example_advanced_list() { + $output = ''; + + $select = db_select('dbtng_example', 'e'); + // Join the users table, so we can get the entry creator's username. + $select->join('users', 'u', 'e.uid = u.uid'); + // Select these specific fields for the output. + $select->addField('e', 'pid'); + $select->addField('u', 'name', 'username'); + $select->addField('e', 'name'); + $select->addField('e', 'surname'); + $select->addField('e', 'age'); + // Filter only persons named "John". + $select->condition('e.name', 'John'); + // Filter only persons older than 18 years. + $select->condition('e.age', 18, '>'); + // Make sure we only get items 0-49, for scalability reasons. + $select->range(0, 50); + + // Now, loop all these entries and show them in a table. Note that there is no + // db_fetch_* object or array function being called here. Also note that the + // following line could have been written as + // $entries = $select->execute()->fetchAll() which would return each selected + // record as an object instead of an array. + $entries = $select->execute()->fetchAll(PDO::FETCH_ASSOC); + if (!empty($entries)) { + $rows = array(); + foreach ($entries as $entry) { + // Sanitize the data before handing it off to the theme layer. + $rows[] = array_map('check_plain', $entry); + } + // Make a table for them. + $header = array(t('Id'), t('Created by'), t('Name'), t('Surname'), t('Age')); + $output .= theme('table', array('header' => $header, 'rows' => $rows)); + } + else { + drupal_set_message(t('No entries meet the filter criteria (Name = "John" and Age > 18).')); + } + return $output; +} + +/** + * Implements hook_help(). + * + * Show some help on each form provided by this module. + */ +function dbtng_example_help($path) { + $output = ''; + switch ($path) { + case 'examples/dbtng': + $output = t('Generate a list of all entries in the database. There is no filter in the query.'); + break; + + case 'examples/dbtng/advanced': + $output = t('A more complex list of entries in the database.') . ' '; + $output .= t('Only the entries with name = "John" and age older than 18 years are shown, the username of the person who created the entry is also shown.'); + break; + + case 'examples/dbtng/update': + $output = t('Demonstrates a database update operation.'); + break; + + case 'examples/dbtng/add': + $output = t('Add an entry to the dbtng_example table.'); + break; + } + return $output; +} + +/** + * Implements hook_menu(). + * + * Set up calls to drupal_get_form() for all our example cases. + */ +function dbtng_example_menu() { + $items = array(); + + $items['examples/dbtng'] = array( + 'title' => 'DBTNG Example', + 'page callback' => 'dbtng_example_list', + 'access callback' => TRUE, + ); + $items['examples/dbtng/list'] = array( + 'title' => 'List', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -10, + ); + $items['examples/dbtng/add'] = array( + 'title' => 'Add entry', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('dbtng_example_form_add'), + 'access callback' => TRUE, + 'type' => MENU_LOCAL_TASK, + 'weight' => -9, + ); + $items['examples/dbtng/update'] = array( + 'title' => 'Update entry', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('dbtng_example_form_update'), + 'type' => MENU_LOCAL_TASK, + 'access callback' => TRUE, + 'weight' => -5, + ); + $items['examples/dbtng/advanced'] = array( + 'title' => 'Advanced list', + 'page callback' => 'dbtng_example_advanced_list', + 'access callback' => TRUE, + 'type' => MENU_LOCAL_TASK, + ); + + return $items; +} + +/** + * Render a list of entries in the database. + */ +function dbtng_example_list() { + $output = ''; + + // Get all entries in the dbtng_example table. + if ($entries = dbtng_example_entry_load()) { + $rows = array(); + foreach ($entries as $entry) { + // Sanitize the data before handing it off to the theme layer. + $rows[] = array_map('check_plain', (array) $entry); + } + // Make a table for them. + $header = array(t('Id'), t('uid'), t('Name'), t('Surname'), t('Age')); + $output .= theme('table', array('header' => $header, 'rows' => $rows)); + } + else { + drupal_set_message(t('No entries have been added yet.')); + } + return $output; +} + +/** + * Prepare a simple form to add an entry, with all the interesting fields. + */ +function dbtng_example_form_add($form, &$form_state) { + $form = array(); + + $form['add'] = array( + '#type' => 'fieldset', + '#title' => t('Add a person entry'), + ); + $form['add']['name'] = array( + '#type' => 'textfield', + '#title' => t('Name'), + '#size' => 15, + ); + $form['add']['surname'] = array( + '#type' => 'textfield', + '#title' => t('Surname'), + '#size' => 15, + ); + $form['add']['age'] = array( + '#type' => 'textfield', + '#title' => t('Age'), + '#size' => 5, + '#description' => t("Values greater than 127 will cause an exception. Try it - it's a great example why exception handling is needed with DTBNG."), + ); + $form['add']['submit'] = array( + '#type' => 'submit', + '#value' => t('Add'), + ); + + return $form; +} + +/** + * Submit handler for 'add entry' form. + */ +function dbtng_example_form_add_submit($form, &$form_state) { + global $user; + + // Save the submitted entry. + $entry = array( + 'name' => $form_state['values']['name'], + 'surname' => $form_state['values']['surname'], + 'age' => $form_state['values']['age'], + 'uid' => $user->uid, + ); + $return = dbtng_example_entry_insert($entry); + if ($return) { + drupal_set_message(t("Created entry @entry", array('@entry' => print_r($entry, TRUE)))); + } +} + +/** + * Sample UI to update a record. + */ +function dbtng_example_form_update($form, &$form_state) { + $form = array( + '#prefix' => '
', + '#suffix' => '
', + ); + + $entries = dbtng_example_entry_load(); + $keyed_entries = array(); + if (empty($entries)) { + $form['no_values'] = array( + '#value' => t("No entries exist in the table dbtng_example table."), + ); + return $form; + } + + foreach ($entries as $entry) { + $options[$entry->pid] = t("@pid: @name @surname (@age)", + array( + '@pid' => $entry->pid, + '@name' => $entry->name, + '@surname' => $entry->surname, + '@age' => $entry->age, + ) + ); + $keyed_entries[$entry->pid] = $entry; + } + $default_entry = !empty($form_state['values']['pid']) ? $keyed_entries[$form_state['values']['pid']] : $entries[0]; + + $form_state['entries'] = $keyed_entries; + + $form['pid'] = array( + '#type' => 'select', + '#options' => $options, + '#title' => t('Choose entry to update'), + '#default_value' => $default_entry->pid, + '#ajax' => array( + 'wrapper' => 'updateform', + 'callback' => 'dbtng_example_form_update_callback', + ), + ); + + $form['name'] = array( + '#type' => 'textfield', + '#title' => t('Updated first name'), + '#size' => 15, + '#default_value' => $default_entry->name, + ); + + $form['surname'] = array( + '#type' => 'textfield', + '#title' => t('Updated last name'), + '#size' => 15, + '#default_value' => $default_entry->surname, + ); + $form['age'] = array( + '#type' => 'textfield', + '#title' => t('Updated age'), + '#size' => 4, + '#default_value' => $default_entry->age, + '#description' => t("Values greater than 127 will cause an exception"), + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Update'), + ); + return $form; +} + +/** + * AJAX callback handler for the pid select. + * + * When the pid changes, populates the defaults from the database in the form. + */ +function dbtng_example_form_update_callback($form, $form_state) { + $entry = $form_state['entries'][$form_state['values']['pid']]; + // Setting the #value of items is the only way I was able to figure out + // to get replaced defaults on these items. #default_value will not do it + // and shouldn't. + foreach (array('name', 'surname', 'age') as $item) { + $form[$item]['#value'] = $entry->$item; + } + return $form; +} + +/** + * Submit handler for 'update entry' form. + */ +function dbtng_example_form_update_submit($form, &$form_state) { + global $user; + + // Save the submitted entry. + $entry = array( + 'pid' => $form_state['values']['pid'], + 'name' => $form_state['values']['name'], + 'surname' => $form_state['values']['surname'], + 'age' => $form_state['values']['age'], + 'uid' => $user->uid, + ); + $count = dbtng_example_entry_update($entry); + drupal_set_message(t("Updated entry @entry (@count row updated)", + array('@count' => $count, '@entry' => print_r($entry, TRUE)))); +} +/** + * @} End of "defgroup dbtng_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.test b/sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.test new file mode 100644 index 00000000..6302bcee --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/dbtng_example/dbtng_example.test @@ -0,0 +1,191 @@ + 'DBTNG example unit and UI tests', + 'description' => 'Various unit tests on the dbtng example module.' , + 'group' => 'Examples', + ); + } + + /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp('dbtng_example'); + } + + /** + * Test default module installation, two entries in the database table. + */ + public function testInstall() { + $result = dbtng_example_entry_load(); + $this->assertEqual( + count($result), + 2, + 'Found two entries in the table after installing the module.' + ); + } + + + /** + * Test the UI. + */ + public function testUI() { + // Test the basic list. + $this->drupalGet('examples/dbtng'); + $this->assertPattern("/John[td\/<>\w]+Doe/", "Text 'John Doe' found in table"); + + // Test the add tab. + // Add the new entry. + $this->drupalPost('examples/dbtng/add', + array( + 'name' => 'Some', + 'surname' => 'Anonymous', + 'age' => 33, + ), + t('Add') + ); + // Now find the new entry. + $this->drupalGet('examples/dbtng'); + $this->assertPattern("/Some[td\/<>\w]+Anonymous/", "Text 'Some Anonymous' found in table"); + + // Try the update tab. + // Find out the pid of our "anonymous" guy. + $result = dbtng_example_entry_load(array('surname' => 'Anonymous')); + $this->drupalGet("examples/dbtng"); + $this->assertEqual( + count($result), + 1, + 'Found one entry in the table with surname = "Anonymous".' + ); + $entry = $result[0]; + unset($entry->uid); + $entry->name = 'NewFirstName'; + $this->drupalPost('examples/dbtng/update', (array) $entry, t('Update')); + // Now find the new entry. + $this->drupalGet('examples/dbtng'); + $this->assertPattern("/NewFirstName[td\/<>\w]+Anonymous/", "Text 'NewFirstName Anonymous' found in table"); + + // Try the advanced tab. + $this->drupalGet('examples/dbtng/advanced'); + $rows = $this->xpath("//*[@id='block-system-main']/div/table[1]/tbody/tr"); + $this->assertEqual(count($rows), 1, "One row found in advanced view"); + $this->assertFieldByXPath("//*[@id='block-system-main']/div/table[1]/tbody/tr/td[4]", "Roe", "Name 'Roe' Exists in advanced list"); + } + + /** + * Test several combinations, adding entries, updating and deleting. + */ + public function testAPIExamples() { + // Create a new entry. + $entry = array( + 'name' => 'James', + 'surname' => 'Doe', + 'age' => 23, + ); + dbtng_example_entry_insert($entry); + + // Save another entry. + $entry = array( + 'name' => 'Jane', + 'surname' => 'NotDoe', + 'age' => 19, + ); + dbtng_example_entry_insert($entry); + + // Verify that 4 records are found in the database. + $result = dbtng_example_entry_load(); + $this->assertEqual( + count($result), + 4, + 'Found a total of four entries in the table after creating two additional entries.' + ); + + // Verify 2 of these records have 'Doe' as surname. + $result = dbtng_example_entry_load(array('surname' => 'Doe')); + $this->assertEqual( + count($result), + 2, + 'Found two entries in the table with surname = "Doe".' + ); + + // Now find our not-Doe entry. + $result = dbtng_example_entry_load(array('surname' => 'NotDoe')); + $this->assertEqual( + count($result), + 1, + 'Found one entry in the table with surname "NotDoe'); + // Our NotDoe will be changed to "NowDoe". + $entry = $result[0]; + $entry->surname = "NowDoe"; + dbtng_example_entry_update((array) $entry); + + $result = dbtng_example_entry_load(array('surname' => 'NowDoe')); + $this->assertEqual( + count($result), + 1, + "Found renamed 'NowDoe' surname"); + + // Read only John Doe entry. + $result = dbtng_example_entry_load(array('name' => 'John', 'surname' => 'Doe')); + $this->assertEqual( + count($result), + 1, + 'Found one entry for John Doe.' + ); + // Get the entry. + $entry = (array) end($result); + // Change age to 45 + $entry['age'] = 45; + // Update entry in database. + dbtng_example_entry_update((array) $entry); + + // Find entries with age = 45 + // Read only John Doe entry. + $result = dbtng_example_entry_load(array('surname' => 'NowDoe')); + $this->assertEqual( + count($result), + 1, + 'Found one entry with surname = Nowdoe.' + ); + + // Verify it is Jane NowDoe. + $entry = (array) end($result); + $this->assertEqual( + $entry['name'], + 'Jane', + 'The name Jane is found in the entry' + ); + $this->assertEqual( + $entry['surname'], + 'NowDoe', + 'The surname NowDoe is found in the entry' + ); + + // Delete the entry. + dbtng_example_entry_delete($entry); + + // Verify that now there are only 3 records. + $result = dbtng_example_entry_load(); + $this->assertEqual( + count($result), + 3, + 'Found only three records, a record was deleted.' + ); + } +} diff --git a/sites/all/modules/contrib/dev/examples/email_example/email_example.info b/sites/all/modules/contrib/dev/examples/email_example/email_example.info new file mode 100644 index 00000000..8b123ab7 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/email_example/email_example.info @@ -0,0 +1,12 @@ +name = E-mail Example +description = Demonstrate Drupal's e-mail APIs. +package = Example modules +core = 7.x +files[] = email_example.test + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/email_example/email_example.module b/sites/all/modules/contrib/dev/examples/email_example/email_example.module new file mode 100644 index 00000000..6b84bc81 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/email_example/email_example.module @@ -0,0 +1,212 @@ + $message['language']->language, + ); + + switch ($key) { + // Send a simple message from the contact form. + case 'contact_message': + $message['subject'] = t('E-mail sent from @site-name', array('@site-name' => variable_get('site_name', 'Drupal')), $options); + // Note that the message body is an array, not a string. + $message['body'][] = t('@name sent you the following message:', array('@name' => $user->name), $options); + // Because this is just user-entered text, we do not need to translate it. + // Since user-entered text may have unintentional HTML entities in it like + // '<' or '>', we need to make sure these entities are properly escaped, + // as the body will later be transformed from HTML to text, meaning + // that a normal use of '<' will result in truncation of the message. + $message['body'][] = check_plain($params['message']); + break; + } +} + +/** + * Sends an e-mail. + * + * @param array $form_values + * An array of values from the contact form fields that were submitted. + * There are just two relevant items: $form_values['email'] and + * $form_values['message']. + */ +function email_example_mail_send($form_values) { + // All system mails need to specify the module and template key (mirrored from + // hook_mail()) that the message they want to send comes from. + $module = 'email_example'; + $key = 'contact_message'; + + // Specify 'to' and 'from' addresses. + $to = $form_values['email']; + $from = variable_get('site_mail', 'admin@example.com'); + + // "params" loads in additional context for email content completion in + // hook_mail(). In this case, we want to pass in the values the user entered + // into the form, which include the message body in $form_values['message']. + $params = $form_values; + + // The language of the e-mail. This will one of three values: + // - user_preferred_language(): Used for sending mail to a particular website + // user, so that the mail appears in their preferred language. + // - global $language: Used when sending a mail back to the user currently + // viewing the site. This will send it in the language they're currently + // using. + // - language_default(): Used when sending mail to a pre-existing, 'neutral' + // address, such as the system e-mail address, or when you're unsure of the + // language preferences of the intended recipient. + // + // Since in our case, we are sending a message to a random e-mail address that + // is not necessarily tied to a user account, we will use the site's default + // language. + $language = language_default(); + + // Whether or not to automatically send the mail when drupal_mail() is + // called. This defaults to TRUE, and is normally what you want unless you + // need to do additional processing before drupal_mail_send() is called. + $send = TRUE; + // Send the mail, and check for success. Note that this does not guarantee + // message delivery; only that there were no PHP-related issues encountered + // while sending. + $result = drupal_mail($module, $key, $to, $language, $params, $from, $send); + if ($result['result'] == TRUE) { + drupal_set_message(t('Your message has been sent.')); + } + else { + drupal_set_message(t('There was a problem sending your message and it was not sent.'), 'error'); + } + +} + +/** + * Implements hook_mail_alter(). + * + * This function is not required to send an email using Drupal's mail system. + * + * Hook_mail_alter() provides an interface to alter any aspect of email sent by + * Drupal. You can use this hook to add a common site footer to all outgoing + * email, add extra header fields, and/or modify the email in anyway. HTML-izing + * the outgoing email is one possibility. + */ +function email_example_mail_alter(&$message) { + // For the purpose of this example, modify all the outgoing messages and + // attach a site signature. The signature will be translated to the language + // in which message was built. + $options = array( + 'langcode' => $message['language']->language, + ); + + $signature = t("\n--\nMail altered by email_example module.", array(), $options); + if (is_array($message['body'])) { + $message['body'][] = $signature; + } + else { + // Some modules use the body as a string, erroneously. + $message['body'] .= $signature; + } +} + +/** + * Supporting functions. + */ + +/** + * Implements hook_menu(). + * + * Set up a page with an e-mail contact form on it. + */ +function email_example_menu() { + $items['example/email_example'] = array( + 'title' => 'E-mail Example: contact form', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('email_example_form'), + 'access arguments' => array('access content'), + ); + + return $items; +} + +/** + * The contact form. + */ +function email_example_form() { + $form['intro'] = array( + '#markup' => t('Use this form to send a message to an e-mail address. No spamming!'), + ); + $form['email'] = array( + '#type' => 'textfield', + '#title' => t('E-mail address'), + '#required' => TRUE, + ); + $form['message'] = array( + '#type' => 'textarea', + '#title' => t('Message'), + '#required' => TRUE, + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + + return $form; +} + +/** + * Form validation logic for the contact form. + */ +function email_example_form_validate($form, &$form_state) { + if (!valid_email_address($form_state['values']['email'])) { + form_set_error('email', t('That e-mail address is not valid.')); + } +} + +/** + * Form submission logic for the contact form. + */ +function email_example_form_submit($form, &$form_state) { + email_example_mail_send($form_state['values']); +} +/** + * @} End of "defgroup email_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/email_example/email_example.test b/sites/all/modules/contrib/dev/examples/email_example/email_example.test new file mode 100644 index 00000000..f95a2cda --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/email_example/email_example.test @@ -0,0 +1,103 @@ + 'Email example', + 'description' => 'Verify the email submission using the contact form.', + 'group' => 'Examples', + ); + } + + /** + * {@inheritdoc} + */ + public function setUp() { + // Enable the email_example module. + parent::setUp('email_example'); + } + + /** + * Verify the functionality of the example module. + */ + public function testContactForm() { + // Create and login user. + $account = $this->drupalCreateUser(); + $this->drupalLogin($account); + + // Set default language for t() translations. + $t_options = array( + 'langcode' => language_default()->language, + ); + + // First try to send to an invalid email address. + $email_options = array( + 'email' => $this->randomName(), + 'message' => $this->randomName(128), + ); + $result = $this->drupalPost('example/email_example', $email_options, t('Submit')); + + // Verify that email address is invalid and email was not sent. + $this->assertText(t('That e-mail address is not valid.'), 'Options were validated and form submitted.'); + $this->assertTrue(!count($this->drupalGetMails()), 'No email was sent.'); + + // Now try with a valid email address. + $email_options['email'] = $this->randomName() . '@' . $this->randomName() . '.drupal'; + $result = $this->drupalPost('example/email_example', $email_options, t('Submit')); + + // Verify that email address is valid and email was sent. + $this->assertTrue(count($this->drupalGetMails()), 'An email has been sent.'); + + // Validate sent email. + $email = $this->drupalGetMails(); + // Grab the first entry. + $email = $email[0]; + + // Verify email recipient. + $this->assertEqual( + $email['to'], + $email_options['email'], + 'Email recipient successfully verified.' + ); + + // Verify email subject. + $this->assertEqual( + $email['subject'], + t('E-mail sent from @site-name', array('@site-name' => variable_get('site_name', 'Drupal')), $t_options), + 'Email subject successfully verified.' + ); + + // Verify email body. + $this->assertTrue( + strstr( + $email['body'], + t('@name sent you the following message:', array('@name' => $account->name), $t_options) + ), + 'Email body successfully verified.' + ); + + // Verify that signature is attached. + $this->assertTrue( + strstr( + $email['body'], + t("--\nMail altered by email_example module.", array(), $t_options) + ), + 'Email signature successfully verified.' + ); + } +} diff --git a/sites/all/modules/contrib/dev/examples/entity_example/entity_example.info b/sites/all/modules/contrib/dev/examples/entity_example/entity_example.info new file mode 100644 index 00000000..4cb8bc1a --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/entity_example/entity_example.info @@ -0,0 +1,14 @@ +name = Entity Example +description = A simple entity example showing the main steps required to set up your own entity. +core = 7.x +package = Example modules +dependencies[] = field +files[] = entity_example.test +configure = admin/structure/entity_example_basic/manage + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/entity_example/entity_example.install b/sites/all/modules/contrib/dev/examples/entity_example/entity_example.install new file mode 100644 index 00000000..9735dce6 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/entity_example/entity_example.install @@ -0,0 +1,71 @@ + 'The base table for our basic entity.', + 'fields' => array( + 'basic_id' => array( + 'description' => 'Primary key of the basic entity.', + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + // If we allow multiple bundles, then the schema must handle that; + // We'll put it in the 'bundle_type' field to avoid confusion with the + // entity type. + 'bundle_type' => array( + 'description' => 'The bundle type', + 'type' => 'text', + 'size' => 'medium', + 'not null' => TRUE, + ), + // Additional properties are just things that are common to all + // entities and don't require field storage. + 'item_description' => array( + 'description' => 'A description of the item', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'created' => array( + 'description' => 'The Unix timestamp of the entity creation time.', + 'type' => 'int', + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('basic_id'), + ); + + return $schema; +} + + +/** + * Implements hook_uninstall(). + * + * At uninstall time we'll notify field.module that the entity was deleted + * so that attached fields can be cleaned up. + * + * @ingroup entity_example + */ +function entity_example_uninstall() { + field_attach_delete_bundle('entity_example_basic', 'first_example_bundle'); +} diff --git a/sites/all/modules/contrib/dev/examples/entity_example/entity_example.module b/sites/all/modules/contrib/dev/examples/entity_example/entity_example.module new file mode 100644 index 00000000..de39adb0 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/entity_example/entity_example.module @@ -0,0 +1,635 @@ + t('Example Basic Entity'), + + // The controller for our Entity, extending the Drupal core controller. + 'controller class' => 'EntityExampleBasicController', + + // The table for this entity defined in hook_schema() + 'base table' => 'entity_example_basic', + + // Returns the uri elements of an entity. + 'uri callback' => 'entity_example_basic_uri', + + // IF fieldable == FALSE, we can't attach fields. + 'fieldable' => TRUE, + + // entity_keys tells the controller what database fields are used for key + // functions. It is not required if we don't have bundles or revisions. + // Here we do not support a revision, so that entity key is omitted. + 'entity keys' => array( + // The 'id' (basic_id here) is the unique id. + 'id' => 'basic_id' , + // Bundle will be determined by the 'bundle_type' field. + 'bundle' => 'bundle_type', + ), + 'bundle keys' => array( + 'bundle' => 'bundle_type', + ), + + // FALSE disables caching. Caching functionality is handled by Drupal core. + 'static cache' => TRUE, + + // Bundles are alternative groups of fields or configuration + // associated with a base entity type. + 'bundles' => array( + 'first_example_bundle' => array( + 'label' => 'First example bundle', + // 'admin' key is used by the Field UI to provide field and + // display UI pages. + 'admin' => array( + 'path' => 'admin/structure/entity_example_basic/manage', + 'access arguments' => array('administer entity_example_basic entities'), + ), + ), + ), + // View modes allow entities to be displayed differently based on context. + // As a demonstration we'll support "Tweaky", but we could have and support + // multiple display modes. + 'view modes' => array( + 'tweaky' => array( + 'label' => t('Tweaky'), + 'custom settings' => FALSE, + ), + ), + ); + + return $info; +} + +/** + * Fetch a basic object. + * + * This function ends up being a shim between the menu system and + * entity_example_basic_load_multiple(). + * + * This function gets its name from the menu system's wildcard + * naming conventions. For example, /path/%wildcard would end + * up calling wildcard_load(%wildcard value). In our case defining + * the path: examples/entity_example/basic/%entity_example_basic in + * hook_menu() tells Drupal to call entity_example_basic_load(). + * + * @param int $basic_id + * Integer specifying the basic entity id. + * @param bool $reset + * A boolean indicating that the internal cache should be reset. + * + * @return object + * A fully-loaded $basic object or FALSE if it cannot be loaded. + * + * @see entity_example_basic_load_multiple() + * @see entity_example_menu() + */ +function entity_example_basic_load($basic_id = NULL, $reset = FALSE) { + $basic_ids = (isset($basic_id) ? array($basic_id) : array()); + $basic = entity_example_basic_load_multiple($basic_ids, array(), $reset); + return $basic ? reset($basic) : FALSE; +} + +/** + * Loads multiple basic entities. + * + * We only need to pass this request along to entity_load(), which + * will in turn call the load() method of our entity controller class. + */ +function entity_example_basic_load_multiple($basic_ids = FALSE, $conditions = array(), $reset = FALSE) { + return entity_load('entity_example_basic', $basic_ids, $conditions, $reset); +} + +/** + * Implements the uri callback. + */ +function entity_example_basic_uri($basic) { + return array( + 'path' => 'examples/entity_example/basic/' . $basic->basic_id, + ); +} + +/** + * Implements hook_menu(). + */ +function entity_example_menu() { + $items['examples/entity_example'] = array( + 'title' => 'Entity Example', + 'page callback' => 'entity_example_info_page', + 'access arguments' => array('view any entity_example_basic entity'), + ); + + // This provides a place for Field API to hang its own + // interface and has to be the same as what was defined + // in basic_entity_info() above. + $items['admin/structure/entity_example_basic/manage'] = array( + 'title' => 'Administer entity_example_basic entity type', + 'page callback' => 'entity_example_basic_list_entities', + 'access arguments' => array('administer entity_example_basic entities'), + ); + + // Add example entities. + $items['admin/structure/entity_example_basic/manage/add'] = array( + 'title' => 'Add an Entity Example Basic Entity', + 'page callback' => 'entity_example_basic_add', + 'access arguments' => array('create entity_example_basic entities'), + 'type' => MENU_LOCAL_ACTION, + ); + + // List of all entity_example_basic entities. + $items['admin/structure/entity_example_basic/manage/list'] = array( + 'title' => 'List', + 'type' => MENU_DEFAULT_LOCAL_TASK, + ); + + // The page to view our entities - needs to follow what + // is defined in basic_uri and will use load_basic to retrieve + // the necessary entity info. + $items['examples/entity_example/basic/%entity_example_basic'] = array( + 'title callback' => 'entity_example_basic_title', + 'title arguments' => array(3), + 'page callback' => 'entity_example_basic_view', + 'page arguments' => array(3), + 'access arguments' => array('view any entity_example_basic entity'), + ); + + // 'View' tab for an individual entity page. + $items['examples/entity_example/basic/%entity_example_basic/view'] = array( + 'title' => 'View', + 'type' => MENU_DEFAULT_LOCAL_TASK, + 'weight' => -10, + ); + + // 'Edit' tab for an individual entity page. + $items['examples/entity_example/basic/%entity_example_basic/edit'] = array( + 'title' => 'Edit', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('entity_example_basic_form', 3), + 'access arguments' => array('edit any entity_example_basic entity'), + 'type' => MENU_LOCAL_TASK, + ); + + // Add example entities. + $items['examples/entity_example/basic/add'] = array( + 'title' => 'Add an Entity Example Basic Entity', + 'page callback' => 'entity_example_basic_add', + 'access arguments' => array('create entity_example_basic entities'), + ); + + return $items; +} + +/** + * Basic information for the page. + */ +function entity_example_info_page() { + $content['preface'] = array( + '#type' => 'item', + '#markup' => t('The entity example provides a simple example entity.'), + ); + if (user_access('administer entity_example_basic entities')) { + $content['preface']['#markup'] = t('You can administer these and add fields and change the view !link.', + array('!link' => l(t('here'), 'admin/structure/entity_example_basic/manage')) + ); + } + $content['table'] = entity_example_basic_list_entities(); + + return $content; +} + +/** + * Implements hook_permission(). + */ +function entity_example_permission() { + $permissions = array( + 'administer entity_example_basic entities' => array( + 'title' => t('Administer entity_example_basic entities'), + ), + 'view any entity_example_basic entity' => array( + 'title' => t('View any Entity Example Basic entity'), + ), + 'edit any entity_example_basic entity' => array( + 'title' => t('Edit any Entity Example Basic entity'), + ), + 'create entity_example_basic entities' => array( + 'title' => t('Create Entity Example Basic Entities'), + ), + ); + return $permissions; +} + +/** + * Returns a render array with all entity_example_basic entities. + * + * In this basic example we know that there won't be many entities, + * so we'll just load them all for display. See pager_example.module + * to implement a pager. Most implementations would probably do this + * with the contrib Entity API module, or a view using views module, + * but we avoid using non-core features in the Examples project. + * + * @see pager_example.module + */ +function entity_example_basic_list_entities() { + $content = array(); + // Load all of our entities. + $entities = entity_example_basic_load_multiple(); + if (!empty($entities)) { + foreach ($entities as $entity) { + // Create tabular rows for our entities. + $rows[] = array( + 'data' => array( + 'id' => $entity->basic_id, + 'item_description' => l($entity->item_description, 'examples/entity_example/basic/' . $entity->basic_id), + 'bundle' => $entity->bundle_type, + ), + ); + } + // Put our entities into a themed table. See theme_table() for details. + $content['entity_table'] = array( + '#theme' => 'table', + '#rows' => $rows, + '#header' => array(t('ID'), t('Item Description'), t('Bundle')), + ); + } + else { + // There were no entities. Tell the user. + $content[] = array( + '#type' => 'item', + '#markup' => t('No entity_example_basic entities currently exist.'), + ); + } + return $content; +} + +/** + * Callback for a page title when this entity is displayed. + */ +function entity_example_basic_title($entity) { + return t('Entity Example Basic (item_description=@item_description)', array('@item_description' => $entity->item_description)); +} + +/** + * Menu callback to display an entity. + * + * As we load the entity for display, we're responsible for invoking a number + * of hooks in their proper order. + * + * @see hook_entity_prepare_view() + * @see hook_entity_view() + * @see hook_entity_view_alter() + */ +function entity_example_basic_view($entity, $view_mode = 'tweaky') { + // Our entity type, for convenience. + $entity_type = 'entity_example_basic'; + // Start setting up the content. + $entity->content = array( + '#view_mode' => $view_mode, + ); + // Build fields content - this is where the Field API really comes in to play. + // The task has very little code here because it all gets taken care of by + // field module. + // field_attach_prepare_view() lets the fields load any data they need + // before viewing. + field_attach_prepare_view($entity_type, array($entity->basic_id => $entity), + $view_mode); + // We call entity_prepare_view() so it can invoke hook_entity_prepare_view() + // for us. + entity_prepare_view($entity_type, array($entity->basic_id => $entity)); + // Now field_attach_view() generates the content for the fields. + $entity->content += field_attach_view($entity_type, $entity, $view_mode); + + // OK, Field API done, now we can set up some of our own data. + $entity->content['created'] = array( + '#type' => 'item', + '#title' => t('Created date'), + '#markup' => format_date($entity->created), + ); + $entity->content['item_description'] = array( + '#type' => 'item', + '#title' => t('Item Description'), + '#markup' => $entity->item_description, + ); + + // Now to invoke some hooks. We need the language code for + // hook_entity_view(), so let's get that. + global $language; + $langcode = $language->language; + // And now invoke hook_entity_view(). + module_invoke_all('entity_view', $entity, $entity_type, $view_mode, + $langcode); + // Now invoke hook_entity_view_alter(). + drupal_alter(array('entity_example_basic_view', 'entity_view'), + $entity->content, $entity_type); + + // And finally return the content. + return $entity->content; +} + +/** + * Implements hook_field_extra_fields(). + * + * This exposes the "extra fields" (usually properties that can be configured + * as if they were fields) of the entity as pseudo-fields + * so that they get handled by the Entity and Field core functionality. + * Node titles get treated in a similar manner. + */ +function entity_example_field_extra_fields() { + $form_elements['item_description'] = array( + 'label' => t('Item Description'), + 'description' => t('Item Description (an extra form field)'), + 'weight' => -5, + ); + $display_elements['created'] = array( + 'label' => t('Creation date'), + 'description' => t('Creation date (an extra display field)'), + 'weight' => 0, + ); + $display_elements['item_description'] = array( + 'label' => t('Item Description'), + 'description' => t('Just like title, but trying to point out that it is a separate property'), + 'weight' => 0, + ); + + // Since we have only one bundle type, we'll just provide the extra_fields + // for it here. + $extra_fields['entity_example_basic']['first_example_bundle']['form'] = $form_elements; + $extra_fields['entity_example_basic']['first_example_bundle']['display'] = $display_elements; + + return $extra_fields; +} + +/** + * Provides a wrapper on the edit form to add a new entity. + */ +function entity_example_basic_add() { + // Create a basic entity structure to be used and passed to the validation + // and submission functions. + $entity = entity_get_controller('entity_example_basic')->create(); + return drupal_get_form('entity_example_basic_form', $entity); +} + +/** + * Form function to create an entity_example_basic entity. + * + * The pattern is: + * - Set up the form for the data that is specific to your + * entity: the columns of your base table. + * - Call on the Field API to pull in the form elements + * for fields attached to the entity. + */ +function entity_example_basic_form($form, &$form_state, $entity) { + $form['item_description'] = array( + '#type' => 'textfield', + '#title' => t('Item Description'), + '#required' => TRUE, + '#default_value' => $entity->item_description, + ); + + $form['basic_entity'] = array( + '#type' => 'value', + '#value' => $entity, + ); + + field_attach_form('entity_example_basic', $entity, $form, $form_state); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), + '#weight' => 100, + ); + $form['delete'] = array( + '#type' => 'submit', + '#value' => t('Delete'), + '#submit' => array('entity_example_basic_edit_delete'), + '#weight' => 200, + ); + + return $form; +} + + +/** + * Validation handler for entity_example_basic_add_form form. + * + * We pass things straight through to the Field API to handle validation + * of the attached fields. + */ +function entity_example_basic_form_validate($form, &$form_state) { + field_attach_form_validate('entity_example_basic', $form_state['values']['basic_entity'], $form, $form_state); +} + + +/** + * Form submit handler: Submits basic_add_form information. + */ +function entity_example_basic_form_submit($form, &$form_state) { + $entity = $form_state['values']['basic_entity']; + $entity->item_description = $form_state['values']['item_description']; + field_attach_submit('entity_example_basic', $entity, $form, $form_state); + $entity = entity_example_basic_save($entity); + $form_state['redirect'] = 'examples/entity_example/basic/' . $entity->basic_id; +} + +/** + * Form deletion handler. + * + * @todo: 'Are you sure?' message. + */ +function entity_example_basic_edit_delete($form, &$form_state) { + $entity = $form_state['values']['basic_entity']; + entity_example_basic_delete($entity); + drupal_set_message(t('The entity %item_description (ID %id) has been deleted', + array('%item_description' => $entity->item_description, '%id' => $entity->basic_id)) + ); + $form_state['redirect'] = 'examples/entity_example'; +} + +/** + * We save the entity by calling the controller. + */ +function entity_example_basic_save(&$entity) { + return entity_get_controller('entity_example_basic')->save($entity); +} + +/** + * Use the controller to delete the entity. + */ +function entity_example_basic_delete($entity) { + entity_get_controller('entity_example_basic')->delete($entity); +} + +/** + * EntityExampleBasicControllerInterface definition. + * + * We create an interface here because anyone could come along and + * use hook_entity_info_alter() to change our controller class. + * We want to let them know what methods our class needs in order + * to function with the rest of the module, so here's a handy list. + * + * @see hook_entity_info_alter() + */ +interface EntityExampleBasicControllerInterface + extends DrupalEntityControllerInterface { + + /** + * Create an entity. + */ + public function create(); + + /** + * Save an entity. + * + * @param object $entity + * The entity to save. + */ + public function save($entity); + + /** + * Delete an entity. + * + * @param object $entity + * The entity to delete. + */ + public function delete($entity); + +} + +/** + * EntityExampleBasicController extends DrupalDefaultEntityController. + * + * Our subclass of DrupalDefaultEntityController lets us add a few + * important create, update, and delete methods. + */ +class EntityExampleBasicController + extends DrupalDefaultEntityController + implements EntityExampleBasicControllerInterface { + + /** + * Create and return a new entity_example_basic entity. + */ + public function create() { + $entity = new stdClass(); + $entity->type = 'entity_example_basic'; + $entity->basic_id = 0; + $entity->bundle_type = 'first_example_bundle'; + $entity->item_description = ''; + return $entity; + } + + /** + * Saves the custom fields using drupal_write_record(). + */ + public function save($entity) { + // If our entity has no basic_id, then we need to give it a + // time of creation. + if (empty($entity->basic_id)) { + $entity->created = time(); + } + // Invoke hook_entity_presave(). + module_invoke_all('entity_presave', $entity, 'entity_example_basic'); + // The 'primary_keys' argument determines whether this will be an insert + // or an update. So if the entity already has an ID, we'll specify + // basic_id as the key. + $primary_keys = $entity->basic_id ? 'basic_id' : array(); + // Write out the entity record. + drupal_write_record('entity_example_basic', $entity, $primary_keys); + // We're going to invoke either hook_entity_update() or + // hook_entity_insert(), depending on whether or not this is a + // new entity. We'll just store the name of hook_entity_insert() + // and change it if we need to. + $invocation = 'entity_insert'; + // Now we need to either insert or update the fields which are + // attached to this entity. We use the same primary_keys logic + // to determine whether to update or insert, and which hook we + // need to invoke. + if (empty($primary_keys)) { + field_attach_insert('entity_example_basic', $entity); + } + else { + field_attach_update('entity_example_basic', $entity); + $invocation = 'entity_update'; + } + // Invoke either hook_entity_update() or hook_entity_insert(). + module_invoke_all($invocation, $entity, 'entity_example_basic'); + return $entity; + } + + /** + * Delete a single entity. + * + * Really a convenience function for deleteMultiple(). + */ + public function delete($entity) { + $this->deleteMultiple(array($entity)); + } + + /** + * Delete one or more entity_example_basic entities. + * + * Deletion is unfortunately not supported in the base + * DrupalDefaultEntityController class. + * + * @param array $entities + * An array of entity IDs or a single numeric ID. + */ + public function deleteMultiple($entities) { + $basic_ids = array(); + if (!empty($entities)) { + $transaction = db_transaction(); + try { + foreach ($entities as $entity) { + // Invoke hook_entity_delete(). + module_invoke_all('entity_delete', $entity, 'entity_example_basic'); + field_attach_delete('entity_example_basic', $entity); + $basic_ids[] = $entity->basic_id; + } + db_delete('entity_example_basic') + ->condition('basic_id', $basic_ids, 'IN') + ->execute(); + } + catch (Exception $e) { + $transaction->rollback(); + watchdog_exception('entity_example', $e); + throw $e; + } + } + } +} + +/** + * @} End of "defgroup entity_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/entity_example/entity_example.test b/sites/all/modules/contrib/dev/examples/entity_example/entity_example.test new file mode 100644 index 00000000..89ad1678 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/entity_example/entity_example.test @@ -0,0 +1,162 @@ + 'Entity example', + 'description' => 'Basic entity example tests', + 'group' => 'Examples', + ); + } + + /** + * {@inheritdoc} + */ + public function setUp() { + // Enable the module. + parent::setUp('entity_example'); + + // Create and login user with access. + $permissions = array( + 'access content', + 'view any entity_example_basic entity', + 'edit any entity_example_basic entity', + 'create entity_example_basic entities', + 'administer entity_example_basic entities', + 'administer site configuration', + 'administer fields', + ); + $account = $this->drupalCreateUser($permissions); + $this->drupalLogin($account); + + // Attach a field. + $field = array( + 'field_name' => 'entity_example_test_text' , + 'type' => 'text', + ); + field_create_field($field); + $instance = array( + 'label' => 'Subject', + 'field_name' => 'entity_example_test_text', + 'entity_type' => 'entity_example_basic', + 'bundle' => 'first_example_bundle', + ); + field_create_instance($instance); + } + + /** + * Test Entity Example features. + * + * - CRUD + * - Table display + * - User access + * - Field management + * - Display management + */ + public function testEntityExampleBasic() { + // Create 10 entities. + for ($i = 1; $i <= 10; $i++) { + $edit[$i]['item_description'] = $this->randomName(); + $edit[$i]['entity_example_test_text[und][0][value]'] = $this->randomName(32); + + $this->drupalPost('examples/entity_example/basic/add', $edit[$i], 'Save'); + $this->assertText('item_description=' . $edit[$i]['item_description']); + + $this->drupalGet('examples/entity_example/basic/' . $i); + $this->assertText('item_description=' . $edit[$i]['item_description']); + $this->assertText($edit[$i]['entity_example_test_text[und][0][value]']); + } + + // Delete entity 5. + $this->drupalPost('examples/entity_example/basic/5/edit', $edit[5], 'Delete'); + $this->drupalGet('examples/entity_example/basic/5'); + $this->assertResponse(404, 'Deleted entity 5 no longer exists'); + unset($edit[5]); + + // Update entity 2 and verify the update. + $edit[2] = array( + 'item_description' => 'updated entity 2 ', + 'entity_example_test_text[und][0][value]' => 'updated entity 2 test text', + ); + $this->drupalPost('examples/entity_example/basic/2/edit', $edit[2], 'Save'); + $this->assertText('item_description=' . $edit[2]['item_description']); + $this->assertText('updated entity 2 test text'); + + // View the entity list page and verify that the items which still exist + // are there, and that the deleted #5 no longer is there. + $this->drupalGet('admin/structure/entity_example_basic/manage'); + foreach ($edit as $id => $item) { + $this->assertRaw('examples/entity_example/basic/' . $id . '">' . $item['item_description'] . ''); + } + $this->assertNoRaw('examples/entity_example/basic/5">'); + + // Add a field through the field UI and verify that it behaves correctly. + $field_edit = array( + 'fields[_add_new_field][label]' => 'New junk field', + 'fields[_add_new_field][field_name]' => 'new_junk_field', + 'fields[_add_new_field][type]' => 'text', + 'fields[_add_new_field][widget_type]' => 'text_textfield', + ); + $this->drupalPost('admin/structure/entity_example_basic/manage/fields', $field_edit, t('Save')); + $this->drupalPost(NULL, array(), t('Save field settings')); + $this->drupalPost(NULL, array(), t('Save settings')); + $this->assertResponse(200); + + // Now verify that we can edit and view this entity with fields. + $edit[10]['field_new_junk_field[und][0][value]'] = $this->randomName(); + $this->drupalPost('examples/entity_example/basic/10/edit', $edit[10], 'Save'); + $this->assertResponse(200); + $this->assertText('item_description=' . $edit[10]['item_description']); + $this->assertText($edit[10]['field_new_junk_field[und][0][value]'], 'Custom field updated successfully'); + + // Create and login user without view access. + $account = $this->drupalCreateUser(array('access content')); + $this->drupalLogin($account); + $this->drupalGet('admin/structure/entity_example_basic/manage'); + $this->assertResponse(403); + $this->drupalGet('examples/entity_example/basic/2'); + $this->assertResponse(403, 'User does not have permission to view entity'); + + // Create and login user with view access but no edit access. + $account = $this->drupalCreateUser(array('access content', 'view any entity_example_basic entity')); + $this->drupalLogin($account); + $this->drupalGet('admin/structure/entity_example_basic/manage'); + $this->assertResponse(403, 'Denied access to admin manage page'); + $this->drupalGet('examples/entity_example/basic/2'); + $this->assertResponse(200, 'User has permission to view entity'); + $this->drupalGet('examples/entity_example/basic/2/edit'); + $this->assertResponse(403, 'User is denied edit privileges'); + + // Create and login user with view and edit but no manage privs. + $account = $this->drupalCreateUser( + array( + 'access content', + 'view any entity_example_basic entity', + 'edit any entity_example_basic entity', + ) + ); + $this->drupalLogin($account); + $this->drupalGet('admin/structure/entity_example_basic/manage'); + $this->assertResponse(403, 'Denied access to admin manage page'); + $this->drupalGet('examples/entity_example/basic/2'); + $this->assertResponse(200, 'User has permission to view entity'); + $this->drupalGet('examples/entity_example/basic/2/edit'); + $this->assertResponse(200, 'User has edit privileges'); + } +} diff --git a/sites/all/modules/contrib/dev/examples/examples.index.php b/sites/all/modules/contrib/dev/examples/examples.index.php new file mode 100644 index 00000000..8056fee0 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/examples.index.php @@ -0,0 +1,40 @@ + array('type' => 'varchar', 'length' => 7, 'not null' => FALSE), + ); + $indexes = array( + 'rgb' => array('rgb'), + ); + return array( + 'columns' => $columns, + 'indexes' => $indexes, + ); +} diff --git a/sites/all/modules/contrib/dev/examples/field_example/field_example.js b/sites/all/modules/contrib/dev/examples/field_example/field_example.js new file mode 100644 index 00000000..3ea7a26a --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/field_example/field_example.js @@ -0,0 +1,25 @@ +/** + * @file + * Javascript for Field Example. + */ + +/** + * Provides a farbtastic colorpicker for the fancier widget. + */ +(function ($) { + Drupal.behaviors.field_example_colorpicker = { + attach: function(context) { + $(".edit-field-example-colorpicker").live("focus", function(event) { + var edit_field = this; + var picker = $(this).closest('div').parent().find(".field-example-colorpicker"); + + // Hide all color pickers except this one. + $(".field-example-colorpicker").hide(); + $(picker).show(); + $.farbtastic(picker, function(color) { + edit_field.value = color; + }).setColor(edit_field.value); + }); + } + } +})(jQuery); diff --git a/sites/all/modules/contrib/dev/examples/field_example/field_example.module b/sites/all/modules/contrib/dev/examples/field_example/field_example.module new file mode 100644 index 00000000..241d06f0 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/field_example/field_example.module @@ -0,0 +1,389 @@ + array( + 'label' => t('Example Color RGB'), + 'description' => t('Demonstrates a field composed of an RGB color.'), + 'default_widget' => 'field_example_3text', + 'default_formatter' => 'field_example_simple_text', + ), + ); +} + +/** + * Implements hook_field_validate(). + * + * This hook gives us a chance to validate content that's in our + * field. We're really only interested in the $items parameter, since + * it holds arrays representing content in the field we've defined. + * We want to verify that the items only contain RGB hex values like + * this: #RRGGBB. If the item validates, we do nothing. If it doesn't + * validate, we add our own error notification to the $errors parameter. + * + * @see field_example_field_widget_error() + */ +function field_example_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) { + foreach ($items as $delta => $item) { + if (!empty($item['rgb'])) { + if (!preg_match('@^#[0-9a-f]{6}$@', $item['rgb'])) { + $errors[$field['field_name']][$langcode][$delta][] = array( + 'error' => 'field_example_invalid', + 'message' => t('Color must be in the HTML format #abcdef.'), + ); + } + } + } +} + + +/** + * Implements hook_field_is_empty(). + * + * hook_field_is_empty() is where Drupal asks us if this field is empty. + * Return TRUE if it does not contain data, FALSE if it does. This lets + * the form API flag an error when required fields are empty. + */ +function field_example_field_is_empty($item, $field) { + return empty($item['rgb']); +} + +/** + * Implements hook_field_formatter_info(). + * + * We need to tell Drupal that we have two different types of formatters + * for this field. One will change the text color, and the other will + * change the background color. + * + * @see field_example_field_formatter_view() + */ +function field_example_field_formatter_info() { + return array( + // This formatter just displays the hex value in the color indicated. + 'field_example_simple_text' => array( + 'label' => t('Simple text-based formatter'), + 'field types' => array('field_example_rgb'), + ), + // This formatter changes the background color of the content region. + 'field_example_color_background' => array( + 'label' => t('Change the background of the output text'), + 'field types' => array('field_example_rgb'), + ), + ); +} + +/** + * Implements hook_field_formatter_view(). + * + * Two formatters are implemented. + * - field_example_simple_text just outputs markup indicating the color that + * was entered and uses an inline style to set the text color to that value. + * - field_example_color_background does the same but also changes the + * background color of div.region-content. + * + * @see field_example_field_formatter_info() + */ +function field_example_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) { + $element = array(); + + switch ($display['type']) { + // This formatter simply outputs the field as text and with a color. + case 'field_example_simple_text': + foreach ($items as $delta => $item) { + $element[$delta] = array( + // We create a render array to produce the desired markup, + // "

The color code ... #hexcolor

". + // See theme_html_tag(). + '#type' => 'html_tag', + '#tag' => 'p', + '#attributes' => array( + 'style' => 'color: ' . $item['rgb'], + ), + '#value' => t('The color code in this field is @code', array('@code' => $item['rgb'])), + ); + } + break; + + // This formatter adds css to the page changing the '.region-content' area's + // background color. If there are many fields, the last one will win. + case 'field_example_color_background': + foreach ($items as $delta => $item) { + $element[$delta] = array( + '#type' => 'html_tag', + '#tag' => 'p', + '#value' => t('The content area color has been changed to @code', array('@code' => $item['rgb'])), + '#attached' => array( + 'css' => array( + array( + 'data' => 'div.region-content { background-color:' . $item['rgb'] . ';}', + 'type' => 'inline', + ), + ), + ), + ); + } + break; + } + + return $element; +} + +/** + * Implements hook_field_widget_info(). + * + * Three widgets are provided. + * - A simple text-only widget where the user enters the '#ffffff'. + * - A 3-textfield widget that gathers the red, green, and blue values + * separately. + * - A farbtastic colorpicker widget that chooses the value graphically. + * + * These widget types will eventually show up in hook_field_widget_form, + * where we will have to flesh them out. + * + * @see field_example_field_widget_form() + */ +function field_example_field_widget_info() { + return array( + 'field_example_text' => array( + 'label' => t('RGB value as #ffffff'), + 'field types' => array('field_example_rgb'), + ), + 'field_example_3text' => array( + 'label' => t('RGB text field'), + 'field types' => array('field_example_rgb'), + ), + 'field_example_colorpicker' => array( + 'label' => t('Color Picker'), + 'field types' => array('field_example_rgb'), + ), + ); +} + +/** + * Implements hook_field_widget_form(). + * + * hook_widget_form() is where Drupal tells us to create form elements for + * our field's widget. + * + * We provide one of three different forms, depending on the widget type of + * the Form API item provided. + * + * The 'field_example_colorpicker' and 'field_example_text' are essentially + * the same, but field_example_colorpicker adds a javascript colorpicker + * helper. + * + * field_example_3text displays three text fields, one each for red, green, + * and blue. However, the field type defines a single text column, + * rgb, which needs an HTML color spec. Define an element validate + * handler that converts our r, g, and b fields into a simulated single + * 'rgb' form element. + */ +function field_example_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) { + $value = isset($items[$delta]['rgb']) ? $items[$delta]['rgb'] : ''; + + $widget = $element; + $widget['#delta'] = $delta; + + switch ($instance['widget']['type']) { + + case 'field_example_colorpicker': + $widget += array( + '#suffix' => '
', + '#attributes' => array('class' => array('edit-field-example-colorpicker')), + '#attached' => array( + // Add Farbtastic color picker. + 'library' => array( + array('system', 'farbtastic'), + ), + // Add javascript to trigger the colorpicker. + 'js' => array(drupal_get_path('module', 'field_example') . '/field_example.js'), + ), + ); + // DELIBERATE fall-through: From here on the field_example_text and + // field_example_colorpicker are exactly the same. + case 'field_example_text': + $widget += array( + '#type' => 'textfield', + '#default_value' => $value, + // Allow a slightly larger size that the field length to allow for some + // configurations where all characters won't fit in input field. + '#size' => 7, + '#maxlength' => 7, + ); + break; + + case 'field_example_3text': + // Convert rgb value into r, g, and b for #default_value. + if (!empty($value)) { + preg_match_all('@..@', substr($value, 1), $match); + } + else { + $match = array(array()); + } + + // Make this a fieldset with the three text fields. + $widget += array( + '#type' => 'fieldset', + '#element_validate' => array('field_example_3text_validate'), + + // #delta is set so that the validation function will be able + // to access external value information which otherwise would be + // unavailable. + '#delta' => $delta, + + '#attached' => array( + 'css' => array(drupal_get_path('module', 'field_example') . '/field_example.css'), + ), + ); + + // Create a textfield for saturation values for Red, Green, and Blue. + foreach (array('r' => t('Red'), 'g' => t('Green'), 'b' => t('Blue')) as $key => $title) { + $widget[$key] = array( + '#type' => 'textfield', + '#title' => $title, + '#size' => 2, + '#default_value' => array_shift($match[0]), + '#attributes' => array('class' => array('rgb-entry')), + '#description' => t('The 2-digit hexadecimal representation of @color saturation, like "a1" or "ff"', array('@color' => $title)), + ); + // Since Form API doesn't allow a fieldset to be required, we + // have to require each field element individually. + if ($instance['required'] == 1) { + $widget[$key]['#required'] = 1; + } + } + break; + + } + + $element['rgb'] = $widget; + return $element; +} + + +/** + * Validate the individual fields and then convert to RGB string. + */ +function field_example_3text_validate($element, &$form_state) { + // @todo: Isn't there a better way to find out which element? + $delta = $element['#delta']; + $field = $form_state['field'][$element['#field_name']][$element['#language']]['field']; + $field_name = $field['field_name']; + if (isset($form_state['values'][$field_name][$element['#language']][$delta]['rgb'])) { + $values = $form_state['values'][$field_name][$element['#language']][$delta]['rgb']; + foreach (array('r', 'g', 'b') as $colorfield) { + $colorfield_value = hexdec($values[$colorfield]); + // If they left any empty, we'll set the value empty and quit. + if (strlen($values[$colorfield]) == 0) { + form_set_value($element, '', $form_state); + return; + } + // If they gave us anything that's not hex, reject it. + if ((strlen($values[$colorfield]) != 2) || $colorfield_value < 0 || $colorfield_value > 255) { + form_error($element[$colorfield], t("Saturation value must be a 2-digit hexadecimal value between 00 and ff.")); + } + } + + $value = sprintf('#%02s%02s%02s', $values['r'], $values['g'], $values['b']); + form_set_value($element, $value, $form_state); + } +} + +/** + * Implements hook_field_widget_error(). + * + * hook_field_widget_error() lets us figure out what to do with errors + * we might have generated in hook_field_validate(). Generally, we'll just + * call form_error(). + * + * @see field_example_field_validate() + * @see form_error() + */ +function field_example_field_widget_error($element, $error, $form, &$form_state) { + switch ($error['error']) { + case 'field_example_invalid': + form_error($element, $error['message']); + break; + } +} + + +/** + * Implements hook_menu(). + * + * Provides a simple user interface that tells the developer where to go. + */ +function field_example_menu() { + $items['examples/field_example'] = array( + 'title' => 'Field Example', + 'page callback' => '_field_example_page', + 'access callback' => TRUE, + ); + return $items; +} + +/** + * A simple page to explain to the developer what to do. + */ +function _field_example_page() { + return t("The Field Example provides a field composed of an HTML RGB value, like #ff00ff. To use it, add the field to a content type."); +} +/** + * @} End of "defgroup field_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/field_example/field_example.test b/sites/all/modules/contrib/dev/examples/field_example/field_example.test new file mode 100644 index 00000000..6baf973d --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/field_example/field_example.test @@ -0,0 +1,184 @@ + 'Field Example', + 'description' => 'Create a content type with example_field_rgb fields, create a node, check for correct values.', + 'group' => 'Examples', + ); + } + + /** + * {@inheritdoc} + */ + public function setUp() { + // Enable the email_example module. + parent::setUp(array('field_ui', 'field_example')); + } + + /** + * Test basic functionality of the example field. + * + * - Creates a content type. + * - Adds a single-valued field_example_rgb to it. + * - Adds a multivalued field_example_rgb to it. + * - Creates a node of the new type. + * - Populates the single-valued field. + * - Populates the multivalued field with two items. + * - Tests the result. + */ + public function testExampleFieldBasic() { + $content_type_machine = strtolower($this->randomName(10)); + $title = $this->randomName(20); + + // Create and login user. + $account = $this->drupalCreateUser(array('administer content types', 'administer fields')); + $this->drupalLogin($account); + + $this->drupalGet('admin/structure/types'); + + // Create the content type. + $this->clickLink(t('Add content type')); + + $edit = array( + 'name' => $content_type_machine, + 'type' => $content_type_machine, + ); + $this->drupalPost(NULL, $edit, t('Save and add fields')); + $this->assertText(t('The content type @name has been added.', array('@name' => $content_type_machine))); + + $single_text_field = strtolower($this->randomName(10)); + $single_colorpicker_field = strtolower($this->randomName(10)); + $single_3text_field = strtolower($this->randomName(10)); + $multivalue_3text_field = strtolower($this->randomName(10)); + + // Description of fields to be created; + $fields[$single_text_field] = array( + 'widget' => 'field_example_text', + 'cardinality' => '1', + ); + $fields[$single_colorpicker_field] = array( + 'widget' => 'field_example_colorpicker', + 'cardinality' => 1, + ); + $fields[$single_3text_field] = array( + 'widget' => 'field_example_3text', + 'cardinality' => 1, + ); + $fields[$multivalue_3text_field] = array( + 'widget' => 'field_example_3text', + 'cardinality' => -1, + ); + + foreach ($fields as $fieldname => $details) { + $this->createField($fieldname, $details['widget'], $details['cardinality']); + } + + // Somehow clicking "save" isn't enough, and we have to do a + // node_types_rebuild(). + node_types_rebuild(); + menu_rebuild(); + $type_exists = db_query('SELECT 1 FROM {node_type} WHERE type = :type', array(':type' => $content_type_machine))->fetchField(); + $this->assertTrue($type_exists, 'The new content type has been created in the database.'); + + $permission = 'create ' . $content_type_machine . ' content'; + // Reset the permissions cache. + $this->checkPermissions(array($permission), TRUE); + + // Now that we have a new content type, create a user that has privileges + // on the content type. + $account = $this->drupalCreateUser(array($permission)); + $this->drupalLogin($account); + + $this->drupalGet('node/add/' . $content_type_machine); + + // Add a node. + $edit = array( + 'title' => $title, + 'field_' . $single_text_field . '[und][0][rgb]' => '#000001', + 'field_' . $single_colorpicker_field . '[und][0][rgb]' => '#000002', + + 'field_' . $single_3text_field . '[und][0][rgb][r]' => '00', + 'field_' . $single_3text_field . '[und][0][rgb][g]' => '00', + 'field_' . $single_3text_field . '[und][0][rgb][b]' => '03', + + 'field_' . $multivalue_3text_field . '[und][0][rgb][r]' => '00', + 'field_' . $multivalue_3text_field . '[und][0][rgb][g]' => '00', + 'field_' . $multivalue_3text_field . '[und][0][rgb][b]' => '04', + + ); + // We want to add a 2nd item to the multivalue field, so hit "add another". + $this->drupalPost(NULL, $edit, t('Add another item')); + + $edit = array( + 'field_' . $multivalue_3text_field . '[und][1][rgb][r]' => '00', + 'field_' . $multivalue_3text_field . '[und][1][rgb][g]' => '00', + 'field_' . $multivalue_3text_field . '[und][1][rgb][b]' => '05', + ); + // Now we can fill in the second item in the multivalue field and save. + $this->drupalPost(NULL, $edit, t('Save')); + $this->assertText(t('@content_type_machine @title has been created', array('@content_type_machine' => $content_type_machine, '@title' => $title))); + + $output_strings = $this->xpath("//div[contains(@class,'field-type-field-example-rgb')]/div/div/p/text()"); + + $this->assertEqual((string) $output_strings[0], "The color code in this field is #000001"); + $this->assertEqual((string) $output_strings[1], "The color code in this field is #000002"); + $this->assertEqual((string) $output_strings[2], "The color code in this field is #000003"); + $this->assertEqual((string) $output_strings[3], "The color code in this field is #000004"); + $this->assertEqual((string) $output_strings[4], "The color code in this field is #000005"); + } + + /** + * Utility function to create fields on a content type. + * + * @param string $field_name + * Name of the field, like field_something + * @param string $widget_type + * Widget type, like field_example_3text + * @param int $cardinality + * Cardinality + */ + protected function createField($field_name, $widget_type, $cardinality) { + // Add a singleton field_example_text field. + $edit = array( + 'fields[_add_new_field][label]' => $field_name, + 'fields[_add_new_field][field_name]' => $field_name, + 'fields[_add_new_field][type]' => 'field_example_rgb', + 'fields[_add_new_field][widget_type]' => $widget_type, + + ); + $this->drupalPost(NULL, $edit, t('Save')); + + // There are no settings for this, so just press the button. + $this->drupalPost(NULL, array(), t('Save field settings')); + + $edit = array('field[cardinality]' => (string) $cardinality); + + // Using all the default settings, so press the button. + $this->drupalPost(NULL, $edit, t('Save settings')); + debug( + t('Saved settings for field %field_name with widget %widget_type and cardinality %cardinality', + array( + '%field_name' => $field_name, + '%widget_type' => $widget_type, + '%cardinality' => $cardinality, + ) + ) + ); + $this->assertText(t('Saved @name configuration.', array('@name' => $field_name))); + } +} diff --git a/sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.css b/sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.css new file mode 100644 index 00000000..59cda31e --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.css @@ -0,0 +1,22 @@ +/** + * @file + * CSS for Field Example. + */ +.stickynote { +background:#fefabc; +padding:0.8em; +font-family:cursive; +font-size:1.1em; +color: #000; +width:15em; + +-moz-transform: rotate(2deg); +-webkit-transform: rotate(2deg); +-o-transform: rotate(2deg); +-ms-transform: rotate(2deg); +transform: rotate(2deg); + +box-shadow: 0px 4px 6px #333; +-moz-box-shadow: 0px 4px 6px #333; +-webkit-box-shadow: 0px 4px 6px #333; +} diff --git a/sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.info b/sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.info new file mode 100644 index 00000000..6f538f72 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.info @@ -0,0 +1,12 @@ +name = Field Permission Example +description = A Field API Example: Fieldnote with Permissions +package = Example modules +core = 7.x +files[] = tests/field_permission_example.test + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.install b/sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.install new file mode 100644 index 00000000..55388d20 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.install @@ -0,0 +1,32 @@ + array('type' => 'text', 'size' => 'normal', 'not null' => FALSE), + ); + return array( + 'columns' => $columns, + ); +} diff --git a/sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.module b/sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.module new file mode 100644 index 00000000..a1a96139 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/field_permission_example/field_permission_example.module @@ -0,0 +1,329 @@ + t('View own fieldnote')); + $perms['edit own fieldnote'] = array('title' => t('Edit own fieldnote')); + $perms['view any fieldnote'] = array('title' => t('View any fieldnote')); + $perms['edit any fieldnote'] = array('title' => t('Edit any fieldnote')); + + return $perms; +} + +/** + * Implements hook_field_access(). + * + * We want to make sure that fields aren't being seen or edited + * by those who shouldn't. + * + * We have to build a permission string similar to those in + * hook_permission() in order to ask Drupal whether the user + * has that permission. Permission strings will end up being + * like 'view any fieldnote' or 'edit own fieldnote'. + * + * The tricky thing here is that a field can be attached to any type + * of entity, so it's not always trivial to figure out whether + * $account 'owns' the entity. We'll support access restrictions for + * user and node entity types, and be permissive with others, + * since that's easy to demonstrate. + * + * @see field_permission_example_permissions() + */ +function field_permission_example_field_access($op, $field, $entity_type, $entity, $account) { + // This hook will be invoked for every field type, so we have to + // check that it's the one we're interested in. + if ($field['type'] == 'field_permission_example_fieldnote') { + // First we'll check if the user has the 'superuser' + // permissions that node provides. This way administrators + // will be able to administer the content types. + if (user_access('bypass node access', $account)) { + drupal_set_message(t('User can bypass node access.')); + return TRUE; + } + if (user_access('administer content types', $account)) { + drupal_set_message(t('User can administer content types.')); + return TRUE; + } + // Now check for our own permissions. + // $context will end up being either 'any' or 'own.' + $context = 'any'; + switch ($entity_type) { + case 'user': + case 'node': + // While administering the field itself, $entity will be + // NULL, so we have to check it. + if ($entity) { + if ($entity->uid == $account->uid) { + $context = 'own'; + } + } + } + // Assemble a permission string, such as + // 'view any fieldnote' + $permission = $op . ' ' . $context . ' fieldnote'; + // Finally, ask Drupal if this account has that permission. + $access = user_access($permission, $account); + $status = 'FALSE'; + if ($access) { + $status = 'TRUE'; + } + drupal_set_message($permission . ': ' . $status); + return $access; + } + // We have no opinion on field types other than our own. + return TRUE; +} + +/** + * Implements hook_field_info(). + * + * Provides the description of the field. + */ +function field_permission_example_field_info() { + return array( + // We name our field as the associative name of the array. + 'field_permission_example_fieldnote' => array( + 'label' => t('Fieldnote'), + 'description' => t('Place a note-taking field on entities, with granular permissions.'), + 'default_widget' => 'field_permission_example_widget', + 'default_formatter' => 'field_permission_example_formatter', + ), + ); +} + +/** + * Implements hook_field_is_empty(). + * + * hook_field_is_empty() is where Drupal asks us if this field is empty. + * Return TRUE if it does not contain data, FALSE if it does. This lets + * the form API flag an error when required fields are empty. + */ +function field_permission_example_field_is_empty($item, $field) { + return empty($item['notes']); +} + +/** + * Implements hook_field_formatter_info(). + * + * We need to tell Drupal about our excellent field formatter. + * + * It's some text in a div, styled to look like a sticky note. + * + * @see field_permission_example_field_formatter_view() + */ +function field_permission_example_field_formatter_info() { + return array( + // This formatter simply displays the text in a text field. + 'field_permission_example_formatter' => array( + 'label' => t('Simple text-based formatter'), + 'field types' => array('field_permission_example_fieldnote'), + ), + ); +} + +/** + * Implements hook_field_formatter_view(). + * + * Here we output the field for general consumption. + * + * The field will have a sticky note appearance, thanks to some + * simple CSS. + * + * Note that all of the permissions and access logic happens + * in hook_field_access(), and none of it is here. + */ +function field_permission_example_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) { + $element = array(); + + switch ($display['type']) { + case 'field_permission_example_formatter': + foreach ($items as $delta => $item) { + $element[$delta] = array( + // We wrap the fieldnote content up in a div tag. + '#type' => 'html_tag', + '#tag' => 'div', + '#value' => check_plain($item['notes']), + // Let's give the note a nice sticky-note CSS appearance. + '#attributes' => array( + 'class' => 'stickynote', + ), + // ..And this is the CSS for the stickynote. + '#attached' => array( + 'css' => array(drupal_get_path('module', 'field_permission_example') . + '/field_permission_example.css'), + ), + ); + } + break; + } + return $element; +} + +/** + * Implements hook_field_widget_info(). + * + * We're implementing just one widget: A basic textarea. + * + * @see field_permission_example_field_widget_form() + */ +function field_permission_example_field_widget_info() { + return array( + 'field_permission_example_widget' => array( + 'label' => t('Field note textarea'), + 'field types' => array('field_permission_example_fieldnote'), + ), + ); +} + +/** + * Implements hook_field_widget_form(). + * + * Drupal wants us to create a form for our field. We'll use + * something very basic like a default textarea. + * + * @see field_permission_example_field_widget_info() + */ +function field_permission_example_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) { + // Grab the existing value for the field. + $value = isset($items[$delta]['notes']) ? $items[$delta]['notes'] : ''; + // Grab a reference to the form element. + $widget = $element; + // Set up the delta for our return element. + $widget['#delta'] = $delta; + + // Figure out which widget we need to generate. + // In our case, there's only one type. + switch ($instance['widget']['type']) { + case 'field_permission_example_widget': + $widget += array( + '#type' => 'textarea', + '#default_value' => $value, + ); + break; + } + + $element['notes'] = $widget; + return $element; +} + +/** + * Implements hook_menu(). + * + * Provides a simple user interface that gives the developer some clues. + */ +function field_permission_example_menu() { + $items['examples/field_permission_example'] = array( + 'title' => 'Field Permission Example', + 'page callback' => '_field_permission_example_page', + 'access callback' => TRUE, + ); + return $items; +} + +/** + * A simple page to explain to the developer what to do. + * + * @see field_permission_example.module + */ +function _field_permission_example_page() { + $page = t("

The Field Permission Example module shows how you can restrict view and edit permissions within your field implementation. It adds a new field type called Fieldnote. Fieldnotes appear as simple text boxes on the create/edit form, and as sticky notes when viewed. By 'sticky note' we mean 'Post-It Note' but that's a trademarked term.

To see this field in action, add it to a content type or user profile. Go to the permissions page ("); + $page .= l(t('admin/people/permissions'), 'admin/people/permissions'); + $page .= t(") and look at the 'Field Permission Example' section. This allows you to change which roles can see and edit Fieldnote fields.

Creating different users with different capabilities will let you see these behaviors in action. Fieldnote helpfully displays a message telling you which permissions it is trying to resolve for the current field/user combination.

Definitely look through the code to see various implementation details.

"); + return $page; +} +/** + * @} End of "defgroup field_permission_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/field_permission_example/tests/field_permission_example.test b/sites/all/modules/contrib/dev/examples/field_permission_example/tests/field_permission_example.test new file mode 100644 index 00000000..7e6c9b71 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/field_permission_example/tests/field_permission_example.test @@ -0,0 +1,572 @@ + 'Generic Field Test', + 'description' => 'Someone neglected to override GenericFieldTest::getInfo().', + 'group' => 'Examples', + ); + } + + /** + * Supply the field types we wish to test. + * + * Return an array of field types to instantiate and test. + * + * @return array + * The field types we wish to use. + */ + protected function getFieldTypes() { + return array('these_are_not', 'valid_field_types', 'please_override'); + } + + /** + * The module to enable. + * + * @return string + * Module machine name. + */ + protected function getModule() { + return 'this-is-not-a-module-name-please-override'; + } + + /** + * Simpletest's setUp(). + * + * We want to be able to subclass this class, so we jump + * through a few hoops in order to get the modules from args + * and add our own. + */ + public function setUp() { + $this->instanceNames = array(); + $modules = func_get_args(); + if (isset($modules[0]) && is_array($modules[0])) { + $modules = $modules[0]; + } + $modules[] = 'node'; + $modules[] = 'field_ui'; + parent::setUp($modules); + } + + /** + * Verify that all required fields are specified in hook_field_info(). + * + * The full list is label, description, settings, instance_settings, + * default_widget, default_formatter, no_ui. + * + * Some are optional, and we won't check for those. + * + * In a sane world, this would be a unit test, rather than a + * web test, but module_implements is unavailable to us + * in unit tests. + * + * @see hook_field_info() + */ + public function runTestGenericFieldInfo() { + $field_types = $this->getFieldTypes(); + $module = $this->getModule(); + $info_keys = array( + 'label', + 'description', + 'default_widget', + 'default_formatter', + ); + // We don't want to use field_info_field_types() + // because there is a hook_field_info_alter(). + // We're testing the module here, not the rest of + // the system. So invoke hook_field_info() ourselves. + $modules = module_implements('field_info'); + $this->assertTrue(in_array($module, $modules), + 'Module ' . $module . ' implements hook_field_info()'); + + foreach ($field_types as $field_type) { + $field_info = module_invoke($module, 'field_info'); + $this->assertTrue(isset($field_info[$field_type]), + 'Module ' . $module . ' defines field type ' . $field_type); + $field_info = $field_info[$field_type]; + foreach ($info_keys as $key) { + $this->assertTrue( + isset($field_info[$key]), + $field_type . "'s " . $key . ' is set.' + ); + } + } + } + + /** + * Add all testable fields as instances to a content type. + * + * As a side-effect: Store the names of the instances created + * in $this->$instance_names. + * + * @param object $node_type + * A content type object. If none is provided, one will be generated. + * + * @return object + * The content type object that has the fields attached. + */ + public function codeTestGenericAddAllFields($node_type = NULL) { + $this->instanceNames = array(); + if (!$node_type) { + $node_type = $this->drupalCreateContentType(); + } + foreach ($this->getFieldTypes() as $field_type) { + $instance_name = drupal_strtolower($this->randomName(32)); + $field = array( + 'field_name' => $instance_name, + 'type' => $field_type, + ); + $field = field_create_field($field); + $instance = array( + 'field_name' => $instance_name, + 'entity_type' => 'node', + 'bundle' => $node_type->name, + 'label' => drupal_strtolower($this->randomName(20)), + ); + // Finally create the instance. + $instance = field_create_instance($instance); + // Reset the caches... + _field_info_collate_fields(TRUE); + // Grab this instance. + $verify_instance = field_info_instance('node', $instance_name, $node_type->name); + $this->assertTrue($verify_instance, 'Instance object exists.'); + $this->assertTrue( + $verify_instance != NULL, + 'field_info_instance() says ' . $instance_name . ' (' . $node_type->name . ') was created.' + ); + $this->instanceNames[] = $instance_name; + } + return $node_type; + } + + /** + * Remove all fields in $this->field_names. + * + * @param mixed $node_type + * A content type object. If none is specified, + * the test fails. + */ + public function codeTestGenericRemoveAllFields($node_type = NULL) { + if (!$node_type) { + $this->fail('No node type.'); + } + if (count($this->instanceNames) < 1) { + $this->fail('There are no instances to remove.'); + return; + } + foreach ($this->instanceNames as $instance_name) { + $instance = field_info_instance('node', $instance_name, $node_type->name); + $this->assertTrue($instance, "Instance exists, now we'll delete it."); + field_delete_field($instance_name); + $instance = field_info_instance('node', $instance_name, $node_type->name); + $this->assertFalse($instance, 'Instance was deleted.'); + } + $this->instanceNames = array(); + } + + /** + * Add and delete all field types through Form API. + * + * @access public + */ + public function formTestGenericFieldNodeAddDeleteForm() { + // Create and login user. + $account = $this->drupalCreateUser(array( + 'administer content types', + 'administer fields', + )); + $this->drupalLogin($account); + + // Add a content type. + $node_type = $this->drupalCreateContentType(); + + // Add all our testable fields. + $field_names = $this->formAddAllFields($node_type); + + // Now let's delete all the fields. + foreach ($field_names as $field_name) { + // This is the path for the 'delete' link on field admin page. + $this->drupalGet('admin/structure/types/manage/' . + $node_type->name . '/fields/field_' . $field_name . '/delete'); + // Click the 'delete' button. + $this->drupalPost(NULL, array(), t('Delete')); + $this->assertText(t('The field @field has been deleted from the @type content type.', + array('@field' => $field_name, '@type' => $node_type->name))); + } + } + + /** + * Add all fields using Form API. + * + * @param mixed $node_type + * A content type object. If none is specified, + * the test fails. + */ + protected function formAddAllFields($node_type = NULL) { + if (!$node_type) { + $this->fail('No content type specified.'); + } + // Get all our field types. + $field_types = $this->getFieldTypes(); + // Keep a list of no_ui fields so we can tell the user. + $unsafe_field_types = array(); + $field_names = array(); + + $manage_path = 'admin/structure/types/manage/' . $node_type->name . '/fields'; + foreach ($field_types as $field_type) { + // Get the field info. + $field_info = field_info_field_types($field_type); + // Exclude no_ui field types. + if (isset($field_info['no_ui']) && $field_info['no_ui']) { + $unsafe_field_types[] = $field_type; + } + else { + // Generate a name for our field. + // 26 is max length for field name. + $field_name = drupal_strtolower($this->randomName(26)); + $field_names[$field_type] = $field_name; + // Create the field through Form API. + $this->formCreateField($manage_path, $field_type, $field_name, + $field_info['default_widget'], 1); + } + } + + // Tell the user which fields we couldn't test. + if (!empty($unsafe_field_types)) { + debug( + 'Unable to attach these no_ui fields: ' . + implode(', ', $unsafe_field_types) + ); + } + + // Somehow clicking "save" isn't enough, and we have to + // rebuild a few caches. + node_types_rebuild(); + menu_rebuild(); + return $field_names; + } + + /** + * Create a field using the content type management form. + * + * @param mixed $manage_path + * Path to our content type management form. + * @param mixed $field_type + * The type of field we're adding. + * @param mixed $field_name + * The name of the field instance we want. + * @param mixed $widget_type + * Which widget would we like? + * @param mixed $cardinality + * Cardinality for this field instance. + */ + protected function formCreateField($manage_path, $field_type, $field_name, $widget_type, $cardinality) { + // $manage_path is the field edit form for our content type. + $this->drupalGet($manage_path); + $edit = array( + 'fields[_add_new_field][label]' => $field_name, + 'fields[_add_new_field][field_name]' => $field_name, + 'fields[_add_new_field][type]' => $field_type, + 'fields[_add_new_field][widget_type]' => $widget_type, + ); + $this->drupalPost(NULL, $edit, t('Save')); + + // Assume there are no settings for this, + // so just press the button. + $this->drupalPost(NULL, array(), t('Save field settings')); + + $edit = array('field[cardinality]' => (string) $cardinality); + $this->drupalPost(NULL, $edit, t('Save settings')); + + debug( + t('Saved settings for field !field_name with widget !widget_type and cardinality !cardinality', + array( + '!field_name' => $field_name, + '!widget_type' => $widget_type, + '!cardinality' => $cardinality, + ) + ) + ); + + $this->assertText(t('Saved @name configuration.', array('@name' => $field_name))); + } + + /** + * Create a node with some field content. + * + * @return object + * Node object for the created node. + */ + public function createFieldContentForUser( + $account = NULL, + $content = 'testable_content', + $node_type = NULL, + $instance_name = '', + $column = NULL + ) { + if (!$column) { + $this->fail('No column name given.'); + return NULL; + } + if (!$account) { + $account = $this->drupalCreateUser(array( + 'bypass node access', + 'administer content types', + )); + } + $this->drupalLogin($account); + + if (!$node_type) { + $node_type = $this->codeTestGenericAddAllFields(); + } + + if (!$instance_name) { + $instance_name = reset($this->instanceNames); + } + $field = array(); + $field[LANGUAGE_NONE][0][$column] = $content; + + $settings = array( + 'type' => $node_type->name, + $instance_name => $field, + ); + $node = $this->drupalCreateNode($settings); + + $this->assertTrue($node, 'Node of type ' . $node->type . ' allegedly created.'); + + $node = node_load($node->nid); + debug('Loaded node id: ' . $node->nid); + $this->assertTrue($node->$instance_name, 'Field actually created.'); + $field = $node->$instance_name; + $this->assertTrue($field[LANGUAGE_NONE][0][$column] == $content, + 'Content was stored properly on the field.'); + return $node; + } + +} + +class FieldTestPermissionsExample extends GenericFieldTest { + + /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp(array('field_permission_example')); + } + + /** + * {@inheritdoc} + */ + public static function getInfo() { + return array( + 'name' => 'Field Permission Example', + 'description' => 'Various tests on the functionality of the Fieldnote field.', + 'group' => 'Examples', + ); + } + + /** + * {@inheritdoc} + */ + protected function getFieldTypes() { + return array('field_permission_example_fieldnote'); + } + + /** + * {@inheritdoc} + */ + protected function getModule() { + return 'field_permission_example'; + } + + /** + * Override createFieldContentForUser(). + * + * We override so we can make sure $column is set to 'notes'. + */ + public function createFieldContentForUser( + $account = NULL, + $content = 'fieldnote_testable_content', + $node_type = NULL, + $instance_name = '', + $column = 'notes' + ) { + return parent::createFieldContentForUser($account, $content, $node_type, $instance_name, $column); + } + + + /** + * Test of hook_field_info() and other implementation requirements. + * + * @see GenericFieldTest::runTestGenericFieldInfo() + */ + public function testFieldnoteInfo() { + $this->runTestGenericFieldInfo(); + } + + /** + * Add and remove the field through Form API. + */ + public function testAddRemoveFieldnoteForm() { + $this->formTestGenericFieldNodeAddDeleteForm(); + } + + /** + * Add and remove the field through code. + */ + public function testAddRemoveFieldnoteCode() { + $node_type = $this->codeTestGenericAddAllFields(); + $this->codeTestGenericRemoveAllFields($node_type); + } + + /** + * Test view permissions. + */ + public function testFieldnoteViewPerms() { + // We create two sets of content so we can get a few + // test cases out of the way. + $view_own_content = $this->randomName(23); + $view_any_content = $this->randomName(23); + $view_own_node = $this->createFieldContentForUser(NULL, $view_own_content); + // Get the type of the node so we can create another one. + $node_type = node_type_load($view_own_node->type); + $view_any_node = $this->createFieldContentForUser(NULL, $view_any_content, $node_type); + + // There should be a node now, with some lovely content, but it's the wrong + // user for the view-own test. + $view_own_account = $this->drupalCreateUser(array( + 'view own fieldnote', + )); + debug("Created user with 'view own fieldnote' permission."); + + // Now change the user id for the test node. + $view_own_node = node_load($view_own_node->nid); + $view_own_node->uid = $view_own_account->uid; + node_save($view_own_node); + $view_own_node = node_load($view_own_node->nid); + $this->assertTrue($view_own_node->uid == $view_own_account->uid, 'New user assigned to node.'); + + // Now we want to look at the page with the field and + // check that we can see it. + $this->drupalLogin($view_own_account); + + $this->drupalGet('node/' . $view_own_node->nid); + // Check that the field content is present. + $output_strings = $this->xpath("//div[contains(@class,'stickynote')]/text()"); + $this->assertEqual((string) reset($output_strings), $view_own_content); + debug("'view own fieldnote' can view own field."); + + // This account shouldn't be able to see the field on the + // 'view any' node. + $this->drupalGet('node/' . $view_any_node->nid); + // Check that the field content is not present. + $output_strings = $this->xpath("//div[contains(@class,'stickynote')]/text()"); + $this->assertNotEqual((string) reset($output_strings), $view_any_content); + debug("'view own fieldnote' cannot view other field."); + + // Now, to test for 'view any fieldnote' we create another user + // with that permission, and try to look at the same node. + $view_any_account = $this->drupalCreateUser(array( + 'view any fieldnote', + )); + debug("Created user with 'view any fieldnote' permission."); + $this->drupalLogin($view_any_account); + // This account should be able to see the field on the + // 'view any' node. + $this->drupalGet('node/' . $view_any_node->nid); + // Check that the field content is present. + $output_strings = $this->xpath("//div[contains(@class,'stickynote')]/text()"); + $this->assertEqual((string) reset($output_strings), $view_any_content); + debug("'view any fieldnote' can view other field."); + } + + /** + * Test edit permissions. + * + * Note that this is mostly identical to testFieldnoteViewPerms() and could + * probably be refactored. + */ + public function testFieldnoteEditPerms() { + // We create two sets of content so we can get a few + // test cases out of the way. + $edit_own_content = $this->randomName(23); + $edit_any_content = $this->randomName(23); + $edit_own_node = $this->createFieldContentForUser(NULL, $edit_own_content); + // Get the type of the node so we can create another one. + $node_type = node_type_load($edit_own_node->type); + $edit_any_node = $this->createFieldContentForUser(NULL, $edit_any_content, $node_type); + + $edit_own_account = $this->drupalCreateUser(array( + 'edit own ' . $node_type->name . ' content', + 'edit own fieldnote', + )); + debug("Created user with 'edit own fieldnote' permission."); + + // Now change the user id for the test node. + $edit_own_node = node_load($edit_own_node->nid); + $edit_own_node->uid = $edit_own_account->uid; + node_save($edit_own_node); + $edit_own_node = node_load($edit_own_node->nid); + $this->assertTrue($edit_own_node->uid == $edit_own_account->uid, 'New edit test user assigned to node.'); + + // Now we want to look at the page with the field and + // check that we can see it. + $this->drupalLogin($edit_own_account); + + $this->drupalGet('node/' . $edit_own_node->nid . '/edit'); + $this->assertText($edit_own_content, "'edit own fieldnote' can edit own fieldnote."); + + // This account shouldn't be able to edit the field on the + // 'edit any' node. + $this->drupalGet('node/' . $edit_any_node->nid . '/edit'); + $this->assertNoText($edit_any_content, "'edit own fieldnote' can not edit any fieldnote."); + + // Now, to test for 'edit any fieldnote' we create another user + // with that permission, and try to edit at the same node. + // We have to add the ability to edit any node content, as well + // or Drupal will deny us access to the page. + $edit_any_account = $this->drupalCreateUser(array( + 'edit any ' . $node_type->name . ' content', + 'edit any fieldnote', + )); + debug("Created user with 'edit any fieldnote' permission."); + $this->drupalLogin($edit_any_account); + // This account should be able to see the field on the + // 'edit any' node. + $this->drupalGet('node/' . $edit_any_node->nid . '/edit'); + $this->assertText($edit_any_content, "'edit any fieldnote' can edit any fieldnote."); + } + +} diff --git a/sites/all/modules/contrib/dev/examples/file_example/file_example.info b/sites/all/modules/contrib/dev/examples/file_example/file_example.info new file mode 100644 index 00000000..92d81e5e --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/file_example/file_example.info @@ -0,0 +1,13 @@ +name = File example +description = Examples of using the Drupal File API and Stream Wrappers. +package = Example modules +core = 7.x +files[] = file_example_session_streams.inc +files[] = file_example.test + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/file_example/file_example.module b/sites/all/modules/contrib/dev/examples/file_example/file_example.module new file mode 100644 index 00000000..c08bd746 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/file_example/file_example.module @@ -0,0 +1,570 @@ + 'File Example', + 'page callback' => 'file_example_intro', + 'access callback' => TRUE, + 'expanded' => TRUE, + ); + $items['examples/file_example/fileapi'] = array( + 'title' => 'Use File API to read/write a file', + 'page callback' => 'drupal_get_form', + 'access arguments' => array('use file example'), + 'page arguments' => array('file_example_readwrite'), + ); + $items['examples/file_example/access_session'] = array( + 'page callback' => 'file_example_session_contents', + 'access arguments' => array('use file example'), + 'type' => MENU_CALLBACK, + ); + return $items; +} + + +/** + * Implements hook_permission(). + */ +function file_example_permission() { + return array( + 'use file example' => array( + 'title' => t('Use the examples in the File Example module'), + ), + ); +} + +/** + * A simple introduction to the workings of this module. + */ +function file_example_intro() { + $markup = t('The file example module provides a form and code to demonstrate the Drupal 7 file api. Experiment with the form, and then look at the submit handlers in the code to understand the file api.'); + return array('#markup' => $markup); +} +/** + * Form builder function. + * + * A simple form that allows creation of a file, managed or unmanaged. It + * also allows reading/deleting a file and creation of a directory. + */ +function file_example_readwrite($form, &$form_state) { + if (empty($_SESSION['file_example_default_file'])) { + $_SESSION['file_example_default_file'] = 'session://drupal.txt'; + } + $default_file = $_SESSION['file_example_default_file']; + if (empty($_SESSION['file_example_default_directory'])) { + $_SESSION['file_example_default_directory'] = 'session://directory1'; + } + $default_directory = $_SESSION['file_example_default_directory']; + + $form['write_file'] = array( + '#type' => 'fieldset', + '#title' => t('Write to a file'), + ); + $form['write_file']['write_contents'] = array( + '#type' => 'textfield', + '#title' => t('Enter something you would like to write to a file') . ' ' . date('m'), + '#default_value' => t('Put some text here or just use this text'), + ); + + $form['write_file']['destination'] = array( + '#type' => 'textfield', + '#default_value' => $default_file, + '#title' => t('Optional: Enter the streamwrapper saying where it should be written'), + '#description' => t('This may be public://some_dir/test_file.txt or private://another_dir/some_file.txt, for example. If you include a directory, it must already exist. The default is "public://". Since this example supports session://, you can also use something like session://somefile.txt.'), + ); + + $form['write_file']['managed_submit'] = array( + '#type' => 'submit', + '#value' => t('Write managed file'), + '#submit' => array('file_example_managed_write_submit'), + ); + $form['write_file']['unmanaged_submit'] = array( + '#type' => 'submit', + '#value' => t('Write unmanaged file'), + '#submit' => array('file_example_unmanaged_write_submit'), + ); + $form['write_file']['unmanaged_php'] = array( + '#type' => 'submit', + '#value' => t('Unmanaged using PHP'), + '#submit' => array('file_example_unmanaged_php_submit'), + ); + + $form['fileops'] = array( + '#type' => 'fieldset', + '#title' => t('Read from a file'), + ); + $form['fileops']['fileops_file'] = array( + '#type' => 'textfield', + '#default_value' => $default_file, + '#title' => t('Enter the URI of a file'), + '#description' => t('This must be a stream-type description like public://some_file.txt or http://drupal.org or private://another_file.txt or (for this example) session://yet_another_file.txt.'), + ); + $form['fileops']['read_submit'] = array( + '#type' => 'submit', + '#value' => t('Read the file and store it locally'), + '#submit' => array('file_example_read_submit'), + ); + $form['fileops']['delete_submit'] = array( + '#type' => 'submit', + '#value' => t('Delete file'), + '#submit' => array('file_example_delete_submit'), + ); + $form['fileops']['check_submit'] = array( + '#type' => 'submit', + '#value' => t('Check to see if file exists'), + '#submit' => array('file_example_file_check_exists_submit'), + ); + + $form['directory'] = array( + '#type' => 'fieldset', + '#title' => t('Create or prepare a directory'), + ); + + $form['directory']['directory_name'] = array( + '#type' => 'textfield', + '#title' => t('Directory to create/prepare/delete'), + '#default_value' => $default_directory, + '#description' => t('This is a directory as in public://some/directory or private://another/dir.'), + ); + $form['directory']['create_directory'] = array( + '#type' => 'submit', + '#value' => t('Create directory'), + '#submit' => array('file_example_create_directory_submit'), + ); + $form['directory']['delete_directory'] = array( + '#type' => 'submit', + '#value' => t('Delete directory'), + '#submit' => array('file_example_delete_directory_submit'), + ); + $form['directory']['check_directory'] = array( + '#type' => 'submit', + '#value' => t('Check to see if directory exists'), + '#submit' => array('file_example_check_directory_submit'), + ); + + $form['debug'] = array( + '#type' => 'fieldset', + '#title' => t('Debugging'), + ); + $form['debug']['show_raw_session'] = array( + '#type' => 'submit', + '#value' => t('Show raw $_SESSION contents'), + '#submit' => array('file_example_show_session_contents_submit'), + ); + + return $form; +} + +/** + * Submit handler to write a managed file. + * + * The key functions used here are: + * - file_save_data(), which takes a buffer and saves it to a named file and + * also creates a tracking record in the database and returns a file object. + * In this function we use FILE_EXISTS_RENAME (the default) as the argument, + * which means that if there's an existing file, create a new non-colliding + * filename and use it. + * - file_create_url(), which converts a URI in the form public://junk.txt or + * private://something/test.txt into a URL like + * http://example.com/sites/default/files/junk.txt. + */ +function file_example_managed_write_submit($form, &$form_state) { + $data = $form_state['values']['write_contents']; + $uri = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL; + + // Managed operations work with a file object. + $file_object = file_save_data($data, $uri, FILE_EXISTS_RENAME); + if (!empty($file_object)) { + $url = file_create_url($file_object->uri); + $_SESSION['file_example_default_file'] = $file_object->uri; + drupal_set_message( + t('Saved managed file: %file to destination %destination (accessible via !url, actual uri=@uri)', + array( + '%file' => print_r($file_object, TRUE), + '%destination' => $uri, '@uri' => $file_object->uri, + '!url' => l(t('this URL'), $url), + ) + ) + ); + } + else { + drupal_set_message(t('Failed to save the managed file'), 'error'); + } +} + +/** + * Submit handler to write an unmanaged file. + * + * The key functions used here are: + * - file_unmanaged_save_data(), which takes a buffer and saves it to a named + * file, but does not create any kind of tracking record in the database. + * This example uses FILE_EXISTS_REPLACE for the third argument, meaning + * that if there's an existing file at this location, it should be replaced. + * - file_create_url(), which converts a URI in the form public://junk.txt or + * private://something/test.txt into a URL like + * http://example.com/sites/default/files/junk.txt. + */ +function file_example_unmanaged_write_submit($form, &$form_state) { + $data = $form_state['values']['write_contents']; + $destination = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL; + + // With the unmanaged file we just get a filename back. + $filename = file_unmanaged_save_data($data, $destination, FILE_EXISTS_REPLACE); + if ($filename) { + $url = file_create_url($filename); + $_SESSION['file_example_default_file'] = $filename; + drupal_set_message( + t('Saved file as %filename (accessible via !url, uri=@uri)', + array( + '%filename' => $filename, + '@uri' => $filename, + '!url' => l(t('this URL'), $url), + ) + ) + ); + } + else { + drupal_set_message(t('Failed to save the file'), 'error'); + } +} + +/** + * Submit handler to write an unmanaged file using plain PHP functions. + * + * The key functions used here are: + * - file_unmanaged_save_data(), which takes a buffer and saves it to a named + * file, but does not create any kind of tracking record in the database. + * - file_create_url(), which converts a URI in the form public://junk.txt or + * private://something/test.txt into a URL like + * http://example.com/sites/default/files/junk.txt. + * - drupal_tempnam() generates a temporary filename for use. + */ +function file_example_unmanaged_php_submit($form, &$form_state) { + $data = $form_state['values']['write_contents']; + $destination = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL; + + if (empty($destination)) { + // If no destination has been provided, use a generated name. + $destination = drupal_tempnam('public://', 'file'); + } + + // With all traditional PHP functions we can use the stream wrapper notation + // for a file as well. + $fp = fopen($destination, 'w'); + + // To demonstrate the fact that everything is based on streams, we'll do + // multiple 5-character writes to put this to the file. We could easily + // (and far more conveniently) write it in a single statement with + // fwrite($fp, $data). + $length = strlen($data); + $write_size = 5; + for ($i = 0; $i < $length; $i += $write_size) { + $result = fwrite($fp, substr($data, $i, $write_size)); + if ($result === FALSE) { + drupal_set_message(t('Failed writing to the file %file', array('%file' => $destination)), 'error'); + fclose($fp); + return; + } + } + $url = file_create_url($destination); + $_SESSION['file_example_default_file'] = $destination; + drupal_set_message( + t('Saved file as %filename (accessible via !url, uri=@uri)', + array( + '%filename' => $destination, + '@uri' => $destination, + '!url' => l(t('this URL'), $url), + ) + ) + ); +} + +/** + * Submit handler for reading a stream wrapper. + * + * Drupal now has full support for PHP's stream wrappers, which means that + * instead of the traditional use of all the file functions + * ($fp = fopen("/tmp/some_file.txt");) far more sophisticated and generalized + * (and extensible) things can be opened as if they were files. Drupal itself + * provides the public:// and private:// schemes for handling public and + * private files. PHP provides file:// (the default) and http://, so that a + * URL can be read or written (as in a POST) as if it were a file. In addition, + * new schemes can be provided for custom applications, as will be demonstrated + * below. + * + * Here we take the stream wrapper provided in the form. We grab the + * contents with file_get_contents(). Notice that's it's as simple as that: + * file_get_contents("http://example.com") or + * file_get_contents("public://somefile.txt") just works. Although it's + * not necessary, we use file_unmanaged_save_data() to save this file locally + * and then find a local URL for it by using file_create_url(). + */ +function file_example_read_submit($form, &$form_state) { + $uri = $form_state['values']['fileops_file']; + + if (!is_file($uri)) { + drupal_set_message(t('The file %uri does not exist', array('%uri' => $uri)), 'error'); + return; + } + + // Make a working filename to save this by stripping off the (possible) + // file portion of the streamwrapper. If it's an evil file extension, + // file_munge_filename() will neuter it. + $filename = file_munge_filename(preg_replace('@^.*/@', '', $uri), '', TRUE); + $buffer = file_get_contents($uri); + + if ($buffer) { + $sourcename = file_unmanaged_save_data($buffer, 'public://' . $filename); + if ($sourcename) { + $url = file_create_url($sourcename); + $_SESSION['file_example_default_file'] = $sourcename; + drupal_set_message( + t('The file was read and copied to %filename which is accessible at !url', + array( + '%filename' => $sourcename, + '!url' => l($url, $url), + ) + ) + ); + } + else { + drupal_set_message(t('Failed to save the file')); + } + } + else { + // We failed to get the contents of the requested file. + drupal_set_message(t('Failed to retrieve the file %file', array('%file' => $uri))); + } +} + +/** + * Submit handler to delete a file. + */ +function file_example_delete_submit($form, &$form_state) { + + $uri = $form_state['values']['fileops_file']; + + // Since we don't know if the file is managed or not, look in the database + // to see. Normally, code would be working with either managed or unmanaged + // files, so this is not a typical situation. + $file_object = file_example_get_managed_file($uri); + + // If a managed file, use file_delete(). + if (!empty($file_object)) { + $result = file_delete($file_object); + if ($result !== TRUE) { + drupal_set_message(t('Failed deleting managed file %uri. Result was %result', + array( + '%uri' => $uri, + '%result' => print_r($result, TRUE), + ) + ), 'error'); + } + else { + drupal_set_message(t('Successfully deleted managed file %uri', array('%uri' => $uri))); + $_SESSION['file_example_default_file'] = $uri; + } + } + // Else use file_unmanaged_delete(). + else { + $result = file_unmanaged_delete($uri); + if ($result !== TRUE) { + drupal_set_message(t('Failed deleting unmanaged file %uri', array('%uri' => $uri, 'error'))); + } + else { + drupal_set_message(t('Successfully deleted unmanaged file %uri', array('%uri' => $uri))); + $_SESSION['file_example_default_file'] = $uri; + } + } +} + +/** + * Submit handler to check existence of a file. + */ +function file_example_file_check_exists_submit($form, &$form_state) { + $uri = $form_state['values']['fileops_file']; + if (is_file($uri)) { + drupal_set_message(t('The file %uri exists.', array('%uri' => $uri))); + } + else { + drupal_set_message(t('The file %uri does not exist.', array('%uri' => $uri))); + } + +} +/** + * Submit handler for directory creation. + * + * Here we create a directory and set proper permissions on it using + * file_prepare_directory(). + */ +function file_example_create_directory_submit($form, &$form_state) { + $directory = $form_state['values']['directory_name']; + + // The options passed to file_prepare_directory are a bitmask, so we can + // specify either FILE_MODIFY_PERMISSIONS (set permissions on the directory), + // FILE_CREATE_DIRECTORY, or both together: + // FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY. + // FILE_MODIFY_PERMISSIONS will set the permissions of the directory by + // by default to 0755, or to the value of the variable 'file_chmod_directory'. + if (!file_prepare_directory($directory, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY)) { + drupal_set_message(t('Failed to create %directory.', array('%directory' => $directory)), 'error'); + } + else { + drupal_set_message(t('Directory %directory is ready for use.', array('%directory' => $directory))); + $_SESSION['file_example_default_directory'] = $directory; + } +} + +/** + * Submit handler for directory deletion. + * + * @see file_unmanaged_delete_recursive() + */ +function file_example_delete_directory_submit($form, &$form_state) { + $directory = $form_state['values']['directory_name']; + + $result = file_unmanaged_delete_recursive($directory); + if (!$result) { + drupal_set_message(t('Failed to delete %directory.', array('%directory' => $directory)), 'error'); + } + else { + drupal_set_message(t('Recursively deleted directory %directory.', array('%directory' => $directory))); + $_SESSION['file_example_default_directory'] = $directory; + } +} + +/** + * Submit handler to test directory existence. + * + * This actually just checks to see if the directory is writable + * + * @param array $form + * FormAPI form. + * @param array $form_state + * FormAPI form state. + */ +function file_example_check_directory_submit($form, &$form_state) { + $directory = $form_state['values']['directory_name']; + $result = is_dir($directory); + if (!$result) { + drupal_set_message(t('Directory %directory does not exist.', array('%directory' => $directory))); + } + else { + drupal_set_message(t('Directory %directory exists.', array('%directory' => $directory))); + } +} + +/** + * Utility submit function to show the contents of $_SESSION. + */ +function file_example_show_session_contents_submit($form, &$form_state) { + // If the devel module is installed, use it's nicer message format. + if (module_exists('devel')) { + dsm($_SESSION['file_example'], t('Entire $_SESSION["file_example"]')); + } + else { + drupal_set_message('
' . print_r($_SESSION['file_example'], TRUE) . '
'); + } +} + +/** + * Utility function to check for and return a managed file. + * + * In this demonstration code we don't necessarily know if a file is managed + * or not, so often need to check to do the correct behavior. Normal code + * would not have to do this, as it would be working with either managed or + * unmanaged files. + * + * @param string $uri + * The URI of the file, like public://test.txt. + */ +function file_example_get_managed_file($uri) { + $fid = db_query('SELECT fid FROM {file_managed} WHERE uri = :uri', array(':uri' => $uri))->fetchField(); + if (!empty($fid)) { + $file_object = file_load($fid); + return $file_object; + } + return FALSE; +} + +/** + * Implements hook_stream_wrappers(). + * + * hook_stream_wrappers() is Drupal's way of exposing the class that PHP will + * use to provide a new stream wrapper class. In this case, we'll expose the + * 'session' scheme, so a file reference like "session://example/example.txt" + * is readable and writable as a location in the $_SESSION variable. + * + * @see FileExampleSessionStreamWrapper + */ +function file_example_stream_wrappers() { + $wrappers = array( + 'session' => array( + 'name' => t('Example: $_SESSION variable storage'), + 'class' => 'FileExampleSessionStreamWrapper', + 'description' => t('Store files in the $_SESSION variable as an example.'), + ), + ); + return $wrappers; +} + +/** + * Show the contents of a session file. + * + * This page callback function is called by the Menu API for the path + * examples/file_example/access_session. Any extra path elements + * beyond this are considered to be the session path. E.g.: + * examples/file_example/access_session/foo/bar.txt would be the + * equivalent of session://foo/bar.txt, which will map into + * $_SESSION as keys: $_SESSION['foo']['bar.txt'] + * + * Menu API will pass in additional path elements as function arguments. You + * can obtain these with func_get_args(). + * + * @return string + * A message containing the contents of the session file. + * + * @see file_get_contents() + */ +function file_example_session_contents() { + $path_components = func_get_args(); + $session_path = 'session://' . implode('/', $path_components); + $content = file_get_contents($session_path); + if ($content !== FALSE) { + return t('Contents of @path :', + array('@path' => check_plain($session_path))) . ' ' . + print_r($content, TRUE); + } + return t('Unable to load contents of: @path', + array('@path' => check_plain($session_path))); +} + +/** + * @} End of "defgroup file_example". + */ diff --git a/sites/all/modules/contrib/dev/examples/file_example/file_example.test b/sites/all/modules/contrib/dev/examples/file_example/file_example.test new file mode 100644 index 00000000..41e73c61 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/file_example/file_example.test @@ -0,0 +1,149 @@ + 'File Example Functionality', + 'description' => 'Test File Example features and sample streamwrapper.', + 'group' => 'Examples', + ); + } + + /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp(array('file_example')); + $this->priviledgedUser = $this->drupalCreateUser(array('use file example')); + $this->drupalLogin($this->priviledgedUser); + } + + /** + * Test the basic File Example UI. + * + * - Create a directory to work with + * - Foreach scheme create and read files using each of the three methods. + */ + public function testFileExampleBasic() { + + $expected_text = array( + t('Write managed file') => t('Saved managed file'), + t('Write unmanaged file') => t('Saved file as'), + t('Unmanaged using PHP') => t('Saved file as'), + ); + // For each of the three buttons == three write types. + $buttons = array( + t('Write managed file'), + t('Write unmanaged file'), + t('Unmanaged using PHP'), + ); + foreach ($buttons as $button) { + // For each scheme supported by Drupal + the session:// wrapper. + $schemes = array('public', 'private', 'temporary', 'session'); + foreach ($schemes as $scheme) { + // Create a directory for use. + $dirname = $scheme . '://' . $this->randomName(10); + + // Directory does not yet exist; assert that. + $edit = array( + 'directory_name' => $dirname, + ); + $this->drupalPost('examples/file_example/fileapi', $edit, t('Check to see if directory exists')); + $this->assertRaw(t('Directory %dirname does not exist', array('%dirname' => $dirname)), 'Verify that directory does not exist.'); + + $this->drupalPost('examples/file_example/fileapi', $edit, t('Create directory')); + $this->assertRaw(t('Directory %dirname is ready for use', array('%dirname' => $dirname))); + + $this->drupalPost('examples/file_example/fileapi', $edit, t('Check to see if directory exists')); + $this->assertRaw(t('Directory %dirname exists', array('%dirname' => $dirname)), 'Verify that directory now does exist.'); + + // Create a file in the directory we created. + $content = $this->randomName(30); + $filename = $dirname . '/' . $this->randomName(30) . '.txt'; + + // Assert that the file we're about to create does not yet exist. + $edit = array( + 'fileops_file' => $filename, + ); + $this->drupalPost('examples/file_example/fileapi', $edit, t('Check to see if file exists')); + $this->assertRaw(t('The file %filename does not exist', array('%filename' => $filename)), 'Verify that file does not yet exist.'); + + debug( + t('Processing button=%button, scheme=%scheme, dir=%dirname, file=%filename', + array( + '%button' => $button, + '%scheme' => $scheme, + '%filename' => $filename, + '%dirname' => $dirname, + ) + ) + ); + $edit = array( + 'write_contents' => $content, + 'destination' => $filename, + ); + $this->drupalPost('examples/file_example/fileapi', $edit, $button); + $this->assertText($expected_text[$button]); + + // Capture the name of the output file, as it might have changed due + // to file renaming. + $element = $this->xpath('//span[@id="uri"]'); + $output_filename = (string) $element[0]; + debug($output_filename, 'Name of output file'); + + // Click the link provided that is an easy way to get the data for + // checking and make sure that the data we put in is what we get out. + if (!in_array($scheme, array('private', 'temporary'))) { + $this->clickLink(t('this URL')); + $this->assertText($content); + } + + // Verify that the file exists. + $edit = array( + 'fileops_file' => $filename, + ); + $this->drupalPost('examples/file_example/fileapi', $edit, t('Check to see if file exists')); + $this->assertRaw(t('The file %filename exists', array('%filename' => $filename)), 'Verify that file now exists.'); + + // Now read the file that got written above and verify that we can use + // the writing tools. + $edit = array( + 'fileops_file' => $output_filename, + ); + $this->drupalPost('examples/file_example/fileapi', $edit, t('Read the file and store it locally')); + + $this->assertText(t('The file was read and copied')); + + $edit = array( + 'fileops_file' => $filename, + ); + $this->drupalPost('examples/file_example/fileapi', $edit, t('Delete file')); + $this->assertText(t('Successfully deleted')); + $this->drupalPost('examples/file_example/fileapi', $edit, t('Check to see if file exists')); + $this->assertRaw(t('The file %filename does not exist', array('%filename' => $filename)), 'Verify file has been deleted.'); + + $edit = array( + 'directory_name' => $dirname, + ); + $this->drupalPost('examples/file_example/fileapi', $edit, t('Delete directory')); + $this->drupalPost('examples/file_example/fileapi', $edit, t('Check to see if directory exists')); + $this->assertRaw(t('Directory %dirname does not exist', array('%dirname' => $dirname)), 'Verify that directory does not exist after deletion.'); + } + } + } +} diff --git a/sites/all/modules/contrib/dev/examples/file_example/file_example_session_streams.inc b/sites/all/modules/contrib/dev/examples/file_example/file_example_session_streams.inc new file mode 100644 index 00000000..dc4850c3 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/file_example/file_example_session_streams.inc @@ -0,0 +1,698 @@ +uri = $uri; + } + + /** + * Implements getUri(). + */ + public function getUri() { + return $this->uri; + } + + /** + * Implements getTarget(). + * + * The "target" is the portion of the URI to the right of the scheme. + * So in session://example/test.txt, the target is 'example/test.txt'. + */ + public function getTarget($uri = NULL) { + if (!isset($uri)) { + $uri = $this->uri; + } + + list($scheme, $target) = explode('://', $uri, 2); + + // Remove erroneous leading or trailing, forward-slashes and backslashes. + // In the session:// scheme, there is never a leading slash on the target. + return trim($target, '\/'); + } + + /** + * Implements getMimeType(). + */ + public static function getMimeType($uri, $mapping = NULL) { + if (!isset($mapping)) { + // The default file map, defined in file.mimetypes.inc is quite big. + // We only load it when necessary. + include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc'; + $mapping = file_mimetype_mapping(); + } + + $extension = ''; + $file_parts = explode('.', basename($uri)); + + // Remove the first part: a full filename should not match an extension. + array_shift($file_parts); + + // Iterate over the file parts, trying to find a match. + // For my.awesome.image.jpeg, we try: + // - jpeg + // - image.jpeg, and + // - awesome.image.jpeg + while ($additional_part = array_pop($file_parts)) { + $extension = drupal_strtolower($additional_part . ($extension ? '.' . $extension : '')); + if (isset($mapping['extensions'][$extension])) { + return $mapping['mimetypes'][$mapping['extensions'][$extension]]; + } + } + + return 'application/octet-stream'; + } + + /** + * Implements getDirectoryPath(). + * + * In this case there is no directory string, so return an empty string. + */ + public function getDirectoryPath() { + return ''; + } + + /** + * Overrides getExternalUrl(). + * + * We have set up a helper function and menu entry to provide access to this + * key via HTTP; normally it would be accessible some other way. + */ + public function getExternalUrl() { + $path = $this->getLocalPath(); + $url = url('examples/file_example/access_session/' . $path, array('absolute' => TRUE)); + return $url; + } + + /** + * We have no concept of chmod, so just return TRUE. + */ + public function chmod($mode) { + return TRUE; + } + + /** + * Implements realpath(). + */ + public function realpath() { + return 'session://' . $this->getLocalPath(); + } + + /** + * Returns the local path. + * + * Here we aren't doing anything but stashing the "file" in a key in the + * $_SESSION variable, so there's not much to do but to create a "path" + * which is really just a key in the $_SESSION variable. So something + * like 'session://one/two/three.txt' becomes + * $_SESSION['file_example']['one']['two']['three.txt'] and the actual path + * is "one/two/three.txt". + * + * @param string $uri + * Optional URI, supplied when doing a move or rename. + */ + protected function getLocalPath($uri = NULL) { + if (!isset($uri)) { + $uri = $this->uri; + } + + $path = str_replace('session://', '', $uri); + $path = trim($path, '/'); + return $path; + } + + /** + * Opens a stream, as for fopen(), file_get_contents(), file_put_contents(). + * + * @param string $uri + * A string containing the URI to the file to open. + * @param string $mode + * The file mode ("r", "wb" etc.). + * @param int $options + * A bit mask of STREAM_USE_PATH and STREAM_REPORT_ERRORS. + * @param string &$opened_path + * A string containing the path actually opened. + * + * @return bool + * Returns TRUE if file was opened successfully. (Always returns TRUE). + * + * @see http://php.net/manual/en/streamwrapper.stream-open.php + */ + public function stream_open($uri, $mode, $options, &$opened_path) { + $this->uri = $uri; + // We make $session_content a reference to the appropriate key in the + // $_SESSION variable. So if the local path were + // /example/test.txt it $session_content would now be a + // reference to $_SESSION['file_example']['example']['test.txt']. + $this->sessionContent = &$this->uri_to_session_key($uri); + + // Reset the stream pointer since this is an open. + $this->streamPointer = 0; + return TRUE; + } + + /** + * Return a reference to the correct $_SESSION key. + * + * @param string $uri + * The uri: session://something + * @param bool $create + * If TRUE, create the key + * + * @return array|bool + * A reference to the array at the end of the key-path, or + * FALSE if the path doesn't map to a key-path (and $create is FALSE). + */ + protected function &uri_to_session_key($uri, $create = TRUE) { + // Since our uri_to_session_key() method returns a reference, we + // have to set up a failure flag variable. + $fail = FALSE; + $path = $this->getLocalPath($uri); + $path_components = explode('/', $path); + // Set up a reference to the root session:// 'directory.' + $var = &$_SESSION['file_example']; + // Handle case of just session://. + if (count($path_components) < 1) { + return $var; + } + // Walk through the path components and create keys in $_SESSION, + // unless we're told not to create them. + foreach ($path_components as $component) { + if ($create || isset($var[$component])) { + $var = &$var[$component]; + } + else { + // This path doesn't exist as keys, either because the + // key doesn't exist, or because we're told not to create it. + return $fail; + } + } + return $var; + } + + /** + * Support for flock(). + * + * The $_SESSION variable has no locking capability, so return TRUE. + * + * @param int $operation + * One of the following: + * - LOCK_SH to acquire a shared lock (reader). + * - LOCK_EX to acquire an exclusive lock (writer). + * - LOCK_UN to release a lock (shared or exclusive). + * - LOCK_NB if you don't want flock() to block while locking (not + * supported on Windows). + * + * @return bool + * Always returns TRUE at the present time. (no support) + * + * @see http://php.net/manual/en/streamwrapper.stream-lock.php + */ + public function stream_lock($operation) { + return TRUE; + } + + /** + * Support for fread(), file_get_contents() etc. + * + * @param int $count + * Maximum number of bytes to be read. + * + * @return string + * The string that was read, or FALSE in case of an error. + * + * @see http://php.net/manual/en/streamwrapper.stream-read.php + */ + public function stream_read($count) { + if (is_string($this->sessionContent)) { + $remaining_chars = drupal_strlen($this->sessionContent) - $this->streamPointer; + $number_to_read = min($count, $remaining_chars); + if ($remaining_chars > 0) { + $buffer = drupal_substr($this->sessionContent, $this->streamPointer, $number_to_read); + $this->streamPointer += $number_to_read; + return $buffer; + } + } + return FALSE; + } + + /** + * Support for fwrite(), file_put_contents() etc. + * + * @param string $data + * The string to be written. + * + * @return int + * The number of bytes written (integer). + * + * @see http://php.net/manual/en/streamwrapper.stream-write.php + */ + public function stream_write($data) { + // Sanitize the data in a simple way since we're putting it into the + // session variable. + $data = check_plain($data); + $this->sessionContent = substr_replace($this->sessionContent, $data, $this->streamPointer); + $this->streamPointer += drupal_strlen($data); + return drupal_strlen($data); + } + + /** + * Support for feof(). + * + * @return bool + * TRUE if end-of-file has been reached. + * + * @see http://php.net/manual/en/streamwrapper.stream-eof.php + */ + public function stream_eof() { + return FALSE; + } + + /** + * Support for fseek(). + * + * @param int $offset + * The byte offset to got to. + * @param int $whence + * SEEK_SET, SEEK_CUR, or SEEK_END. + * + * @return bool + * TRUE on success. + * + * @see http://php.net/manual/en/streamwrapper.stream-seek.php + */ + public function stream_seek($offset, $whence) { + if (drupal_strlen($this->sessionContent) >= $offset) { + $this->streamPointer = $offset; + return TRUE; + } + return FALSE; + } + + /** + * Support for fflush(). + * + * @return bool + * TRUE if data was successfully stored (or there was no data to store). + * This always returns TRUE, as this example provides and needs no + * flush support. + * + * @see http://php.net/manual/en/streamwrapper.stream-flush.php + */ + public function stream_flush() { + return TRUE; + } + + /** + * Support for ftell(). + * + * @return int + * The current offset in bytes from the beginning of file. + * + * @see http://php.net/manual/en/streamwrapper.stream-tell.php + */ + public function stream_tell() { + return $this->streamPointer; + } + + /** + * Support for fstat(). + * + * @return array + * An array with file status, or FALSE in case of an error - see fstat() + * for a description of this array. + * + * @see http://php.net/manual/en/streamwrapper.stream-stat.php + */ + public function stream_stat() { + return array( + 'size' => drupal_strlen($this->sessionContent), + ); + } + + /** + * Support for fclose(). + * + * @return bool + * TRUE if stream was successfully closed. + * + * @see http://php.net/manual/en/streamwrapper.stream-close.php + */ + public function stream_close() { + $this->streamPointer = 0; + // Unassign the reference. + unset($this->sessionContent); + return TRUE; + } + + /** + * Support for unlink(). + * + * @param string $uri + * A string containing the uri to the resource to delete. + * + * @return bool + * TRUE if resource was successfully deleted. + * + * @see http://php.net/manual/en/streamwrapper.unlink.php + */ + public function unlink($uri) { + $path = $this->getLocalPath($uri); + $path_components = preg_split('/\//', $path); + $unset = '$_SESSION[\'file_example\']'; + foreach ($path_components as $component) { + $unset .= '[\'' . $component . '\']'; + } + // TODO: Is there a better way to delete from an array? + // drupal_array_get_nested_value() doesn't work because it only returns + // a reference; unsetting a reference only unsets the reference. + eval("unset($unset);"); + return TRUE; + } + + /** + * Support for rename(). + * + * @param string $from_uri + * The uri to the file to rename. + * @param string $to_uri + * The new uri for file. + * + * @return bool + * TRUE if file was successfully renamed. + * + * @see http://php.net/manual/en/streamwrapper.rename.php + */ + public function rename($from_uri, $to_uri) { + $from_key = &$this->uri_to_session_key($from_uri); + $to_key = &$this->uri_to_session_key($to_uri); + if (is_dir($to_key) || is_file($to_key)) { + return FALSE; + } + $to_key = $from_key; + unset($from_key); + return TRUE; + } + + /** + * Gets the name of the directory from a given path. + * + * @param string $uri + * A URI. + * + * @return string + * A string containing the directory name. + * + * @see drupal_dirname() + */ + public function dirname($uri = NULL) { + list($scheme, $target) = explode('://', $uri, 2); + $target = $this->getTarget($uri); + if (strpos($target, '/')) { + $dirname = preg_replace('@/[^/]*$@', '', $target); + } + else { + $dirname = ''; + } + return $scheme . '://' . $dirname; + } + + /** + * Support for mkdir(). + * + * @param string $uri + * A string containing the URI to the directory to create. + * @param int $mode + * Permission flags - see mkdir(). + * @param int $options + * A bit mask of STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE. + * + * @return bool + * TRUE if directory was successfully created. + * + * @see http://php.net/manual/en/streamwrapper.mkdir.php + */ + public function mkdir($uri, $mode, $options) { + // If this already exists, then we can't mkdir. + if (is_dir($uri) || is_file($uri)) { + return FALSE; + } + + // Create the key in $_SESSION; + $this->uri_to_session_key($uri, TRUE); + + // Place a magic file inside it to differentiate this from an empty file. + $marker_uri = $uri . '/.isadir.txt'; + $this->uri_to_session_key($marker_uri, TRUE); + return TRUE; + } + + /** + * Support for rmdir(). + * + * @param string $uri + * A string containing the URI to the directory to delete. + * @param int $options + * A bit mask of STREAM_REPORT_ERRORS. + * + * @return bool + * TRUE if directory was successfully removed. + * + * @see http://php.net/manual/en/streamwrapper.rmdir.php + */ + public function rmdir($uri, $options) { + $path = $this->getLocalPath($uri); + $path_components = preg_split('/\//', $path); + $unset = '$_SESSION[\'file_example\']'; + foreach ($path_components as $component) { + $unset .= '[\'' . $component . '\']'; + } + // TODO: I really don't like this eval. + debug($unset, 'array element to be unset'); + eval("unset($unset);"); + + return TRUE; + } + + /** + * Support for stat(). + * + * This important function goes back to the Unix way of doing things. + * In this example almost the entire stat array is irrelevant, but the + * mode is very important. It tells PHP whether we have a file or a + * directory and what the permissions are. All that is packed up in a + * bitmask. This is not normal PHP fodder. + * + * @param string $uri + * A string containing the URI to get information about. + * @param int $flags + * A bit mask of STREAM_URL_STAT_LINK and STREAM_URL_STAT_QUIET. + * + * @return array|bool + * An array with file status, or FALSE in case of an error - see fstat() + * for a description of this array. + * + * @see http://php.net/manual/en/streamwrapper.url-stat.php + */ + public function url_stat($uri, $flags) { + // Get a reference to the $_SESSION key for this URI. + $key = $this->uri_to_session_key($uri, FALSE); + // Default to fail. + $return = FALSE; + $mode = 0; + + // We will call an array a directory and the root is always an array. + if (is_array($key) && array_key_exists('.isadir.txt', $key)) { + // S_IFDIR means it's a directory. + $mode = 0040000; + } + elseif ($key !== FALSE) { + // S_IFREG, means it's a file. + $mode = 0100000; + } + + if ($mode) { + $size = 0; + if ($mode == 0100000) { + $size = drupal_strlen($key); + } + + // There are no protections on this, so all writable. + $mode |= 0777; + $return = array( + 'dev' => 0, + 'ino' => 0, + 'mode' => $mode, + 'nlink' => 0, + 'uid' => 0, + 'gid' => 0, + 'rdev' => 0, + 'size' => $size, + 'atime' => 0, + 'mtime' => 0, + 'ctime' => 0, + 'blksize' => 0, + 'blocks' => 0, + ); + } + return $return; + } + + /** + * Support for opendir(). + * + * @param string $uri + * A string containing the URI to the directory to open. + * @param int $options + * Whether or not to enforce safe_mode (0x04). + * + * @return bool + * TRUE on success. + * + * @see http://php.net/manual/en/streamwrapper.dir-opendir.php + */ + public function dir_opendir($uri, $options) { + $var = &$this->uri_to_session_key($uri, FALSE); + if ($var === FALSE || !array_key_exists('.isadir.txt', $var)) { + return FALSE; + } + + // We grab the list of key names, flip it so that .isadir.txt can easily + // be removed, then flip it back so we can easily walk it as a list. + $this->directoryKeys = array_flip(array_keys($var)); + unset($this->directoryKeys['.isadir.txt']); + $this->directoryKeys = array_keys($this->directoryKeys); + $this->directoryPointer = 0; + return TRUE; + } + + /** + * Support for readdir(). + * + * @return string|bool + * The next filename, or FALSE if there are no more files in the directory. + * + * @see http://php.net/manual/en/streamwrapper.dir-readdir.php + */ + public function dir_readdir() { + if ($this->directoryPointer < count($this->directoryKeys)) { + $next = $this->directoryKeys[$this->directoryPointer]; + $this->directoryPointer++; + return $next; + } + return FALSE; + } + + /** + * Support for rewinddir(). + * + * @return bool + * TRUE on success. + * + * @see http://php.net/manual/en/streamwrapper.dir-rewinddir.php + */ + public function dir_rewinddir() { + $this->directoryPointer = 0; + } + + /** + * Support for closedir(). + * + * @return bool + * TRUE on success. + * + * @see http://php.net/manual/en/streamwrapper.dir-closedir.php + */ + public function dir_closedir() { + $this->directoryPointer = 0; + unset($this->directoryKeys); + return TRUE; + } +} diff --git a/sites/all/modules/contrib/dev/examples/filter_example/filter_example.info b/sites/all/modules/contrib/dev/examples/filter_example/filter_example.info new file mode 100644 index 00000000..75d14081 --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/filter_example/filter_example.info @@ -0,0 +1,12 @@ +name = Filter example +description = An example module showing how to define a custom filter. +package = Example modules +core = 7.x +files[] = filter_example.test + +; Information added by Drupal.org packaging script on 2016-09-18 +version = "7.x-1.x-dev" +core = "7.x" +project = "examples" +datestamp = "1474218553" + diff --git a/sites/all/modules/contrib/dev/examples/filter_example/filter_example.module b/sites/all/modules/contrib/dev/examples/filter_example/filter_example.module new file mode 100644 index 00000000..f5e9dffe --- /dev/null +++ b/sites/all/modules/contrib/dev/examples/filter_example/filter_example.module @@ -0,0 +1,203 @@ +, and replace it by the current time. + * + * Foo filter + * + * Drupal has several content formats (they are not filters), and in our example + * the foo replacement can be configured for each one of them, allowing an html + * or php replacement, so the module includes a settings callback, with options + * to configure that replacements. Also, a Tips callback will help showing the + * current replacement for the content type being edited. + * + * Time filter. + * + * This filter is a little trickier to implement than the previous one. + * Since the input involves special HTML characters (< and >) we have to + * run the filter before HTML is escaped/stripped by other filters. But + * we want to use HTML in our result as well, and so if we run this filter + * first our replacement string could be escaped or stripped. The solution + * is to use the "prepare" operation to escape the special characters, and + * to later replace our escaped version in the "process" step. + */ + +/** + * Implements hook_menu(). + */ +function filter_example_menu() { + $items['examples/filter_example'] = array( + 'title' => 'Filter Example', + 'page callback' => '_filter_example_information', + 'access callback' => TRUE, + ); + return $items; +} + +/** + * Implements hook_help(). + */ +function filter_example_help($path, $arg) { + switch ($path) { + case 'admin/help#filter_example': + return _filter_example_information(); + } +} + +/** + * Simply returns a little bit of information about the example. + */ +function _filter_example_information() { + return t("

This example provides two filters.

Foo Filter replaces + 'foo' with a configurable replacement.

Time Tag replaces the string + '<time />' with the current time.

To use these filters, go to !link and + configure an input format, or create a new one.

", + array('!link' => l(t('admin/config/content/formats'), 'admin/config/content/formats')) + ); +} + +/** + * Implements hook_filter_info(). + * + * Here we define the different filters provided by the module. For this + * example, time_filter is a very static and simple replacement, but it requires + * some preparation of the string because of the special html tags < and >. The + * foo_filter is more complex, including its own settings and inline tips. + */ +function filter_example_filter_info() { + $filters['filter_foo'] = array( + 'title' => t('Foo Filter (example)'), + 'description' => t('Every instance of "foo" in the input text will be replaced with a preconfigured replacement.'), + 'process callback' => '_filter_example_filter_foo_process', + 'default settings' => array( + 'filter_example_foo' => 'bar', + ), + 'settings callback' => '_filter_example_filter_foo_settings', + 'tips callback' => '_filter_example_filter_foo_tips', + ); + $filters['filter_time'] = array( + 'title' => t('Time Tag (example)'), + 'description' => t("Every instance of the special <time /> tag will be replaced with the current date and time in the user's specified time zone."), + 'prepare callback' => '_filter_example_filter_time_prepare', + 'process callback' => '_filter_example_filter_time_process', + 'tips callback' => '_filter_example_filter_time_tips', + ); + return $filters; +} + +/* + * Foo filter + * + * Drupal has several text formats (they are not filters), and in our example + * the foo replacement can be configured for each one of them, so the module + * includes a settings callback, with options to configure those replacements. + * Also, a Tips callback will help showing the current replacement + * for the content type being edited. + */ + +/** + * Settings callback for foo filter. + * + * Make use of $format to have different replacements for every input format. + * Since we allow the administrator to define the string that gets substituted + * when "foo" is encountered, we need to provide an interface for this kind of + * customization. The object format is also an argument of the callback. + * + * The settings defined in this form are stored in database by the filter + * module, and they will be available in the $filter argument. + */ +function _filter_example_filter_foo_settings($form, $form_state, $filter, $format, $defaults) { + $settings['filter_example_foo'] = array( + '#type' => 'textfield', + '#title' => t('Substitution string'), + '#default_value' => isset($filter->settings['filter_example_foo']) ? $filter->settings['filter_example_foo'] : $defaults['filter_example_foo'], + '#description' => t('The string to substitute for "foo" everywhere in the text.'), + ); + return $settings; +} + +/** + * Foo filter process callback. + * + * The actual filtering is performed here. The supplied text should be returned, + * once any necessary substitutions have taken place. The example just replaces + * foo with our custom defined string in the settings page. + */ +function _filter_example_filter_foo_process($text, $filter, $format) { + $replacement = isset($filter->settings['filter_example_foo']) ? $filter->settings['filter_example_foo'] : 'bar'; + return str_replace('foo', $replacement, $text); +} + + +/** + * Filter tips callback for foo filter. + * + * The tips callback allows filters to provide help text to users during the + * content editing process. Short tips are provided on the content editing + * screen, while long tips are provided on a separate linked page. Short tips + * are optional, but long tips are highly recommended. + */ +function _filter_example_filter_foo_tips($filter, $format, $long = FALSE) { + $replacement = isset($filter->settings['filter_example_foo']) ? $filter->settings['filter_example_foo'] : 'bar'; + if (!$long) { + // This string will be shown in the content add/edit form. + return t('foo replaced with %replacement.', array('%replacement' => $replacement)); + } + else { + return t('Every instance of "foo" in the input text will be replaced with a configurable value. You can configure this value and put whatever you want there. The replacement value is "%replacement".', array('%replacement' => $replacement)); + } +} + +/** + * Time filter prepare callback. + * + * We'll use [filter-example-time] as a replacement for the time tag. + * Note that in a more complicated filter a closing tag may also be + * required. For more information, see "Temporary placeholders and + * delimiters" at http://drupal.org/node/209715. + */ +function _filter_example_filter_time_prepare($text, $filter) { + return preg_replace('!