[Zope] Re: Best Practice for including Javascript inZope Applications

Matt Hollingsworth mr.hworth at gmail.com
Wed Jan 2 06:13:12 EST 2008


>Andreas Jung wrote:
>> 
>...
>>> Larger JS frameworks like Dojo tend to be split across several files and
>>> directories. The fun starts when such frameworks load/reload stuff
>>> using relative URLs. A co-worker using Dojo intensively had to invest
>>> some time in order to integrate such a JS monster properly. As far as I
>>> remember Extjs also uses multiple files (but not as much as Dojo
>>> does)..so please check in advance.
>>>
>> Another point: consider using CMF and putting your library files into a
>> directory system view on the filesystem. This makes your life much
easier.
>
>Or just upload via WEBDAV.
>One of the biggest advantages of Zope is the isolation from physical
>file system.
>
>Regards
>Tino

Hello,

Thanks to everyone for your help.  I thought about Tres's solution and
quickly discovered that I would be doing a *lot* of clicking/typing if I
wanted to upload all of the files necessary to make the ExtJS framework
available.   I'll look into the WebDAV idea; I didn't think of that until
you mentioned it.

However, I came up with another possible solution that may be generally
useful after some (a lot actually) of coaxing.  I threw this together in the
time between my new year's festivities :) : it's incredibly sloppy at the
moment, but before I worried about cleaning it up, I wanted to get some
feedback from you guys about it (pardon the annoying formatting problems):

def package_home(gdict):
    """Returns the location of the file that calls the function.  You 
    must pass it globals() as the argument for it to work right.  
    
    :Parameters:
        gdict : dict
            A dictionary containing all of the global definitions for the
            module.  This is accessible via the python built-in function
globals()
            
    :return: The fully qualified path for the directory in which the calling
        module is residing
    :rtype: string
    
    
    """
    filename = gdict["__file__"] 
    return os.path.dirname(filename)
	

class FileSystemResource(Implicit,Item):
    """FileSystemResource is meant to make it easy to access file system
objects
    through Zope.  It works by taking over the object traversal process to
    recursively return resources, simulating a directory structure, until
    it finally reaches the end (__call__()), when it accesses the file
    and returns it.
    
    If you do 
    
    js = FileSystemResource()
    
    in the class that you are publishing, then 
    
    http://www.domain.com/yourId/js/all.js
    
    would return the contents of all.js.
    
    :Authors: - Matt
    :Date: 2007-1-1
    """
    
    def
__init__(self,path,name,cache=True,persist=False,sync=True,rootdir=package_h
ome(globals())):
        """Create a FileSystemResource with the specified name"""
        self.path = path
        self.name= name
        self.cache = cache
        self.persist = persist
        self.sync = sync
        self.rootdir = rootdir
        
        if cache:
            self._cache = {}
    #########   
    # Hooks #
    #########
    
    def __before_publishing_traverse__(self,obj,REQUEST):
        """Just print the request path so I can debug easier"""
        #print "REQUEST.path: " + str(REQUEST.path)
        print "REQUEST.path: " + str(REQUEST.path)
    
    
    def __bobo_traverse__(self, request, key):
        """Takes the key, meshes it with the request, and
        generates the object from that"""
        
        full_path = os.path.join(self.path,key)
        
        if self.cache:
            if self._cache.has_key(key):
                o = self._cache[key]
                fsr = o[0]
                mod_time = o[1]
                file_size = o[4]
                #If modtime isn't the same, refresh the resource
                
                latest_access_time = time.localtime()
                num_accesses = o[3] + 1
                
                new_entry =
(fsr,mod_time,latest_access_time,num_accesses,file_size)
                
                
                self._cache[key] = new_entry
                return new_entry[0]
            else:
                o = FileSystemResource(full_path,name=None)
                #Set the modification time
                mod_time = "time" #TODO: Implement
                latest_access_time = time.localtime()
                num_accesses = 1
                file_size = 0 #TODO: Implement
                self._cache[key] =
(o,mod_time,latest_access_time,num_accesses,file_size)
                return o
            
        o = FileSystemResource(full_path)
        print "Returning object " + str(o)
        return o
    
    ###############
    # ! End Hooks #
    ###############

    def cleanCache(self):
        #TODO: Not implemented (placeholder vars so I'll remember what's in
the tuples)
        for key,value in self._cache.items():
            file_location = key
            file_obj = value[0]
            mod_time = value[1]
            latest_access_time = value[2]
            num_accesses = value[3]
            file_size = value[4]
            
    def getResource(self,path):
       """Gets the resource sepcified by the given path.  The path
       should be relative to this particular object's path.
       
       :Parameters:
           path
               The path (relative to this object's path) of the file or
               folder that you are looking for
        
        :return: Returns the content of the specified resource
        :rtype: Zope File object
       """
       #TODO: Implement
    
    
    def __call__(self,REQUEST):
        """Gets the representation of the file on the filesystem"""
        #TODO: Cache results
        #TODO: Make it possible to use non-memory cached files        
        fname = os.path.abspath(os.path.join(self.rootdir,self.path))
        type = guess_type(fname)[0]
        if not os.path.exists(fname):
            raise FileNotFoundException("File " + fname + " was not found on
the file system.")
        
        print "Opening file " + fname
        
        f = open(fname)
        
        data = ""
        for line in f:
            data +=line
        
        tmp_file = File(data)
        ret = FileReadFile(tmp_file)
        
        #Set the response content type
        REQUEST.response.setHeader("Content-Type",type)
        
        return ret.read()
    
    def __str__(self):
        """Gets the string representation of this FileObject"""
        return self.path


This class is working like a charm as it stands (I have
js=FileSystemResource("js","Javascript Repository") in my published object),
but it is terribly sloppily implemented for the time being, especially in
regard to binary files (doing for line... instead of going over chunks) and
to caching/memory issues (there is no caching except for the intermediate
objects and everything is loaded into memory first [big files = unusable]).
And someone could just pass ../'s to the path to get anywhere on the file
system they wanted, I suppose.  All of these could easily be fixed of
course, but I wanted feedback before I put more than 30 minutes into the
prospect :)

Thanks for all your help!

-Matt



More information about the Zope mailing list