diff options
| author | ianb <devnull@localhost> | 2005-08-22 18:22:27 +0000 |
|---|---|---|
| committer | ianb <devnull@localhost> | 2005-08-22 18:22:27 +0000 |
| commit | 27f2c911e823216a8db5873a53b1da10c0a4c4d1 (patch) | |
| tree | 1ed476b090fdda9834d088b38c54c27687e8e23b /examples/filebrowser | |
| parent | e17ed7b172e6b8e914c28cd3dfec53fa7b452eb7 (diff) | |
| download | paste-27f2c911e823216a8db5873a53b1da10c0a4c4d1.tar.gz | |
Examples will be kept in a separate location in the repository in the future; build-pkg is deprecated also
Diffstat (limited to 'examples/filebrowser')
35 files changed, 0 insertions, 2413 deletions
diff --git a/examples/filebrowser/README.txt b/examples/filebrowser/README.txt deleted file mode 100644 index 7962e8b..0000000 --- a/examples/filebrowser/README.txt +++ /dev/null @@ -1,37 +0,0 @@ -Filebrowser Example Application -=============================== - -:author: Ian Bicking <ianb@colorstudy.com> - -Purpose -------- - -This is primarily meant as an example of using Ajax (DHTML) -development using Paste, ZPT, and Wareweb. It's really an experiment. -It uses the `Prototype <http://prototype.conio.net/>`_ library (which -is currently distributed with the example). - -I should say that I've found this library to be pleasant to work -with. It embodies several patterns -- but not too many -- and does -them well. I still don't understand the entire library, but what I -have used has worked well, without terrible challenges or -difficulties. And I don't have to work too hard. - -I do have my eye on making this application into something of a -framework for other filesystem-like applications, like a CMS, or a svn -browser (this uses py.path, part of the `py lib -<http://codespeak.net/py/current/doc/home.html>`_, which has an svn -backend already), or whatever. - -Status ------- - -This is still at an early stage. There are almost certainly security -problems with the application (where a user can escape the root of the -application). Lots of obviously useful functions (like add and -delete) are missing. - -There's a framework kind of planned (``handlers``) for registering -different kinds of handlers with different file types. Reading -metadata, doing editing, etc. This hasn't been developed or used at -all yet.
\ No newline at end of file diff --git a/examples/filebrowser/__init__.py b/examples/filebrowser/__init__.py deleted file mode 100644 index 1cb2d1b..0000000 --- a/examples/filebrowser/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from paste.util.thirdparty import add_package - -add_package('ZopePageTemplates') -add_package('ZPTKit') diff --git a/examples/filebrowser/handlers.py b/examples/filebrowser/handlers.py deleted file mode 100644 index 6d28d87..0000000 --- a/examples/filebrowser/handlers.py +++ /dev/null @@ -1,32 +0,0 @@ -from paste.util.classinit import ClassInitMeta - -handler_exts = {} - -def get_handler(path): - if path.check(dir=True): - ext_type = 'dir' - else: - ext_type = path.ext - return handler_exts.get(ext, handler_exts['*'])(path) - -class Handler(object): - - __metaclass__ = ClassInitMeta - - abstract = True - exts = () - - def __classinit__(cls, new_args): - if cls.abstract and 'abstract' not in new_args: - cls.abstract = False - if not cls.abstract: - for ext in self.exts: - assert ext not in handler_exts, ( - "Handler %s already registered for extension %r; " - "trying to overwrite with %s" - % (handler_exts[ext], ext, cls)) - handler_exts[ext] = cls - - def __init__(self, path): - self.path = path - diff --git a/examples/filebrowser/icons/1downarrow.png b/examples/filebrowser/icons/1downarrow.png Binary files differdeleted file mode 100644 index a0491b6..0000000 --- a/examples/filebrowser/icons/1downarrow.png +++ /dev/null diff --git a/examples/filebrowser/icons/1leftarrow.png b/examples/filebrowser/icons/1leftarrow.png Binary files differdeleted file mode 100644 index 7e3fda7..0000000 --- a/examples/filebrowser/icons/1leftarrow.png +++ /dev/null diff --git a/examples/filebrowser/icons/1rightarrow.png b/examples/filebrowser/icons/1rightarrow.png Binary files differdeleted file mode 100644 index 3264e13..0000000 --- a/examples/filebrowser/icons/1rightarrow.png +++ /dev/null diff --git a/examples/filebrowser/icons/1uparrow.png b/examples/filebrowser/icons/1uparrow.png Binary files differdeleted file mode 100644 index c68fd87..0000000 --- a/examples/filebrowser/icons/1uparrow.png +++ /dev/null diff --git a/examples/filebrowser/icons/editcopy.png b/examples/filebrowser/icons/editcopy.png Binary files differdeleted file mode 100644 index ee19948..0000000 --- a/examples/filebrowser/icons/editcopy.png +++ /dev/null diff --git a/examples/filebrowser/icons/editcut.png b/examples/filebrowser/icons/editcut.png Binary files differdeleted file mode 100644 index 0407aff..0000000 --- a/examples/filebrowser/icons/editcut.png +++ /dev/null diff --git a/examples/filebrowser/icons/editpaste.png b/examples/filebrowser/icons/editpaste.png Binary files differdeleted file mode 100755 index 0e3ecff..0000000 --- a/examples/filebrowser/icons/editpaste.png +++ /dev/null diff --git a/examples/filebrowser/icons/goto.png b/examples/filebrowser/icons/goto.png Binary files differdeleted file mode 100755 index 5cfe404..0000000 --- a/examples/filebrowser/icons/goto.png +++ /dev/null diff --git a/examples/filebrowser/icons/remove.png b/examples/filebrowser/icons/remove.png Binary files differdeleted file mode 100644 index d65de9e..0000000 --- a/examples/filebrowser/icons/remove.png +++ /dev/null diff --git a/examples/filebrowser/js-lib/common.js b/examples/filebrowser/js-lib/common.js deleted file mode 100644 index c035695..0000000 --- a/examples/filebrowser/js-lib/common.js +++ /dev/null @@ -1,97 +0,0 @@ -function jump(anchor) { - var dest_url = anchor.getAttribute('jumpurl'); - var name = window.prompt('Jump where? ("root" for /, "edit:" for edit screen)') - if (name) { - location.href = dest_url + '?name=' + escape(name); - } -} - -Element.hidden = function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - if (element.style.display != 'none') { - return false; - } - } - return true; -} - -function lazyToggle(container, url, options) { - options = extend({method: 'get'}, options || {}); - if (Element.hidden(container)) { - Element.show(container); - if (! $(container).lazy_loaded) { - new Ajax.Updater(container, url, options); - $(container).lazy_loaded = true; - } - if (options.link) { - var newHTML = options.link.getAttribute('shownhtml'); - if (newHTML) { - options.link.setAttribute('hiddenhtml', options.link.innerHTML); - options.link.innerHTML = newHTML; - } - } - } else { - Element.hide(container); - if (options.link) { - var newHTML = options.link.getAttribute('hiddenhtml'); - if (newHTML) { - options.link.innerHTML = newHTML; - } - } - } -} - -function toggle(container, options) { - if (Element.hidden(container)) { - Element.show(container); - if (options && options.link) { - var newHTML = options.link.getAttribute('shownhtml'); - if (newHTML) { - options.link.setAttribute('hiddenhtml', options.link.innerHTML); - options.link.innerHTML = newHTML; - } - } - } else { - Element.hide(container); - if (options && options.link) { - var newHTML = options.link.getAttribute('hiddenhtml'); - if (newHTML) { - options.link.setAttribute('shownhtml', options.link.innerHTML); - options.link.innerHTML = newHTML; - } - } - } -} - -/* From: http://www.quirksmode.org/js/cookies.html */ - -function createCookie(name,value,days) -{ - if (days) - { - var date = new Date(); - date.setTime(date.getTime()+(days*24*60*60*1000)); - var expires = "; expires="+date.toGMTString(); - } - else var expires = ""; - document.cookie = name+"="+value+expires+"; path=/"; -} - -function readCookie(name) -{ - var nameEQ = name + "="; - var ca = document.cookie.split(';'); - for(var i=0;i < ca.length;i++) - { - var c = ca[i]; - while (c.charAt(0)==' ') c = c.substring(1,c.length); - if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); - } - return null; -} - -function eraseCookie(name) -{ - createCookie(name,"",-1); -} diff --git a/examples/filebrowser/js-lib/prototype-1.2.0.js b/examples/filebrowser/js-lib/prototype-1.2.0.js deleted file mode 100644 index 47916bc..0000000 --- a/examples/filebrowser/js-lib/prototype-1.2.0.js +++ /dev/null @@ -1,768 +0,0 @@ -/* Prototype: an object-oriented Javascript library, version 1.2.0 - * (c) 2005 Sam Stephenson <sam@conio.net> - * - * THIS FILE IS AUTOMATICALLY GENERATED. When sending patches, please diff - * against the source tree, available from the Prototype darcs repository. - * - * Prototype is freely distributable under the terms of an MIT-style license. - * - * For details, see the Prototype web site: http://prototype.conio.net/ - * -/*--------------------------------------------------------------------------*/ - -var Prototype = { - Version: '1.2.0' -} - -var Class = { - create: function() { - return function() { - if (! this.initialize) alert('this: ' + this + ' init: ' + this.initialize); - this.initialize.apply(this, arguments); - } - } -} - -var Abstract = new Object(); - -function extend(ob1, ob2) { - for (property in ob2) { - ob1[property] = ob2[property]; - } - return ob1; -} - -Function.prototype.bind = function(object) { - var method = this; - return function() { - method.apply(object, arguments); - } -} - -Function.prototype.bindAsEventListener = function(object) { - var method = this; - return function(event) { - method.call(object, event || window.event); - } -} - -Number.prototype.toColorPart = function() { - var digits = this.toString(16); - if (this < 16) return '0' + digits; - return digits; -} - -var Try = { - these: function() { - var returnValue; - - for (var i = 0; i < arguments.length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) {} - } - - return returnValue; - } -} - -/*--------------------------------------------------------------------------*/ - -var PeriodicalExecuter = Class.create(); -PeriodicalExecuter.prototype = { - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.callback(); - } finally { - this.currentlyExecuting = false; - } - } - - this.registerCallback(); - } -} - -/*--------------------------------------------------------------------------*/ - -function $() { - var elements = new Array(); - - for (var i = 0; i < arguments.length; i++) { - var element = arguments[i]; - if (typeof element == 'string') - element = document.getElementById(element); - - if (arguments.length == 1) - return element; - - elements.push(element); - } - - return elements; -} - -/*--------------------------------------------------------------------------*/ - -if (!Array.prototype.push) { - Array.prototype.push = function() { - var startLength = this.length; - for (var i = 0; i < arguments.length; i++) - this[startLength + i] = arguments[i]; - return this.length; - } -} - -if (!Function.prototype.apply) { - // Based on code from http://www.youngpup.net/ - Function.prototype.apply = function(object, parameters) { - var parameterStrings = new Array(); - if (!object) object = window; - if (!parameters) parameters = new Array(); - - for (var i = 0; i < parameters.length; i++) - parameterStrings[i] = 'x[' + i + ']'; - - object.__apply__ = this; - var result = eval('obj.__apply__(' + - parameterStrings[i].join(', ') + ')'); - object.__apply__ = null; - - return result; - } -} - -/*--------------------------------------------------------------------------*/ - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')}, - function() {return new XMLHttpRequest()} - ) || false; - }, - - emptyFunction: function() {} -} - -Ajax.Base = function() {}; -Ajax.Base.prototype = { - setOptions: function(options) { - this.options = extend({ - method: 'post', - asynchronous: true, - parameters: '' - }, options || {}); - } -} - -Ajax.Request = Class.create(); -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Request.prototype = extend(new Ajax.Base(), { - initialize: function(url, options) { - this.transport = Ajax.getTransport(); - this.setOptions(options); - - try { - if (this.options.method == 'get') - url += '?' + this.options.parameters + '&_='; - - this.transport.open(this.options.method, url, true); - - if (this.options.asynchronous) { - this.transport.onreadystatechange = this.onStateChange.bind(this); - setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); - } - - this.transport.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); - this.transport.setRequestHeader('X-Prototype-Version', Prototype.Version); - - if (this.options.method == 'post') { - this.transport.setRequestHeader('Connection', 'close'); - this.transport.setRequestHeader('Content-type', - 'application/x-www-form-urlencoded'); - } - - this.transport.send(this.options.method == 'post' ? - this.options.parameters + '&_=' : null); - - } catch (e) { - } - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState != 1) - this.respondToReadyState(this.transport.readyState); - }, - - respondToReadyState: function(readyState) { - var event = Ajax.Request.Events[readyState]; - (this.options['on' + event] || Ajax.emptyFunction)(this.transport); - } -}); - -Ajax.Updater = Class.create(); -Ajax.Updater.prototype = extend(new Ajax.Base(), { - initialize: function(container, url, options) { - this.container = $(container); - if (! this.container) { - alert('Container ' + container + ' does not exist'); - } - this.setOptions(options); - - if (this.options.asynchronous) { - this.onComplete = this.options.onComplete; - this.options.onComplete = this.updateContent.bind(this); - } - - this.request = new Ajax.Request(url, this.options); - - if (!this.options.asynchronous) - this.updateContent(); - }, - - updateContent: function() { - if (this.options.insertion) { - new this.options.insertion(this.container, - this.request.transport.responseText); - } else { - this.container.innerHTML = this.request.transport.responseText; - } - - if (this.onComplete) { - setTimeout((function() {this.onComplete(this.request)}).bind(this), 10); - } - } -}); - -/*--------------------------------------------------------------------------*/ - -var Field = { - clear: function() { - for (var i = 0; i < arguments.length; i++) - $(arguments[i]).value = ''; - }, - - focus: function(element) { - $(element).focus(); - }, - - present: function() { - for (var i = 0; i < arguments.length; i++) - if ($(arguments[i]).value == '') return false; - return true; - }, - - select: function(element) { - $(element).select(); - }, - - activate: function(element) { - $(element).focus(); - $(element).select(); - } -} - -/*--------------------------------------------------------------------------*/ - -var Form = { - serialize: function(form) { - var elements = Form.getElements($(form)); - var queryComponents = new Array(); - - for (var i = 0; i < elements.length; i++) { - var queryComponent = Form.Element.serialize(elements[i]); - if (queryComponent) - queryComponents.push(queryComponent); - } - - return queryComponents.join('&'); - }, - - getElements: function(form) { - form = $(form); - var elements = new Array(); - - for (tagName in Form.Element.Serializers) { - var tagElements = form.getElementsByTagName(tagName); - for (var j = 0; j < tagElements.length; j++) - elements.push(tagElements[j]); - } - return elements; - }, - - disable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.blur(); - element.disable = 'true'; - } - }, - - focusFirstElement: function(form) { - form = $(form); - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - if (element.type != 'hidden' && !element.disabled) { - Field.activate(element); - break; - } - } - }, - - reset: function(form) { - $(form).reset(); - } -} - -Form.Element = { - serialize: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) - return encodeURIComponent(parameter[0]) + '=' + - encodeURIComponent(parameter[1]); - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) - return parameter[1]; - } -} - -Form.Element.Serializers = { - input: function(element) { - switch (element.type.toLowerCase()) { - case 'hidden': - case 'password': - case 'text': - return Form.Element.Serializers.textarea(element); - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element); - } - return false; - }, - - inputSelector: function(element) { - if (element.checked) - return [element.name, element.value]; - }, - - textarea: function(element) { - return [element.name, element.value]; - }, - - select: function(element) { - var index = element.selectedIndex; - var value = element.options[index].value || element.options[index].text; - return [element.name, (index >= 0) ? value : '']; - } -} - -/*--------------------------------------------------------------------------*/ - -var $F = Form.Element.getValue; - -/*--------------------------------------------------------------------------*/ - -Abstract.TimedObserver = function() {} -Abstract.TimedObserver.prototype = { - initialize: function(element, frequency, callback) { - this.frequency = frequency; - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - this.registerCallback(); - }, - - registerCallback: function() { - setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - - this.registerCallback(); - } -} - -Form.Element.Observer = Class.create(); -Form.Element.Observer.prototype = extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(); -Form.Observer.prototype = extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); - - -/*--------------------------------------------------------------------------*/ - -document.getElementsByClassName = function(className) { - var children = document.getElementsByTagName('*') || document.all; - var elements = new Array(); - - for (var i = 0; i < children.length; i++) { - var child = children[i]; - var classNames = child.className.split(' '); - for (var j = 0; j < classNames.length; j++) { - if (classNames[j] == className) { - elements.push(child); - break; - } - } - } - - return elements; -} - -/*--------------------------------------------------------------------------*/ - -var Element = { - toggle: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = - (element.style.display == 'none' ? '' : 'none'); - } - }, - - hide: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = 'none'; - } - }, - - show: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = ''; - } - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - }, - - getHeight: function(element) { - element = $(element); - return element.offsetHeight; - } -} - -var Toggle = new Object(); -Toggle.display = Element.toggle; - -/*--------------------------------------------------------------------------*/ - -Abstract.Insertion = function(adjacency) { - this.adjacency = adjacency; -} - -Abstract.Insertion.prototype = { - initialize: function(element, content) { - this.element = $(element); - this.content = content; - - if (this.adjacency && this.element.insertAdjacentHTML) { - this.element.insertAdjacentHTML(this.adjacency, this.content); - } else { - this.range = this.element.ownerDocument.createRange(); - if (this.initializeRange) this.initializeRange(); - this.fragment = this.range.createContextualFragment(this.content); - this.insertContent(); - } - } -} - -var Insertion = new Object(); - -Insertion.Before = Class.create(); -Insertion.Before.prototype = extend(new Abstract.Insertion('beforeBegin'), { - initializeRange: function() { - this.range.setStartBefore(this.element); - }, - - insertContent: function() { - this.element.parentNode.insertBefore(this.fragment, this.element); - } -}); - -Insertion.Top = Class.create(); -Insertion.Top.prototype = extend(new Abstract.Insertion('afterBegin'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(true); - }, - - insertContent: function() { - this.element.insertBefore(this.fragment, this.element.firstChild); - } -}); - -Insertion.Bottom = Class.create(); -Insertion.Bottom.prototype = extend(new Abstract.Insertion('beforeEnd'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(this.element); - }, - - insertContent: function() { - this.element.appendChild(this.fragment); - } -}); - -Insertion.After = Class.create(); -Insertion.After.prototype = extend(new Abstract.Insertion('afterEnd'), { - initializeRange: function() { - this.range.setStartAfter(this.element); - }, - - insertContent: function() { - this.element.parentNode.insertBefore(this.fragment, - this.element.nextSibling); - } -}); - -/*--------------------------------------------------------------------------*/ - -var Effect = new Object(); - -Effect.Highlight = Class.create(); -Effect.Highlight.prototype = { - initialize: function(element) { - this.element = $(element); - this.start = 153; - this.finish = 255; - this.current = this.start; - this.fade(); - }, - - fade: function() { - if (this.isFinished()) return; - if (this.timer) clearTimeout(this.timer); - this.highlight(this.element, this.current); - this.current += 17; - this.timer = setTimeout(this.fade.bind(this), 250); - }, - - isFinished: function() { - return this.current > this.finish; - }, - - highlight: function(element, current) { - element.style.backgroundColor = "#ffff" + current.toColorPart(); - } -} - - -Effect.Fade = Class.create(); -Effect.Fade.prototype = { - initialize: function(element) { - this.element = $(element); - this.start = 100; - this.finish = 0; - this.current = this.start; - this.fade(); - }, - - fade: function() { - if (this.isFinished()) { this.element.style.display = 'none'; return; } - if (this.timer) clearTimeout(this.timer); - this.setOpacity(this.element, this.current); - this.current -= 10; - this.timer = setTimeout(this.fade.bind(this), 50); - }, - - isFinished: function() { - return this.current <= this.finish; - }, - - setOpacity: function(element, opacity) { - opacity = (opacity == 100) ? 99.999 : opacity; - element.style.filter = "alpha(opacity:"+opacity+")"; - element.style.opacity = opacity/100 /*//*/; - } -} - -Effect.Scale = Class.create(); -Effect.Scale.prototype = { - initialize: function(element, percent) { - this.element = $(element); - this.startScale = 1.0; - this.startHeight = this.element.offsetHeight; - this.startWidth = this.element.offsetWidth; - this.currentHeight = this.startHeight; - this.currentWidth = this.startWidth; - this.finishScale = (percent/100) /*//*/; - if (this.element.style.fontSize=="") this.sizeEm = 1.0; - if (this.element.style.fontSize.indexOf("em")>0) - this.sizeEm = parseFloat(this.element.style.fontSize); - if(this.element.effect_scale) { - clearTimeout(this.element.effect_scale.timer); - this.startScale = this.element.effect_scale.currentScale; - this.startHeight = this.element.effect_scale.startHeight; - this.startWidth = this.element.effect_scale.startWidth; - if(this.element.effect_scale.sizeEm) - this.sizeEm = this.element.effect_scale.sizeEm; - } - this.element.effect_scale = this; - this.currentScale = this.startScale; - this.factor = this.finishScale - this.startScale; - this.options = arguments[2] || {}; - this.scale(); - }, - - scale: function() { - if (this.isFinished()) { - this.setDimensions(this.element, this.startWidth*this.finishScale, this.startHeight*this.finishScale); - if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.finishScale + "em"; - if(this.options.complete) this.options.complete(this); - return; - } - if (this.timer) clearTimeout(this.timer); - if (this.options.step) this.options.step(this); - this.setDimensions(this.element, this.currentWidth, this.currentHeight); - if(this.sizeEm) this.element.style.fontSize = this.sizeEm*this.currentScale + "em"; - this.currentScale += (this.factor/10) /*//*/; - this.currentWidth = this.startWidth * this.currentScale; - this.currentHeight = this.startHeight * this.currentScale; - this.timer = setTimeout(this.scale.bind(this), 50); - }, - - isFinished: function() { - return (this.factor < 0) ? - this.currentScale <= this.finishScale : this.currentScale >= this.finishScale; - }, - - setDimensions: function(element, width, height) { - element.style.width = width + 'px'; - element.style.height = height + 'px'; - } -} - -Effect.Squish = Class.create(); -Effect.Squish.prototype = { - initialize: function(element) { - this.element = $(element); - new Effect.Scale(this.element, 1, { complete: this.hide.bind(this) } ); - }, - hide: function() { - this.element.style.display = 'none'; - } -} - -Effect.Puff = Class.create(); -Effect.Puff.prototype = { - initialize: function(element) { - this.element = $(element); - this.opacity = 100; - this.startTop = this.element.top || this.element.offsetTop; - this.startLeft = this.element.left || this.element.offsetLeft; - new Effect.Scale(this.element, 200, { step: this.fade.bind(this), complete: this.hide.bind(this) } ); - }, - fade: function(effect) { - topd = (((effect.currentScale)*effect.startHeight) - effect.startHeight)/2; - leftd = (((effect.currentScale)*effect.startWidth) - effect.startWidth)/2; - this.element.style.position='absolute'; - this.element.style.top = this.startTop-topd + "px"; - this.element.style.left = this.startLeft-leftd + "px"; - this.opacity -= 10; - this.setOpacity(this.element, this.opacity); - if(navigator.appVersion.indexOf('AppleWebKit')>0) this.element.innerHTML += ''; //force redraw on safari - }, - hide: function() { - this.element.style.display = 'none'; - }, - setOpacity: function(element, opacity) { - opacity = (opacity == 100) ? 99.999 : opacity; - element.style.filter = "alpha(opacity:"+opacity+")"; - element.style.opacity = opacity/100 /*//*/; - } -} - -Effect.Appear = Class.create(); -Effect.Appear.prototype = { - initialize: function(element) { - this.element = $(element); - this.start = 0; - this.finish = 100; - this.current = this.start; - this.fade(); - }, - - fade: function() { - if (this.isFinished()) return; - if (this.timer) clearTimeout(this.timer); - this.setOpacity(this.element, this.current); - this.current += 10; - this.timer = setTimeout(this.fade.bind(this), 50); - }, - - isFinished: function() { - return this.current > this.finish; - }, - - setOpacity: function(element, opacity) { - opacity = (opacity == 100) ? 99.999 : opacity; - element.style.filter = "alpha(opacity:"+opacity+")"; - element.style.opacity = opacity/100 /*//*/; - element.style.display = ''; - } -} - -Effect.ContentZoom = Class.create(); -Effect.ContentZoom.prototype = { - initialize: function(element, percent) { - this.element = $(element); - if (this.element.style.fontSize=="") this.sizeEm = 1.0; - if (this.element.style.fontSize.indexOf("em")>0) - this.sizeEm = parseFloat(this.element.style.fontSize); - if(this.element.effect_contentzoom) { - this.sizeEm = this.element.effect_contentzoom.sizeEm; - } - this.element.effect_contentzoom = this; - this.element.style.fontSize = this.sizeEm*(percent/100) + "em" /*//*/; - if(navigator.appVersion.indexOf('AppleWebKit')>0) { this.element.scrollTop -= 1; }; - } -} diff --git a/examples/filebrowser/js-lib/xinha_config.js b/examples/filebrowser/js-lib/xinha_config.js deleted file mode 100644 index 2d5db9e..0000000 --- a/examples/filebrowser/js-lib/xinha_config.js +++ /dev/null @@ -1,94 +0,0 @@ -// From http://xinha.python-hosting.com/wiki/NewbieGuide - -xinha_editors = null; -xinha_init = null; -xinha_config = null; -xinha_plugins = null; - -// This contains the names of textareas we will make into Xinha editors -xinha_init = xinha_init ? xinha_init : function() { - /** STEP 1 ********************************************************** - * First, what are the plugins you will be using in the editors on - * this page. List all the plugins you will need, even if not all - * the editors will use all the plugins. - ********************************************************************/ - - xinha_plugins = xinha_plugins ? xinha_plugins : - ['CharacterMap', - 'FullScreen', - 'ListType', - 'SuperClean', - ]; - // THIS BIT OF JAVASCRIPT LOADS THE PLUGINS, NO TOUCHING :) - if(!HTMLArea.loadPlugins(xinha_plugins, xinha_init)) return; - - /** STEP 2 ********************************************************** - * Now, what are the names of the textareas you will be turning into - * editors? - ********************************************************************/ - - xinha_editors = xinha_editors ? xinha_editors : - ['myTextArea', - 'anotherOne' - ]; - - /** STEP 3 *********************************************************** - * We create a default configuration to be used by all the editors. - * If you wish to configure some of the editors differently this will be - * done in step 5. - * - * If you want to modify the default config you might do something like this. - * - * xinha_config = new HTMLArea.Config(); - * xinha_config.width = '640px'; - * xinha_config.height = '420px'; - * - *********************************************************************/ - - xinha_config = xinha_config ? xinha_config() : new HTMLArea.Config(); - xinha_config.height = '420px'; - - if (typeof(xinha_stylesheets) != 'undefined') { - xinha_config.pageStyleSheets = xinha_stylesheets; - } - - /** STEP 4 *********************************************************** - * We first create editors for the textareas. - * - * You can do this in two ways, either - * - * xinha_editors = HTMLArea.makeEditors(xinha_editors, xinha_config, xinha_plugins); - * - * if you want all the editor objects to use the same set of plugins, OR; - * - * xinha_editors = HTMLArea.makeEditors(xinha_editors, xinha_config); - * xinha_editors['myTextArea'].registerPlugins(['Stylist','FullScreen']); - * xinha_editors['anotherOne'].registerPlugins(['CSS','SuperClean']); - * - * if you want to use a different set of plugins for one or more of the - * editors. - ********************************************************************/ - - xinha_editors = HTMLArea.makeEditors(xinha_editors, xinha_config, xinha_plugins); - - /** STEP 5 *********************************************************** - * If you want to change the configuration variables of any of the - * editors, this is the place to do that, for example you might want to - * change the width and height of one of the editors, like this... - * - * xinha_editors.myTextArea.config.width = '640px'; - * xinha_editors.myTextArea.config.height = '480px'; - * - ********************************************************************/ - - - /** STEP 6 *********************************************************** - * Finally we "start" the editors, this turns the textareas into - * Xinha editors. - ********************************************************************/ - - HTMLArea.startEditors(xinha_editors); -} - -window.onload = xinha_init; - diff --git a/examples/filebrowser/pathobj.py b/examples/filebrowser/pathobj.py deleted file mode 100644 index aeda780..0000000 --- a/examples/filebrowser/pathobj.py +++ /dev/null @@ -1,511 +0,0 @@ -import re -import os -import mimetypes -import itertools -import random -import urllib -import cgi -import htmlentitydefs -import shutil -from paste.wareweb import dispatch, public -from paste.httpexceptions import * -import sitepage - -view_servlet_module = None - -class BadFilePath(Exception): - pass - -def html_quote(v): - return cgi.escape(v, 1) -def html_unquote(v, encoding='UTF8'): - for name, codepoint in htmlentitydefs.name2codepoint.iteritems(): - v = v.replace('&%s;' % name, unichr(codepoint).encode(encoding)) - return v - -class PathContext(object): - - path_classes = {} - - def __init__(self, root, config): - self.root = root - self.config = config - - def path(self, path): - filename = self.root + '/' + path.lstrip('/') - if os.path.isdir(filename): - ptype = 'dir' - else: - ptype = os.path.splitext(filename)[1] - path_class = self.path_classes.get(ptype) - if not path_class: - mimetype, encoding = mimetypes.guess_type(filename) - if mimetype: - path_class = self.path_classes.get(mimetype) - if mimetype and not path_class: - path_class = self.path_classes.get(mimetype.split('/')[0]+'/*') - if not path_class: - path_class = self.path_classes['*'] - return path_class(path, filename, self) - - @classmethod - def register_class(cls, path_class): - assert not isinstance(path_class.extensions, (str, unicode)) - for ptype in path_class.extensions: - assert ptype not in cls.path_classes, ( - "When adding class %r, conflict with class %r for " - "extension %r" % (path_class, cls.path_classes[ptype], - ptype)) - cls.path_classes[ptype] = path_class - - def stylesheets(self): - if self.config.get('stylesheet'): - value = self.config['stylesheet'] - else: - value = [] - if isinstance(value, (str, unicode)): - value = [value] - return [self.path(p) for p in value] - - def translate_path(self, path): - possible = self.config.get('live_web_translation', {}).items() - possible.sort(lambda a, b: cmp(len(a[0]), len(b[0]))) - for source, dest in possible: - if path.startswith(source): - return dest + path[len(source):] - return None - -class Path(sitepage.SitePage): - - extensions = ['*'] - - dispatch = dispatch.ActionDispatch( - action_name='action', - default_action='view_raw') - - isdir = False - allow_edit = False - view_file_view = 'view_file.pt' - - def __init__(self, path, filename, context): - super(Path, self).__init__() - self.path = path - self.filename = filename - self.pathcontext = context - self.root = context.root - self.mimetype, self.encoding = mimetypes.guess_type(self.filename) - if not self.mimetype: - self.mimetype = 'application/octet-stream' - self.basename = os.path.basename(filename) - self.exists = os.path.exists(filename) - - def __str__(self): - return self.path - - def __repr__(self): - return '<%s %s>' % (self.__class__.__name__, self.path) - - def size_text(self): - st = os.stat(self.filename) - size = st.st_size - if size < 1024: - return '%i bytes' % size - if size < 1024*1024: - return '%iKb' % (size/1024) - return '%.1fMb' % (size/1024.0/1024.0) - - def setup(self): - self.title = 'File: %s' % self.basename - self.options.parent = { - 'url': self.pathurl.up(), - 'name': self.pathurl.up().name() or 'root', - } - self.options.allow_edit = self.allow_edit - self.setup_file() - - def setup_file(self): - mime = self.mimetype - if mime and mime.startswith('text/'): - self.options.content = self.read() - else: - self.options.content = None - self.options.use_iframe = mime == 'text/html' - - def action_view(self): - self.view = self.view_file_view - - def action_download(self): - # @@: This loads the entire file into memory, but currently - # Wareweb has no streaming method -- really it should forward - # the request to a WSGI file-serving application - self.view = None - self.set_header('content-type', self.mimetype) - f = open(self.filename, 'rb') - self.write(f.read()) - f.close() - - def action_delete(self): - parent = self.pathurl.up() - os.unlink(self.filename) - self.message.write('%s deleted' % self.basename) - self.redirect(parent, action='view') - - def join(self, name): - parts = name.split('/') - for part in parts: - if part.startswith('.'): - raise BadFilePath( - "The path part %r starts with '.', which is illegal" - % part) - if ':' in name: - raise BadFilePath( - "The path %r contains ':', which is illegal" % name) - if '\\' in name: - raise BadFilePath( - "The path %r contains '\\', which is illegal" % name) - name = name.lstrip('/') - name = re.sub(r'//+', '/', name) - new_path = self.path - if not new_path.endswith('/'): - new_path += '/' - new_path += name - return self.pathcontext.path(new_path) - - def live_url(self): - return self.pathcontext.translate_path(self.path) - - bad_regexes = [ - re.compile(r'<script.*?</script>', re.I+re.S), - re.compile(r'style="[^"]*position:.*?"', re.I+re.S), - ] - - def action_view_raw(self): - self.view = None - if not self.exists: - raise HTTPNotFound - self.set_header('Content-type', self.mimetype) - content = self.read() - if (self.mimetype.startswith('text/html') - and self.fields.get('html') == 'clean'): - for bad_regex in bad_regexes: - content = self.bad_regex.sub('', content) - self.write(content) - - def action_save(self): - content = self.fields.content - self.write_text(content) - self.message.write('%i bytes saved to %s' - % (len(content), self.basename)) - self.redirect(str(self.pathurl(action='edit'))) - - def action_rename(self): - dest = self.fields.get('dest') - if dest and ('/' in dest or '\\' in dest): - self.message.write('Bad filename (cannot contain / or \\): %r' - % dest) - dest = None - if not dest: - self.options.action = self.pathurl(action='rename') - self.view = 'rename.pt' - return - new_filename = os.path.join(os.path.dirname(self.filename), dest) - new_path = os.path.join(os.path.dirname(self.path), dest) - shutil.move(self.filename, new_filename) - self.message.write('Renamed to %s' % dest) - self.redirect(self.pathurl(new_path, action='view')) - - def read(self): - f = open(self.filename, 'rb') - content = f.read() - f.close() - return content - - def write_text(self, content): - f = open(self.filename, 'wb') - f.write(content) - f.close() - -PathContext.register_class(Path) - -class Image(Path): - - extensions = ['.png', '.gif', '.jpg', 'image/*'] - view_file_view = 'view_image.pt' - -PathContext.register_class(Image) - -class TextFile(Path): - - extensions = ['.txt', 'text/plain', 'text/*'] - allow_edit = True - edit_view = 'edit_text.pt' - - def action_view(self): - if self.fragment: - # The HTML iframe is nice in a fragment - self.view = 'view_html.pt' - else: - self.view = 'view_text.pt' - - def action_edit(self): - self.view = self.edit_view - self.options.content = self.read() - self.options.action = str(self.pathurl) - self.options.ta_height = self.cookies.get('default_ta_height', 10) - -PathContext.register_class(TextFile) - -class HTMLFile(TextFile): - - allow_edit = True - extensions = ['.html', '.htm', 'text/html'] - edit_view = 'edit_html.pt' - - def action_view(self): - self.view = 'view_html.pt' - - def action_edit(self): - super(HTMLFile, self).action_edit() - content = self.read() - head, body, tail = self.split_content(content) - self.options.content = body - props = self.read_properties(head) - op_props = self.options.properties = [] - for name, value in sorted(props.items()): - op_props.append({ - 'description': name, - 'input_name': 'property_' + name, - 'type': 'text', - 'value': value}) - - def action_save(self): - # Unlike Path.save, this doesn't save the entire contents - # of the file - content = self.fields.content - assert content is not None, ( - "No content?: %s" % repr(self.fields.keys())) - props = {} - for name, value in self.fields.items(): - if name.startswith('property_'): - props[name[len('property_'):]] = value - self.save(content, props) - self.message.write('File %s saved' % self.basename) - self.redirect(str(self.pathurl(action='edit'))) - - def save(self, content, props): - current = self.read() - head, body, tail = self.split_content(current) - new_head = self.save_properties(head, props) - new_content = new_head + content + tail - self.write_text(new_content) - - def get_regexes(self, name, default=()): - regex = self.config.get(name) - if regex is None: - regex = [] - if not isinstance(regex, (list, tuple)): - regex = [regex] - regex = list(regex) - if default: - regex.extend(default) - for i in range(len(regex)): - if isinstance(regex[i], (str, unicode)): - regex[i] = re.compile(regex[i], re.I) - return regex - - def first_match(self, regexes, body): - for regex in regexes: - m = regex.search(body) - if m: - return m - return None - - def split_content(self, content): - body_start_regex = self.get_regexes( - 'body_start_regex', ['<body.*?>']) - body_end_regex = self.get_regexes( - 'body_end_regex', ['</body>']) - m = self.first_match(body_start_regex, content) - if m: - head = content[:m.end()] - content = content[m.end():] - else: - head = '' - m = self.first_match(body_end_regex, content) - if m: - tail = content[m.start():] - content = content[:m.start()] - else: - tail = '' - return head, content, tail - - title_re = re.compile('<title>(.*?)</title>', re.I|re.S) - def read_properties(self, head): - prop_regex = self.get_regexes( - 'property_regex') - props = {} - m = self.title_re.search(head) - if m: - props['title'] = m.group(1) - for regex in prop_regex: - for match in regex.finditer(head): - groups = match.groupdict() - if 'value' in groups: - value = groups['value'] - elif 'html_value' in groups: - value = html_unquote(groups['html_value']) - elif 'url_value' in groups: - value = urllib.unquote(groups['url_value']) - props[match.group('name')] = value - return props - - def save_properties(self, head, props): - prop_regex = self.get_regexes( - 'property_regex') - prop_tmpl = self.config['property_template'] - if 'title' in props: - title_html = '<title>%s</title>' % html_quote(props['title']) - m = self.title_re.search(head) - if m: - head = head[:m.start()] + title_html + head[m.end():] - del props['title'] - else: - head = title_html + head - for name, value in props.items(): - new_prop = prop_tmpl % { - 'name': name, - 'html_value': html_quote(value), - 'url_value': urllib.quote(value), - 'value': value} - for regex in prop_regex: - for match in regex.finditer(head): - if name != match.group('name'): - continue - head = (head[:match.start()] + new_prop - + head[match.end():]) - break - else: - head = new_prop + head - return head - - -PathContext.register_class(HTMLFile) - -class Dir(Path): - - extensions = ['dir'] - - isdir = True - - upload_id = itertools.count(random.randint(0, 15000)) - - def size_text(self): - return None - - def setup_file(self): - files = [] - for filename in sorted(os.listdir(self.filename)): - try: - path_servlet = self.join(filename) - except BadFilePath: - continue - files.append({ - 'path': path_servlet, - 'name': filename, - 'url': self.pathurl(filename, action='view'), - 'copyid': self.pathid('copy_', str(path_servlet)), - }) - if path_servlet.isdir: - files[-1]['name'] += '/' - self.options.files = files - self.options.upload_id = self.upload_id.next() - # With upload progress, something like this will be necessary: - #self.options.upload_url = self.globalurl( - # 'uploader', upload_id=self.options.upload_id, - # redirect='/') - self.options.upload_url = self.pathurl(action='upload') - - def action_view_raw(self): - self.action_view() - - def action_view(self): - self.view = 'directory.pt' - - def action_upload(self): - number = 0 - for name in self.fields: - if name.startswith('file_'): - field = self.fields[name] - if isinstance(field, str) and not field: - continue - assert not isinstance(field, (str, unicode)), ( - "Bad field %s (contains %r)" % (name, field)) - result = self._do_upload(field) - number += 1 - if not number: - self.message.write('No files uploaded') - if number == 1: - self.redirect(self.pathurl(result.path, action='view')) - else: - self.redirect(self.pathurl(action='view')) - - def _do_upload(self, field): - filename = field.filename - if '/' in filename: - filename = filename.split('/')[-1] - if '\\' in filename: - filename = filename.split('\\')[-1] - content = field.value - f = self.join(filename) - f.write_text(content) - self.message.write('File %s uploaded' % filename) - return f - - def action_mkdir(self): - dirname = self.fields.dirname - dest = self.join(dirname) - os.mkdir(dest.filename) - self.message.write('Created directory %s' % dest) - self.redirect(self.pathurl(dest.path, action='view')) - - def action_create_from_blank(self): - tmpl = self.fields.template - filename = self.fields.filename - good = True - if not tmpl: - self.message.write('You must select a blank template') - good = False - if not filename: - self.message.write('You must give a filename') - good = False - if not good: - self.redirect(self.pathurl(action='view')) - if not os.path.splitext(filename)[1]: - filename += os.path.splitext(tmpl)[1] - source = self.pathcontext.path(tmpl) - dest = self.join(filename) - dest.write_text(source.read()) - self.message.write('%s created' % dest.basename) - self.redirect(self.pathurl(dest.path, action='edit')) - - def listdir(self): - result = [] - for fn in os.listdir(self.filename): - try: - result.append(self.join(fn)) - except BadFilePath: - pass - return result - - def find_filename(self, filename): - results = [] - for file in self.listdir(): - if filename.lower() in file.basename.lower(): - results.append(file) - if file.isdir: - results.extend(file.find_filename(filename)) - return results - - -PathContext.register_class(Dir) - diff --git a/examples/filebrowser/server.conf b/examples/filebrowser/server.conf deleted file mode 100644 index a7a1127..0000000 --- a/examples/filebrowser/server.conf +++ /dev/null @@ -1,46 +0,0 @@ -# -*- python -*- Note: this file is in Python syntax - -import os - -app_template = 'wareweb_zpt' -app_name = 'filebrowser' -framework = 'wareweb' -root_path = os.path.dirname(__file__) -publish_dir = os.path.join(root_path, 'web') - -## Server options: - -verbose = True -# The name of the server-type to start: -server = 'wsgiutils' -# If true, files will be regularly polled and the server restarted -# if files are modified: -reload = True -# If true, tracebacks will be shown in the browser: -debug = True -show_exceptions_in_error_log = False - -browse_path = os.path.join(root_path, 'test-data') - -if os.path.exists(os.path.join(root_path, 'local.conf')): - include('local.conf') - -# This is an example that uses SSIs for the page structure: -body_start_regex = [ - r'<!--#include virtual="/lib/header.ssi" -->'] -body_end_regex = [ - r'<!--#include virtual="/lib/footer.ssi" -->'] -property_regex = [ - r'<!--#set\s+var="(?P<name>[^"]*)"\s+value="(?P<html_value>[^"]*)"\s+-->'] -property_template = '<!--#set var="%(name)s" value="%(html_value)s" -->\n' - -from mimetypes import types_map -types_map['.ssi'] = 'text/plain' -types_map['.inc'] = 'text/plain' - -# This is used for the stylesheet in the WYSIWYG editor: -stylesheet = '/lib/style.css' -# This directory is searched for blank.* files: -blank_file_dir = '/lib' -# This is used to map files to their 'live' URLs: -live_web_translation = {'/': 'http://host.com/dir/'} diff --git a/examples/filebrowser/sitepage.py b/examples/filebrowser/sitepage.py deleted file mode 100644 index a5a300a..0000000 --- a/examples/filebrowser/sitepage.py +++ /dev/null @@ -1,268 +0,0 @@ -import cgi -import itertools -import os -import urllib -import random -from paste.wareweb import * -from paste import wsgilib -from paste import CONFIG -from ZPTKit.zptwareweb import ZPTComponent -import handlers - -class SitePage(Servlet): - - message = Notify() - template = ZPTComponent() - app_name = 'filebrowser' - - def awake(self): - super(SitePage, self).awake(call_setup=False) - self.pathcontext = self.environ['filebrowser.pathcontext'] - self.pathurl = URL(self.environ, - script_name=self.app_url, - path_info=self.path_info) - # While this is the URL that points to the non-file-specific - # application (for things like copy and past) - self.globalurl = URL(self.environ, - script_name=self.app_url + '/_app', - path_info='') - self.icons = Icon(self.app_url + '/_icons') - self.app_static_url = self.app_url + '/_static' - # Prototype adds this special _ variable for Ajax requests: - self.fragment = '_' in self.fields - self.copybin = self.session.setdefault('copybin', {}) - self.update_copybin_display() - self.setup() - - def handler(self, path=None): - path = path or self.file - handler = handlers.get_handler(path) - - def update_copybin_display(self): - files = self.options.copyfiles = [] - for filename, cutcopy in self.copybin.items(): - path = self.pathcontext.path(filename) - files.append( - {'filename': filename, - 'url': self.app_url + filename + "?action=view", - 'path': path, - 'name': path.basename, - 'cut': cutcopy=='cut', - 'copy': cutcopy=='copy', - 'id': self.pathid('copy_', filename), - }) - files.sort(key=lambda x: x['filename']) - - def pathid(self, prefix, path): - return prefix + str(path).replace('/', '__') - - def copybutton(self, path, copytype='copy'): - assert copytype in ('copy', 'cut') - copyurl = self.globalurl('copybin', **{ - copytype: path}) - remote = copyurl.remote( - id='copybin', - onComplete='function (req) {new Effect.Highlight(%r)}' - % self.pathid('copy_', path)) - img = self.icons('edit%s.png' % copytype, alt=copytype, - title=copytype) - return remote.link(img) - - def pastebutton(self, path): - copyurl = self.globalurl('copybin', paste=path, - back=wsgilib.construct_url(self.environ)) - return '<a href="%s">%s</a>' % ( - copyurl, self.icons('editpaste', alt="paste", - title="Paste Files")) - - def setup_xinha(self): - html = [] - base_url = self.app_url + '/_js-lib/xinha/' - html.append('<script type="text/javascript">') - html.append('_editor_url = %r;' % base_url) - html.append('_editor_lang = "en";') - stylesheets = self.pathcontext.stylesheets() - if stylesheets: - html.append('xinha_stylesheets = %r;' - % [str(self.pathurl(s.path)) for s in stylesheets]) - html.append('</script>') - html.append('<script type="text/javascript" src="%s"></script>' - % (base_url + 'htmlarea.js')) - html.append('<script type="text/javascript" src="%s"></script>' - % (self.app_url + '/_js-lib/xinha_config.js')) - return '\n'.join(html) - - -class URL(object): - - def __init__(self, environ, script_name=None, path_info=None, - vars=None): - if script_name is None: - script_name = environ['SCRIPT_NAME'] - self.script_name = script_name - if path_info is None: - path_info = environ['PATH_INFO'] - self.path_info = path_info - self.environ = environ - self.vars = vars or {} - - def __str__(self): - return wsgilib.construct_url( - self.environ, with_query_string=True, with_path_info=True, - script_name=self.script_name, path_info=self.path_info, - querystring=urllib.urlencode(self.vars)) - - def __repr__(self): - return '<URL %s>' % self - - def url_without_qs(self): - return wsgilib.construct_url( - self.environ, with_query_string=True, with_path_info=True, - script_name=self.script_name, path_info=self.path_info, - querystring='') - url_without_qs = property(url_without_qs) - - def __getitem__(self, add): - vars = self.vars.copy() - path_info = self.path_info - if add and '=' in add: - name, value = add.split('=', 1) - if name == 'confirm': - return ConfirmLink(self, urllib.unquote_plus(value)) - vars[name] = value - elif add and add.startswith('/'): - path_info = add - elif add: - if not path_info.endswith('/'): - path_info += '/' - path_info += add - return self.__class__(self.environ, script_name=self.script_name, - path_info=path_info, vars=vars) - - def __call__(self, *args, **kw): - obj = self[None] - for arg in args: - obj = obj[arg] - for name, value in kw.items(): - obj.vars[name] = value - return obj - - def remote(self, id=None, **options): - if id is None: - id = idgen() - return JSRemote(self, id, options) - - def toggle(self, id=None, **options): - if id is None: - id = idgen() - return JSToggle(self, id, options) - - def up(self): - path_info = '/'.join(self.path_info.split('/')[:-1]) - return self.__class__( - self.environ, script_name=self.script_name, - path_info=path_info, vars=self.vars) - - def name(self): - return self.path_info.split('/')[-1] - - def js_set_location(self): - return 'location.href = %r; return false' % str(self) - -# @@: This repeats numbers after a restart -_idgen_count = itertools.count(random.randint(0, 15000)) -def idgen(): - return 'node%s' % hex(_idgen_count.next() % 0xffffff)[2:] - -class JSRemote(object): - - def __init__(self, url, id, options): - self.url = url - self.id = id - self.options = options - - def option_js(self, **base): - base.update(self.options) - return '{%s}' % (', '.join([ - '%s: %s' % (name, value) - for name, value in base.items()])) - - def javascript(self): - return "new Ajax.Updater(%r, %r, %s); return false" % ( - self.id, self.url.url_without_qs, - self.option_js(parameters=repr(urllib.urlencode(self.url.vars.items())), - method=repr('get'))) - - javascript = property(javascript) - - def link(self, description, structure=True, **kw): - if not structure: - description = cgi.escape(description, 1) - return '<a href="%s" onclick="%s"%s>%s</a>' % ( - cgi.escape(str(self.url), 1), cgi.escape(self.javascript, 1), - html_attrs(kw), description) - -class JSToggle(JSRemote): - - def javascript(self): - return "lazyToggle(%r, %r, %s); return false" % ( - self.id, self.url.url_without_qs, - self.option_js(parameters=repr(urllib.urlencode(self.url.vars.items())), - link='this')) - - javascript = property(javascript) - -class ConfirmLink(object): - - def __init__(self, link, confirm): - self.link = link - self.confirm = confirm - - def __str__(self): - return ("if (window.confirm(%r)) {location.href=%r}; return false" - % (self.confirm, str(self.link))) - -def html_attrs(kw): - if not kw: - return '' - return ''.join([ - ' %s="%s"' % (name, cgi.escape(str(value), 1)) - for name, value in kw.items()]) - -class Icon(object): - - def __init__(self, url, attrs=None): - self.url = url - self.attrs = attrs or {} - - def html__get(self): - return '<img src="%s" border=0%s>' % ( - self.url, html_attrs(self.attrs)) - html = property(html__get) - - __str__ = html__get - - def copy(self): - return self.__class__(self.url, self.attrs.copy()) - - def __call__(self, *names, **kw): - obj = self.copy() - for name in names: - obj = obj[name] - obj.attrs.update(kw) - return obj - - def __getitem__(self, icon_name): - if '=' in icon_name: - obj = self.copy() - name, value = icon_name.split('=', 1) - value = value.replace('+', ' ') - obj.attrs[name] = value - return obj - else: - return self.__class__(self.url + '/' + icon_name) - -# This protects "from sitepage import *", since we will no longer -# need these variables: -del ZPTComponent -del Notify diff --git a/examples/filebrowser/static/stylesheet.css b/examples/filebrowser/static/stylesheet.css deleted file mode 100644 index afa3d9a..0000000 --- a/examples/filebrowser/static/stylesheet.css +++ /dev/null @@ -1,48 +0,0 @@ -body { - font-family: Helvetica, Arial, sans-serif; -} - -fieldset#copybinframe { - width: 40%; - float: right; - padding: 3px; -} - -td { - vertical-align: top; -} - -div.controls { - float: right; - display: inline; -} - -blockquote.subdisplay { - margin-top: 0; - margin-bottom: 0; - margin-right: 0; -} - -div.item { - margin-top: 0; - margin-bottom: 0; -} - -div.odd { - background-color: #eee; -} - -pre { - overflow: auto; -} - -div.notifyMessage { - border: 2px solid black; - background-color: #007700; - color: #ffffff; - padding: 5px; -} - -form.inline { - display: inline; -} diff --git a/examples/filebrowser/templates/addfile_form.pt b/examples/filebrowser/templates/addfile_form.pt deleted file mode 100644 index e75275e..0000000 --- a/examples/filebrowser/templates/addfile_form.pt +++ /dev/null @@ -1,13 +0,0 @@ -<form class="inline" action="" method="POST"> -<input type="hidden" name="action" value="create_from_blank"> -Create from: -<select name="template"> - <option value="">select template</option> - <option tal:repeat="blank options/blanks" - tal:attributes="value blank/path" - tal:content="blank/basename"/> -</select> -in: -<input type="text" name="filename" style="width: 5em"> -<input type="submit" value="create"> -</form> diff --git a/examples/filebrowser/templates/copybin.pt b/examples/filebrowser/templates/copybin.pt deleted file mode 100644 index a2d011c..0000000 --- a/examples/filebrowser/templates/copybin.pt +++ /dev/null @@ -1,28 +0,0 @@ -<metal:tpl define-macro="copybin"> - -<tal:if condition="options/copyfiles"> - -<tal:for repeat="f options/copyfiles"> - <div tal:attributes="class python: 'item %s' % test(repeat['f'].odd(), - 'odd', 'even'); - id f/id"> - <div class="controls"> - <span tal:replace="structure python: servlet.globalurl('copybin', - remove=f['filename']).remote('copybin').link(servlet.icons( - 'remove.png', title='Remove from clipboard'))"/> - </div> - <a tal:attributes="href f/url" - tal:content="f/filename" /> - <tal:if condition="f/cut">(cut)</tal:if> - </div> -</tal:for> - -<span style="float: right" - tal:content="structure python: servlet.globalurl('copybin', clear='t').remote('copybin').link('clear')"/> -</tal:if> - -<tal:if condition="not: options/copyfiles"> -the bin is empty -</tal:if> - -</metal:tpl> diff --git a/examples/filebrowser/templates/directory.pt b/examples/filebrowser/templates/directory.pt deleted file mode 100644 index cf57072..0000000 --- a/examples/filebrowser/templates/directory.pt +++ /dev/null @@ -1,95 +0,0 @@ -<html metal:use-macro="here/standard_template.pt/macros/page"> - -<metal:extra fill-slot="extra_head"> - -<script type="text/javascript"> -var field_index = 1; -function add_upload() { - var form = $('upload-form'); - var upload = document.createElement('INPUT'); - upload.setAttribute('type', 'file'); - field_index++; - upload.setAttribute('name', 'file_' + field_index); - form.appendChild(document.createElement('BR')); - form.appendChild(document.createTextNode('Upload: ')); - form.appendChild(upload); -} - -function change_upload_button() { - var button = $('upload-button'); - button.disabled = 'true'; - button.value = 'Uploading...'; -} -</script> - -</metal:extra> - -<metal:body fill-slot="body"> - -<div class="header"> - <div class="controls"> - <span tal:replace="structure python: - servlet.pastebutton(servlet.path)"/> - </div> - <tal:if condition="python: not servlet.fragment and options.get('parent')"> - Parent: <a tal:attributes="href options/parent/url" - tal:content="options/parent/name"/><br> - </tal:if> - Files: <tt tal:content="python: len(options['files'])"/> - | <a href="#" onclick="toggle('mkdir', {link: this}); return false" - shownhtml="&lt;&lt;&lt;" - style="text-decoration: none; color: #226">make dir...</a> - <span id="mkdir" style="display: none"> - <form tal:attributes="action servlet/pathurl/action=mkdir" - method="POST" class="inline"> - <input type="text" name="dirname" style="width: 5em"> - <input type="submit" value="make"> - </form> - </span> - - | <tal:let define="toggle servlet/globalurl/addfile_form/toggle"> - <span tal:replace="structure python: toggle.link( - 'add file...', shownhtml='&lt;&lt;&lt;', - style='text-decoration: none; color: #226')"/> - <span tal:attributes="id toggle/id" style="display: none"> - ... - </span> - </tal:let> - -</div> - -<tal:for repeat="f options/files"> - <div tal:attributes="class python: 'item %s' % test(repeat['f'].odd(), - 'odd', 'even')" - tal:define="toggle f/url/toggle"> - <div class="controls"> - <span tal:condition="python: f['path'].isdir" - tal:replace="structure python: servlet.pastebutton(f['path'])"/> - <span tal:replace="structure python: servlet.copybutton(f['path'], 'cut')"/> - <span tal:replace="structure python: servlet.copybutton(f['path'], - 'copy')"/> - </div> - <span tal:replace="structure python: toggle.link( - servlet.icons('1downarrow.png', alt='display'), - shownhtml=servlet.icons('1uparrow.png', alt='hide'))"/> - <a tal:attributes="href f/url" - tal:content="f/name" /> - <blockquote tal:attributes="id toggle/id" - style="display: none" class="subdisplay">...</blockquote> - </div> -</tal:for> - -<p tal:condition="not: options/files"> -There are no files in this directory -</p> - -<form tal:attributes="action options/upload_url" method="POST" - enctype="multipart/form-data" id="upload-form" - onsubmit="change_upload_button(); return true;"> -Upload: <input type="file" name="file_1"> -<input type="submit" value="Upload" id="upload-button"> -<button onclick="add_upload(); return false;">More...</button> -</form> - -</metal:body> -</html> diff --git a/examples/filebrowser/templates/edit_html.pt b/examples/filebrowser/templates/edit_html.pt deleted file mode 100644 index 74afda0..0000000 --- a/examples/filebrowser/templates/edit_html.pt +++ /dev/null @@ -1,35 +0,0 @@ -<html metal:use-macro="here/standard_template.pt/macros/page"> - -<metal:head fill-slot="extra_head"> -<span tal:replace="structure servlet/setup_xinha"/> -<script type="text/javascript"> -xinha_editors = ['txt-content']; - -</script> -</metal:head> - -<metal:body fill-slot="body"> - -<form tal:attributes="action options/action" method="POST"> -<input type="hidden" name="action" value="save"> - -<table tal:condition="options/properties | nothing"> - <tr tal:repeat="prop options/properties"> - <td tal:content="prop/description">name</td> - <td><input tal:attributes="type prop/type; name prop/input_name; - value prop/value" style="width: 100%"></td> - </tr> -</table> - -<textarea name="content" id="txt-content" cols=60 style="width: 100%" - tal:attributes="rows options/ta_height" - tal:content="options/content"></textarea> -<br> -<input type="submit" value="Save"> -<button tal:attributes="onclick - servlet/pathurl/action=view/js_set_location">Cancel</button> - -</form> - -</metal:body> -</html>
\ No newline at end of file diff --git a/examples/filebrowser/templates/edit_text.pt b/examples/filebrowser/templates/edit_text.pt deleted file mode 100644 index b730ae7..0000000 --- a/examples/filebrowser/templates/edit_text.pt +++ /dev/null @@ -1,72 +0,0 @@ -<html metal:use-macro="here/standard_template.pt/macros/page"> - -<metal:head fill-slot="extra_head"> -<script type="text/javascript"> - -function adjust_textarea(id, adjustment) { - var el = $(id); - current = parseInt(el.getAttribute('rows')); - current += adjustment; - if (current < 2) { - current = 2; - } - el.setAttribute('rows', current); - createCookie('default_ta_height', current, 365*2); - return false; -} - -function find_text(txt_id, input_id) { - var textarea = $(txt_id); - var txt = textarea.value.toLowerCase(); - var input = $(input_id); - input.style.backgroundColor = '#fff'; - var search_term = input.value.toLowerCase(); - if (! search_term) { - return false; - } - var search_txt = txt; - var offset = 0; - if (textarea.selectionEnd - textarea.selectionStart) { - search_txt = txt.substring(textarea.selectionEnd); - offset = textarea.selectionEnd; - } - var pos = search_txt.indexOf(search_term); - if (pos == -1) { - input.style.backgroundColor = '#fdd'; - textarea.selectionStart = textarea.selectionEnd = 0; - return false; - } - textarea.selectionStart = pos + offset; - textarea.selectionEnd = pos + offset + search_term.length; - return false; -} - -</script> -</metal:head> - -<metal:body fill-slot="body"> - -<form tal:attributes="action options/action" method="POST"> -<input type="hidden" name="action" value="save"> -<textarea name="content" id="txt-content" cols=60 style="width: 100%" - tal:attributes="rows options/ta_height" - tal:content="options/content"></textarea> -<br> -<input type="submit" value="Save"> -<button tal:attributes="onclick - servlet/pathurl/action=view/js_set_location">Cancel</button> -<button onclick="return adjust_textarea('txt-content', 1)">+</button> -<button onclick="return adjust_textarea('txt-content', -1)">-</button> -<a href="#" onclick="toggle('find-txt', {link: this}); return false" - shownhtml="&lt;&lt;&lt;" - style="text-decoration: none; color: #226">find...</a> -<span id="find-txt" style="display: none"> -<input type="text" id="find-input" style="width: 5em"> -<button onclick="return find_text('txt-content', - 'find-input')">find</button> -</span> - -</form> - -</metal:body> -</html>
\ No newline at end of file diff --git a/examples/filebrowser/templates/generic_error.pt b/examples/filebrowser/templates/generic_error.pt deleted file mode 100644 index 7b32820..0000000 --- a/examples/filebrowser/templates/generic_error.pt +++ /dev/null @@ -1,7 +0,0 @@ -<html metal:use-macro="here/standard_template.pt/macros/page"> -<metal:body fill-slot="body"> - -<tal:block replace="structure options/error_message" /> - -</metal:body> -</html>
\ No newline at end of file diff --git a/examples/filebrowser/templates/rename.pt b/examples/filebrowser/templates/rename.pt deleted file mode 100644 index f36d27e..0000000 --- a/examples/filebrowser/templates/rename.pt +++ /dev/null @@ -1,15 +0,0 @@ -<html metal:use-macro="here/standard_template.pt/macros/page"> -<metal:body fill-slot="body"> - -<form tal:attributes="action options/action" method="POST"> -Rename <span tal:replace="servlet/path"/> to:<br> -<input type="text" name="dest" style="width: 100%" - tal:attributes="value servlet/basename"> -<br> -<input type="submit" value="Rename"> -<button tal:attributes="onclick - servlet/pathurl/action=view/js_set_location">Cancel</button> -</form> - -</metal:body> -</html> diff --git a/examples/filebrowser/templates/standard_template.pt b/examples/filebrowser/templates/standard_template.pt deleted file mode 100644 index 31e7359..0000000 --- a/examples/filebrowser/templates/standard_template.pt +++ /dev/null @@ -1,59 +0,0 @@ -<metal:tpl define-macro="page"> -<tal:if condition="not: servlet/fragment"> -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" - "http://www.w3.org/TR/REC-html40/loose.dtd"> -<html lang="en-US"> -<head> -<title tal:content="servlet/title">title</title> -<link rel="stylesheet" type="text/css" - tal:attributes="href python: servlet.app_static_url + '/stylesheet.css'"> -<script type="text/javascript" - tal:attributes="src string: ${servlet/app_url}/_js-lib/prototype-1.2.0.js"> -</script> -<script type="text/javascript" - tal:attributes="src string: ${servlet/app_url}/_js-lib/common.js"> -</script> - -<metal:slot define-slot="extra_head"></metal:slot> - -</head> -<body> - -<fieldset id="copybinframe"> -<legend>clipboard <a onclick="toggle('copybin', {link: this})" - tal:attributes="hiddenhtml - servlet/icons/1uparrow.png/alt=show/title=show+clipboard/html" - tal:content="structure servlet/icons/1downarrow.png/alt=hide/title=hide+clipboard/html"/> - <a onclick="jump(this)" - tal:attributes="jumpurl servlet/globalurl/jump" - tal:content="structure servlet/icons/goto.png/alt=goto/title=jump+to+file/html"/> -</legend> -<div id="copybin"> -<metal:tpl use-macro="here/copybin.pt/macros/copybin"> -</metal:tpl> -</div> -</fieldset> - -<h1><tal:mark replace="servlet/html_title"/></h1> - -<div class="notifyMessage" - tal:condition="servlet/message" - tal:content="structure servlet/message/html"> - [This is where the notification messages go] -</div> - -<div id="content"> -<metal:tpl define-slot="body"> -[This page has not customized its "body" slot] -</metal:tpl> -</div> - -</body> -</html> -</tal:if> -<tal:if condition="servlet/fragment"> -<metal:tpl define-slot="body"> -[This page has not customized its "body" slot] -</metal:tpl> -</tal:if> -</metal:tpl> diff --git a/examples/filebrowser/templates/view_file.pt b/examples/filebrowser/templates/view_file.pt deleted file mode 100644 index 6f6dae6..0000000 --- a/examples/filebrowser/templates/view_file.pt +++ /dev/null @@ -1,31 +0,0 @@ -<metal:tpl define-macro="view"> -<html metal:use-macro="here/standard_template.pt/macros/page"> -<metal:body fill-slot="body"> - -<p> -<tal:if condition="not: servlet/fragment"> -<tal:if condition="options/parent | nothing"> -Parent: <a tal:attributes="href options/parent/url" - tal:content="options/parent/name">name</a><br> -</tal:if> -</tal:if> -Mimetype: <tt tal:content="servlet/mimetype"/> -<tal:if condition="servlet/size_text | nothing"> - Size: <tt tal:content="servlet/size_text"/></tal:if> -<br> -<a tal:attributes="href servlet/pathurl/action=download">download</a> -<tal:if condition="options/allow_edit"> | - <a tal:attributes="href servlet/pathurl/action=edit">edit</a></tal:if> -| <a tal:attributes="href servlet/pathurl/action=rename">rename</a> -| <a href="#" tal:attributes="onclick - servlet/pathurl/action=delete/confirm=Are+you+sure+you+want+to+delete+this?" - >delete</a> - -</p> - -<metal:slot define-slot="view_inline"> -</metal:slot> - -</metal:body> -</html> -</metal:tpl>
\ No newline at end of file diff --git a/examples/filebrowser/templates/view_html.pt b/examples/filebrowser/templates/view_html.pt deleted file mode 100644 index b467426..0000000 --- a/examples/filebrowser/templates/view_html.pt +++ /dev/null @@ -1,9 +0,0 @@ -<html metal:use-macro="here/view_file.pt/macros/view"> -<metal:slot fill-slot="view_inline"> -<iframe width="100%" height="200" name="test" - tal:attributes="src - servlet/pathurl/action=download/html=clean"></iframe> - -</metal:slot> -</html> - diff --git a/examples/filebrowser/templates/view_image.pt b/examples/filebrowser/templates/view_image.pt deleted file mode 100644 index 193be66..0000000 --- a/examples/filebrowser/templates/view_image.pt +++ /dev/null @@ -1,6 +0,0 @@ -<html metal:use-macro="here/view_file.pt/macros/view"> -<metal:slot fill-slot="view_inline"> -<img tal:attributes="src servlet/pathurl/action=download"> -</metal:slot> -</html> - diff --git a/examples/filebrowser/templates/view_text.pt b/examples/filebrowser/templates/view_text.pt deleted file mode 100644 index 7606d4f..0000000 --- a/examples/filebrowser/templates/view_text.pt +++ /dev/null @@ -1,7 +0,0 @@ -<html metal:use-macro="here/view_file.pt/macros/view"> -<metal:slot fill-slot="view_inline"> -<pre style="overflow: auto" - tal:content="options/content">content</pre> -</metal:slot> -</html> - diff --git a/examples/filebrowser/web/__init__.py b/examples/filebrowser/web/__init__.py deleted file mode 100644 index 8b8f313..0000000 --- a/examples/filebrowser/web/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -import os -import urllib -from paste import CONFIG -from paste import wsgilib -from paste import httpexceptions -from paste import urlparser -from filebrowser import pathobj - -def urlparser_hook(environ): - if not environ.has_key('filebrowser.base_url'): - environ['filebrowser.base_url'] = environ['SCRIPT_NAME'] - -special_dirs = {} - -for special_dir in ['js-lib', 'icons', 'static']: - special_dirs[special_dir] = urlparser.URLParser( - os.path.join(os.path.dirname(os.path.dirname(__file__)), - special_dir), None) - -special_dirs['app'] = urlparser.URLParser( - os.path.dirname(__file__), 'filebrowser.web') - -def application(environ, start_response): - context = environ['filebrowser.pathcontext'] = pathobj.PathContext( - root=environ['paste.config']['browse_path'], - config=environ['paste.config']) - if environ.get('filebrowser.resolved'): - return special_dirs['app'](environ, start_response) - path_info = environ.get('PATH_INFO', '') - for special_dir, parser in special_dirs.items(): - if path_info.startswith('/_%s/' % special_dir): - environ['filebrowser.resolved'] = True - wsgilib.path_info_pop(environ) - return parser(environ, start_response) - path = urllib.unquote(environ['PATH_INFO']) - path_servlet = context.path(path) - return path_servlet(environ, start_response) - - diff --git a/examples/filebrowser/web/addfile_form.py b/examples/filebrowser/web/addfile_form.py deleted file mode 100644 index c459b59..0000000 --- a/examples/filebrowser/web/addfile_form.py +++ /dev/null @@ -1,10 +0,0 @@ -from filebrowser.sitepage import * - -class addfile_form(SitePage): - - def setup(self): - root = self.pathcontext.path(self.config.get('blank_file_dir', '/')) - self.options.blanks = root.find_filename('blank') - - -
\ No newline at end of file diff --git a/examples/filebrowser/web/copybin.py b/examples/filebrowser/web/copybin.py deleted file mode 100644 index e2a9696..0000000 --- a/examples/filebrowser/web/copybin.py +++ /dev/null @@ -1,54 +0,0 @@ -import shutil -from filebrowser.sitepage import * - -class copybin(SitePage): - - bins = ['copy', 'cut'] - - def setup(self): - for fn in self.fields.getlist('copy'): - self.copybin[fn] = 'copy' - for fn in self.fields.getlist('cut'): - self.copybin[fn] = 'cut' - for fn in self.fields.getlist('remove'): - if fn in self.copybin: - del self.copybin[fn] - if self.fields.get('clear'): - self.copybin.clear() - if 'paste' in self.fields: - return self.paste() - self.update_copybin_display() - - def paste(self): - if not self.copybin: - self.message.write('No items to paste') - self.redirect(self.fields.back) - return - dest = self.pathcontext.path(self.fields.paste) - copied = 0 - moved = 0 - for filename, copytype in self.copybin.items(): - path = self.pathcontext.path(filename) - dest_path = dest.join(path.basename) - if copytype == 'copy': - copied += 1 - shutil.copyfile(path.filename, dest_path.filename) - elif copytype == 'cut': - try: - shutil.movefile(path.filename, dest_path.filename) - except Exception, e: - self.message.write( - 'Cannot move to %s (%s)' % (dest, e)) - else: - moved += 1 - msg = [] - if copied: - msg.append('%i file%s copied' % ( - copied, copied>1 and 's' or '')) - if moved: - msg.append('%i file%s moved' % ( - moved, moved>1 and 's' or '')) - msg = ', '.join(msg) - self.copybin.clear() - self.message.write('%s to %s' % (msg, self.fields.paste)) - self.redirect(self.fields.back) diff --git a/examples/filebrowser/web/jump.py b/examples/filebrowser/web/jump.py deleted file mode 100644 index 72f7b39..0000000 --- a/examples/filebrowser/web/jump.py +++ /dev/null @@ -1,28 +0,0 @@ -from filebrowser.sitepage import * - -class jump(SitePage): - - def setup(self): - name = self.fields.name.strip() - action = 'view' - if name.startswith('edit:'): - action = 'edit' - name = name[5:].strip() - root = self.pathcontext.path('/') - if name == 'root': - possible = [root] - else: - possible = root.find_filename(name) - if not possible: - self.message.write('No files with %r found' % name) - self.redirect(self.environ['HTTP_REFERER']) - dest = possible[0] - if possible[1:]: - self.message.write('Other matches:') - for path in possible[1:]: - self.message.write( - '<a href="%s">%s</a>' - % (self.pathurl(path.path, action=action), path.path)) - self.redirect(self.pathurl(dest.path, action=action)) - -
\ No newline at end of file |
