Currently, if we want different view for a file-type (image, PDF, video,...), we must use an "if" and render explicitly an other view.
A class for every file-type (instead only the UploadedFile) is a nice idea because:
- the view can be automatically selected from the
@page class;
- specific file-type methods can be organized on it's own place.
but, that is a bad idea because:
- we must to migrate all UploadedFiles;
- we will must to migrate every time when we create a new file-type class;
- we will suffer in pain if we want to remove an specific file-type class handler;
- by the pain we may be afraid to make plugins of file-type class.
The solution is to make a presenter class for each file-type, and that will be a kind of
decorator.
A presenter object will incorporate the original UploadedFile, but will call a specific view, may add some methods for it's specific view, and
may (only "may") change some original file methods to act like an
exhibit.
An abstract class
FilePresenter will be implemented by specific file-types or for a sort of file-types. The concrete file presenter classes will response if it can present some UploadedFile and its priority to the class selection chain.
class FilePresenter
# Will return a encapsulated UploadedFile or the same object if no
# one accepts it. That behave allow to give any model to this class,
# like a Article and have no trouble with that.
def self.for(f)
klass = subclasses.sort_by { |c| c.accepts?(f) || 0 }.last
klass.accepts?(f) ? klass.new(f) : f
end
def initialize(f)
@file = f
end
# This method must be overridden in subclasses.
#
# If the class accepts the file, return a number that represents the
# priority the class should be given to handle that file. Higher numbers
# mean higher priority.
#
# If the class does not accept the file, return false.
def self.accepts?(f)
nil
end
def method_missing(m, *args)
file.send(m, *args)
end
end
class Playable < FilePresenter
def self.accepts?(f)
type = f.content_type[0..5]
( type == 'video/' || type == 'audio/' ) ? 5 : nil
end
end
class Video < FilePresenter
def self.accepts?(f)
( f.content_type[0..5] == 'video/' ) ? 10 : nil
end
def web_versions
...
end
end
class Image < FilePresenter
def self.accepts?(f)
( f.image? ) ? 10 : nil
end
end
On
view_page method on
content_viewer_controller.rb, after
@page.hit, we may add
"
@page = FilePresenter.for(@page)".
--
AurelioAHeckert - 29 Jun 2012
I'm working on this feature on
this branch.
That adds this features:
- Allows specific methods to the file types.
- Gives specific views to identified file types.
- Set file type related icon on CMS and folder listing.
- Provide a basic HTML5 Video plugin to exemplify the custom FilePresenter creation
- Gives a generic info page to unhandled files types.
--
AurelioAHeckert - 09 May 2013
Merge Request:
https://gitorious.org/noosfero/noosfero/merge_requests/316
--
AurelioAHeckert - 16 May 2013