zena 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +18 -0
- data/README.txt +133 -0
- data/app/controllers/application_controller.rb +3 -0
- data/app/controllers/comments_controller.rb +141 -0
- data/app/controllers/data_entries_controller.rb +81 -0
- data/app/controllers/discussions_controller.rb +48 -0
- data/app/controllers/documents_controller.rb +136 -0
- data/app/controllers/groups_controller.rb +99 -0
- data/app/controllers/iformats_controller.rb +78 -0
- data/app/controllers/links_controller.rb +98 -0
- data/app/controllers/nodes_controller.rb +497 -0
- data/app/controllers/preferences_controller.rb +52 -0
- data/app/controllers/relations_controller.rb +95 -0
- data/app/controllers/sessions_controller.rb +41 -0
- data/app/controllers/sites_controller.rb +112 -0
- data/app/controllers/users_controller.rb +139 -0
- data/app/controllers/versions_controller.rb +268 -0
- data/app/controllers/virtual_classes_controller.rb +95 -0
- data/app/helpers/application_helper.rb +4 -0
- data/app/helpers/documents_helper.rb +13 -0
- data/app/helpers/nodes_helper.rb +20 -0
- data/app/helpers/versions_helper.rb +18 -0
- data/app/models/book.rb +242 -0
- data/app/models/cache.rb +52 -0
- data/app/models/cached_page.rb +134 -0
- data/app/models/comment.rb +125 -0
- data/app/models/contact.rb +32 -0
- data/app/models/contact_content.rb +70 -0
- data/app/models/contact_version.rb +40 -0
- data/app/models/data_entry.rb +162 -0
- data/app/models/discussion.rb +65 -0
- data/app/models/document.rb +146 -0
- data/app/models/document_content.rb +186 -0
- data/app/models/document_version.rb +13 -0
- data/app/models/dyn_attribute.rb +4 -0
- data/app/models/group.rb +142 -0
- data/app/models/iformat.rb +146 -0
- data/app/models/image.rb +96 -0
- data/app/models/image_content.rb +189 -0
- data/app/models/image_version.rb +21 -0
- data/app/models/link.rb +121 -0
- data/app/models/node.rb +1752 -0
- data/app/models/note.rb +58 -0
- data/app/models/page.rb +53 -0
- data/app/models/project.rb +10 -0
- data/app/models/reference.rb +18 -0
- data/app/models/relation.rb +18 -0
- data/app/models/relation_proxy.rb +379 -0
- data/app/models/section.rb +5 -0
- data/app/models/site.rb +355 -0
- data/app/models/skin.rb +20 -0
- data/app/models/template.rb +134 -0
- data/app/models/template_content.rb +112 -0
- data/app/models/template_version.rb +37 -0
- data/app/models/text_document.rb +162 -0
- data/app/models/text_document_content.rb +46 -0
- data/app/models/text_document_version.rb +21 -0
- data/app/models/user.rb +412 -0
- data/app/models/version.rb +328 -0
- data/app/models/virtual_class.rb +134 -0
- data/app/models/zip.rb +6 -0
- data/app/views/comments/_add.rhtml +6 -0
- data/app/views/comments/_bin.rhtml +5 -0
- data/app/views/comments/_form.rhtml +26 -0
- data/app/views/comments/_li.rhtml +13 -0
- data/app/views/comments/_li_simple.rhtml +3 -0
- data/app/views/comments/_list.rhtml +13 -0
- data/app/views/comments/create.rjs +32 -0
- data/app/views/comments/edit.rjs +2 -0
- data/app/views/comments/empty_bin.rjs +1 -0
- data/app/views/comments/index.rhtml +12 -0
- data/app/views/comments/publish.rjs +7 -0
- data/app/views/comments/remove.rjs +9 -0
- data/app/views/comments/reply_to.rjs +2 -0
- data/app/views/comments/update.rjs +1 -0
- data/app/views/data_entries/_li.html.erb +9 -0
- data/app/views/data_entries/create.rjs +1 -0
- data/app/views/data_entries/destroy.rjs +1 -0
- data/app/views/data_entries/edit.rjs +1 -0
- data/app/views/data_entries/index.html.erb +5 -0
- data/app/views/data_entries/show.html.erb +5 -0
- data/app/views/data_entries/show.rjs +1 -0
- data/app/views/data_entries/update.rjs +1 -0
- data/app/views/discussions/_add.rhtml +6 -0
- data/app/views/discussions/_form.rhtml +21 -0
- data/app/views/discussions/_li.rhtml +9 -0
- data/app/views/discussions/_list.rhtml +4 -0
- data/app/views/discussions/create.rjs +10 -0
- data/app/views/discussions/remove.rjs +7 -0
- data/app/views/discussions/show.rjs +1 -0
- data/app/views/discussions/update.rjs +2 -0
- data/app/views/documents/_crop.rhtml +10 -0
- data/app/views/documents/crop_form.rjs +4 -0
- data/app/views/documents/new.rhtml +18 -0
- data/app/views/documents/show.rhtml +17 -0
- data/app/views/groups/_add.rhtml +6 -0
- data/app/views/groups/_form.rhtml +44 -0
- data/app/views/groups/_li.rhtml +13 -0
- data/app/views/groups/create.rjs +8 -0
- data/app/views/groups/destroy.rjs +2 -0
- data/app/views/groups/edit.html.erb +5 -0
- data/app/views/groups/index.rhtml +6 -0
- data/app/views/groups/show.html.erb +5 -0
- data/app/views/groups/show.rjs +1 -0
- data/app/views/iformats/_add.rhtml +6 -0
- data/app/views/iformats/_form.rhtml +29 -0
- data/app/views/iformats/_li.rhtml +15 -0
- data/app/views/iformats/create.rjs +8 -0
- data/app/views/iformats/destroy.rjs +11 -0
- data/app/views/iformats/edit.html.erb +5 -0
- data/app/views/iformats/index.rhtml +7 -0
- data/app/views/iformats/show.html.erb +5 -0
- data/app/views/iformats/show.rjs +1 -0
- data/app/views/iformats/update.rjs +5 -0
- data/app/views/image/_title.rhtml +8 -0
- data/app/views/links/_add.rhtml +6 -0
- data/app/views/links/_form.rhtml +34 -0
- data/app/views/links/_li.rhtml +7 -0
- data/app/views/links/_list.rhtml +9 -0
- data/app/views/links/create.rjs +5 -0
- data/app/views/links/destroy.rjs +11 -0
- data/app/views/links/show.rjs +5 -0
- data/app/views/nodes/404.html +15 -0
- data/app/views/nodes/500.html +15 -0
- data/app/views/nodes/_dates.rhtml +13 -0
- data/app/views/nodes/_edit_attribute.rhtml +32 -0
- data/app/views/nodes/_gallery.rhtml +16 -0
- data/app/views/nodes/_groups.rhtml +25 -0
- data/app/views/nodes/_import_results.rhtml +20 -0
- data/app/views/nodes/_list_nodes.rhtml +9 -0
- data/app/views/nodes/_parent.rhtml +15 -0
- data/app/views/nodes/_position.rhtml +22 -0
- data/app/views/nodes/_results.rhtml +29 -0
- data/app/views/nodes/_show_attr.rhtml +6 -0
- data/app/views/nodes/_table.rhtml +14 -0
- data/app/views/nodes/clear_order.rjs +7 -0
- data/app/views/nodes/create.rjs +17 -0
- data/app/views/nodes/drive.rjs +2 -0
- data/app/views/nodes/drop.rjs +1 -0
- data/app/views/nodes/edit.html.erb +17 -0
- data/app/views/nodes/edit.rjs +7 -0
- data/app/views/nodes/import.rhtml +10 -0
- data/app/views/nodes/save_text.rjs +13 -0
- data/app/views/nodes/search.rjs +3 -0
- data/app/views/nodes/show.rjs +1 -0
- data/app/views/nodes/table_update.rjs +8 -0
- data/app/views/nodes/update.rjs +29 -0
- data/app/views/nodes/zafu.rjs +1 -0
- data/app/views/relations/_add.erb +6 -0
- data/app/views/relations/_form.erb +43 -0
- data/app/views/relations/_li.erb +16 -0
- data/app/views/relations/create.rjs +8 -0
- data/app/views/relations/destroy.rjs +6 -0
- data/app/views/relations/edit.erb +2 -0
- data/app/views/relations/index.erb +6 -0
- data/app/views/relations/new.erb +2 -0
- data/app/views/relations/show.rjs +1 -0
- data/app/views/relations/update.rjs +5 -0
- data/app/views/search/_form.rhtml +13 -0
- data/app/views/sites/_form.erb +37 -0
- data/app/views/sites/_li.erb +13 -0
- data/app/views/sites/clear_cache.rjs +2 -0
- data/app/views/sites/edit.erb +2 -0
- data/app/views/sites/index.erb +6 -0
- data/app/views/sites/show.rjs +1 -0
- data/app/views/sites/update.rjs +5 -0
- data/app/views/sites/zena_up.html.erb +11 -0
- data/app/views/templates/defaults/+adminLayout.zafu +69 -0
- data/app/views/templates/defaults/+login.zafu +32 -0
- data/app/views/templates/document_create_tabs/_file.rhtml +13 -0
- data/app/views/templates/document_create_tabs/_import.rhtml +9 -0
- data/app/views/templates/document_create_tabs/_template.rhtml +22 -0
- data/app/views/templates/document_create_tabs/_text_doc.rhtml +14 -0
- data/app/views/templates/drive_tabs/_drive.rhtml +11 -0
- data/app/views/templates/drive_tabs/_help.rhtml +0 -0
- data/app/views/templates/drive_tabs/_links.rhtml +8 -0
- data/app/views/templates/edit_tabs/_contact.rhtml +8 -0
- data/app/views/templates/edit_tabs/_custom.rhtml +6 -0
- data/app/views/templates/edit_tabs/_document.rhtml +8 -0
- data/app/views/templates/edit_tabs/_help.rhtml +7 -0
- data/app/views/templates/edit_tabs/_image.rhtml +19 -0
- data/app/views/templates/edit_tabs/_template.rhtml +8 -0
- data/app/views/templates/edit_tabs/_text.rhtml +1 -0
- data/app/views/templates/edit_tabs/_textdocument.rhtml +16 -0
- data/app/views/templates/edit_tabs/_title.rhtml +27 -0
- data/app/views/users/_add.rhtml +6 -0
- data/app/views/users/_form.rhtml +49 -0
- data/app/views/users/_li.rhtml +18 -0
- data/app/views/users/change_info.rjs +7 -0
- data/app/views/users/change_password.rjs +7 -0
- data/app/views/users/create.rjs +8 -0
- data/app/views/users/index.rhtml +7 -0
- data/app/views/users/preferences.html.erb +40 -0
- data/app/views/users/show.rjs +1 -0
- data/app/views/users/update.rjs +16 -0
- data/app/views/versions/_li.rhtml +3 -0
- data/app/views/versions/_list.rhtml +5 -0
- data/app/views/versions/_tr.rhtml +10 -0
- data/app/views/versions/backup.rjs +16 -0
- data/app/views/versions/css_preview.rjs +2 -0
- data/app/views/versions/destroy.rjs +6 -0
- data/app/views/versions/diff.rjs +3 -0
- data/app/views/versions/edit.rhtml +55 -0
- data/app/views/versions/preview.rjs +9 -0
- data/app/views/versions/show.rjs +5 -0
- data/app/views/versions/update.rjs +9 -0
- data/app/views/virtual_classes/_add.erb +6 -0
- data/app/views/virtual_classes/_form.erb +30 -0
- data/app/views/virtual_classes/_li.erb +12 -0
- data/app/views/virtual_classes/create.rjs +8 -0
- data/app/views/virtual_classes/destroy.rjs +6 -0
- data/app/views/virtual_classes/index.erb +7 -0
- data/app/views/virtual_classes/new.erb +2 -0
- data/app/views/virtual_classes/show.rjs +1 -0
- data/app/views/virtual_classes/update.rjs +5 -0
- data/bin/zena +5 -0
- data/bricks/captcha/MIT-LICENSE +19 -0
- data/bricks/captcha/README +11 -0
- data/bricks/captcha/patch/application_controller.rb +10 -0
- data/bricks/captcha/patch/application_helper.rb +32 -0
- data/bricks/captcha/patch/site.rb +2 -0
- data/bricks/captcha/zafu/captcha.rb +29 -0
- data/bricks/math/patch/application_helper.rb +95 -0
- data/bricks/tags/README +31 -0
- data/bricks/tags/lib/has_tags.rb +164 -0
- data/bricks/tags/patch/node.rb +15 -0
- data/bricks/tags/test/sites/zena/links.yml +11 -0
- data/bricks/tags/test/unit/tags_test.rb +103 -0
- data/bricks/tags/test/zafu/tags.yml +28 -0
- data/bricks/toto.zip +0 -0
- data/config/awstats.conf.rhtml +1497 -0
- data/config/boot.rb +109 -0
- data/config/database.rhtml +25 -0
- data/config/database.yml +40 -0
- data/config/database_example.yml +27 -0
- data/config/deploy.rb +382 -0
- data/config/deploy_config_example.rb +7 -0
- data/config/environment.rb +13 -0
- data/config/environments/development.rb +21 -0
- data/config/environments/production.rb +27 -0
- data/config/environments/test.rb +22 -0
- data/config/gems.yml +46 -0
- data/config/httpd.rhtml +18 -0
- data/config/initializers/mime_types.rb +10 -0
- data/config/initializers/zena.rb +1 -0
- data/config/locales/de.yml +120 -0
- data/config/locales/fr-CH.yml +123 -0
- data/config/locales/fr.yml +123 -0
- data/config/mongrel_upload_progress.conf +7 -0
- data/config/routes.rb +3 -0
- data/config/start.html +44 -0
- data/config/stats.vhost.rhtml +40 -0
- data/config/vhost.rhtml +84 -0
- data/config/vhost_www.rhtml +10 -0
- data/config/zena.rb +39 -0
- data/db/init/base/help.en.zml +94 -0
- data/db/init/base/help.fr.zml +88 -0
- data/db/init/base/skins.zml +3 -0
- data/db/init/base/skins/default.zml +10 -0
- data/db/init/base/skins/default/Node-+adminLayout.zafu +45 -0
- data/db/init/base/skins/default/Node-+index.zafu +1 -0
- data/db/init/base/skins/default/Node-+login.zafu +25 -0
- data/db/init/base/skins/default/Node-+notFound.zafu +14 -0
- data/db/init/base/skins/default/Node-+popupLayout.zafu +39 -0
- data/db/init/base/skins/default/Node-+search.zafu +20 -0
- data/db/init/base/skins/default/Node-tree.zafu +19 -0
- data/db/init/base/skins/default/Node.zafu +95 -0
- data/db/init/base/skins/default/Project.zafu +8 -0
- data/db/init/base/skins/default/favicon.png +0 -0
- data/db/init/base/skins/default/notes.zafu +22 -0
- data/db/init/base/skins/default/style.css +80 -0
- data/db/migrate/001_create_base.rb +156 -0
- data/db/migrate/002_add_time_zone_to_users.rb +9 -0
- data/db/migrate/003_add_custom_base_flag.rb +11 -0
- data/db/migrate/004_rename_template_skin.rb +9 -0
- data/db/migrate/005_create_cached_pages.rb +20 -0
- data/db/migrate/006_create_sites.rb +60 -0
- data/db/migrate/007_replace_id_by_zip.rb +17 -0
- data/db/migrate/008_user_status.rb +10 -0
- data/db/migrate/009_fulltext.rb +13 -0
- data/db/migrate/010_create_template_content.rb +17 -0
- data/db/migrate/011_project_to_section.rb +9 -0
- data/db/migrate/012_add_project_id.rb +12 -0
- data/db/migrate/013_remove_defaults.rb +29 -0
- data/db/migrate/014_add_sort_field.rb +10 -0
- data/db/migrate/015_add_dyn_attributes.rb +18 -0
- data/db/migrate/016_remove_translations.rb +20 -0
- data/db/migrate/017_rename_authorize.rb +9 -0
- data/db/migrate/018_add_auth_option.rb +9 -0
- data/db/migrate/019_remove_user_status.rb +25 -0
- data/db/migrate/020_create_participation.rb +30 -0
- data/db/migrate/021_create_relations.rb +23 -0
- data/db/migrate/022_create_virtual_classes.rb +20 -0
- data/db/migrate/023_ip_on_anonymous_comment.rb +9 -0
- data/db/migrate/024_correct_vclass_kpath.rb +11 -0
- data/db/migrate/025_move_tag_into_vclass.rb +13 -0
- data/db/migrate/026_rename_templates.rb +47 -0
- data/db/migrate/027_add_country_to_contacts.rb +9 -0
- data/db/migrate/028_change_size_of_conten_type_field.rb +9 -0
- data/db/migrate/029_create_data_entries.rb +21 -0
- data/db/migrate/030_redit_auto_publish_site_settings.rb +13 -0
- data/db/migrate/031_create_iformats.rb +21 -0
- data/db/migrate/032_caches_context_as_hash.rb +10 -0
- data/db/migrate/033_documents_kpath_change.rb +17 -0
- data/db/migrate/034_change_file_storage.rb +38 -0
- data/db/migrate/035_add_status_to_link.rb +13 -0
- data/db/migrate/036_add_flag_fields_on_nodes.rb +11 -0
- data/db/migrate/037_add_auto_create_discussion_to_v_class.rb +11 -0
- data/db/migrate/038_create_site_attributes.rb +15 -0
- data/db/migrate/039_default_position.rb +10 -0
- data/db/migrate/040_second_value_for_data_entry.rb +11 -0
- data/db/migrate/041_add_attributes_to_v_class.rb +9 -0
- data/db/migrate/042_fix_position_should_be_float.rb +8 -0
- data/db/migrate/043_move_user_lang_into_participation.rb +15 -0
- data/db/migrate/044_remove_monolingual_site_option.rb +9 -0
- data/db/migrate/045_avoid_star_in_templates.rb +13 -0
- data/db/migrate/046_fix_zazen_image_tag.rb +47 -0
- data/db/migrate/047_change_default_link_id_to_zero.rb +12 -0
- data/db/migrate/048_link_source_target_can_be_null.rb +11 -0
- data/db/migrate/049_fix_publish_from_is_null.rb +9 -0
- data/db/migrate/050_date_in_links.rb +9 -0
- data/db/migrate/051_add_exif_tags_to_images.rb +9 -0
- data/db/migrate/20090825201159_insert_zero_link.rb +8 -0
- data/db/migrate/20090825201200_merge_bricks_migrations_with_std_migrations.rb +19 -0
- data/db/migrate/20090924141459_zafu_fix_sept09.rb +19 -0
- data/db/migrate/20090927125912_allow_null_in_text_fields.rb +17 -0
- data/db/migrate/20090928133440_no_more_private_nodes.rb +25 -0
- data/db/migrate/20090928143754_version_status_change.rb +24 -0
- data/db/migrate/20091001084025_change_status_values_for_comments.rb +22 -0
- data/db/migrate/20091009084057_add_vhash_in_node.rb +13 -0
- data/db/migrate/20091013100351_rename_publish_group_to_drive_group.rb +12 -0
- data/db/migrate/20091014130833_fix_template_title.rb +16 -0
- data/db/migrate/20091014183726_merge_participation_into_users.rb +21 -0
- data/db/production.sqlite3 +0 -0
- data/db/schema.rb +281 -0
- data/lib/base_additions.rb +7 -0
- data/lib/bricks/patcher.rb +68 -0
- data/lib/comment_query.rb +92 -0
- data/lib/core_ext/date_time.rb +5 -0
- data/lib/core_ext/dir.rb +12 -0
- data/lib/core_ext/fixnum.rb +20 -0
- data/lib/core_ext/string.rb +74 -0
- data/lib/exif_data.rb +54 -0
- data/lib/fix_rails_layouts.rb +9 -0
- data/lib/gettext_strings.rb +160 -0
- data/lib/image_builder.rb +325 -0
- data/lib/log_recorder/lib/log_recorder.rb +138 -0
- data/lib/log_recorder/test/log_recorder_test.rb +0 -0
- data/lib/parser.rb +1 -0
- data/lib/tasks/capistrano.rake +99 -0
- data/lib/tasks/zena.rake +358 -0
- data/lib/tasks/zena.rb +2 -0
- data/lib/upload_progress_server.rb +24 -0
- data/lib/webdav_adapter.rb +172 -0
- data/lib/zafu_parser.rb +3 -0
- data/lib/zazen_parser.rb +1 -0
- data/lib/zena.rb +398 -0
- data/lib/zena/acts/multiversion.rb +755 -0
- data/lib/zena/acts/secure.rb +774 -0
- data/lib/zena/app.rb +39 -0
- data/lib/zena/code_syntax.rb +275 -0
- data/lib/zena/controller/test_case.rb +32 -0
- data/lib/zena/db.rb +252 -0
- data/lib/zena/fix/mysql_connection.rb +17 -0
- data/lib/zena/foxy_parser.rb +845 -0
- data/lib/zena/migrator.rb +109 -0
- data/lib/zena/parser.rb +601 -0
- data/lib/zena/parser/zafu_rules.rb +232 -0
- data/lib/zena/parser/zafu_tags.rb +197 -0
- data/lib/zena/parser/zazen_rules.rb +427 -0
- data/lib/zena/parser/zazen_tags.rb +44 -0
- data/lib/zena/parser/zena_rules.rb +29 -0
- data/lib/zena/parser/zena_tags.rb +3559 -0
- data/lib/zena/root.rb +3 -0
- data/lib/zena/routes.rb +73 -0
- data/lib/zena/test_controller.rb +74 -0
- data/lib/zena/unit/test_case.rb +24 -0
- data/lib/zena/use/ajax.rb +119 -0
- data/lib/zena/use/authentification.rb +120 -0
- data/lib/zena/use/calendar.rb +130 -0
- data/lib/zena/use/custom_queries/complex.host.yml +173 -0
- data/lib/zena/use/dates.rb +230 -0
- data/lib/zena/use/dyn_attributes.rb +256 -0
- data/lib/zena/use/error_rendering.rb +52 -0
- data/lib/zena/use/fixtures.rb +133 -0
- data/lib/zena/use/grid.rb +148 -0
- data/lib/zena/use/html_tags.rb +603 -0
- data/lib/zena/use/i18n.rb +247 -0
- data/lib/zena/use/nested_attributes_alias.rb +201 -0
- data/lib/zena/use/node_query_finders.rb +491 -0
- data/lib/zena/use/refactor.rb +231 -0
- data/lib/zena/use/relations.rb +360 -0
- data/lib/zena/use/rendering.rb +248 -0
- data/lib/zena/use/test_helper.rb +151 -0
- data/lib/zena/use/urls.rb +180 -0
- data/lib/zena/use/zafu.rb +549 -0
- data/lib/zena/use/zazen.rb +230 -0
- data/lib/zena/view/test_case.rb +23 -0
- data/locale/en/LC_MESSAGES/zena.mo +0 -0
- data/locale/en/zena.po +2116 -0
- data/locale/fr/LC_MESSAGES/zena.mo +0 -0
- data/locale/fr/zena.po +2172 -0
- data/locale/zena.pot +1915 -0
- data/public/calendar/calendar-brown.css +225 -0
- data/public/calendar/calendar-setup.js +153 -0
- data/public/calendar/calendar.js +1817 -0
- data/public/calendar/iconCalendar.gif +0 -0
- data/public/calendar/lang/calendar-en-utf8.js +128 -0
- data/public/calendar/lang/calendar-fr-utf8.js +120 -0
- data/public/calendar/lang/lang.zip +0 -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/accept.png +0 -0
- data/public/images/action.png +0 -0
- data/public/images/add.png +0 -0
- data/public/images/ajax-loader.gif +0 -0
- data/public/images/anchor.png +0 -0
- data/public/images/application.png +0 -0
- data/public/images/application_add.png +0 -0
- data/public/images/application_cascade.png +0 -0
- data/public/images/application_delete.png +0 -0
- data/public/images/application_double.png +0 -0
- data/public/images/application_edit.png +0 -0
- data/public/images/application_error.png +0 -0
- data/public/images/application_form.png +0 -0
- data/public/images/application_form_add.png +0 -0
- data/public/images/application_form_delete.png +0 -0
- data/public/images/application_form_edit.png +0 -0
- data/public/images/application_form_magnify.png +0 -0
- data/public/images/application_get.png +0 -0
- data/public/images/application_go.png +0 -0
- data/public/images/application_home.png +0 -0
- data/public/images/application_key.png +0 -0
- data/public/images/application_lightning.png +0 -0
- data/public/images/application_link.png +0 -0
- data/public/images/application_osx.png +0 -0
- data/public/images/application_osx_terminal.png +0 -0
- data/public/images/application_put.png +0 -0
- data/public/images/application_side_boxes.png +0 -0
- data/public/images/application_side_contract.png +0 -0
- data/public/images/application_side_expand.png +0 -0
- data/public/images/application_side_list.png +0 -0
- data/public/images/application_side_tree.png +0 -0
- data/public/images/application_split.png +0 -0
- data/public/images/application_tile_horizontal.png +0 -0
- data/public/images/application_tile_vertical.png +0 -0
- data/public/images/application_view_columns.png +0 -0
- data/public/images/application_view_detail.png +0 -0
- data/public/images/application_view_gallery.png +0 -0
- data/public/images/application_view_icons.png +0 -0
- data/public/images/application_view_list.png +0 -0
- data/public/images/application_view_tile.png +0 -0
- data/public/images/application_xp.png +0 -0
- data/public/images/application_xp_terminal.png +0 -0
- data/public/images/arrow_branch.png +0 -0
- data/public/images/arrow_divide.png +0 -0
- data/public/images/arrow_down.png +0 -0
- data/public/images/arrow_in.png +0 -0
- data/public/images/arrow_inout.png +0 -0
- data/public/images/arrow_join.png +0 -0
- data/public/images/arrow_left.png +0 -0
- data/public/images/arrow_merge.png +0 -0
- data/public/images/arrow_out.png +0 -0
- data/public/images/arrow_redo.png +0 -0
- data/public/images/arrow_refresh.png +0 -0
- data/public/images/arrow_refresh_small.png +0 -0
- data/public/images/arrow_right.png +0 -0
- data/public/images/arrow_rotate_anticlockwise.png +0 -0
- data/public/images/arrow_rotate_clockwise.png +0 -0
- data/public/images/arrow_switch.png +0 -0
- data/public/images/arrow_turn_left.png +0 -0
- data/public/images/arrow_turn_right.png +0 -0
- data/public/images/arrow_undo.png +0 -0
- data/public/images/arrow_up.png +0 -0
- data/public/images/asterisk_orange.png +0 -0
- data/public/images/asterisk_yellow.png +0 -0
- data/public/images/attach.png +0 -0
- data/public/images/award_star_add.png +0 -0
- data/public/images/award_star_bronze_1.png +0 -0
- data/public/images/award_star_bronze_2.png +0 -0
- data/public/images/award_star_bronze_3.png +0 -0
- data/public/images/award_star_delete.png +0 -0
- data/public/images/award_star_gold_1.png +0 -0
- data/public/images/award_star_gold_2.png +0 -0
- data/public/images/award_star_gold_3.png +0 -0
- data/public/images/award_star_silver_1.png +0 -0
- data/public/images/award_star_silver_2.png +0 -0
- data/public/images/award_star_silver_3.png +0 -0
- data/public/images/basket.png +0 -0
- data/public/images/basket_add.png +0 -0
- data/public/images/basket_delete.png +0 -0
- data/public/images/basket_edit.png +0 -0
- data/public/images/basket_error.png +0 -0
- data/public/images/basket_go.png +0 -0
- data/public/images/basket_put.png +0 -0
- data/public/images/basket_remove.png +0 -0
- data/public/images/bell.png +0 -0
- data/public/images/bell_add.png +0 -0
- data/public/images/bell_delete.png +0 -0
- data/public/images/bell_error.png +0 -0
- data/public/images/bell_go.png +0 -0
- data/public/images/bell_link.png +0 -0
- data/public/images/bin.png +0 -0
- data/public/images/bin_closed.png +0 -0
- data/public/images/bin_empty.gif +0 -0
- data/public/images/bin_empty.png +0 -0
- data/public/images/bin_full.gif +0 -0
- data/public/images/bomb.png +0 -0
- data/public/images/book.png +0 -0
- data/public/images/book_add.png +0 -0
- data/public/images/book_addresses.png +0 -0
- data/public/images/book_delete.png +0 -0
- data/public/images/book_edit.png +0 -0
- data/public/images/book_error.png +0 -0
- data/public/images/book_go.png +0 -0
- data/public/images/book_key.png +0 -0
- data/public/images/book_link.png +0 -0
- data/public/images/book_next.png +0 -0
- data/public/images/book_open.png +0 -0
- data/public/images/book_previous.png +0 -0
- data/public/images/box.png +0 -0
- data/public/images/brick.png +0 -0
- data/public/images/brick_add.png +0 -0
- data/public/images/brick_delete.png +0 -0
- data/public/images/brick_edit.png +0 -0
- data/public/images/brick_error.png +0 -0
- data/public/images/brick_go.png +0 -0
- data/public/images/brick_link.png +0 -0
- data/public/images/bricks.png +0 -0
- data/public/images/briefcase.png +0 -0
- data/public/images/bug.png +0 -0
- data/public/images/bug_add.png +0 -0
- data/public/images/bug_delete.png +0 -0
- data/public/images/bug_edit.png +0 -0
- data/public/images/bug_error.png +0 -0
- data/public/images/bug_go.png +0 -0
- data/public/images/bug_link.png +0 -0
- data/public/images/building.png +0 -0
- data/public/images/building_add.png +0 -0
- data/public/images/building_delete.png +0 -0
- data/public/images/building_edit.png +0 -0
- data/public/images/building_error.png +0 -0
- data/public/images/building_go.png +0 -0
- data/public/images/building_key.png +0 -0
- data/public/images/building_link.png +0 -0
- data/public/images/bullet_add.png +0 -0
- data/public/images/bullet_arrow_bottom.png +0 -0
- data/public/images/bullet_arrow_down.png +0 -0
- data/public/images/bullet_arrow_top.png +0 -0
- data/public/images/bullet_arrow_up.png +0 -0
- data/public/images/bullet_black.png +0 -0
- data/public/images/bullet_blue.png +0 -0
- data/public/images/bullet_delete.png +0 -0
- data/public/images/bullet_disk.png +0 -0
- data/public/images/bullet_error.png +0 -0
- data/public/images/bullet_feed.png +0 -0
- data/public/images/bullet_go.png +0 -0
- data/public/images/bullet_green.png +0 -0
- data/public/images/bullet_key.png +0 -0
- data/public/images/bullet_orange.png +0 -0
- data/public/images/bullet_picture.png +0 -0
- data/public/images/bullet_pink.png +0 -0
- data/public/images/bullet_purple.png +0 -0
- data/public/images/bullet_red.png +0 -0
- data/public/images/bullet_star.png +0 -0
- data/public/images/bullet_toggle_minus.png +0 -0
- data/public/images/bullet_toggle_plus.png +0 -0
- data/public/images/bullet_white.png +0 -0
- data/public/images/bullet_wrench.png +0 -0
- data/public/images/bullet_yellow.png +0 -0
- data/public/images/cake.png +0 -0
- data/public/images/calculator.png +0 -0
- data/public/images/calculator_add.png +0 -0
- data/public/images/calculator_delete.png +0 -0
- data/public/images/calculator_edit.png +0 -0
- data/public/images/calculator_error.png +0 -0
- data/public/images/calculator_link.png +0 -0
- data/public/images/calendar.png +0 -0
- data/public/images/calendar_add.png +0 -0
- data/public/images/calendar_delete.png +0 -0
- data/public/images/calendar_edit.png +0 -0
- data/public/images/calendar_link.png +0 -0
- data/public/images/calendar_view_day.png +0 -0
- data/public/images/calendar_view_month.png +0 -0
- data/public/images/calendar_view_week.png +0 -0
- data/public/images/camera.png +0 -0
- data/public/images/camera_add.png +0 -0
- data/public/images/camera_delete.png +0 -0
- data/public/images/camera_edit.png +0 -0
- data/public/images/camera_error.png +0 -0
- data/public/images/camera_go.png +0 -0
- data/public/images/camera_link.png +0 -0
- data/public/images/camera_small.png +0 -0
- data/public/images/cancel.png +0 -0
- data/public/images/car.png +0 -0
- data/public/images/car_add.png +0 -0
- data/public/images/car_delete.png +0 -0
- data/public/images/cart.png +0 -0
- data/public/images/cart_add.png +0 -0
- data/public/images/cart_delete.png +0 -0
- data/public/images/cart_edit.png +0 -0
- data/public/images/cart_error.png +0 -0
- data/public/images/cart_go.png +0 -0
- data/public/images/cart_put.png +0 -0
- data/public/images/cart_remove.png +0 -0
- data/public/images/cd.png +0 -0
- data/public/images/cd_add.png +0 -0
- data/public/images/cd_burn.png +0 -0
- data/public/images/cd_delete.png +0 -0
- data/public/images/cd_edit.png +0 -0
- data/public/images/cd_eject.png +0 -0
- data/public/images/cd_go.png +0 -0
- data/public/images/chart_bar.png +0 -0
- data/public/images/chart_bar_add.png +0 -0
- data/public/images/chart_bar_delete.png +0 -0
- data/public/images/chart_bar_edit.png +0 -0
- data/public/images/chart_bar_error.png +0 -0
- data/public/images/chart_bar_link.png +0 -0
- data/public/images/chart_curve.png +0 -0
- data/public/images/chart_curve_add.png +0 -0
- data/public/images/chart_curve_delete.png +0 -0
- data/public/images/chart_curve_edit.png +0 -0
- data/public/images/chart_curve_error.png +0 -0
- data/public/images/chart_curve_go.png +0 -0
- data/public/images/chart_curve_link.png +0 -0
- data/public/images/chart_line.png +0 -0
- data/public/images/chart_line_add.png +0 -0
- data/public/images/chart_line_delete.png +0 -0
- data/public/images/chart_line_edit.png +0 -0
- data/public/images/chart_line_error.png +0 -0
- data/public/images/chart_line_link.png +0 -0
- data/public/images/chart_organisation.png +0 -0
- data/public/images/chart_organisation_add.png +0 -0
- data/public/images/chart_organisation_delete.png +0 -0
- data/public/images/chart_pie.png +0 -0
- data/public/images/chart_pie_add.png +0 -0
- data/public/images/chart_pie_delete.png +0 -0
- data/public/images/chart_pie_edit.png +0 -0
- data/public/images/chart_pie_error.png +0 -0
- data/public/images/chart_pie_link.png +0 -0
- data/public/images/clock.png +0 -0
- data/public/images/clock_add.png +0 -0
- data/public/images/clock_delete.png +0 -0
- data/public/images/clock_edit.png +0 -0
- data/public/images/clock_error.png +0 -0
- data/public/images/clock_go.png +0 -0
- data/public/images/clock_link.png +0 -0
- data/public/images/clock_pause.png +0 -0
- data/public/images/clock_play.png +0 -0
- data/public/images/clock_red.png +0 -0
- data/public/images/clock_stop.png +0 -0
- data/public/images/cog.png +0 -0
- data/public/images/cog_add.png +0 -0
- data/public/images/cog_delete.png +0 -0
- data/public/images/cog_edit.png +0 -0
- data/public/images/cog_error.png +0 -0
- data/public/images/cog_go.png +0 -0
- data/public/images/coins.png +0 -0
- data/public/images/coins_add.png +0 -0
- data/public/images/coins_delete.png +0 -0
- data/public/images/collection.png +0 -0
- data/public/images/color_swatch.png +0 -0
- data/public/images/color_wheel.png +0 -0
- data/public/images/column_add.png +0 -0
- data/public/images/column_delete.png +0 -0
- data/public/images/comment.png +0 -0
- data/public/images/comment_add.png +0 -0
- data/public/images/comment_delete.png +0 -0
- data/public/images/comment_edit.png +0 -0
- data/public/images/comments.png +0 -0
- data/public/images/comments_add.png +0 -0
- data/public/images/comments_delete.png +0 -0
- data/public/images/comments_red.png +0 -0
- data/public/images/compress.png +0 -0
- data/public/images/computer.png +0 -0
- data/public/images/computer_add.png +0 -0
- data/public/images/computer_delete.png +0 -0
- data/public/images/computer_edit.png +0 -0
- data/public/images/computer_error.png +0 -0
- data/public/images/computer_go.png +0 -0
- data/public/images/computer_key.png +0 -0
- data/public/images/computer_link.png +0 -0
- data/public/images/connect.png +0 -0
- data/public/images/contrast.png +0 -0
- data/public/images/contrast_decrease.png +0 -0
- data/public/images/contrast_high.png +0 -0
- data/public/images/contrast_increase.png +0 -0
- data/public/images/contrast_low.png +0 -0
- data/public/images/control_eject.png +0 -0
- data/public/images/control_eject_blue.png +0 -0
- data/public/images/control_end.png +0 -0
- data/public/images/control_end_blue.png +0 -0
- data/public/images/control_equalizer.png +0 -0
- data/public/images/control_equalizer_blue.png +0 -0
- data/public/images/control_fastforward.png +0 -0
- data/public/images/control_fastforward_blue.png +0 -0
- data/public/images/control_pause.png +0 -0
- data/public/images/control_pause_blue.png +0 -0
- data/public/images/control_play.png +0 -0
- data/public/images/control_play_blue.png +0 -0
- data/public/images/control_repeat.png +0 -0
- data/public/images/control_repeat_blue.png +0 -0
- data/public/images/control_rewind.png +0 -0
- data/public/images/control_rewind_blue.png +0 -0
- data/public/images/control_start.png +0 -0
- data/public/images/control_start_blue.png +0 -0
- data/public/images/control_stop.png +0 -0
- data/public/images/control_stop_blue.png +0 -0
- data/public/images/controller.png +0 -0
- data/public/images/controller_add.png +0 -0
- data/public/images/controller_delete.png +0 -0
- data/public/images/controller_error.png +0 -0
- data/public/images/creditcards.png +0 -0
- data/public/images/cross.png +0 -0
- data/public/images/css.png +0 -0
- data/public/images/css_add.png +0 -0
- data/public/images/css_delete.png +0 -0
- data/public/images/css_go.png +0 -0
- data/public/images/css_valid.png +0 -0
- data/public/images/cup.png +0 -0
- data/public/images/cup_add.png +0 -0
- data/public/images/cup_delete.png +0 -0
- data/public/images/cup_edit.png +0 -0
- data/public/images/cup_error.png +0 -0
- data/public/images/cup_go.png +0 -0
- data/public/images/cup_key.png +0 -0
- data/public/images/cup_link.png +0 -0
- data/public/images/cursor.png +0 -0
- data/public/images/cut.png +0 -0
- data/public/images/cut_red.png +0 -0
- data/public/images/database.png +0 -0
- data/public/images/database_add.png +0 -0
- data/public/images/database_connect.png +0 -0
- data/public/images/database_delete.png +0 -0
- data/public/images/database_edit.png +0 -0
- data/public/images/database_error.png +0 -0
- data/public/images/database_gear.png +0 -0
- data/public/images/database_go.png +0 -0
- data/public/images/database_key.png +0 -0
- data/public/images/database_lightning.png +0 -0
- data/public/images/database_link.png +0 -0
- data/public/images/database_refresh.png +0 -0
- data/public/images/database_save.png +0 -0
- data/public/images/database_table.png +0 -0
- data/public/images/date.png +0 -0
- data/public/images/date_add.png +0 -0
- data/public/images/date_delete.png +0 -0
- data/public/images/date_edit.png +0 -0
- data/public/images/date_error.png +0 -0
- data/public/images/date_go.png +0 -0
- data/public/images/date_link.png +0 -0
- data/public/images/date_magnify.png +0 -0
- data/public/images/date_next.png +0 -0
- data/public/images/date_previous.png +0 -0
- data/public/images/delete.png +0 -0
- data/public/images/disconnect.png +0 -0
- data/public/images/disk.png +0 -0
- data/public/images/disk_multiple.png +0 -0
- data/public/images/door.png +0 -0
- data/public/images/door_in.png +0 -0
- data/public/images/door_open.png +0 -0
- data/public/images/door_out.png +0 -0
- data/public/images/drink.png +0 -0
- data/public/images/drink_empty.png +0 -0
- data/public/images/drive.png +0 -0
- data/public/images/drive_add.png +0 -0
- data/public/images/drive_burn.png +0 -0
- data/public/images/drive_cd.png +0 -0
- data/public/images/drive_cd_empty.png +0 -0
- data/public/images/drive_delete.png +0 -0
- data/public/images/drive_disk.png +0 -0
- data/public/images/drive_edit.png +0 -0
- data/public/images/drive_error.png +0 -0
- data/public/images/drive_go.png +0 -0
- data/public/images/drive_key.png +0 -0
- data/public/images/drive_link.png +0 -0
- data/public/images/drive_magnify.png +0 -0
- data/public/images/drive_network.png +0 -0
- data/public/images/drive_rename.png +0 -0
- data/public/images/drive_user.png +0 -0
- data/public/images/drive_web.png +0 -0
- data/public/images/dvd.png +0 -0
- data/public/images/dvd_add.png +0 -0
- data/public/images/dvd_delete.png +0 -0
- data/public/images/dvd_edit.png +0 -0
- data/public/images/dvd_error.png +0 -0
- data/public/images/dvd_go.png +0 -0
- data/public/images/dvd_key.png +0 -0
- data/public/images/dvd_link.png +0 -0
- data/public/images/email.png +0 -0
- data/public/images/email_add.png +0 -0
- data/public/images/email_attach.png +0 -0
- data/public/images/email_delete.png +0 -0
- data/public/images/email_edit.png +0 -0
- data/public/images/email_error.png +0 -0
- data/public/images/email_go.png +0 -0
- data/public/images/email_link.png +0 -0
- data/public/images/email_open.png +0 -0
- data/public/images/email_open_image.png +0 -0
- data/public/images/emoticon_evilgrin.png +0 -0
- data/public/images/emoticon_grin.png +0 -0
- data/public/images/emoticon_happy.png +0 -0
- data/public/images/emoticon_smile.png +0 -0
- data/public/images/emoticon_surprised.png +0 -0
- data/public/images/emoticon_tongue.png +0 -0
- data/public/images/emoticon_unhappy.png +0 -0
- data/public/images/emoticon_waii.png +0 -0
- data/public/images/emoticon_wink.png +0 -0
- data/public/images/error.png +0 -0
- data/public/images/error_add.png +0 -0
- data/public/images/error_delete.png +0 -0
- data/public/images/error_go.png +0 -0
- data/public/images/exclamation.png +0 -0
- data/public/images/ext/contact.png +0 -0
- data/public/images/ext/contact_pv.png +0 -0
- data/public/images/ext/doc.png +0 -0
- data/public/images/ext/doc_tiny.png +0 -0
- data/public/images/ext/jpg.png +0 -0
- data/public/images/ext/jpg_tiny.png +0 -0
- data/public/images/ext/other.png +0 -0
- data/public/images/ext/other_pv.png +0 -0
- data/public/images/ext/other_tiny.png +0 -0
- data/public/images/ext/page.png +0 -0
- data/public/images/ext/page_pv.png +0 -0
- data/public/images/ext/page_tiny.png +0 -0
- data/public/images/ext/pdf.png +0 -0
- data/public/images/ext/pdf_pv.png +0 -0
- data/public/images/ext/pdf_tiny.png +0 -0
- data/public/images/ext/png.png +0 -0
- data/public/images/ext/png_tiny.png +0 -0
- data/public/images/ext/post.png +0 -0
- data/public/images/ext/post_pv.png +0 -0
- data/public/images/ext/post_tiny.png +0 -0
- data/public/images/ext/project.png +0 -0
- data/public/images/ext/project_pv.png +0 -0
- data/public/images/ext/project_tiny.png +0 -0
- data/public/images/ext/rtf.png +0 -0
- data/public/images/ext/rtf_tiny.png +0 -0
- data/public/images/ext/tag.png +0 -0
- data/public/images/ext/tag_pv.png +0 -0
- data/public/images/ext/xls.png +0 -0
- data/public/images/ext/xls_tiny.png +0 -0
- data/public/images/ext/zip.png +0 -0
- data/public/images/ext/zip_pv.png +0 -0
- data/public/images/ext/zip_tiny.png +0 -0
- data/public/images/eye.png +0 -0
- data/public/images/feed.png +0 -0
- data/public/images/feed_add.png +0 -0
- data/public/images/feed_delete.png +0 -0
- data/public/images/feed_disk.png +0 -0
- data/public/images/feed_edit.png +0 -0
- data/public/images/feed_error.png +0 -0
- data/public/images/feed_go.png +0 -0
- data/public/images/feed_key.png +0 -0
- data/public/images/feed_link.png +0 -0
- data/public/images/feed_magnify.png +0 -0
- data/public/images/female.png +0 -0
- data/public/images/film.png +0 -0
- data/public/images/film_add.png +0 -0
- data/public/images/film_delete.png +0 -0
- data/public/images/film_edit.png +0 -0
- data/public/images/film_error.png +0 -0
- data/public/images/film_go.png +0 -0
- data/public/images/film_key.png +0 -0
- data/public/images/film_link.png +0 -0
- data/public/images/film_save.png +0 -0
- data/public/images/find.png +0 -0
- data/public/images/flag_blue.png +0 -0
- data/public/images/flag_green.png +0 -0
- data/public/images/flag_orange.png +0 -0
- data/public/images/flag_pink.png +0 -0
- data/public/images/flag_purple.png +0 -0
- data/public/images/flag_red.png +0 -0
- data/public/images/flag_yellow.png +0 -0
- data/public/images/folder.png +0 -0
- data/public/images/folder_add.png +0 -0
- data/public/images/folder_bell.png +0 -0
- data/public/images/folder_brick.png +0 -0
- data/public/images/folder_bug.png +0 -0
- data/public/images/folder_camera.png +0 -0
- data/public/images/folder_database.png +0 -0
- data/public/images/folder_delete.png +0 -0
- data/public/images/folder_edit.png +0 -0
- data/public/images/folder_error.png +0 -0
- data/public/images/folder_explore.png +0 -0
- data/public/images/folder_feed.png +0 -0
- data/public/images/folder_find.png +0 -0
- data/public/images/folder_go.png +0 -0
- data/public/images/folder_heart.png +0 -0
- data/public/images/folder_image.png +0 -0
- data/public/images/folder_key.png +0 -0
- data/public/images/folder_lightbulb.png +0 -0
- data/public/images/folder_link.png +0 -0
- data/public/images/folder_magnify.png +0 -0
- data/public/images/folder_page.png +0 -0
- data/public/images/folder_page_white.png +0 -0
- data/public/images/folder_palette.png +0 -0
- data/public/images/folder_picture.png +0 -0
- data/public/images/folder_star.png +0 -0
- data/public/images/folder_table.png +0 -0
- data/public/images/folder_user.png +0 -0
- data/public/images/folder_wrench.png +0 -0
- data/public/images/font.png +0 -0
- data/public/images/font_add.png +0 -0
- data/public/images/font_delete.png +0 -0
- data/public/images/font_go.png +0 -0
- data/public/images/group.png +0 -0
- data/public/images/group_add.png +0 -0
- data/public/images/group_admin.png +0 -0
- data/public/images/group_delete.png +0 -0
- data/public/images/group_edit.png +0 -0
- data/public/images/group_error.png +0 -0
- data/public/images/group_gear.png +0 -0
- data/public/images/group_go.png +0 -0
- data/public/images/group_key.png +0 -0
- data/public/images/group_link.png +0 -0
- data/public/images/group_pub.png +0 -0
- data/public/images/group_site.png +0 -0
- data/public/images/heart.png +0 -0
- data/public/images/heart_add.png +0 -0
- data/public/images/heart_delete.png +0 -0
- data/public/images/help.png +0 -0
- data/public/images/home.png +0 -0
- data/public/images/hourglass.png +0 -0
- data/public/images/hourglass_add.png +0 -0
- data/public/images/hourglass_delete.png +0 -0
- data/public/images/hourglass_go.png +0 -0
- data/public/images/hourglass_link.png +0 -0
- data/public/images/house.png +0 -0
- data/public/images/house_go.png +0 -0
- data/public/images/house_link.png +0 -0
- data/public/images/html.png +0 -0
- data/public/images/html_add.png +0 -0
- data/public/images/html_delete.png +0 -0
- data/public/images/html_go.png +0 -0
- data/public/images/html_valid.png +0 -0
- data/public/images/image.png +0 -0
- data/public/images/image_add.png +0 -0
- data/public/images/image_delete.png +0 -0
- data/public/images/image_edit.png +0 -0
- data/public/images/image_link.png +0 -0
- data/public/images/images.png +0 -0
- data/public/images/img_not_found.png +0 -0
- data/public/images/information.png +0 -0
- data/public/images/ipod.png +0 -0
- data/public/images/ipod_cast.png +0 -0
- data/public/images/ipod_cast_add.png +0 -0
- data/public/images/ipod_cast_delete.png +0 -0
- data/public/images/ipod_sound.png +0 -0
- data/public/images/joystick.png +0 -0
- data/public/images/joystick_add.png +0 -0
- data/public/images/joystick_delete.png +0 -0
- data/public/images/joystick_error.png +0 -0
- data/public/images/key.png +0 -0
- data/public/images/key_add.png +0 -0
- data/public/images/key_delete.png +0 -0
- data/public/images/key_go.png +0 -0
- data/public/images/keyboard.png +0 -0
- data/public/images/keyboard_add.png +0 -0
- data/public/images/keyboard_delete.png +0 -0
- data/public/images/keyboard_magnify.png +0 -0
- data/public/images/latex_error.png +0 -0
- data/public/images/layers.png +0 -0
- data/public/images/layout.png +0 -0
- data/public/images/layout_add.png +0 -0
- data/public/images/layout_content.png +0 -0
- data/public/images/layout_delete.png +0 -0
- data/public/images/layout_edit.png +0 -0
- data/public/images/layout_error.png +0 -0
- data/public/images/layout_header.png +0 -0
- data/public/images/layout_link.png +0 -0
- data/public/images/layout_sidebar.png +0 -0
- data/public/images/lightbulb.png +0 -0
- data/public/images/lightbulb_add.png +0 -0
- data/public/images/lightbulb_delete.png +0 -0
- data/public/images/lightbulb_off.png +0 -0
- data/public/images/lightning.png +0 -0
- data/public/images/lightning_add.png +0 -0
- data/public/images/lightning_delete.png +0 -0
- data/public/images/lightning_go.png +0 -0
- data/public/images/link.png +0 -0
- data/public/images/link_add.png +0 -0
- data/public/images/link_break.png +0 -0
- data/public/images/link_delete.png +0 -0
- data/public/images/link_edit.png +0 -0
- data/public/images/link_error.png +0 -0
- data/public/images/link_go.png +0 -0
- data/public/images/lock.png +0 -0
- data/public/images/lock_add.png +0 -0
- data/public/images/lock_break.png +0 -0
- data/public/images/lock_delete.png +0 -0
- data/public/images/lock_edit.png +0 -0
- data/public/images/lock_go.png +0 -0
- data/public/images/lock_open.png +0 -0
- data/public/images/lorry.png +0 -0
- data/public/images/lorry_add.png +0 -0
- data/public/images/lorry_delete.png +0 -0
- data/public/images/lorry_error.png +0 -0
- data/public/images/lorry_flatbed.png +0 -0
- data/public/images/lorry_go.png +0 -0
- data/public/images/lorry_link.png +0 -0
- data/public/images/magifier_zoom_out.png +0 -0
- data/public/images/magnifier.png +0 -0
- data/public/images/magnifier_zoom_in.png +0 -0
- data/public/images/male.png +0 -0
- data/public/images/map.png +0 -0
- data/public/images/map_add.png +0 -0
- data/public/images/map_delete.png +0 -0
- data/public/images/map_edit.png +0 -0
- data/public/images/map_go.png +0 -0
- data/public/images/map_magnify.png +0 -0
- data/public/images/medal_bronze_1.png +0 -0
- data/public/images/medal_bronze_2.png +0 -0
- data/public/images/medal_bronze_3.png +0 -0
- data/public/images/medal_bronze_add.png +0 -0
- data/public/images/medal_bronze_delete.png +0 -0
- data/public/images/medal_gold_1.png +0 -0
- data/public/images/medal_gold_2.png +0 -0
- data/public/images/medal_gold_3.png +0 -0
- data/public/images/medal_gold_add.png +0 -0
- data/public/images/medal_gold_delete.png +0 -0
- data/public/images/medal_silver_1.png +0 -0
- data/public/images/medal_silver_2.png +0 -0
- data/public/images/medal_silver_3.png +0 -0
- data/public/images/medal_silver_add.png +0 -0
- data/public/images/medal_silver_delete.png +0 -0
- data/public/images/money.png +0 -0
- data/public/images/money_add.png +0 -0
- data/public/images/money_delete.png +0 -0
- data/public/images/money_dollar.png +0 -0
- data/public/images/money_euro.png +0 -0
- data/public/images/money_pound.png +0 -0
- data/public/images/money_yen.png +0 -0
- data/public/images/monitor.png +0 -0
- data/public/images/monitor_add.png +0 -0
- data/public/images/monitor_delete.png +0 -0
- data/public/images/monitor_edit.png +0 -0
- data/public/images/monitor_error.png +0 -0
- data/public/images/monitor_go.png +0 -0
- data/public/images/monitor_lightning.png +0 -0
- data/public/images/monitor_link.png +0 -0
- data/public/images/mouse.png +0 -0
- data/public/images/mouse_add.png +0 -0
- data/public/images/mouse_delete.png +0 -0
- data/public/images/mouse_error.png +0 -0
- data/public/images/music.png +0 -0
- data/public/images/new.png +0 -0
- data/public/images/newspaper.png +0 -0
- data/public/images/newspaper_add.png +0 -0
- data/public/images/newspaper_delete.png +0 -0
- data/public/images/newspaper_go.png +0 -0
- data/public/images/newspaper_link.png +0 -0
- data/public/images/note.png +0 -0
- data/public/images/note_add.png +0 -0
- data/public/images/note_delete.png +0 -0
- data/public/images/note_edit.png +0 -0
- data/public/images/note_error.png +0 -0
- data/public/images/note_go.png +0 -0
- data/public/images/overlays.png +0 -0
- data/public/images/package.png +0 -0
- data/public/images/package_add.png +0 -0
- data/public/images/package_delete.png +0 -0
- data/public/images/package_go.png +0 -0
- data/public/images/package_green.png +0 -0
- data/public/images/package_link.png +0 -0
- data/public/images/page.png +0 -0
- data/public/images/page_add.png +0 -0
- data/public/images/page_attach.png +0 -0
- data/public/images/page_code.png +0 -0
- data/public/images/page_copy.png +0 -0
- data/public/images/page_delete.png +0 -0
- data/public/images/page_edit.png +0 -0
- data/public/images/page_error.png +0 -0
- data/public/images/page_excel.png +0 -0
- data/public/images/page_find.png +0 -0
- data/public/images/page_gear.png +0 -0
- data/public/images/page_go.png +0 -0
- data/public/images/page_green.png +0 -0
- data/public/images/page_key.png +0 -0
- data/public/images/page_lightning.png +0 -0
- data/public/images/page_link.png +0 -0
- data/public/images/page_paintbrush.png +0 -0
- data/public/images/page_paste.png +0 -0
- data/public/images/page_red.png +0 -0
- data/public/images/page_refresh.png +0 -0
- data/public/images/page_save.png +0 -0
- data/public/images/page_white.png +0 -0
- data/public/images/page_white_acrobat.png +0 -0
- data/public/images/page_white_actionscript.png +0 -0
- data/public/images/page_white_add.png +0 -0
- data/public/images/page_white_c.png +0 -0
- data/public/images/page_white_camera.png +0 -0
- data/public/images/page_white_cd.png +0 -0
- data/public/images/page_white_code.png +0 -0
- data/public/images/page_white_code_red.png +0 -0
- data/public/images/page_white_coldfusion.png +0 -0
- data/public/images/page_white_compressed.png +0 -0
- data/public/images/page_white_copy.png +0 -0
- data/public/images/page_white_cplusplus.png +0 -0
- data/public/images/page_white_csharp.png +0 -0
- data/public/images/page_white_cup.png +0 -0
- data/public/images/page_white_database.png +0 -0
- data/public/images/page_white_delete.png +0 -0
- data/public/images/page_white_dvd.png +0 -0
- data/public/images/page_white_edit.png +0 -0
- data/public/images/page_white_error.png +0 -0
- data/public/images/page_white_excel.png +0 -0
- data/public/images/page_white_find.png +0 -0
- data/public/images/page_white_flash.png +0 -0
- data/public/images/page_white_freehand.png +0 -0
- data/public/images/page_white_gear.png +0 -0
- data/public/images/page_white_get.png +0 -0
- data/public/images/page_white_go.png +0 -0
- data/public/images/page_white_h.png +0 -0
- data/public/images/page_white_horizontal.png +0 -0
- data/public/images/page_white_key.png +0 -0
- data/public/images/page_white_lightning.png +0 -0
- data/public/images/page_white_link.png +0 -0
- data/public/images/page_white_magnify.png +0 -0
- data/public/images/page_white_medal.png +0 -0
- data/public/images/page_white_office.png +0 -0
- data/public/images/page_white_paint.png +0 -0
- data/public/images/page_white_paintbrush.png +0 -0
- data/public/images/page_white_paste.png +0 -0
- data/public/images/page_white_php.png +0 -0
- data/public/images/page_white_picture.png +0 -0
- data/public/images/page_white_powerpoint.png +0 -0
- data/public/images/page_white_put.png +0 -0
- data/public/images/page_white_ruby.png +0 -0
- data/public/images/page_white_stack.png +0 -0
- data/public/images/page_white_star.png +0 -0
- data/public/images/page_white_swoosh.png +0 -0
- data/public/images/page_white_text.png +0 -0
- data/public/images/page_white_text_width.png +0 -0
- data/public/images/page_white_tux.png +0 -0
- data/public/images/page_white_vector.png +0 -0
- data/public/images/page_white_visualstudio.png +0 -0
- data/public/images/page_white_width.png +0 -0
- data/public/images/page_white_word.png +0 -0
- data/public/images/page_white_world.png +0 -0
- data/public/images/page_white_wrench.png +0 -0
- data/public/images/page_white_zip.png +0 -0
- data/public/images/page_word.png +0 -0
- data/public/images/page_world.png +0 -0
- data/public/images/paintbrush.png +0 -0
- data/public/images/paintcan.png +0 -0
- data/public/images/palette.png +0 -0
- data/public/images/paste_plain.png +0 -0
- data/public/images/paste_word.png +0 -0
- data/public/images/pencil.png +0 -0
- data/public/images/pencil_add.png +0 -0
- data/public/images/pencil_delete.png +0 -0
- data/public/images/pencil_go.png +0 -0
- data/public/images/phone.png +0 -0
- data/public/images/phone_add.png +0 -0
- data/public/images/phone_delete.png +0 -0
- data/public/images/phone_sound.png +0 -0
- data/public/images/photo.png +0 -0
- data/public/images/photo_add.png +0 -0
- data/public/images/photo_blue.png +0 -0
- data/public/images/photo_delete.png +0 -0
- data/public/images/photo_grey.png +0 -0
- data/public/images/photo_link.png +0 -0
- data/public/images/photos.png +0 -0
- data/public/images/picture.png +0 -0
- data/public/images/picture_add.png +0 -0
- data/public/images/picture_delete.png +0 -0
- data/public/images/picture_edit.png +0 -0
- data/public/images/picture_empty.png +0 -0
- data/public/images/picture_error.png +0 -0
- data/public/images/picture_go.png +0 -0
- data/public/images/picture_key.png +0 -0
- data/public/images/picture_link.png +0 -0
- data/public/images/picture_save.png +0 -0
- data/public/images/pictures.png +0 -0
- data/public/images/pilcrow.png +0 -0
- data/public/images/pill.png +0 -0
- data/public/images/pill_add.png +0 -0
- data/public/images/pill_delete.png +0 -0
- data/public/images/pill_go.png +0 -0
- data/public/images/plugin.png +0 -0
- data/public/images/plugin_add.png +0 -0
- data/public/images/plugin_delete.png +0 -0
- data/public/images/plugin_disabled.png +0 -0
- data/public/images/plugin_edit.png +0 -0
- data/public/images/plugin_error.png +0 -0
- data/public/images/plugin_go.png +0 -0
- data/public/images/plugin_link.png +0 -0
- data/public/images/printer.png +0 -0
- data/public/images/printer_add.png +0 -0
- data/public/images/printer_delete.png +0 -0
- data/public/images/printer_empty.png +0 -0
- data/public/images/printer_error.png +0 -0
- data/public/images/project.png +0 -0
- data/public/images/rails.png +0 -0
- data/public/images/rainbow.png +0 -0
- data/public/images/report.png +0 -0
- data/public/images/report_add.png +0 -0
- data/public/images/report_delete.png +0 -0
- data/public/images/report_disk.png +0 -0
- data/public/images/report_edit.png +0 -0
- data/public/images/report_go.png +0 -0
- data/public/images/report_key.png +0 -0
- data/public/images/report_link.png +0 -0
- data/public/images/report_magnify.png +0 -0
- data/public/images/report_picture.png +0 -0
- data/public/images/report_user.png +0 -0
- data/public/images/report_word.png +0 -0
- data/public/images/resultset_first.png +0 -0
- data/public/images/resultset_last.png +0 -0
- data/public/images/resultset_next.png +0 -0
- data/public/images/resultset_previous.png +0 -0
- data/public/images/rosette.png +0 -0
- data/public/images/row_add.png +0 -0
- data/public/images/row_delete.png +0 -0
- data/public/images/rss.png +0 -0
- data/public/images/rss_add.png +0 -0
- data/public/images/rss_delete.png +0 -0
- data/public/images/rss_go.png +0 -0
- data/public/images/rss_valid.png +0 -0
- data/public/images/ruby.png +0 -0
- data/public/images/ruby_add.png +0 -0
- data/public/images/ruby_delete.png +0 -0
- data/public/images/ruby_gear.png +0 -0
- data/public/images/ruby_get.png +0 -0
- data/public/images/ruby_go.png +0 -0
- data/public/images/ruby_key.png +0 -0
- data/public/images/ruby_link.png +0 -0
- data/public/images/ruby_put.png +0 -0
- data/public/images/script.png +0 -0
- data/public/images/script_add.png +0 -0
- data/public/images/script_code.png +0 -0
- data/public/images/script_code_red.png +0 -0
- data/public/images/script_delete.png +0 -0
- data/public/images/script_edit.png +0 -0
- data/public/images/script_error.png +0 -0
- data/public/images/script_gear.png +0 -0
- data/public/images/script_go.png +0 -0
- data/public/images/script_key.png +0 -0
- data/public/images/script_lightning.png +0 -0
- data/public/images/script_link.png +0 -0
- data/public/images/script_palette.png +0 -0
- data/public/images/script_save.png +0 -0
- data/public/images/server.png +0 -0
- data/public/images/server_add.png +0 -0
- data/public/images/server_chart.png +0 -0
- data/public/images/server_compressed.png +0 -0
- data/public/images/server_connect.png +0 -0
- data/public/images/server_database.png +0 -0
- data/public/images/server_delete.png +0 -0
- data/public/images/server_edit.png +0 -0
- data/public/images/server_error.png +0 -0
- data/public/images/server_go.png +0 -0
- data/public/images/server_key.png +0 -0
- data/public/images/server_lightning.png +0 -0
- data/public/images/server_link.png +0 -0
- data/public/images/server_uncompressed.png +0 -0
- data/public/images/shading.png +0 -0
- data/public/images/shape_align_bottom.png +0 -0
- data/public/images/shape_align_center.png +0 -0
- data/public/images/shape_align_left.png +0 -0
- data/public/images/shape_align_middle.png +0 -0
- data/public/images/shape_align_right.png +0 -0
- data/public/images/shape_align_top.png +0 -0
- data/public/images/shape_flip_horizontal.png +0 -0
- data/public/images/shape_flip_vertical.png +0 -0
- data/public/images/shape_group.png +0 -0
- data/public/images/shape_handles.png +0 -0
- data/public/images/shape_move_back.png +0 -0
- data/public/images/shape_move_backwards.png +0 -0
- data/public/images/shape_move_forwards.png +0 -0
- data/public/images/shape_move_front.png +0 -0
- data/public/images/shape_rotate_anticlockwise.png +0 -0
- data/public/images/shape_rotate_clockwise.png +0 -0
- data/public/images/shape_square.png +0 -0
- data/public/images/shape_square_add.png +0 -0
- data/public/images/shape_square_delete.png +0 -0
- data/public/images/shape_square_edit.png +0 -0
- data/public/images/shape_square_error.png +0 -0
- data/public/images/shape_square_go.png +0 -0
- data/public/images/shape_square_key.png +0 -0
- data/public/images/shape_square_link.png +0 -0
- data/public/images/shape_ungroup.png +0 -0
- data/public/images/shield.png +0 -0
- data/public/images/shield_add.png +0 -0
- data/public/images/shield_delete.png +0 -0
- data/public/images/shield_go.png +0 -0
- data/public/images/silk.html +1495 -0
- data/public/images/sitemap.png +0 -0
- data/public/images/sitemap_color.png +0 -0
- data/public/images/sound.png +0 -0
- data/public/images/sound_add.png +0 -0
- data/public/images/sound_delete.png +0 -0
- data/public/images/sound_low.png +0 -0
- data/public/images/sound_mute.png +0 -0
- data/public/images/sound_none.png +0 -0
- data/public/images/spellcheck.png +0 -0
- data/public/images/sport_8ball.png +0 -0
- data/public/images/sport_basketball.png +0 -0
- data/public/images/sport_football.png +0 -0
- data/public/images/sport_golf.png +0 -0
- data/public/images/sport_raquet.png +0 -0
- data/public/images/sport_shuttlecock.png +0 -0
- data/public/images/sport_soccer.png +0 -0
- data/public/images/sport_tennis.png +0 -0
- data/public/images/star.png +0 -0
- data/public/images/status_away.png +0 -0
- data/public/images/status_busy.png +0 -0
- data/public/images/status_offline.png +0 -0
- data/public/images/status_online.png +0 -0
- data/public/images/stop.png +0 -0
- data/public/images/style.png +0 -0
- data/public/images/style_add.png +0 -0
- data/public/images/style_delete.png +0 -0
- data/public/images/style_edit.png +0 -0
- data/public/images/style_go.png +0 -0
- data/public/images/sum.png +0 -0
- data/public/images/swf/xspf/Main.as +55 -0
- data/public/images/swf/xspf/com/zuardi/musicplayer/MusicButton.as +557 -0
- data/public/images/swf/xspf/com/zuardi/musicplayer/MusicPlayer.as +118 -0
- data/public/images/swf/xspf/com/zuardi/musicplayer/Playlist.as +127 -0
- data/public/images/swf/xspf/com/zuardi/musicplayer/ProgressiveSlider.as +66 -0
- data/public/images/swf/xspf/license.txt +10 -0
- data/public/images/swf/xspf/musicplayer.swf +0 -0
- data/public/images/swf/xspf/musicplayer_f6.swf +0 -0
- data/public/images/swf/xspf/musicplayerbtn.fla +0 -0
- data/public/images/swf/xspf/parameters.as +39 -0
- data/public/images/tab.png +0 -0
- data/public/images/tab_add.png +0 -0
- data/public/images/tab_delete.png +0 -0
- data/public/images/tab_edit.png +0 -0
- data/public/images/tab_go.png +0 -0
- data/public/images/table.png +0 -0
- data/public/images/table_add.png +0 -0
- data/public/images/table_delete.png +0 -0
- data/public/images/table_edit.png +0 -0
- data/public/images/table_error.png +0 -0
- data/public/images/table_gear.png +0 -0
- data/public/images/table_go.png +0 -0
- data/public/images/table_key.png +0 -0
- data/public/images/table_lightning.png +0 -0
- data/public/images/table_link.png +0 -0
- data/public/images/table_multiple.png +0 -0
- data/public/images/table_refresh.png +0 -0
- data/public/images/table_relationship.png +0 -0
- data/public/images/table_row_delete.png +0 -0
- data/public/images/table_row_insert.png +0 -0
- data/public/images/table_save.png +0 -0
- data/public/images/table_sort.png +0 -0
- data/public/images/tag.png +0 -0
- data/public/images/tag_blue.png +0 -0
- data/public/images/tag_blue_add.png +0 -0
- data/public/images/tag_blue_delete.png +0 -0
- data/public/images/tag_blue_edit.png +0 -0
- data/public/images/tag_green.png +0 -0
- data/public/images/tag_orange.png +0 -0
- data/public/images/tag_pink.png +0 -0
- data/public/images/tag_purple.png +0 -0
- data/public/images/tag_red.png +0 -0
- data/public/images/tag_yellow.png +0 -0
- data/public/images/target.png +0 -0
- data/public/images/telephone.png +0 -0
- data/public/images/telephone_add.png +0 -0
- data/public/images/telephone_delete.png +0 -0
- data/public/images/telephone_edit.png +0 -0
- data/public/images/telephone_error.png +0 -0
- data/public/images/telephone_go.png +0 -0
- data/public/images/telephone_key.png +0 -0
- data/public/images/telephone_link.png +0 -0
- data/public/images/television.png +0 -0
- data/public/images/television_add.png +0 -0
- data/public/images/television_delete.png +0 -0
- data/public/images/text_align_center.png +0 -0
- data/public/images/text_align_justify.png +0 -0
- data/public/images/text_align_left.png +0 -0
- data/public/images/text_align_right.png +0 -0
- data/public/images/text_allcaps.png +0 -0
- data/public/images/text_bold.png +0 -0
- data/public/images/text_columns.png +0 -0
- data/public/images/text_dropcaps.png +0 -0
- data/public/images/text_heading_1.png +0 -0
- data/public/images/text_heading_2.png +0 -0
- data/public/images/text_heading_3.png +0 -0
- data/public/images/text_heading_4.png +0 -0
- data/public/images/text_heading_5.png +0 -0
- data/public/images/text_heading_6.png +0 -0
- data/public/images/text_horizontalrule.png +0 -0
- data/public/images/text_indent.png +0 -0
- data/public/images/text_indent_remove.png +0 -0
- data/public/images/text_italic.png +0 -0
- data/public/images/text_kerning.png +0 -0
- data/public/images/text_letter_omega.png +0 -0
- data/public/images/text_letterspacing.png +0 -0
- data/public/images/text_linespacing.png +0 -0
- data/public/images/text_list_bullets.png +0 -0
- data/public/images/text_list_numbers.png +0 -0
- data/public/images/text_lowercase.png +0 -0
- data/public/images/text_padding_bottom.png +0 -0
- data/public/images/text_padding_left.png +0 -0
- data/public/images/text_padding_right.png +0 -0
- data/public/images/text_padding_top.png +0 -0
- data/public/images/text_replace.png +0 -0
- data/public/images/text_signature.png +0 -0
- data/public/images/text_smallcaps.png +0 -0
- data/public/images/text_strikethrough.png +0 -0
- data/public/images/text_subscript.png +0 -0
- data/public/images/text_superscript.png +0 -0
- data/public/images/text_underline.png +0 -0
- data/public/images/text_uppercase.png +0 -0
- data/public/images/textfield.png +0 -0
- data/public/images/textfield_add.png +0 -0
- data/public/images/textfield_delete.png +0 -0
- data/public/images/textfield_key.png +0 -0
- data/public/images/textfield_rename.png +0 -0
- data/public/images/thumb_down.png +0 -0
- data/public/images/thumb_up.png +0 -0
- data/public/images/tick.png +0 -0
- data/public/images/time.png +0 -0
- data/public/images/time_add.png +0 -0
- data/public/images/time_delete.png +0 -0
- data/public/images/time_go.png +0 -0
- data/public/images/timeline_marker.png +0 -0
- data/public/images/transmit.png +0 -0
- data/public/images/transmit_add.png +0 -0
- data/public/images/transmit_blue.png +0 -0
- data/public/images/transmit_delete.png +0 -0
- data/public/images/transmit_edit.png +0 -0
- data/public/images/transmit_error.png +0 -0
- data/public/images/transmit_go.png +0 -0
- data/public/images/tux.png +0 -0
- data/public/images/user.png +0 -0
- data/public/images/user_add.png +0 -0
- data/public/images/user_admin.png +0 -0
- data/public/images/user_comment.png +0 -0
- data/public/images/user_delete.png +0 -0
- data/public/images/user_edit.png +0 -0
- data/public/images/user_female.png +0 -0
- data/public/images/user_go.png +0 -0
- data/public/images/user_gray.png +0 -0
- data/public/images/user_green.png +0 -0
- data/public/images/user_orange.png +0 -0
- data/public/images/user_pub.png +0 -0
- data/public/images/user_red.png +0 -0
- data/public/images/user_su.png +0 -0
- data/public/images/user_suit.png +0 -0
- data/public/images/validate.png +0 -0
- data/public/images/valider.png +0 -0
- data/public/images/vcard.png +0 -0
- data/public/images/vcard_add.png +0 -0
- data/public/images/vcard_delete.png +0 -0
- data/public/images/vcard_edit.png +0 -0
- data/public/images/vector.png +0 -0
- data/public/images/vector_add.png +0 -0
- data/public/images/vector_delete.png +0 -0
- data/public/images/wand.png +0 -0
- data/public/images/weather_clouds.png +0 -0
- data/public/images/weather_cloudy.png +0 -0
- data/public/images/weather_lightning.png +0 -0
- data/public/images/weather_rain.png +0 -0
- data/public/images/weather_snow.png +0 -0
- data/public/images/weather_sun.png +0 -0
- data/public/images/webcam.png +0 -0
- data/public/images/webcam_add.png +0 -0
- data/public/images/webcam_delete.png +0 -0
- data/public/images/webcam_error.png +0 -0
- data/public/images/world.png +0 -0
- data/public/images/world_add.png +0 -0
- data/public/images/world_delete.png +0 -0
- data/public/images/world_edit.png +0 -0
- data/public/images/world_go.png +0 -0
- data/public/images/world_link.png +0 -0
- data/public/images/wrench.png +0 -0
- data/public/images/wrench_orange.png +0 -0
- data/public/images/xhtml.png +0 -0
- data/public/images/xhtml_add.png +0 -0
- data/public/images/xhtml_delete.png +0 -0
- data/public/images/xhtml_go.png +0 -0
- data/public/images/xhtml_valid.png +0 -0
- data/public/images/zoom.png +0 -0
- data/public/images/zoom_in.png +0 -0
- data/public/images/zoom_out.png +0 -0
- data/public/img/logo.png +0 -0
- data/public/javascripts/application.js +2 -0
- data/public/javascripts/builder.js +136 -0
- data/public/javascripts/controls.js +965 -0
- data/public/javascripts/dragdrop.js +975 -0
- data/public/javascripts/effects.js +1130 -0
- data/public/javascripts/prototype.js +4320 -0
- data/public/javascripts/scriptaculous.js +60 -0
- data/public/javascripts/slider.js +275 -0
- data/public/javascripts/sound.js +55 -0
- data/public/javascripts/tablekit.js +965 -0
- data/public/javascripts/unittest.js +568 -0
- data/public/javascripts/upload-progress.js +133 -0
- data/public/javascripts/zena.js +501 -0
- data/public/robots.txt +1 -0
- data/public/stylesheets/admin.css +77 -0
- data/public/stylesheets/calendar.css +55 -0
- data/public/stylesheets/code.css +67 -0
- data/public/stylesheets/comment.css +43 -0
- data/public/stylesheets/csshover2.htc +121 -0
- data/public/stylesheets/default.css +85 -0
- data/public/stylesheets/popup.css +200 -0
- data/public/stylesheets/reset.css +33 -0
- data/public/stylesheets/search.css +19 -0
- data/public/stylesheets/upload-progress.css +4 -0
- data/public/stylesheets/wiki.css +100 -0
- data/public/stylesheets/zen.css +230 -0
- data/public/stylesheets/zena.css +78 -0
- data/rails/init.rb +2 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- data/test/fixtures/comments.yml +126 -0
- data/test/fixtures/contact_contents.yml +132 -0
- data/test/fixtures/data_entries.yml +65 -0
- data/test/fixtures/discussions.yml +48 -0
- data/test/fixtures/document_contents.yml +108 -0
- data/test/fixtures/dyn_attributes.yml +66 -0
- data/test/fixtures/files/Node-test.zafu +307 -0
- data/test/fixtures/files/bird.jpg +0 -0
- data/test/fixtures/files/bomb.png +0 -0
- data/test/fixtures/files/exif_sample.jpg +0 -0
- data/test/fixtures/files/flower.jpg +0 -0
- data/test/fixtures/files/forest.pdf +0 -0
- data/test/fixtures/files/import.tgz +0 -0
- data/test/fixtures/files/jet_30.zip +0 -0
- data/test/fixtures/files/lake.jpg +0 -0
- data/test/fixtures/files/letter.zip +0 -0
- data/test/fixtures/files/other.txt +1 -0
- data/test/fixtures/files/simple.zml.gz +0 -0
- data/test/fixtures/files/some.txt +1 -0
- data/test/fixtures/files/translations_de.yml +4 -0
- data/test/fixtures/files/translations_fr.yml +4 -0
- data/test/fixtures/files/tree.jpg +0 -0
- data/test/fixtures/files/water.pdf +0 -0
- data/test/fixtures/groups.yml +86 -0
- data/test/fixtures/groups_users.yml +81 -0
- data/test/fixtures/iformats.yml +28 -0
- data/test/fixtures/import/photos.en.zml +11 -0
- data/test/fixtures/import/photos/bird.jpg +0 -0
- data/test/fixtures/import/photos/bird.jpg.en.zml +1 -0
- data/test/fixtures/import/photos/bird.jpg.fr.zml +1 -0
- data/test/fixtures/import/photos/document.yml.en +4 -0
- data/test/fixtures/import/photos/document.yml.fr +4 -0
- data/test/fixtures/import/simple.zml +8 -0
- data/test/fixtures/links.yml +313 -0
- data/test/fixtures/nodes.yml +2592 -0
- data/test/fixtures/relations.yml +126 -0
- data/test/fixtures/sites.yml +58 -0
- data/test/fixtures/template_contents.yml +172 -0
- data/test/fixtures/users.yml +167 -0
- data/test/fixtures/versions.yml +1909 -0
- data/test/fixtures/virtual_classes.yml +87 -0
- data/test/fixtures/zips.yml +15 -0
- data/test/functional/application_controller_test.rb +136 -0
- data/test/functional/calendar_controller_test.rb +25 -0
- data/test/functional/comments_controller_test.rb +59 -0
- data/test/functional/data_entries_controller_test.rb +22 -0
- data/test/functional/discussion_controller_test.rb +20 -0
- data/test/functional/documents_controller_test.rb +155 -0
- data/test/functional/groups_controller_test.rb +109 -0
- data/test/functional/iformats_controller_test.rb +115 -0
- data/test/functional/links_controller_test.rb +26 -0
- data/test/functional/nodes_controller_test.rb +448 -0
- data/test/functional/note_controller_test.rb +53 -0
- data/test/functional/preferences_controller_test.rb +11 -0
- data/test/functional/relations_controller_test.rb +55 -0
- data/test/functional/search_controller_test.rb +41 -0
- data/test/functional/sessions_controller_test.rb +73 -0
- data/test/functional/sites_controller_test.rb +102 -0
- data/test/functional/users_controller_test.rb +28 -0
- data/test/functional/versions_controller_test.rb +99 -0
- data/test/functional/virtual_classes_controller_test.rb +62 -0
- data/test/helpers/node_query/basic.yml +149 -0
- data/test/helpers/node_query/comments.yml +18 -0
- data/test/helpers/node_query/complex.yml +98 -0
- data/test/helpers/node_query/filters.yml +105 -0
- data/test/helpers/node_query/relations.yml +43 -0
- data/test/helpers/node_query_test.rb +117 -0
- data/test/integration/multiple_hosts_test.rb +98 -0
- data/test/integration/multiversion_test.rb +164 -0
- data/test/integration/navigation_test.rb +283 -0
- data/test/sites/README +2 -0
- data/test/sites/complex/complex.png +0 -0
- data/test/sites/complex/groups.yml +9 -0
- data/test/sites/complex/links.yml +75 -0
- data/test/sites/complex/nodes.yml +253 -0
- data/test/sites/complex/relations.yml +11 -0
- data/test/sites/complex/sites.yml +13 -0
- data/test/sites/complex/users.yml +20 -0
- data/test/sites/complex/versions.yml +1 -0
- data/test/sites/complex/virtual_classes.yml +19 -0
- data/test/sites/ocean/contact_contents.yml +19 -0
- data/test/sites/ocean/groups.yml +9 -0
- data/test/sites/ocean/iformats.yml +7 -0
- data/test/sites/ocean/nodes.yml +36 -0
- data/test/sites/ocean/sites.yml +14 -0
- data/test/sites/ocean/template_contents.yml +8 -0
- data/test/sites/ocean/users.yml +33 -0
- data/test/sites/ocean/versions.yml +48 -0
- data/test/sites/zena/comments.yml +82 -0
- data/test/sites/zena/contact_contents.yml +55 -0
- data/test/sites/zena/data_entries.yml +42 -0
- data/test/sites/zena/discussions.yml +30 -0
- data/test/sites/zena/document_contents.yml +76 -0
- data/test/sites/zena/dyn_attributes.yml +43 -0
- data/test/sites/zena/groups.yml +11 -0
- data/test/sites/zena/iformats.yml +6 -0
- data/test/sites/zena/links.yml +49 -0
- data/test/sites/zena/nodes.yml +338 -0
- data/test/sites/zena/relations.yml +66 -0
- data/test/sites/zena/sites.yml +13 -0
- data/test/sites/zena/template_contents.yml +103 -0
- data/test/sites/zena/users.yml +48 -0
- data/test/sites/zena/versions.yml +558 -0
- data/test/sites/zena/virtual_classes.yml +23 -0
- data/test/test_helper.rb +62 -0
- data/test/test_zena.rb +138 -0
- data/test/unit/cache_test.rb +62 -0
- data/test/unit/cached_page_test.rb +165 -0
- data/test/unit/comment_test.rb +185 -0
- data/test/unit/contact_content_test.rb +33 -0
- data/test/unit/contact_test.rb +39 -0
- data/test/unit/contact_version_test.rb +48 -0
- data/test/unit/core_ext_test.rb +48 -0
- data/test/unit/data_entry_test.rb +92 -0
- data/test/unit/discussion_test.rb +59 -0
- data/test/unit/document_content_test.rb +110 -0
- data/test/unit/document_test.rb +234 -0
- data/test/unit/document_version_test.rb +11 -0
- data/test/unit/dyn_attributes_test.rb +229 -0
- data/test/unit/exif_data_test.rb +66 -0
- data/test/unit/group_test.rb +142 -0
- data/test/unit/iformat_test.rb +190 -0
- data/test/unit/image_builder_test.rb +214 -0
- data/test/unit/image_content_test.rb +154 -0
- data/test/unit/image_test.rb +311 -0
- data/test/unit/image_version_test.rb +18 -0
- data/test/unit/letter_test.rb +9 -0
- data/test/unit/link_test.rb +32 -0
- data/test/unit/multiversion_test.rb +1008 -0
- data/test/unit/node_test.rb +1578 -0
- data/test/unit/note_test.rb +85 -0
- data/test/unit/page_test.rb +79 -0
- data/test/unit/project_test.rb +32 -0
- data/test/unit/reference_test.rb +9 -0
- data/test/unit/relation_proxy_test.rb +409 -0
- data/test/unit/relation_test.rb +48 -0
- data/test/unit/section_test.rb +32 -0
- data/test/unit/secure_test.rb +939 -0
- data/test/unit/site_test.rb +236 -0
- data/test/unit/skin_test.rb +18 -0
- data/test/unit/template_content_test.rb +9 -0
- data/test/unit/template_test.rb +357 -0
- data/test/unit/template_version_test.rb +7 -0
- data/test/unit/text_document_content_test.rb +8 -0
- data/test/unit/text_document_test.rb +139 -0
- data/test/unit/text_document_version_test.rb +37 -0
- data/test/unit/user_test.rb +295 -0
- data/test/unit/version_test.rb +312 -0
- data/test/unit/virtual_class_test.rb +242 -0
- data/test/unit/zena/db_test.rb +94 -0
- data/test/unit/zena/parser/latex.yml +14 -0
- data/test/unit/zena/parser/zafu.yml +391 -0
- data/test/unit/zena/parser/zafu_asset.yml +43 -0
- data/test/unit/zena/parser/zafu_insight.yml +3 -0
- data/test/unit/zena/parser/zazen.yml +211 -0
- data/test/unit/zena/parser_test.rb +184 -0
- data/test/unit/zena/unit/test_case_test.rb +12 -0
- data/test/unit/zena/use/calendar_test.rb +49 -0
- data/test/unit/zena/use/dates_model_methods_test.rb +41 -0
- data/test/unit/zena/use/dates_string_methods_test.rb +94 -0
- data/test/unit/zena/use/dates_view_methods_test.rb +158 -0
- data/test/unit/zena/use/html_tags_test.rb +244 -0
- data/test/unit/zena/use/i18n_test.rb +34 -0
- data/test/unit/zena/use/nested_attributes_alias_model_test.rb +104 -0
- data/test/unit/zena/use/nested_attributes_alias_view_test.rb +99 -0
- data/test/unit/zena/use/refactor_test.rb +52 -0
- data/test/unit/zena/use/rendering_test.rb +23 -0
- data/test/unit/zena/use/urls_test.rb +119 -0
- data/test/unit/zena/use/zafu_test.rb +21 -0
- data/test/unit/zena/use/zazen_test.rb +230 -0
- data/test/unit/zena/zena_tags/ajax.yml +233 -0
- data/test/unit/zena/zena_tags/apphelper.yml +85 -0
- data/test/unit/zena/zena_tags/basic.yml +1295 -0
- data/test/unit/zena/zena_tags/complex.yml +249 -0
- data/test/unit/zena/zena_tags/data.yml +73 -0
- data/test/unit/zena/zena_tags/errors.yml +71 -0
- data/test/unit/zena/zena_tags/eval.yml +51 -0
- data/test/unit/zena/zena_tags/relations.yml +411 -0
- data/test/unit/zena/zena_tags/zazen.yml +84 -0
- data/test/unit/zena/zena_tags_test.rb +235 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run 2.tmCommand +24 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run Context.tmCommand +58 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run Focused Should.tmCommand +88 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/Run.tmCommand +27 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Commands/YAML to Shoulda.tmCommand +23 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Preferences/Symbol List: Context.tmPreferences +19 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Preferences/Symbol List: Should.tmPreferences +19 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory attributes for.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory build.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_define with class.tmSnippet +18 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_define.tmSnippet +18 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_next.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/Factory_sequence.tmSnippet +18 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_bad_value.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_contains.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_does_not_contain.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_good_value.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_same_elements.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_save.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_sent_email.tmSnippet +18 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/assert_valid.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/association.tmSnippet +17 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/attribute.tmSnippet +17 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/before_should block.tmSnippet +18 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block get.tmSnippet +22 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block post.tmSnippet +23 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/context block with setup.tmSnippet +25 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/setup.tmSnippet +18 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should block with before proc.tmSnippet +18 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should block.tmSnippet +18 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_allow_values_for.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_assign_to.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_be_restful denied.tmSnippet +20 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_be_restful.tmSnippet +20 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_belong_to.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_change by.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_change from to.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_at_least.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_in_range.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_length_is.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_ensure_value_in_range.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_eventually.tmSnippet +18 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_filter_params.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_and_belong_to_many.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_class_methods.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_db_column.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_db_columns.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_index.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_indices.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_instance_methods.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_many.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_named_scope.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_one.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_have_readonly_attributes.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_allow_mass_assignment_of.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_allow_values_for.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_assign_to.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_change.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_not_set_the_flash.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_redirect_to.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_a_form.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_template.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_with_layout.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_render_without_layout.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_respond_with.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_respond_with_content_type.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_return_from_session.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_route.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_set_the_flash_to.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_acceptance_of.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_numericality_of.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_presence_of.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_uniqueness_of with scope.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Snippets/should_validate_uniqueness_of.tmSnippet +16 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/catch_exception.rb +39 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/run_script.rb +104 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/stdin_dialog.rb +14 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/test.rb +17 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/RubyMate/todo.txt +13 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Support/bin/yaml_to_shoulda.rb +25 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/Syntaxes/Ruby on Rails (Shoulda).tmLanguage +166 -0
- data/vendor/TextMate/Ruby Shoulda.tmbundle/info.plist +304 -0
- data/vendor/TextMate/Zena.tmbundle/Commands/Run all yaml tests.tmCommand +37 -0
- data/vendor/TextMate/Zena.tmbundle/Commands/Run focused yaml test.tmCommand +53 -0
- data/vendor/TextMate/Zena.tmbundle/Support/RubyMate/run_script.rb +74 -0
- data/vendor/TextMate/Zena.tmbundle/info.plist +15 -0
- data/vendor/apache_upload/mod_upload_progress.c +813 -0
- data/vendor/bricks/20070122-172926.txt +282 -0
- data/vendor/plugins/ar_mysql_full_text/README +15 -0
- data/vendor/plugins/ar_mysql_full_text/init.rb +1 -0
- data/vendor/plugins/ar_mysql_full_text/lib/ar_mysql_full_text.rb +69 -0
- data/vendor/plugins/gettext_i18n_rails/README.markdown +139 -0
- data/vendor/plugins/gettext_i18n_rails/Rakefile +6 -0
- data/vendor/plugins/gettext_i18n_rails/init.rb +10 -0
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails.rb +21 -0
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/action_controller.rb +6 -0
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/active_record.rb +17 -0
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/backend.rb +47 -0
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/haml_parser.rb +43 -0
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/i18n_hacks.rb +10 -0
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/model_attributes_finder.rb +46 -0
- data/vendor/plugins/gettext_i18n_rails/lib/gettext_i18n_rails/ruby_gettext_extractor.rb +136 -0
- data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/action_controller_spec.rb +36 -0
- data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/active_record_spec.rb +50 -0
- data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails/backend_spec.rb +41 -0
- data/vendor/plugins/gettext_i18n_rails/spec/gettext_i18n_rails_spec.rb +43 -0
- data/vendor/plugins/gettext_i18n_rails/spec/spec_helper.rb +15 -0
- data/vendor/plugins/gettext_i18n_rails/tasks/gettext_rails_i18n.rake +73 -0
- data/vendor/plugins/responds_to_parent/MIT-LICENSE +20 -0
- data/vendor/plugins/responds_to_parent/README +42 -0
- data/vendor/plugins/responds_to_parent/Rakefile +22 -0
- data/vendor/plugins/responds_to_parent/init.rb +1 -0
- data/vendor/plugins/responds_to_parent/lib/responds_to_parent.rb +46 -0
- data/vendor/plugins/responds_to_parent/test/responds_to_parent_test.rb +115 -0
- data/vendor/plugins/rjs-assertions/MIT-LICENSE +20 -0
- data/vendor/plugins/rjs-assertions/README +64 -0
- data/vendor/plugins/rjs-assertions/init.rb +1 -0
- data/vendor/plugins/rjs-assertions/lib/rjs-assertions.rb +99 -0
- data/vendor/rails_patches/support_for_inverse_relationships_on_active_record_objects.diff +739 -0
- metadata +2075 -0
data/app/models/link.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
class Link < ActiveRecord::Base
|
2
|
+
include RubyLess::SafeClass
|
3
|
+
safe_attribute :status, :comment, :date
|
4
|
+
|
5
|
+
attr_reader :relation
|
6
|
+
attr_accessor :start, :side
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def find_through(node, link_id)
|
10
|
+
return nil unless link = Link.find(:first, :conditions => ['(source_id = ? OR target_id = ?) AND id = ?', node[:id], node[:id], link_id])
|
11
|
+
link.start = node
|
12
|
+
node.link = link
|
13
|
+
link
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# TODO: is this used ?
|
18
|
+
def update_attributes_with_transformations(attrs)
|
19
|
+
return false unless @node
|
20
|
+
|
21
|
+
if attrs['role']
|
22
|
+
# TODO: destroy this link and create a new one ?
|
23
|
+
end
|
24
|
+
|
25
|
+
rel = @node.relation_proxy_from_link(self)
|
26
|
+
rel.other_link = self
|
27
|
+
|
28
|
+
Zena::Use::Relations::LINK_ATTRIBUTES.each do |k|
|
29
|
+
k = k.to_s # TODO: use only strings or symbols but avoid this mess
|
30
|
+
rel.send("other_#{k}=", attrs[k]) if attrs.has_key?(k)
|
31
|
+
self[k] = attrs[k]
|
32
|
+
end
|
33
|
+
|
34
|
+
if other_id = attrs['other_id'] || attrs['other_zip']
|
35
|
+
other_id = secure(Node) { Node.translate_pseudo_id(other_id, :id, @node) }
|
36
|
+
rel.other_id = other_id
|
37
|
+
if @side == :source
|
38
|
+
self[:target_id] = other_id
|
39
|
+
@target = nil
|
40
|
+
else
|
41
|
+
self[:source_id] = other_id
|
42
|
+
@source = nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
@node.save
|
47
|
+
@node.link = self
|
48
|
+
@errors = @node.errors
|
49
|
+
return errors.empty?
|
50
|
+
end
|
51
|
+
|
52
|
+
def target
|
53
|
+
@target ||= begin
|
54
|
+
node = secure!(Node) { Node.find(target_id) }
|
55
|
+
node.link = self
|
56
|
+
node
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def source
|
61
|
+
@source ||= begin
|
62
|
+
node = secure!(Node) { Node.find(source_id) }
|
63
|
+
node.link = self
|
64
|
+
node
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def start=(node)
|
69
|
+
@node = node
|
70
|
+
if @node[:id] == self[:source_id]
|
71
|
+
@side = :source
|
72
|
+
@source = @node
|
73
|
+
else
|
74
|
+
@side = :target
|
75
|
+
@target = @node
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def other
|
80
|
+
@side == :source ? target : source
|
81
|
+
end
|
82
|
+
|
83
|
+
def this
|
84
|
+
@side == :source ? source : target
|
85
|
+
end
|
86
|
+
|
87
|
+
def other_zip
|
88
|
+
other[:zip]
|
89
|
+
end
|
90
|
+
|
91
|
+
def this_zip
|
92
|
+
this[:zip]
|
93
|
+
end
|
94
|
+
|
95
|
+
def zip
|
96
|
+
self[:id]
|
97
|
+
end
|
98
|
+
|
99
|
+
def can_write?
|
100
|
+
this.can_write?
|
101
|
+
end
|
102
|
+
|
103
|
+
def relation_proxy(node=nil)
|
104
|
+
return @relation_proxy if defined?(@relation_proxy)
|
105
|
+
rel = RelationProxy.find(self[:relation_id])
|
106
|
+
@node = node if node
|
107
|
+
if @node
|
108
|
+
if self[:source_id] == @node[:id]
|
109
|
+
rel.side = :source
|
110
|
+
else
|
111
|
+
rel.side = :target
|
112
|
+
end
|
113
|
+
rel.start = @node
|
114
|
+
end
|
115
|
+
@relation_proxy = rel
|
116
|
+
end
|
117
|
+
|
118
|
+
def role
|
119
|
+
relation_proxy.other_role
|
120
|
+
end
|
121
|
+
end
|
data/app/models/node.rb
ADDED
@@ -0,0 +1,1752 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
A Node is the root class of all elements in the zena application. Class inheritance diagram:
|
3
|
+
|
4
|
+
|
5
|
+
FIXME: some parts are not correct (Partial, Task, Request, Milestone). Either correct this tree or add these classes.
|
6
|
+
Node (manages access and publication cycle)
|
7
|
+
|
|
8
|
+
+-- Page (web pages)
|
9
|
+
| |
|
10
|
+
| +--- Project (has it's own project_id. Can contain notes, collaborators, etc)
|
11
|
+
| |
|
12
|
+
| +--- Section (has it's own section_id = group of pages)
|
13
|
+
| |
|
14
|
+
| +--- Skin (theme: contains css, templates, etc)
|
15
|
+
|
|
16
|
+
+--- Document
|
17
|
+
| |
|
18
|
+
| +--- Image
|
19
|
+
| |
|
20
|
+
| +--- TextDocument (for css, scripts)
|
21
|
+
| |
|
22
|
+
| +--- Partial (uses the zafu templating language)
|
23
|
+
| |
|
24
|
+
| +--- Template (entry for rendering)
|
25
|
+
|
|
26
|
+
+-- Note (date related information, event)
|
27
|
+
| |
|
28
|
+
| +--- Post (blog entry)
|
29
|
+
| |
|
30
|
+
| +--- Task
|
31
|
+
| | |
|
32
|
+
| | +--- Letter
|
33
|
+
| | |
|
34
|
+
| | +--- Request
|
35
|
+
| | |
|
36
|
+
| | +--- Bug
|
37
|
+
| |
|
38
|
+
| +--- Milestone
|
39
|
+
|
|
40
|
+
+-- Reference
|
41
|
+
|
|
42
|
+
+-- Contact (address, name, phone)
|
43
|
+
|
44
|
+
=== Node, Version and Content
|
45
|
+
|
46
|
+
The +nodes+ table only holds columns to secure the access. This table does not hold every possible data for every sub-class of Node. The text data is stored into the +versions+ table and any other specific content goes in its own table (+document_contents+ for example). This is an example of how an Image is stored :
|
47
|
+
|
48
|
+
Node o----------- Version o--------- Content
|
49
|
+
dgroup_id title width
|
50
|
+
wgroup_id text height
|
51
|
+
user_id summary content_type
|
52
|
+
... ... ...
|
53
|
+
|
54
|
+
=== Acessing version and content data
|
55
|
+
|
56
|
+
To ease the work to set/retrieve the data from the version and or content, we use some special notation. This notation abstracts this Node/Version/Content structure so you can use a version's attribute as if it was in the node directly.
|
57
|
+
|
58
|
+
TODO: DOC removed (was out of sync)
|
59
|
+
|
60
|
+
=== Dynamic attributes
|
61
|
+
|
62
|
+
The Version class uses dynamic attributes. These let you add any attribute you like to the versions (see DynAttribute for details). These attributes can be accessed by using the +d_+ prefix :
|
63
|
+
|
64
|
+
@node.d_whatever ===> @node.version.dyn[:whatever]
|
65
|
+
|
66
|
+
=== Attributes
|
67
|
+
|
68
|
+
Each node uses the following basic attributes:
|
69
|
+
|
70
|
+
Base attributes:
|
71
|
+
|
72
|
+
zip:: unique id (incremented in each site's scope).
|
73
|
+
name:: used to build the node's url when 'custom_base' is set. Used for document names.
|
74
|
+
site_id:: site to which this node belongs to.
|
75
|
+
parent_id:: parent node (every node except root is inserted in a unique place through this attribute).
|
76
|
+
user_id:: owner of the node.
|
77
|
+
ref_lang:: original node language.
|
78
|
+
created_at:: creation date.
|
79
|
+
updated_at:: modification date.
|
80
|
+
custom_base:: boolean value. When set to true, the node's url becomes it's fullpath. All it descendants will use this node's fullpath as their base url. See below for an example.
|
81
|
+
inherit:: inheritance mode (0=custom, 1=inherit, -1=private).
|
82
|
+
|
83
|
+
Attributes inherited from the parent:
|
84
|
+
section_id:: reference project (cannot be overwritten even if inheritance mode is custom).
|
85
|
+
rgroup_id:: id of the readers group.
|
86
|
+
wgroup_id:: id of the writers group.
|
87
|
+
dgroup_id:: id of the publishers group.
|
88
|
+
skin:: name of theSkin to use when rendering the pate ('theme').
|
89
|
+
|
90
|
+
Attributes used internally:
|
91
|
+
publish_from:: earliest publication date from all published versions.
|
92
|
+
kpath:: inheritance hierarchy. For example an Image has 'NPDI' (Node, Page, Document, Image), a Letter would have 'NNTL' (Node, Note, Task. Letter). This is used to optimize sql queries.
|
93
|
+
fullpath:: cached full path made of ancestors' names (<gdparent name>/<parent name>/<self name>).
|
94
|
+
basepath:: cached base path (the base path is used to build the url depending on the 'custom_base' flag).
|
95
|
+
|
96
|
+
=== Node url
|
97
|
+
A node's url is made of it's class and +zip+. For the examples below, this is our site tree:
|
98
|
+
root
|
99
|
+
|
|
100
|
+
+--- projects (Page)
|
101
|
+
|
|
102
|
+
+--- worldTour (Project)
|
103
|
+
| |
|
104
|
+
| +--- photos (Page)
|
105
|
+
|
|
106
|
+
+--- music (Project)
|
107
|
+
|
108
|
+
The worldTour project's url would look like:
|
109
|
+
/en/project21.html
|
110
|
+
|
111
|
+
The 'photos' url would be:
|
112
|
+
/en/page23.html
|
113
|
+
|
114
|
+
When custom base is set (only for descendants of Page), worldTour url becomes its fullpath:
|
115
|
+
/en/projects/worldTour
|
116
|
+
|
117
|
+
and the 'photos' url is now in the worldTour project's basepath:
|
118
|
+
/en/projects/worldTour/page23.html
|
119
|
+
|
120
|
+
Setting 'custom_base' on a node should be done with caution as the node's zip is on longer in the url and when you move the node around, there is no way to find the new location from the old url. Custom_base should therefore only be used for nodes that are not going to move.
|
121
|
+
=end
|
122
|
+
class Node < ActiveRecord::Base
|
123
|
+
|
124
|
+
include RubyLess::SafeClass
|
125
|
+
safe_attribute :created_at, :updated_at, :event_at, :log_at, :publish_from, :basepath, :inherit
|
126
|
+
|
127
|
+
# we use safe_method because the columns can be null, but the values are never null
|
128
|
+
safe_method :name => String, :kpath => String, :user_zip => Number, :parent_zip => Number,
|
129
|
+
:project_zip => Number, :section_zip => Number, :skin => String, :ref_lang => String,
|
130
|
+
:fullpath => String, :rootpath => String, :position => Number, :rgroup_id => Number,
|
131
|
+
:wgroup_id => Number, :dgroup_id => Number, :custom_base => Boolean, :klass => String,
|
132
|
+
:score => Number, :comments_count => Number,
|
133
|
+
:custom_a => Number, :custom_b => Number,
|
134
|
+
:m_text => String, :m_title => String, :m_author => String,
|
135
|
+
:zip => Number
|
136
|
+
# FIXME: remove 'zip' and use :id => {:class => Number, :method => 'zip'}
|
137
|
+
# same with parent_zip, section_zip, etc...
|
138
|
+
|
139
|
+
#attr_accessible :version_content
|
140
|
+
has_many :discussions, :dependent => :destroy
|
141
|
+
has_many :links
|
142
|
+
has_and_belongs_to_many :cached_pages
|
143
|
+
belongs_to :virtual_class, :foreign_key => 'vclass_id'
|
144
|
+
belongs_to :site
|
145
|
+
before_validation :node_before_validation # run our 'before_validation' after 'secure'
|
146
|
+
validates_presence_of :name
|
147
|
+
validate :validate_node
|
148
|
+
before_create :node_before_create
|
149
|
+
before_save :change_klass
|
150
|
+
after_save :spread_project_and_section
|
151
|
+
after_save :clear_children_fullpath
|
152
|
+
after_create :node_after_create
|
153
|
+
attr_protected :site_id, :zip, :id, :section_id, :project_id, :publish_from
|
154
|
+
attr_protected :site_id
|
155
|
+
|
156
|
+
include Zena::Use::Dates::ModelMethods
|
157
|
+
parse_date_attribute :event_at, :log_at
|
158
|
+
|
159
|
+
include Zena::Use::NestedAttributesAlias::ModelMethods
|
160
|
+
nested_attributes_alias %r{^v_(\w+)} => ['version']
|
161
|
+
nested_attributes_alias %r{^c_(\w+)} => ['version', 'content']
|
162
|
+
nested_attributes_alias %r{^d_(\w+)} => ['version', 'dyn']
|
163
|
+
|
164
|
+
zafu_context :author => "Contact", :parent => "Node",
|
165
|
+
:project => "Project", :section => "Section",
|
166
|
+
:real_project => "Project", :real_section => "Section",
|
167
|
+
:user => "User",
|
168
|
+
:version => "Version", :comments => ["Comment"],
|
169
|
+
:data => {:node_class => ["DataEntry"], :data_root => 'node_a'},
|
170
|
+
:data_a => {:node_class => ["DataEntry"], :data_root => 'node_a'},
|
171
|
+
:data_b => {:node_class => ["DataEntry"], :data_root => 'node_b'},
|
172
|
+
:data_c => {:node_class => ["DataEntry"], :data_root => 'node_c'},
|
173
|
+
:data_d => {:node_class => ["DataEntry"], :data_root => 'node_d'}
|
174
|
+
|
175
|
+
extend Zena::Acts::SecureNode
|
176
|
+
extend Zena::Acts::Multiversion
|
177
|
+
include Zena::Use::Relations::ModelMethods
|
178
|
+
|
179
|
+
acts_as_secure_node
|
180
|
+
acts_as_multiversioned
|
181
|
+
use_node_query
|
182
|
+
|
183
|
+
@@native_node_classes = {'N' => self}
|
184
|
+
@@unhandled_children = []
|
185
|
+
class << self
|
186
|
+
|
187
|
+
# needed for compatibility with virtual classes
|
188
|
+
alias create_instance create
|
189
|
+
alias new_instance new
|
190
|
+
|
191
|
+
def inherited(child)
|
192
|
+
super
|
193
|
+
@@unhandled_children << child
|
194
|
+
end
|
195
|
+
|
196
|
+
# Return the list of (kpath,subclasses) for the current class.
|
197
|
+
def native_classes
|
198
|
+
# this is to make sure subclasses are loaded before the first call
|
199
|
+
[Note,Page,Project,Section,Reference,Contact,Document,Image,TextDocument,Skin,Template]
|
200
|
+
while child = @@unhandled_children.pop
|
201
|
+
@@native_node_classes[child.kpath] = child
|
202
|
+
end
|
203
|
+
@@native_node_classes.reject{|kpath,klass| !(kpath =~ /^#{self.kpath}/) }
|
204
|
+
end
|
205
|
+
|
206
|
+
# check inheritance chain through kpath
|
207
|
+
def kpath_match?(kpath)
|
208
|
+
self.kpath =~ /^#{kpath}/
|
209
|
+
end
|
210
|
+
|
211
|
+
# Class list to which this class can change to
|
212
|
+
def change_to_classes_for_form
|
213
|
+
classes_for_form(:class => 'Node', :without => 'Document, Contact')
|
214
|
+
end
|
215
|
+
|
216
|
+
# List of classes that a node can change to.
|
217
|
+
def allowed_change_to_classes
|
218
|
+
change_to_classes_for_form.map {|k,v| v}
|
219
|
+
end
|
220
|
+
|
221
|
+
# FIXME: how to make sure all sub-classes of Node are loaded before this is called ?
|
222
|
+
def classes_for_form(opts={})
|
223
|
+
if klass = opts.delete(:class)
|
224
|
+
if klass = get_class(klass)
|
225
|
+
klass.classes_for_form(opts)
|
226
|
+
else
|
227
|
+
return ['', ''] # bad class
|
228
|
+
end
|
229
|
+
else
|
230
|
+
all_classes(opts).map{|a,b| [a[0..-1].sub(/^#{self.kpath}/,'').gsub(/./,' ') + b.to_s, b.to_s] } # white spaces are insecable spaces (not ' ')
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# FIXME: how to make sure all sub-classes of Node are loaded before this is called ?
|
235
|
+
def kpaths_for_form(opts={})
|
236
|
+
all_classes(opts).map{|a,b| [a[1..-1].gsub(/./,' ') + b.to_s, a.to_s] } # white spaces are insecable spaces (not ' ')
|
237
|
+
end
|
238
|
+
|
239
|
+
def all_classes(opts={})
|
240
|
+
virtual_classes = VirtualClass.find(:all, :conditions => ["site_id = ? AND create_group_id IN (?) AND kpath LIKE '#{self.kpath}%'", current_site[:id], visitor.group_ids])
|
241
|
+
classes = (virtual_classes.map{|r| [r.kpath, r.name]} + native_classes.to_a).sort{|a,b| a[0] <=> b[0]}
|
242
|
+
if opts[:without]
|
243
|
+
reject_kpath = opts[:without].split(',').map(&:strip).map {|name| Node.get_class(name) }.compact.map { |kla| kla.kpath }.join('|')
|
244
|
+
classes.reject! {|k,c| k =~ /^#{reject_kpath}/ }
|
245
|
+
end
|
246
|
+
classes
|
247
|
+
end
|
248
|
+
|
249
|
+
# Return class or virtual class from name.
|
250
|
+
def get_class(rel, opts={})
|
251
|
+
class_name = rel.singularize.camelize # mushroom_types ==> MushroomType
|
252
|
+
begin
|
253
|
+
klass = Module.const_get(class_name)
|
254
|
+
raise NameError unless klass.ancestors.include?(Node)
|
255
|
+
rescue NameError
|
256
|
+
# find the virtual class
|
257
|
+
if opts[:create]
|
258
|
+
klass = VirtualClass.find(:first, :conditions=>["site_id = ? AND create_group_id IN (?) AND name = ?",current_site[:id], visitor.group_ids, class_name])
|
259
|
+
else
|
260
|
+
klass = VirtualClass.find(:first, :conditions=>["site_id = ? AND name = ?",current_site[:id], class_name])
|
261
|
+
end
|
262
|
+
end
|
263
|
+
klass
|
264
|
+
end
|
265
|
+
|
266
|
+
# Return a new object of the class name or nil if the class name does not exist.
|
267
|
+
def new_from_class(rel)
|
268
|
+
if k = get_class(rel, :create => true)
|
269
|
+
k.new
|
270
|
+
else
|
271
|
+
nil
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def get_class_from_kpath(kp)
|
276
|
+
native_classes[kp] || VirtualClass.find(:first, :conditions=>["site_id = ? AND kpath = ?",current_site[:id], kp])
|
277
|
+
end
|
278
|
+
|
279
|
+
# Find a node's attribute based on a pseudo (id or path). Used by zazen to create a link for ""::art or "":(people/ant) for example.
|
280
|
+
def translate_pseudo_id(id, sym = :id, base_node = nil)
|
281
|
+
if id.to_s =~ /\A(-?)(\d+)\Z/
|
282
|
+
# zip
|
283
|
+
# FIXME: this is not secure
|
284
|
+
res = Zena::Db.fetch_row("SELECT #{sym} FROM nodes WHERE site_id = #{current_site[:id]} AND zip = '#{$2}'")
|
285
|
+
res ? ($1.blank? ? res.to_i : -res.to_i) : nil
|
286
|
+
elsif node = find_node_by_pseudo(id,base_node)
|
287
|
+
node[sym]
|
288
|
+
else
|
289
|
+
nil
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# Find a node based on a query shortcut. Used by zazen to create a link for ""::art for example.
|
294
|
+
def find_node_by_pseudo(id, base_node = nil)
|
295
|
+
raise Zena::AccessViolation if self.scoped_methods == []
|
296
|
+
str = id.to_s
|
297
|
+
if str =~ /\A\d+\Z/
|
298
|
+
# zip
|
299
|
+
find_by_zip(str)
|
300
|
+
elsif str =~ /\A:?([0-9a-zA-Z ]+)(\+*)\Z/
|
301
|
+
offset = $2.to_s.size
|
302
|
+
find(:first, Node.match_query($1.gsub('-',' '), :offset => offset))
|
303
|
+
elsif path = str[/\A\(([^\)]*)\)\Z/,1]
|
304
|
+
if path[0..0] == '/'
|
305
|
+
find_by_path(path[1..-1])
|
306
|
+
elsif base_node
|
307
|
+
find_by_path(path.abs_path(base_node.fullpath))
|
308
|
+
else
|
309
|
+
# do not use (path) pseudo when there is no base_node (during create_or_update_node for example).
|
310
|
+
# FIXME: path pseudo is needed for links... and it should be done here (egg and hen problem)
|
311
|
+
nil
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
# def attr_public?(attribute)
|
317
|
+
# if attribute.to_s =~ /(.*)_zips?$/
|
318
|
+
# return true if self.ancestors.include?(Node) && RelationProxy.find_by_role($1.singularize)
|
319
|
+
# end
|
320
|
+
# super
|
321
|
+
# end
|
322
|
+
|
323
|
+
def create_or_update_node(new_attributes)
|
324
|
+
attributes = transform_attributes(new_attributes)
|
325
|
+
unless attributes['name'] && attributes['parent_id']
|
326
|
+
node = Node.new
|
327
|
+
node.errors.add('name', "can't be blank") unless attributes['name']
|
328
|
+
node.errors.add('parent_id', "can't be blank") unless attributes['parent_id']
|
329
|
+
return node
|
330
|
+
end
|
331
|
+
|
332
|
+
begin
|
333
|
+
klass = Node.get_class(attributes['klass'] || 'Node')
|
334
|
+
klass = klass.real_class if klass.kind_of?(VirtualClass)
|
335
|
+
rescue NameError
|
336
|
+
klass = Node
|
337
|
+
end
|
338
|
+
|
339
|
+
# FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
|
340
|
+
node = klass.send(:with_exclusive_scope) do
|
341
|
+
klass.find(:first, :conditions => ['site_id = ? AND name = ? AND parent_id = ?',
|
342
|
+
current_site[:id], attributes['name'].url_name, attributes['parent_id']])
|
343
|
+
end
|
344
|
+
|
345
|
+
if node
|
346
|
+
visitor.visit(node) # secure
|
347
|
+
# TODO: class ignored (could be used to transform from one class to another...)
|
348
|
+
attributes.delete('class')
|
349
|
+
attributes.delete('klass')
|
350
|
+
updated_date = node.updated_at
|
351
|
+
node.update_attributes(attributes)
|
352
|
+
|
353
|
+
if updated_date != node.updated_at
|
354
|
+
node[:create_or_update] = 'updated'
|
355
|
+
else
|
356
|
+
node[:create_or_update] = 'same'
|
357
|
+
end
|
358
|
+
else
|
359
|
+
node = create_node(new_attributes)
|
360
|
+
node[:create_or_update] = 'new'
|
361
|
+
end
|
362
|
+
|
363
|
+
node
|
364
|
+
end
|
365
|
+
|
366
|
+
# TODO: cleanup and rename with something indicating the attrs cleanup that this method does.
|
367
|
+
def create_node(new_attributes)
|
368
|
+
attributes = transform_attributes(new_attributes)
|
369
|
+
|
370
|
+
# the way this works here and in do_update_attributes is not good
|
371
|
+
publish_after_save = (attributes.delete('v_status').to_i == Zena::Status[:pub])
|
372
|
+
|
373
|
+
# TODO: replace this hack with a proper class method 'secure' behaving like the
|
374
|
+
# instance method. It would get the visitor and scope from the same hack below.
|
375
|
+
scope = self.scoped_methods[0] || {}
|
376
|
+
|
377
|
+
klass_name = attributes.delete('class') || attributes.delete('klass') || 'Page'
|
378
|
+
unless klass = get_class(klass_name, :create => true)
|
379
|
+
node = Node.new
|
380
|
+
node.instance_eval { @attributes = attributes }
|
381
|
+
node.errors.add('klass', 'invalid')
|
382
|
+
# This is to show the klass in the form seizure
|
383
|
+
node.instance_variable_set(:@klass, klass_name.to_s)
|
384
|
+
def node.klass; @klass; end
|
385
|
+
return node
|
386
|
+
end
|
387
|
+
|
388
|
+
node = if klass != self
|
389
|
+
# FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
|
390
|
+
klass.send(:with_exclusive_scope, scope) { klass.create_instance(attributes) }
|
391
|
+
else
|
392
|
+
self.create_instance(attributes)
|
393
|
+
end
|
394
|
+
|
395
|
+
node.publish if publish_after_save
|
396
|
+
node
|
397
|
+
end
|
398
|
+
|
399
|
+
# Create new nodes from the data in a folder or archive.
|
400
|
+
def create_nodes_from_folder(opts)
|
401
|
+
# TODO: all this method needs cleaning, it's a mess.
|
402
|
+
return [] unless (opts[:folder] || opts[:archive]) && (opts[:parent] || opts[:parent_id])
|
403
|
+
scope = self.scoped_methods[0] || {}
|
404
|
+
parent_id = opts[:parent_id] || opts[:parent][:id]
|
405
|
+
folder = opts[:folder]
|
406
|
+
defaults = (opts[:defaults] || {}).stringify_keys
|
407
|
+
klass = opts[:klass] || "Page"
|
408
|
+
res = {}
|
409
|
+
|
410
|
+
# create from archive
|
411
|
+
unless folder
|
412
|
+
archive = opts[:archive]
|
413
|
+
n = 0
|
414
|
+
while true
|
415
|
+
folder = File.join(RAILS_ROOT, 'tmp', sprintf('%s.%d.%d', 'import', $$, n))
|
416
|
+
break unless File.exists?(folder)
|
417
|
+
end
|
418
|
+
|
419
|
+
begin
|
420
|
+
FileUtils::mkpath(folder)
|
421
|
+
|
422
|
+
if archive.kind_of?(StringIO)
|
423
|
+
filename = archive.original_filename
|
424
|
+
tempf = Tempfile.new(archive.original_filename)
|
425
|
+
File.open(tempf.path, 'wb') { |f| f.syswrite(archive.read) }
|
426
|
+
archive = tempf
|
427
|
+
else
|
428
|
+
filename = archive.original_filename
|
429
|
+
end
|
430
|
+
|
431
|
+
# extract file in this temporary folder.
|
432
|
+
# FIXME: is there a security risk here ?
|
433
|
+
if filename =~ /\.tgz$/
|
434
|
+
`tar -C '#{folder}' -xz < '#{archive.path}'`
|
435
|
+
elsif filename =~ /\.tar$/
|
436
|
+
`tar -C '#{folder}' -x < '#{archive.path}'`
|
437
|
+
elsif filename =~ /\.zip$/
|
438
|
+
`unzip -d '#{folder}' '#{archive.path}'`
|
439
|
+
elsif filename =~ /(.*)(\.gz|\.z)$/
|
440
|
+
`gzip -d '#{archive.path}' -c > '#{folder}/#{$1.gsub("'",'')}'`
|
441
|
+
else
|
442
|
+
# FIXME: send errors back
|
443
|
+
puts "BAD #{archive.inspect}"
|
444
|
+
end
|
445
|
+
res = create_nodes_from_folder(:folder => folder, :parent_id => parent_id, :defaults => defaults, :klass => klass)
|
446
|
+
ensure
|
447
|
+
FileUtils::rmtree(folder)
|
448
|
+
end
|
449
|
+
return res
|
450
|
+
end
|
451
|
+
|
452
|
+
entries = Dir.entries(folder).reject { |f| f =~ /^([\._~]|[^\w])/ }.sort
|
453
|
+
index = 0
|
454
|
+
|
455
|
+
while entries[index]
|
456
|
+
type = current_obj = sub_folder = document_path = nil
|
457
|
+
versions = []
|
458
|
+
filename = entries[index]
|
459
|
+
|
460
|
+
path = File.join(folder, filename)
|
461
|
+
|
462
|
+
if File.stat(path).directory?
|
463
|
+
type = :folder
|
464
|
+
name = filename
|
465
|
+
sub_folder = path
|
466
|
+
attrs = defaults.dup
|
467
|
+
elsif filename =~ /^(.+?)(\.\w\w|)(\.\d+|)\.zml$/ # bird.jpg.en.zml
|
468
|
+
# node content in yaml
|
469
|
+
type = :node
|
470
|
+
name = "#{$1}#{$4}"
|
471
|
+
lang = $2.blank? ? nil : $2[1..-1]
|
472
|
+
|
473
|
+
# no need for base_node (this is done after all with parse_assets in the controller)
|
474
|
+
attrs = defaults.merge(get_attributes_from_yaml(path))
|
475
|
+
attrs['name'] = name
|
476
|
+
attrs['v_lang'] = lang || attrs['v_lang'] || visitor.lang
|
477
|
+
versions << attrs
|
478
|
+
elsif filename =~ /^((.+?)\.(.+?))(\.\w\w|)(\.\d+|)$/ # bird.jpg.en
|
479
|
+
type = :document
|
480
|
+
name = $1
|
481
|
+
attrs = defaults.dup
|
482
|
+
lang = $4.blank? ? nil : $4[1..-1]
|
483
|
+
attrs['v_lang'] = lang || attrs['v_lang'] || visitor.lang
|
484
|
+
attrs['c_ext'] = $3
|
485
|
+
document_path = path
|
486
|
+
end
|
487
|
+
|
488
|
+
index += 1
|
489
|
+
while entries[index] =~ /^#{name}(\.\w\w|)(\.\d+|)\.zml$/ # bird.jpg.en.zml
|
490
|
+
lang = $1.blank? ? visitor.lang : $1[1..-1]
|
491
|
+
path = File.join(folder,entries[index])
|
492
|
+
|
493
|
+
# we have a zml file. Create a version with this file
|
494
|
+
# no need for base_node (this is done after all with parse_assets in the controller)
|
495
|
+
attrs = defaults.merge(get_attributes_from_yaml(path))
|
496
|
+
attrs['name'] = name
|
497
|
+
attrs['v_lang'] ||= lang
|
498
|
+
versions << attrs
|
499
|
+
|
500
|
+
index += 1
|
501
|
+
end
|
502
|
+
|
503
|
+
if versions.empty?
|
504
|
+
if type == :folder
|
505
|
+
# minimal node for a folder
|
506
|
+
attrs['name'] = name
|
507
|
+
attrs['v_lang'] ||= lang
|
508
|
+
attrs['class'] = klass
|
509
|
+
versions << attrs
|
510
|
+
elsif type == :document
|
511
|
+
# minimal node for a document
|
512
|
+
attrs['name'] = name
|
513
|
+
attrs['v_lang'] ||= lang
|
514
|
+
versions << attrs
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
new_object = false
|
519
|
+
versions.each do |attrs|
|
520
|
+
# FIXME: same lang: remove before update current_obj.remove if current_obj.v_lang == attrs['v_lang'] && current_obj.v_status != Zena::Status[:red]
|
521
|
+
# FIXME: current_obj.publish if attrs['v_status'].to_i == Zena::Status[:pub]
|
522
|
+
if type == :document
|
523
|
+
attrs['name' ] = attrs['name'].split('.')[0..-2].join('.')
|
524
|
+
if document_path
|
525
|
+
attrs['c_ext'] ||= document_path.split('.').last
|
526
|
+
# file
|
527
|
+
insert_zafu_headings = false
|
528
|
+
if opts[:parent_class] == 'Skin' && ['html','xhtml'].include?(attrs['c_ext']) && attrs['name'] == 'index'
|
529
|
+
attrs['c_ext'] = 'zafu'
|
530
|
+
attrs['name'] = 'Node'
|
531
|
+
insert_zafu_headings = true
|
532
|
+
end
|
533
|
+
|
534
|
+
ctype = EXT_TO_TYPE[attrs['c_ext']]
|
535
|
+
ctype = ctype ? ctype[0] : "application/octet-stream"
|
536
|
+
attrs['c_content_type'] = ctype
|
537
|
+
|
538
|
+
|
539
|
+
File.open(document_path) do |file|
|
540
|
+
(class << file; self; end;).class_eval do
|
541
|
+
alias local_path path if defined?(:path)
|
542
|
+
alias o_read read
|
543
|
+
define_method(:original_filename) { filename }
|
544
|
+
define_method(:content_type) { ctype }
|
545
|
+
define_method(:read) do
|
546
|
+
if insert_zafu_headings
|
547
|
+
o_read.sub(%r{</head>}," <r:stylesheets/>\n <r:javascripts/>\n <r:uses_datebox/>\n</head>")
|
548
|
+
else
|
549
|
+
o_read
|
550
|
+
end
|
551
|
+
end
|
552
|
+
end
|
553
|
+
current_obj = create_or_update_node(attrs.merge(:c_file => file, :klass => 'Document', :_parent_id => parent_id))
|
554
|
+
end
|
555
|
+
document_path = nil
|
556
|
+
else
|
557
|
+
current_obj = create_or_update_node(attrs.merge(:_parent_id => parent_id, :klass => 'Document'))
|
558
|
+
end
|
559
|
+
else
|
560
|
+
# :folder, :node
|
561
|
+
current_obj = create_or_update_node(attrs.merge(:_parent_id => parent_id))
|
562
|
+
end
|
563
|
+
new_object = new_object || current_obj.instance_variable_get(:@new_record_before_save)
|
564
|
+
end
|
565
|
+
current_obj.instance_variable_set(:@new_record_before_save, new_object)
|
566
|
+
|
567
|
+
current_obj.instance_variable_set(:@versions_count, versions.size)
|
568
|
+
res[current_obj[:id].to_i] = current_obj
|
569
|
+
|
570
|
+
res.merge!(create_nodes_from_folder(:folder => sub_folder, :parent_id => current_obj[:id], :defaults => defaults, :parent_class => opts[:klass])) if sub_folder && !current_obj.new_record?
|
571
|
+
end
|
572
|
+
res
|
573
|
+
end
|
574
|
+
|
575
|
+
def find_by_zip(zip)
|
576
|
+
node = find(:first, :conditions=>"zip = #{zip.to_i}")
|
577
|
+
raise ActiveRecord::RecordNotFound unless node
|
578
|
+
node
|
579
|
+
end
|
580
|
+
|
581
|
+
# Find a node by it's full path. Cache 'fullpath' if found.
|
582
|
+
def find_by_path(path)
|
583
|
+
return nil unless scope = scoped_methods[0]
|
584
|
+
return nil unless scope[:find] # not secured find. refuse.
|
585
|
+
node = self.find_by_fullpath(path)
|
586
|
+
if node.nil?
|
587
|
+
path = path.split('/')
|
588
|
+
last = path.pop
|
589
|
+
# FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
|
590
|
+
Node.send(:with_exclusive_scope) do
|
591
|
+
node = Node.find(current_site[:root_id])
|
592
|
+
path.each do |p|
|
593
|
+
raise ActiveRecord::RecordNotFound unless node = Node.find_by_name_and_parent_id(p, node[:id])
|
594
|
+
end
|
595
|
+
end
|
596
|
+
raise ActiveRecord::RecordNotFound unless node = self.find_by_name_and_parent_id(last, node[:id])
|
597
|
+
path << last
|
598
|
+
node.fullpath = path.join('/')
|
599
|
+
# bypass callbacks here
|
600
|
+
Node.connection.execute "UPDATE #{Node.table_name} SET fullpath='#{path.join('/').gsub("'",'"')}' WHERE id='#{node[:id]}'"
|
601
|
+
end
|
602
|
+
node
|
603
|
+
end
|
604
|
+
|
605
|
+
# Paginate found results. Returns [previous_page, collection, next_page]. You can specify page and items per page in the query hash :
|
606
|
+
# :page => 1, :per_page => 20. This should be wrapped into a secure scope.
|
607
|
+
def find_with_pagination(count, opts)
|
608
|
+
previous_page, collection, next_page, count_all = nil, [], nil, nil
|
609
|
+
per_page = (opts.delete(:per_page) || 20).to_i
|
610
|
+
page = opts.delete(:page) || 1
|
611
|
+
page = page > 0 ? page.to_i : 1
|
612
|
+
offset = (page - 1) * per_page
|
613
|
+
|
614
|
+
if opts[:group]
|
615
|
+
count_select = "DISTINCT #{opts[:group]}"
|
616
|
+
else
|
617
|
+
count_select = opts.delete(:count) || 'nodes.id'
|
618
|
+
end
|
619
|
+
|
620
|
+
# FIXME: why do we need 'exclusive scope' here ?
|
621
|
+
with_exclusive_scope(self.scoped_methods[0] || {}) do
|
622
|
+
count_all = count(opts.merge( :select => count_select, :order => nil, :group => nil ))
|
623
|
+
if count_all > offset
|
624
|
+
collection = find(count, opts.merge(:offset => offset, :limit => per_page))
|
625
|
+
if count_all > (offset + per_page)
|
626
|
+
next_page = page + 1
|
627
|
+
end
|
628
|
+
previous_page = page > 1 ? (page - 1) : nil
|
629
|
+
else
|
630
|
+
# offset too big, previous page = last page
|
631
|
+
previous_page = page > 1 ? ((count_all + per_page - 1) / per_page) : nil
|
632
|
+
end
|
633
|
+
end
|
634
|
+
[previous_page, collection, next_page, count_all]
|
635
|
+
end
|
636
|
+
|
637
|
+
# Return a hash to do a fulltext query.
|
638
|
+
def match_query(query, opts={})
|
639
|
+
node = opts.delete(:node)
|
640
|
+
if query == '.' && node
|
641
|
+
return opts.merge(
|
642
|
+
:conditions => ["parent_id = ?",node[:id]],
|
643
|
+
:order => 'name ASC' )
|
644
|
+
elsif !query.blank?
|
645
|
+
if Zena::Db.adapter == 'mysql' && RAILS_ENV != 'test'
|
646
|
+
match = sanitize_sql(["MATCH (vs.title,vs.text,vs.summary) AGAINST (?) OR nodes.name LIKE ?", query, "#{opts[:name_query] || query.url_name}%"])
|
647
|
+
select = sanitize_sql(["nodes.*, MATCH (vs.title,vs.text,vs.summary) AGAINST (?) + (5 * (nodes.name LIKE ?)) AS score", query, "#{query}%"])
|
648
|
+
else
|
649
|
+
match = sanitize_sql(["nodes.name LIKE ?", "#{query}%"])
|
650
|
+
select = "nodes.*, #{match} AS score"
|
651
|
+
end
|
652
|
+
|
653
|
+
return opts.merge(
|
654
|
+
:select => select,
|
655
|
+
:joins => "INNER JOIN versions AS vs ON vs.node_id = nodes.id AND vs.status >= #{Zena::Status[:pub]}",
|
656
|
+
:conditions => match,
|
657
|
+
:group => "nodes.id",
|
658
|
+
:order => "score DESC, zip ASC")
|
659
|
+
else
|
660
|
+
# error
|
661
|
+
return opts.merge(:conditions => '0')
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
665
|
+
# FIXME: Where is this used ?
|
666
|
+
def class_for_relation(rel)
|
667
|
+
case rel
|
668
|
+
when 'author'
|
669
|
+
User
|
670
|
+
when 'traductions'
|
671
|
+
Version
|
672
|
+
when 'versions'
|
673
|
+
Version
|
674
|
+
else
|
675
|
+
Node
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
def plural_relation?(rel)
|
680
|
+
rel = rel.split(/\s/).first
|
681
|
+
if ['root', 'parent', 'self', 'children', 'documents_only', 'all_pages'].include?(rel) || Node.get_class(rel)
|
682
|
+
rel.pluralize == rel
|
683
|
+
elsif rel =~ /\A\d+\Z/
|
684
|
+
false
|
685
|
+
else
|
686
|
+
relation = RelationProxy.find_by_role(rel.singularize)
|
687
|
+
return rel =~ /s$/ unless relation
|
688
|
+
relation.target_role == rel.singularize ? !relation.target_unique : !relation.source_unique
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
# Translate attributes from the visitor's reference to the application.
|
693
|
+
# This method translates dates, zazen shortcuts and zips and returns a stringified hash.
|
694
|
+
def transform_attributes(new_attributes, base_node = nil)
|
695
|
+
res = {}
|
696
|
+
res['parent_id'] = new_attributes[:_parent_id] if new_attributes[:_parent_id] # real id set inside zena.
|
697
|
+
|
698
|
+
attributes = new_attributes.stringify_keys
|
699
|
+
|
700
|
+
if attributes['copy'] || attributes['copy_id']
|
701
|
+
copy_node = attributes.delete('copy')
|
702
|
+
copy_node ||= Node.find_by_zip(attributes.delete('copy_id'))
|
703
|
+
attributes = copy_node.replace_attributes_in_values(attributes)
|
704
|
+
end
|
705
|
+
|
706
|
+
if !res['parent_id'] && p = attributes['parent_id']
|
707
|
+
res['parent_id'] = Node.translate_pseudo_id(p, :id, base_node) || p
|
708
|
+
end
|
709
|
+
|
710
|
+
attributes.keys.each do |key|
|
711
|
+
next if ['_parent_id', 'parent_id'].include?(key)
|
712
|
+
|
713
|
+
if ['rgroup_id', 'wgroup_id', 'dgroup_id'].include?(key)
|
714
|
+
res[key] = Group.translate_pseudo_id(attributes[key], :id) || attributes[key]
|
715
|
+
elsif ['rgroup', 'wgroup', 'dgroup'].include?(key)
|
716
|
+
res["#{key}_id"] = Group.translate_pseudo_id(attributes[key], :id) || attributes[key]
|
717
|
+
elsif ['user_id'].include?(key)
|
718
|
+
res[key] = User.translate_pseudo_id(attributes[key], :id) || attributes[key]
|
719
|
+
elsif ['date'].include?(key)
|
720
|
+
# FIXME: this is a temporary hack because date in links do not support timezones/formats properly
|
721
|
+
if attributes[key].kind_of?(Time)
|
722
|
+
res[key] = attributes[key]
|
723
|
+
elsif attributes[key]
|
724
|
+
# parse date
|
725
|
+
res[key] = attributes[key].to_utc("%Y-%m-%d %H:%M:%S")
|
726
|
+
end
|
727
|
+
elsif key =~ /^(\w+)_id$/
|
728
|
+
if key[0..1] == 'd_'
|
729
|
+
res[key] = Node.translate_pseudo_id(attributes[key], :zip, base_node) || attributes[key]
|
730
|
+
else
|
731
|
+
res[key] = Node.translate_pseudo_id(attributes[key], :id, base_node) || attributes[key]
|
732
|
+
end
|
733
|
+
elsif key =~ /^(\w+)_ids$/
|
734
|
+
# Id list. Bad ids are removed.
|
735
|
+
values = attributes[key].kind_of?(Array) ? attributes[key] : attributes[key].split(',')
|
736
|
+
if key[0..1] == 'd_'
|
737
|
+
values.map! {|v| Node.translate_pseudo_id(v, :zip, base_node) }
|
738
|
+
else
|
739
|
+
values.map! {|v| Node.translate_pseudo_id(v, :id, base_node) }
|
740
|
+
end
|
741
|
+
res[key] = values.compact
|
742
|
+
elsif key == 'file'
|
743
|
+
unless attributes[key].blank?
|
744
|
+
res[key] = attributes[key]
|
745
|
+
end
|
746
|
+
elsif attributes[key].kind_of?(Hash)
|
747
|
+
res[key] = transform_attributes(attributes[key], base_node)
|
748
|
+
else
|
749
|
+
# translate zazen
|
750
|
+
value = attributes[key]
|
751
|
+
if value.kind_of?(String)
|
752
|
+
# FIXME: ignore if 'v_text' of a TextDocument...
|
753
|
+
res[key] = ZazenParser.new(value,:helper=>self).render(:translate_ids=>:zip, :node=>base_node)
|
754
|
+
else
|
755
|
+
res[key] = value
|
756
|
+
end
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
res
|
761
|
+
end
|
762
|
+
|
763
|
+
def get_attributes_from_yaml(filepath, base_node = nil)
|
764
|
+
attributes = YAML::load( File.read( filepath ) )
|
765
|
+
attributes.delete(:_parent_id)
|
766
|
+
transform_attributes(attributes, base_node)
|
767
|
+
end
|
768
|
+
|
769
|
+
def safe_method_type(signature)
|
770
|
+
if signature.size > 1
|
771
|
+
RubyLess::SafeClass.safe_method_type_for(self, signature)
|
772
|
+
else
|
773
|
+
method = signature.first
|
774
|
+
# if model_names = nested_model_names_for_alias(method)
|
775
|
+
# # ...
|
776
|
+
# end
|
777
|
+
case method[0..1]
|
778
|
+
when 'v_'
|
779
|
+
method = method[2..-1]
|
780
|
+
if type = version_class.safe_method_type([method])
|
781
|
+
type.merge(:method => "version.#{type[:method]}")
|
782
|
+
else
|
783
|
+
# might be readable by sub-classes
|
784
|
+
# what is the expected return type ?
|
785
|
+
{:method => "version.safe_read(#{method.inspect})", :nil => true, :class => String}
|
786
|
+
end
|
787
|
+
when 'c_'
|
788
|
+
method = method[2..-1]
|
789
|
+
klass = version_class.content_class
|
790
|
+
if klass && type = klass.safe_method_type([method])
|
791
|
+
type.merge(:method => "version.content.#{type[:method]}")
|
792
|
+
else
|
793
|
+
{:method => "version.safe_content_read(#{method.inspect})", :nil => true, :class => String}
|
794
|
+
end
|
795
|
+
when 'd_'
|
796
|
+
{:method => "version.dyn[#{method[2..-1].inspect}]", :nil => true, :class => String}
|
797
|
+
else
|
798
|
+
if method =~ /^(.+)_((id|zip|status|comment)(s?))\Z/ && !instance_methods.include?(method)
|
799
|
+
{:method => "rel[#{$1.inspect}].try(:other_#{$2})", :nil => true, :class => ($4.blank? ? Number : [Number])}
|
800
|
+
else
|
801
|
+
RubyLess::SafeClass.safe_method_type_for(self, signature)
|
802
|
+
end
|
803
|
+
end
|
804
|
+
end
|
805
|
+
end
|
806
|
+
|
807
|
+
# Return a safe string to access node attributes in compiled templates and compiled sql.
|
808
|
+
def zafu_attribute(node, attribute)
|
809
|
+
if node.kind_of?(String)
|
810
|
+
raise Exception.new("You should use safe_method_type...")
|
811
|
+
else
|
812
|
+
node.safe_read(attribute)
|
813
|
+
end
|
814
|
+
end
|
815
|
+
|
816
|
+
|
817
|
+
def auto_create_discussion
|
818
|
+
false
|
819
|
+
end
|
820
|
+
end
|
821
|
+
|
822
|
+
# TODO: remove when :inverse_of works.
|
823
|
+
def versions_with_secure(*args)
|
824
|
+
proxy = versions_without_secure(*args)
|
825
|
+
if frozen?
|
826
|
+
proxy = []
|
827
|
+
elsif proxy.loaded?
|
828
|
+
proxy.each do |v|
|
829
|
+
v.node = self
|
830
|
+
end
|
831
|
+
end
|
832
|
+
proxy
|
833
|
+
end
|
834
|
+
alias_method_chain :versions, :secure
|
835
|
+
|
836
|
+
# Additional security so that unsecure finders explode when trying to update/save or follow relations.
|
837
|
+
def visitor
|
838
|
+
return @visitor if @visitor
|
839
|
+
# We need to be more tolerant during object creation since 'v_foo' can be
|
840
|
+
# set before 'visitor' and we need visitor.lang when creating versions.
|
841
|
+
return Thread.current.visitor if new_record?
|
842
|
+
raise Zena::RecordNotSecured.new("Visitor not set, record not secured.")
|
843
|
+
end
|
844
|
+
|
845
|
+
# Return an attribute if it is safe (RubyLess allowed). Return nil otherwise.
|
846
|
+
# This is mostly used when the zafu compiler cannot decide whether a method is safe or not at compile time.
|
847
|
+
def safe_read(attribute)
|
848
|
+
case attribute[0..1]
|
849
|
+
when 'v_'
|
850
|
+
version.safe_read(attribute[2..-1])
|
851
|
+
when 'c_'
|
852
|
+
version.safe_content_read(attribute[2..-1])
|
853
|
+
when 'd_'
|
854
|
+
version.dyn[attribute[2..-1]]
|
855
|
+
else
|
856
|
+
if @attributes.has_key?(attribute) &&
|
857
|
+
!self.class.column_names.include?(attribute) &&
|
858
|
+
!methods.include?(attribute) &&
|
859
|
+
!self.class.safe_method_type([attribute])
|
860
|
+
# db fetch only: select 'created_at AS age' ----> 'age' can be read
|
861
|
+
@attributes[attribute]
|
862
|
+
else
|
863
|
+
super
|
864
|
+
end
|
865
|
+
end
|
866
|
+
end
|
867
|
+
|
868
|
+
# check inheritance chain through kpath
|
869
|
+
def kpath_match?(kpath)
|
870
|
+
vclass.kpath =~ /^#{kpath}/
|
871
|
+
end
|
872
|
+
|
873
|
+
# virtual class
|
874
|
+
def vclass
|
875
|
+
virtual_class || self.class
|
876
|
+
end
|
877
|
+
|
878
|
+
def klass
|
879
|
+
@new_klass || @set_klass || vclass.to_s
|
880
|
+
end
|
881
|
+
|
882
|
+
def dyn_attribute_keys
|
883
|
+
(version.dyn.keys + (virtual_class ? virtual_class.dyn_keys.to_s.split(',').map(&:strip) : [])).uniq.sort
|
884
|
+
end
|
885
|
+
|
886
|
+
def klass=(str)
|
887
|
+
return if str == klass
|
888
|
+
@new_klass = str
|
889
|
+
end
|
890
|
+
|
891
|
+
# include virtual classes to check inheritance chain
|
892
|
+
def vkind_of?(klass)
|
893
|
+
if self.class.ancestors.map{|k| k.to_s}.include?(klass)
|
894
|
+
true
|
895
|
+
elsif virt = VirtualClass.find(:first, :conditions=>["site_id = ? AND name = ?",current_site[:id], klass])
|
896
|
+
kpath_match?(virt.kpath)
|
897
|
+
end
|
898
|
+
end
|
899
|
+
|
900
|
+
# Update a node's attributes, transforming the attributes first from the visitor's context to Node context.
|
901
|
+
def update_attributes_with_transformation(new_attributes)
|
902
|
+
update_attributes(secure(Node) {Node.transform_attributes(new_attributes, self)})
|
903
|
+
end
|
904
|
+
|
905
|
+
# Replace [id], [v_title], etc in attributes values
|
906
|
+
def replace_attributes_in_values(hash)
|
907
|
+
hash.each do |k,v|
|
908
|
+
v.gsub!(/\[([^\]]+)\]/) do
|
909
|
+
attribute = $1
|
910
|
+
real_attribute = attribute =~ /\Ad_/ ? attribute : attribute.gsub(/\A(|[\w_]+)id(s?)\Z/, '\1zip\2')
|
911
|
+
Node.zafu_attribute(self, real_attribute)
|
912
|
+
end
|
913
|
+
end
|
914
|
+
end
|
915
|
+
|
916
|
+
|
917
|
+
# Parse text content and replace all relative urls ('../projects/art') by ids ('34')
|
918
|
+
def parse_assets(text, helper, key)
|
919
|
+
# helper is used in textdocuments
|
920
|
+
ZazenParser.new(text,:helper=>helper).render(:translate_ids => :zip, :node => self)
|
921
|
+
end
|
922
|
+
|
923
|
+
# Parse text and replace ids '!30!' by their pseudo path '!(img/bird)!'
|
924
|
+
def unparse_assets(text, helper, key)
|
925
|
+
ZazenParser.new(text,:helper=>helper).render(:translate_ids => :relative_path, :node=>self)
|
926
|
+
end
|
927
|
+
|
928
|
+
# Return the list of ancestors (without self): [root, obj, obj]
|
929
|
+
# ancestors to which the visitor has no access are removed from the list
|
930
|
+
def ancestors(start=[])
|
931
|
+
raise Zena::InvalidRecord, "Infinit loop in 'ancestors' (#{start.inspect} --> #{self[:id]})" if start.include?(self[:id])
|
932
|
+
start += [self[:id]]
|
933
|
+
if self[:id] == current_site[:root_id]
|
934
|
+
[]
|
935
|
+
elsif self[:parent_id].nil?
|
936
|
+
[]
|
937
|
+
else
|
938
|
+
parent = @parent || Node.find(self[:parent_id])
|
939
|
+
parent.visitor = visitor
|
940
|
+
if parent.can_read?
|
941
|
+
parent.ancestors(start) + [parent]
|
942
|
+
else
|
943
|
+
parent.ancestors(start)
|
944
|
+
end
|
945
|
+
end
|
946
|
+
end
|
947
|
+
|
948
|
+
|
949
|
+
# Return the same basepath as the parent. Is overwriten by 'Page' class.
|
950
|
+
def basepath(rebuild=false, update= true)
|
951
|
+
if !self[:basepath] || rebuild
|
952
|
+
if self[:parent_id]
|
953
|
+
parent = parent(false)
|
954
|
+
path = parent ? parent.basepath(rebuild) : ''
|
955
|
+
else
|
956
|
+
path = ''
|
957
|
+
end
|
958
|
+
self.connection.execute "UPDATE #{self.class.table_name} SET basepath='#{path}' WHERE id='#{self[:id]}'" if path != self[:basepath] && update
|
959
|
+
self[:basepath] = path
|
960
|
+
end
|
961
|
+
self[:basepath]
|
962
|
+
end
|
963
|
+
|
964
|
+
# Return the full path as an array if it is cached or build it when asked for.
|
965
|
+
def fullpath(rebuild=false, update = true, loop_ids = [])
|
966
|
+
return "" if loop_ids.include?(self.id)
|
967
|
+
loop_ids << self.id
|
968
|
+
if !self[:fullpath] || rebuild
|
969
|
+
if parent = parent(false)
|
970
|
+
path = parent.fullpath(rebuild,true,loop_ids).split('/') + [name.gsub("'",'')]
|
971
|
+
else
|
972
|
+
path = []
|
973
|
+
end
|
974
|
+
path = path.join('/')
|
975
|
+
self.connection.execute "UPDATE #{self.class.table_name} SET fullpath='#{path}' WHERE id='#{self[:id]}'" if path != self[:fullpath] && update
|
976
|
+
self[:fullpath] = path
|
977
|
+
end
|
978
|
+
self[:fullpath]
|
979
|
+
end
|
980
|
+
|
981
|
+
# Same as fullpath, but the path includes the root node.
|
982
|
+
def rootpath
|
983
|
+
current_site.name + (fullpath != "" ? "/#{fullpath}" : "")
|
984
|
+
end
|
985
|
+
|
986
|
+
alias path rootpath
|
987
|
+
|
988
|
+
# Return an array with the node name and the last two parents' names.
|
989
|
+
def short_path
|
990
|
+
path = self.rootpath.split('/')
|
991
|
+
if path.size > 2
|
992
|
+
['..'] + path[-2..-1]
|
993
|
+
else
|
994
|
+
path
|
995
|
+
end
|
996
|
+
end
|
997
|
+
|
998
|
+
def pseudo_id(root_node, sym)
|
999
|
+
case sym
|
1000
|
+
when :zip
|
1001
|
+
self.zip
|
1002
|
+
when :relative_path
|
1003
|
+
full = self.fullpath
|
1004
|
+
root = root_node ? root_node.fullpath : ''
|
1005
|
+
"(#{full.rel_path(root)})"
|
1006
|
+
end
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
# Return save path for an asset (element produced by text like a png file from LateX)
|
1010
|
+
def asset_path(asset_filename)
|
1011
|
+
# It would be nice to move this outside 'self[:id]' so that the same asset can
|
1012
|
+
# be used by many pages... But then, how do we expire unused assets ?
|
1013
|
+
"#{SITES_ROOT}#{site.data_path}/asset/#{self[:id]}/#{asset_filename}"
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
# Used by zafu to find the search score
|
1017
|
+
# def score
|
1018
|
+
# self[:score]
|
1019
|
+
# end
|
1020
|
+
|
1021
|
+
def all_relations
|
1022
|
+
@all_relations ||= self.vclass.all_relations(self)
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
# Find parent
|
1026
|
+
def parent(is_secure = true)
|
1027
|
+
# make sure the cache is in sync with 'parent_id' (used during validation)
|
1028
|
+
if self[:parent_id].nil?
|
1029
|
+
nil
|
1030
|
+
elsif is_secure
|
1031
|
+
# cache parent result (done through secure query)
|
1032
|
+
return @parent if @parent && @parent[:id] == self[:parent_id]
|
1033
|
+
@parent = secure(Node) { Node.find(self[:parent_id]) }
|
1034
|
+
else
|
1035
|
+
# not secured (inside an exclusive scope)
|
1036
|
+
return @parent_insecure if @parent_insecure && @parent_insecure[:id] == self[:parent_id]
|
1037
|
+
@parent_insecure = secure(Node, :secure => false) { Node.find(self[:parent_id]) }
|
1038
|
+
end
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
# Return self if the current node is a section else find section.
|
1042
|
+
def section
|
1043
|
+
self.kind_of?(Section) ? self : real_section
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
# Find real section
|
1047
|
+
def real_section(is_secure = true)
|
1048
|
+
return self if self[:parent_id].nil? # root
|
1049
|
+
# we cannot use Section to find because the root node behaves like a Section but is a Project.
|
1050
|
+
if is_secure
|
1051
|
+
secure(Node) { Node.find(self[:section_id]) }
|
1052
|
+
else
|
1053
|
+
secure(Node, :secure => false) { Node.find(self[:section_id]) }
|
1054
|
+
end
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
# Return self if the current node is a project else find project.
|
1058
|
+
def project
|
1059
|
+
self.kind_of?(Project) ? self : real_project
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
# Find real project (Project's project if node is a Project)
|
1063
|
+
def real_project(is_secure = true)
|
1064
|
+
return self if self[:parent_id].nil?
|
1065
|
+
if is_secure
|
1066
|
+
secure(Project) { Project.find(self[:project_id]) }
|
1067
|
+
else
|
1068
|
+
secure(Node, :secure => false) { Project.find(self[:project_id]) }
|
1069
|
+
end
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
# Create a child and let him inherit from rwp groups and section_id
|
1073
|
+
def new_child(opts={})
|
1074
|
+
klass = opts.delete(:class) || Page
|
1075
|
+
c = klass.new(opts)
|
1076
|
+
c.parent_id = self[:id]
|
1077
|
+
c.instance_variable_set(:@parent, self)
|
1078
|
+
|
1079
|
+
c.visitor = visitor
|
1080
|
+
|
1081
|
+
c.inherit = 1
|
1082
|
+
c.rgroup_id = self.rgroup_id
|
1083
|
+
c.wgroup_id = self.wgroup_id
|
1084
|
+
c.dgroup_id = self.dgroup_id
|
1085
|
+
|
1086
|
+
c.section_id = self.get_section_id
|
1087
|
+
c.project_id = self.get_project_id
|
1088
|
+
c
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
# ACCESSORS
|
1092
|
+
def author
|
1093
|
+
user.contact
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
# Find icon through a relation named 'icon' or use first image child
|
1097
|
+
def icon
|
1098
|
+
return nil if new_record?
|
1099
|
+
return @icon if defined? @icon
|
1100
|
+
query = Node.build_find(:first, ['icon group by id,l_id order by l_id desc, position asc, name asc', 'image'], :node_name => 'self')
|
1101
|
+
sql_str, uses_node_name = query.to_s, query.uses_node_name
|
1102
|
+
@icon = sql_str ? do_find(:first, eval(sql_str), :ignore_source => !uses_node_name) : nil
|
1103
|
+
end
|
1104
|
+
|
1105
|
+
alias o_user user
|
1106
|
+
|
1107
|
+
def user
|
1108
|
+
secure!(User) { o_user }
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
# Find all data entries linked to the current node
|
1112
|
+
def data
|
1113
|
+
list = DataEntry.find(:all, :conditions => "node_a_id = #{id} OR node_b_id = #{id} OR node_c_id = #{id} OR node_d_id = #{id}", :order => 'date ASC,created_at ASC')
|
1114
|
+
list == [] ? nil : list
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
if Node.connection.tables.include?('data_entries')
|
1118
|
+
# We need this guard during initial migration (Node loaded before data entries table is created).
|
1119
|
+
# FIXME: remove in [1.1] when we 'squash' all migrations
|
1120
|
+
|
1121
|
+
DataEntry::NodeLinkSymbols.each do |sym|
|
1122
|
+
# Find data entries through a specific slot (node_a, node_b). "data_entries_a" finds all data entries link through 'node_a_id'.
|
1123
|
+
class_eval "def #{sym.to_s.gsub('node', 'data')}
|
1124
|
+
return nil if new_record?
|
1125
|
+
list = DataEntry.find(:all, :conditions=>\"#{sym}_id = '\#{self[:id]}'\")
|
1126
|
+
list == [] ? nil : list
|
1127
|
+
end"
|
1128
|
+
end
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
def ext
|
1132
|
+
(name && name != '' && name =~ /\./ ) ? name.split('.').last : ''
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
# set name: remove all accents and camelize
|
1136
|
+
def name=(str)
|
1137
|
+
return unless str && str != ""
|
1138
|
+
self[:name] = str.url_name
|
1139
|
+
end
|
1140
|
+
|
1141
|
+
# Return current discussion id (used by query_builder)
|
1142
|
+
def get_discussion_id
|
1143
|
+
(discussion && !discussion.new_record?) ? discussion[:id] : '0'
|
1144
|
+
end
|
1145
|
+
|
1146
|
+
# Return self[:id] if the node is a kind of Section. Return section_id otherwise.
|
1147
|
+
def get_section_id
|
1148
|
+
# root node is it's own section and project
|
1149
|
+
self[:parent_id].nil? ? self[:id] : self[:section_id]
|
1150
|
+
end
|
1151
|
+
|
1152
|
+
# Return self[:id] if the node is a kind of Project. Return project_id otherwise.
|
1153
|
+
def get_project_id
|
1154
|
+
# root node is it's own section and project
|
1155
|
+
self[:parent_id].nil? ? self[:id] : self[:project_id]
|
1156
|
+
end
|
1157
|
+
|
1158
|
+
# Id to zip mapping for parent_id. Used by zafu and forms.
|
1159
|
+
def parent_zip
|
1160
|
+
parent ? parent[:zip] : nil
|
1161
|
+
end
|
1162
|
+
|
1163
|
+
# Id to zip mapping for section_id. Used by zafu and forms.
|
1164
|
+
def section_zip
|
1165
|
+
section[:zip]
|
1166
|
+
end
|
1167
|
+
|
1168
|
+
# Id to zip mapping for project_id. Used by zafu and forms.
|
1169
|
+
def project_zip
|
1170
|
+
project[:zip]
|
1171
|
+
end
|
1172
|
+
|
1173
|
+
# Id to zip mapping for user_id. Used by zafu and forms.
|
1174
|
+
def user_zip; self[:user_id]; end
|
1175
|
+
|
1176
|
+
# transform to another class
|
1177
|
+
# def vclass=(new_class)
|
1178
|
+
# if new_class.kind_of?(String)
|
1179
|
+
# klass = Module.const_get(new_class)
|
1180
|
+
# else
|
1181
|
+
# klass = new_class
|
1182
|
+
# end
|
1183
|
+
# raise NameError if !klass.ancestors.include?(Node) || klass.version_class != self.class.content_class
|
1184
|
+
#
|
1185
|
+
#
|
1186
|
+
#
|
1187
|
+
# rescue NameError
|
1188
|
+
# errors.add('klass', 'invalid')
|
1189
|
+
# end
|
1190
|
+
|
1191
|
+
# transform an Node into another Object. This is a two step operation :
|
1192
|
+
# 1. create a new object with the attributes from the old one
|
1193
|
+
# 2. move old object out of the way (setting parent_id and section_id to -1)
|
1194
|
+
# 3. try to save new object
|
1195
|
+
# 4. delete old and set new object id to old
|
1196
|
+
# THIS IS DANGEROUS !! NEEDS TESTING
|
1197
|
+
# def change_to(klass)
|
1198
|
+
# return nil if self[:id] == current_site[:root_id]
|
1199
|
+
# # ==> Check for class specific information (file to remove, participations, tags, etc) ... should we leave these things and
|
1200
|
+
# # not care ?
|
1201
|
+
# # ==> When changing into something else : update version type and data !!!
|
1202
|
+
# my_id = self[:id].to_i
|
1203
|
+
# my_parent = self[:parent_id].to_i
|
1204
|
+
# my_project = self[:section_id].to_i
|
1205
|
+
# connection = self.class.connection
|
1206
|
+
# # 1. create a new object with the attributes from the old one
|
1207
|
+
# new_obj = secure!(klass) { klass.new(self.attributes) }
|
1208
|
+
# # 2. move old object out of the way (setting parent_id and section_id to -1)
|
1209
|
+
# self.class.connection.execute "UPDATE #{self.class.table_name} SET parent_id='0', section_id='0' WHERE id=#{my_id}"
|
1210
|
+
# # 3. try to save new object
|
1211
|
+
# if new_obj.save
|
1212
|
+
# tmp_id = new_obj[:id]
|
1213
|
+
# # 4. delete old and set new object id to old. Delete tmp Version.
|
1214
|
+
# self.class.connection.execute "DELETE FROM #{self.class.table_name} WHERE id=#{my_id}"
|
1215
|
+
# self.class.connection.execute "DELETE FROM #{Version.table_name} WHERE node_id=#{tmp_id}"
|
1216
|
+
# self.class.connection.execute "UPDATE #{self.class.table_name} SET id='#{my_id}' WHERE id=#{tmp_id}"
|
1217
|
+
# self.class.connection.execute "UPDATE #{self.class.table_name} SET section_id=id WHERE id=#{my_id}" if new_obj.kind_of?(Section)
|
1218
|
+
# self.class.logger.info "[#{self[:id]}] #{self.class} --> #{klass}"
|
1219
|
+
# if new_obj.kind_of?(Section)
|
1220
|
+
# # update section_id for children
|
1221
|
+
# sync_section(my_id)
|
1222
|
+
# elsif self.kind_of?(Section)
|
1223
|
+
# # update section_id for children
|
1224
|
+
# sync_section(parent[:section_id])
|
1225
|
+
# end
|
1226
|
+
# secure ( klass ) { klass.find(my_id) }
|
1227
|
+
# else
|
1228
|
+
# # set object back
|
1229
|
+
# self.class.connection.execute "UPDATE #{self.class.table_name} SET parent_id='#{my_parent}', section_id='#{my_project}' WHERE id=#{my_id}"
|
1230
|
+
# self
|
1231
|
+
# end
|
1232
|
+
# end
|
1233
|
+
|
1234
|
+
# Find the discussion for the current context (v_status and v_lang). This automatically creates a new #Discussion if there is
|
1235
|
+
# no closed or open discussion for the current lang and Node#can_auto_create_discussion? is true
|
1236
|
+
def discussion
|
1237
|
+
return @discussion if defined?(@discussion)
|
1238
|
+
|
1239
|
+
@discussion = Discussion.find(:first, :conditions=>[ "node_id = ? AND inside = ? AND lang = ?",
|
1240
|
+
self[:id], v_status != Zena::Status[:pub], v_lang ], :order=>'id DESC') ||
|
1241
|
+
if can_auto_create_discussion?
|
1242
|
+
Discussion.new(:node_id=>self[:id], :lang=>v_lang, :inside=>(v_status != Zena::Status[:pub]))
|
1243
|
+
else
|
1244
|
+
nil
|
1245
|
+
end
|
1246
|
+
end
|
1247
|
+
|
1248
|
+
# Automatically create a discussion if any of the following conditions are met:
|
1249
|
+
# - there already exists an +outside+, +open+ discussion for another language
|
1250
|
+
# - the node is not published (creates an internal discussion)
|
1251
|
+
# - the user has drive access to the node
|
1252
|
+
def can_auto_create_discussion?
|
1253
|
+
can_drive? ||
|
1254
|
+
(v_status != Zena::Status[:pub]) ||
|
1255
|
+
Discussion.find(:first, :conditions=>[ "node_id = ? AND inside = ? AND open = ?",
|
1256
|
+
self[:id], false, true ])
|
1257
|
+
end
|
1258
|
+
|
1259
|
+
# FIXME: use nested_attributes_alias and try to use native Rails to create the comment
|
1260
|
+
# comment_attributes=, ...
|
1261
|
+
def m_text; ''; end
|
1262
|
+
def m_title; ''; end
|
1263
|
+
def m_author; ''; end
|
1264
|
+
|
1265
|
+
def m_text=(str)
|
1266
|
+
@add_comment ||= {}
|
1267
|
+
@add_comment[:text] = str
|
1268
|
+
end
|
1269
|
+
|
1270
|
+
def m_title=(str)
|
1271
|
+
@add_comment ||= {}
|
1272
|
+
@add_comment[:title] = str
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
def m_author=(str)
|
1276
|
+
@add_comment ||= {}
|
1277
|
+
@add_comment[:author] = str
|
1278
|
+
end
|
1279
|
+
|
1280
|
+
# Comments for the current context. Returns nil when there is no discussion.
|
1281
|
+
def comments
|
1282
|
+
if discussion
|
1283
|
+
res = discussion.comments(:with_prop=>can_drive?)
|
1284
|
+
res == [] ? nil : res
|
1285
|
+
else
|
1286
|
+
nil
|
1287
|
+
end
|
1288
|
+
end
|
1289
|
+
|
1290
|
+
# TODO: remove, replace by relation proxy: proxy.count...
|
1291
|
+
def comments_count
|
1292
|
+
if discussion
|
1293
|
+
discussion.comments_count(:with_prop=>can_drive?)
|
1294
|
+
else
|
1295
|
+
0
|
1296
|
+
end
|
1297
|
+
end
|
1298
|
+
|
1299
|
+
# Return true if it is allowed to add comments to the node in the current context
|
1300
|
+
def can_comment?
|
1301
|
+
visitor.commentator? && discussion && discussion.open?
|
1302
|
+
end
|
1303
|
+
|
1304
|
+
# TODO: test
|
1305
|
+
def sweep_cache
|
1306
|
+
return if current_site.being_created?
|
1307
|
+
# zafu 'erb' rendering cache expire
|
1308
|
+
# TODO: expire only 'dev' rendering if version is a redaction
|
1309
|
+
CachedPage.expire_with(self) if self.kind_of?(Template)
|
1310
|
+
|
1311
|
+
# Clear element cache
|
1312
|
+
Cache.sweep(:visitor_id=>self[:user_id], :visitor_groups=>[rgroup_id, wgroup_id, dgroup_id], :kpath=>self.vclass.kpath)
|
1313
|
+
|
1314
|
+
# Clear full result cache
|
1315
|
+
|
1316
|
+
# we want to be sure to find the project and parent, even if the visitor does not have an
|
1317
|
+
# access to these elements.
|
1318
|
+
# FIXME: use self + modified relations instead of parent/project
|
1319
|
+
[self, self.real_project(false), self.real_section(false), self.parent(false)].compact.uniq.each do |obj|
|
1320
|
+
# destroy all pages in project, parent and section !
|
1321
|
+
CachedPage.expire_with(obj)
|
1322
|
+
# this destroys less cache but might miss things like 'changes in project' that are displayed on every page.
|
1323
|
+
# CachedPage.expire_with(self, [self[:project_id], self[:section_id], self[:parent_id]].compact.uniq)
|
1324
|
+
end
|
1325
|
+
|
1326
|
+
# clear assets
|
1327
|
+
FileUtils::rmtree(asset_path(''))
|
1328
|
+
end
|
1329
|
+
|
1330
|
+
# Include data entry verification in multiversion's empty? method.
|
1331
|
+
def empty?
|
1332
|
+
return true if new_record?
|
1333
|
+
super && 0 == self.class.count_by_sql("SELECT COUNT(*) FROM #{DataEntry.table_name} WHERE node_a_id = #{id} OR node_b_id = #{id} OR node_c_id = #{id} OR node_d_id = #{id}")
|
1334
|
+
end
|
1335
|
+
|
1336
|
+
# create a 'tgz' archive with node content and children, returning temporary file path
|
1337
|
+
def archive
|
1338
|
+
n = 0
|
1339
|
+
while true
|
1340
|
+
folder_path = File.join(RAILS_ROOT, 'tmp', sprintf('%s.%d.%d', 'archive', $$, n))
|
1341
|
+
break unless File.exists?(folder_path)
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
begin
|
1345
|
+
FileUtils::mkpath(folder_path)
|
1346
|
+
export_to_folder(folder_path)
|
1347
|
+
tempf = Tempfile.new(name)
|
1348
|
+
`cd #{folder_path}; tar czf #{tempf.path} *`
|
1349
|
+
ensure
|
1350
|
+
FileUtils::rmtree(folder_path)
|
1351
|
+
end
|
1352
|
+
tempf
|
1353
|
+
end
|
1354
|
+
|
1355
|
+
# export node content and children into a folder
|
1356
|
+
def export_to_folder(path)
|
1357
|
+
children = secure(Node) { Node.find(:all, :conditions=>['parent_id = ?', self[:id] ]) }
|
1358
|
+
|
1359
|
+
if kind_of?(Document) && version.title == name && (kind_of?(TextDocument) || version.text.blank? || version.text == "!#{zip}!")
|
1360
|
+
# skip zml
|
1361
|
+
# TODO: this should better check that version content is really useless
|
1362
|
+
elsif version.title == name && version.text.blank? && klass == 'Page' && children
|
1363
|
+
# skip zml
|
1364
|
+
else
|
1365
|
+
File.open(File.join(path, name + '.zml'), 'wb') do |f|
|
1366
|
+
f.puts self.to_yaml
|
1367
|
+
end
|
1368
|
+
end
|
1369
|
+
|
1370
|
+
if kind_of?(Document)
|
1371
|
+
data = kind_of?(TextDocument) ? StringIO.new(version.text) : version.content.file
|
1372
|
+
File.open(File.join(path, filename), 'wb') { |f| f.syswrite(data.read) }
|
1373
|
+
end
|
1374
|
+
|
1375
|
+
if children
|
1376
|
+
content_folder = File.join(path,name)
|
1377
|
+
FileUtils::mkpath(content_folder)
|
1378
|
+
children.each do |child|
|
1379
|
+
child.export_to_folder(content_folder)
|
1380
|
+
end
|
1381
|
+
end
|
1382
|
+
end
|
1383
|
+
|
1384
|
+
# export node as a hash
|
1385
|
+
def to_yaml
|
1386
|
+
hash = {}
|
1387
|
+
export_keys[:zazen].each do |k, v|
|
1388
|
+
hash[k] = unparse_assets(v, self, k)
|
1389
|
+
end
|
1390
|
+
|
1391
|
+
export_keys[:dates].each do |k, v|
|
1392
|
+
hash[k] = visitor.tz.utc_to_local(v).strftime("%Y-%m-%d %H:%M:%S")
|
1393
|
+
end
|
1394
|
+
|
1395
|
+
hash.merge!('class' => self.klass)
|
1396
|
+
hash.to_yaml
|
1397
|
+
end
|
1398
|
+
|
1399
|
+
# List of attribute keys to export in a zml file.
|
1400
|
+
def export_keys
|
1401
|
+
{
|
1402
|
+
:zazen => version.export_keys[:zazen],
|
1403
|
+
:dates => version.export_keys[:dates],
|
1404
|
+
}
|
1405
|
+
end
|
1406
|
+
|
1407
|
+
# List of attribute keys to transform (change references, etc).
|
1408
|
+
def parse_keys
|
1409
|
+
export_keys[:zazen].keys
|
1410
|
+
end
|
1411
|
+
|
1412
|
+
# This is needed during 'unparse_assets' when the node is it's own helper
|
1413
|
+
def find_node_by_pseudo(string, base_node = nil)
|
1414
|
+
secure(Node) { Node.find_node_by_pseudo(string, base_node || self) }
|
1415
|
+
end
|
1416
|
+
|
1417
|
+
protected
|
1418
|
+
|
1419
|
+
# after node is saved, make sure it's children have the correct section set
|
1420
|
+
def spread_project_and_section
|
1421
|
+
if @spread_section_id || @spread_project_id
|
1422
|
+
# update children
|
1423
|
+
sync_section_and_project(@spread_section_id, @spread_project_id)
|
1424
|
+
remove_instance_variable :@spread_section_id if @spread_section_id
|
1425
|
+
remove_instance_variable :@spread_project_id if @spread_project_id
|
1426
|
+
end
|
1427
|
+
end
|
1428
|
+
|
1429
|
+
# node [change project and section]
|
1430
|
+
# |
|
1431
|
+
# +-- node [set project] [set section]
|
1432
|
+
# |
|
1433
|
+
# +-- section 4 [set project] [ keep ]
|
1434
|
+
# | |
|
1435
|
+
# | +-- node [set project] [ keep ]
|
1436
|
+
# | |
|
1437
|
+
# | +-- project [ keep ] [ keep ] => skip
|
1438
|
+
# |
|
1439
|
+
# +-- page [set project] [set section]
|
1440
|
+
# |
|
1441
|
+
# +-- project [ keep ] [set section]
|
1442
|
+
# |
|
1443
|
+
# +-- node [ keep ] [set section]
|
1444
|
+
# |
|
1445
|
+
# +-- section [ keep ] [ keep ] => skip
|
1446
|
+
def sync_section_and_project(section_id, project_id)
|
1447
|
+
|
1448
|
+
# If this code is optimized, do not forget to sweep_cache for each modified child.
|
1449
|
+
all_children.each do |child|
|
1450
|
+
if child.kind_of?(Section) # [keep section] [set project]
|
1451
|
+
next unless project_id # => skip
|
1452
|
+
# needed when doing 'sweep_cache'.
|
1453
|
+
visitor.visit(child)
|
1454
|
+
|
1455
|
+
child[:project_id] = project_id # [set project]
|
1456
|
+
child.save_with_validation(false)
|
1457
|
+
child.sync_section_and_project( nil , project_id)
|
1458
|
+
|
1459
|
+
elsif child.kind_of?(Project) # [set section] [keep project]
|
1460
|
+
next unless section_id # => skip
|
1461
|
+
# needed when doing 'sweep_cache'.
|
1462
|
+
visitor.visit(child)
|
1463
|
+
|
1464
|
+
child[:section_id] = section_id # [set section]
|
1465
|
+
child.save_with_validation(false)
|
1466
|
+
child.sync_section_and_project(section_id, nil )
|
1467
|
+
else # [set section] [set project]
|
1468
|
+
# needed when doing 'sweep_cache'.
|
1469
|
+
visitor.visit(child)
|
1470
|
+
|
1471
|
+
child[:section_id] = section_id if section_id #[set section]
|
1472
|
+
child[:project_id] = project_id if project_id # [set project]
|
1473
|
+
child.save_with_validation(false)
|
1474
|
+
child.sync_section_and_project(section_id, project_id)
|
1475
|
+
end
|
1476
|
+
end
|
1477
|
+
end
|
1478
|
+
|
1479
|
+
private
|
1480
|
+
def node_before_validation
|
1481
|
+
self[:kpath] = self.vclass.kpath
|
1482
|
+
|
1483
|
+
self.name ||= (version.title || '').url_name
|
1484
|
+
|
1485
|
+
if ref_lang == version.lang &&
|
1486
|
+
((full_drive? && version.status == Zena::Status[:pub]) ||
|
1487
|
+
(can_drive? && vhash['r'][ref_lang].nil?))
|
1488
|
+
if name_changed? && !name.blank?
|
1489
|
+
version.title = self.name.gsub(/([A-Z])/) { " #{$1.downcase}" }
|
1490
|
+
elsif !version.title.blank?
|
1491
|
+
self.name = version.title.url_name
|
1492
|
+
end
|
1493
|
+
end
|
1494
|
+
|
1495
|
+
unless name.blank?
|
1496
|
+
# update cached fullpath
|
1497
|
+
if new_record? || name_changed? || parent_id_changed?
|
1498
|
+
self[:fullpath] = self.fullpath(true,false)
|
1499
|
+
elsif !new_record? && custom_base_changed?
|
1500
|
+
self[:basepath] = self.basepath(true,false)
|
1501
|
+
end
|
1502
|
+
if !new_record? && fullpath_changed?
|
1503
|
+
# FIXME: update children's cached fullpaths
|
1504
|
+
@clear_children_fullpath = true
|
1505
|
+
end
|
1506
|
+
end
|
1507
|
+
|
1508
|
+
# make sure section is the same as the parent
|
1509
|
+
if self[:parent_id].nil?
|
1510
|
+
# root node
|
1511
|
+
self[:section_id] = self[:id]
|
1512
|
+
self[:project_id] = self[:id]
|
1513
|
+
elsif parent
|
1514
|
+
self[:section_id] = ref.get_section_id
|
1515
|
+
self[:project_id] = ref.get_project_id
|
1516
|
+
else
|
1517
|
+
# bad parent will be caught later.
|
1518
|
+
end
|
1519
|
+
|
1520
|
+
if !new_record? && self[:parent_id]
|
1521
|
+
# node updated and it is not the root node
|
1522
|
+
if !kind_of?(Section) && section_id_changed?
|
1523
|
+
@spread_section_id = self[:section_id]
|
1524
|
+
end
|
1525
|
+
if !kind_of?(Project) && project_id_changed?
|
1526
|
+
@spread_project_id = self[:project_id]
|
1527
|
+
end
|
1528
|
+
end
|
1529
|
+
|
1530
|
+
# set position
|
1531
|
+
if klass != 'Node'
|
1532
|
+
# 'Node' does not have a position scope (need two first letters of kpath)
|
1533
|
+
if new_record?
|
1534
|
+
if self[:position].to_f == 0
|
1535
|
+
pos = Zena::Db.fetch_row("SELECT `position` FROM #{Node.table_name} WHERE parent_id = #{Node.connection.quote(self[:parent_id])} AND kpath like #{Node.connection.quote("#{self.class.kpath[0..1]}%")} ORDER BY position DESC LIMIT 1").to_f
|
1536
|
+
self[:position] = pos > 0 ? pos + 1.0 : 0.0
|
1537
|
+
end
|
1538
|
+
elsif parent_id_changed?
|
1539
|
+
# moved, update position
|
1540
|
+
pos = Zena::Db.fetch_row("SELECT `position` FROM #{Node.table_name} WHERE parent_id = #{Node.connection.quote(self[:parent_id])} AND kpath like #{Node.connection.quote("#{self.class.kpath[0..1]}%")} ORDER BY position DESC LIMIT 1").to_f
|
1541
|
+
self[:position] = pos > 0 ? pos + 1.0 : 0.0
|
1542
|
+
end
|
1543
|
+
end
|
1544
|
+
|
1545
|
+
end
|
1546
|
+
|
1547
|
+
# Make sure the node is complete before creating it (check parent and project references)
|
1548
|
+
def validate_node
|
1549
|
+
# when creating root node, self[:id] and :root_id are both nil, so it works.
|
1550
|
+
if parent_id_changed? && self[:id] == current_site[:root_id]
|
1551
|
+
errors.add("parent_id", "root should not have a parent") unless self[:parent_id].blank?
|
1552
|
+
end
|
1553
|
+
|
1554
|
+
errors.add(:base, 'You do not have the rights to post comments.') if @add_comment && !can_comment?
|
1555
|
+
|
1556
|
+
if @new_klass
|
1557
|
+
if !can_drive? || !self[:parent_id]
|
1558
|
+
errors.add('klass', 'You do not have the rights to do this.')
|
1559
|
+
else
|
1560
|
+
errors.add('klass', 'invalid') if !self.class.allowed_change_to_classes.include?(@new_klass)
|
1561
|
+
end
|
1562
|
+
end
|
1563
|
+
end
|
1564
|
+
|
1565
|
+
# Called before destroy. An node must be empty to be destroyed
|
1566
|
+
def secure_on_destroy
|
1567
|
+
return false unless super
|
1568
|
+
# expire cache
|
1569
|
+
# TODO: test, use observer instead...
|
1570
|
+
CachedPage.expire_with(self)
|
1571
|
+
true
|
1572
|
+
end
|
1573
|
+
|
1574
|
+
# Get unique zip in the current site's scope
|
1575
|
+
def node_before_create
|
1576
|
+
self[:zip] = Zena::Db.next_zip(self[:site_id])
|
1577
|
+
end
|
1578
|
+
|
1579
|
+
# Create an 'outside' discussion if the virtual class has auto_create_discussion set
|
1580
|
+
def node_after_create
|
1581
|
+
if vclass.auto_create_discussion
|
1582
|
+
Discussion.create(:node_id=>self[:id], :lang=>v_lang, :inside => false)
|
1583
|
+
end
|
1584
|
+
end
|
1585
|
+
|
1586
|
+
# Called after a node is 'unpublished'
|
1587
|
+
def after_unpublish
|
1588
|
+
if !self[:publish_from] && !@new_record_before_save
|
1589
|
+
# not published any more. 'unpublish' documents
|
1590
|
+
sync_documents(:unpublish)
|
1591
|
+
else
|
1592
|
+
true
|
1593
|
+
end
|
1594
|
+
end
|
1595
|
+
|
1596
|
+
def after_redit
|
1597
|
+
return true if @new_record_before_save
|
1598
|
+
sync_documents(:redit)
|
1599
|
+
end
|
1600
|
+
|
1601
|
+
# Called after a node is 'removed'
|
1602
|
+
def after_remove
|
1603
|
+
return true if @new_record_before_save
|
1604
|
+
sync_documents(:remove)
|
1605
|
+
end
|
1606
|
+
|
1607
|
+
# Called after a node is 'proposed'
|
1608
|
+
def after_propose
|
1609
|
+
return true if @new_record_before_save
|
1610
|
+
sync_documents(:propose)
|
1611
|
+
end
|
1612
|
+
|
1613
|
+
# Called after a node is 'refused'
|
1614
|
+
def after_refuse
|
1615
|
+
return true if @new_record_before_save
|
1616
|
+
sync_documents(:refuse)
|
1617
|
+
end
|
1618
|
+
|
1619
|
+
# Called after a node is published
|
1620
|
+
def after_publish
|
1621
|
+
return true if @new_record_before_save
|
1622
|
+
sync_documents(:publish)
|
1623
|
+
end
|
1624
|
+
|
1625
|
+
# Publish, refuse, propose the Documents of a redaction
|
1626
|
+
def sync_documents(action)
|
1627
|
+
allOK = true
|
1628
|
+
documents = secure_drive(Document) { Document.find(:all, :conditions=>"parent_id = #{self[:id]}") } || []
|
1629
|
+
case action
|
1630
|
+
when :propose
|
1631
|
+
documents.each do |doc|
|
1632
|
+
if doc.can_propose?
|
1633
|
+
allOK = doc.propose(Zena::Status[:prop_with]) && allOK
|
1634
|
+
end
|
1635
|
+
end
|
1636
|
+
when :unpublish
|
1637
|
+
# FIXME: use a 'before_unpublish' callback to make sure all sub-nodes can be unpublished...
|
1638
|
+
documents.each do |doc|
|
1639
|
+
unless doc.unpublish
|
1640
|
+
doc.errors.each do |k, v|
|
1641
|
+
errors.add('document', "#{k} #{v}")
|
1642
|
+
end
|
1643
|
+
allOK = false
|
1644
|
+
end
|
1645
|
+
end
|
1646
|
+
else
|
1647
|
+
documents.each do |doc|
|
1648
|
+
if doc.can_apply?(action)
|
1649
|
+
allOK = doc.apply(action) && allOK
|
1650
|
+
end
|
1651
|
+
end
|
1652
|
+
end
|
1653
|
+
allOK
|
1654
|
+
end
|
1655
|
+
|
1656
|
+
# Whenever something changed (publication/proposition/redaction/link/...)
|
1657
|
+
def after_all
|
1658
|
+
sweep_cache
|
1659
|
+
if @add_comment
|
1660
|
+
# add comment
|
1661
|
+
@discussion ||= self.discussion
|
1662
|
+
@discussion.save if @discussion.new_record?
|
1663
|
+
@add_comment[:author_name] = nil unless visitor.is_anon? # only anonymous user should set 'author_name'
|
1664
|
+
@add_comment[:discussion_id] = @discussion[:id]
|
1665
|
+
@add_comment[:user_id] = visitor[:id]
|
1666
|
+
|
1667
|
+
@comment = secure!(Comment) { Comment.create(@add_comment) }
|
1668
|
+
|
1669
|
+
remove_instance_variable(:@add_comment)
|
1670
|
+
end
|
1671
|
+
remove_instance_variable(:@discussion) if defined?(@discussion) # force reload
|
1672
|
+
|
1673
|
+
true
|
1674
|
+
end
|
1675
|
+
|
1676
|
+
def change_klass
|
1677
|
+
|
1678
|
+
if @new_klass && !new_record?
|
1679
|
+
old_kpath = self.kpath
|
1680
|
+
|
1681
|
+
klass = Node.get_class(@new_klass)
|
1682
|
+
if klass.kind_of?(VirtualClass)
|
1683
|
+
self[:vclass_id] = klass.kind_of?(VirtualClass) ? klass[:id] : nil
|
1684
|
+
self[:type] = klass.real_class.to_s
|
1685
|
+
else
|
1686
|
+
self[:vclass_id] = klass.kind_of?(VirtualClass) ? klass[:id] : nil
|
1687
|
+
self[:type] = klass.to_s
|
1688
|
+
end
|
1689
|
+
self[:kpath] = klass.kpath
|
1690
|
+
|
1691
|
+
if old_kpath[/^NPS/] && !self[:kpath][/^NPS/]
|
1692
|
+
@spread_section_id = self[:section_id]
|
1693
|
+
elsif !old_kpath[/^NPS/] && self[:kpath][/^NPS/]
|
1694
|
+
@spread_section_id = self[:id]
|
1695
|
+
end
|
1696
|
+
|
1697
|
+
if old_kpath[/^NPP/] && !self[:kpath][/^NPP/]
|
1698
|
+
@spread_project_id = self[:project_id]
|
1699
|
+
elsif !old_kpath[/^NPP/] && self[:kpath][/^NPP/]
|
1700
|
+
@spread_project_id = self[:id]
|
1701
|
+
end
|
1702
|
+
|
1703
|
+
@set_klass = @new_klass
|
1704
|
+
remove_instance_variable(:@new_klass)
|
1705
|
+
end
|
1706
|
+
|
1707
|
+
true
|
1708
|
+
end
|
1709
|
+
|
1710
|
+
# Find all children, whatever visitor is here (used to check if the node can be destroyed or to update section_id)
|
1711
|
+
def all_children
|
1712
|
+
# FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
|
1713
|
+
Node.send(:with_exclusive_scope) do
|
1714
|
+
Node.find(:all, :conditions=>['parent_id = ?', self[:id] ])
|
1715
|
+
end
|
1716
|
+
end
|
1717
|
+
|
1718
|
+
def clear_children_fullpath(i = self[:id])
|
1719
|
+
return true unless @clear_children_fullpath
|
1720
|
+
base_class.connection.execute "UPDATE nodes SET fullpath = NULL WHERE #{ref_field(false)}='#{i}'"
|
1721
|
+
ids = nil
|
1722
|
+
# FIXME: remove 'with_exclusive_scope' once scopes are clarified and removed from 'secure'
|
1723
|
+
base_class.send(:with_exclusive_scope) do
|
1724
|
+
ids = Zena::Db.fetch_ids("SELECT id FROM #{base_class.table_name} WHERE #{ref_field(true)} = '#{i.to_i}' AND inherit='1'")
|
1725
|
+
end
|
1726
|
+
|
1727
|
+
ids.each { |i| clear_children_fullpath(i) }
|
1728
|
+
true
|
1729
|
+
end
|
1730
|
+
|
1731
|
+
# Base class
|
1732
|
+
def base_class
|
1733
|
+
Node
|
1734
|
+
end
|
1735
|
+
|
1736
|
+
# Reference class
|
1737
|
+
def ref_class
|
1738
|
+
Node
|
1739
|
+
end
|
1740
|
+
|
1741
|
+
# return the id of the reference
|
1742
|
+
def ref_field(for_heirs=false)
|
1743
|
+
if !for_heirs && (self[:id] == current_site[:root_id])
|
1744
|
+
:id # root is it's own reference
|
1745
|
+
else
|
1746
|
+
:parent_id
|
1747
|
+
end
|
1748
|
+
end
|
1749
|
+
|
1750
|
+
end
|
1751
|
+
|
1752
|
+
Bricks::Patcher.apply_patches
|