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::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?, 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, #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, #real_project, #real_section, #reload, #replace_attributes_in_values, #safe_method_type, #safe_send, #section, #section_zip, #skin, #skin_zip, #skin_zip=, #sweep_cache, #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_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::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, #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, #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
# File 'app/models/text_document.rb', line 17

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

.accept_content_type_change?Boolean

Return true if the content_type can change independantly from the file

Returns:

  • (Boolean)


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

def accept_content_type_change?
  true
end

Instance Method Details

#can_parse_assets?Boolean

Returns:

  • (Boolean)


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

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.



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

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

#file(format = nil) ⇒ Object



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

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

#file=(file) ⇒ Object



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

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

#filenameObject



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

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

#filepath(format = nil) ⇒ Object

Get the file path defined in attachment.



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

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’)



33
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
# File 'app/models/text_document.rb', line 33

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



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

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

#size(format = nil) ⇒ Object

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



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

def size(format=nil)
  (text || '').size
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’)



115
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
# File 'app/models/text_document.rb', line 115

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