Class: TextDocument

Inherits:
Document show all
Defined in:
app/models/text_document.rb

Overview

Any document that can be edited as text (html file, script, source code) is a text document. The file content is not stored in an external file. It is kept in the version text. This means that the content of such a document can be edited by editing the version’s text.

Version

The version class used by text documents is the TextDocumentVersion.

Content

Content (file data) is stored in the TextDocumentVersion. The content class (TextDocumentContent) is responsible for faking the exitence of a real file.

Direct Known Subclasses

Template

Defined Under Namespace

Classes: AssetHelper

Constant Summary

Constants inherited from Node

Node::Caster, Node::VERSION_ATTRIBUTES

Constants included from Zena::Use::Workflow

Zena::Use::Workflow::WORKFLOW_ATTRIBUTES

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Document

change_to_classes_for_form, document_class_from_content_type, #image?, new, o_new, version_class

Methods inherited from Node

#all_relations, allowed_change_to_classes, #archive, #asset_path, #author, author_proc, auto_create_discussion, #can_auto_create_discussion?, #can_comment?, cast_to_class, change_to_classes_for_form, class_for_relation, classes_for_form, #comments, #comments_count, #content_lang, create_node, create_nodes_from_folder, create_or_update_node, #data, #discussion, #dyn_attribute_keys, #empty?, #export_to_folder, extract_archive, find_by_parent_title_and_kpath, find_by_title, find_by_zip, find_node_by_pseudo, #find_node_by_pseudo, get_attributes_from_yaml, get_class, #get_discussion_id, #get_project_id, get_role, #get_section_id, inherited, inspect, #klass, #klass=, #klass_changed?, kpath_match?, #kpath_match?, kpaths_for_form, load_unhandled_children, #login_info, #m_author, #m_author=, #m_text, #m_text=, #m_title, #m_title=, make_schema, #merge_multi_errors, native_classes, native_classes_by_name, new, #new_child, new_node, #o_skin, #o_user, #parent, #parent_zip, #parent_zip=, plural_relation?, #project, #project_zip, #rcast, #real_project, #real_section, #reload, #replace_attributes_in_values, #safe_method_type, #safe_send, #section, #section_zip, #skin, #skin_zip, #skin_zip=, #to_yaml, transform_attributes, translate_pseudo_id, #update_attributes_with_transformation, #user, #user_zip, #v_number, #vclass, #versions_with_secure, #virtual_class, #virtual_class=, #vkind_of?, zafu_attribute, #zafu_eval, #zafu_versions

Methods included from Zena::Use::Search::NodeClassMethods

#match_query, #search_index, #search_records, #search_text

Methods included from Zena::Acts::Secure

#secure_scope, #secure_write_scope, #visitor=

Methods included from Zena::Acts::Secure::SecureResult

#construct_id_map, #secure_result

Methods included from Zena::Acts::SecureNode

#acts_as_secure_node

Methods included from Zena::Use::Dates::ModelMethods

included

Methods included from Zena::Use::Dates::Common

#format_date

Methods included from Zena::Use::QueryNode::ModelMethods

#db_attr, #find, included, #safe_first, #start_node_zip

Methods included from Zena::Use::ScopeIndex::ModelMethods

included, #rebuild_index_with_scope_index!, #rebuild_scope_index!, #scope_index, scope_index_proc

Methods included from Zena::Use::Relations::ModelMethods

#add_link, #all_relations, included, #l_comment, #l_comment=, #l_date, #l_date=, #l_status, #l_status=, #link_id, #link_id=, #linked_node, #linked_node=, #rel, #rel=, #rel_attributes=, #relation_alias, #relation_links, #relation_proxy, #relation_proxy_from_link, #relations_for_form, #remove_link

Methods included from Zena::Use::Fulltext::ModelMethods

included, #rebuild_index_for_version_with_fulltext

Methods included from Zena::Use::PropEval::ModelMethods

included, #merge_prop_eval, #need_set__id, #rebuild_index_for_version_with_prop_eval, #set__id

Methods included from Zena::Use::VersionHash::ModelMethods

#rebuild_vhash, #v_public?, #version, #version_id, #vhash, #visible_versions

Methods included from Zena::Acts::Serializable::ModelMethods

#all_link_ids, #default_serialization_options, #export_ids, #export_properties, included, #to_xml

Methods included from Zena::Use::Ancestry::ModelMethods

#ancestors, #basepath, #fullpath_as_title, included, #is_ancestor?, #pseudo_id, #short_path, #z_ancestors

Methods included from Zena::Use::Workflow

#after_all, #apply, #apply_with_callbacks, #auto_publish?, #can_apply?, #can_destroy_version?, #can_edit?, #can_propose?, #can_publish?, #can_refuse?, #can_remove?, #can_unpublish?, #can_update?, #destroy_version, #edit_content!, #get_publish_from, included, #propose, #publish, #redit, #refuse, #remove, #set_current_transition, #traductions, #transition_allowed?, #transition_for, #unpublish, #update_attributes, #would_change_original?

Methods included from Zena::Use::NestedAttributesAlias::ModelMethods

#attributes_with_nested_alias=, included, #nested_model_names_for_alias, #resolve_attributes_alias

Methods included from Zena::Acts::Enrollable::ModelMethods

#assigned_roles, #has_role?, included, #zafu_possible_roles

Methods included from Zena::Use::FieldIndex::ModelMethods

included, #property_field_index

Methods included from Zena::Use::MLIndex::ModelMethods

included, #index_reader, #rebuild_index_for_version, #rebuild_index_with_multi_lingual!

Methods included from Zena::Use::Kpath::InstanceMethods

included

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Zena::Use::Relations::ModelMethods

Class Method Details

.accept_content_type?(content_type) ⇒ Boolean

Return true if a new text document can be created with the content_type. Used by the superclass Document to choose the corret subclass when creating a new object.

Returns:

  • (Boolean)


17
18
19
20
# File 'app/models/text_document.rb', line 17

def accept_content_type?(content_type)
  (content_type =~ /(^text|^image\/svg\+xml|javascript)/) && 
  (Zena::TYPE_TO_EXT[content_type.chomp] != ['rtf'])
end

.accept_content_type_change?Boolean

Return true if the content_type can change independantly from the file

Returns:

  • (Boolean)


23
24
25
# File 'app/models/text_document.rb', line 23

def accept_content_type_change?
  true
end

Instance Method Details

#can_parse_assets?Boolean

Returns:

  • (Boolean)


29
30
31
# File 'app/models/text_document.rb', line 29

def can_parse_assets?
  return ['text/css'].include?(content_type)
end

#export_keysObject

List of keys to export in a zml file. “text” is ignored since it’s exported in a separate file.



156
157
158
159
160
# File 'app/models/text_document.rb', line 156

def export_keys
  h = super
  h[:zazen].delete('text')
  h
end

#file(format = nil) ⇒ Object



97
98
99
# File 'app/models/text_document.rb', line 97

def file(format=nil)
  @loaded_file ||= @new_file || StringIO.new(text)
end

#file=(file) ⇒ Object



92
93
94
95
# File 'app/models/text_document.rb', line 92

def file=(file)
  @new_file = file
  self.text = @new_file.read
end

#filenameObject



101
102
103
# File 'app/models/text_document.rb', line 101

def filename
  "#{title}.#{ext}"
end

#filepath(format = nil) ⇒ Object

Get the file path defined in attachment.



106
107
108
# File 'app/models/text_document.rb', line 106

def filepath(format=nil)
  nil
end

#parse_assets(text, helper, key) ⇒ Object

Parse text content and replace all reference to relative urls (‘img/footer.png’) by their zen_path (‘/en/image34.png’)



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'app/models/text_document.rb', line 34

def parse_assets(text, helper, key)
  if key == 'text' && prop['content_type'] == 'text/css'
    res = text.dup
    # use skin as root
    skin = section

    # not in a Skin. Cannot replace assets in CSS.
    # error
    unless skin.kind_of?(Skin)
      errors.add('base', 'Cannot parse assets if not in a Skin.')
      return text
    end

    res.gsub!(/url\(\s*(.*?)\s*\)/) do
      match, src = $&, $1
      if src =~ /('|")(.*?)\1/
        quote, src = $1, $2
      else
        quote = "'"
      end
      if src[0..6] == 'http://'
        match
      elsif src =~ %r{/\w\w/.*?(\d+)(_\w+|)\.\w+(\?\d+|)}
        # already parsed
        zip, mode, stamp = $1, $2, $3
        if src_node = secure(Node) { Node.find_by_zip(zip) }
          if mode.blank?
            # no cachestamp, we need it
            "url(#{quote}#{helper.send(:data_path, src_node)}#{quote})"
          else
            "url(#{quote}#{helper.send(:data_path, src_node, :mode => mode[1..-1])}#{quote})"
          end
        else
          # ok
          "url(#{quote}#{src}#{quote})"
        end
      else
        if new_src = helper.send(:template_url_for_asset,
            :src          => src,
            :parent       => parent,
            :parse_assets => true )

          "url(#{quote}#{new_src}#{quote})"
        elsif !(src =~ /\.\./) && File.exist?(File.join(SITES_ROOT, current_site.public_path, src))
          "url(#{quote}#{src}?#{File.mtime(File.join(SITES_ROOT, current_site.public_path, src)).to_i}#{quote})"
        else
          errors.add('asset', _('%{asset} not found') % {:asset => src.inspect})
          "url(#{quote}#{src}#{quote})"
        end
      end
    end
  else
    # unknown type
    super
  end
  res
end

#parse_keysObject

List of keys which need transformations



163
164
165
# File 'app/models/text_document.rb', line 163

def parse_keys
  (super + (content_type == 'text/css' ? ['text'] : [])).uniq
end

#size(format = nil) ⇒ Object

Return document file size (= version’s text size).



111
112
113
# File 'app/models/text_document.rb', line 111

def size(format=nil)
  (text || '').size
end

#sweep_cacheObject

Do not sweep TextDocument cache in dev mode unless expire_in_dev.



168
169
170
171
172
173
174
175
# File 'app/models/text_document.rb', line 168

def sweep_cache
  if visitor.dev_mode? && !current_site.expire_in_dev?
    # Only expire templates built for dev mode
    super(:conditions => ['path like ?', "%/dev_#{visitor.lang}/%"])
  else
    super
  end
end

#unparse_assets(text, helper, key) ⇒ Object

Parse text and replace absolute urls (‘/en/image30.jpg’) by their relative value in the current skin (‘img/bird.jpg’)



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'app/models/text_document.rb', line 116

def unparse_assets(text, helper, key)
  if key == 'text' && prop['content_type'] == 'text/css'
    res = text.dup
    # use parent as relative root
    base_path = parent.fullpath

    res.gsub!(/url\(('|")(.*?)\1\)/) do
      if $2[0..6] == 'http://'
        $&
      else
        quote, url   = $1, $2
        if url =~ /\A\/\w\w\/.*?(\d+)(_\w+|)\./
          zip, mode = $1, $2
          if asset = secure(Node) { Node.find_by_zip(zip) }
            if asset.fullpath =~ /\A#{base_path}\/(.+)/
              path = fullpath_as_title($1)
              "url(#{quote}#{path}#{mode}.#{asset.prop['ext']}#{quote})"
            else
              "url(#{quote}/#{asset.fullpath_as_title.map(&:to_filename).join('/')}#{mode}.#{asset.prop['ext']}#{quote})"
            end
          else
            errors.add('asset', '%{zip} not found', :zip => zip)
            "url(#{quote}#{url}#{quote})"
          end
        elsif File.exist?(File.join(SITES_ROOT, current_site.public_path, url.sub(/\?\d+\Z/,'')))
          "url(#{quote}#{url.sub(/\?\d+\Z/,'')}#{quote})"
        else
          # bad format
          errors.add('base', "cannot unparse asset url #{url.inspect}")
          "url(#{quote}#{url}#{quote})"
        end
      end
    end
    res
  else
    super
  end
end