The Python web server now uses jQuery Tablesorter
BIN
python/res/asc.gif
Normal file
|
After Width: | Height: | Size: 54 B |
BIN
python/res/bg.gif
Normal file
|
After Width: | Height: | Size: 64 B |
BIN
python/res/desc.gif
Normal file
|
After Width: | Height: | Size: 54 B |
BIN
python/res/icons/first.png
Normal file
|
After Width: | Height: | Size: 720 B |
BIN
python/res/icons/last.png
Normal file
|
After Width: | Height: | Size: 737 B |
BIN
python/res/icons/next.png
Normal file
|
After Width: | Height: | Size: 736 B |
BIN
python/res/icons/prev.png
Normal file
|
After Width: | Height: | Size: 745 B |
32
python/res/jquery-latest.js
vendored
Normal file
12
python/res/jquery.dimensions.min.js
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/* Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
|
||||
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
|
||||
*
|
||||
* $LastChangedDate: 2007-12-20 08:43:48 -0600 (Thu, 20 Dec 2007) $
|
||||
* $Rev: 4257 $
|
||||
*
|
||||
* Version: 1.2
|
||||
*
|
||||
* Requires: jQuery 1.2+
|
||||
*/
|
||||
(function($){$.dimensions={version:'1.2'};$.each(['Height','Width'],function(i,name){$.fn['inner'+name]=function(){if(!this[0])return;var torl=name=='Height'?'Top':'Left',borr=name=='Height'?'Bottom':'Right';return this.is(':visible')?this[0]['client'+name]:num(this,name.toLowerCase())+num(this,'padding'+torl)+num(this,'padding'+borr);};$.fn['outer'+name]=function(options){if(!this[0])return;var torl=name=='Height'?'Top':'Left',borr=name=='Height'?'Bottom':'Right';options=$.extend({margin:false},options||{});var val=this.is(':visible')?this[0]['offset'+name]:num(this,name.toLowerCase())+num(this,'border'+torl+'Width')+num(this,'border'+borr+'Width')+num(this,'padding'+torl)+num(this,'padding'+borr);return val+(options.margin?(num(this,'margin'+torl)+num(this,'margin'+borr)):0);};});$.each(['Left','Top'],function(i,name){$.fn['scroll'+name]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(name=='Left'?val:$(window)['scrollLeft'](),name=='Top'?val:$(window)['scrollTop']()):this['scroll'+name]=val;}):this[0]==window||this[0]==document?self[(name=='Left'?'pageXOffset':'pageYOffset')]||$.boxModel&&document.documentElement['scroll'+name]||document.body['scroll'+name]:this[0]['scroll'+name];};});$.fn.extend({position:function(){var left=0,top=0,elem=this[0],offset,parentOffset,offsetParent,results;if(elem){offsetParent=this.offsetParent();offset=this.offset();parentOffset=offsetParent.offset();offset.top-=num(elem,'marginTop');offset.left-=num(elem,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&$.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return $(offsetParent);}});function num(el,prop){return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0;};})(jQuery);
|
||||
122
python/res/jquery.metadata.js
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Metadata - jQuery plugin for parsing metadata from elements
|
||||
*
|
||||
* Copyright (c) 2006 John Resig, Yehuda Katz, J<EFBFBD>örn Zaefferer, Paul McLanahan
|
||||
*
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*
|
||||
* Revision: $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets the type of metadata to use. Metadata is encoded in JSON, and each property
|
||||
* in the JSON will become a property of the element itself.
|
||||
*
|
||||
* There are three supported types of metadata storage:
|
||||
*
|
||||
* attr: Inside an attribute. The name parameter indicates *which* attribute.
|
||||
*
|
||||
* class: Inside the class attribute, wrapped in curly braces: { }
|
||||
*
|
||||
* elem: Inside a child element (e.g. a script tag). The
|
||||
* name parameter indicates *which* element.
|
||||
*
|
||||
* The metadata for an element is loaded the first time the element is accessed via jQuery.
|
||||
*
|
||||
* As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
|
||||
* matched by expr, then redefine the metadata type and run another $(expr) for other elements.
|
||||
*
|
||||
* @name $.metadata.setType
|
||||
*
|
||||
* @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p>
|
||||
* @before $.metadata.setType("class")
|
||||
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
||||
* @desc Reads metadata from the class attribute
|
||||
*
|
||||
* @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p>
|
||||
* @before $.metadata.setType("attr", "data")
|
||||
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
||||
* @desc Reads metadata from a "data" attribute
|
||||
*
|
||||
* @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>
|
||||
* @before $.metadata.setType("elem", "script")
|
||||
* @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
|
||||
* @desc Reads metadata from a nested script element
|
||||
*
|
||||
* @param String type The encoding type
|
||||
* @param String name The name of the attribute to be used to get metadata (optional)
|
||||
* @cat Plugins/Metadata
|
||||
* @descr Sets the type of encoding to be used when loading metadata for the first time
|
||||
* @type undefined
|
||||
* @see metadata()
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
|
||||
$.extend({
|
||||
metadata : {
|
||||
defaults : {
|
||||
type: 'class',
|
||||
name: 'metadata',
|
||||
cre: /({.*})/,
|
||||
single: 'metadata'
|
||||
},
|
||||
setType: function( type, name ){
|
||||
this.defaults.type = type;
|
||||
this.defaults.name = name;
|
||||
},
|
||||
get: function( elem, opts ){
|
||||
var settings = $.extend({},this.defaults,opts);
|
||||
// check for empty string in single property
|
||||
if ( !settings.single.length ) settings.single = 'metadata';
|
||||
|
||||
var data = $.data(elem, settings.single);
|
||||
// returned cached data if it already exists
|
||||
if ( data ) return data;
|
||||
|
||||
data = "{}";
|
||||
|
||||
if ( settings.type == "class" ) {
|
||||
var m = settings.cre.exec( elem.className );
|
||||
if ( m )
|
||||
data = m[1];
|
||||
} else if ( settings.type == "elem" ) {
|
||||
if( !elem.getElementsByTagName )
|
||||
return undefined;
|
||||
var e = elem.getElementsByTagName(settings.name);
|
||||
if ( e.length )
|
||||
data = $.trim(e[0].innerHTML);
|
||||
} else if ( elem.getAttribute != undefined ) {
|
||||
var attr = elem.getAttribute( settings.name );
|
||||
if ( attr )
|
||||
data = attr;
|
||||
}
|
||||
|
||||
if ( data.indexOf( '{' ) <0 )
|
||||
data = "{" + data + "}";
|
||||
|
||||
data = eval("(" + data + ")");
|
||||
|
||||
$.data( elem, settings.single, data );
|
||||
return data;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns the metadata object for the first member of the jQuery object.
|
||||
*
|
||||
* @name metadata
|
||||
* @descr Returns element's metadata object
|
||||
* @param Object opts An object contianing settings to override the defaults
|
||||
* @type jQuery
|
||||
* @cat Plugins/Metadata
|
||||
*/
|
||||
$.fn.metadata = function( opts ){
|
||||
return $.metadata.get( this[0], opts );
|
||||
};
|
||||
|
||||
})(jQuery);
|
||||
2
python/res/jquery.tablesorter.min.js
vendored
Normal file
25
python/res/jquery.tablesorter.pager.css
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
div.tablesorterPager {
|
||||
padding: 10px 0 10px 0;
|
||||
background-color: #D6D2C2;
|
||||
text-align: center;
|
||||
}
|
||||
div.tablesorterPager span {
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
div.tablesorterPager input.prev {
|
||||
width: auto;
|
||||
margin-right: 10px;
|
||||
}
|
||||
div.tablesorterPager input.next {
|
||||
width: auto;
|
||||
margin-left: 10px;
|
||||
}
|
||||
div.tablesorterPager input {
|
||||
font-size: 8px;
|
||||
width: 50px;
|
||||
border: 1px solid #330000;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
184
python/res/jquery.tablesorter.pager.js
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
(function($) {
|
||||
$.extend({
|
||||
tablesorterPager: new function() {
|
||||
|
||||
function updatePageDisplay(c) {
|
||||
var s = $(c.cssPageDisplay,c.container).val((c.page+1) + c.seperator + c.totalPages);
|
||||
}
|
||||
|
||||
function setPageSize(table,size) {
|
||||
var c = table.config;
|
||||
c.size = size;
|
||||
c.totalPages = Math.ceil(c.totalRows / c.size);
|
||||
c.pagerPositionSet = false;
|
||||
moveToPage(table);
|
||||
fixPosition(table);
|
||||
}
|
||||
|
||||
function fixPosition(table) {
|
||||
var c = table.config;
|
||||
if(!c.pagerPositionSet && c.positionFixed) {
|
||||
var c = table.config, o = $(table);
|
||||
if(o.offset) {
|
||||
c.container.css({
|
||||
top: o.offset().top + o.height() + 'px',
|
||||
position: 'absolute'
|
||||
});
|
||||
}
|
||||
c.pagerPositionSet = true;
|
||||
}
|
||||
}
|
||||
|
||||
function moveToFirstPage(table) {
|
||||
var c = table.config;
|
||||
c.page = 0;
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
function moveToLastPage(table) {
|
||||
var c = table.config;
|
||||
c.page = (c.totalPages-1);
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
function moveToNextPage(table) {
|
||||
var c = table.config;
|
||||
c.page++;
|
||||
if(c.page >= (c.totalPages-1)) {
|
||||
c.page = (c.totalPages-1);
|
||||
}
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
function moveToPrevPage(table) {
|
||||
var c = table.config;
|
||||
c.page--;
|
||||
if(c.page <= 0) {
|
||||
c.page = 0;
|
||||
}
|
||||
moveToPage(table);
|
||||
}
|
||||
|
||||
|
||||
function moveToPage(table) {
|
||||
var c = table.config;
|
||||
if(c.page < 0 || c.page > (c.totalPages-1)) {
|
||||
c.page = 0;
|
||||
}
|
||||
|
||||
renderTable(table,c.rowsCopy);
|
||||
}
|
||||
|
||||
function renderTable(table,rows) {
|
||||
|
||||
var c = table.config;
|
||||
var l = rows.length;
|
||||
var s = (c.page * c.size);
|
||||
var e = (s + c.size);
|
||||
if(e > rows.length ) {
|
||||
e = rows.length;
|
||||
}
|
||||
|
||||
|
||||
var tableBody = $(table.tBodies[0]);
|
||||
|
||||
// clear the table body
|
||||
|
||||
$.tablesorter.clearTableBody(table);
|
||||
|
||||
for(var i = s; i < e; i++) {
|
||||
|
||||
//tableBody.append(rows[i]);
|
||||
|
||||
var o = rows[i];
|
||||
var l = o.length;
|
||||
for(var j=0; j < l; j++) {
|
||||
|
||||
tableBody[0].appendChild(o[j]);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fixPosition(table,tableBody);
|
||||
|
||||
$(table).trigger("applyWidgets");
|
||||
|
||||
if( c.page >= c.totalPages ) {
|
||||
moveToLastPage(table);
|
||||
}
|
||||
|
||||
updatePageDisplay(c);
|
||||
}
|
||||
|
||||
this.appender = function(table,rows) {
|
||||
|
||||
var c = table.config;
|
||||
|
||||
c.rowsCopy = rows;
|
||||
c.totalRows = rows.length;
|
||||
c.totalPages = Math.ceil(c.totalRows / c.size);
|
||||
|
||||
renderTable(table,rows);
|
||||
};
|
||||
|
||||
this.defaults = {
|
||||
size: 10,
|
||||
offset: 0,
|
||||
page: 0,
|
||||
totalRows: 0,
|
||||
totalPages: 0,
|
||||
container: null,
|
||||
cssNext: '.next',
|
||||
cssPrev: '.prev',
|
||||
cssFirst: '.first',
|
||||
cssLast: '.last',
|
||||
cssPageDisplay: '.pagedisplay',
|
||||
cssPageSize: '.pagesize',
|
||||
seperator: "/",
|
||||
positionFixed: true,
|
||||
appender: this.appender
|
||||
};
|
||||
|
||||
this.construct = function(settings) {
|
||||
|
||||
return this.each(function() {
|
||||
|
||||
config = $.extend(this.config, $.tablesorterPager.defaults, settings);
|
||||
|
||||
var table = this, pager = config.container;
|
||||
|
||||
$(this).trigger("appendCache");
|
||||
|
||||
config.size = parseInt($(".pagesize",pager).val());
|
||||
|
||||
$(config.cssFirst,pager).click(function() {
|
||||
moveToFirstPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssNext,pager).click(function() {
|
||||
moveToNextPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssPrev,pager).click(function() {
|
||||
moveToPrevPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssLast,pager).click(function() {
|
||||
moveToLastPage(table);
|
||||
return false;
|
||||
});
|
||||
$(config.cssPageSize,pager).change(function() {
|
||||
setPageSize(table,parseInt($(this).val()));
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
}
|
||||
});
|
||||
// extend plugin scope
|
||||
$.fn.extend({
|
||||
tablesorterPager: $.tablesorterPager.construct
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
39
python/res/style.css
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* tables */
|
||||
table.tablesorter {
|
||||
font-family:arial;
|
||||
background-color: #CDCDCD;
|
||||
margin:10px 0pt 15px;
|
||||
font-size: 8pt;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
table.tablesorter thead tr th, table.tablesorter tfoot tr th {
|
||||
background-color: #e6EEEE;
|
||||
border: 1px solid #FFF;
|
||||
font-size: 8pt;
|
||||
padding: 4px;
|
||||
}
|
||||
table.tablesorter thead tr .header {
|
||||
background-image: url(bg.gif);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center right;
|
||||
cursor: pointer;
|
||||
}
|
||||
table.tablesorter tbody td {
|
||||
color: #3D3D3D;
|
||||
padding: 4px;
|
||||
background-color: #FFF;
|
||||
vertical-align: top;
|
||||
}
|
||||
table.tablesorter tbody tr.odd td {
|
||||
background-color:#F0F0F6;
|
||||
}
|
||||
table.tablesorter thead tr .headerSortUp {
|
||||
background-image: url(asc.gif);
|
||||
}
|
||||
table.tablesorter thead tr .headerSortDown {
|
||||
background-image: url(desc.gif);
|
||||
}
|
||||
table.tablesorter thead tr .headerSortDown, table.tablesorter thead tr .headerSortUp {
|
||||
background-color: #8dbdd8;
|
||||
}
|
||||
157
python/server.py
|
|
@ -4,35 +4,104 @@ import ledger
|
|||
import cgi
|
||||
import sys
|
||||
import types
|
||||
import posixpath
|
||||
import urllib
|
||||
import shutil
|
||||
import os
|
||||
import re
|
||||
|
||||
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
||||
from os.path import exists, join, isfile
|
||||
|
||||
from Cheetah.Template import Template
|
||||
from Cheetah.Filters import WebSafe
|
||||
from Cheetah.Filters import Filter, WebSafe
|
||||
|
||||
class UnicodeFilter(WebSafe):
|
||||
webroot = join(os.getcwd(), 'python', 'res')
|
||||
|
||||
class UnicodeFilter(Filter):
|
||||
def filter(self, s, **kargs):
|
||||
return WebSafe.filter(self, s, str=unicode, **kargs)
|
||||
return Filter.filter(self, s, str=unicode, **kargs)
|
||||
|
||||
def strip(value):
|
||||
#return re.sub('\n', '<br />', value.strip_annotations().to_string())
|
||||
return value.strip_annotations().to_string()
|
||||
|
||||
templateDef = '''#encoding utf-8
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<title>$title</title>
|
||||
<link rel="stylesheet" href="/style.css" type="text/css" media="print, projection, screen" />
|
||||
<script type="text/javascript" src="/jquery-latest.js"></script>
|
||||
<script type="text/javascript" src="/jquery.tablesorter.min.js"></script>
|
||||
<script type="text/javascript" src="/jquery.tablesorter.pager.js"></script>
|
||||
<script type="text/javascript" src="/jquery.dimensions.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
\$(function() {
|
||||
\$("table")
|
||||
.tablesorter({textExtraction: 'complex',
|
||||
widthFixed: true,
|
||||
widgets: ['zebra']})
|
||||
.tablesorterPager({size: 100,
|
||||
container: \$("\#pager")});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
#for $xact in $journal
|
||||
#for $post in $xact
|
||||
<tr>
|
||||
<td>$post.date</td>
|
||||
<td>$post.xact.payee</td>
|
||||
<td>$post.account</td>
|
||||
<td>$post.amount</td>
|
||||
</tr>
|
||||
#end for
|
||||
#end for
|
||||
<div id="main">
|
||||
<h1>Register report</h1>
|
||||
<table id="register" cellspacing="1" class="tablesorter">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Payee</th>
|
||||
<th>Account</th>
|
||||
<th>Amount</th>
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Payee</th>
|
||||
<th>Account</th>
|
||||
<th>Amount</th>
|
||||
<th>Total</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
#for $xact in $journal
|
||||
#for $post in $xact
|
||||
#set $total = $total + $post.amount
|
||||
<tr>
|
||||
<!--<td>${$xact.date if $xact is not $last_xact else $empty}</td>
|
||||
<td>${$xact.payee if $xact is not $last_xact else $empty}</td>-->
|
||||
<td>$xact.date</td>
|
||||
<td>$xact.payee</td>
|
||||
<td>$post.account</td>
|
||||
<td>${strip($post.amount)}</td>
|
||||
<td>${strip($total)}</td>
|
||||
</tr>
|
||||
#set $last_xact = $xact
|
||||
#end for
|
||||
#end for
|
||||
</tbody>
|
||||
</table>
|
||||
<div id="pager" class="pager">
|
||||
<form>
|
||||
<img src="/icons/first.png" class="first"/>
|
||||
<img src="/icons/prev.png" class="prev"/>
|
||||
<input type="text" class="pagedisplay"/>
|
||||
<img src="/icons/next.png" class="next"/>
|
||||
<img src="/icons/last.png" class="last"/>
|
||||
<select class="pagesize">
|
||||
<option selected="selected" value="100">100</option>
|
||||
<option value="200">200</option>
|
||||
<option value="500">500</option>
|
||||
<option value="1000">1000</option>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
|
|
@ -43,14 +112,23 @@ class LedgerHandler(BaseHTTPRequestHandler):
|
|||
BaseHTTPRequestHandler.__init__(self, *args)
|
||||
|
||||
def do_GET(self):
|
||||
tmpl = Template(templateDef, filter=UnicodeFilter)
|
||||
path = self.translate_path(self.path)
|
||||
|
||||
tmpl.title = 'Ledger Journal'
|
||||
tmpl.journal = self.journal
|
||||
if path and exists(path) and isfile(path):
|
||||
self.copyfile(open(path), self.wfile)
|
||||
else:
|
||||
tmpl = Template(templateDef, filter=UnicodeFilter)
|
||||
|
||||
html = unicode(tmpl)
|
||||
html = html.encode('utf-8')
|
||||
self.wfile.write(html)
|
||||
tmpl.title = 'Ledger Journal'
|
||||
tmpl.journal = self.journal
|
||||
tmpl.total = ledger.Value(0)
|
||||
tmpl.strip = strip
|
||||
tmpl.last_xact = None
|
||||
tmpl.empty = ""
|
||||
|
||||
html = unicode(tmpl)
|
||||
html = html.encode('utf-8')
|
||||
self.wfile.write(html)
|
||||
|
||||
def do_POST(self):
|
||||
print "Saw a POST request!"
|
||||
|
|
@ -63,6 +141,45 @@ class LedgerHandler(BaseHTTPRequestHandler):
|
|||
except Exception:
|
||||
print "Saw exception in POST handler"
|
||||
|
||||
# This code is straight from SimpleHTTPServer.py
|
||||
def copyfile(self, source, outputfile):
|
||||
"""Copy all data between two file objects.
|
||||
|
||||
The SOURCE argument is a file object open for reading
|
||||
(or anything with a read() method) and the DESTINATION
|
||||
argument is a file object open for writing (or
|
||||
anything with a write() method).
|
||||
|
||||
The only reason for overriding this would be to change
|
||||
the block size or perhaps to replace newlines by CRLF
|
||||
-- note however that this the default server uses this
|
||||
to copy binary data as well.
|
||||
|
||||
"""
|
||||
shutil.copyfileobj(source, outputfile)
|
||||
|
||||
def translate_path(self, path):
|
||||
"""Translate a /-separated PATH to the local filename syntax.
|
||||
|
||||
Components that mean special things to the local file system
|
||||
(e.g. drive or directory names) are ignored. (XXX They should
|
||||
probably be diagnosed.)
|
||||
|
||||
"""
|
||||
# abandon query parameters
|
||||
path = path.split('?',1)[0]
|
||||
path = path.split('#',1)[0]
|
||||
path = posixpath.normpath(urllib.unquote(path))
|
||||
words = path.split('/')
|
||||
words = filter(None, words)
|
||||
path = webroot
|
||||
for word in words:
|
||||
drive, word = os.path.splitdrive(word)
|
||||
head, word = os.path.split(word)
|
||||
if word in (os.curdir, os.pardir): continue
|
||||
path = os.path.join(path, word)
|
||||
return path
|
||||
|
||||
def main(*args):
|
||||
try:
|
||||
port = 9000
|
||||
|
|
|
|||
|
|
@ -541,8 +541,8 @@ public:
|
|||
void print(std::ostream& out,
|
||||
const int first_width = -1,
|
||||
const int latter_width = -1,
|
||||
const bool right_justify = true,
|
||||
const bool colorize = true) const;
|
||||
const bool right_justify = false,
|
||||
const bool colorize = false) const;
|
||||
|
||||
/**
|
||||
* Debugging methods. There are two methods defined to help with
|
||||
|
|
|
|||
17
src/value.cc
|
|
@ -1114,18 +1114,18 @@ void value_t::in_place_cast(type_t cast_type)
|
|||
break;
|
||||
}
|
||||
|
||||
case BALANCE:
|
||||
case BALANCE: {
|
||||
const balance_t& bal(as_balance());
|
||||
switch (cast_type) {
|
||||
case AMOUNT: {
|
||||
const balance_t& temp(as_balance());
|
||||
if (temp.amounts.size() == 1) {
|
||||
if (bal.amounts.size() == 1) {
|
||||
// Because we are changing the current balance value to an amount
|
||||
// value, and because set_amount takes a reference (and that memory is
|
||||
// about to be repurposed), we must pass in a copy.
|
||||
set_amount(amount_t((*temp.amounts.begin()).second));
|
||||
set_amount(amount_t((*bal.amounts.begin()).second));
|
||||
return;
|
||||
}
|
||||
else if (temp.amounts.size() == 0) {
|
||||
else if (bal.amounts.size() == 0) {
|
||||
set_amount(0L);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1135,10 +1135,17 @@ void value_t::in_place_cast(type_t cast_type)
|
|||
}
|
||||
break;
|
||||
}
|
||||
case STRING:
|
||||
if (bal.is_empty())
|
||||
set_string("");
|
||||
else
|
||||
set_string(as_balance().to_string());
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case STRING:
|
||||
switch (cast_type) {
|
||||
|
|
|
|||