* Add fedoraGroupDesc (short description field)

* Include current LDIF files
 * Rename editAccount and editGroup to viewAccount and viewGroup * Separate account editing into different form
 * Setup base for editGroup implentation
 * Misc template fixes
 * Temporarily remove any javascript-dependent features for now
This commit is contained in:
Ricky Zhou 2007-08-08 23:28:41 -04:00
parent 5ad3479d52
commit 89fe26b8a2
44 changed files with 450 additions and 9149 deletions

View file

@ -4,8 +4,9 @@
# (such as template engine, encodings, etc.) all go in
# fas/config/app.cfg
mail.on = True
mail.server = 'bastion.fedora.phx.redhat.com'
base_url_filter.base_url = "http://192.168.2.101:8080"
#mail.server = 'bastion.fedora.phx.redhat.com'
#base_url_filter.base_url = "http://192.168.2.101:8080"
mail.server = 'localhost'
base_url_filter.use_x_forwarded_host = True
# DATABASE

View file

@ -21,7 +21,23 @@ class knownUser(validators.FancyValidator):
def validate_python(self, value, state):
p = Person.byUserName(value)
if p.cn:
raise validators.Invalid("'%s' already axists" % value, value, state)
raise validators.Invalid("'%s' already exists" % value, value, state)
class unknownUser(validators.FancyValidator):
def _to_python(self, value, state):
return value.strip()
def validate_python(self, value, state):
p = Person.byUserName(value)
if not p.cn:
raise validators.Invalid("'%s' does not exist" % value, value, state)
class unknownGroup(validators.FancyValidator):
def _to_python(self, value, state):
return value.strip()
def validate_python(self, value, state):
g = Groups.groups(groupName)
if not g:
raise validators.Invalid("'%s' does not exist" % value, value, state)
class newPerson(widgets.WidgetsList):
@ -32,14 +48,38 @@ class newPerson(widgets.WidgetsList):
telephoneNumber = widgets.TextField(label='Telephone Number', validator=validators.PhoneNumber(not_empty=True))
postalAddress = widgets.TextArea(label='Postal Address', validator=validators.NotEmpty)
newPersonForm = widgets.TableForm(fields=newPerson(), submit_text='Sign Up')
newPersonForm = widgets.ListForm(fields=newPerson(), submit_text='Sign Up')
class editPerson(widgets.WidgetsList):
# cn = widgets.TextField(label='Username', validator=validators.PlainText(not_empty=True, max=10))
userName = widgets.HiddenField(validator=validators.All(unknownUser(not_empty=True, max=10), validators.String(max=32, min=3)))
givenName = widgets.TextField(label='Full Name', validator=validators.String(not_empty=True, max=42))
mail = widgets.TextField(label='Email', validator=validators.Email(not_empty=True, strip=True))
fedoraPersonBugzillaMail = widgets.TextField(label='Bugzilla Email', validator=validators.Email(not_empty=True, strip=True))
fedoraPersonIrcNick = widgets.TextField(label='IRC Nick')
fedoraPersonKeyId = widgets.TextField(label='PGP Key')
telephoneNumber = widgets.TextField(label='Telephone Number', validator=validators.PhoneNumber(not_empty=True))
postalAddress = widgets.TextArea(label='Postal Address', validator=validators.NotEmpty)
description = widgets.TextArea(label='Description')
editPersonForm = widgets.ListForm(fields=editPerson(), submit_text='Update')
class editGroup(widgets.WidgetsList):
groupName = widgets.HiddenField(validator=validators.All(unknownGroup(not_empty=True, max=10), validators.String(max=32, min=3)))
fedoraGroupDesc = widgets.TextField(label='Description', validator=validators.NotEmpty)
fedoraGroupOwner = widgets.TextField(label='Group Owner', validator=validators.All(knownUser(not_empty=True, max=10), validators.String(max=32, min=3)))
fedoraGroupNeedsSponsor = widgets.CheckBox(label='Needs Sponsor')
fedoraGroupUserCanRemove = widgets.CheckBox(label='Self Removal')
fedoraGroupJoinMsg = widgets.TextField(label='Group Join Message')
editGroupForm = widgets.ListForm(fields=editPerson(), submit_text='Update')
class findUser(widgets.WidgetsList):
userName = widgets.AutoCompleteField(label='Username', search_controller='search', search_param='userName', result_name='people')
action = widgets.HiddenField(label='action', default='apply', validator=validators.String(not_empty=True))
groupName = widgets.HiddenField(label='groupName', validator=validators.String(not_empty=True))
searchUserForm = widgets.TableForm(fields=findUser(), submit_text='Invite')
searchUserForm = widgets.ListForm(fields=findUser(), submit_text='Invite')
class Root(controllers.RootController):
@ -75,6 +115,7 @@ class Root(controllers.RootController):
if not identity.current.anonymous \
and identity.was_login_attempted() \
and not identity.get_identity_errors():
turbogears.flash('Welcome, %s' % Person.byUserName(turbogears.identity.current.user_name).givenName)
raise redirect(forward_url)
forward_url=None
@ -98,35 +139,67 @@ class Root(controllers.RootController):
@expose()
def logout(self):
identity.current.logout()
turbogears.flash('You have successfully logged out.')
raise redirect("/")
@expose(template="fas.templates.viewAccount")
@identity.require(identity.not_anonymous())
def viewAccount(self,userName=None, action=None):
if not userName:
userName = turbogears.identity.current.user_name
if turbogears.identity.current.user_name == userName:
personal = True
else:
personal = False
try:
Groups.byUserName(turbogears.identity.current.user_name)['accounts'].cn
admin = True
except KeyError:
admin = False
user = Person.byUserName(userName)
groups = Groups.byUserName(userName)
groupsPending = Groups.byUserName(userName, unapprovedOnly=True)
groupdata={}
for g in groups:
groupdata[g] = Groups.groups(g)[g]
for g in groupsPending:
groupdata[g] = Groups.groups(g)[g]
try:
groups['cla_done']
claDone=True
except KeyError:
claDone=None
return dict(user=user, groups=groups, groupsPending=groupsPending, action=action, groupdata=groupdata, claDone=claDone, personal=personal, admin=admin)
@expose(template="fas.templates.editAccount")
@identity.require(identity.not_anonymous())
def editAccount(self,userName=None, action=None):
def editAccount(self, userName=None, action=None):
if userName:
try:
Groups.byUserName(turbogears.identity.current.user_name)['accounts'].cn
if not userName:
userName = turbogears.identity.current.user_name
except KeyError:
turbogears.flash('You cannot view %s' % userName )
turbogears.flash('You cannot edit %s' % userName )
userName = turbogears.identity.current.user_name
else:
userName = turbogears.identity.current.user_name
user = Person.byUserName(userName)
groups = Groups.byUserName(userName)
groupsPending = Groups.byUserName(userName, unapprovedOnly=True)
try:
groups['cla_done']
claDone=True
except KeyError:
claDone=None
return dict(user=user, groups=groups, groupsPending=groupsPending, action=action, claDone=claDone)
value = {'userName' : userName,
'givenName' : user.givenName,
'mail' : user.mail,
'fedoraPersonBugzillaMail' : user.fedoraPersonBugzillaMail,
'fedoraPersonIrcNick' : user.fedoraPersonIrcNick,
'fedoraPersonKeyId' : user.fedoraPersonKeyId,
'telephoneNumber' : user.telephoneNumber,
'postalAddress' : user.postalAddress,
'description' : user.description, }
return dict(form=editPersonForm, value=value)
@expose(template="fas.templates.editGroup")
@expose(template="fas.templates.viewGroup")
@exception_handler(errorMessage,rules="isinstance(tg_exceptions,ValueError)")
@identity.require(identity.not_anonymous())
def editGroup(self, groupName):
def viewGroup(self, groupName):
try:
groups = Groups.byGroupName(groupName, includeUnapproved=True)
except KeyError, e:
@ -152,6 +225,32 @@ class Root(controllers.RootController):
value = {'groupName' : group.cn}
return dict(groups=groups, group=group, me=me, searchUserForm=searchUserForm, value=value)
@expose(template="fas.templates.editGroup")
@identity.require(identity.not_anonymous())
def editGroup(self, groupName, action=None):
pass
userName = turbogears.identity.current.user_name
try:
Groups.byUserName(userName)['accounts'].cn
except KeyError:
try:
Groups.byUserName(userName)[groupName]
if Groups.byUserName(userName)[groupName].fedoraRoleType.lower() != 'administrator':
raise KeyError
except KeyError:
turbogears.flash('You cannot edit %s' % groupName)
turbogears.redirect('viewGroup?groupName=%s' % groupName)
group = Groups.groups(groupName)[groupName]
#value = {'givenName' : user.givenName,
# 'mail' : user.mail,
# 'fedoraPersonBugzillaMail' : user.fedoraPersonBugzillaMail,
# 'fedoraPersonIrcNick' : user.fedoraPersonIrcNick,
# 'fedoraPersonKeyId' : user.fedoraPersonKeyId,
# 'telephoneNumber' : user.telephoneNumber,
# 'postalAddress' : user.postalAddress,
# 'description' : user.description, }
return dict(form=editGroupForm, value=value)
@expose(template="fas.templates.groupList")
@exception_handler(errorMessage,rules="isinstance(tg_exceptions,ValueError)")
@identity.require(identity.not_anonymous())
@ -208,7 +307,7 @@ class Root(controllers.RootController):
if turbogears.identity.current.user_name:
turbogears.flash("Password Changed")
turbogears.redirect("editAccount")
turbogears.redirect("viewAccount")
else:
turbogears.flash('Your password has been emailed to you')
return dict()
@ -223,34 +322,18 @@ class Root(controllers.RootController):
except:
turbogears.flash("No users found matching '%s'" % search)
users = []
return dict(printList=users, search=search)
cla_done = Groups.byGroupName('cla_done')
claDone = {}
for u in users:
try:
cla_done[u]
claDone[u] = True
except KeyError:
claDone[u] = False
return dict(users=users, claDone=claDone, search=search)
listUsers = listUser
@expose(template='fas.templates.edit')
@exception_handler(errorMessage,rules="isinstance(tg_exceptions,ValueError)")
@identity.require(identity.not_anonymous())
def editUserAttribute(self, attribute, value, userName=None):
try:
Groups.byUserName(turbogears.identity.current.user_name)['accounts'].cn
if not userName:
userName = turbogears.identity.current.user_name
except KeyError:
turbogears.flash('You cannot view %s' % userName )
userName = turbogears.identity.current.user_name
attribute = attribute.encode('utf8')
value = value.encode('utf8')
if attribute and value:
p = Person.byUserName(userName)
p.__setattr__(attribute, value)
turbogears.flash("'%s' Updated to %s" % (attribute, value))
if userName == turbogears.identity.current.user_name:
turbogears.redirect('editAccount')
else:
turbogears.redirect('editAccount?userName=%s' % userName)
return dict(userName=userName, attribute=attribute, value=value)
# @expose(template='fas.templates.apply')
# @exception_handler(errorMessage, rules="isinstance(tg_exceptions,ValueError)")
# @identity.require(identity.not_anonymous())
@ -258,9 +341,9 @@ class Root(controllers.RootController):
# # This doesn't work
# turbogears.identity.current.user_name=userName
# turbogears.flash('Sudoed to %s' % userName)
# turbogears.recirect('editAccount')
# turbogears.recirect('viewAccount')
# @error_handler(editGroup)
# @error_handler(viewGroup)
# @validate(form=newPersonForm)
@expose(template='fas.templates.apply')
@identity.require(identity.not_anonymous())
@ -276,14 +359,14 @@ class Root(controllers.RootController):
group = Groups.groups(groupName)[groupName]
except KeyError, e:
turbogears.flash('Group Error: %s does not exist - %s' % (groupName, e))
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
try:
p = Person.byUserName(userName)
if not p.cn:
raise KeyError, 'User %s, just not there' % userName
except KeyError, e:
turbogears.flash('User Error: %s does not exist - %s' % (userName, e))
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
g = Groups.byGroupName(groupName, includeUnapproved=True)
@ -293,14 +376,14 @@ class Root(controllers.RootController):
Groups.apply(groupName, userName)
except ldap.ALREADY_EXISTS:
turbogears.flash('%s Already in group!' % p.cn)
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
else:
turbogears.flash('%s Applied!' % p.cn)
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
# Some error checking for the sponsors
if g[userName].fedoraRoleType.lower() == 'administrator' and g[sponsor].fedoraRoleType.lower() == 'sponsor':
raise ValueError, 'Sponsors cannot alter administrators. End of story'
raise ValueError, 'Sponsors cannot alter administrators. End of story.'
try:
userGroup = Groups.byGroupName(groupName)[userName]
@ -315,10 +398,10 @@ class Root(controllers.RootController):
Groups.remove(group.cn, p.cn)
except TypeError:
turbogears.flash('%s could not be removed from %s!' % (p.cn, group.cn))
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
else:
turbogears.flash('%s removed from %s!' % (p.cn, group.cn))
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
return dict()
# Upgrade user in a group
@ -329,9 +412,9 @@ class Root(controllers.RootController):
p.upgrade(groupName)
except TypeError, e:
turbogears.flash('Cannot upgrade %s - %s!' % (p.cn, e))
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
turbogears.flash('%s Upgraded!' % p.cn)
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
# Downgrade user in a group
@ -342,18 +425,18 @@ class Root(controllers.RootController):
p.downgrade(groupName)
except TypeError, e:
turbogears.flash('Cannot downgrade %s - %s!' % (p.cn, e))
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
turbogears.flash('%s Downgraded!' % p.cn)
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
# Sponsor / Approve User
elif action == 'sponsor' or action == 'apply':
p.sponsor(groupName, sponsor)
turbogears.flash('%s has been sponsored!' % p.cn)
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
turbogears.flash('Invalid action: %s' % action)
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
return dict()
@expose(template='fas.templates.inviteMember')
@ -380,27 +463,27 @@ class Root(controllers.RootController):
turbogears.flash('Application sent for %s' % user.cn)
except ldap.ALREADY_EXISTS, e:
turbogears.flash('Application Denied: %s' % e[0]['desc'])
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
if action == 'Remove' and group.fedoraGroupUserCanRemove == 'TRUE':
try:
Groups.remove(group.cn, user.cn)
except TypeError:
turbogears.flash('%s could not be removed from %s!' % (user.cn, group.cn))
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
else:
turbogears.flash('%s removed from %s!' % (user.cn, group.cn))
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
else:
turbogears.flash('%s does not allow self removal' % group.cn)
turbogears.redirect('editGroup?groupName=%s' % group.cn)
turbogears.redirect('viewGroup?groupName=%s' % group.cn)
return dict()
@expose(template='fas.templates.signUp')
def signUp(self):
if turbogears.identity.not_anonymous():
turbogears.flash('No need to sign up, You have an account!')
turbogears.redirect('editAccount')
turbogears.redirect('viewAccount')
return dict(form=newPersonForm)
@validate(form=newPersonForm)
@ -424,38 +507,41 @@ class Root(controllers.RootController):
turbogears.redirect('signUp')
return dict()
@validate(form=editPersonForm)
@error_handler(editAccount)
@expose(template='fas.templates.editAccount')
def editAccountSubmit(self, givenName, mail, fedoraPersonBugzillaMail, telephoneNumber, postalAddress, userName=None, fedoraPersonIrcNick='', fedoraPersonKeyId='', description=''):
if userName:
try:
Groups.byUserName(turbogears.identity.current.user_name)['accounts'].cn
if not userName:
userName = turbogears.identity.current.user_name
except KeyError:
turbogears.flash('You cannot view %s' % userName)
userName = turbogears.identity.current.user_name
turbogears.redirect("editAccount")
return dict()
else:
userName = turbogears.identity.current.user_name
user = Person.byUserName(userName)
user.__setattr__('givenName', givenName.encode('utf8'))
user.__setattr__('mail', mail.encode('utf8'))
user.__setattr__('fedoraPersonBugzillaMail', fedoraPersonBugzillaMail.encode('utf8'))
user.__setattr__('fedoraPersonIrcNick', fedoraPersonIrcNick.encode('utf8'))
user.__setattr__('fedoraPersonKeyId', fedoraPersonKeyId.encode('utf8'))
user.__setattr__('telephoneNumber', telephoneNumber.encode('utf8'))
user.__setattr__('postalAddress', postalAddress.encode('utf8'))
user.__setattr__('description', description.encode('utf8'))
turbogears.flash('Your account has been updated.')
turbogears.redirect("viewAccount?userName=%s" % userName)
return dict()
@expose(format="json")
def search(self, userName=None, groupName=None):
people = Person.users('%s*' % userName)
return dict(people=
filter(lambda item: userName in item.lower(), people))
@expose(format="json")
def help(self, helpID='Unknown'):
messages = {
'Unknown' : ''' Unknown: If you know what help should be here, please email accounts@fedoraproject.org and tell them.''',
'postalAddress' : ''' Postal Address: Your local mailing address. It could be a work address or a home address.''',
'cn' : ''' Account Name: A unique identifier for each user. This is your 'username' for many parts of fedora. This will also be your @fedoraproject.org email alias.''',
'givenName' : ''' Real Name: This is your full name, often Firstname Lastname.''',
'mail' : ''' Email Address: This is your primary email address. Notifications, aliases, password resets all get sent to this address. Other email addresses can be added (like bugzilla address)''',
'fedoraPersonBugzillaMail' : ''' Bugzilla Email: For most this is the same address as as their primary email address.''',
'fedoraPersonIrcNick' : ''' IRC Nick: Many fedora developers can be found on freenode.net. Make sure your nick is registered so no one else takes it. After you have registered, let the rest of fedora know what your nick is.''',
'fedoraPersonKeyId' : ''' PGP Key: PGP key's are required to verify your identity to others and to encrypt messages. It is required in order to sign the CLA and, as such, is required to be a contributor. In order to create and upload your key please see our howto at: <a href='http://fedoraproject.org/wiki/DocsProject/UsingGpg/CreatingKeys'>http://fedoraproject.org/wiki/DocsProject/UsingGpg/CreatingKeys</a> ''',
'telephoneNumber' : ''' Telephone Number: Please include a country code if outside of the united states. ''',
'description' : ''' Description: Just a brief comment on yourself. Could include your website or blog. ''',
'password' : ''' Password: Used to access fedora resources. Resources that don't require your password may require ssh keys ''',
'accountStatus' : ''' Account Status: Some accounts may be disabled because of misconduct or password expiration. If your account is not active and you are not sure why, please contact <a href='mailto:accounts@fedoraproject.org>accounts@fedoraproject.org</a> or join #fedora-admin on <a href='http://irc.freenode.net/'>irc.freenode.net</a> ''',
'cla' : ''' Contributor License Agreement: This agreement is required in order to be a Fedora contributor. The CLA can be found at: <a href='http://fedoraproject.org/wiki/Legal/Licenses/CLA'>http://fedoraproject.org/wiki/Legal/Licenses/CLA</a> ''',
'inviteToGroup' : ''' This will add a user to the following group. They will initially be unapproved, just as if they had applied themselves. An email notification will be sent. '''
}
try:
messages[helpID]
except KeyError:
helpID='Unknown'
return dict(help=messages[helpID])
#filter(lambda item: userName in item.lower(), people))
@expose(template='fas.templates.invite')
@exception_handler(errorMessage,rules="isinstance(tg_exceptions,ValueError)")

View file

@ -20,8 +20,9 @@ class Group:
__filter = ''
__cn = ''
def __init__(self, cn, fedoraGroupOwner, fedoraGroupType, fedoraGroupNeedsSponsor, fedoraGroupUserCanRemove, fedoraGroupJoinMsg):
def __init__(self, cn, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupType, fedoraGroupNeedsSponsor, fedoraGroupUserCanRemove, fedoraGroupJoinMsg):
self.cn = cn
self.fedoraGroupDesc = fedoraGroupDesc
self.fedoraGroupOwner = fedoraGroupOwner
self.fedoraGroupType = fedoraGroupType
self.fedoraGroupNeedsSponsor = fedoraGroupNeedsSponsor
@ -59,10 +60,11 @@ class Group:
# modify(base, attr, value, self.__getattr__(attr))
@classmethod
def newGroup(self, cn, fedoraGroupOwner, fedoraGroupNeedsSponsor, fedoraGroupUserCanRemove, fedoraGroupJoinMsg):
def newGroup(self, cn, fedoraGroupDesc, fedoraGroupOwner, fedoraGroupNeedsSponsor, fedoraGroupUserCanRemove, fedoraGroupJoinMsg):
''' Create a new group '''
attributes = { 'cn' : cn,
'objectClass' : ('fedoraGroup'),
'fedoraGroupDesc' : fedoraGroupDesc,
'fedoraGroupOwner' : fedoraGroupOwner,
'fedoraGroupType' : '1',
'fedoraGroupNeedsSponsor' : fedoraGroupNeedsSponsor,
@ -151,6 +153,7 @@ class Groups:
print group
groups[name] = Group(
cn = group[0][1]['cn'][0],
fedoraGroupDesc = group[0][1]['fedoraGroupDesc'][0],
fedoraGroupOwner = group[0][1]['fedoraGroupOwner'][0],
fedoraGroupType = group[0][1]['fedoraGroupType'][0],
fedoraGroupNeedsSponsor = group[0][1]['fedoraGroupNeedsSponsor'][0],
@ -452,7 +455,7 @@ def delete(base, ldapServer=None):
s = Server()
ldapServer = s.ldapConn
ldapServer.simple_bind_s('cn=directory manager', 'test')
ldapServer.simple_bind_s('cn=directory manager', 'fedoraproject')
print "Deleteing %s " % base
ldapServer.delete_s(base)
@ -463,7 +466,7 @@ def add(base, attributes, ldapServer=None):
ldapServer = s.ldapConn
attributes=[ (k,v) for k,v in attributes.items() ]
ldapServer.simple_bind_s('cn=directory manager', 'test')
ldapServer.simple_bind_s('cn=directory manager', 'fedoraproject')
ldapServer.add_s(base, attributes)
def modify(base, attribute, new, old=None, ldapServer=None):
@ -476,7 +479,7 @@ def modify(base, attribute, new, old=None, ldapServer=None):
ldapServer = s.ldapConn
from ldap import modlist
ldapServer.simple_bind_s('cn=directory manager', 'test')
ldapServer.simple_bind_s('cn=directory manager', 'fedoraproject')
if old == None:
old = 'None'
@ -500,7 +503,7 @@ def search(base, filter, attributes=None, ldapServer=None):
scope = ldap.SCOPE_SUBTREE
count = 0
timeout = 2
ldapServer.simple_bind_s('cn=directory manager', 'test')
ldapServer.simple_bind_s('cn=directory manager', 'fedoraproject')
result_set = []
try:
result_id = ldapServer.search(base, scope, filter, attributes)

View file

@ -3,7 +3,7 @@ from xml.dom import minidom
class Koji:
def __init__(self, userName, url='http://publictest8/koji/recentbuilds?user='):
def __init__(self, userName, url='http://publictest8.fedora.redhat.com/koji/recentbuilds?user='):
buildFeed = minidom.parse(urllib.urlopen(url + userName))
try:
self.userLink = buildFeed.getElementsByTagName('link')[0].childNodes[0].data

View file

@ -1,28 +0,0 @@
h1 {
font-size: 2em;
color: #4B4545;
text-align: center;
}
.draggable
{
color: white;
cursor: move;
font-size: 20px;
// height: 100px;
// line-height: 100px;
position: absolute;
text-align: center;
top: 200px;
width: 100px;
}
.blue { background: blue; }
.green { background: green; }
.red { background: red; }
.white
{
background: white;
border: 1px solid black;
color: black;
}

View file

@ -1,354 +0,0 @@
*
{
margin: 0;
padding: 0;
}
body
{
font-size: 76%;
}
a
{
text-decoration: none;
}
#wrapper
{
font: normal 2ex/1.5 sans-serif;
}
#head
{
overflow: hidden;
margin-top: 35px;
height: 70px;
line-height: 70px;
background: url(images/head.png) 0 0 repeat-x;
}
#head h1
{
width: 250px;
float: left;
text-indent: -9999px;
overflow: hidden;
background: url(images/logo.png) 1ex 50% no-repeat;
}
#searchbox
{
width: 36ex;
float: right;
text-align: right;
margin-right: 2ex;
}
#searchbox label
{
display: none;
}
#searchbox input
{
display: inline;
border: 1px solid #CCCCCC;
}
#searchbox #q
{
width: 20ex;
}
#topnav
{
height: 30px;
line-height: 30px;
background: url(images/topnav.png) 0 0 repeat-x;
font-size: 1.6ex;
}
#topnav ul
{
list-style: none;
text-align: center;
}
#topnav ul li
{
display: inline;
background: url(images/topnav-separator.png) 0 50% no-repeat;
padding-left: 3px;
}
#topnav ul li.first
{
background: none;
}
#topnav a
{
color: #445566;
margin: 0 2ex;
}
#topnav a:hover
{
color: #000000;
}
#infobar
{
position: absolute;
top: 0;
left: 0;
right: 0;
height: 35px;
line-height: 35px;
background: url(images/infobar.png) 0 0 repeat-x;
font-size: 1.6ex;
}
#authstatus
{
width: 40ex;
float: left;
color: #FFFFFF;
padding-left: 1.5ex;
}
#authstatus strong
{
color: #DED6A1;
}
#control
{
width: 40ex;
float: right;
margin-right: 1ex;
}
#control ul
{
list-style: none;
text-align: right;
}
#control ul li
{
display: inline;
background: url(images/control-separator.png) 0 50% no-repeat;
}
#control a
{
color: #DED6A1;
margin: 0 1.5ex;
}
#main
{
background: url(images/shadow.png) 0 0 repeat-x;
}
#sidebar
{
width: 22ex;
float: left;
background: #335F9D url(images/sidebar.png) 0 0 repeat-x;
border: 1px solid #112233;
}
#sidebar ul
{
list-style: none;
}
#sidebar li
{
border-top: 1px solid #CCCCCC;
}
#sidebar li.first
{
border-top: none;
}
#sidebar a
{
display: block;
text-align: center;
color: #FFFFFF;
padding: 0.5ex 0;
}
#sidebar a:hover
{
background: #082C59;
}
#content
{
margin-left: 22ex;
padding: 2ex 4ex;
}
#content h2
{
/* header icon */
}
#content a
{
color: #0C6ED0;
}
.userbox
{
}
.userbox dt
{
width: 23ex;
float: left;
text-align: right;
}
.userbox dd
{
margin-left: 25ex;
}
.account
{
padding-left: 30px;
background: url(images/account.png) 0 68% no-repeat;
}
.approved
{
padding-left: 20px;
background: url(images/approved.png) 0 68% no-repeat;
}
.unapproved
{
padding-left: 20px;
background: url(images/unapproved.png) 0 68% no-repeat;
}
.attn
{
padding-left: 20px;
background: url(images/attn.png) 0 68% no-repeat;
}
.roleslist
{
list-style: none;
}
.roleslist li
{
margin-left: 0.5ex;
}
.actions
{
margin-top: 1.5ex;
list-style: none;
}
.actions li
{
display: inline;
}
#rolespanel
{
list-style: none;
}
#rolespanel li.role
{
border-top: 2px solid #EEEEEE;
margin-top: 1ex;
padding-top: 1ex;
padding-left: 22px;
background: url(images/arrow.png) 0 1.6ex no-repeat;
}
#rolespanel h4
{
display: inline;
}
#rolespanel dt
{
width: 10ex;
float: left;
text-align: right;
margin-bottom: 1ex;
}
#rolespanel dd
{
margin-left: 12ex;
margin-bottom: 1ex;
}
#rolespanel .tools, #rolespanel .queue
{
list-style: none;
}
#rolespanel .tools li
{
padding-left: 22px;
background: url(images/tools.png) 0 50% no-repeat;
}
#rolespanel .queue li
{
padding-left: 22px;
background: url(images/queue.png) 0 50% no-repeat;
}
#footer
{
font-size: 1.6ex;
clear: both;
text-align: center;
padding: 15px 0 2.5ex;
background: url(images/footer-top.png) 0 0 repeat-x;
}
#footlinks
{
padding-top: 3px;
padding-bottom: 18px;
background: #EEEEEE url(images/footer-bottom.png) 0 100% repeat-x;
list-style: none;
}
#footlinks li
{
display: inline;
border-left: 1px solid #CCCCCC;
padding-left: 1px;
}
#footlinks li.first
{
padding-left: 0;
border-left: none;
}
#footlinks a
{
margin: 0 2ex;
color: #3465A4;
}

View file

@ -1,66 +0,0 @@
h1 {
font-size: 2em;
color: #4B4545;
text-align: center;
}
table.datagrid {
/* width: 100%; */
border-collapse: collapse;
}
table.datagrid thead th {
text-align: left;
background-color: #4B4545;
background-repeat: no-repeat;
background-position: right center;
color: white;
font-weight: bold;
padding: .3em .7em;
font-size: .9em;
padding-right: 5px;
background-repeat: no-repeat;
background-position: 95% right;
}
table.datagrid thead th a {
color: white;
text-decoration: none;
font-size: 1.0em;
background-repeat: no-repeat;
background-position: center right;
padding-right: 15px;
}
table.datagrid thead th.over {
background-color: #746B6B;
cursor: pointer;
}
table.datagrid tbody th {
font-weight: bold;
}
table.datagrid tbody td, table.datagrid tbody th {
text-align: left;
padding: .3em .7em;
border-bottom: 1px solid #eee;
}
table.datagrid tbody tr.alternate td, table.datagrid tbody tr.alternate th {
background-color: #f1f1f1;
}
table.datagrid tfoot td, table.datagrid tfoot th {
background-color: #FFFEE3;
color: #4B4545;
padding: .5em;
font-weight: bold;
border-top: 2px solid #4B4545;
}
table.datagrid tfoot th { text-align: left; }
table.datagrid tfoot td { }
.invisible { display: none; }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -325,6 +325,11 @@ a
background: url(/fas/static/images/footer-top.png) 0 0 repeat-x;
}
#footer .copy, #footer .disclaimer
{
font-size: 1.5ex;
}
#footlinks
{
padding-top: 3px;
@ -360,17 +365,6 @@ a
margin: 1ex 0;
}
.flash
{
float: left;
background: #DEE6B1 url(/fas/static/images/success.png) 10px 50% no-repeat;
height: 50px;
line-height: 50px;
border: 1px solid #998877;
padding: 0 15px 0 43px;
margin-top: 9px;
}
.help
{
background: #DEE6B1 url(/fas/static/images/help.png) 10px 50% no-repeat;
@ -379,3 +373,56 @@ a
margin: 1ex 0;
}
.letters
{
list-style: none;
}
.letters li
{
display: inline;
margin-right: 1ex;
}
#content table
{
border-collapse: collapse;
}
#content table th, #content table td
{
padding: 0 2ex;
}
pre
{
font-size: 3ex;
}
form ul
{
list-style: none;
}
form li
{
margin: 0 0 1ex;
text-align: left;
overflow: auto;
}
form li label
{
float: left;
clear: left;
width: 16ex;
text-align: right;
margin: 0;
padding: 0 2ex 0 0;
}
form li input, form li textarea
{
margin: 0;
}

View file

@ -1,774 +0,0 @@
/***
MochiKit.DragAndDrop 1.4
See <http://mochikit.com/> for documentation, downloads, license, etc.
Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
Mochi-ized By Thomas Herve (_firstname_@nimail.org)
***/
if (typeof(dojo) != 'undefined') {
dojo.provide('MochiKit.DragAndDrop');
dojo.require('MochiKit.Base');
dojo.require('MochiKit.DOM');
dojo.require('MochiKit.Iter');
dojo.require('MochiKit.Visual');
dojo.require('MochiKit.Signal');
}
if (typeof(JSAN) != 'undefined') {
JSAN.use("MochiKit.Base", []);
JSAN.use("MochiKit.DOM", []);
JSAN.use("MochiKit.Visual", []);
JSAN.use("MochiKit.Iter", []);
JSAN.use("MochiKit.Signal", []);
}
try {
if (typeof(MochiKit.Base) == 'undefined' ||
typeof(MochiKit.DOM) == 'undefined' ||
typeof(MochiKit.Visual) == 'undefined' ||
typeof(MochiKit.Signal) == 'undefined' ||
typeof(MochiKit.Iter) == 'undefined') {
throw "";
}
} catch (e) {
throw "MochiKit.DragAndDrop depends on MochiKit.Base, MochiKit.DOM, MochiKit.Visual, MochiKit.Signal and MochiKit.Iter!";
}
if (typeof(MochiKit.DragAndDrop) == 'undefined') {
MochiKit.DragAndDrop = {};
}
MochiKit.DragAndDrop.NAME = 'MochiKit.DragAndDrop';
MochiKit.DragAndDrop.VERSION = '1.4';
MochiKit.DragAndDrop.__repr__ = function () {
return '[' + this.NAME + ' ' + this.VERSION + ']';
};
MochiKit.DragAndDrop.toString = function () {
return this.__repr__();
};
MochiKit.DragAndDrop.EXPORT = [
"Droppable",
"Draggable"
];
MochiKit.DragAndDrop.EXPORT_OK = [
"Droppables",
"Draggables"
];
MochiKit.DragAndDrop.Droppables = {
/***
Manage all droppables. Shouldn't be used, use the Droppable object instead.
***/
drops: [],
remove: function (element) {
this.drops = MochiKit.Base.filter(function (d) {
return d.element != MochiKit.DOM.getElement(element)
}, this.drops);
},
register: function (drop) {
this.drops.push(drop);
},
unregister: function (drop) {
this.drops = MochiKit.Base.filter(function (d) {
return d != drop;
}, this.drops);
},
prepare: function (element) {
MochiKit.Base.map(function (drop) {
if (drop.isAccepted(element)) {
if (drop.options.activeclass) {
MochiKit.DOM.addElementClass(drop.element,
drop.options.activeclass);
}
drop.options.onactive(drop.element, element);
}
}, this.drops);
},
findDeepestChild: function (drops) {
deepest = drops[0];
for (i = 1; i < drops.length; ++i) {
if (MochiKit.DOM.isParent(drops[i].element, deepest.element)) {
deepest = drops[i];
}
}
return deepest;
},
show: function (point, element) {
if (!this.drops.length) {
return;
}
var affected = [];
if (this.last_active) {
this.last_active.deactivate();
}
MochiKit.Iter.forEach(this.drops, function (drop) {
if (drop.isAffected(point, element)) {
affected.push(drop);
}
});
if (affected.length > 0) {
drop = this.findDeepestChild(affected);
MochiKit.Position.within(drop.element, point.page.x, point.page.y);
drop.options.onhover(element, drop.element,
MochiKit.Position.overlap(drop.options.overlap, drop.element));
drop.activate();
}
},
fire: function (event, element) {
if (!this.last_active) {
return;
}
MochiKit.Position.prepare();
if (this.last_active.isAffected(event.mouse(), element)) {
this.last_active.options.ondrop(element,
this.last_active.element, event);
}
},
reset: function (element) {
MochiKit.Base.map(function (drop) {
if (drop.options.activeclass) {
MochiKit.DOM.removeElementClass(drop.element,
drop.options.activeclass);
}
drop.options.ondesactive(drop.element, element);
}, this.drops);
if (this.last_active) {
this.last_active.deactivate();
}
}
};
MochiKit.DragAndDrop.Droppable = function (element, options) {
this.__init__(element, options);
};
MochiKit.DragAndDrop.Droppable.prototype = {
/***
A droppable object. Simple use is to create giving an element:
new MochiKit.DragAndDrop.Droppable('myelement');
Generally you'll want to define the 'ondrop' function and maybe the
'accept' option to filter draggables.
***/
__class__: MochiKit.DragAndDrop.Droppable,
__init__: function (element, /* optional */options) {
var d = MochiKit.DOM;
var b = MochiKit.Base;
this.element = d.getElement(element);
this.options = b.update({
greedy: true,
hoverclass: null,
activeclass: null,
hoverfunc: b.noop,
accept: null,
onactive: b.noop,
ondesactive: b.noop,
onhover: b.noop,
ondrop: b.noop,
containment: [],
tree: false
}, options || {});
// cache containers
this.options._containers = [];
b.map(MochiKit.Base.bind(function (c) {
this.options._containers.push(d.getElement(c));
}, this), this.options.containment);
d.makePositioned(this.element); // fix IE
MochiKit.DragAndDrop.Droppables.register(this);
},
isContained: function (element) {
if (this._containers) {
var containmentNode;
if (this.options.tree) {
containmentNode = element.treeNode;
} else {
containmentNode = element.parentNode;
}
return MochiKit.Iter.some(this._containers, function (c) {
return containmentNode == c;
});
} else {
return true;
}
},
isAccepted: function (element) {
return ((!this.options.accept) || MochiKit.Iter.some(
this.options.accept, function (c) {
return MochiKit.DOM.hasElementClass(element, c);
}));
},
isAffected: function (point, element) {
return ((this.element != element) &&
this.isContained(element) &&
this.isAccepted(element) &&
MochiKit.Position.within(this.element, point.page.x,
point.page.y));
},
deactivate: function () {
/***
A droppable is deactivate when a draggable has been over it and left.
***/
if (this.options.hoverclass) {
MochiKit.DOM.removeElementClass(this.element,
this.options.hoverclass);
}
this.options.hoverfunc(this.element, false);
MochiKit.DragAndDrop.Droppables.last_active = null;
},
activate: function () {
/***
A droppable is active when a draggable is over it.
***/
if (this.options.hoverclass) {
MochiKit.DOM.addElementClass(this.element, this.options.hoverclass);
}
this.options.hoverfunc(this.element, true);
MochiKit.DragAndDrop.Droppables.last_active = this;
},
destroy: function () {
/***
Delete this droppable.
***/
MochiKit.DragAndDrop.Droppables.unregister(this);
},
repr: function () {
return '[' + this.__class__.NAME + ", options:" + MochiKit.Base.repr(this.options) + "]";
}
};
MochiKit.DragAndDrop.Draggables = {
/***
Manage draggables elements. Not intended to direct use.
***/
drags: [],
observers: [],
register: function (draggable) {
if (this.drags.length === 0) {
var conn = MochiKit.Signal.connect;
this.eventMouseUp = conn(document, 'onmouseup', this, this.endDrag);
this.eventMouseMove = conn(document, 'onmousemove', this,
this.updateDrag);
this.eventKeypress = conn(document, 'onkeypress', this,
this.keyPress);
}
this.drags.push(draggable);
},
unregister: function (draggable) {
this.drags = MochiKit.Base.filter(function (d) {
return d != draggable;
}, this.drags);
if (this.drags.length === 0) {
var disc = MochiKit.Signal.disconnect
disc(this.eventMouseUp);
disc(this.eventMouseMove);
disc(this.eventKeypress);
}
},
activate: function (draggable) {
// allows keypress events if window is not currently focused
// fails for Safari
window.focus();
this.activeDraggable = draggable;
},
deactivate: function () {
this.activeDraggable = null;
},
updateDrag: function (event) {
if (!this.activeDraggable) {
return;
}
var pointer = event.mouse();
// Mozilla-based browsers fire successive mousemove events with
// the same coordinates, prevent needless redrawing (moz bug?)
if (this._lastPointer && (MochiKit.Base.repr(this._lastPointer.page) ==
MochiKit.Base.repr(pointer.page))) {
return;
}
this._lastPointer = pointer;
this.activeDraggable.updateDrag(event, pointer);
},
endDrag: function (event) {
if (!this.activeDraggable) {
return;
}
this._lastPointer = null;
this.activeDraggable.endDrag(event);
this.activeDraggable = null;
},
keyPress: function (event) {
if (this.activeDraggable) {
this.activeDraggable.keyPress(event);
}
},
addObserver: function (observer) {
this.observers.push(observer);
this._cacheObserverCallbacks();
},
removeObserver: function (element) {
// element instead of observer fixes mem leaks
this.observers = MochiKit.Base.filter(function (o) {
return o.element != element;
}, this.observers);
this._cacheObserverCallbacks();
},
notify: function (eventName, draggable, event) {
// 'onStart', 'onEnd', 'onDrag'
if (this[eventName + 'Count'] > 0) {
MochiKit.Base.map(function (o) {
if (o[eventName]) {
o[eventName](eventName, draggable, event);
}
}, this.observers);
}
},
_cacheObserverCallbacks: function () {
var b = MochiKit.Base;
var self = MochiKit.DragAndDrop.Draggables;
b.map(function (eventName) {
self[eventName + 'Count'] = b.filter(function (o) {
return o[eventName];
}, self.observers).length;
}, ['onStart', 'onEnd', 'onDrag']);
}
};
MochiKit.DragAndDrop.Draggable = function (element, options) {
this.__init__(element, options);
};
MochiKit.DragAndDrop.Draggable.prototype = {
/***
A draggable object. Simple instantiate :
new MochiKit.DragAndDrop.Draggable('myelement');
***/
__class__ : MochiKit.DragAndDrop.Draggable,
__init__: function (element, /* optional */options) {
var v = MochiKit.Visual;
var b = MochiKit.Base;
options = b.update({
handle: false,
starteffect: function (innerelement) {
this._savedOpacity = MochiKit.DOM.getOpacity(innerelement) || 1.0;
new v.Opacity(innerelement, {duration:0.2, from:this._savedOpacity, to:0.7});
},
reverteffect: function (innerelement, top_offset, left_offset) {
var dur = Math.sqrt(Math.abs(top_offset^2) +
Math.abs(left_offset^2))*0.02;
return new v.Move(innerelement,
{x: -left_offset, y: -top_offset, duration: dur});
},
endeffect: function (innerelement) {
new v.Opacity(innerelement, {duration:0.2, from:0.7, to:this._savedOpacity});
},
onchange: b.noop,
zindex: 1000,
revert: false,
scroll: false,
scrollSensitivity: 20,
scrollSpeed: 15,
// false, or xy or [x, y] or function (x, y){return [x, y];}
snap: false
}, options || {});
var d = MochiKit.DOM;
this.element = d.getElement(element);
if (options.handle && (typeof(options.handle) == 'string')) {
this.handle = d.getFirstElementByTagAndClassName(null,
options.handle, this.element);
}
if (!this.handle) {
this.handle = d.getElement(options.handle);
}
if (!this.handle) {
this.handle = this.element;
}
if (options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
options.scroll = d.getElement(options.scroll);
}
d.makePositioned(this.element); // fix IE
this.delta = this.currentDelta();
this.options = options;
this.dragging = false;
this.eventMouseDown = MochiKit.Signal.connect(this.handle,
'onmousedown', this, this.initDrag);
MochiKit.DragAndDrop.Draggables.register(this);
},
destroy: function () {
MochiKit.Signal.disconnect(this.eventMouseDown);
MochiKit.DragAndDrop.Draggables.unregister(this);
},
currentDelta: function () {
var s = MochiKit.DOM.getStyle;
return [
parseInt(s(this.element, 'left') || '0'),
parseInt(s(this.element, 'top') || '0')];
},
initDrag: function (event) {
if (!event.mouse().button.left) {
return;
}
// abort on form elements, fixes a Firefox issue
var src = event.target;
if (src.tagName && (
src.tagName == 'INPUT' || src.tagName == 'SELECT' ||
src.tagName == 'OPTION' || src.tagName == 'BUTTON' ||
src.tagName == 'TEXTAREA')) {
return;
}
if (this._revert) {
this._revert.cancel();
this._revert = null;
}
var pointer = event.mouse();
var pos = MochiKit.Position.cumulativeOffset(this.element);
this.offset = [pointer.page.x - pos.x, pointer.page.y - pos.y]
MochiKit.DragAndDrop.Draggables.activate(this);
event.stop();
},
startDrag: function (event) {
this.dragging = true;
if (this.options.selectclass) {
MochiKit.DOM.addElementClass(this.element,
this.options.selectclass);
}
if (this.options.zindex) {
this.originalZ = parseInt(MochiKit.DOM.getStyle(this.element,
'z-index') || '0');
this.element.style.zIndex = this.options.zindex;
}
if (this.options.ghosting) {
this._clone = this.element.cloneNode(true);
this.ghostPosition = MochiKit.Position.absolutize(this.element);
this.element.parentNode.insertBefore(this._clone, this.element);
}
if (this.options.scroll) {
if (this.options.scroll == window) {
var where = this._getWindowScroll(this.options.scroll);
this.originalScrollLeft = where.left;
this.originalScrollTop = where.top;
} else {
this.originalScrollLeft = this.options.scroll.scrollLeft;
this.originalScrollTop = this.options.scroll.scrollTop;
}
}
MochiKit.DragAndDrop.Droppables.prepare(this.element);
MochiKit.DragAndDrop.Draggables.notify('onStart', this, event);
if (this.options.starteffect) {
this.options.starteffect(this.element);
}
},
updateDrag: function (event, pointer) {
if (!this.dragging) {
this.startDrag(event);
}
MochiKit.Position.prepare();
MochiKit.DragAndDrop.Droppables.show(pointer, this.element);
MochiKit.DragAndDrop.Draggables.notify('onDrag', this, event);
this.draw(pointer);
this.options.onchange(this);
if (this.options.scroll) {
this.stopScrolling();
var p, q;
if (this.options.scroll == window) {
var s = this._getWindowScroll(this.options.scroll);
p = new MochiKit.Style.Coordinates(s.left, s.top);
q = new MochiKit.Style.Coordinates(s.left + s.width,
s.top + s.height);
} else {
p = MochiKit.Position.page(this.options.scroll);
p.x += this.options.scroll.scrollLeft;
p.y += this.options.scroll.scrollTop;
q = new MochiKit.Style.Coordinates(p.x + this.options.scroll.offsetWidth,
p.y + this.options.scroll.offsetHeight);
}
var speed = [0, 0];
if (pointer.page.x > (q.x - this.options.scrollSensitivity)) {
speed[0] = pointer.page.x - (q.x - this.options.scrollSensitivity);
} else if (pointer.page.x < (p.x + this.options.scrollSensitivity)) {
speed[0] = pointer.page.x - (p.x + this.options.scrollSensitivity);
}
if (pointer.page.y > (q.y - this.options.scrollSensitivity)) {
speed[1] = pointer.page.y - (q.y - this.options.scrollSensitivity);
} else if (pointer.page.y < (p.y + this.options.scrollSensitivity)) {
speed[1] = pointer.page.y - (p.y + this.options.scrollSensitivity);
}
this.startScrolling(speed);
}
// fix AppleWebKit rendering
if (MochiKit.Base.isSafari()) {
window.scrollBy(0, 0);
}
event.stop();
},
finishDrag: function (event, success) {
var dr = MochiKit.DragAndDrop;
this.dragging = false;
if (this.options.selectclass) {
MochiKit.DOM.removeElementClass(this.element,
this.options.selectclass);
}
if (this.options.ghosting) {
// XXX: from a user point of view, it would be better to remove
// the node only *after* the MochiKit.Visual.Move end when used
// with revert.
MochiKit.Position.relativize(this.element, this.ghostPosition);
MochiKit.DOM.removeElement(this._clone);
this._clone = null;
}
if (success) {
dr.Droppables.fire(event, this.element);
}
dr.Draggables.notify('onEnd', this, event);
var revert = this.options.revert;
if (revert && typeof(revert) == 'function') {
revert = revert(this.element);
}
var d = this.currentDelta();
if (revert && this.options.reverteffect) {
this._revert = this.options.reverteffect(this.element,
d[1] - this.delta[1], d[0] - this.delta[0]);
} else {
this.delta = d;
}
if (this.options.zindex) {
this.element.style.zIndex = this.originalZ;
}
if (this.options.endeffect) {
this.options.endeffect(this.element);
}
dr.Draggables.deactivate();
dr.Droppables.reset(this.element);
},
keyPress: function (event) {
if (event.keyString != "KEY_ESCAPE") {
return;
}
this.finishDrag(event, false);
event.stop();
},
endDrag: function (event) {
if (!this.dragging) {
return;
}
this.stopScrolling();
this.finishDrag(event, true);
event.stop();
},
draw: function (point) {
var pos = MochiKit.Position.cumulativeOffset(this.element);
var d = this.currentDelta();
pos.x -= d[0];
pos.y -= d[1];
if (this.options.scroll && !this.options.scroll.scrollTo) {
pos.x -= this.options.scroll.scrollLeft - this.originalScrollLeft;
pos.y -= this.options.scroll.scrollTop - this.originalScrollTop;
}
var p = [point.page.x - pos.x - this.offset[0],
point.page.y - pos.y - this.offset[1]]
if (this.options.snap) {
if (typeof(this.options.snap) == 'function') {
p = this.options.snap(p[0], p[1]);
} else {
if (this.options.snap instanceof Array) {
var i = -1;
p = MochiKit.Base.map(MochiKit.Base.bind(function (v) {
i += 1;
return Math.round(v/this.options.snap[i]) *
this.options.snap[i]
}, this), p)
} else {
p = MochiKit.Base.map(MochiKit.Base.bind(function (v) {
return Math.round(v/this.options.snap) *
this.options.snap
}, this), p)
}
}
}
var style = this.element.style;
if ((!this.options.constraint) ||
(this.options.constraint == 'horizontal')) {
style.left = p[0] + 'px';
}
if ((!this.options.constraint) ||
(this.options.constraint == 'vertical')) {
style.top = p[1] + 'px';
}
if (style.visibility == 'hidden') {
style.visibility = ''; // fix gecko rendering
}
},
stopScrolling: function () {
if (this.scrollInterval) {
clearInterval(this.scrollInterval);
this.scrollInterval = null;
}
},
startScrolling: function (speed) {
if (!speed[0] || !speed[1]) {
return;
}
this.scrollSpeed = [speed[0] * this.options.scrollSpeed,
speed[1] * this.options.scrollSpeed];
this.lastScrolled = new Date();
this.scrollInterval = setInterval(MochiKit.Base.bind(this.scroll, this), 10);
},
scroll: function () {
var current = new Date();
var delta = current - this.lastScrolled;
this.lastScrolled = current;
if (this.options.scroll == window) {
var s = this._getWindowScroll(this.options.scroll);
if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
var d = delta / 1000;
this.options.scroll.scrollTo(s.left + d * this.scrollSpeed[0],
s.top + d * this.scrollSpeed[1]);
}
} else {
this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000;
}
var d = MochiKit.DragAndDrop;
MochiKit.Position.prepare();
d.Droppables.show(d.Draggables._lastPointer, this.element);
this.draw(d.Draggables._lastPointer);
this.options.onchange(this);
},
_getWindowScroll: function (w) {
var T, L, W, H;
with (w.document) {
if (w.document.documentElement && documentElement.scrollTop) {
T = documentElement.scrollTop;
L = documentElement.scrollLeft;
} else if (w.document.body) {
T = body.scrollTop;
L = body.scrollLeft;
}
if (w.innerWidth) {
W = w.innerWidth;
H = w.innerHeight;
} else if (w.document.documentElement && documentElement.clientWidth) {
W = documentElement.clientWidth;
H = documentElement.clientHeight;
} else {
W = body.offsetWidth;
H = body.offsetHeight
}
}
return {top: T, left: L, width: W, height: H};
},
repr: function () {
return '[' + this.__class__.NAME + ", options:" + MochiKit.Base.repr(this.options) + "]";
}
};
MochiKit.DragAndDrop.__new__ = function () {
MochiKit.Base.nameFunctions(this);
this.EXPORT_TAGS = {
":common": this.EXPORT,
":all": MochiKit.Base.concat(this.EXPORT, this.EXPORT_OK)
};
};
MochiKit.DragAndDrop.__new__();
MochiKit.Base._exportSymbols(this, MochiKit.DragAndDrop);

File diff suppressed because it is too large Load diff

View file

@ -1,366 +0,0 @@
MochiKit.Base.update(MochiKit.Base, {
isIE: function () {
return /MSIE/.test(navigator.userAgent);
},
isGecko: function () {
return /Gecko/.test(navigator.userAgent);
},
isKHTML: function () {
return /Konqueror|Safari|KHTML/.test(navigator.userAgent)
},
isSafari: function () {
return navigator.appVersion.indexOf('AppleWebKit') > 0;
},
isOpera: function () {
return navigator.userAgent.indexOf('Opera') > 0;
}
});
MochiKit.Base.update(MochiKit.DOM, {
getStyle: function (element, style) {
element = MochiKit.DOM.getElement(element);
var value = element.style[MochiKit.Base.camelize(style)];
if (!value) {
if (document.defaultView && document.defaultView.getComputedStyle) {
var css = document.defaultView.getComputedStyle(element, null);
value = css ? css.getPropertyValue(style) : null;
} else if (element.currentStyle) {
value = element.currentStyle[MochiKit.Base.camelize(style)];
}
}
if (MochiKit.Base.isOpera() && (MochiKit.Base.find(['left', 'top', 'right', 'bottom'], style))) {
if (MochiKit.DOM.getStyle(element, 'position') == 'static') {
value = 'auto';
}
}
return value == 'auto' ? null : value;
},
setStyle: function (element, style) {
element = MochiKit.DOM.getElement(element);
for (name in style) {
element.style[MochiKit.Base.camelize(name)] = style[name];
}
},
getOpacity: function (element) {
var opacity;
if (opacity = MochiKit.DOM.getStyle(element, 'opacity')) {
return parseFloat(opacity);
}
if (opacity = (MochiKit.DOM.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/)) {
if (opacity[1]) {
return parseFloat(opacity[1]) / 100;
}
}
return 1.0;
},
getInlineOpacity: function (element) {
return MochiKit.DOM.getElement(element).style.opacity || '';
},
setOpacity: function (element, value) {
element = MochiKit.DOM.getElement(element);
if (value == 1) {
MochiKit.DOM.setStyle(element, {opacity:
(MochiKit.Base.isGecko() && !MochiKit.Base.isKHTML()) ?
0.999999 : null});
if (MochiKit.Base.isIE())
MochiKit.DOM.setStyle(element, {filter:
MochiKit.DOM.getStyle(element, 'filter').replace(/alpha\([^\)]*\)/gi, '')});
} else {
if (value < 0.00001) {
value = 0;
}
MochiKit.DOM.setStyle(element, {opacity: value});
if (MochiKit.Base.isIE()) {
MochiKit.DOM.setStyle(element,
{filter: MochiKit.DOM.getStyle(element, 'filter').replace(/alpha\([^\)]*\)/gi, '') + 'alpha(opacity=' + value * 100 + ')' });
}
}
},
isVisible: function (element) {
return MochiKit.DOM.getElement(element).style.display != 'none';
},
makeClipping: function (element) {
element = MochiKit.DOM.getElement(element);
if (element._overflow) {
return;
}
element._overflow = element.style.overflow;
if ((MochiKit.DOM.getStyle(element, 'overflow') || 'visible') != 'hidden') {
element.style.overflow = 'hidden';
}
},
undoClipping: function (element) {
element = MochiKit.DOM.getElement(element);
if (!element._overflow) {
return;
}
element.style.overflow = element._overflow;
element._overflow = undefined;
},
makePositioned: function (element) {
element = MochiKit.DOM.getElement(element);
/*if (!element.style) {
alert(element);
}*/
var pos = MochiKit.DOM.getStyle(element, 'position');
if ((pos == 'static' || !pos) && !element._madePositioned) {
element._madePositioned = true;
element.style.position = 'relative';
// Opera returns the offset relative to the positioning context,
// when an element is position relative but top and left have
// not been defined
if (MochiKit.Base.isOpera()) {
element.style.top = 0;
element.style.left = 0;
}
}
},
undoPositioned: function (element) {
element = MochiKit.DOM.getElement(element);
if (element._madePositioned) {
element._madePositioned = undefined;
element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = '';
}
},
getFirstElementByTagAndClassName: function (tagName, className,
/* optional */parent) {
var self = MochiKit.DOM;
if (typeof(tagName) == 'undefined' || tagName === null) {
tagName = '*';
}
if (typeof(parent) == 'undefined' || parent === null) {
parent = self._document;
}
parent = self.getElement(parent);
var children = (parent.getElementsByTagName(tagName)
|| self._document.all);
if (typeof(className) == 'undefined' || className === null) {
return MochiKit.Base.extend(null, children);
}
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) {
return child;
}
}
}
},
isParent: function (child, element) {
if (!child.parentNode || child == element) {
return false;
}
if (child.parentNode == element) {
return true;
}
return MochiKit.DOM.isParent(child.parentNode, element);
}
});
MochiKit.Position = {
// set to true if needed, warning: firefox performance problems
// NOT neeeded for page scrolling, only if draggable contained in
// scrollable elements
includeScrollOffsets: false,
prepare: function () {
var deltaX = window.pageXOffset
|| document.documentElement.scrollLeft
|| document.body.scrollLeft
|| 0;
var deltaY = window.pageYOffset
|| document.documentElement.scrollTop
|| document.body.scrollTop
|| 0;
this.windowOffset = new MochiKit.Style.Coordinates(deltaX, deltaY);
},
cumulativeOffset: function (element) {
var valueT = 0;
var valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
} while (element);
return new MochiKit.Style.Coordinates(valueL, valueT);
},
realOffset: function (element) {
var valueT = 0;
var valueL = 0;
do {
valueT += element.scrollTop || 0;
valueL += element.scrollLeft || 0;
element = element.parentNode;
} while (element);
return new MochiKit.Style.Coordinates(valueL, valueT);
},
within: function (element, x, y) {
if (this.includeScrollOffsets) {
return this.withinIncludingScrolloffsets(element, x, y);
}
this.xcomp = x;
this.ycomp = y;
this.offset = this.cumulativeOffset(element);
if (element.style.position == "fixed") {
this.offset.x += this.windowOffset.x;
this.offset.y += this.windowOffset.y;
}
return (y >= this.offset.y &&
y < this.offset.y + element.offsetHeight &&
x >= this.offset.x &&
x < this.offset.x + element.offsetWidth);
},
withinIncludingScrolloffsets: function (element, x, y) {
var offsetcache = this.realOffset(element);
this.xcomp = x + offsetcache.x - this.windowOffset.x;
this.ycomp = y + offsetcache.y - this.windowOffset.y;
this.offset = this.cumulativeOffset(element);
return (this.ycomp >= this.offset.y &&
this.ycomp < this.offset.y + element.offsetHeight &&
this.xcomp >= this.offset.x &&
this.xcomp < this.offset.x + element.offsetWidth);
},
// within must be called directly before
overlap: function (mode, element) {
if (!mode) {
return 0;
}
if (mode == 'vertical') {
return ((this.offset.y + element.offsetHeight) - this.ycomp) /
element.offsetHeight;
}
if (mode == 'horizontal') {
return ((this.offset.x + element.offsetWidth) - this.xcomp) /
element.offsetWidth;
}
},
absolutize: function (element) {
element = MochiKit.DOM.getElement(element);
if (element.style.position == 'absolute') {
return;
}
MochiKit.Position.prepare();
var offsets = MochiKit.Position.positionedOffset(element);
var width = element.clientWidth;
var height = element.clientHeight;
var oldStyle = {
'position': element.style.position,
'left': offsets.x - parseFloat(element.style.left || 0),
'top': offsets.y - parseFloat(element.style.top || 0),
'width': element.style.width,
'height': element.style.height
};
element.style.position = 'absolute';
element.style.top = offsets.y + 'px';
element.style.left = offsets.x + 'px';
element.style.width = width + 'px';
element.style.height = height + 'px';
return oldStyle;
},
positionedOffset: function (element) {
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
if (element) {
p = MochiKit.DOM.getStyle(element, 'position');
if (p == 'relative' || p == 'absolute') {
break;
}
}
} while (element);
return new MochiKit.Style.Coordinates(valueL, valueT);
},
relativize: function (element, oldPos) {
element = MochiKit.DOM.getElement(element);
if (element.style.position == 'relative') {
return;
}
MochiKit.Position.prepare();
var top = parseFloat(element.style.top || 0) -
(oldPos['top'] || 0);
var left = parseFloat(element.style.left || 0) -
(oldPos['left'] || 0);
element.style.position = oldPos['position'];
element.style.top = top + 'px';
element.style.left = left + 'px';
element.style.width = oldPos['width'];
element.style.height = oldPos['height'];
},
clone: function (source, target) {
source = MochiKit.DOM.getElement(source);
target = MochiKit.DOM.getElement(target);
target.style.position = 'absolute';
var offsets = this.cumulativeOffset(source);
target.style.top = offsets.y + 'px';
target.style.left = offsets.x + 'px';
target.style.width = source.offsetWidth + 'px';
target.style.height = source.offsetHeight + 'px';
},
page: function (forElement) {
var valueT = 0;
var valueL = 0;
var element = forElement;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
// Safari fix
if (element.offsetParent == document.body && MochiKit.DOM.getStyle(element, 'position') == 'absolute') {
break;
}
} while (element = element.offsetParent);
element = forElement;
do {
valueT -= element.scrollTop || 0;
valueL -= element.scrollLeft || 0;
} while (element = element.parentNode);
return new MochiKit.Style.Coordinates(valueL, valueT);
}
};

View file

@ -1,531 +0,0 @@
/***
Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
Mochi-ized By Thomas Herve (_firstname_@nimail.org)
See scriptaculous.js for full license.
***/
if (typeof(dojo) != 'undefined') {
dojo.provide('MochiKit.DragAndDrop');
dojo.require('MochiKit.Base');
dojo.require('MochiKit.DOM');
dojo.require('MochiKit.Iter');
}
if (typeof(JSAN) != 'undefined') {
JSAN.use("MochiKit.Base", []);
JSAN.use("MochiKit.DOM", []);
JSAN.use("MochiKit.Iter", []);
}
try {
if (typeof(MochiKit.Base) == 'undefined' ||
typeof(MochiKit.DOM) == 'undefined' ||
typeof(MochiKit.Iter) == 'undefined') {
throw "";
}
} catch (e) {
throw "MochiKit.DragAndDrop depends on MochiKit.Base, MochiKit.DOM and MochiKit.Iter!";
}
if (typeof(MochiKit.Sortable) == 'undefined') {
MochiKit.Sortable = {};
}
MochiKit.Sortable.NAME = 'MochiKit.Sortable';
MochiKit.Sortable.VERSION = '1.4';
MochiKit.Sortable.__repr__ = function () {
return '[' + this.NAME + ' ' + this.VERSION + ']';
};
MochiKit.Sortable.toString = function () {
return this.__repr__();
};
MochiKit.Sortable.EXPORT = [
"SortableObserver"
];
MochiKit.DragAndDrop.EXPORT_OK = [
"Sortable"
];
MochiKit.Sortable.SortableObserver = function (element, observer) {
this.__init__(element, observer);
};
MochiKit.Sortable.SortableObserver.prototype = {
/***
Observe events of drag and drop sortables.
***/
__init__: function (element, observer) {
this.element = MochiKit.DOM.getElement(element);
this.observer = observer;
this.lastValue = MochiKit.Sortable.Sortable.serialize(this.element);
},
onStart: function () {
this.lastValue = MochiKit.Sortable.Sortable.serialize(this.element);
},
onEnd: function () {
MochiKit.Sortable.Sortable.unmark();
if (this.lastValue != MochiKit.Sortable.Sortable.serialize(this.element)) {
this.observer(this.element)
}
}
};
MochiKit.Sortable.Sortable = {
/***
Manage sortables. Mainly use the create function to add a sortable.
***/
sortables: {},
_findRootElement: function (element) {
while (element.tagName != "BODY") {
if (element.id && MochiKit.Sortable.Sortable.sortables[element.id]) {
return element;
}
element = element.parentNode;
}
},
options: function (element) {
element = MochiKit.Sortable.Sortable._findRootElement(MochiKit.DOM.getElement(element));
if (!element) {
return;
}
return MochiKit.Sortable.Sortable.sortables[element.id];
},
destroy: function (element){
var s = MochiKit.Sortable.Sortable.options(element);
var b = MochiKit.Base;
var d = MochiKit.DragAndDrop;
if (s) {
d.Draggables.removeObserver(s.element);
b.map(function (dr) {
d.Droppables.remove(dr);
}, s.droppables);
b.map(function (dr) {
dr.destroy();
}, s.draggables);
delete MochiKit.Sortable.Sortable.sortables[s.element.id];
}
},
create: function (element, options) {
element = MochiKit.DOM.getElement(element);
var self = MochiKit.Sortable.Sortable;
options = MochiKit.Base.update({
element: element,
tag: 'li', // assumes li children, override with tag: 'tagname'
dropOnEmpty: false,
tree: false,
treeTag: 'ul',
overlap: 'vertical', // one of 'vertical', 'horizontal'
constraint: 'vertical', // one of 'vertical', 'horizontal', false
// also takes array of elements (or ids); or false
containment: [element],
handle: false, // or a CSS class
only: false,
hoverclass: null,
ghosting: false,
scroll: false,
scrollSensitivity: 20,
scrollSpeed: 15,
format: /^[^_]*_(.*)$/,
onChange: MochiKit.Base.noop,
onUpdate: MochiKit.Base.noop,
accept: null
}, options);
// clear any old sortable with same element
self.destroy(element);
// build options for the draggables
var options_for_draggable = {
revert: true,
ghosting: options.ghosting,
scroll: options.scroll,
scrollSensitivity: options.scrollSensitivity,
scrollSpeed: options.scrollSpeed,
constraint: options.constraint,
handle: options.handle
};
if (options.starteffect) {
options_for_draggable.starteffect = options.starteffect;
}
if (options.reverteffect) {
options_for_draggable.reverteffect = options.reverteffect;
} else if (options.ghosting) {
options_for_draggable.reverteffect = function (innerelement) {
innerelement.style.top = 0;
innerelement.style.left = 0;
};
}
if (options.endeffect) {
options_for_draggable.endeffect = options.endeffect;
}
if (options.zindex) {
options_for_draggable.zindex = options.zindex;
}
// build options for the droppables
var options_for_droppable = {
overlap: options.overlap,
containment: options.containment,
hoverclass: options.hoverclass,
onhover: self.onHover,
tree: options.tree,
accept: options.accept
}
var options_for_tree = {
onhover: self.onEmptyHover,
overlap: options.overlap,
containment: options.containment,
hoverclass: options.hoverclass,
accept: options.accept
}
// fix for gecko engine
MochiKit.DOM.removeEmptyTextNodes(element);
options.draggables = [];
options.droppables = [];
// drop on empty handling
if (options.dropOnEmpty || options.tree) {
new MochiKit.DragAndDrop.Droppable(element, options_for_tree);
options.droppables.push(element);
}
MochiKit.Base.map(function (e) {
// handles are per-draggable
var handle = options.handle ?
MochiKit.DOM.getFirstElementByTagAndClassName(null,
options.handle, e) : e;
options.draggables.push(
new MochiKit.DragAndDrop.Draggable(e,
MochiKit.Base.update(options_for_draggable,
{handle: handle})));
new MochiKit.DragAndDrop.Droppable(e, options_for_droppable);
if (options.tree) {
e.treeNode = element;
}
options.droppables.push(e);
}, (self.findElements(element, options) || []));
if (options.tree) {
MochiKit.Base.map(function (e) {
new MochiKit.DragAndDrop.Droppable(e, options_for_tree);
e.treeNode = element;
options.droppables.push(e);
}, (self.findTreeElements(element, options) || []));
}
// keep reference
self.sortables[element.id] = options;
// for onupdate
MochiKit.DragAndDrop.Draggables.addObserver(
new MochiKit.Sortable.SortableObserver(element, options.onUpdate));
},
// return all suitable-for-sortable elements in a guaranteed order
findElements: function (element, options) {
return MochiKit.Sortable.Sortable.findChildren(
element, options.only, options.tree ? true : false, options.tag);
},
findTreeElements: function (element, options) {
return MochiKit.Sortable.Sortable.findChildren(
element, options.only, options.tree ? true : false, options.treeTag);
},
findChildren: function (element, only, recursive, tagName) {
if (!element.hasChildNodes()) {
return null;
}
tagName = tagName.toUpperCase();
if (only) {
only = MochiKit.Base.flattenArray([only]);
}
var elements = [];
MochiKit.Base.map(function (e) {
if (e.tagName &&
e.tagName.toUpperCase() == tagName &&
(!only ||
MochiKit.Iter.some(only, function (c) {
return MochiKit.DOM.hasElementClass(e, c);
}))) {
elements.push(e);
}
if (recursive) {
var grandchildren = MochiKit.Sortable.Sortable.findChildren(e, only, recursive, tagName);
if (grandchildren && grandchildren.length > 0) {
elements = elements.concat(grandchildren);
}
}
}, element.childNodes);
return elements;
},
onHover: function (element, dropon, overlap) {
if (MochiKit.DOM.isParent(dropon, element)) {
return;
}
var self = MochiKit.Sortable.Sortable;
if (overlap > .33 && overlap < .66 && self.options(dropon).tree) {
return;
} else if (overlap > 0.5) {
self.mark(dropon, 'before');
if (dropon.previousSibling != element) {
var oldParentNode = element.parentNode;
element.style.visibility = 'hidden'; // fix gecko rendering
dropon.parentNode.insertBefore(element, dropon);
if (dropon.parentNode != oldParentNode) {
self.options(oldParentNode).onChange(element);
}
self.options(dropon.parentNode).onChange(element);
}
} else {
self.mark(dropon, 'after');
var nextElement = dropon.nextSibling || null;
if (nextElement != element) {
var oldParentNode = element.parentNode;
element.style.visibility = 'hidden'; // fix gecko rendering
dropon.parentNode.insertBefore(element, nextElement);
if (dropon.parentNode != oldParentNode) {
self.options(oldParentNode).onChange(element);
}
self.options(dropon.parentNode).onChange(element);
}
}
},
_offsetSize: function (element, type) {
if (type == 'vertical' || type == 'height') {
return element.offsetHeight;
} else {
return element.offsetWidth;
}
},
onEmptyHover: function (element, dropon, overlap) {
var oldParentNode = element.parentNode;
var self = MochiKit.Sortable.Sortable;
var droponOptions = self.options(dropon);
if (!MochiKit.DOM.isParent(dropon, element)) {
var index;
var children = self.findElements(dropon, {tag: droponOptions.tag,
only: droponOptions.only});
var child = null;
if (children) {
var offset = self._offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap);
for (index = 0; index < children.length; index += 1) {
if (offset - self._offsetSize(children[index], droponOptions.overlap) >= 0) {
offset -= self._offsetSize(children[index], droponOptions.overlap);
} else if (offset - (self._offsetSize (children[index], droponOptions.overlap) / 2) >= 0) {
child = index + 1 < children.length ? children[index + 1] : null;
break;
} else {
child = children[index];
break;
}
}
}
dropon.insertBefore(element, child);
self.options(oldParentNode).onChange(element);
droponOptions.onChange(element);
}
},
unmark: function () {
var m = MochiKit.Sortable.Sortable._marker;
if (m) {
MochiKit.Style.hideElement(m);
}
},
mark: function (dropon, position) {
// mark on ghosting only
var d = MochiKit.DOM;
var self = MochiKit.Sortable.Sortable;
var sortable = self.options(dropon.parentNode);
if (sortable && !sortable.ghosting) {
return;
}
if (!self._marker) {
self._marker = d.getElement('dropmarker') ||
document.createElement('DIV');
MochiKit.Style.hideElement(self._marker);
d.addElementClass(self._marker, 'dropmarker');
self._marker.style.position = 'absolute';
document.getElementsByTagName('body').item(0).appendChild(self._marker);
}
var offsets = MochiKit.Position.cumulativeOffset(dropon);
self._marker.style.left = offsets.x + 'px';
self._marker.style.top = offsets.y + 'px';
if (position == 'after') {
if (sortable.overlap == 'horizontal') {
self._marker.style.left = (offsets.x + dropon.clientWidth) + 'px';
} else {
self._marker.style.top = (offsets.y + dropon.clientHeight) + 'px';
}
}
MochiKit.Style.showElement(self._marker);
},
_tree: function (element, options, parent) {
var self = MochiKit.Sortable.Sortable;
var children = self.findElements(element, options) || [];
for (var i = 0; i < children.length; ++i) {
var match = children[i].id.match(options.format);
if (!match) {
continue;
}
var child = {
id: encodeURIComponent(match ? match[1] : null),
element: element,
parent: parent,
children: [],
position: parent.children.length,
container: self._findChildrenElement(children[i], options.treeTag.toUpperCase())
}
/* Get the element containing the children and recurse over it */
if (child.container) {
self._tree(child.container, options, child)
}
parent.children.push (child);
}
return parent;
},
/* Finds the first element of the given tag type within a parent element.
Used for finding the first LI[ST] within a L[IST]I[TEM].*/
_findChildrenElement: function (element, containerTag) {
if (element && element.hasChildNodes) {
for (var i = 0; i < element.childNodes.length; ++i) {
if (element.childNodes[i].tagName == containerTag) {
return element.childNodes[i];
}
}
}
return null;
},
tree: function (element, options) {
element = MochiKit.DOM.getElement(element);
var sortableOptions = MochiKit.Sortable.Sortable.options(element);
options = MochiKit.Base.update({
tag: sortableOptions.tag,
treeTag: sortableOptions.treeTag,
only: sortableOptions.only,
name: element.id,
format: sortableOptions.format
}, options || {});
var root = {
id: null,
parent: null,
children: new Array,
container: element,
position: 0
}
return MochiKit.Sortable.Sortable._tree(element, options, root);
},
setSequence: function (element, newSequence, options) {
var self = MochiKit.Sortable.Sortable;
var b = MochiKit.Base;
element = MochiKit.DOM.getElement(element);
options = b.update(self.options(element), options || {});
var nodeMap = {};
b.map(function (n) {
var m = n.id.match(options.format);
if (m) {
nodeMap[m[1]] = [n, n.parentNode];
}
n.parentNode.removeChild(n);
}, self.findElements(element, options));
b.map(function (ident) {
var n = nodeMap[ident];
if (n) {
n[1].appendChild(n[0]);
delete nodeMap[ident];
}
}, newSequence);
},
/* Construct a [i] index for a particular node */
_constructIndex: function (node) {
var index = '';
do {
if (node.id) {
index = '[' + node.position + ']' + index;
}
} while ((node = node.parent) != null);
return index;
},
sequence: function (element, options) {
element = MochiKit.DOM.getElement(element);
var self = MochiKit.Sortable.Sortable;
var options = MochiKit.Base.update(self.options(element), options || {});
return MochiKit.Base.map(function (item) {
return item.id.match(options.format) ? item.id.match(options.format)[1] : '';
}, MochiKit.DOM.getElement(self.findElements(element, options) || []));
},
serialize: function (element, options) {
element = MochiKit.DOM.getElement(element);
var self = MochiKit.Sortable.Sortable;
options = MochiKit.Base.update(self.options(element), options || {});
var name = encodeURIComponent(options.name || element.id);
if (options.tree) {
return MochiKit.Base.flattenArray(MochiKit.Base.map(function (item) {
return [name + self._constructIndex(item) + "[id]=" +
encodeURIComponent(item.id)].concat(item.children.map(arguments.callee));
}, self.tree(element, options).children)).join('&');
} else {
return MochiKit.Base.map(function (item) {
return name + "[]=" + encodeURIComponent(item);
}, self.sequence(element, options)).join('&');
}
}
};

View file

@ -1,57 +0,0 @@
function getSelected() {
return getElement("foreback").value;
}
function updateDisplay() {
var textbox = getElement("as_string");
var current = getSelected();
if (current == "Foreground") {
textbox.value = Color.fromText("sample").toString();
} else {
textbox.value = Color.fromBackground("sample").toString();
}
}
function setSampleFromElement(elem, toSet) {
var elem = getElement(elem);
var samplediv = getElement("sample");
var color = Color.fromString(elem.value);
if (color == null) {
alert("Unknown color string");
return;
}
samplediv.style[toSet] = color;
updateDisplay();
}
function setColor() {
var current = getSelected();
if (current == "Foreground") {
setSampleFromElement("as_string", "color");
} else {
setSampleFromElement("as_string", "background");
}
}
function setForeground() {
setSampleFromElement("foreground", "color");
}
function setBackground() {
setSampleFromElement("background", "background");
}
function cloneColor() {
var samplediv = getElement("sample");
var current = getSelected();
if (current == "Foreground") {
samplediv.style.color = Color.fromText("header");
} else {
samplediv.style.background = Color.fromBackground("header");
}
updateDisplay();
}

View file

@ -1,120 +0,0 @@
/*
Drag: A Really Simple Drag Handler
*/
var nextInChain = [];
RollingSign = function(element, newstring, options) {
this.__init__(element, newstring, options);
}
RollingSign.prototype = new Base();
update(RollingSign.prototype, {
__init__ : function(element, newstring, options) {
this.element = getElement(element);
options = update(
{
charSpaceSize: 26,
startingChar: 65
}, options || {});
this.newstring = newstring;
this.oldstring = this.element.innerHTML;
this.start(options);
},
update: function(position) {
curchar = this.newstring.length * position;
toMake = this.newstring.length - curchar;
ending = "";
for (i = 0; i < toMake; i++) {
ending += String.fromCharCode(
Math.random() * this.options.charSpaceSize +
this.options.startingChar);
}
this.element.innerHTML = this.newstring.substr(0, curchar) +
ending;
},
finish: function() {
this.element.innerHTML = this.newstring;
}
}
);
Drag = {
_move: null,
_down: null,
start: function(e) {
e.stop();
// We need to remember what we're dragging.
Drag._target = e.target();
/*
There's no cross-browser way to get offsetX and offsetY, so we
have to do it ourselves. For performance, we do this once and
cache it.
*/
Drag._offset = Drag._diff(
e.mouse().page,
getElementPosition(Drag._target));
Drag._move = connect(document, 'onmousemove', Drag._drag);
Drag._down = connect(document, 'onmouseup', Drag._stop);
},
_offset: null,
_target: null,
_diff: function(lhs, rhs) {
return new MochiKit.Style.Coordinates(lhs.x - rhs.x, lhs.y - rhs.y);
},
_drag: function(e) {
e.stop();
setElementPosition(
Drag._target,
Drag._diff(e.mouse().page, Drag._offset));
},
_stop: function(e) {
disconnect(Drag._move);
disconnect(Drag._down);
}
};
connect(window, 'onload',
function() {
/*
Find all DIVs tagged with the draggable class, and connect them to
the Drag handler.
*/
var d = getElementsByTagAndClassName('DIV', 'draggable');
forEach(d,
function(elem) {
connect(elem, 'onmousedown', Drag.start);
});
});
connect(window, 'onload',
function() {
var elems = getElementsByTagAndClassName("A", "view-source");
var page = "draggable/";
for (var i = 0; i < elems.length; i++) {
var elem = elems[i];
var href = elem.href.split(/\//).pop();
elem.target = "_blank";
elem.href = "../view-source/view-source.html#" + page + href;
}
});

View file

@ -1,35 +0,0 @@
function cancelEdit(element) {
switchOff(element + 'Form')
appear(element)
}
function formEdit(element) {
var elements = Array("givenName", "mail", "fedoraPersonBugzillaMail", "fedoraPersonIrcNick", "fedoraPersonKeyId", "telephoneNumber", "postalAddress", "description")
for(var i = 0; i != elements.length; i++) {
if (elements[i] != element) {
var form = document.getElementById(elements[i] + 'Form');
if ( form.style.display != 'none') {
new Highlight(elements[i] + 'Form');
return false;
}
}
}
switchOff(element);
appear(element + 'Form');
}
function displayHelp(helpID) {
grow('helpMessageMain');
getElement('helpMessage').innerHTML = 'Please Wait...';
//d = MochiKit.Async.doSimpleXMLHttpRequest('/fas/help', {});
var d = loadJSONDoc('/fas/help', {helpID: helpID});
var gotMetadata = function (meta) {
getElement('helpMessage').innerHTML = meta.help
};
//getElement('helpMessage').innerHTML = d.help;
var metadataFetchFailed = function (err) {
getElement('helpMessage').innerHTML = 'Could not fetch help message!'
};
d.addCallbacks(gotMetadata, metadataFetchFailed)
return false;
}

View file

@ -1,13 +0,0 @@
var currentSelected = null;
function changeSelected(e) {
if (currentSelected != null) {
logDebug("Disconnecting " + currentSelected);
disconnectAll(currentSelected);
}
var es = getElement("elemselect");
currentSelected = es.value;
var ev = getElement("eventselect").value;
logDebug("Connecting " + currentSelected + " for event " + ev);
connect(currentSelected, ev, log);
}

View file

@ -1,203 +0,0 @@
/*
On page load, the SortableManager:
- Finds the table by its id (sortable_table).
- Parses its thead for columns with a "mochi:format" attribute.
- Parses the data out of the tbody based upon information given in the
"mochi:format" attribute, and clones the tr elements for later re-use.
- Clones the column header th elements for use as a template when drawing
sort arrow columns.
- Stores away a reference to the tbody, as it will be replaced on each sort.
- Performs the first sort.
On sort request:
- Sorts the data based on the given key and direction
- Creates a new tbody from the rows in the new ordering
- Replaces the column header th elements with clickable versions, adding an
indicator (&uarr; or &darr;) to the most recently sorted column.
*/
SortableManager = function () {
this.thead = null;
this.tbody = null;
this.columns = [];
this.rows = [];
this.sortState = {};
this.sortkey = 0;
};
mouseOverFunc = function () {
addElementClass(this, "over");
};
mouseOutFunc = function () {
removeElementClass(this, "over");
};
ignoreEvent = function (ev) {
if (ev && ev.preventDefault) {
ev.preventDefault();
ev.stopPropagation();
} else if (typeof(event) != 'undefined') {
event.cancelBubble = false;
event.returnValue = false;
}
};
update(SortableManager.prototype, {
"initWithTable": function (table) {
/***
Initialize the SortableManager with a table object
***/
// Ensure that it's a DOM element
table = getElement(table);
// Find the thead
this.thead = table.getElementsByTagName('thead')[0];
// get the mochi:format key and contents for each column header
var cols = this.thead.getElementsByTagName('th');
for (var i = 0; i < cols.length; i++) {
var node = cols[i];
var attr = null;
try {
attr = node.getAttribute("mochi:format");
} catch (err) {
// pass
}
var o = node.childNodes;
this.columns.push({
"format": attr,
"element": node,
"proto": node.cloneNode(true)
});
}
// scrape the tbody for data
this.tbody = table.getElementsByTagName('tbody')[0];
// every row
var rows = this.tbody.getElementsByTagName('tr');
for (var i = 0; i < rows.length; i++) {
// every cell
var row = rows[i];
var cols = row.getElementsByTagName('td');
var rowData = [];
for (var j = 0; j < cols.length; j++) {
// scrape the text and build the appropriate object out of it
var cell = cols[j];
var obj = scrapeText(cell);
switch (this.columns[j].format) {
case 'isodate':
obj = isoDate(obj);
break;
case 'str':
break;
case 'istr':
obj = obj.toLowerCase();
break;
// cases for numbers, etc. could be here
default:
break;
}
rowData.push(obj);
}
// stow away a reference to the TR and save it
rowData.row = row.cloneNode(true);
this.rows.push(rowData);
}
// do initial sort on first column
this.drawSortedRows(this.sortkey, true, false);
},
"onSortClick": function (name) {
/***
Return a sort function for click events
***/
return method(this, function () {
log('onSortClick', name);
var order = this.sortState[name];
if (order == null) {
order = true;
} else if (name == this.sortkey) {
order = !order;
}
this.drawSortedRows(name, order, true);
});
},
"drawSortedRows": function (key, forward, clicked) {
/***
Draw the new sorted table body, and modify the column headers
if appropriate
***/
log('drawSortedRows', key, forward);
this.sortkey = key;
// sort based on the state given (forward or reverse)
var cmp = (forward ? keyComparator : reverseKeyComparator);
this.rows.sort(cmp(key));
// save it so we can flip next time
this.sortState[key] = forward;
// get every "row" element from this.rows and make a new tbody
var newBody = TBODY(null, map(itemgetter("row"), this.rows));
// swap in the new tbody
this.tbody = swapDOM(this.tbody, newBody);
for (var i = 0; i < this.columns.length; i++) {
var col = this.columns[i];
var node = col.proto.cloneNode(true);
// remove the existing events to minimize IE leaks
col.element.onclick = null;
col.element.onmousedown = null;
col.element.onmouseover = null;
col.element.onmouseout = null;
// set new events for the new node
node.onclick = this.onSortClick(i);
node.onmousedown = ignoreEvent;
node.onmouseover = mouseOverFunc;
node.onmouseout = mouseOutFunc;
// if this is the sorted column
if (key == i) {
// \u2193 is down arrow, \u2191 is up arrow
// forward sorts mean the rows get bigger going down
var arrow = (forward ? "\u2193" : "\u2191");
// add the character to the column header
node.appendChild(SPAN(null, arrow));
if (clicked) {
node.onmouseover();
}
}
// swap in the new th
col.element = swapDOM(col.element, node);
}
}
});
sortableManager = new SortableManager();
addLoadEvent(function () {
sortableManager.initWithTable('sortable_table');
});
// rewrite the view-source links
addLoadEvent(function () {
var elems = getElementsByTagAndClassName("A", "view-source");
var page = "sortable_tables/";
for (var i = 0; i < elems.length; i++) {
var elem = elems[i];
var href = elem.href.split(/\//).pop();
elem.target = "_blank";
elem.href = "../view-source/view-source.html#" + page + href;
}
});

View file

@ -1,67 +0,0 @@
// getElementDimensions, getElementPosition
function updateStatus() {
var e = getElement("thetestelem");
var dim = getElementDimensions(e);
var pos = getElementPosition(e);
getElement("dimensions").innerHTML = repr(dim);
getElement("coordinates").innerHTML = repr(pos);
getElement("width").value = dim.w;
getElement("height").value = dim.h;
getElement("x").value = pos.x;
getElement("y").value = pos.y;
}
// showElement and hideElement
function hideTheTestElem() {
// Toggles our guinea testelem element
var button = getElement("hidebutton");
if (button.value == "Hide Element") {
hideElement("thetestelem");
button.value = "Show Element";
} else {
showElement("thetestelem");
button.value = "Hide Element";
}
updateStatus();
}
// setElementDimensions
function setTestElemDimensions() {
var e = getElement("thetestelem");
var dim = new Dimensions(getElement("width").value,
getElement("height").value);
setElementDimensions(e, dim);
updateStatus();
}
// setElementPosition
function setTestElemPosition() {
var e = getElement("thetestelem");
var pos = new Coordinates(getElement("x").value,
getElement("y").value);
setElementPosition(e, pos);
updateStatus();
}
// setOpacity
function setTestElemOpacity() {
setOpacity("thetestelem", getElement("opacity").value);
}
// computedStyle
function getTestElemStyle() {
var prop = getElement("testelemprop").value;
var style = computedStyle("thetestelem", prop);
getElement("testelemstyle").innerHTML = style;
}

View file

@ -1,19 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#">
<head>
<style type="text/css">
@import "/static/css/fas.css";
</style>
</head>
<body>
<div py:if="tg_flash" class="flash" py:content="tg_flash"></div>
<form method='post'>
<!-- This needs to be fixed before going live -->
<input type='hidden' name='attribute' value='${attribute}'/>
<input type='hidden' name='update' value='True'/>
<input type='hidden' name='userName' value='${userName}' />
<input type='text' name='value' value='${value}'/>
</form>
</body>
</html>

View file

@ -1,236 +1,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
<head>
<style type="text/css">
@import "/static/css/fas.css";
@import "/static/css/draggable.css";
</style>
<title>Edit Account</title>
</head>
<body>
<div class='draggable white' style="left: 10px; display: none" id='help'>close</div>
<script src="/fas/static/javascript/forms.js" type="text/javascript"></script>
<script src="/fas/static/javascript/draggable.js" type="text/javascript"></script>
<h2 id="your-account-header"><img src="static/images/header-icon_account.png" />Your Fedora Account</h2>
<table class="account-info" id="your-account-basic-info">
<tbody>
<tr>
<td>Account Name <a href='' onClick="displayHelp('cn'); return false;">(?)</a>:</td>
<td>${user.cn}</td>
</tr>
<tr>
<td>Real Name <a href='' onClick="displayHelp('givenName'); return false;">(?)</a>:</td>
<td>
<div id='givenName'>${user.givenName} <a href="" onclick="formEdit('givenName'); return false;">(edit)</a></div>
<div id='givenNameForm' style='display: none'>
<form method='post' action='editUserAttribute'>
<input type='hidden' name='userName' value='${user.cn}'/>
<input type='hidden' name='attribute' value='givenName'/>
<input type='text' name='value' value='${user.givenName}'/>
<a href='' onclick="cancelEdit('givenName'); return false;">(cancel)</a>
</form>
</div>
</td>
</tr>
<tr>
<td>Email <a href='' onClick="displayHelp('mail'); return false;">(?)</a>:</td>
<td>
<div id='mail'>${user.mail} <a href='' onclick="formEdit('mail'); return false;">(edit)</a></div>
<div id='mailForm' style='display: none'>
<form method='post' action='editUserAttribute'>
<input type='hidden' name='userName' value='${user.cn}'/>
<input type='hidden' name='attribute' value='mail'/>
<input type='text' name='value' value='${user.mail}'/>
<a href='editAccount' onclick="cancelEdit('mail'); return false;">(cancel)</a>
</form>
</div>
</td>
</tr>
<tr>
<td>Bugzilla Email <a href='' onClick="displayHelp('fedoraPersonBugzillaMail'); return false;">(?)</a>:</td>
<td>
<div id='fedoraPersonBugzillaMail'>${user.fedoraPersonBugzillaMail} <a href='' onclick="formEdit('fedoraPersonBugzillaMail'); return false;">(edit)</a></div>
<div id='fedoraPersonBugzillaMailForm' style='display: none'>
<form method='post' action='editUserAttribute'>
<input type='hidden' name='userName' value='${user.cn}'/>
<input type='hidden' name='attribute' value='fedoraPersonBugzillaMail'/>
<input type='text' name='value' value='${user.fedoraPersonBugzillaMail}'/>
<a href='editAccount' onclick="cancelEdit('fedoraPersonBugzillaMail'); return false;">(cancel)</a>
</form>
</div>
</td>
</tr>
<tr>
<td>IRC Nick <a href='' onClick="displayHelp('fedoraPersonIrcNick'); return false;">(?)</a>:</td>
<td>
<div id='fedoraPersonIrcNick'>${user.fedoraPersonIrcNick} <a href='' onclick="formEdit('fedoraPersonIrcNick'); return false;">(edit)</a></div>
<div id='fedoraPersonIrcNickForm' style='display: none'>
<form method='post' action='editUserAttribute'>
<input type='hidden' name='userName' value='${user.cn}'/>
<input type='hidden' name='attribute' value='fedoraPersonIrcNick'/>
<input type='text' name='value' value='${user.fedoraPersonIrcNick}'/>
<a href='editAccount' onclick="cancelEdit('fedoraPersonIrcNick'); return false;">(cancel)</a>
</form>
</div>
</td>
</tr>
<tr>
<td>PGP Key <a href='' onClick="displayHelp('fedoraPersonKeyId'); return false;">(?)</a>:</td>
<td>
<div id='fedoraPersonKeyId'>${user.fedoraPersonKeyId} <a href='' onclick="formEdit('fedoraPersonKeyId'); return false;">(edit)</a></div>
<div id='fedoraPersonKeyIdForm' style='display: none'>
<form method='post' action='editUserAttribute'>
<input type='hidden' name='userName' value='${user.cn}'/>
<input type='hidden' name='attribute' value='fedoraPersonKeyId'/>
<input type='text' name='value' value='${user.fedoraPersonKeyId}'/>
<a href='editAccount' onclick="cancelEdit('fedoraPersonKeyId'); return false;">(cancel)</a>
</form>
</div>
</td>
</tr>
<tr>
<td>Telephone Number <a href='' onClick="displayHelp('telephoneNumber'); return false;">(?)</a>:</td>
<td>
<div id='telephoneNumber'>${user.telephoneNumber} <a href='' onclick="formEdit('telephoneNumber'); return false;">(edit)</a></div>
<div id='telephoneNumberForm' style='display: none'>
<form method='post' action='editUserAttribute'>
<input type='hidden' name='userName' value='${user.cn}'/>
<input type='hidden' name='attribute' value='telephoneNumber'/>
<input type='text' name='value' value='${user.telephoneNumber}'/>
<a href='editAccount' onclick="cancelEdit('telephoneNumber'); return false;">(cancel)</a>
</form>
</div>
</td>
</tr>
<tr>
<td>Postal Address <a href='' onClick="displayHelp('postalAddress'); return false;">(?)</a>:</td>
<td>
<div id='postalAddress'><pre>${user.postalAddress}</pre><a href='' onclick="formEdit('postalAddress'); return false;">(edit)</a></div>
<div id='postalAddressForm' style='display: none'>
<form method='post' action='editUserAttribute'>
<input type='hidden' name='userName' value='${user.cn}'/>
<input type='hidden' name='attribute' value='postalAddress'/>
<textarea name='value'>${user.postalAddress}</textarea>
<input type='submit' value='submit'/>
<a href='editAccount' onclick="cancelEdit('postalAddress'); return false;">(cancel)</a>
</form>
</div>
</td>
</tr>
<tr>
<td>Description <a href='' onClick="displayHelp('description'); return false;">(?)</a>:</td>
<td>
<div id='description'><pre>${user.description}</pre><a href='' onclick="formEdit('description'); return false;">(edit)</a></div>
<div id='descriptionForm' style='display: none'>
<form method='post' action='editUserAttribute'>
<input type='hidden' name='userName' value='${user.cn}'/>
<input type='hidden' name='attribute' value='description'/>
<textarea name='value'>${user.description}</textarea>
<input type='submit' value='submit'/>
<a href='editAccount' onclick="cancelEdit('description'); return false;">(cancel)</a>
</form>
</div>
</td>
</tr>
<tr>
<td>Password <a href='' onClick="displayHelp('password'); return false;">(?)</a>: </td>
<td><img src="static/images/status_approved.png" />
Valid <span class="edit-button"><a href="resetPassword">(change)</a></span>
</td>
</tr>
<tr>
<td>Account Status <a href='' onClick="displayHelp('accountStatus'); return false;">(?)</a>:</td>
<td><img src="static/images/status_approved.png" />
Approved, Active <span class="edit-button"><a href="#">(deactivate)</a></span>
</td>
</tr>
<tr>
<td>CLA <a href='' onClick="displayHelp('cla'); return false;">(?)</a>:</td>
<td py:if='claDone'><img src='static/images/status_approved.png'/> Done <a href="#">(?)</a></td>
<td py:if='not claDone'><img src='static/images/status_incomplete.png'/> Not Done <a href="#">(?)</a></td>
</tr>
<!-- <tr>
<td>Description:</td>
<td>
<div id="description_form" style="display: none"><form method='post' action='editUserAttribute'>
<input type='hidden' name='attribute' value='description'/>
<textarea name='value'>${user.description}</textarea>
<input type='submit' value='submit'/>
<a href='editAccount'>(Cancel)</a>
</form></div>
<div id='description_actual'>
<pre>${user.description}</pre>
</div>
<a href='#' onClick="toggle('description_form'); return false;">Edit</a>
</td>
<td py:if='not action == "description"'><pre>${user.description}</pre>
<span class="edit-button">
<a href="${tg.url('', action='description')}">(edit)</a>
</span>-
</td>
</tr>-->
</tbody>
</table>
<h2 id="your-account-header-roles">Your Roles</h2>
<h2 py:if="groupsPending">Pending</h2>
<div id='gpShow' style='display: none'><a href='' onclick="blindDown('groupsPending'); fade('gpShow'); appear('gpHide'); return false;">Show</a></div>
<div id='gpHide'><a href='' onclick="blindUp('groupsPending'); fade('gpHide'); appear('gpShow'); return false;">Hide</a></div>
<div id='groupsPending'>
<ul class="tool-links">
<li py:for='group in groupsPending'><img src="static/images/status_incomplete.png"/> ${groupsPending[group].cn} <a href="${tg.url('editGroup', groupName=groupsPending[group].cn)}">(edit)</a></li>
</ul>
</div>
<h2 py:if="groups">Approved</h2>
<div id='gShow'><a href='' onclick="blindDown('groups'); fade('gShow'); appear('gHide'); return false;">Show</a></div>
<div id='gHide' style='display: none'><a href='' onclick="blindUp('groups'); fade('gHide'); appear('gShow'); return false;">Hide</a></div>
<div id='groups' style='display: none'>
<ul class="tool-links">
<li py:for='group in groups'><img src="static/images/status_approved.png"/> ${groups[group].cn} <a href="${tg.url('editGroup', groupName=groups[group].cn)}">(edit)</a></li>
</ul>
</div>
<h2>Misc</h2>
<table class="account-info your-account-role-info">
<tbody>
<tr>
<td>Status:</td>
<td><img src="static/images/status_approved.png" />
Approved, Active <a href="#">(edit)</a>
</td>
</tr><tr>
<td>Tools:</td>
<td>
<ul class="tool-links">
<li><a href="listGroup">Apply for new group ...</a></li>
<li><a href="invite">Invite a New Member ...</a></li>
<li><a href="#">View All Pending Membership Requests ...</a></li>
</ul>
</td>
</tr><tr>
<td>Queue:</td>
<td>
<ul class="queue-links">
<li><a href="#">Chewbacca D. Wookiee requests approval to join project as <strong>user</strong> ...</a></li>
<li><a href="#">Gaius Baltar request approval to upgrade from <strong>user</strong> to <strong>administrator</strong> ...</a></li>
<li><a href="#">Leia Organa requests approval to upgrade from <strong>user</strong> to <strong>sponsor</strong> ...</a></li>
</ul>
</td>
</tr>
</tbody>
</table>
<h2>Edit Account</h2>
${form(action='editAccountSubmit', method='post', value=value)}
</body>
</html>

View file

@ -1,88 +1,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'"
xmlns:mochi="MyUniqueMochiUri">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
<head>
<style type="text/css">
@import "/fas/static/css/fas.css";
@import '/fas/static/css/sortable_tables.css';
</style>
<title>Edit Group</title>
</head>
<body>
<script src="/fas/static/javascript/sortable_tables.js" type="text/javascript"></script>
<h1>My Status: ${me.fedoraRoleStatus}</h1>
<form py:if="'Not a Member' in me.fedoraRoleStatus" action='applyForGroup'>
<input type='hidden' name='groupName' value='${group.cn}'/>
<input type='text' name='requestField' value='Please let me join..'/>
<input type='submit' name='action' value='Join'/>
</form>
<a py:if="'Not a Member' not in me.fedoraRoleStatus" href="${tg.url('applyForGroup', groupName=group.cn, action='Remove')}">Remove me</a>
<h2>${group.cn}</h2>
<table>
<!-- <script language="JavaScript" type="text/JavaScript">
AutoCompleteManager${field_id} = new AutoCompleteManager('${field_id}',
'${text_field.field_id}', '${hidden_field.field_id}',
'${search_controller}', '${search_param}', '${result_name}',${str(only_suggest).lower()},
'${tg.url([tg.widgets, 'turbogears.widgets/spinner.gif'])}', ${complete_delay});
addLoadEvent(AutoCompleteManager${field_id}.initialize);
</script>
-->
<tr><td>Name</td><td>${group.cn}</td></tr>
<tr><td>Owner</td><td>${group.fedoraGroupOwner}</td></tr>
<tr><td>Type</td><td>${group.fedoraGroupType}</td></tr>
<tr><td>Needs Sponsor</td><td>${group.fedoraGroupNeedsSponsor}</td></tr>
<tr><td>Self Removal</td><td>${group.fedoraGroupUserCanRemove}</td></tr>
<tr><td>fedoraGroupJoinMsg</td><td>${group.fedoraGroupJoinMsg}</td></tr>
</table>
<h2 py:if='me.fedoraRoleStatus == "approved"'>Invite <a href='' onClick="displayHelp('inviteToGroup'); return false;">(?)</a></h2>
<span py:if='me.fedoraRoleStatus == "approved"'>${searchUserForm(action='modifyGroup', value=value, method='get')}</span>
<h2>Members</h2>
<span>
<!-- <form action='modifyGroup'>
<input type='hidden' name='groupName' value='${group.cn}'/>
<input type='text' name='userName'/>
<input type='submit' name='action' value='apply'/>
</form>-->
</span>
<table id='sortable_table' class='datagrid'>
<thead>
<tr><th mochi:format="str">Username</th><th>Sponsor</th><th mochi:format="str">Date Added</th><th>Date Approved</th><th mochi:format="str">Approval</th><th>Role Type</th><th py:if='me.fedoraRoleType == "administrator" or me.fedoraRoleType == "sponsor"'>Action</th><th></th></tr>
</thead>
<tr py:for="user in groups">
<td><a href='editAccount?userName=${user}'>${user}</a></td>
<td py:if='not(groups[user].fedoraRoleSponsor == "None")'><a href='editAccount?userName=${groups[user].fedoraRoleSponsor}'>${groups[user].fedoraRoleSponsor}</a></td>
<td py:if='groups[user].fedoraRoleSponsor == "None"'>${groups[user].fedoraRoleSponsor}</td>
<td>${groups[user].fedoraRoleCreationDate}</td>
<td>${groups[user].fedoraRoleApprovalDate}</td>
<td>${groups[user].fedoraRoleStatus}</td>
<td>${groups[user].fedoraRoleType}</td>
<!--<td>${groups[user].fedoraRoleDomain}</td>-->
<!-- This section includes all action items -->
<td py:if='me.fedoraRoleType == "administrator"'>
<a py:if="group.fedoraGroupNeedsSponsor.upper() == 'TRUE'" href="${tg.url('modifyGroup', groupName=groups[user].cn, userName=user, action='sponsor')}">Sponsor</a>
<a py:if="not group.fedoraGroupNeedsSponsor.upper() == 'TRUE' and groups[user].fedoraRoleStatus.lower() != 'approved'" href="${tg.url('modifyGroup', groupName=groups[user].cn, userName=user, action='sponsor')}">Approve</a>
<a href="${tg.url('modifyGroup', groupName=groups[user].cn, userName=user, action='remove')}">Delete</a>
<a href="${tg.url('modifyGroup', groupName=groups[user].cn, userName=user, action='upgrade')}">Upgrade</a>
<a href="${tg.url('modifyGroup', groupName=groups[user].cn, userName=user, action='downgrade')}">Downgrade</a> Suspend
</td>
<td py:if='me.fedoraRoleType == "sponsor" and not groups[user].fedoraRoleType == "administrator"'>
<a href="${tg.url('modifyGroup', groupName=groups[user].cn, userName=user, action='sponsor')}" py:if="group.fedoraGroupNeedsSponsor.upper() == 'TRUE'">Sponsor</a>
<a href="${tg.url('modifyGroup', groupName=groups[user].cn, userName=user, action='sponsor')}" py:if="not group.fedoraGroupNeedsSponsor.upper() == 'TRUE'">Approve</a>
<a href="${tg.url('modifyGroup', groupName=groups[user].cn, userName=user, action='remove')}">Delete</a>
<a py:if='groups[user].fedoraRoleType' href="${tg.url('modifyGroup', groupName=groups[user].cn, userName=user, action='upgrade')}">Upgrade</a>
<a href="${tg.url('modifyGroup', groupName=groups[user].cn, userName=user, action='downgrade')}">Downgrade</a> Suspend
<div py:if="'not' in '%s' % tg_flash and user in '%s' % tg_flash"> -- Error!</div>
</td>
</tr>
</table>
<h2>Edit Group</h2>
${form(action='editGroupSubmit', method='post', value=value)}
</body>
</html>

View file

@ -1,44 +1,49 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'"
xmlns:mochi="MyUniqueMochiUri">
py:extends="'master.kid'">
<head>
<title>Groups List</title>
</head>
<head>
<style type="text/css">
@import "/fas/static/css/fas.css";
@import '/fas/static/css/sortable_tables.css';
</style>
</head>
<body>
<body>
<h2>List (${search})</h2>
<script src="/fas/static/javascript/sortable_tables.js" type="text/javascript"></script>
<h1>List (${search})</h1>
<h3>Search Groups</h3>
<form method="GET">
<p>"*" is a wildcard (Ex: "cvs*")</p>
<div>
<input type="text" value="${search}" name="search" size="15 "/>
<input type="submit" value="Search" />
</div>
</form>
<form method='GET'>
Search <input type='text' value='${search}' name='search' size='15'/> (Ex: "cvs*")
</form>
<h3>Results</h3>
<ul class="letters">
<li py:for="letter in 'abcdefghijklmnopqrstuvwxyz'.upper()"><a href="?search=${letter}*">${letter}</a></li>
<li><a href="?search=*">All</a></li>
</ul>
<table>
<tr>
<td width='10' align='center' py:for="letter in 'abcdefghijklmnopqrstuvwxyz'.upper()">
<a href='?search=${letter}*'>${letter}</a>
</td>
<td><a href='?search=*'>All</a></td>
</tr>
</table>
<table py:if="groups" id='sortable_table' class='datagrid'>
<thead>
<tr><th mochi:format="str">Group</th><th mochi:format='istr'>Status</th></tr>
</thead>
<tr py:for="group in groups">
<td>${groups[group].cn} <a href="editGroup?groupName=${groups[group].cn}">(edit)</a>
<a href='' onClick="displayHelp('info'); return false;">(info)</a></td>
<td align='center'>
<a py:if="groups[group].cn in myGroups" href="${tg.url('editGroup', groupName=groups[group].cn)}"><img src="static/images/status_approved.png" border='0'/></a>
<a py:if="groups[group].cn not in myGroups" href="${tg.url('editGroup', groupName=groups[group].cn)}"><img src="static/images/status_incomplete.png" border='0'/></a>
</td>
</tr>
</table>
</body>
<table py:if="groups">
<thead>
<tr><th>Group</th><th>Description</th><th>Status</th></tr>
</thead>
<tbody>
<?python
keys = groups.keys()
keys.sort()
?>
<tr py:for="group in map(groups.get, keys)">
<td><a href="${tg.url('viewGroup', groupName=group.cn)}">${group.cn}</a></td>
<td>${group.fedoraGroupDesc}</td>
<td>
<a py:if="group.cn in myGroups" href="${tg.url('viewGroup', groupName=group.cn)}">
<span class="approved" py:if="myGroups[group.cn].fedoraRoleStatus.lower() == 'approved'">Approved</span>
<span class="unapproved" py:if="myGroups[group.cn].fedoraRoleStatus.lower() == 'unapproved'">Unapproved</span>
</a>
<a py:if="group.cn not in myGroups" href="${tg.url('viewGroup', groupName=group.cn)}"><span>Not a Member</span></a>
</td>
</tr>
</tbody>
</table>
</body>
</html>

View file

@ -1,28 +1,20 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'"
xmlns:mochi="MyUniqueMochiUri">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
<head>
<style type="text/css">
@import "/fas/static/css/fas.css";
@import '/fas/static/css/sortable_tables.css';
</style>
<title>Fedora Accounts System</title>
</head>
<body>
<script src="/fas/static/javascript/sortable_tables.js" type="text/javascript"></script>
<h2 py:if="'userID' in builds.userLink" id="your-account-header"><img src="static/images/header-icon_account.png" /> Recent Builds <a href='${builds.userLink}'>(Koji)</a></h2>
<table py:if="'userID' in builds.userLink" id='sortable_table' class='datagrid'>
<h2 py:if="'userID' in builds.userLink" class="accounts">Recent Builds <a href='${builds.userLink}'>(Koji)</a></h2>
<table py:if="'userID' in builds.userLink">
<thead>
<tr><th mochi:format='str'>Build</th><th mochi:format='date'>Build Date</th></tr>
<tr><th>Build</th><th>Build Date</th></tr>
</thead>
<!--<tr><td>Koji</td><td><a href='${builds.userLink}'>Build Info</a></td></tr>-->
<tr py:for="build in builds.builds">
<td>
<font py:if="'complete' in builds.builds[build]['title']" color='green'>${builds.builds[build]['title']}</font>
<font py:if="'failed' in builds.builds[build]['title']" color='red'>${builds.builds[build]['title']}</font>
<a href="${build}">(build)</a>
<span py:if="'complete' in builds.builds[build]['title']" class="approved"><a href="${build}">${builds.builds[build]['title']}</a></span>
<span py:if="'failed' in builds.builds[build]['title']" class="unapproved"><a href="${build}">${builds.builds[build]['title']}</a></span>
</td>
<td>${builds.builds[build]['pubDate']}</td>
</tr>

View file

@ -9,15 +9,16 @@
</head>
<body>
<h1>Invite a new community member!</h1>
<h2>Invite a new community member!</h2>
<form method='POST'>
To email: <input type='text' value='' name='target'/><br/>
From: ${user.mail}<br/>
Subject: Invitation to join the Fedora Team!<br/>
Message: Please come up with a better more inviting message.<br/>
<form method="POST">
<div>
To email: <input type='text' value='' name='target'/><br/>
From: ${user.mail}<br/>
Subject: Invitation to join the Fedora Team!<br/>
Message:
<pre>
${user.givenName} &le;<a href='mailto: ${user.mail}'>${user.mail}</a>&ge; has invited you to join the Fedora
${user.givenName} &lt;<a href='mailto: ${user.mail}'>${user.mail}</a>&gt; has invited you to join the Fedora
Project! We are a community of users and developers who produce a
complete operating system from entirely free and open source software
(FOSS). ${user.givenName} thinks that you have knowledge and skills
@ -33,8 +34,8 @@ very smart and talented people.
Fedora and FOSS are changing the world -- come be a part of it!
</pre>
<input type='submit'/>
<input type="submit" value="Send" />
</div>
</form>
</body>
</html>

View file

@ -1,118 +1,36 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://purl.org/kid/ns#">
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
<head>
<meta content="text/html; charset=UTF-8"
http-equiv="content-type" py:replace="''"/>
<title>Login</title>
<style type="text/css">
#loginBox
{
width: 30%;
margin: auto;
margin-top: 10%;
padding-left: 10%;
padding-right: 10%;
padding-top: 5%;
padding-bottom: 5%;
font-family: verdana;
font-size: 10px;
background-color: #eee;
border: 2px solid #ccc;
}
<head>
<title>Login to the Fedora Accounts System</title>
</head>
#loginBox h1
{
font-size: 42px;
font-family: "Trebuchet MS";
margin: 0;
color: #ddd;
}
<style type="text/css">
#content ul
{
list-style: square;
margin: 1ex 3ex;
}
</style>
#loginBox p
{
position: relative;
top: -1.5em;
padding-left: 4em;
font-size: 12px;
margin: 0;
color: #666;
}
#loginBox table
{
table-layout: fixed;
border-spacing: 0;
width: 100%;
}
#loginBox td.label
{
width: 33%;
text-align: right;
}
#loginBox td.field
{
width: 66%;
}
#loginBox td.field input
{
width: 100%;
}
#loginBox td.buttons
{
text-align: right;
}
</style>
</head>
<body>
<div id="loginBox">
<h1>Login</h1>
<p>${message}</p>
<form action="${previous_url}" method="POST">
<table>
<tr>
<td class="label">
<label for="user_name">User Name:</label>
</td>
<td class="field">
<input type="text" id="user_name" name="user_name"/>
</td>
</tr>
<tr>
<td class="label">
<label for="password">Password:</label>
</td>
<td class="field">
<input type="password" id="password" name="password"/>
</td>
</tr>
<tr>
<td colspan="2" class="buttons">
<input type="submit" name="login" value="Login"/>
</td>
</tr>
<tr>
<td align='right'><a href='resetPassword'>Forgot Password?</a></td>
</tr>
<tr>
<td align='right'><a href='signUp'>Sign Up</a></td>
</tr>
</table>
<input py:if="forward_url" type="hidden" name="forward_url"
value="${forward_url}"/>
<input py:for="name,value in original_parameters.items()"
type="hidden" name="${name}" value="${value}"/>
</form>
</div>
</body>
<body>
<h2>Login</h2>
<p>${message}</p>
<form action="${previous_url}" method="POST">
<ul>
<li><label for="user_name">User Name:</label> <input type="text" id="user_name" name="user_name" /></li>
<li><label for="password">Password:</label> <input type="password" id="password" name="password" /></li>
<li>
<input type="submit" name="login" value="Login" />
<input py:if="forward_url" type="hidden" name="forward_url" value="${tg.url(forward_url)}" />
<input py:for="name,value in original_parameters.items()" type="hidden" name="${name}" value="${value}" />
</li>
</ul>
</form>
<ul>
<li><a href="resetPassword">Forgot Password?</a></li>
<li><a href="signUp">Sign Up</a></li>
</ul>
</body>
</html>

View file

@ -2,37 +2,21 @@
<?python import sitetemplate ?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="sitetemplate">
<head py:match="item.tag=='{http://www.w3.org/1999/xhtml}head'" py:attrs="item.items()">
<meta content="text/html; charset=UTF-8" http-equiv="content-type" py:replace="''"/>
<title py:replace="''">Your title goes here</title>
<head py:match="item.tag=='{http://www.w3.org/1999/xhtml}head'" py:attrs="item.items()">
<title py:replace="''">Title</title>
<link href="${tg.url('/static/css/style.css')}" rel="stylesheet" type="text/css" />
<meta py:replace="item[:]"/>
<style type="text/css">
#pageLogin
{
font-size: 10px;
font-family: verdana;
text-align: right;
}
</style>
<style type="text/css" media="screen">
@import "/fas/static/css/style.css";
</style>
<script src="/fas/static/javascript/MochiKit.js" type="text/javascript"></script>
<script src="/fas/static/javascript/New.js" type="text/javascript"></script>
</head>
</head>
<body py:match="item.tag=='{http://www.w3.org/1999/xhtml}body'" py:attrs="item.items()">
<body py:match="item.tag=='{http://www.w3.org/1999/xhtml}body'" py:attrs="item.items()">
<div id="wrapper">
<div id="head">
<h1><a href="/">Fedora</a></h1>
<div py:if="tg_flash" class="flash" id='flashMessage'>
${tg_flash} <a href='' onClick="squish('flashMessage'); return false;">(hide)</a>
</div>
<div id="searchbox">
<form action="" method="get">
<label for="q">Search:</label>
<input type="text" name="q" id="q"/>
<input type="submit" value="Search"/>
<input type="text" name="q" id="q" />
<input type="submit" value="Search" />
</form>
</div>
</div>
@ -49,74 +33,50 @@
<div id="infobar">
<div id="authstatus">
<span py:if="not tg.identity.anonymous">
<strong>Logged in: </strong>${tg.identity.user.user_name}.
<strong>Logged in:</strong> ${tg.identity.user.user_name}
</span>
</div>
<div id="control">
<ul>
<li py:if="not tg.identity.anonymous"><a href="editAccount">My Account</a></li>
<li py:if="not tg.identity.anonymous"><a href="logout">Log Out</a></li>
<li py:if="tg.identity.anonymous"><a href="login">Log In</a></li>
<li py:if="not tg.identity.anonymous"><a href="${tg.url('viewAccount')}">My Account</a></li>
<li py:if="not tg.identity.anonymous"><a href="${tg.url('logout')}">Log Out</a></li>
<li py:if="tg.identity.anonymous"><a href="${tg.url('login')}">Log In</a></li>
</ul>
</div>
</div>
<div id="main">
<div id="sidebar">
<ul>
<li class="first"><a href="listGroup">Group List</a></li>
<li class="first"><a href="${tg.url('listGroup')}">Group List</a></li>
<li py:if="'accounts' in tg.identity.groups"><a href="listUser">User List</a></li>
<li><a href="http://fedoraproject.org/wiki/FWN/LatestIssue">News</a></li>
<li><a href="listGroup?search=A*">Apply For a new Group</a></li>
<li><a href="${tg.url('listGroup', search='A*')}">Apply For a new Group</a></li>
</ul>
</div>
<!-- </div>
</div>-->
<div id='content'>
<div py:if="tg_flash" class="flash">
${tg_flash}
</div>
<div py:replace="[item.text]+item[:]" />
</div> <!-- End main -->
<div id="footer">
<ul id="footlinks">
<li class="first"><a href="/">About</a></li>
<li><a href="/">Contact Us</a></li>
<li><a href="/">Legal &amp; Privacy</a></li>
<!-- <div py:if="tg.config('identity.on',False) and not 'logging_in' in locals()"
id="pageLogin">
<span py:if="tg.identity.anonymous">
<a href="${tg.url('/login')}">Login</a>
</span>
<span py:if="not tg.identity.anonymous">
Welcome ${tg.identity.user.user_name}.
<a href="${tg.url('/logout')}">Logout</a>
</span>
</div>-->
<!-- <div id="header">&nbsp;</div>
<div id="main_content">-->
<div id='content'>
<div class="help" id='helpMessageMain' style='display: none'>
<div id='helpMessage'>
Help! What is interesting about this piece of help is that it's really long. I wonder if it will word wrap? That is so f'ing beautiful. You have NO idea.
</div>
<a href='' onClick="squish('helpMessageMain'); return false;">(hide)</a>
<script src="/fas/static/javascript/forms.js" type="text/javascript"></script>
<li><a href="/">Site Map</a></li>
<li><a href="/">Log Out</a></li>
</ul>
<p class="copy">
Copyright &copy; 2007 Red Hat, Inc. and others. All Rights Reserved.
Please send any comments or corrections to the <a href="mailto:webmaster@fedoraproject.org">websites team</a>.
</p>
<p class="disclaimer">
The Fedora Project is maintained and driven by the community and sponsored by Red Hat. This is a community maintained site. Red Hat is not responsible for content.
</p>
</div>
<!--<div py:if="tg_flash" class="flash" id='flashMessage'>
${tg_flash} <a href='' onClick="squish('flashMessage'); return false;">(hide)</a>
</div>-->
<div py:replace="[item.text]+item[:]"/>
<!-- End of content -->
</div>
</div> <!-- End main -->
<div id="footer"> <img src="/static/images/under_the_hood_blue.png" alt="TurboGears under the hood" />
<p>TurboGears is a open source front-to-back web development
framework written in Python</p>
<p>Copyright &copy; 2006 Kevin Dangoor</p>
</div>
</div> <!-- End wrapper -->
</body>
</div>
</div> <!-- End wrapper -->
</body>
</html>

View file

@ -1,28 +1,30 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'">
<head>
<style type="text/css">
@import "/fas/static/css/fas.css";
</style>
</head>
<body>
<span py:if="tg.identity.anonymous">
<form method='post'>
Username: <input type='text' name='userName'/><br/>
Primary Email: <input type='password' name='mail'/><br/>
<input type='submit'/>
</form>
</span>
<span py:if=" not tg.identity.anonymous">
<form method='post'>
New password for ${tg.identity.user.user_name}<br/>
New Password: <input type='password' name='password'/><br/>
Verify Password: <input type='password' name='passwordCheck'/>
<input type='submit'/>
</form>
</span>
</body>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
<head>
<title>Reset Password</title>
</head>
<body>
<h2>Reset Password</h2>
<div py:if="tg.identity.anonymous" py:strip="">
<form method="post">
<ul>
<li><label for="userName">Username:</label> <input type="text" id="userName" name="userName" /></li>
<li><label for="mail">Primary Email:</label> <input type="password" id="mail" name="mail" /></li>
<li><input type="submit" value="Reset Password" /></li>
</ul>
</form>
</div>
<div py:if="not tg.identity.anonymous" py:strip="">
<p>
New password for ${tg.identity.user.user_name}
</p>
<form method="post">
<ul>
<li><label for="password">New Password:</label> <input type="password" name="password" /></li>
<li><label for="password">Verify Password:</label> <input type="password" name="passwordCheck" /></li>
<li><input type="submit" /></li>
</ul>
</form>
</div>
</body>
</html>

View file

@ -1,28 +1,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#"
py:extends="'master.kid'">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://purl.org/kid/ns#" py:extends="'master.kid'">
<head>
<style type="text/css">
@import "/static/css/fas.css";
</style>
<title>Sign up for a Fedora account</title>
</head>
<body>
<script src="/fas/static/javascript/forms.js" type="text/javascript"></script>
<!--
<form action='newAccountSubmit' method='post'>
<table>
<tr><td>username:</td><td><input type='text' name='cn'/></td></tr>
<tr><td>Real Name:</td><td><input type='text' name='givenName'/></td></tr>
<tr><td>email:</td><td><input type='text' name='mail'/></td></tr>
<tr><td>Telephone Number:</td><td><input type='text' name='telephoneNumber'/></td></tr>
<tr><td>Postal Address:</td><td><textarea name='postalAddress'></textarea></td></tr>
<tr><td><input type='submit'/></td><td></td></tr>
</table>
</form>-->
${form(action='newAccountSubmit', method='post')}
<h2>Sign up for a Fedora account</h2>
${form(action='newAccountSubmit', method='post')}
</body>
</html>

View file

@ -4,35 +4,44 @@
xmlns:mochi="MyUniqueMochiUri">
<head>
<style type="text/css">
@import "/fas/static/css/fas.css";
@import '/fas/static/css/sortable_tables.css';
</style>
<title>Users List</title>
</head>
<body>
<script src="/fas/static/javascript/sortable_tables.js" type="text/javascript"></script>
<h2>List (${search})</h2>
<h1>List (${search})</h1>
<form method='GET'>
Search <input type='text' name='search' value='${search}' size='15'/> (Ex: "mmcg*")
<form method="GET">
<p>"*" is a wildcard (Ex: "cvs*")</p>
<div>
<input type="text" value="${search}" name="search" size="15 "/>
<input type="submit" value="Search" />
</div>
</form>
<h3>Results</h3>
<ul class="letters">
<li py:for="letter in 'abcdefghijklmnopqrstuvwxyz'.upper()"><a href="?search=${letter}*">${letter}</a></li>
<li><a href="?search=*">All</a></li>
</ul>
<table>
<tr>
<td width='10' align='center' py:for="letter in 'abcdefghijklmnopqrstuvwxyz'.upper()">
<a href='?search=${letter}*'>${letter}</a>
</td>
<td><a href='?search=*'>All</a></td>
</tr>
</table>
<table id='sortable_table' class='datagrid'>
<thead>
<tr><th mochi:format="str">Username</th></tr>
<tr>
<th>Username</th>
<th>Account Status</th>
</tr>
</thead>
<tr py:for="item in printList">
<td>${item} <a href="editAccount?userName=${item}">(edit)</a></td>
<tbody>
<?python
users.sort()
?>
<tr py:for="user in users">
<td><a href="editAccount?userName=${user}">${user}</a></td>
<td>
<span py:if='claDone[user]' class="approved"> Done</span>
<span py:if='not claDone[user]' class="unapproved"> Done</span>
</td>
</tr>
</tbody>
</table>
</body>

View file

@ -2,12 +2,16 @@
#it is based on the inetOrgPerson shema, but has some spicific
#attribues added onto it for use by the Account system
#for now this is the contents
#sshkey bugzillaemail
#sshkey bugzillaemail ircNick approvalStatus creationDate
dn: cn=schema
attributeTypes: ( 2.5.444.8 NAME 'sshkey' DESC 'ssh key for this member' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
attributeTypes: ( 2.5.444.9 NAME 'bugzillaemail' DESC 'members preferred bugzilla email address' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
attributeTypes: ( 2.5.444.8 NAME 'fedoraPersonSshKey' DESC 'ssh key for this member' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{4096} SINGLE-VALUE)
attributeTypes: ( 2.5.444.9 NAME 'fedoraPersonBugzillaMail' DESC 'members preferred bugzilla email address' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
attributeTypes: ( 2.5.444.16 NAME 'fedoraPersonIrcNick' DESC 'irc nick of the user on freenode' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{100} )
attributetypes: ( 2.5.444.17 NAME 'fedoraPersonCreationDate' DESC 'date entry was created' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
attributeTypes: ( 2.5.444.18 NAME 'fedoraPersonApprovalStatus' DESC 'users approval status' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
attributeTypes: ( 2.5.444.19 NAME 'fedoraPersonKeyId' DESC 'users GPG key ID' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
# fedoraPerson
# The fedoraPerson represents people who are a member of the fedora project
# in some way. It is a structural class and inherits
# from the inetOrgPerson class
objectclasses: ( 2.5.555.1 NAME 'fedoraPerson' DESC 'A member of the fedoraproject group' SUP inetOrgPerson STRUCTURAL MUST ( sshkey $ bugzillaemail ) )
objectClasses: ( 2.5.555.1 NAME 'fedoraPerson' DESC 'A member of the fedoraproject group' SUP inetOrgPerson STRUCTURAL MUST ( fedoraPersonSshKey $ mail $ fedoraPersonCreationDate ) MAY (fedoraPersonIrcNick $ fedoraPersonApprovalStatus $ fedoraPersonBugzillaMail $ fedoraPersonKeyId ) )

View file

@ -12,5 +12,6 @@ attributeTypes: ( 2.5.444.11 NAME 'fedoraGroupType' DESC 'the type of group' EQU
attributeTypes: ( 2.5.444.12 NAME 'fedoraGroupNeedsSponsor' DESC 'boolean indicating whether or not the group needs a sponsor' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )
attributeTypes: ( 2.5.444.13 NAME 'fedoraGroupUserCanRemove' DESC 'boolean indicating whether or not the user can remove the group' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )
attributeTypes: ( 2.5.444.14 NAME 'fedoraGroupJoinMsg' DESC 'message received upon joining the group' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1000} )
attributeTypes: ( 2.5.444.21 NAME 'fedoraGroupDesc' DESC 'group description' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{100} )
attributeTypes: ( 2.5.444.20 NAME 'fedoraGroupRequires' DESC 'Requisites of this Group' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{50} )
objectClasses: ( 2.5.555.3 NAME 'fedoraGroup' DESC 'A object describing a group entry' STRUCTURAL MUST ( cn $ fedoraGroupOwner ) MAY ( fedoraGroupJoinMsg $ fedoraGroupUsercanRemove $ fedoraGroupType $ fedoraGroupNeedsSponsor $ fedoraGroupUserCanRemove $ fedoraGroupRequires ) )
objectClasses: ( 2.5.555.3 NAME 'fedoraGroup' DESC 'A object describing a group entry' STRUCTURAL MUST ( cn $ fedoraGroupDesc $ fedoraGroupOwner ) MAY ( fedoraGroupJoinMsg $ fedoraGroupUsercanRemove $ fedoraGroupType $ fedoraGroupNeedsSponsor $ fedoraGroupUserCanRemove $ fedoraGroupRequires ) )