trusty-cms 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.gitignore +23 -0
- data/CHANGELOG.md +754 -0
- data/CONTRIBUTORS.md +263 -0
- data/Gemfile +40 -0
- data/Gemfile.lock +177 -0
- data/INSTALL.md +10 -0
- data/LICENSE.md +21 -0
- data/README.md +85 -0
- data/Rakefile +7 -0
- data/app/controllers/admin/configuration_controller.rb +50 -0
- data/app/controllers/admin/extensions_controller.rb +11 -0
- data/app/controllers/admin/layouts_controller.rb +8 -0
- data/app/controllers/admin/page_fields_controller.rb +9 -0
- data/app/controllers/admin/page_parts_controller.rb +9 -0
- data/app/controllers/admin/pages_controller.rb +89 -0
- data/app/controllers/admin/preferences_controller.rb +46 -0
- data/app/controllers/admin/references_controller.rb +7 -0
- data/app/controllers/admin/resource_controller.rb +245 -0
- data/app/controllers/admin/users_controller.rb +40 -0
- data/app/controllers/admin/welcome_controller.rb +48 -0
- data/app/controllers/application_controller.rb +114 -0
- data/app/controllers/site_controller.rb +97 -0
- data/app/helpers/admin/configuration_helper.rb +80 -0
- data/app/helpers/admin/export_helper.rb +2 -0
- data/app/helpers/admin/extensions_helper.rb +2 -0
- data/app/helpers/admin/layouts_helper.rb +21 -0
- data/app/helpers/admin/node_helper.rb +96 -0
- data/app/helpers/admin/pages_helper.rb +117 -0
- data/app/helpers/admin/preferences_helper.rb +3 -0
- data/app/helpers/admin/references_helper.rb +46 -0
- data/app/helpers/admin/regions_helper.rb +28 -0
- data/app/helpers/admin/resource_helper.rb +2 -0
- data/app/helpers/admin/users_helper.rb +8 -0
- data/app/helpers/admin/welcome_helper.rb +2 -0
- data/app/helpers/application_helper.rb +241 -0
- data/app/helpers/site_helper.rb +2 -0
- data/app/models/deprecated_tags.rb +42 -0
- data/app/models/file_not_found_page.rb +32 -0
- data/app/models/layout.rb +15 -0
- data/app/models/menu_renderer.rb +140 -0
- data/app/models/page.rb +377 -0
- data/app/models/page_context.rb +53 -0
- data/app/models/page_field.rb +3 -0
- data/app/models/page_part.rb +20 -0
- data/app/models/standard_tags.rb +1318 -0
- data/app/models/status.rb +41 -0
- data/app/models/text_filter.rb +36 -0
- data/app/models/trusty_cms/config.rb +313 -0
- data/app/models/trusty_cms/page_response_cache_director.rb +43 -0
- data/app/models/user.rb +96 -0
- data/app/models/user_action_observer.rb +25 -0
- data/app/views/admin/configuration/edit.html.haml +38 -0
- data/app/views/admin/configuration/show.html.haml +58 -0
- data/app/views/admin/extensions/index.html.haml +41 -0
- data/app/views/admin/layouts/_form.html.haml +39 -0
- data/app/views/admin/layouts/edit.html.haml +9 -0
- data/app/views/admin/layouts/index.html.haml +35 -0
- data/app/views/admin/layouts/new.html.haml +7 -0
- data/app/views/admin/layouts/remove.html.haml +16 -0
- data/app/views/admin/page_fields/_page_field.html.haml +12 -0
- data/app/views/admin/page_parts/_page_part.html.haml +18 -0
- data/app/views/admin/pages/_fields.html.haml +71 -0
- data/app/views/admin/pages/_meta_row.html.haml +8 -0
- data/app/views/admin/pages/_node.html.haml +26 -0
- data/app/views/admin/pages/_popups.html.haml +27 -0
- data/app/views/admin/pages/children.html.haml +2 -0
- data/app/views/admin/pages/edit.html.haml +12 -0
- data/app/views/admin/pages/index.html.haml +26 -0
- data/app/views/admin/pages/new.html.haml +10 -0
- data/app/views/admin/pages/remove.html.haml +18 -0
- data/app/views/admin/preferences/edit.html.haml +44 -0
- data/app/views/admin/references/_tag_reference.haml +3 -0
- data/app/views/admin/references/filters.haml +6 -0
- data/app/views/admin/references/tags.haml +30 -0
- data/app/views/admin/users/_avatar.html.haml +5 -0
- data/app/views/admin/users/_form.html.haml +53 -0
- data/app/views/admin/users/_password_fields.html.haml +18 -0
- data/app/views/admin/users/edit.html.haml +9 -0
- data/app/views/admin/users/index.html.haml +39 -0
- data/app/views/admin/users/new.html.haml +6 -0
- data/app/views/admin/users/remove.html.haml +16 -0
- data/app/views/admin/welcome/login.html.haml +23 -0
- data/app/views/layouts/application.html.haml +50 -0
- data/app/views/site/not_found.html.haml +3 -0
- data/bin/ci/before_script +15 -0
- data/bin/trusty_cms +53 -0
- data/config/application.rb +124 -0
- data/config/boot.rb +9 -0
- data/config/compass.config +15 -0
- data/config/database.db2.yml +20 -0
- data/config/database.mysql.yml +25 -0
- data/config/database.postgresql.yml +25 -0
- data/config/database.sqlite.yml +16 -0
- data/config/database.sqlserver.yml +20 -0
- data/config/environment.rb +5 -0
- data/config/environments/development.rb +19 -0
- data/config/environments/production.rb +27 -0
- data/config/environments/test.rb +35 -0
- data/config/initializers/active_record_extensions.rb +1 -0
- data/config/initializers/configuration_extensions.rb +0 -0
- data/config/initializers/haml.rb +2 -0
- data/config/initializers/object_extensions.rb +1 -0
- data/config/initializers/radiant_config.rb +16 -0
- data/config/initializers/rails_patch.rb +2 -0
- data/config/initializers/response_cache_timeout.rb +3 -0
- data/config/initializers/string_extensions.rb +1 -0
- data/config/initializers/symbol_extensions.rb +1 -0
- data/config/initializers/tmp.rb +2 -0
- data/config/locales/en.yml +230 -0
- data/config/locales/en_available_tags.yml +625 -0
- data/config/preinitializer.rb +18 -0
- data/config/routes.rb +30 -0
- data/db/migrate/001_create_radiant_tables.rb +75 -0
- data/db/migrate/002_insert_initial_data.rb +12 -0
- data/db/migrate/003_rename_behavior_column.rb +9 -0
- data/db/migrate/004_rename_filter_column.rb +11 -0
- data/db/migrate/005_add_virtual_column_to_page.rb +9 -0
- data/db/migrate/006_integer_columns_to_boolean.rb +36 -0
- data/db/migrate/007_remove_virtual_column_from_page.rb +9 -0
- data/db/migrate/008_add_virtual_column_to_page_again.rb +9 -0
- data/db/migrate/009_add_content_type_field_to_layout.rb +9 -0
- data/db/migrate/010_merge_behaviors_and_pages.rb +57 -0
- data/db/migrate/011_rename_type_column_on_page_to_class_name.rb +9 -0
- data/db/migrate/012_create_extension_meta.rb +13 -0
- data/db/migrate/013_add_notes_field_to_user.rb +9 -0
- data/db/migrate/014_rename_config_default_parts_key.rb +17 -0
- data/db/migrate/015_add_optimistic_locking.rb +15 -0
- data/db/migrate/016_add_sessions.rb +16 -0
- data/db/migrate/017_rename_created_by_updated_by_columns.rb +15 -0
- data/db/migrate/018_add_description_and_keywords_to_pages.rb +11 -0
- data/db/migrate/019_add_salt_to_users.rb +11 -0
- data/db/migrate/020_add_session_info_to_users.rb +11 -0
- data/db/migrate/021_remove_session_expire_from_users.rb +9 -0
- data/db/migrate/20081203140407_add_indexes.rb +19 -0
- data/db/migrate/20090226140109_add_user_language.rb +9 -0
- data/db/migrate/20090929164633_rename_developer_role_to_designer.rb +9 -0
- data/db/migrate/20091003095744_change_user_language_to_locale.rb +9 -0
- data/db/migrate/20100805154952_add_page_fields.rb +15 -0
- data/db/migrate/20100805155020_convert_page_metas.rb +24 -0
- data/db/migrate/20100810151922_add_field_name_index.rb +11 -0
- data/db/migrate/20110902203823_add_allowed_children_cache_to_pages.rb +13 -0
- data/db/migrate/20111016150725_extend_page_part_content_limit.rb +15 -0
- data/db/migrate/20120209231801_change_pages_allowed_children_cache_to_text.rb +11 -0
- data/db/schema.rb +128 -0
- data/lib/active_record_extensions/active_record_extensions.rb +27 -0
- data/lib/annotatable.rb +68 -0
- data/lib/configuration_extensions/configuration_extensions.rb +357 -0
- data/lib/generators/extension/USAGE +30 -0
- data/lib/generators/extension/extension_generator.rb +97 -0
- data/lib/generators/extension/templates/README.md +6 -0
- data/lib/generators/extension/templates/RSpecRakefile +109 -0
- data/lib/generators/extension/templates/Rakefile +25 -0
- data/lib/generators/extension/templates/cucumber.yml +1 -0
- data/lib/generators/extension/templates/cucumber_env.rb +11 -0
- data/lib/generators/extension/templates/cucumber_paths.rb +22 -0
- data/lib/generators/extension/templates/en.yml +3 -0
- data/lib/generators/extension/templates/extension.rb +21 -0
- data/lib/generators/extension/templates/functional_test.rb +15 -0
- data/lib/generators/extension/templates/gemspec.rb +29 -0
- data/lib/generators/extension/templates/lib.rb +8 -0
- data/lib/generators/extension/templates/migration.rb +9 -0
- data/lib/generators/extension/templates/radiant_config.rb +3 -0
- data/lib/generators/extension/templates/routes.rb +5 -0
- data/lib/generators/extension/templates/spec.opts +6 -0
- data/lib/generators/extension/templates/spec_helper.rb +42 -0
- data/lib/generators/extension/templates/tasks.rake +47 -0
- data/lib/generators/extension/templates/test_helper.rb +26 -0
- data/lib/generators/extension_controller/USAGE +36 -0
- data/lib/generators/extension_controller/extension_controller_generator.rb +84 -0
- data/lib/generators/extension_controller/templates/controller.rb +10 -0
- data/lib/generators/extension_controller/templates/controller_spec.rb +23 -0
- data/lib/generators/extension_controller/templates/functional_test.rb +11 -0
- data/lib/generators/extension_controller/templates/helper.rb +2 -0
- data/lib/generators/extension_controller/templates/helper_spec.rb +11 -0
- data/lib/generators/extension_controller/templates/helper_test.rb +4 -0
- data/lib/generators/extension_controller/templates/view.html.erb +2 -0
- data/lib/generators/extension_controller/templates/view_spec.rb +12 -0
- data/lib/generators/extension_mailer/USAGE +17 -0
- data/lib/generators/extension_mailer/extension_mailer_generator.rb +68 -0
- data/lib/generators/extension_mailer/templates/fixture.erb +3 -0
- data/lib/generators/extension_mailer/templates/mailer.rb +15 -0
- data/lib/generators/extension_mailer/templates/unit_test.rb +21 -0
- data/lib/generators/extension_mailer/templates/view.erb +3 -0
- data/lib/generators/extension_migration/USAGE +34 -0
- data/lib/generators/extension_migration/extension_migration_generator.rb +25 -0
- data/lib/generators/extension_migration/templates/migration.rb +11 -0
- data/lib/generators/extension_model/USAGE +35 -0
- data/lib/generators/extension_model/extension_model_generator.rb +68 -0
- data/lib/generators/extension_model/templates/fixtures.yml +19 -0
- data/lib/generators/extension_model/templates/migration.rb +16 -0
- data/lib/generators/extension_model/templates/model.rb +2 -0
- data/lib/generators/extension_model/templates/model_spec.rb +11 -0
- data/lib/generators/extension_model/templates/unit_test.rb +8 -0
- data/lib/generators/generator_base_extension.rb +16 -0
- data/lib/generators/instance/instance_generator.rb +148 -0
- data/lib/generators/instance/templates/databases/db2.yml +40 -0
- data/lib/generators/instance/templates/databases/mysql.yml +47 -0
- data/lib/generators/instance/templates/databases/postgresql.yml +44 -0
- data/lib/generators/instance/templates/databases/sqlite3.yml +16 -0
- data/lib/generators/instance/templates/databases/sqlserver.yml +21 -0
- data/lib/generators/instance/templates/instance_boot.rb +122 -0
- data/lib/generators/instance/templates/instance_config.ru +2 -0
- data/lib/generators/instance/templates/instance_environment.rb +83 -0
- data/lib/generators/instance/templates/instance_gemfile +81 -0
- data/lib/generators/instance/templates/instance_generate +6 -0
- data/lib/generators/instance/templates/instance_radiant_config.rb +16 -0
- data/lib/generators/instance/templates/instance_rakefile +3 -0
- data/lib/generators/instance/templates/instance_routes.rb +1 -0
- data/lib/generators/language_extension/USAGE +27 -0
- data/lib/generators/language_extension/language_extension_generator.rb +71 -0
- data/lib/generators/language_extension/templates/README +3 -0
- data/lib/generators/language_extension/templates/RSpecRakefile +123 -0
- data/lib/generators/language_extension/templates/Rakefile +25 -0
- data/lib/generators/language_extension/templates/available_tags.yml +553 -0
- data/lib/generators/language_extension/templates/cucumber.yml +1 -0
- data/lib/generators/language_extension/templates/cucumber_env.rb +16 -0
- data/lib/generators/language_extension/templates/cucumber_paths.rb +14 -0
- data/lib/generators/language_extension/templates/extension.rb +12 -0
- data/lib/generators/language_extension/templates/functional_test.rb +15 -0
- data/lib/generators/language_extension/templates/gemspec.rb +24 -0
- data/lib/generators/language_extension/templates/lang.yml +181 -0
- data/lib/generators/language_extension/templates/lib.rb +8 -0
- data/lib/generators/language_extension/templates/spec.opts +6 -0
- data/lib/generators/language_extension/templates/spec_helper.rb +36 -0
- data/lib/generators/language_extension/templates/tasks.rake +28 -0
- data/lib/generators/language_extension/templates/test_helper.rb +26 -0
- data/lib/inheritable_class_attributes.rb +65 -0
- data/lib/local_time.rb +6 -0
- data/lib/login_system.rb +132 -0
- data/lib/method_observer.rb +50 -0
- data/lib/object_extensions/object_extensions.rb +5 -0
- data/lib/simpleton.rb +21 -0
- data/lib/string_extensions/string_extensions.rb +25 -0
- data/lib/symbol_extensions/symbol_extensions.rb +5 -0
- data/lib/tasks/database.rake +85 -0
- data/lib/tasks/environments.rake +11 -0
- data/lib/tasks/extensions.rake +85 -0
- data/lib/tasks/framework.rake +255 -0
- data/lib/tasks/instance.rake +23 -0
- data/lib/tasks/prototype.rake +31 -0
- data/lib/tasks/radiant_config.rake +18 -0
- data/lib/tasks/release.rake +131 -0
- data/lib/tasks/translate.rake +59 -0
- data/lib/tasks/undefine.rake +28 -0
- data/lib/translation_support.rb +54 -0
- data/lib/trusty_cms/admin_ui/region_partials.rb +23 -0
- data/lib/trusty_cms/admin_ui/region_set.rb +35 -0
- data/lib/trusty_cms/admin_ui.rb +244 -0
- data/lib/trusty_cms/available_locales.rb +19 -0
- data/lib/trusty_cms/cache.rb +100 -0
- data/lib/trusty_cms/config/definition.rb +142 -0
- data/lib/trusty_cms/engine.rb +10 -0
- data/lib/trusty_cms/extension/script.rb +395 -0
- data/lib/trusty_cms/extension.rb +146 -0
- data/lib/trusty_cms/extension_loader.rb +130 -0
- data/lib/trusty_cms/extension_migrator.rb +98 -0
- data/lib/trusty_cms/extension_path.rb +200 -0
- data/lib/trusty_cms/initializer.rb +162 -0
- data/lib/trusty_cms/pagination/controller.rb +41 -0
- data/lib/trusty_cms/pagination/link_renderer.rb +34 -0
- data/lib/trusty_cms/resource_responses.rb +121 -0
- data/lib/trusty_cms/setup.rb +227 -0
- data/lib/trusty_cms/taggable.rb +138 -0
- data/lib/trusty_cms/task_support.rb +66 -0
- data/lib/trusty_cms.rb +19 -0
- data/log/.keep +0 -0
- data/public/.htaccess +40 -0
- data/public/404.html +8 -0
- data/public/500.html +8 -0
- data/public/dispatch.cgi +10 -0
- data/public/dispatch.fcgi +24 -0
- data/public/dispatch.rb +10 -0
- data/public/favicon.ico +0 -0
- data/public/images/admin/add_tab.png +0 -0
- data/public/images/admin/avatar_32x32.png +0 -0
- data/public/images/admin/avatar_64x64.png +0 -0
- data/public/images/admin/avatar_96x96.png +0 -0
- data/public/images/admin/brown_bottom_line.gif +0 -0
- data/public/images/admin/calendar_down.gif +0 -0
- data/public/images/admin/collapse.png +0 -0
- data/public/images/admin/draft_page.png +0 -0
- data/public/images/admin/expand.png +0 -0
- data/public/images/admin/image.png +0 -0
- data/public/images/admin/javascript.png +0 -0
- data/public/images/admin/layout.png +0 -0
- data/public/images/admin/metadata_toggle.png +0 -0
- data/public/images/admin/minus.png +0 -0
- data/public/images/admin/minus_disabled.png +0 -0
- data/public/images/admin/minus_grey.png +0 -0
- data/public/images/admin/navigation_secondary_separator.gif +0 -0
- data/public/images/admin/page.png +0 -0
- data/public/images/admin/plus.png +0 -0
- data/public/images/admin/plus_disabled.png +0 -0
- data/public/images/admin/plus_grey.png +0 -0
- data/public/images/admin/popup_border_background.png +0 -0
- data/public/images/admin/popup_border_bottom_left.png +0 -0
- data/public/images/admin/popup_border_bottom_right.png +0 -0
- data/public/images/admin/popup_border_top_left.png +0 -0
- data/public/images/admin/popup_border_top_right.png +0 -0
- data/public/images/admin/search.png +0 -0
- data/public/images/admin/single_form_shadow.png +0 -0
- data/public/images/admin/snippet.png +0 -0
- data/public/images/admin/spinner.gif +0 -0
- data/public/images/admin/status_background.png +0 -0
- data/public/images/admin/status_bottom_left.png +0 -0
- data/public/images/admin/status_bottom_right.png +0 -0
- data/public/images/admin/status_spinner.gif +0 -0
- data/public/images/admin/status_top_left.png +0 -0
- data/public/images/admin/status_top_right.png +0 -0
- data/public/images/admin/stylesheet.png +0 -0
- data/public/images/admin/tab_close.png +0 -0
- data/public/images/admin/upload.png +0 -0
- data/public/images/admin/virtual_page.png +0 -0
- data/public/images/radiant/radiant-badge-color.png +0 -0
- data/public/javascripts/admin/application.js +94 -0
- data/public/javascripts/admin/codearea.js +165 -0
- data/public/javascripts/admin/controls.js +965 -0
- data/public/javascripts/admin/cookie.js +80 -0
- data/public/javascripts/admin/dateinput.js +402 -0
- data/public/javascripts/admin/dragdrop.js +974 -0
- data/public/javascripts/admin/dropdown.js +216 -0
- data/public/javascripts/admin/effects.js +1122 -0
- data/public/javascripts/admin/lowpro.js +340 -0
- data/public/javascripts/admin/overrides.js +1 -0
- data/public/javascripts/admin/page_preview.js +41 -0
- data/public/javascripts/admin/pagefield.js +54 -0
- data/public/javascripts/admin/pagestatus.js +17 -0
- data/public/javascripts/admin/popup.js +339 -0
- data/public/javascripts/admin/prototype.js +4874 -0
- data/public/javascripts/admin/ruledtable.js +13 -0
- data/public/javascripts/admin/shortcuts.js +33 -0
- data/public/javascripts/admin/sitemap.js +149 -0
- data/public/javascripts/admin/status.js +233 -0
- data/public/javascripts/admin/tabcontrol.js +123 -0
- data/public/javascripts/admin/toggle.js +430 -0
- data/public/javascripts/admin/utility.js +53 -0
- data/public/javascripts/admin/validationerror.js +18 -0
- data/public/loading-iframe.html +11 -0
- data/public/robots.txt +1 -0
- data/public/stylesheets/sass/admin/_base.sass +18 -0
- data/public/stylesheets/sass/admin/main.sass +27 -0
- data/public/stylesheets/sass/admin/modules/_boxes.sass +6 -0
- data/public/stylesheets/sass/admin/modules/_gradients.sass +4 -0
- data/public/stylesheets/sass/admin/modules/_links.sass +18 -0
- data/public/stylesheets/sass/admin/overrides.sass +2 -0
- data/public/stylesheets/sass/admin/partials/_actions.sass +96 -0
- data/public/stylesheets/sass/admin/partials/_avatars.sass +10 -0
- data/public/stylesheets/sass/admin/partials/_content.sass +58 -0
- data/public/stylesheets/sass/admin/partials/_dateinput.sass +62 -0
- data/public/stylesheets/sass/admin/partials/_deprecated.sass +55 -0
- data/public/stylesheets/sass/admin/partials/_dropdown.sass +28 -0
- data/public/stylesheets/sass/admin/partials/_footer.sass +12 -0
- data/public/stylesheets/sass/admin/partials/_forms.sass +322 -0
- data/public/stylesheets/sass/admin/partials/_header.sass +114 -0
- data/public/stylesheets/sass/admin/partials/_index.sass +147 -0
- data/public/stylesheets/sass/admin/partials/_layout.sass +10 -0
- data/public/stylesheets/sass/admin/partials/_messages.sass +10 -0
- data/public/stylesheets/sass/admin/partials/_popup.sass +213 -0
- data/public/stylesheets/sass/admin/partials/_tabcontrol.sass +72 -0
- data/public/stylesheets/sass/admin/partials/_toolbar.sass +31 -0
- data/public/stylesheets/sass/admin/partials/_typography.sass +60 -0
- data/public/stylesheets/sass/admin/partials/_validations.sass +19 -0
- data/rails/init.rb +1 -0
- data/script/about +4 -0
- data/script/breakpointer +3 -0
- data/script/console +3 -0
- data/script/dbconsole +3 -0
- data/script/destroy +3 -0
- data/script/extension +5 -0
- data/script/generate +3 -0
- data/script/performance/benchmarker +3 -0
- data/script/performance/profiler +3 -0
- data/script/performance/request +3 -0
- data/script/plugin +3 -0
- data/script/process/inspector +3 -0
- data/script/process/reaper +3 -0
- data/script/process/spawner +3 -0
- data/script/process/spinner +3 -0
- data/script/rails +6 -0
- data/script/runner +3 -0
- data/script/server +3 -0
- data/script/version +5 -0
- data/spec/ci/database.mysql.yml +4 -0
- data/spec/ci/database.postgresql.yml +4 -0
- data/spec/ci/database.sqlite.yml +3 -0
- data/trusty_cms.gemspec +50 -0
- metadata +781 -0
|
@@ -0,0 +1,1318 @@
|
|
|
1
|
+
require 'trusty_cms/taggable'
|
|
2
|
+
require 'local_time'
|
|
3
|
+
module StandardTags
|
|
4
|
+
|
|
5
|
+
include TrustyCms::Taggable
|
|
6
|
+
include LocalTime
|
|
7
|
+
|
|
8
|
+
require "will_paginate/view_helpers"
|
|
9
|
+
include WillPaginate::ViewHelpers
|
|
10
|
+
|
|
11
|
+
class TagError < StandardError; end
|
|
12
|
+
class RequiredAttributeError < StandardError; end
|
|
13
|
+
|
|
14
|
+
desc %{
|
|
15
|
+
Causes the tags referring to a page's attributes to refer to the current page.
|
|
16
|
+
|
|
17
|
+
*Usage:*
|
|
18
|
+
|
|
19
|
+
<pre><code><r:page>...</r:page></code></pre>
|
|
20
|
+
}
|
|
21
|
+
tag 'page' do |tag|
|
|
22
|
+
tag.locals.page = tag.globals.page
|
|
23
|
+
tag.expand
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
[:breadcrumb, :slug, :title].each do |method|
|
|
27
|
+
desc %{
|
|
28
|
+
Renders the @#{method}@ attribute of the current page.
|
|
29
|
+
}
|
|
30
|
+
tag method.to_s do |tag|
|
|
31
|
+
tag.locals.page.send(method)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
desc %{
|
|
36
|
+
Renders the @path@ attribute of the current page.
|
|
37
|
+
}
|
|
38
|
+
tag 'path' do |tag|
|
|
39
|
+
relative_url_for(tag.locals.page.path, tag.globals.page.request)
|
|
40
|
+
end
|
|
41
|
+
deprecated_tag 'url', :substitute => 'path', :deadline => '1.2'
|
|
42
|
+
|
|
43
|
+
desc %{
|
|
44
|
+
Gives access to a page's children.
|
|
45
|
+
|
|
46
|
+
*Usage:*
|
|
47
|
+
|
|
48
|
+
<pre><code><r:children>...</r:children></code></pre>
|
|
49
|
+
}
|
|
50
|
+
tag 'children' do |tag|
|
|
51
|
+
tag.locals.children = tag.locals.page.children
|
|
52
|
+
tag.expand
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
desc %{
|
|
56
|
+
Renders the total number of children.
|
|
57
|
+
}
|
|
58
|
+
tag 'children:count' do |tag|
|
|
59
|
+
options = children_find_options(tag)
|
|
60
|
+
options.delete(:order) # Order is irrelevant
|
|
61
|
+
tag.locals.children.count(options)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
desc %{
|
|
65
|
+
Returns the first child. Inside this tag all page attribute tags are mapped to
|
|
66
|
+
the first child. Takes the same ordering options as @<r:children:each>@.
|
|
67
|
+
|
|
68
|
+
*Usage:*
|
|
69
|
+
|
|
70
|
+
<pre><code><r:children:first>...</r:children:first></code></pre>
|
|
71
|
+
}
|
|
72
|
+
tag 'children:first' do |tag|
|
|
73
|
+
options = children_find_options(tag)
|
|
74
|
+
children = tag.locals.children.where(options)
|
|
75
|
+
if first = children.first
|
|
76
|
+
tag.locals.page = first
|
|
77
|
+
tag.expand
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
desc %{
|
|
82
|
+
Returns the last child. Inside this tag all page attribute tags are mapped to
|
|
83
|
+
the last child. Takes the same ordering options as @<r:children:each>@.
|
|
84
|
+
|
|
85
|
+
*Usage:*
|
|
86
|
+
|
|
87
|
+
<pre><code><r:children:last>...</r:children:last></code></pre>
|
|
88
|
+
}
|
|
89
|
+
tag 'children:last' do |tag|
|
|
90
|
+
options = children_find_options(tag)
|
|
91
|
+
children = tag.locals.children.where(options)
|
|
92
|
+
if last = children.last
|
|
93
|
+
tag.locals.page = last
|
|
94
|
+
tag.expand
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
desc %{
|
|
99
|
+
Cycles through each of the children. Inside this tag all page attribute tags
|
|
100
|
+
are mapped to the current child page.
|
|
101
|
+
|
|
102
|
+
Supply @paginated="true"@ to paginate the displayed list. will_paginate view helper
|
|
103
|
+
options can also be specified, including @per_page@, @previous_label@, @next_label@,
|
|
104
|
+
@class@, @separator@, @inner_window@ and @outer_window@.
|
|
105
|
+
|
|
106
|
+
*Usage:*
|
|
107
|
+
|
|
108
|
+
<pre><code><r:children:each [offset="number"] [limit="number"]
|
|
109
|
+
[by="published_at|updated_at|created_at|slug|title|keywords|description"]
|
|
110
|
+
[order="asc|desc"]
|
|
111
|
+
[status="draft|reviewed|published|hidden|all"]
|
|
112
|
+
[paginated="true"]
|
|
113
|
+
[per_page="number"]
|
|
114
|
+
>
|
|
115
|
+
...
|
|
116
|
+
</r:children:each>
|
|
117
|
+
</code></pre>
|
|
118
|
+
}
|
|
119
|
+
tag 'children:each' do |tag|
|
|
120
|
+
render_children_with_pagination(tag)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
desc %{
|
|
124
|
+
The pagination tag is not usually called directly. Supply paginated="true" when you display a list and it will
|
|
125
|
+
be automatically display only the current page of results, with pagination controls at the bottom.
|
|
126
|
+
|
|
127
|
+
*Usage:*
|
|
128
|
+
|
|
129
|
+
<pre><code><r:children:each paginated="true" per_page="50" container="false" previous_label="foo" next_label="bar">
|
|
130
|
+
<r:child>...</r:child>
|
|
131
|
+
</r:children:each>
|
|
132
|
+
</code></pre>
|
|
133
|
+
}
|
|
134
|
+
tag 'pagination' do |tag|
|
|
135
|
+
if tag.locals.paginated_list
|
|
136
|
+
will_paginate(tag.locals.paginated_list, will_paginate_options(tag))
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
desc %{
|
|
141
|
+
Page attribute tags inside of this tag refer to the current child. This is occasionally
|
|
142
|
+
useful if you are inside of another tag (like <r:find>) and need to refer back to the
|
|
143
|
+
current child.
|
|
144
|
+
|
|
145
|
+
*Usage:*
|
|
146
|
+
|
|
147
|
+
<pre><code><r:children:each>
|
|
148
|
+
<r:child>...</r:child>
|
|
149
|
+
</r:children:each>
|
|
150
|
+
</code></pre>
|
|
151
|
+
}
|
|
152
|
+
tag 'children:each:child' do |tag|
|
|
153
|
+
tag.locals.page = tag.locals.child
|
|
154
|
+
tag.expand
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
desc %{
|
|
158
|
+
Renders the tag contents only if the current page is the first child in the context of
|
|
159
|
+
a children:each tag
|
|
160
|
+
|
|
161
|
+
*Usage:*
|
|
162
|
+
|
|
163
|
+
<pre><code><r:children:each>
|
|
164
|
+
<r:if_first >
|
|
165
|
+
...
|
|
166
|
+
</r:if_first>
|
|
167
|
+
</r:children:each>
|
|
168
|
+
</code></pre>
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
tag 'children:each:if_first' do |tag|
|
|
172
|
+
tag.expand if tag.locals.first_child
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
desc %{
|
|
177
|
+
Renders the tag contents unless the current page is the first child in the context of
|
|
178
|
+
a children:each tag
|
|
179
|
+
|
|
180
|
+
*Usage:*
|
|
181
|
+
|
|
182
|
+
<pre><code><r:children:each>
|
|
183
|
+
<r:unless_first >
|
|
184
|
+
...
|
|
185
|
+
</r:unless_first>
|
|
186
|
+
</r:children:each>
|
|
187
|
+
</code></pre>
|
|
188
|
+
|
|
189
|
+
}
|
|
190
|
+
tag 'children:each:unless_first' do |tag|
|
|
191
|
+
tag.expand unless tag.locals.first_child
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
desc %{
|
|
195
|
+
Renders the tag contents only if the current page is the last child in the context of
|
|
196
|
+
a children:each tag
|
|
197
|
+
|
|
198
|
+
*Usage:*
|
|
199
|
+
|
|
200
|
+
<pre><code><r:children:each>
|
|
201
|
+
<r:if_last >
|
|
202
|
+
...
|
|
203
|
+
</r:if_last>
|
|
204
|
+
</r:children:each>
|
|
205
|
+
</code></pre>
|
|
206
|
+
|
|
207
|
+
}
|
|
208
|
+
tag 'children:each:if_last' do |tag|
|
|
209
|
+
tag.expand if tag.locals.last_child
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
desc %{
|
|
214
|
+
Renders the tag contents unless the current page is the last child in the context of
|
|
215
|
+
a children:each tag
|
|
216
|
+
|
|
217
|
+
*Usage:*
|
|
218
|
+
|
|
219
|
+
<pre><code><r:children:each>
|
|
220
|
+
<r:unless_last >
|
|
221
|
+
...
|
|
222
|
+
</r:unless_last>
|
|
223
|
+
</r:children:each>
|
|
224
|
+
</code></pre>
|
|
225
|
+
|
|
226
|
+
}
|
|
227
|
+
tag 'children:each:unless_last' do |tag|
|
|
228
|
+
tag.expand unless tag.locals.last_child
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
desc %{
|
|
232
|
+
Renders the tag contents only if the contents do not match the previous header. This
|
|
233
|
+
is extremely useful for rendering date headers for a list of child pages.
|
|
234
|
+
|
|
235
|
+
If you would like to use several header blocks you may use the @name@ attribute to
|
|
236
|
+
name the header. When a header is named it will not restart until another header of
|
|
237
|
+
the same name is different.
|
|
238
|
+
|
|
239
|
+
Using the @restart@ attribute you can cause other named headers to restart when the
|
|
240
|
+
present header changes. Simply specify the names of the other headers in a semicolon
|
|
241
|
+
separated list.
|
|
242
|
+
|
|
243
|
+
*Usage:*
|
|
244
|
+
|
|
245
|
+
<pre><code><r:children:each>
|
|
246
|
+
<r:header [name="header_name"] [restart="name1[;name2;...]"]>
|
|
247
|
+
...
|
|
248
|
+
</r:header>
|
|
249
|
+
</r:children:each>
|
|
250
|
+
</code></pre>
|
|
251
|
+
}
|
|
252
|
+
tag 'children:each:header' do |tag|
|
|
253
|
+
previous_headers = tag.locals.previous_headers
|
|
254
|
+
name = tag.attr['name'] || :unnamed
|
|
255
|
+
restart = (tag.attr['restart'] || '').split(';')
|
|
256
|
+
header = tag.expand
|
|
257
|
+
unless header == previous_headers[name]
|
|
258
|
+
previous_headers[name] = header
|
|
259
|
+
unless restart.empty?
|
|
260
|
+
restart.each do |n|
|
|
261
|
+
previous_headers[n] = nil
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
header
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
desc %{
|
|
269
|
+
Page attribute tags inside this tag refer to the parent of the current page.
|
|
270
|
+
|
|
271
|
+
*Usage:*
|
|
272
|
+
|
|
273
|
+
<pre><code><r:parent>...</r:parent></code></pre>
|
|
274
|
+
}
|
|
275
|
+
tag "parent" do |tag|
|
|
276
|
+
parent = tag.locals.page.parent
|
|
277
|
+
tag.locals.page = parent
|
|
278
|
+
tag.expand if parent
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
desc %{
|
|
282
|
+
Renders the contained elements only if the current contextual page has a parent, i.e.
|
|
283
|
+
is not the root page.
|
|
284
|
+
|
|
285
|
+
*Usage:*
|
|
286
|
+
|
|
287
|
+
<pre><code><r:if_parent>...</r:if_parent></code></pre>
|
|
288
|
+
}
|
|
289
|
+
tag "if_parent" do |tag|
|
|
290
|
+
parent = tag.locals.page.parent
|
|
291
|
+
tag.expand if parent
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
desc %{
|
|
295
|
+
Renders the contained elements only if the current contextual page has no parent, i.e.
|
|
296
|
+
is the root page.
|
|
297
|
+
|
|
298
|
+
*Usage:*
|
|
299
|
+
|
|
300
|
+
<pre><code><r:unless_parent>...</r:unless_parent></code></pre>
|
|
301
|
+
}
|
|
302
|
+
tag "unless_parent" do |tag|
|
|
303
|
+
parent = tag.locals.page.parent
|
|
304
|
+
tag.expand unless parent
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
desc %{
|
|
308
|
+
Renders the contained elements only if the current contextual page has one or
|
|
309
|
+
more child pages. The @status@ attribute limits the status of found child pages
|
|
310
|
+
to the given status, the default is @"published"@. @status="all"@ includes all
|
|
311
|
+
non-virtual pages regardless of status.
|
|
312
|
+
|
|
313
|
+
*Usage:*
|
|
314
|
+
|
|
315
|
+
<pre><code><r:if_children [status="published"]>...</r:if_children></code></pre>
|
|
316
|
+
}
|
|
317
|
+
tag "if_children" do |tag|
|
|
318
|
+
children = tag.locals.page.children.where(children_find_options(tag)[:conditions]).count
|
|
319
|
+
tag.expand if children > 0
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
desc %{
|
|
323
|
+
Renders the contained elements only if the current contextual page has no children.
|
|
324
|
+
The @status@ attribute limits the status of found child pages to the given status,
|
|
325
|
+
the default is @"published"@. @status="all"@ includes all non-virtual pages
|
|
326
|
+
regardless of status.
|
|
327
|
+
|
|
328
|
+
*Usage:*
|
|
329
|
+
|
|
330
|
+
<pre><code><r:unless_children [status="published"]>...</r:unless_children></code></pre>
|
|
331
|
+
}
|
|
332
|
+
tag "unless_children" do |tag|
|
|
333
|
+
children = tag.locals.page.children.where(children_find_options(tag)[:conditions]).count
|
|
334
|
+
tag.expand unless children > 0
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
desc %{
|
|
338
|
+
Aggregates the children of multiple paths using the @paths@ attribute.
|
|
339
|
+
Useful for combining many different sections/categories into a single
|
|
340
|
+
feed or listing.
|
|
341
|
+
|
|
342
|
+
*Usage*:
|
|
343
|
+
|
|
344
|
+
<pre><code><r:aggregate paths="/section1; /section2; /section3"> ... </r:aggregate></code></pre>
|
|
345
|
+
}
|
|
346
|
+
tag "aggregate" do |tag|
|
|
347
|
+
required_attr(tag, 'paths', 'urls')
|
|
348
|
+
paths = (tag.attr['paths']||tag.attr["urls"]).split(";").map(&:strip).reject(&:blank?).map { |u| clean_path u }
|
|
349
|
+
parent_ids = paths.map {|u| Page.find_by_path(u) }.map(&:id)
|
|
350
|
+
tag.locals.parent_ids = parent_ids
|
|
351
|
+
tag.expand
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
desc %{
|
|
355
|
+
Sets the scope to the individual aggregated page allowing you to
|
|
356
|
+
iterate through each of the listed paths.
|
|
357
|
+
|
|
358
|
+
*Usage*:
|
|
359
|
+
|
|
360
|
+
<pre><code><r:aggregate:each paths="/section1; /section2; /section3"> ... </r:aggregate:each></code></pre>
|
|
361
|
+
}
|
|
362
|
+
tag "aggregate:each" do |tag|
|
|
363
|
+
aggregates = []
|
|
364
|
+
tag.locals.aggregated_pages = tag.locals.parent_ids.map {|p| Page.find(p)}
|
|
365
|
+
tag.locals.aggregated_pages.each do |aggregate_page|
|
|
366
|
+
tag.locals.page = aggregate_page
|
|
367
|
+
aggregates << tag.expand
|
|
368
|
+
end
|
|
369
|
+
aggregates.flatten.join('')
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
tag "aggregate:each:children" do |tag|
|
|
373
|
+
tag.locals.children = tag.locals.page.children
|
|
374
|
+
tag.expand
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
tag "aggregate:each:children:each" do |tag|
|
|
378
|
+
options = children_find_options(tag)
|
|
379
|
+
result = []
|
|
380
|
+
children = tag.locals.children
|
|
381
|
+
tag.locals.previous_headers = {}
|
|
382
|
+
children.where(options).each do |item|
|
|
383
|
+
tag.locals.child = item
|
|
384
|
+
tag.locals.page = item
|
|
385
|
+
result << tag.expand
|
|
386
|
+
end
|
|
387
|
+
result.flatten.join('')
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
tag "aggregate:children" do |tag|
|
|
391
|
+
tag.expand
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
desc %{
|
|
395
|
+
Renders the total count of children of the aggregated pages. Accepts the
|
|
396
|
+
same options as @<r:children:each />@.
|
|
397
|
+
|
|
398
|
+
*Usage*:
|
|
399
|
+
|
|
400
|
+
<pre><code><r:aggregate paths="/section1; /section2; /section3">
|
|
401
|
+
<r:children:count />
|
|
402
|
+
</r:aggregate></code></pre>
|
|
403
|
+
}
|
|
404
|
+
tag "aggregate:children:count" do |tag|
|
|
405
|
+
options = aggregate_children(tag)
|
|
406
|
+
if ActiveRecord::Base.connection.adapter_name.downcase == 'postgresql'
|
|
407
|
+
options[:group] = Page.columns.map {|c| c.name}.join(', ')
|
|
408
|
+
Page.where(options).size
|
|
409
|
+
else
|
|
410
|
+
Page.where(options).count
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
desc %{
|
|
414
|
+
Renders the contained block for each child of the aggregated pages. Accepts the
|
|
415
|
+
same options as the plain @<r:children:each />@.
|
|
416
|
+
|
|
417
|
+
*Usage*:
|
|
418
|
+
|
|
419
|
+
<pre><code><r:aggregate paths="/section1; /section2; /section3">
|
|
420
|
+
<r:children:each>
|
|
421
|
+
...
|
|
422
|
+
</r:children:each>
|
|
423
|
+
</r:aggregate></code></pre>
|
|
424
|
+
}
|
|
425
|
+
tag "aggregate:children:each" do |tag|
|
|
426
|
+
render_children_with_pagination(tag, :aggregate => true)
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
desc %{
|
|
430
|
+
Renders the first child of the aggregated pages. Accepts the
|
|
431
|
+
same options as @<r:children:each />@.
|
|
432
|
+
|
|
433
|
+
*Usage*:
|
|
434
|
+
|
|
435
|
+
<pre><code><r:aggregate paths="/section1; /section2; /section3">
|
|
436
|
+
<r:children:first>
|
|
437
|
+
...
|
|
438
|
+
</r:children:first>
|
|
439
|
+
</r:aggregate></code></pre>
|
|
440
|
+
}
|
|
441
|
+
tag "aggregate:children:first" do |tag|
|
|
442
|
+
options = aggregate_children(tag)
|
|
443
|
+
children = Page.where(options)
|
|
444
|
+
|
|
445
|
+
# TODO: What is this nonsnese?
|
|
446
|
+
if first = children.first
|
|
447
|
+
tag.locals.page = first
|
|
448
|
+
tag.expand
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
desc %{
|
|
453
|
+
Renders the last child of the aggregated pages. Accepts the
|
|
454
|
+
same options as @<r:children:each />@.
|
|
455
|
+
|
|
456
|
+
*Usage*:
|
|
457
|
+
|
|
458
|
+
<pre><code><r:aggregate paths="/section1; /section2; /section3">
|
|
459
|
+
<r:children:last>
|
|
460
|
+
...
|
|
461
|
+
</r:children:last>
|
|
462
|
+
</r:aggregate></code></pre>
|
|
463
|
+
}
|
|
464
|
+
tag "aggregate:children:last" do |tag|
|
|
465
|
+
options = aggregate_children(tag)
|
|
466
|
+
children = Page.where(options)
|
|
467
|
+
|
|
468
|
+
# TODO: More nonsense
|
|
469
|
+
if last = children.last
|
|
470
|
+
tag.locals.page = last
|
|
471
|
+
tag.expand
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
desc %{
|
|
476
|
+
Renders a counter value or one of the values given based on a global cycle counter.
|
|
477
|
+
|
|
478
|
+
To get a numeric counter just use the tag, or specify a start value with @start@.
|
|
479
|
+
Use the @reset@ attribute to reset the cycle to the beginning. Using @reset@ on a
|
|
480
|
+
numbered cycle will begin at 0. Use the @name@ attribute to track multiple cycles;
|
|
481
|
+
the default is @cycle@.
|
|
482
|
+
|
|
483
|
+
*Usage:*
|
|
484
|
+
|
|
485
|
+
<pre><code><r:cycle [values="first, second, third"] [reset="true|false"] [name="cycle"] [start="second"] /></code></pre>
|
|
486
|
+
<pre><code><r:cycle start="3" /></code></pre>
|
|
487
|
+
}
|
|
488
|
+
tag 'cycle' do |tag|
|
|
489
|
+
cycle = (tag.globals.cycle ||= {})
|
|
490
|
+
if tag.attr['values']
|
|
491
|
+
values = tag.attr['values'].split(",").collect(&:strip)
|
|
492
|
+
end
|
|
493
|
+
start = tag.attr['start']
|
|
494
|
+
cycle_name = tag.attr['name'] || 'cycle'
|
|
495
|
+
if values
|
|
496
|
+
if start
|
|
497
|
+
current_index = (cycle[cycle_name] ||= values.index(start))
|
|
498
|
+
else
|
|
499
|
+
current_index = (cycle[cycle_name] ||= 0)
|
|
500
|
+
end
|
|
501
|
+
current_index = 0 if tag.attr['reset'] == 'true'
|
|
502
|
+
cycle[cycle_name] = (current_index + 1) % values.size
|
|
503
|
+
values[current_index]
|
|
504
|
+
else
|
|
505
|
+
cycle[cycle_name] ||= (start.presence || 0).to_i
|
|
506
|
+
output = cycle[cycle_name]
|
|
507
|
+
cycle[cycle_name] += 1
|
|
508
|
+
if tag.attr['reset'] == 'true'
|
|
509
|
+
cycle[cycle_name] = 0
|
|
510
|
+
output = cycle[cycle_name]
|
|
511
|
+
end
|
|
512
|
+
output
|
|
513
|
+
end
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
desc %{
|
|
517
|
+
Renders the main content of a page. Use the @part@ attribute to select a specific
|
|
518
|
+
page part. By default the @part@ attribute is set to body. Use the @inherit@
|
|
519
|
+
attribute to specify that if a page does not have a content part by that name that
|
|
520
|
+
the tag should render the parent's content part. By default @inherit@ is set to
|
|
521
|
+
@false@. Use the @contextual@ attribute to force a part inherited from a parent
|
|
522
|
+
part to be evaluated in the context of the child page. By default 'contextual'
|
|
523
|
+
is set to true.
|
|
524
|
+
|
|
525
|
+
*Usage:*
|
|
526
|
+
|
|
527
|
+
<pre><code><r:content [part="part_name"] [inherit="true|false"] [contextual="true|false"] /></code></pre>
|
|
528
|
+
}
|
|
529
|
+
tag 'content' do |tag|
|
|
530
|
+
page = tag.locals.page
|
|
531
|
+
part_name = tag_part_name(tag)
|
|
532
|
+
# Prevent simple and deep recursive rendering of the same page part
|
|
533
|
+
rendering_parts = (tag.locals.rendering_parts ||= Hash.new {|h,k| h[k] = []})
|
|
534
|
+
if rendering_parts[page.id].include?(part_name)
|
|
535
|
+
raise TagError.new(%{Recursion error: already rendering the `#{part_name}' part.})
|
|
536
|
+
else
|
|
537
|
+
rendering_parts[page.id] << part_name
|
|
538
|
+
end
|
|
539
|
+
inherit = boolean_attr_or_error(tag,'inherit',false)
|
|
540
|
+
part_page = page
|
|
541
|
+
if inherit
|
|
542
|
+
while (part_page.part(part_name).nil? and (not part_page.parent.nil?)) do
|
|
543
|
+
part_page = part_page.parent
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
contextual = boolean_attr_or_error(tag,'contextual', true)
|
|
547
|
+
part = part_page.part(part_name)
|
|
548
|
+
tag.locals.page = part_page unless contextual
|
|
549
|
+
result = tag.globals.page.render_snippet(part) unless part.nil?
|
|
550
|
+
rendering_parts[page.id].delete(part_name)
|
|
551
|
+
result
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
desc %{
|
|
555
|
+
Renders the containing elements if all of the listed parts exist on a page.
|
|
556
|
+
By default the @part@ attribute is set to @body@, but you may list more than one
|
|
557
|
+
part by separating them with a comma. Setting the optional @inherit@ to true will
|
|
558
|
+
search ancestors independently for each part. By default @inherit@ is set to @false@.
|
|
559
|
+
|
|
560
|
+
When listing more than one part, you may optionally set the @find@ attribute to @any@
|
|
561
|
+
so that it will render the containing elements if any of the listed parts are found.
|
|
562
|
+
By default the @find@ attribute is set to @all@.
|
|
563
|
+
|
|
564
|
+
*Usage:*
|
|
565
|
+
|
|
566
|
+
<pre><code><r:if_content [part="part_name, other_part"] [inherit="true"] [find="any"]>...</r:if_content></code></pre>
|
|
567
|
+
}
|
|
568
|
+
tag 'if_content' do |tag|
|
|
569
|
+
part_name = tag_part_name(tag)
|
|
570
|
+
parts_arr = part_name.split(',')
|
|
571
|
+
inherit = boolean_attr_or_error(tag, 'inherit', 'false')
|
|
572
|
+
find = attr_or_error(tag, :attribute_name => 'find', :default => 'all', :values => 'any, all')
|
|
573
|
+
expandable = true
|
|
574
|
+
one_found = false
|
|
575
|
+
parts_arr.each do |name|
|
|
576
|
+
part_page = tag.locals.page
|
|
577
|
+
name.strip!
|
|
578
|
+
if inherit
|
|
579
|
+
while (part_page.part(name).nil? and (not part_page.parent.nil?)) do
|
|
580
|
+
part_page = part_page.parent
|
|
581
|
+
end
|
|
582
|
+
end
|
|
583
|
+
expandable = false if part_page.part(name).nil?
|
|
584
|
+
one_found ||= true if !part_page.part(name).nil?
|
|
585
|
+
end
|
|
586
|
+
expandable = true if (find == 'any' and one_found)
|
|
587
|
+
tag.expand if expandable
|
|
588
|
+
end
|
|
589
|
+
|
|
590
|
+
desc %{
|
|
591
|
+
The opposite of the @if_content@ tag. It renders the contained elements if all of the
|
|
592
|
+
specified parts do not exist. Setting the optional @inherit@ to true will search
|
|
593
|
+
ancestors independently for each part. By default @inherit@ is set to @false@.
|
|
594
|
+
|
|
595
|
+
When listing more than one part, you may optionally set the @find@ attribute to @any@
|
|
596
|
+
so that it will not render the containing elements if any of the listed parts are found.
|
|
597
|
+
By default the @find@ attribute is set to @all@.
|
|
598
|
+
|
|
599
|
+
*Usage:*
|
|
600
|
+
|
|
601
|
+
<pre><code><r:unless_content [part="part_name, other_part"] [inherit="false"] [find="any"]>...</r:unless_content></code></pre>
|
|
602
|
+
}
|
|
603
|
+
tag 'unless_content' do |tag|
|
|
604
|
+
part_name = tag_part_name(tag)
|
|
605
|
+
parts_arr = part_name.split(',')
|
|
606
|
+
inherit = boolean_attr_or_error(tag, 'inherit', false)
|
|
607
|
+
find = attr_or_error(tag, :attribute_name => 'find', :default => 'all', :values => 'any, all')
|
|
608
|
+
expandable, all_found = true, true
|
|
609
|
+
parts_arr.each do |name|
|
|
610
|
+
part_page = tag.locals.page
|
|
611
|
+
name.strip!
|
|
612
|
+
if inherit
|
|
613
|
+
while (part_page.part(name).nil? and (not part_page.parent.nil?)) do
|
|
614
|
+
part_page = part_page.parent
|
|
615
|
+
end
|
|
616
|
+
end
|
|
617
|
+
expandable = false if !part_page.part(name).nil?
|
|
618
|
+
all_found = false if part_page.part(name).nil?
|
|
619
|
+
end
|
|
620
|
+
if all_found == false and find == 'all'
|
|
621
|
+
expandable = true
|
|
622
|
+
end
|
|
623
|
+
tag.expand if expandable
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
desc %{
|
|
627
|
+
Renders the containing elements only if the page's path matches the regular expression
|
|
628
|
+
given in the @matches@ attribute. If the @ignore_case@ attribute is set to false, the
|
|
629
|
+
match is case sensitive. By default, @ignore_case@ is set to true.
|
|
630
|
+
|
|
631
|
+
*Usage:*
|
|
632
|
+
|
|
633
|
+
<pre><code><r:if_path matches="regexp" [ignore_case="true|false"]>...</r:if_path></code></pre>
|
|
634
|
+
}
|
|
635
|
+
tag 'if_path' do |tag|
|
|
636
|
+
required_attr(tag,'matches')
|
|
637
|
+
regexp = build_regexp_for(tag, 'matches')
|
|
638
|
+
unless tag.locals.page.path.match(regexp).nil?
|
|
639
|
+
tag.expand
|
|
640
|
+
end
|
|
641
|
+
end
|
|
642
|
+
deprecated_tag 'if_url', :substitute => 'if_path', :deadline => '1.2'
|
|
643
|
+
|
|
644
|
+
desc %{
|
|
645
|
+
The opposite of the @if_path@ tag.
|
|
646
|
+
|
|
647
|
+
*Usage:*
|
|
648
|
+
|
|
649
|
+
<pre><code><r:unless_path matches="regexp" [ignore_case="true|false"]>...</r:unless_path></code></pre>
|
|
650
|
+
}
|
|
651
|
+
tag 'unless_path' do |tag|
|
|
652
|
+
required_attr(tag, 'matches')
|
|
653
|
+
regexp = build_regexp_for(tag, 'matches')
|
|
654
|
+
if tag.locals.page.path.match(regexp).nil?
|
|
655
|
+
tag.expand
|
|
656
|
+
end
|
|
657
|
+
end
|
|
658
|
+
deprecated_tag 'unless_url', :substitute => 'unless_path', :deadline => '1.2'
|
|
659
|
+
|
|
660
|
+
desc %{
|
|
661
|
+
Renders the contained elements if the current contextual page is either the actual page or one of its parents.
|
|
662
|
+
|
|
663
|
+
This is typically used inside another tag (like <r:children:each>) to add conditional mark-up if the child element is or descends from the current page.
|
|
664
|
+
|
|
665
|
+
*Usage:*
|
|
666
|
+
|
|
667
|
+
<pre><code><r:if_ancestor_or_self>...</r:if_ancestor_or_self></code></pre>
|
|
668
|
+
}
|
|
669
|
+
tag "if_ancestor_or_self" do |tag|
|
|
670
|
+
tag.expand if (tag.globals.page.ancestors + [tag.globals.page]).include?(tag.locals.page)
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
desc %{
|
|
674
|
+
Renders the contained elements unless the current contextual page is either the actual page or one of its parents.
|
|
675
|
+
|
|
676
|
+
This is typically used inside another tag (like <r:children:each>) to add conditional mark-up unless the child element is or descends from the current page.
|
|
677
|
+
|
|
678
|
+
*Usage:*
|
|
679
|
+
|
|
680
|
+
<pre><code><r:unless_ancestor_or_self>...</r:unless_ancestor_or_self></code></pre>
|
|
681
|
+
}
|
|
682
|
+
tag "unless_ancestor_or_self" do |tag|
|
|
683
|
+
tag.expand unless (tag.globals.page.ancestors + [tag.globals.page]).include?(tag.locals.page)
|
|
684
|
+
end
|
|
685
|
+
|
|
686
|
+
desc %{
|
|
687
|
+
Renders the contained elements if the current contextual page is also the actual page.
|
|
688
|
+
|
|
689
|
+
This is typically used inside another tag (like <r:children:each>) to add conditional mark-up if the child element is the current page.
|
|
690
|
+
|
|
691
|
+
*Usage:*
|
|
692
|
+
|
|
693
|
+
<pre><code><r:if_self>...</r:if_self></code></pre>
|
|
694
|
+
}
|
|
695
|
+
tag "if_self" do |tag|
|
|
696
|
+
tag.expand if tag.locals.page == tag.globals.page
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
desc %{
|
|
700
|
+
Renders the contained elements unless the current contextual page is also the actual page.
|
|
701
|
+
|
|
702
|
+
This is typically used inside another tag (like <r:children:each>) to add conditional mark-up unless the child element is the current page.
|
|
703
|
+
|
|
704
|
+
*Usage:*
|
|
705
|
+
|
|
706
|
+
<pre><code><r:unless_self>...</r:unless_self></code></pre>
|
|
707
|
+
}
|
|
708
|
+
tag "unless_self" do |tag|
|
|
709
|
+
tag.expand unless tag.locals.page == tag.globals.page
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
desc %{
|
|
713
|
+
Renders the name of the author of the current page.
|
|
714
|
+
}
|
|
715
|
+
tag 'author' do |tag|
|
|
716
|
+
page = tag.locals.page
|
|
717
|
+
if author = page.created_by
|
|
718
|
+
author.name
|
|
719
|
+
end
|
|
720
|
+
end
|
|
721
|
+
|
|
722
|
+
desc %{
|
|
723
|
+
Renders the Gravatar of the author of the current page or the named user.
|
|
724
|
+
|
|
725
|
+
*Usage:*
|
|
726
|
+
|
|
727
|
+
<pre><code><r:gravatar /></code></pre>
|
|
728
|
+
|
|
729
|
+
or
|
|
730
|
+
|
|
731
|
+
<pre><code><r:gravatar [name="User Name"]
|
|
732
|
+
[rating="G | PG | R | X"]
|
|
733
|
+
[size="32px"] /></code></pre>
|
|
734
|
+
}
|
|
735
|
+
tag 'gravatar' do |tag|
|
|
736
|
+
page = tag.locals.page
|
|
737
|
+
name = (tag.attr['name'] || page.created_by.name)
|
|
738
|
+
rating = (tag.attr['rating'] || 'G')
|
|
739
|
+
size = (tag.attr['size'] || '32px')
|
|
740
|
+
user = User.find_by_name(name)
|
|
741
|
+
email = user ? user.email : nil
|
|
742
|
+
local_avatar_url = "/images/admin/avatar_#{([size.to_i] * 2).join('x')}.png"
|
|
743
|
+
default_avatar_url = "#{request.protocol}#{request.host_with_port}#{local_avatar_url}"
|
|
744
|
+
|
|
745
|
+
unless email.blank?
|
|
746
|
+
url = '//gravatar.com/avatar/'
|
|
747
|
+
url << "#{Digest::MD5.new.update(email)}?"
|
|
748
|
+
url << "rating=#{rating}"
|
|
749
|
+
url << "&size=#{size.to_i}"
|
|
750
|
+
url << "&default=#{default_avatar_url}" unless request.host_with_port == 'testhost.tld'
|
|
751
|
+
# Test the Gravatar url
|
|
752
|
+
require 'open-uri'
|
|
753
|
+
begin; open "http:#{url}", :proxy => true
|
|
754
|
+
rescue; local_avatar_url
|
|
755
|
+
else; url
|
|
756
|
+
end
|
|
757
|
+
else
|
|
758
|
+
local_avatar_url
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
desc %{
|
|
763
|
+
Renders the date based on the current page (by default when it was published or created).
|
|
764
|
+
The format attribute uses the same formating codes used by the Ruby @strftime@ function.
|
|
765
|
+
By default it's set to @%A, %B %d, %Y@. You may also use the string @rfc1123@ as a shortcut
|
|
766
|
+
for @%a, %d %b %Y %H:%M:%S GMT@ (non-localized). The @for@ attribute selects which date to
|
|
767
|
+
render. Valid options are @published_at@, @created_at@, @updated_at@, and @now@. @now@ will
|
|
768
|
+
render the current date/time, regardless of the page.
|
|
769
|
+
|
|
770
|
+
*Usage:*
|
|
771
|
+
|
|
772
|
+
<pre><code><r:date [format="%A, %B %d, %Y"] [for="published_at"]/></code></pre>
|
|
773
|
+
}
|
|
774
|
+
tag 'date' do |tag|
|
|
775
|
+
page = tag.locals.page
|
|
776
|
+
format = (tag.attr['format'] || '%A, %B %d, %Y')
|
|
777
|
+
time_attr = tag.attr['for']
|
|
778
|
+
date = if time_attr
|
|
779
|
+
case
|
|
780
|
+
when time_attr == 'now'
|
|
781
|
+
Time.zone.now
|
|
782
|
+
when Page.date_column_names.include?(time_attr)
|
|
783
|
+
page[time_attr]
|
|
784
|
+
else
|
|
785
|
+
raise TagError, "Invalid value for 'for' attribute."
|
|
786
|
+
end
|
|
787
|
+
else
|
|
788
|
+
page.published_at || page.created_at
|
|
789
|
+
end
|
|
790
|
+
case format
|
|
791
|
+
when 'rfc1123'
|
|
792
|
+
CGI.rfc1123_date(date.to_time)
|
|
793
|
+
else
|
|
794
|
+
@i18n_date_format_keys ||= (I18n.config.backend.send(:translations)[I18n.locale][:date][:formats].keys rescue [])
|
|
795
|
+
format = @i18n_date_format_keys.include?(format.to_sym) ? format.to_sym : format
|
|
796
|
+
I18n.l date, :format => format
|
|
797
|
+
end
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
desc %{
|
|
801
|
+
Renders a link to the page. When used as a single tag it uses the page's title
|
|
802
|
+
for the link name. When used as a double tag the part in between both tags will
|
|
803
|
+
be used as the link text. The link tag passes all attributes over to the HTML
|
|
804
|
+
@a@ tag. This is very useful for passing attributes like the @class@ attribute
|
|
805
|
+
or @id@ attribute. If the @anchor@ attribute is passed to the tag it will
|
|
806
|
+
append a pound sign (<code>#</code>) followed by the value of the attribute to
|
|
807
|
+
the @href@ attribute of the HTML @a@ tag--effectively making an HTML anchor.
|
|
808
|
+
|
|
809
|
+
*Usage:*
|
|
810
|
+
|
|
811
|
+
<pre><code><r:link [anchor="name"] [other attributes...] /></code></pre>
|
|
812
|
+
|
|
813
|
+
or
|
|
814
|
+
|
|
815
|
+
<pre><code><r:link [anchor="name"] [other attributes...]>link text here</r:link></code></pre>
|
|
816
|
+
}
|
|
817
|
+
tag 'link' do |tag|
|
|
818
|
+
options = tag.attr.dup
|
|
819
|
+
anchor = options['anchor'] ? "##{options.delete('anchor')}" : ''
|
|
820
|
+
attributes = options.inject('') { |s, (k, v)| s << %{#{k.downcase}="#{v}" } }.strip
|
|
821
|
+
attributes = " #{attributes}" unless attributes.empty?
|
|
822
|
+
text = tag.double? ? tag.expand : tag.render('title')
|
|
823
|
+
%{<a href="#{tag.render('path')}#{anchor}"#{attributes}>#{text}</a>}
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
desc %{
|
|
827
|
+
Renders a trail of breadcrumbs to the current page. The separator attribute
|
|
828
|
+
specifies the HTML fragment that is inserted between each of the breadcrumbs. By
|
|
829
|
+
default it is set to @>@. The boolean @nolinks@ attribute can be specified to render
|
|
830
|
+
breadcrumbs in plain text, without any links (useful when generating title tag).
|
|
831
|
+
Set the boolean @noself@ attribute to omit the present page (useful in page headers).
|
|
832
|
+
|
|
833
|
+
*Usage:*
|
|
834
|
+
|
|
835
|
+
<pre><code><r:breadcrumbs [separator="separator_string"] [nolinks="true"] [noself="true"]/></code></pre>
|
|
836
|
+
}
|
|
837
|
+
tag 'breadcrumbs' do |tag|
|
|
838
|
+
page = tag.locals.page
|
|
839
|
+
nolinks = (tag.attr['nolinks'] == 'true')
|
|
840
|
+
noself = (tag.attr['noself'] == 'true')
|
|
841
|
+
breadcrumbs = []
|
|
842
|
+
breadcrumbs.unshift page.breadcrumb unless noself
|
|
843
|
+
page.ancestors.each do |ancestor|
|
|
844
|
+
tag.locals.page = ancestor
|
|
845
|
+
if nolinks
|
|
846
|
+
breadcrumbs.unshift tag.render('breadcrumb')
|
|
847
|
+
else
|
|
848
|
+
breadcrumbs.unshift %{<a href="#{tag.render('path')}">#{tag.render('breadcrumb')}</a>}
|
|
849
|
+
end
|
|
850
|
+
end
|
|
851
|
+
separator = tag.attr['separator'] || ' > '
|
|
852
|
+
breadcrumbs.join(separator)
|
|
853
|
+
end
|
|
854
|
+
|
|
855
|
+
desc %{
|
|
856
|
+
Inside this tag all page related tags refer to the page found at the @path@ attribute.
|
|
857
|
+
@path@s may be relative or absolute paths.
|
|
858
|
+
|
|
859
|
+
*Usage:*
|
|
860
|
+
|
|
861
|
+
<pre><code><r:find path="value_to_find">...</r:find></code></pre>
|
|
862
|
+
}
|
|
863
|
+
tag 'find' do |tag|
|
|
864
|
+
required_attr(tag,'path','url')
|
|
865
|
+
path = tag.attr['path'] || tag.attr['url']
|
|
866
|
+
|
|
867
|
+
found = Page.find_by_path(absolute_path_for(tag.locals.page.path, path))
|
|
868
|
+
if page_found?(found)
|
|
869
|
+
tag.locals.page = found
|
|
870
|
+
tag.expand
|
|
871
|
+
end
|
|
872
|
+
end
|
|
873
|
+
|
|
874
|
+
desc %{
|
|
875
|
+
Randomly renders one of the options specified by the @option@ tags.
|
|
876
|
+
|
|
877
|
+
*Usage:*
|
|
878
|
+
|
|
879
|
+
<pre><code><r:random>
|
|
880
|
+
<r:option>...</r:option>
|
|
881
|
+
<r:option>...</r:option>
|
|
882
|
+
...
|
|
883
|
+
<r:random>
|
|
884
|
+
</code></pre>
|
|
885
|
+
}
|
|
886
|
+
tag 'random' do |tag|
|
|
887
|
+
tag.locals.random = []
|
|
888
|
+
tag.expand
|
|
889
|
+
options = tag.locals.random
|
|
890
|
+
option = options[rand(options.size)]
|
|
891
|
+
option if option
|
|
892
|
+
end
|
|
893
|
+
tag 'random:option' do |tag|
|
|
894
|
+
items = tag.locals.random
|
|
895
|
+
items << tag.expand
|
|
896
|
+
end
|
|
897
|
+
|
|
898
|
+
desc %{
|
|
899
|
+
Nothing inside a set of hide tags is rendered.
|
|
900
|
+
|
|
901
|
+
*Usage:*
|
|
902
|
+
|
|
903
|
+
<pre><code><r:hide>...</r:hide></code></pre>
|
|
904
|
+
}
|
|
905
|
+
tag 'hide' do |tag|
|
|
906
|
+
end
|
|
907
|
+
|
|
908
|
+
desc %{
|
|
909
|
+
Escapes angle brackets, etc. for rendering in an HTML document.
|
|
910
|
+
|
|
911
|
+
*Usage:*
|
|
912
|
+
|
|
913
|
+
<pre><code><r:escape_html>...</r:escape_html></code></pre>
|
|
914
|
+
}
|
|
915
|
+
tag "escape_html" do |tag|
|
|
916
|
+
CGI.escapeHTML(tag.expand)
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
desc %{
|
|
920
|
+
Renders a list of links specified in the @paths@ attribute according to three
|
|
921
|
+
states:
|
|
922
|
+
|
|
923
|
+
* @normal@ specifies the normal state for the link
|
|
924
|
+
* @here@ specifies the state of the link when the path matches the current
|
|
925
|
+
page's PATH
|
|
926
|
+
* @selected@ specifies the state of the link when the current page matches
|
|
927
|
+
is a child of the specified path
|
|
928
|
+
# @if_last@ renders its contents within a @normal@, @here@ or
|
|
929
|
+
@selected@ tag if the item is the last in the navigation elements
|
|
930
|
+
# @if_first@ renders its contents within a @normal@, @here@ or
|
|
931
|
+
@selected@ tag if the item is the first in the navigation elements
|
|
932
|
+
|
|
933
|
+
The @between@ tag specifies what should be inserted in between each of the links.
|
|
934
|
+
|
|
935
|
+
*Usage:*
|
|
936
|
+
|
|
937
|
+
<pre><code><r:navigation paths="[Title: path | Title: path | ...]">
|
|
938
|
+
<r:normal><a href="<r:path />"><r:title /></a></r:normal>
|
|
939
|
+
<r:here><strong><r:title /></strong></r:here>
|
|
940
|
+
<r:selected><strong><a href="<r:path />"><r:title /></a></strong></r:selected>
|
|
941
|
+
<r:between> | </r:between>
|
|
942
|
+
</r:navigation>
|
|
943
|
+
</code></pre>
|
|
944
|
+
}
|
|
945
|
+
tag 'navigation' do |tag|
|
|
946
|
+
hash = tag.locals.navigation = {}
|
|
947
|
+
tag.expand
|
|
948
|
+
raise TagError.new("`navigation' tag must include a `normal' tag") unless hash.has_key? :normal
|
|
949
|
+
ActiveSupport::Deprecation.warn("The 'urls' attribute of the r:navigation tag has been deprecated in favour of 'paths'. Please update your site.") if tag.attr['urls']
|
|
950
|
+
result = []
|
|
951
|
+
pairs = (tag.attr['paths']||tag.attr['urls']).to_s.split('|').map do |pair|
|
|
952
|
+
parts = pair.split(':')
|
|
953
|
+
value = parts.pop
|
|
954
|
+
key = parts.join(':')
|
|
955
|
+
[key.strip, value.strip]
|
|
956
|
+
end
|
|
957
|
+
pairs.each_with_index do |(title, path), i|
|
|
958
|
+
compare_path = remove_trailing_slash(path)
|
|
959
|
+
page_path = remove_trailing_slash(self.path)
|
|
960
|
+
hash[:title] = title
|
|
961
|
+
hash[:path] = path
|
|
962
|
+
tag.locals.first_child = i == 0
|
|
963
|
+
tag.locals.last_child = i == pairs.length - 1
|
|
964
|
+
case page_path
|
|
965
|
+
when compare_path
|
|
966
|
+
result << (hash[:here] || hash[:selected] || hash[:normal]).call
|
|
967
|
+
when Regexp.compile( '^' + Regexp.quote(path))
|
|
968
|
+
result << (hash[:selected] || hash[:normal]).call
|
|
969
|
+
else
|
|
970
|
+
result << hash[:normal].call
|
|
971
|
+
end
|
|
972
|
+
end
|
|
973
|
+
between = hash.has_key?(:between) ? hash[:between].call : ' '
|
|
974
|
+
result.reject { |i| i.blank? }.join(between)
|
|
975
|
+
end
|
|
976
|
+
[:normal, :here, :selected, :between].each do |symbol|
|
|
977
|
+
tag "navigation:#{symbol}" do |tag|
|
|
978
|
+
hash = tag.locals.navigation
|
|
979
|
+
hash[symbol] = tag.block
|
|
980
|
+
end
|
|
981
|
+
end
|
|
982
|
+
[:title, :path].each do |symbol|
|
|
983
|
+
tag "navigation:#{symbol}" do |tag|
|
|
984
|
+
hash = tag.locals.navigation
|
|
985
|
+
hash[symbol]
|
|
986
|
+
end
|
|
987
|
+
end
|
|
988
|
+
tag "navigation:url" do |tag|
|
|
989
|
+
hash = tag.locals.navigation
|
|
990
|
+
ActiveSupport::Deprecation.warn("The 'r:navigation:url' tag has been deprecated in favour of 'r:navigation:path'. Please update your site.")
|
|
991
|
+
hash[:path]
|
|
992
|
+
end
|
|
993
|
+
|
|
994
|
+
desc %{
|
|
995
|
+
Renders the containing elements if the element is the first
|
|
996
|
+
in the navigation list
|
|
997
|
+
|
|
998
|
+
*Usage:*
|
|
999
|
+
|
|
1000
|
+
<pre><code><r:normal><r:if_first>...</r:if_first></r:normal></code></pre>
|
|
1001
|
+
}
|
|
1002
|
+
tag 'navigation:if_first' do |tag|
|
|
1003
|
+
tag.expand if tag.locals.first_child
|
|
1004
|
+
end
|
|
1005
|
+
|
|
1006
|
+
desc %{
|
|
1007
|
+
Renders the containing elements unless the element is the first
|
|
1008
|
+
in the navigation list
|
|
1009
|
+
|
|
1010
|
+
*Usage:*
|
|
1011
|
+
|
|
1012
|
+
<pre><code><r:normal><r:unless_first>...</r:unless_first></r:normal></code></pre>
|
|
1013
|
+
}
|
|
1014
|
+
tag 'navigation:unless_first' do |tag|
|
|
1015
|
+
tag.expand unless tag.locals.first_child
|
|
1016
|
+
end
|
|
1017
|
+
|
|
1018
|
+
desc %{
|
|
1019
|
+
Renders the containing elements unless the element is the last
|
|
1020
|
+
in the navigation list
|
|
1021
|
+
|
|
1022
|
+
*Usage:*
|
|
1023
|
+
|
|
1024
|
+
<pre><code><r:normal><r:unless_last>...</r:unless_last></r:normal></code></pre>
|
|
1025
|
+
}
|
|
1026
|
+
tag 'navigation:unless_last' do |tag|
|
|
1027
|
+
tag.expand unless tag.locals.last_child
|
|
1028
|
+
end
|
|
1029
|
+
|
|
1030
|
+
desc %{
|
|
1031
|
+
Renders the containing elements if the element is the last
|
|
1032
|
+
in the navigation list
|
|
1033
|
+
|
|
1034
|
+
*Usage:*
|
|
1035
|
+
|
|
1036
|
+
<pre><code><r:normal><r:if_last>...</r:if_last></r:normal></code></pre>
|
|
1037
|
+
}
|
|
1038
|
+
tag 'navigation:if_last' do |tag|
|
|
1039
|
+
tag.expand if tag.locals.last_child
|
|
1040
|
+
end
|
|
1041
|
+
|
|
1042
|
+
desc %{
|
|
1043
|
+
Renders the containing elements only if TrustyCms in is development mode.
|
|
1044
|
+
|
|
1045
|
+
*Usage:*
|
|
1046
|
+
|
|
1047
|
+
<pre><code><r:if_dev>...</r:if_dev></code></pre>
|
|
1048
|
+
}
|
|
1049
|
+
tag 'if_dev' do |tag|
|
|
1050
|
+
tag.expand if dev?(tag.globals.page.request)
|
|
1051
|
+
end
|
|
1052
|
+
|
|
1053
|
+
desc %{
|
|
1054
|
+
The opposite of the @if_dev@ tag.
|
|
1055
|
+
|
|
1056
|
+
*Usage:*
|
|
1057
|
+
|
|
1058
|
+
<pre><code><r:unless_dev>...</r:unless_dev></code></pre>
|
|
1059
|
+
}
|
|
1060
|
+
tag 'unless_dev' do |tag|
|
|
1061
|
+
tag.expand unless dev?(tag.globals.page.request)
|
|
1062
|
+
end
|
|
1063
|
+
|
|
1064
|
+
desc %{
|
|
1065
|
+
Prints the page's status as a string. Optional attribute 'downcase'
|
|
1066
|
+
will cause the status to be all lowercase.
|
|
1067
|
+
|
|
1068
|
+
*Usage:*
|
|
1069
|
+
|
|
1070
|
+
<pre><code><r:status [downcase='true'] /></code></pre>
|
|
1071
|
+
}
|
|
1072
|
+
tag 'status' do |tag|
|
|
1073
|
+
status = tag.globals.page.status.name
|
|
1074
|
+
return status.downcase if tag.attr['downcase']
|
|
1075
|
+
status
|
|
1076
|
+
end
|
|
1077
|
+
|
|
1078
|
+
desc %(
|
|
1079
|
+
Renders the content of the field given in the @name@ attribute.
|
|
1080
|
+
|
|
1081
|
+
*Usage:*
|
|
1082
|
+
|
|
1083
|
+
<pre><code><r:field name="Keywords" /></code></pre>
|
|
1084
|
+
)
|
|
1085
|
+
tag 'field' do |tag|
|
|
1086
|
+
required_attr(tag,'name')
|
|
1087
|
+
tag.locals.page.field(tag.attr['name']).try(:content)
|
|
1088
|
+
end
|
|
1089
|
+
|
|
1090
|
+
desc %(
|
|
1091
|
+
Renders the contained elements if the field given in the @name@ attribute
|
|
1092
|
+
exists. The tag also takes an optional @equals@ or @matches@ attribute;
|
|
1093
|
+
these will expand the tag if the field's content equals or matches the
|
|
1094
|
+
given string or regex.
|
|
1095
|
+
|
|
1096
|
+
*Usage:*
|
|
1097
|
+
|
|
1098
|
+
<pre><code><r:if_field name="author" [equals|matches="John"] [ignore_case="true|false"]>...</r:if_field></code></pre>
|
|
1099
|
+
)
|
|
1100
|
+
tag 'if_field' do |tag|
|
|
1101
|
+
required_attr(tag,'name')
|
|
1102
|
+
field = tag.locals.page.field(tag.attr['name'])
|
|
1103
|
+
return '' if field.nil?
|
|
1104
|
+
tag.expand if case
|
|
1105
|
+
when (tag.attr['equals'] and tag.attr['ignore_case'] == 'false') then field.content == tag.attr['equals']
|
|
1106
|
+
when tag.attr['equals'] then field.content.downcase == tag.attr['equals'].downcase
|
|
1107
|
+
when tag.attr['matches'] then field.content =~ build_regexp_for(tag, 'matches')
|
|
1108
|
+
else field
|
|
1109
|
+
end
|
|
1110
|
+
end
|
|
1111
|
+
|
|
1112
|
+
desc %(
|
|
1113
|
+
The opposite of @if_field@. Renders the contained elements unless the field
|
|
1114
|
+
given in the @name@ attribute exists. The tag also takes an optional
|
|
1115
|
+
@equals@ or @matches@ attribute; these will expand the tag unless the
|
|
1116
|
+
field's content equals or matches the given string or regex.
|
|
1117
|
+
|
|
1118
|
+
*Usage:*
|
|
1119
|
+
|
|
1120
|
+
<pre><code><r:unless_field name="author" [equals|matches="John"] [ignore_case="true|false"]>...</r:unless_field></code></pre>
|
|
1121
|
+
)
|
|
1122
|
+
tag 'unless_field' do |tag|
|
|
1123
|
+
required_attr(tag,'name')
|
|
1124
|
+
field = tag.locals.page.field(tag.attr['name'])
|
|
1125
|
+
tag.expand unless case
|
|
1126
|
+
when (field and (tag.attr['equals'] and tag.attr['ignore_case'] == 'false')) then field.content == tag.attr['equals']
|
|
1127
|
+
when (field and tag.attr['equals']) then field.content.downcase == tag.attr['equals'].downcase
|
|
1128
|
+
when (field and tag.attr['matches']) then field.content =~ build_regexp_for(tag, 'matches')
|
|
1129
|
+
else field
|
|
1130
|
+
end
|
|
1131
|
+
end
|
|
1132
|
+
|
|
1133
|
+
tag 'site' do |tag|
|
|
1134
|
+
tag.expand
|
|
1135
|
+
end
|
|
1136
|
+
desc %{
|
|
1137
|
+
Returns TrustyCms::Config['site.title'] as configured under the Settings tab.
|
|
1138
|
+
}
|
|
1139
|
+
tag "site:title" do |tag|
|
|
1140
|
+
TrustyCms::Config["site.title"]
|
|
1141
|
+
end
|
|
1142
|
+
desc %{
|
|
1143
|
+
Returns TrustyCms::Config['site.host'] as configured under the Settings tab.
|
|
1144
|
+
}
|
|
1145
|
+
tag "site:host" do |tag|
|
|
1146
|
+
TrustyCms::Config["site.host"]
|
|
1147
|
+
end
|
|
1148
|
+
desc %{
|
|
1149
|
+
Returns TrustyCms::Config['dev.host'] as configured under the Settings tab.
|
|
1150
|
+
}
|
|
1151
|
+
tag "site:dev_host" do |tag|
|
|
1152
|
+
TrustyCms::Config["dev.host"]
|
|
1153
|
+
end
|
|
1154
|
+
|
|
1155
|
+
private
|
|
1156
|
+
def render_children_with_pagination(tag, opts={})
|
|
1157
|
+
if opts[:aggregate]
|
|
1158
|
+
findable = Page
|
|
1159
|
+
options = aggregate_children(tag)
|
|
1160
|
+
else
|
|
1161
|
+
findable = tag.locals.children
|
|
1162
|
+
options = children_find_options(tag)
|
|
1163
|
+
end
|
|
1164
|
+
paging = pagination_find_options(tag)
|
|
1165
|
+
result = []
|
|
1166
|
+
tag.locals.previous_headers = {}
|
|
1167
|
+
displayed_children = paging ? findable.paginate(options.merge(paging)) : findable.all(options)
|
|
1168
|
+
displayed_children.each_with_index do |item, i|
|
|
1169
|
+
tag.locals.child = item
|
|
1170
|
+
tag.locals.page = item
|
|
1171
|
+
tag.locals.first_child = i == 0
|
|
1172
|
+
tag.locals.last_child = i == displayed_children.length - 1
|
|
1173
|
+
result << tag.expand
|
|
1174
|
+
end
|
|
1175
|
+
if paging && displayed_children.total_pages > 1
|
|
1176
|
+
tag.locals.paginated_list = displayed_children
|
|
1177
|
+
result << tag.render('pagination', tag.attr.dup)
|
|
1178
|
+
end
|
|
1179
|
+
result.flatten.join('')
|
|
1180
|
+
end
|
|
1181
|
+
|
|
1182
|
+
def children_find_options(tag)
|
|
1183
|
+
attr = tag.attr.symbolize_keys
|
|
1184
|
+
|
|
1185
|
+
options = {}
|
|
1186
|
+
|
|
1187
|
+
[:limit, :offset].each do |symbol|
|
|
1188
|
+
if number = attr[symbol]
|
|
1189
|
+
if number =~ /^\d+$/
|
|
1190
|
+
options[symbol] = number.to_i
|
|
1191
|
+
else
|
|
1192
|
+
raise TagError.new("`#{symbol}' attribute must be a positive number")
|
|
1193
|
+
end
|
|
1194
|
+
end
|
|
1195
|
+
end
|
|
1196
|
+
|
|
1197
|
+
by = (attr[:by] || 'published_at').strip
|
|
1198
|
+
order = (attr[:order] || 'asc').strip
|
|
1199
|
+
order_string = ''
|
|
1200
|
+
if self.attributes.keys.include?(by)
|
|
1201
|
+
order_string << by
|
|
1202
|
+
else
|
|
1203
|
+
raise TagError.new("`by' attribute of `each' tag must be set to a valid field name")
|
|
1204
|
+
end
|
|
1205
|
+
if order =~ /^(asc|desc)$/i
|
|
1206
|
+
order_string << " #{$1.upcase}"
|
|
1207
|
+
else
|
|
1208
|
+
raise TagError.new(%{`order' attribute of `each' tag must be set to either "asc" or "desc"})
|
|
1209
|
+
end
|
|
1210
|
+
options[:order] = order_string
|
|
1211
|
+
|
|
1212
|
+
status = (attr[:status] || ( dev?(tag.globals.page.request) ? 'all' : 'published')).downcase
|
|
1213
|
+
unless status == 'all'
|
|
1214
|
+
stat = Status[status]
|
|
1215
|
+
unless stat.nil?
|
|
1216
|
+
options[:conditions] = ["(virtual = ?) and (status_id = ?)", false, stat.id]
|
|
1217
|
+
else
|
|
1218
|
+
raise TagError.new(%{`status' attribute of `each' tag must be set to a valid status})
|
|
1219
|
+
end
|
|
1220
|
+
else
|
|
1221
|
+
options[:conditions] = ["virtual = ?", false]
|
|
1222
|
+
end
|
|
1223
|
+
options
|
|
1224
|
+
end
|
|
1225
|
+
|
|
1226
|
+
def aggregate_children(tag)
|
|
1227
|
+
options = children_find_options(tag)
|
|
1228
|
+
parent_ids = tag.locals.parent_ids
|
|
1229
|
+
|
|
1230
|
+
conditions = options[:conditions]
|
|
1231
|
+
conditions.first << " AND parent_id IN (?)"
|
|
1232
|
+
conditions << parent_ids
|
|
1233
|
+
options
|
|
1234
|
+
end
|
|
1235
|
+
|
|
1236
|
+
def pagination_find_options(tag)
|
|
1237
|
+
attr = tag.attr.symbolize_keys
|
|
1238
|
+
if attr[:paginated] == 'true'
|
|
1239
|
+
pagination_parameters.merge(attr.slice(:per_page))
|
|
1240
|
+
else
|
|
1241
|
+
false
|
|
1242
|
+
end
|
|
1243
|
+
end
|
|
1244
|
+
|
|
1245
|
+
def will_paginate_options(tag)
|
|
1246
|
+
attr = tag.attr.symbolize_keys
|
|
1247
|
+
if attr[:paginated] == 'true'
|
|
1248
|
+
attr.slice(:class, :previous_label, :next_label, :inner_window, :outer_window, :separator, :per_page).merge({:renderer => TrustyCms::Pagination::LinkRenderer.new(tag.globals.page.path)})
|
|
1249
|
+
else
|
|
1250
|
+
{}
|
|
1251
|
+
end
|
|
1252
|
+
end
|
|
1253
|
+
|
|
1254
|
+
def remove_trailing_slash(string)
|
|
1255
|
+
(string =~ %r{^(.*?)/$}) ? $1 : string
|
|
1256
|
+
end
|
|
1257
|
+
|
|
1258
|
+
def tag_part_name(tag)
|
|
1259
|
+
tag.attr['part'] || 'body'
|
|
1260
|
+
end
|
|
1261
|
+
|
|
1262
|
+
def build_regexp_for(tag, attribute_name)
|
|
1263
|
+
ignore_case = tag.attr.has_key?('ignore_case') && tag.attr['ignore_case']=='false' ? nil : true
|
|
1264
|
+
begin
|
|
1265
|
+
regexp = Regexp.new(tag.attr['matches'], ignore_case)
|
|
1266
|
+
rescue RegexpError => e
|
|
1267
|
+
raise TagError.new("Malformed regular expression in `#{attribute_name}' argument of `#{tag.name}' tag: #{e.message}")
|
|
1268
|
+
end
|
|
1269
|
+
regexp
|
|
1270
|
+
end
|
|
1271
|
+
|
|
1272
|
+
def relative_url_for(url, request)
|
|
1273
|
+
File.join(ActionController::Base.relative_url_root || '', url)
|
|
1274
|
+
end
|
|
1275
|
+
|
|
1276
|
+
def absolute_path_for(base_path, new_path)
|
|
1277
|
+
if new_path.first == '/'
|
|
1278
|
+
new_path
|
|
1279
|
+
else
|
|
1280
|
+
File.expand_path(File.join(base_path, new_path))
|
|
1281
|
+
end
|
|
1282
|
+
end
|
|
1283
|
+
|
|
1284
|
+
def page_found?(page)
|
|
1285
|
+
page && !(FileNotFoundPage === page)
|
|
1286
|
+
end
|
|
1287
|
+
|
|
1288
|
+
def boolean_attr_or_error(tag, attribute_name, default)
|
|
1289
|
+
attribute = attr_or_error(tag, :attribute_name => attribute_name, :default => default.to_s, :values => 'true, false')
|
|
1290
|
+
(attribute.to_s.downcase == 'true') ? true : false
|
|
1291
|
+
end
|
|
1292
|
+
|
|
1293
|
+
def attr_or_error(tag, options = {})
|
|
1294
|
+
attribute_name = options[:attribute_name].to_s
|
|
1295
|
+
default = options[:default]
|
|
1296
|
+
values = options[:values].split(',').map!(&:strip)
|
|
1297
|
+
|
|
1298
|
+
attribute = (tag.attr[attribute_name] || default).to_s
|
|
1299
|
+
raise TagError.new(%{`#{attribute_name}' attribute of `#{tag.name}' tag must be one of: #{values.join(', ')}}) unless values.include?(attribute)
|
|
1300
|
+
return attribute
|
|
1301
|
+
end
|
|
1302
|
+
|
|
1303
|
+
def required_attr(tag, *attribute_names)
|
|
1304
|
+
attr_collection = attribute_names.map{|a| "`#{a}'"}.join(' or ')
|
|
1305
|
+
raise TagError.new("`#{tag.name}' tag must contain a #{attr_collection} attribute.") if (tag.attr.keys & attribute_names).blank?
|
|
1306
|
+
end
|
|
1307
|
+
|
|
1308
|
+
def dev?(request)
|
|
1309
|
+
return false if request.nil?
|
|
1310
|
+
# TODO: More nonsense!
|
|
1311
|
+
if dev_host = TrustyCms::Config['dev.host']
|
|
1312
|
+
dev_host == request.host
|
|
1313
|
+
else
|
|
1314
|
+
request.host =~ /^dev\./
|
|
1315
|
+
end
|
|
1316
|
+
end
|
|
1317
|
+
|
|
1318
|
+
end
|