├── __init__.py ├── cron ├── crontab └── crontab.example ├── static ├── 403.html ├── 404.html ├── 500.html ├── uploads │ └── readme.txt ├── css │ ├── statistics.css │ ├── border-h.gif │ ├── border-v.gif │ ├── jquery.awesome-cropper.css │ ├── imgareaselect-default.css │ ├── floatfixed.css │ ├── tela-login-registro.css │ ├── base.grey.css │ ├── calendar.css │ ├── team.css │ ├── card_modal.css │ ├── home-syle.css │ ├── web2py_bootstrap_nojs.css │ └── user.css ├── img │ ├── logo.png │ ├── clear.png │ ├── images1.png │ ├── loading.gif │ ├── select2.png │ ├── cor_fundo.png │ ├── select2x2.png │ ├── ajax-loader.gif │ ├── breadcrumb.png │ ├── menu-active.png │ ├── scrumfor-me.png │ ├── scrum_screen1.png │ ├── scrum_screen2.png │ ├── scrum_screen3.png │ ├── scrumformelogo.png │ ├── no-image_project.jpg │ ├── select2-spinner.gif │ ├── serach_icon_gray.png │ ├── wild_oliva_light.png │ ├── agenciax4-signature.png │ ├── glyphicons-halflings.png │ ├── glyphicons-halflings-white.png │ └── login_register_background.png ├── audio │ ├── notify.mp3 │ ├── notify.ogg │ └── notify.wav ├── font │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff ├── fonts │ ├── playball.eot │ ├── playball.ttf │ ├── playball.woff │ ├── Elusive-Icons.eot │ ├── Elusive-Icons.ttf │ └── Elusive-Icons.woff ├── images │ ├── facebook.png │ ├── favicon.ico │ ├── favicon.png │ ├── gplus-32.png │ ├── twitter.png │ ├── scrumfor-me.png │ ├── glyphicons-halflings.png │ └── glyphicons-halflings-white.png └── js │ ├── delete_project.js │ ├── board-livesearch.js │ ├── tela-login-registro.js │ ├── jquery.ui.touch-punch.min.js │ ├── web2py_bootstrap.js │ ├── jquery.livesearch.js │ ├── board-editable.js │ ├── bootstrap-custom.min.js │ ├── highcharts │ ├── modules │ │ ├── funnel.js │ │ └── data.js │ ├── themes │ │ ├── skies.js │ │ ├── grid.js │ │ ├── dark-green.js │ │ ├── dark-blue.js │ │ └── gray.js │ └── adapters │ │ ├── mootools-adapter.js │ │ └── prototype-adapter.js │ ├── team.js │ ├── floatfixed.js │ ├── share.js │ ├── bootstrap-custom-modal.min.js │ ├── sprints.js │ ├── board-card.js │ ├── realtime.js │ ├── date.format.js │ ├── sprints-modal.js │ ├── base.js │ └── dd_belatedpng.js ├── views ├── __init__.py ├── default │ ├── nojs.html │ ├── breadcrumb.html │ ├── load_tasks.html │ ├── statistics.html │ ├── projects.html │ ├── project_info.html │ ├── check_your_email.html │ ├── chat.html │ ├── team.html │ ├── header.html │ ├── sprints.html │ └── card.html ├── generic.json ├── generic.xml ├── generic.pdf ├── generic.rss ├── generic.html ├── generic.jsonp ├── generic.ics ├── web2py_ajax.html ├── generic.load ├── reset_password.html ├── verify_email.html ├── invite_project_email.html └── generic.map ├── modules ├── __init__.py ├── data_config.py ├── realtime.py ├── convertImage.py └── gravatar.py ├── ABOUT ├── LICENSE ├── controllers └── setup.py ├── languages ├── plural-en.py ├── plural-ru.py ├── plural-uk.py ├── plural-cs.py └── default.py ├── .gitignore ├── package.json ├── models ├── 15_my_field_properties.py ├── 05_auth_settings.py ├── 00_db.py └── 10_define_my_own_tables.py ├── Gruntfile.js └── README.md /__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cron/crontab: -------------------------------------------------------------------------------- 1 | #crontab -------------------------------------------------------------------------------- /static/403.html: -------------------------------------------------------------------------------- 1 | 403 2 | -------------------------------------------------------------------------------- /static/404.html: -------------------------------------------------------------------------------- 1 | 404 2 | -------------------------------------------------------------------------------- /static/500.html: -------------------------------------------------------------------------------- 1 | 500 2 | -------------------------------------------------------------------------------- /views/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cron/crontab.example: -------------------------------------------------------------------------------- 1 | #crontab -------------------------------------------------------------------------------- /modules/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /views/default/nojs.html: -------------------------------------------------------------------------------- 1 |

{{=message}}

-------------------------------------------------------------------------------- /static/uploads/readme.txt: -------------------------------------------------------------------------------- 1 | here's all the pictures thumbnails -------------------------------------------------------------------------------- /ABOUT: -------------------------------------------------------------------------------- 1 | Write something about this app. 2 | Developed with web2py. 3 | -------------------------------------------------------------------------------- /static/css/statistics.css: -------------------------------------------------------------------------------- 1 | #all_content { 2 | background-color: #fff; 3 | } -------------------------------------------------------------------------------- /views/generic.json: -------------------------------------------------------------------------------- 1 | {{from gluon.serializers import json}}{{=XML(json(response._vars))}} 2 | -------------------------------------------------------------------------------- /static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/logo.png -------------------------------------------------------------------------------- /static/img/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/clear.png -------------------------------------------------------------------------------- /static/img/images1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/images1.png -------------------------------------------------------------------------------- /static/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/loading.gif -------------------------------------------------------------------------------- /static/img/select2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/select2.png -------------------------------------------------------------------------------- /views/generic.xml: -------------------------------------------------------------------------------- 1 | {{from gluon.serializers import xml}}{{=XML(xml(response._vars,quote=False))}} 2 | -------------------------------------------------------------------------------- /static/audio/notify.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/audio/notify.mp3 -------------------------------------------------------------------------------- /static/audio/notify.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/audio/notify.ogg -------------------------------------------------------------------------------- /static/audio/notify.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/audio/notify.wav -------------------------------------------------------------------------------- /static/css/border-h.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/css/border-h.gif -------------------------------------------------------------------------------- /static/css/border-v.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/css/border-v.gif -------------------------------------------------------------------------------- /static/img/cor_fundo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/cor_fundo.png -------------------------------------------------------------------------------- /static/img/select2x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/select2x2.png -------------------------------------------------------------------------------- /static/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/font/FontAwesome.otf -------------------------------------------------------------------------------- /static/fonts/playball.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/fonts/playball.eot -------------------------------------------------------------------------------- /static/fonts/playball.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/fonts/playball.ttf -------------------------------------------------------------------------------- /static/fonts/playball.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/fonts/playball.woff -------------------------------------------------------------------------------- /static/images/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/images/facebook.png -------------------------------------------------------------------------------- /static/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/images/favicon.ico -------------------------------------------------------------------------------- /static/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/images/favicon.png -------------------------------------------------------------------------------- /static/images/gplus-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/images/gplus-32.png -------------------------------------------------------------------------------- /static/images/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/images/twitter.png -------------------------------------------------------------------------------- /static/img/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/ajax-loader.gif -------------------------------------------------------------------------------- /static/img/breadcrumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/breadcrumb.png -------------------------------------------------------------------------------- /static/img/menu-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/menu-active.png -------------------------------------------------------------------------------- /static/img/scrumfor-me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/scrumfor-me.png -------------------------------------------------------------------------------- /static/images/scrumfor-me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/images/scrumfor-me.png -------------------------------------------------------------------------------- /static/img/scrum_screen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/scrum_screen1.png -------------------------------------------------------------------------------- /static/img/scrum_screen2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/scrum_screen2.png -------------------------------------------------------------------------------- /static/img/scrum_screen3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/scrum_screen3.png -------------------------------------------------------------------------------- /static/img/scrumformelogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/scrumformelogo.png -------------------------------------------------------------------------------- /static/fonts/Elusive-Icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/fonts/Elusive-Icons.eot -------------------------------------------------------------------------------- /static/fonts/Elusive-Icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/fonts/Elusive-Icons.ttf -------------------------------------------------------------------------------- /static/fonts/Elusive-Icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/fonts/Elusive-Icons.woff -------------------------------------------------------------------------------- /static/img/no-image_project.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/no-image_project.jpg -------------------------------------------------------------------------------- /static/img/select2-spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/select2-spinner.gif -------------------------------------------------------------------------------- /static/img/serach_icon_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/serach_icon_gray.png -------------------------------------------------------------------------------- /static/img/wild_oliva_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/wild_oliva_light.png -------------------------------------------------------------------------------- /static/img/agenciax4-signature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/agenciax4-signature.png -------------------------------------------------------------------------------- /static/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /static/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /static/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /static/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /static/images/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/images/glyphicons-halflings.png -------------------------------------------------------------------------------- /static/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /static/img/login_register_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/img/login_register_background.png -------------------------------------------------------------------------------- /static/images/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolaborativa/scrumforme/HEAD/static/images/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The web2py welcome app is licensed under public domain 2 | (except for the css and js files that it includes, which have their own third party licenses). 3 | 4 | You can modify this license when you add your own code. 5 | -------------------------------------------------------------------------------- /modules/data_config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ## Authentication with Facebook 4 | 5 | FACEBOOK_ID = '' 6 | FACEBOOK_SECRET = '' 7 | 8 | ## Authentication for sending mail 9 | 10 | EMAIL_SERVER = 'smtp.gmail.com:587' 11 | CLIENT_EMAIL = 'you@gmail.com' 12 | CLIENT_LOGIN = 'username:password' -------------------------------------------------------------------------------- /static/js/delete_project.js: -------------------------------------------------------------------------------- 1 | // Delete project 2 | $('.delete_project').click(function(){ 3 | var project_id = $(this)[0].dataset['project']; 4 | var remove = confirm(msg.confirmRemove); 5 | if (remove){ 6 | window.location = url.delete_project + '?project_id=' + project_id; 7 | } 8 | }); 9 | -------------------------------------------------------------------------------- /modules/realtime.py: -------------------------------------------------------------------------------- 1 | def _update_card(element): 2 | from gluon.contrib.websocket_messaging import websocket_send 3 | import json 4 | # sending websocket message 5 | # js = "console.log('Here boy!!!')" 6 | data = json.dumps(element) 7 | print "novo" 8 | websocket_send('http://localhost:8888', element, 'mykey', 'mygroup') 9 | -------------------------------------------------------------------------------- /controllers/setup.py: -------------------------------------------------------------------------------- 1 | __author__ = 'Anna Cruz' 2 | 3 | 4 | def install(): 5 | ''' 6 | This is a function to populate role table before use the application 7 | :return: nothing 8 | ''' 9 | roles = ['Product Owner', 'Scrum Master', 'Team', 'Guest'] 10 | for role in roles: 11 | db.role.insert(name=role) 12 | return "" 13 | -------------------------------------------------------------------------------- /views/generic.pdf: -------------------------------------------------------------------------------- 1 | {{ 2 | import os 3 | from gluon.contrib.generics import pdf_from_html 4 | filename = '%s/%s.html' % (request.controller,request.function) 5 | if os.path.exists(os.path.join(request.folder,'views',filename)): 6 | html=response.render(filename) 7 | else: 8 | html=BODY(BEAUTIFY(response._vars)).xml() 9 | pass 10 | =pdf_from_html(html) 11 | }} 12 | -------------------------------------------------------------------------------- /languages/plural-en.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | { 3 | # "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], 4 | 'account': ['accounts'], 5 | 'book': ['books'], 6 | 'is': ['are'], 7 | 'man': ['men'], 8 | 'miss': ['misses'], 9 | 'person': ['people'], 10 | 'quark': ['quarks'], 11 | 'shop': ['shops'], 12 | 'this': ['these'], 13 | 'was': ['were'], 14 | 'woman': ['women'], 15 | } 16 | -------------------------------------------------------------------------------- /views/generic.rss: -------------------------------------------------------------------------------- 1 | {{ 2 | ### 3 | # response._vars contains the dictionary returned by the controller action 4 | # for this to work the action must return something like 5 | # 6 | # dict(title=...,link=...,description=...,created_on='...',items=...) 7 | # 8 | # items is a list of dictionaries each with title, link, description, pub_date. 9 | ### 10 | from gluon.serializers import rss}}{{=XML(rss(response._vars))}} 11 | -------------------------------------------------------------------------------- /static/css/jquery.awesome-cropper.css: -------------------------------------------------------------------------------- 1 | .awesome-cropper { 2 | } 3 | .awesome-cropper-drop-area { 4 | } 5 | .awesome-cropper .preview { 6 | } 7 | .awesome-cropper .modal, .awesome-cropper .modal.fade.in { 8 | /*width: 900px;*/ 9 | /*width: 60%;*/ 10 | /*margin-left: -450px;*/ 11 | /*margin-right: -480px;*/ 12 | /*top: 10%;*/ 13 | } 14 | .awesome-cropper .modal-body { 15 | max-height: none; 16 | /*width: 100%;*/ 17 | } 18 | 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # backup, log files and compiled sources 2 | *.*~ 3 | *.bak 4 | *.log 5 | *.ogv 6 | *.pyc 7 | *.swp 8 | *.avi 9 | 10 | # sqlite database files and web2py table structs 11 | *.sqlite 12 | *.table 13 | 14 | # web2py cache, errors and sessions files 15 | cache/* 16 | errors/* 17 | sessions/* 18 | 19 | # project ignored files 20 | static/uploads/*.png 21 | static/uploads/*.jpg 22 | static/uploads/*.gif 23 | static/uploads/*.txt 24 | 25 | # ide files 26 | .idea 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scrumforme", 3 | "version": "0.0.1", 4 | "description": "Scrumforme", 5 | "homepage": "http://scrumform.me", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/gustavox4ids/scrumforme" 9 | }, 10 | "engines": { 11 | "node": "0.10.x", 12 | "npm": "1.2.x" 13 | }, 14 | "devDependencies": { 15 | "grunt": "~0.4.1", 16 | "grunt-contrib-concat": "~0.3.0", 17 | } 18 | } -------------------------------------------------------------------------------- /views/default/breadcrumb.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 8 |
9 |
10 |
-------------------------------------------------------------------------------- /views/generic.html: -------------------------------------------------------------------------------- 1 | {{extend 'layout.html'}} 2 | {{""" 3 | 4 | You should not modify this file. 5 | It is used as default when a view is not provided for your controllers 6 | 7 | """}} 8 |

{{=' '.join(x.capitalize() for x in request.function.split('_'))}}

9 | {{if len(response._vars)==1:}} 10 | {{=BEAUTIFY(response._vars.values()[0])}} 11 | {{elif len(response._vars)>1:}} 12 | {{=BEAUTIFY(response._vars)}} 13 | {{pass}} 14 | {{if request.is_local:}} 15 | {{=response.toolbar()}} 16 | {{pass}} 17 | -------------------------------------------------------------------------------- /languages/plural-ru.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | { 3 | # "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], 4 | 'выбрана': ['выбраны','выбрано'], 5 | 'запись': ['записи','записей'], 6 | 'изменена': ['изменены','изменено'], 7 | 'строка': ['строки','строк'], 8 | 'удалена': ['удалены','удалено'], 9 | 'день': ['дня', 'дней'], 10 | 'месяц': ['месяца','месяцев'], 11 | 'неделю': ['недели','недель'], 12 | 'год': ['года','лет'], 13 | 'час': ['часа','часов'], 14 | 'минуту': ['минуты','минут'], 15 | 'секунду': ['секунды','секунд'], 16 | } 17 | -------------------------------------------------------------------------------- /views/generic.jsonp: -------------------------------------------------------------------------------- 1 | {{ 2 | ### 3 | # response._vars contains the dictionary returned by the controller action 4 | ### 5 | try: 6 | from gluon.serializers import json 7 | result = "%s(%s)" % (request.vars['callback'], json(response._vars)) 8 | response.write(result, escape=False) 9 | response.headers['Content-Type'] = 'application/jsonp' 10 | except (TypeError, ValueError): 11 | raise HTTP(405, 'JSON serialization error') 12 | except ImportError: 13 | raise HTTP(405, 'JSON not available') 14 | except: 15 | raise HTTP(405, 'JSON error') 16 | }} -------------------------------------------------------------------------------- /views/generic.ics: -------------------------------------------------------------------------------- 1 | {{ 2 | ### 3 | # response._vars contains the dictionary returned by the controller action 4 | # Assuming something like: 5 | # 6 | # db.define_table('event', 7 | # Field('title'), 8 | # Field('start_datetime','datetime'), 9 | # Field('stop_datetime','datetime')) 10 | # events = db(db.event).select() 11 | # 12 | # Aor this to work the action must return something like 13 | # 14 | # dict(events=events, title='title',link=URL('action'),timeshift=0) 15 | # 16 | ### 17 | from gluon.serializers import ics}}{{=XML(ics(**response._vars))}} 18 | -------------------------------------------------------------------------------- /languages/plural-uk.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | { 3 | # "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], 4 | 'байт': ['байти','байтів'], 5 | 'годину': ['години','годин'], 6 | 'елемент': ['елементи','елементів'], 7 | 'запис': ['записи','записів'], 8 | 'поцілювання': ['поцілювання','поцілювань'], 9 | 'рядок': ['рядки','рядків'], 10 | 'секунду': ['секунди','секунд'], 11 | 'схибнення': ['схибнення','схибнень'], 12 | 'хвилину': ['хвилини','хвилин'], 13 | 'день': ['дні', 'днів'], 14 | 'місяць': ['місяці','місяців'], 15 | 'тиждень': ['тижні','тижнів'], 16 | 'рік': ['роки','років'], 17 | } 18 | -------------------------------------------------------------------------------- /modules/convertImage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ## Convert string Base64 Images 4 | 5 | def convertBase64String(base64Img,uploadfolder): 6 | if base64Img.startswith("data:image/png;base64,"): 7 | import base64 8 | import random 9 | base64Img = base64Img[22:] 10 | image = base64.b64decode(base64Img) 11 | filename = "projects_thumbnail_%s%s.png" %(random.random(), random.random()) 12 | 13 | with open(uploadfolder+filename, 'wb') as imgFile: 14 | imgFile.write(image) 15 | 16 | return filename 17 | 18 | else: 19 | return False -------------------------------------------------------------------------------- /models/15_my_field_properties.py: -------------------------------------------------------------------------------- 1 | Project.name.requires=IS_NOT_EMPTY(error_message=T('The field name can not be empty!')) 2 | Sprint.name.requires=IS_NOT_EMPTY(error_message=T('The field name can not be empty!')) 3 | Sprint.weeks.requires=IS_NOT_EMPTY(error_message=T('Choose how many weeks for your sprint!')) 4 | Story.title.requires=IS_NOT_EMPTY(error_message=T('This field can not be empty!')) 5 | Story.benefit.requires=IS_NOT_EMPTY(error_message=T('This field can not be empty!')) 6 | Story.story_points.requires=IS_NOT_EMPTY(error_message=T('This field can not be empty!')) 7 | Definition_ready.title.requires=IS_NOT_EMPTY(error_message=T('This field can not be empty!')) 8 | -------------------------------------------------------------------------------- /languages/plural-cs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | { 3 | # "singular form (0)": ["first plural form (1)", "second plural form (2)", ...], 4 | 'vteřina': ['vteřiny', 'vteřin'], 5 | 'vteřinou': ['vteřinami', 'vteřinami'], 6 | 'minuta': ['minuty', 'minut'], 7 | 'minutou': ['minutami', 'minutami'], 8 | 'hodina': ['hodiny','hodin'], 9 | 'hodinou': ['hodinami','hodinami'], 10 | 'den': ['dny','dnů'], 11 | 'dnem': ['dny','dny'], 12 | 'týden': ['týdny','týdnů'], 13 | 'týdnem': ['týdny','týdny'], 14 | 'měsíc': ['měsíce','měsíců'], 15 | 'měsícem': ['měsíci','měsíci'], 16 | 'rok': ['roky','let'], 17 | 'rokem': ['roky','lety'], 18 | 'záznam': ['záznamy', 'záznamů'], 19 | 'soubor': ['soubory', 'souborů'] 20 | } 21 | -------------------------------------------------------------------------------- /static/js/board-livesearch.js: -------------------------------------------------------------------------------- 1 | // livesearch 2 | $('input[name="livesearch"]').search('.task', function(on) { 3 | var nofound = $('#nothingfound'), 4 | td = $('.table td'), 5 | ul = $('.table ul'); 6 | 7 | on.reset(function(ui) { 8 | nofound.hide(); 9 | td.show(); 10 | ul.show(); 11 | }); 12 | 13 | on.empty(function() { 14 | nofound.show(); 15 | td.hide(); 16 | ul.hide(); 17 | }); 18 | 19 | on.results(function(results) { 20 | nofound.hide(); 21 | td.hide(); 22 | ul.hide(); 23 | $(results).closest("td").show(); 24 | $(results).closest("ul").show(); 25 | $(results).closest("tr").find("td").show(); 26 | }); 27 | }); -------------------------------------------------------------------------------- /views/web2py_ajax.html: -------------------------------------------------------------------------------- 1 | 8 | {{ 9 | response.files.insert(0,URL('static','js/jquery.js')) 10 | response.files.insert(1,URL('static','css/calendar.css')) 11 | response.files.insert(2,URL('static','js/calendar.js')) 12 | response.files.insert(3,URL('static','js/web2py.js')) 13 | response.include_meta() 14 | response.include_files() 15 | }} 16 | -------------------------------------------------------------------------------- /static/js/tela-login-registro.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded", tudo); 2 | function tudo(){ 3 | document.getElementById("login_index").addEventListener("click", mostra_login) 4 | document.getElementById("registro_index").addEventListener("click", mostra_registro) 5 | } 6 | function mostra_login(){ 7 | document.getElementById("registro").style.display = "none" 8 | document.getElementById("entrar").style.display = "block" 9 | document.getElementById("login_index").style.background = "#34abbd" 10 | document.getElementById("registro_index").style.background = "#197a8b" 11 | } 12 | function mostra_registro(){ 13 | document.getElementById("entrar").style.display = "none" 14 | document.getElementById("registro").style.display = "block" 15 | document.getElementById("login_index").style.background = "#197a8b" 16 | document.getElementById("registro_index").style.background = "#34abbd" 17 | } -------------------------------------------------------------------------------- /static/css/imgareaselect-default.css: -------------------------------------------------------------------------------- 1 | /* 2 | * imgAreaSelect default style 3 | */ 4 | 5 | .imgareaselect-border1 { 6 | background: url(border-v.gif) repeat-y left top; 7 | } 8 | 9 | .imgareaselect-border2 { 10 | background: url(border-h.gif) repeat-x left top; 11 | } 12 | 13 | .imgareaselect-border3 { 14 | background: url(border-v.gif) repeat-y right top; 15 | } 16 | 17 | .imgareaselect-border4 { 18 | background: url(border-h.gif) repeat-x left bottom; 19 | } 20 | 21 | .imgareaselect-border1, .imgareaselect-border2, 22 | .imgareaselect-border3, .imgareaselect-border4 { 23 | filter: alpha(opacity=50); 24 | opacity: 0.5; 25 | } 26 | 27 | .imgareaselect-handle { 28 | background-color: #fff; 29 | border: solid 1px #000; 30 | filter: alpha(opacity=50); 31 | opacity: 0.5; 32 | } 33 | 34 | .imgareaselect-outer { 35 | background-color: #000; 36 | filter: alpha(opacity=50); 37 | opacity: 0.5; 38 | } 39 | 40 | .imgareaselect-selection { 41 | } -------------------------------------------------------------------------------- /views/generic.load: -------------------------------------------------------------------------------- 1 | {{''' 2 | # License: Public Domain 3 | # Author: Iceberg at 21cn dot com 4 | 5 | With this generic.load file, you can use same function to serve two purposes. 6 | 7 | = regular action 8 | - ajax callback (when called with .load) 9 | 10 | Example modified from http://www.web2py.com/AlterEgo/default/show/252: 11 | 12 | def index(): 13 | return dict( 14 | part1='hello world', 15 | part2=LOAD(url=URL(r=request,f='auxiliary.load'),ajax=True)) 16 | 17 | def auxiliary(): 18 | form=SQLFORM.factory(Field('name')) 19 | if form.accepts(request.vars): 20 | response.flash = 'ok' 21 | return dict(message="Hello %s" % form.vars.name) 22 | return dict(form=form) 23 | 24 | Notice: 25 | 26 | - no need to set response.headers['web2py-response-flash'] 27 | - no need to return a string 28 | even if the function is called via ajax. 29 | 30 | '''}}{{if len(response._vars)==1:}}{{=response._vars.values()[0]}}{{else:}}{{=BEAUTIFY(response._vars)}}{{pass}} -------------------------------------------------------------------------------- /static/css/floatfixed.css: -------------------------------------------------------------------------------- 1 | #back-top { 2 | background-color: #222236; 3 | background-color: rgba(0, 0, 0, 0.3); 4 | color: #fff; 5 | font-size: 18px; 6 | width: 40px; 7 | height: 40px; 8 | text-align: center; 9 | line-height: 40px; 10 | position: fixed; 11 | bottom: 60px; 12 | right: 20px; 13 | display: none; 14 | overflow: hidden; 15 | z-index: 1000; 16 | -webkit-border-radius: 20px; 17 | -webkit-background-clip: padding-box; 18 | -moz-border-radius: 20px; 19 | -moz-background-clip: padding; 20 | border-radius: 20px; 21 | background-clip: padding-box; 22 | -webkit-transition: background 0.3s ease-in-out; 23 | -moz-transition: background 0.3s ease-in-out; 24 | -o-transition: background 0.3s ease-in-out; 25 | -ms-transition: background 0.3s ease-in-out; 26 | transition: background 0.3s ease-in-out; 27 | text-decoration: none 28 | } 29 | #back-top:hover, 30 | #back-top:focus { 31 | background-color: #181826; 32 | background-color: rgba(0, 0, 0, 0.5); 33 | color: #fff; 34 | text-decoration: none; 35 | } 36 | .standardClass:after{ 37 | content: '^'; 38 | } 39 | 40 | .fixed-nav{ 41 | 42 | } 43 | -------------------------------------------------------------------------------- /static/js/jquery.ui.touch-punch.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI Touch Punch 0.2.2 3 | * 4 | * Copyright 2011, Dave Furfero 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * 7 | * Depends: 8 | * jquery.ui.widget.js 9 | * jquery.ui.mouse.js 10 | */ 11 | (function(b){b.support.touch="ontouchend" in document;if(!b.support.touch){return;}var c=b.ui.mouse.prototype,e=c._mouseInit,a;function d(g,h){if(g.originalEvent.touches.length>1){return;}g.preventDefault();var i=g.originalEvent.changedTouches[0],f=document.createEvent("MouseEvents");f.initMouseEvent(h,true,true,window,1,i.screenX,i.screenY,i.clientX,i.clientY,false,false,false,false,0,null);g.target.dispatchEvent(f);}c._touchStart=function(g){var f=this;if(a||!f._mouseCapture(g.originalEvent.changedTouches[0])){return;}a=true;f._touchMoved=false;d(g,"mouseover");d(g,"mousemove");d(g,"mousedown");};c._touchMove=function(f){if(!a){return;}this._touchMoved=true;d(f,"mousemove");};c._touchEnd=function(f){if(!a){return;}d(f,"mouseup");d(f,"mouseout");if(!this._touchMoved){d(f,"click");}a=false;};c._mouseInit=function(){var f=this;f.element.bind("touchstart",b.proxy(f,"_touchStart")).bind("touchmove",b.proxy(f,"_touchMove")).bind("touchend",b.proxy(f,"_touchEnd"));e.call(f);};})(jQuery); -------------------------------------------------------------------------------- /views/reset_password.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 | Scrumforme 9 |
10 |
11 |
12 |

{{=T("Reset your password!")}}

13 |
14 |

{{=T("Click on the link")}} {{=link}} {{=T("to change your password")}}

15 |
16 |
17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /views/verify_email.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 | Scrumforme 9 |
10 |
11 |
12 |

{{=T("Activate your registration!")}}

13 |
14 |

{{=T("Click on the link")}} {{=link}} {{=T("to verify your email")}}

15 |
16 |
17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /models/05_auth_settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | def __afterVerify(form): 4 | """Function that creates a person 5 | """ 6 | name = '%s %s' % (form.first_name, form.last_name) 7 | person_id = Person.insert(name=name) 8 | db.user_relationship.insert(auth_user_id=form.id, person_id=person_id) 9 | 10 | 11 | def send_email(type_email): 12 | data = { 13 | "verify_email" : {'link' : 'http://'+request.env.http_host+URL(r=request,c='default',f='user',args=['verify_email'])+'/%(key)s', 'render_view' : 'verify_email.html'}, 14 | "reset_password" : {'link' : 'http://'+request.env.http_host+URL(r=request,c='default',f='user',args=['reset_password'])+'/%(key)s', 'render_view' : 'reset_password.html'}, 15 | } 16 | link = data[type_email]["link"] 17 | context = dict(link=link) 18 | 19 | return response.render(data[type_email]["render_view"], context) 20 | 21 | auth.settings.verify_email_onaccept = lambda form: __afterVerify(form) 22 | auth.messages.verify_email = send_email("verify_email") 23 | auth.messages.reset_password = send_email("reset_password") 24 | 25 | auth.settings.register_fields = ['first_name', 'last_name', 'email', 'password'] 26 | auth.settings.register_next= URL('check_your_email') 27 | auth.settings.login_next = URL('projects') -------------------------------------------------------------------------------- /static/js/web2py_bootstrap.js: -------------------------------------------------------------------------------- 1 | // this code improves bootstrap menus and adds dropdown support 2 | jQuery(function(){ 3 | jQuery('.nav>li>a').each(function(){ 4 | if(jQuery(this).parent().find('ul').length) 5 | jQuery(this).attr({'class':'dropdown-toggle','data-toggle':'dropdown'}).append(''); 6 | }); 7 | jQuery('.nav li li').each(function(){ 8 | if(jQuery(this).find('ul').length) 9 | jQuery(this).addClass('dropdown-submenu'); 10 | }); 11 | function hoverMenu(){ 12 | var wid = document.documentElement.clientWidth; //faster than $(window).width() and cross browser 13 | if (wid>=980){ 14 | jQuery('ul.nav a.dropdown-toggle').parent().hover(function(){ 15 | mi = jQuery(this).addClass('open'); 16 | mi.children('.dropdown-menu').stop(true, true).delay(200).fadeIn(400); 17 | }, function(){ 18 | mi = jQuery(this); 19 | mi.children('.dropdown-menu').stop(true, true).delay(200).fadeOut(function(){mi.removeClass('open')}); 20 | }); 21 | }; 22 | } 23 | hoverMenu(); // first page load 24 | jQuery(window).resize(hoverMenu); // on resize event 25 | jQuery('ul.nav li.dropdown a').click(function(){window.location=jQuery(this).attr('href');}); 26 | // make all buttons bootstrap buttons 27 | jQuery('button, form input[type="submit"], form input[type="button"]').addClass('btn'); 28 | }); 29 | -------------------------------------------------------------------------------- /views/default/load_tasks.html: -------------------------------------------------------------------------------- 1 | {{count=0}} 2 | {{for task in tasks:}} 3 | 28 | {{count +=1}} 29 | {{pass}} -------------------------------------------------------------------------------- /views/default/statistics.html: -------------------------------------------------------------------------------- 1 | {{extend 'default/layout_base.html'}} 2 | 3 | 34 | 35 |
36 | {{include "default/project_info.html"}} 37 |
38 |
39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | 50 | -------------------------------------------------------------------------------- /static/js/jquery.livesearch.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $.extend($.expr[':'], { 3 | 'containsi': function(elem, i, match, array) { 4 | return $(elem).text().toLowerCase() 5 | .indexOf((match[3] || "").toLowerCase()) >= 0; 6 | } 7 | }); 8 | 9 | var Search = function(block) { 10 | this.callbacks = {}; 11 | block(this); 12 | } 13 | 14 | Search.prototype.all = function(fn) { this.callbacks.all = fn; } 15 | Search.prototype.reset = function(fn) { this.callbacks.reset = fn; } 16 | Search.prototype.empty = function(fn) { this.callbacks.empty = fn; } 17 | Search.prototype.results = function(fn) { this.callbacks.results = fn; } 18 | 19 | function query(selector) { 20 | if (val = this.val()) { 21 | return $(selector + ':containsi("' + val + '")'); 22 | } else { 23 | return false; 24 | } 25 | } 26 | 27 | $.fn.search = function search(selector, block) { 28 | var search = new Search(block); 29 | var callbacks = search.callbacks; 30 | 31 | function perform() { 32 | if (result = query.call($(this), selector)) { 33 | callbacks.all && callbacks.all.call(this, result); 34 | var method = result.size() > 0 ? 'results' : 'empty'; 35 | return callbacks[method] && callbacks[method].call(this, result); 36 | } else { 37 | callbacks.all && callbacks.all.call(this, $(selector)); 38 | return callbacks.reset && callbacks.reset.call(this); 39 | }; 40 | } 41 | 42 | $(this).on('keypress', perform); 43 | $(this).on('keydown', perform); 44 | $(this).on('keyup', perform); 45 | $(this).bind('blur', perform); 46 | } 47 | })(jQuery); 48 | -------------------------------------------------------------------------------- /views/default/projects.html: -------------------------------------------------------------------------------- 1 | {{extend 'default/layout_base.html'}} 2 | 11 | 12 |
13 |
14 |
15 | {{if own_projects:}} 16 |

{{=T('My Projects')}} {{=len(own_projects)}}

17 |
    18 | {{for i in own_projects:}} 19 |
  • 20 | {{=i.name}} 21 | 22 |
  • 23 | {{pass}} 24 |
25 | {{pass}} 26 |
27 |
28 | {{if all_shared_with:}} 29 |

{{=T('Projects that I am part')}} {{=len(all_shared_with)}}

30 | 35 | {{pass}} 36 |
37 |
38 |
39 | 40 | -------------------------------------------------------------------------------- /static/js/board-editable.js: -------------------------------------------------------------------------------- 1 | // ============= 2 | // PLUGIN HACKS 3 | // ============= 4 | 5 | // modify style buttons 6 | $.fn.editableform.buttons = 7 | '' + 8 | ''; 9 | $.fn.editable.defaults.mode = 'inline'; 10 | 11 | //apply editable to parent div 12 | $('.table').editable({ 13 | selector: 'a.editable', 14 | url: url.create_or_update_itens, 15 | emptytext: msg.field_empty, 16 | rows: 1, 17 | params: function(params) { 18 | // sending parameters indicating whether the item is to upgrade or not 19 | // send the new ID as param 20 | var dbUpdate = $(this).attr("data-update"), 21 | dbID = $(this).attr("data-pk"), 22 | definitionready = $(this).closest('.item_container').attr('data-definitionready'); 23 | 24 | if (dbUpdate) { 25 | params.dbUpdate = true; 26 | params.dbID = dbID; 27 | } else { 28 | params.dbUpdate = false; 29 | params.definitionready = definitionready; 30 | } 31 | 32 | params.project_id = info.project_id; 33 | params.page = info.page; 34 | return params; 35 | }, 36 | validate: function(value) { 37 | if (value === '') return msg.validation_error; 38 | }, 39 | success: function(value, response) { 40 | // get the coming new database ID and update in DOM 41 | $(this).attr("data-pk", value.database_id); 42 | // changes the status of the created item for item update 43 | $(this).attr("data-update", true); 44 | } 45 | }); -------------------------------------------------------------------------------- /static/js/bootstrap-custom.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bootstrap.js by @fat & @mdo 3 | * plugins: bootstrap-dropdown.js 4 | * Copyright 2012 Twitter, Inc. 5 | * http://www.apache.org/licenses/LICENSE-2.0.txt 6 | */ 7 | !function(a){function d(){a(b).each(function(){e(a(this)).removeClass("open")})}function e(b){var c=b.attr("data-target"),d;c||(c=b.attr("href"),c=c&&/#/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,"")),d=c&&a(c);if(!d||!d.length)d=b.parent();return d}var b="[data-toggle=dropdown]",c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),f,g;if(c.is(".disabled, :disabled"))return;return f=e(c),g=f.hasClass("open"),d(),g||f.toggleClass("open"),c.focus(),!1},keydown:function(c){var d,f,g,h,i,j;if(!/(38|40|27)/.test(c.keyCode))return;d=a(this),c.preventDefault(),c.stopPropagation();if(d.is(".disabled, :disabled"))return;h=e(d),i=h.hasClass("open");if(!i||i&&c.keyCode==27)return c.which==27&&h.find(b).focus(),d.click();f=a("[role=menu] li:not(.divider):visible a",h);if(!f.length)return;j=f.index(f.filter(":focus")),c.keyCode==38&&j>0&&j--,c.keyCode==40&&j 2 | 3 | 4 | 5 | 6 |
7 |
8 | Scrumforme 9 |
10 |
11 |
12 |

{{=T("Hello")}} {{=person.auth_user_id.first_name}},

13 |
14 |

{{=T("You have been invited for the project")}} {{=project.name}}.

15 |
16 | {{=T("Project")}} {{=project.name}} 17 |

{{=T("Click on the link")}} {{="http://"+request.env.http_host+URL(f="team",args=project.id)}} {{=T("to access the project")}}.

18 |
19 |
20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /static/js/highcharts/modules/funnel.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Highcharts funnel module, Beta 4 | 5 | (c) 2010-2012 Torstein Hønsi 6 | 7 | License: www.highcharts.com/license 8 | */ 9 | (function(l){var B=l.getOptions().plotOptions,q=l.seriesTypes,D=l.merge,C=function(){},z=l.each;B.funnel=D(B.pie,{center:["50%","50%"],width:"90%",neckWidth:"30%",height:"100%",neckHeight:"25%",dataLabels:{connectorWidth:1,connectorColor:"#606060"},size:!0,states:{select:{color:"#C0C0C0",borderColor:"#000000",shadow:!1}}});q.funnel=l.extendClass(q.pie,{type:"funnel",animate:C,translate:function(){var a=function(i,a){return/%$/.test(i)?a*parseInt(i,10)/100:parseInt(i,10)},f=0,d=this.chart,e=d.plotWidth, 10 | d=d.plotHeight,g=0,c=this.options,j=c.center,b=a(j[0],e),j=a(j[0],d),l=a(c.width,e),h,r,m=a(c.height,d),s=a(c.neckWidth,e),u=a(c.neckHeight,d),v=m-u,a=this.data,w,x,q=c.dataLabels.position==="left"?1:0,y,n,A,o,k,t,p;this.getWidthAt=r=function(i){return i>m-u?s:s+(l-s)*((m-u-i)/(m-u))};this.getX=function(i,a){return b+(a?-1:1)*(r(i)/2+c.dataLabels.distance)};this.center=[b,j,m];this.centerX=b;z(a,function(a){f+=a.y});z(a,function(a){p=null;x=f?a.y/f:0;n=g*m;k=n+x*m;h=r(n);y=b-h/2;A=y+h;h=r(k);o=b- 11 | h/2;t=o+h;n>v?(y=o=b-s/2,A=t=b+s/2):k>v&&(p=k,h=r(v),o=b-h/2,t=o+h,k=v);w=["M",y,n,"L",A,n,t,k];p&&w.push(t,p,o,p);w.push(o,k,"Z");a.shapeType="path";a.shapeArgs={d:w};a.percentage=x*100;a.plotX=b;a.plotY=(n+(p||k))/2;a.tooltipPos=[b,a.plotY];a.slice=C;a.half=q;g+=x});this.setTooltipPoints()},drawPoints:function(){var a=this,f=a.options,d=a.chart.renderer;z(a.data,function(e){var g=e.graphic,c=e.shapeArgs;g?g.animate(c):e.graphic=d.path(c).attr({fill:e.color,stroke:f.borderColor,"stroke-width":f.borderWidth}).add(a.group)})}, 12 | drawDataLabels:function(){var a=this.data,f=this.options.dataLabels.distance,d,e,g,c=a.length,j,b;for(this.center[2]-=2*f;c--;)g=a[c],e=(d=g.half)?1:-1,b=g.plotY,j=this.getX(b,d),g.labelPos=[0,b,j+(f-5)*e,b,j+f*e,b,d?"right":"left",0];q.pie.prototype.drawDataLabels.call(this)}})})(Highcharts); 13 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | 'use strict'; 3 | 4 | // configuração do projeto 5 | var gruntConfig = { 6 | pkg: grunt.file.readJSON('package.json'), 7 | // Arquivos que serão concatenados (arquivos de origem e de destino) 8 | concat: { 9 | js: { 10 | src: ['static/js/module1.js', 'lib/module2.js', 'lib/plugin.js'], 11 | dest: 'dist/all.js' 12 | }, 13 | css: { 14 | src: ['static/js/product_backlog.*.css', ], 15 | dest: 'dist/main.css' 16 | } 17 | }, 18 | // Arquivos que serão minificados (arquivos de origem e de destino) 19 | min: { 20 | dist: { 21 | src: ['src/assets/js/main.js'], 22 | dest: 'src/assets/js/all.min.js' 23 | } 24 | }, 25 | cssmin: { 26 | dist: { 27 | src: ['src/assets/css/main.css'], 28 | dest: 'src/assets/css/all.min.css' 29 | } 30 | }, 31 | rsync: { 32 | dist: { 33 | src: './', 34 | dest: '../scrumforme_deploy', 35 | recursive: true, 36 | syncDest: true, 37 | exclude: ['main.*'] 38 | }, 39 | deploy: { 40 | src: '../scrumforme_deploy', 41 | dest: '/home/agenciax4/sites/scrumforme/', 42 | host: 'root@vagnersantana.com 43 | ', 44 | recursive: true, 45 | syncDest: true 46 | } 47 | }, 48 | }; 49 | 50 | grunt.initConfig(gruntConfig); 51 | 52 | // Carrega os plugins que proveem as tarefas especificadas no package.json. 53 | grunt.loadNpmTasks('grunt-contrib-concat'); 54 | 55 | // Tarefa padrão que será executada se o Grunt 56 | // for chamado sem parâmetros. 57 | grunt.registerTask('default', 'concat min cssmin'); 58 | }; -------------------------------------------------------------------------------- /static/js/highcharts/themes/skies.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Skies theme for Highcharts JS 3 | * @author Torstein Hønsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#514F78", "#42A07B", "#9B5E4A", "#72727F", "#1F949A", "#82914E", "#86777F", "#42A07B"], 8 | chart: { 9 | className: 'skies', 10 | borderWidth: 0, 11 | plotShadow: true, 12 | plotBackgroundImage: '/demo/gfx/skies.jpg', 13 | plotBackgroundColor: { 14 | linearGradient: [0, 0, 250, 500], 15 | stops: [ 16 | [0, 'rgba(255, 255, 255, 1)'], 17 | [1, 'rgba(255, 255, 255, 0)'] 18 | ] 19 | }, 20 | plotBorderWidth: 1 21 | }, 22 | title: { 23 | style: { 24 | color: '#3E576F', 25 | font: '16px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 26 | } 27 | }, 28 | subtitle: { 29 | style: { 30 | color: '#6D869F', 31 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 32 | } 33 | }, 34 | xAxis: { 35 | gridLineWidth: 0, 36 | lineColor: '#C0D0E0', 37 | tickColor: '#C0D0E0', 38 | labels: { 39 | style: { 40 | color: '#666', 41 | fontWeight: 'bold' 42 | } 43 | }, 44 | title: { 45 | style: { 46 | color: '#666', 47 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 48 | } 49 | } 50 | }, 51 | yAxis: { 52 | alternateGridColor: 'rgba(255, 255, 255, .5)', 53 | lineColor: '#C0D0E0', 54 | tickColor: '#C0D0E0', 55 | tickWidth: 1, 56 | labels: { 57 | style: { 58 | color: '#666', 59 | fontWeight: 'bold' 60 | } 61 | }, 62 | title: { 63 | style: { 64 | color: '#666', 65 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 66 | } 67 | } 68 | }, 69 | legend: { 70 | itemStyle: { 71 | font: '9pt Trebuchet MS, Verdana, sans-serif', 72 | color: '#3E576F' 73 | }, 74 | itemHoverStyle: { 75 | color: 'black' 76 | }, 77 | itemHiddenStyle: { 78 | color: 'silver' 79 | } 80 | }, 81 | labels: { 82 | style: { 83 | color: '#3E576F' 84 | } 85 | } 86 | }; 87 | 88 | // Apply the theme 89 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 90 | -------------------------------------------------------------------------------- /static/js/highcharts/adapters/mootools-adapter.js: -------------------------------------------------------------------------------- 1 | /* 2 | Highcharts JS v3.0.1 (2013-04-09) 3 | MooTools adapter 4 | 5 | (c) 2010-2013 Torstein Hønsi 6 | 7 | License: www.highcharts.com/license 8 | */ 9 | (function(){var e=window,h=document,f=e.MooTools.version.substring(0,3),i=f==="1.2"||f==="1.1",j=i||f==="1.3",g=e.$extend||function(){return Object.append.apply(Object,arguments)};e.HighchartsAdapter={init:function(a){var b=Fx.prototype,c=b.start,d=Fx.Morph.prototype,e=d.compute;b.start=function(b,d){var e=this.element;if(b.d)this.paths=a.init(e,e.d,this.toD);c.apply(this,arguments);return this};d.compute=function(b,c,d){var f=this.paths;if(f)this.element.attr("d",a.step(f[0],f[1],d,this.toD));else return e.apply(this, 10 | arguments)}},adapterRun:function(a,b){if(b==="width"||b==="height")return parseInt($(a).getStyle(b),10)},getScript:function(a,b){var c=h.getElementsByTagName("head")[0],d=h.createElement("script");d.type="text/javascript";d.src=a;d.onload=b;c.appendChild(d)},animate:function(a,b,c){var d=a.attr,f=c&&c.complete;if(d&&!a.setStyle)a.getStyle=a.attr,a.setStyle=function(){var a=arguments;this.attr.call(this,a[0],a[1][0])},a.$family=function(){return!0};e.HighchartsAdapter.stop(a);c=new Fx.Morph(d?a:$(a), 11 | g({transition:Fx.Transitions.Quad.easeInOut},c));if(d)c.element=a;if(b.d)c.toD=b.d;f&&c.addEvent("complete",f);c.start(b);a.fx=c},each:function(a,b){return i?$each(a,b):Array.each(a,b)},map:function(a,b){return a.map(b)},grep:function(a,b){return a.filter(b)},inArray:function(a,b,c){return b.indexOf(a,c)},offset:function(a){a=a.getPosition();return{left:a.x,top:a.y}},extendWithEvents:function(a){a.addEvent||(a.nodeName?$(a):g(a,new Events))},addEvent:function(a,b,c){typeof b==="string"&&(b==="unload"&& 12 | (b="beforeunload"),e.HighchartsAdapter.extendWithEvents(a),a.addEvent(b,c))},removeEvent:function(a,b,c){typeof a!=="string"&&a.addEvent&&(b?(b==="unload"&&(b="beforeunload"),c?a.removeEvent(b,c):a.removeEvents&&a.removeEvents(b)):a.removeEvents())},fireEvent:function(a,b,c,d){b={type:b,target:a};b=j?new Event(b):new DOMEvent(b);b=g(b,c);if(!b.target&&b.event)b.target=b.event.target;b.preventDefault=function(){d=null};a.fireEvent&&a.fireEvent(b.type,b);d&&d(b)},washMouseEvent:function(a){if(a.page)a.pageX= 13 | a.page.x,a.pageY=a.page.y;return a},stop:function(a){a.fx&&a.fx.cancel()}}})(); 14 | -------------------------------------------------------------------------------- /static/js/highcharts/themes/grid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Grid theme for Highcharts JS 3 | * @author Torstein Hønsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ['#058DC7', '#50B432', '#ED561B', '#DDDF00', '#24CBE5', '#64E572', '#FF9655', '#FFF263', '#6AF9C4'], 8 | chart: { 9 | backgroundColor: { 10 | linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 }, 11 | stops: [ 12 | [0, 'rgb(255, 255, 255)'], 13 | [1, 'rgb(240, 240, 255)'] 14 | ] 15 | }, 16 | borderWidth: 2, 17 | plotBackgroundColor: 'rgba(255, 255, 255, .9)', 18 | plotShadow: true, 19 | plotBorderWidth: 1 20 | }, 21 | title: { 22 | style: { 23 | color: '#000', 24 | font: 'bold 16px "Trebuchet MS", Verdana, sans-serif' 25 | } 26 | }, 27 | subtitle: { 28 | style: { 29 | color: '#666666', 30 | font: 'bold 12px "Trebuchet MS", Verdana, sans-serif' 31 | } 32 | }, 33 | xAxis: { 34 | gridLineWidth: 1, 35 | lineColor: '#000', 36 | tickColor: '#000', 37 | labels: { 38 | style: { 39 | color: '#000', 40 | font: '11px Trebuchet MS, Verdana, sans-serif' 41 | } 42 | }, 43 | title: { 44 | style: { 45 | color: '#333', 46 | fontWeight: 'bold', 47 | fontSize: '12px', 48 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 49 | 50 | } 51 | } 52 | }, 53 | yAxis: { 54 | minorTickInterval: 'auto', 55 | lineColor: '#000', 56 | lineWidth: 1, 57 | tickWidth: 1, 58 | tickColor: '#000', 59 | labels: { 60 | style: { 61 | color: '#000', 62 | font: '11px Trebuchet MS, Verdana, sans-serif' 63 | } 64 | }, 65 | title: { 66 | style: { 67 | color: '#333', 68 | fontWeight: 'bold', 69 | fontSize: '12px', 70 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 71 | } 72 | } 73 | }, 74 | legend: { 75 | itemStyle: { 76 | font: '9pt Trebuchet MS, Verdana, sans-serif', 77 | color: 'black' 78 | 79 | }, 80 | itemHoverStyle: { 81 | color: '#039' 82 | }, 83 | itemHiddenStyle: { 84 | color: 'gray' 85 | } 86 | }, 87 | labels: { 88 | style: { 89 | color: '#99b' 90 | } 91 | }, 92 | 93 | navigation: { 94 | buttonOptions: { 95 | theme: { 96 | stroke: '#CCCCCC' 97 | } 98 | } 99 | } 100 | }; 101 | 102 | // Apply the theme 103 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 104 | -------------------------------------------------------------------------------- /views/default/project_info.html: -------------------------------------------------------------------------------- 1 | {{if not "have_permission" in globals():}} 2 | {{have_permission = False}} 3 | {{pass}} 4 | 5 |
6 |
7 | {{ if project.thumbnail:}} 8 | {{=project.name}} 9 | {{else:}} 10 | {{=project.name}} 11 | {{pass}} 12 | {{if have_permission:}} 13 | 14 | {{=T("Change image")}} 15 | 16 | 17 | 18 | {{pass}} 19 |
20 |
21 | {{if have_permission:}} 22 |

{{=project.name}} - {{=project.url}}

23 | 24 |

{{=project.description}}

25 | {{else:}} 26 |

{{=project.name}} - {{=project.url}}

27 |

{{=project.description}}

28 | {{pass}} 29 |
30 |
31 |
32 | -------------------------------------------------------------------------------- /static/css/tela-login-registro.css: -------------------------------------------------------------------------------- 1 | *{ 2 | padding: 0px; 3 | margin: 0px; 4 | border: none; 5 | list-style: none; 6 | font-family: Helvetica; 7 | } 8 | a, a:hover{ 9 | text-decoration: none; 10 | color: #fff; 11 | font-size: 10px; 12 | padding-top: 5px; 13 | padding-bottom: 5px; 14 | } 15 | 16 | .link-color, small { 17 | color: #0b5b69; 18 | } 19 | 20 | input[type="text"] , input[type="email"] , input[type="password"]{ 21 | background-color: #a8d9e0; 22 | height: 20px; 23 | width: 70%; 24 | } 25 | 26 | .form-homepage-icon { 27 | padding-right: .5em; 28 | font-size: 1.2em; 29 | color: #197a8b; 30 | } 31 | 32 | .bloco_grande { 33 | width: 309px; 34 | box-shadow: 0px 0px 50px black; 35 | margin-top: 4em; 36 | float: right; 37 | } 38 | .menu{ 39 | width: 100%; 40 | height: 18px; 41 | background-color: orange; 42 | } 43 | .menu a{ 44 | text-decoration: none; 45 | display: inline-block; 46 | background-color: #34abbd; 47 | text-align: center; 48 | float: left; 49 | width: 50%; 50 | padding: 10px 0px; 51 | } 52 | 53 | .menu_login--links { 54 | width: 66%; 55 | margin: 1em auto 0; 56 | } 57 | 58 | .menu_login--links .link{ 59 | float: left; 60 | padding: .2em; 61 | } 62 | 63 | .menu_login--links .link:first-child{ 64 | margin-top: .5em; 65 | } 66 | 67 | .conteudo{ 68 | width: 100%; 69 | background-color: #34abbd; 70 | } 71 | 72 | #entrar{ 73 | display: block; 74 | } 75 | #registro{ 76 | display: none; 77 | padding-bottom:1.2em; 78 | } 79 | .menu_registro{ 80 | margin: 0 auto; 81 | text-align: center; 82 | } 83 | .menu_login{ 84 | text-align: center; 85 | } 86 | #registro_index{ 87 | background-color: #197a8b; 88 | } 89 | .conteudo ul{ 90 | padding-top: 15%; 91 | } 92 | .redes_sociais img{ 93 | padding: 6px; 94 | } 95 | .menu_login img , .menu_registro img , input[type="checkbox"]{ 96 | vertical-align: middle; 97 | } 98 | 99 | .button-chamada-meus-projetos { 100 | width: 309px; 101 | margin-top: 6em; 102 | margin-right: 5em; 103 | padding-top: 4em; 104 | float: right; 105 | } 106 | 107 | .button-chamada-meus-projetos a, .button-chamada-meus-projetos a:hover { 108 | font-size: 14px; 109 | background-color: #197a8b; 110 | color: #FFF; 111 | cursor: pointer; 112 | padding: 3em 6em; 113 | } 114 | 115 | .scrumforme-button-success{ 116 | padding: .5em 2em; 117 | font-size: 14px; 118 | background-color: #197a8b; 119 | color: #FFF; 120 | cursor: pointer; 121 | } 122 | -------------------------------------------------------------------------------- /static/js/team.js: -------------------------------------------------------------------------------- 1 | function MultiAjaxAutoComplete(element, url) { 2 | $(element).select2({ 3 | placeholder: msg.placeholder, 4 | minimumInputLength: 1, 5 | multiple: true, 6 | formatNoMatches: function(){return msg.noMatches}, 7 | formatSearching: function(){return msg.searching}, 8 | formatInputTooShort: function(){return msg.inputTooShort}, 9 | 10 | id: function(e) { return e.id+":"+e.title; }, 11 | ajax: { 12 | url: url, 13 | dataType: 'json', 14 | data: function(term, page) { 15 | 16 | return { 17 | q: term, 18 | page_limit: 10, 19 | }; 20 | }, 21 | results: function(data, page) { 22 | return { 23 | results: data.persons 24 | }; 25 | } 26 | }, 27 | formatResult: formatResult, 28 | formatSelection: formatSelection, 29 | initSelection: function(element, callback) { 30 | var data = []; 31 | $(element.val().split(",")).each(function(i) { 32 | var item = this.split(':'); 33 | data.push({ 34 | id: item[0], 35 | title: item[1] 36 | }); 37 | }); 38 | callback(data); 39 | } 40 | }); 41 | }; 42 | 43 | function formatResult(person) { 44 | return '
' + person.title + '
'; 45 | }; 46 | 47 | function formatSelection(data) { 48 | return data.title; 49 | }; 50 | 51 | MultiAjaxAutoComplete('#e6', url.get_persons); 52 | 53 | // Get persons IDs 54 | function persons_id(single) { 55 | var result = single.split(':'); 56 | return result[0]; 57 | } 58 | 59 | // Add users 60 | $('#add').click(function() { 61 | var persons = $('#e6').val().split(','), 62 | persons_len = persons_id.length, 63 | array_persons = persons.map(persons_id); 64 | 65 | window.location = url.add_member + '&persons_id=' + array_persons; 66 | }); 67 | 68 | // Edit role 69 | $('.edit_role').click(function(event){ 70 | event.preventDefault(); 71 | $(".role_team").hide('normal'); 72 | $(this).closest(".users").find(".role_team").toggle('normal'); 73 | }); 74 | 75 | $('.cancel').click(function(event){ 76 | event.preventDefault(); 77 | $(this).closest(".role_team").toggle('normal'); 78 | }); 79 | 80 | // Remove member 81 | $('.remove_member').click(function(){ 82 | var person_id = $(this)[0].dataset['member']; 83 | var remove = confirm(msg.confirmRemove); 84 | if (remove){ 85 | window.location = url.remove_member + '&person_id=' + person_id; 86 | } 87 | }); 88 | -------------------------------------------------------------------------------- /static/js/floatfixed.js: -------------------------------------------------------------------------------- 1 | /* 2 | #WebMaster : Felipe Campos 3 | #Version : 1.2 4 | #Reparo : Gustavo De Souza Lima - @dodilei 5 | */ 6 | jQuery.fn.floatfixed = function (settings) { 7 | var nav = $(this), 8 | windowElement = $(window), 9 | options, 10 | backTop, 11 | defaults = { 12 | 'topx': '0px', 13 | 'offsetTopx': nav.offset().top, 14 | 'leftx': '0px', 15 | 'scrollTopx': true, 16 | 'scrollTopSpeed': 400, 17 | 'scrollOffsetTopx': 200, 18 | 'floatFixedx': true, 19 | 'scrollClass': 'standardClass' 20 | }; 21 | 22 | if (settings) { 23 | options = $.extend(defaults, settings); 24 | } 25 | 26 | if (options.scrollTopx) { 27 | $('body').append(''); 28 | backTop = $("#back-top"); 29 | backTop.hide(); 30 | 31 | windowElement.scroll(function () { 32 | if ($(this).scrollTop() > options.scrollOffsetTopx) { 33 | backTop.fadeIn(); 34 | } else { 35 | backTop.fadeOut(); 36 | } 37 | }); 38 | 39 | backTop.click(function () { 40 | 41 | $('body,html').animate({ 42 | scrollTop: 0 43 | }, options.scrollTopSpeed); 44 | return false; 45 | }); 46 | } 47 | 48 | return this.each(function () { 49 | var position, 50 | top, 51 | left, 52 | index, 53 | sticky_scroll; 54 | 55 | if (nav.length > 0) { 56 | position = nav.css("position"); 57 | top = nav.css("top"); 58 | left = nav.css("left"); 59 | index = nav.css("z-index"); 60 | } 61 | 62 | windowElement.scroll(function () { 63 | 64 | if (options.floatFixedx) { 65 | sticky_scroll = $(this).scrollTop(); 66 | 67 | if (sticky_scroll > options.offsetTopx) { 68 | nav.css({ 69 | "position": "fixed", 70 | "top": options.topx, 71 | "left": options.leftx, 72 | "z-index": "999" 73 | }).addClass("fixed-nav"); 74 | 75 | } else { 76 | nav.css({ 77 | "position": position, 78 | "top": top, 79 | "left": left, 80 | "z-index": index 81 | }).removeClass("fixed-nav"); 82 | 83 | } 84 | } 85 | }); 86 | }); 87 | }; 88 | -------------------------------------------------------------------------------- /static/js/share.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Created and copyrighted by Massimo Di Pierro 4 | (MIT license) 5 | 6 | Example: 7 | 8 | 9 | 10 | **/ 11 | 12 | jQuery(function(){ 13 | var script_source = jQuery('script[src*="share.js"]').attr('src'); 14 | var params = function(name,default_value) { 15 | var match = RegExp('[?&]' + name + '=([^&]*)').exec(script_source); 16 | return match && decodeURIComponent(match[1].replace(/\+/g, ' '))||default_value; 17 | } 18 | var path = params('static','social'); 19 | var url = encodeURIComponent(window.location.href); 20 | var host = window.location.hostname; 21 | var title = escape(jQuery('title').text()); 22 | var twit = 'http://twitter.com/home?status='+title+'%20'+url; 23 | var facebook = 'http://www.facebook.com/sharer.php?u='+url; 24 | var gplus = 'https://plus.google.com/share?url='+url; 25 | var tbar = '
Share
Share on TwitterShare on facebookShare on Google Plus
'; 26 | // Add the share tool bar. 27 | jQuery('body').append(tbar); 28 | var st = jQuery('#socialdrawer'); 29 | st.css({'opacity':'.7','z-index':'3000','background':'#FFF','border':'solid 1px #666','border-width':' 1px 0 0 1px','height':'20px','width':'40px','position':'fixed','bottom':'0','right':'0','padding':'2px 5px','overflow':'hidden','-webkit-border-top-left-radius':' 12px','-moz-border-radius-topleft':' 12px','border-top-left-radius':' 12px','-moz-box-shadow':' -3px -3px 3px rgba(0,0,0,0.5)','-webkit-box-shadow':' -3px -3px 3px rgba(0,0,0,0.5)','box-shadow':' -3px -3px 3px rgba(0,0,0,0.5)'}); 30 | jQuery('#socialdrawer a').css({'float':'left','width':'32px','margin':'3px 2px 2px 2px','padding':'0','cursor':'pointer'}); 31 | jQuery('#socialdrawer span').css({'float':'left','margin':'2px 3px','text-shadow':' 1px 1px 1px #FFF','color':'#444','font-size':'12px','line-height':'1em'}); 32 | jQuery('#socialdrawer img').hide(); 33 | // hover 34 | st.click(function(){ 35 | jQuery(this).animate({height:'40px', width:'160px', opacity: 0.95}, 300); 36 | jQuery('#socialdrawer img').show(); 37 | }); 38 | //leave 39 | st.mouseleave(function(){ 40 | st.animate({height:'20px', width: '40px', opacity: .7}, 300); 41 | jQuery('#socialdrawer img').hide(); 42 | return false; 43 | } ); 44 | }); 45 | -------------------------------------------------------------------------------- /static/css/base.grey.css: -------------------------------------------------------------------------------- 1 | body { 2 | /*background-color: #444444;*/ 3 | } 4 | 5 | #search input[type=text], #search button { 6 | /*background-color: #222222;*/ 7 | } 8 | #search input[type=text]:focus { 9 | color: #777777; 10 | } 11 | 12 | #sidebar > ul { 13 | /*border-top: 1px solid #393939;*/ 14 | border-bottom: 1px solid #4E4E4E; 15 | } 16 | #sidebar > ul > li { 17 | border-top: 1px solid #4E4E4E; 18 | border-bottom: 1px solid #393939; 19 | } 20 | #sidebar > ul > li.active { 21 | background-color: #3a3a3a; 22 | background-image: -webkit-gradient(linear, 0 0%, 0 100%, from(#333333), to(#3F3F3F)); 23 | background-image: -webkit-linear-gradient(top, #333333 0%, #3F3F3F 100%); 24 | background-image: -moz-linear-gradient(top, #333333 0%, #3F3F3F 100%); 25 | background-image: -ms-linear-gradient(top, #333333 0%, #3F3F3F 100%); 26 | background-image: -o-linear-gradient(top, #333333 0%, #3F3F3F 100%); 27 | background-image: linear-gradient(top, #333333 0%, #3F3F3F 100%); 28 | } 29 | 30 | #sidebar > ul > li.open.submenu > a { 31 | border-bottom: 1px solid #393939; 32 | } 33 | #sidebar > ul > li.open.active.submenu > a { 34 | border-bottom: 1px solid #2A2A2A; 35 | } 36 | #sidebar > ul > li > a > .label { 37 | background-color: #333333; 38 | } 39 | #sidebar > ul > li > a:hover { 40 | background-color: #4A4A4A; 41 | } 42 | #sidebar > ul ul { 43 | border-top: 1px solid #4E4E4E; 44 | background-color: #2A2A2A; 45 | } 46 | #sidebar > ul ul li a { 47 | border-top: 1px solid #333333; 48 | border-bottom: 1px solid #202020; 49 | } 50 | #sidebar > ul ul li a:hover, #sidebar > ul ul li.active a { 51 | color: #CCCCCC; 52 | background-color: #272727; 53 | } 54 | 55 | .dropdown-menu li a:hover, .dropdown-menu .active a, .dropdown-menu .active a:hover { 56 | color: #eeeeee; 57 | background-color: #444444; 58 | background-image: -webkit-gradient(linear, 0 0%, 0 100%, #555555, #222222); 59 | background-image: -webkit-linear-gradient(top, #555555 0%, #222222 100%); 60 | background-image: -moz-linear-gradient(top, #555555 0%, #222222 100%); 61 | background-image: -ms-linear-gradient(top, #555555 0%, #222222 100%); 62 | background-image: -o-linear-gradient(top, #555555 0%, #222222 100%); 63 | background-image: linear-gradient(top, #555555 0%, #222222 100%); 64 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#555555', endColorstr='#222222',GradientType=0 ); /* IE6-9 */ 65 | } 66 | 67 | @media (max-width: 480px) { 68 | #sidebar > a { 69 | background-image: -moz-linear-gradient(top, #464646 0%, #404040 100%); 70 | border-bottom: 1px solid #6e6e6e; 71 | } 72 | #sidebar > ul { 73 | background-color: #444444; 74 | } 75 | } 76 | @media (min-width: 481px) and (max-width: 767px) { 77 | #sidebar > ul ul:before { 78 | border-right: 7px solid rgba(0, 0, 0, 0.2); 79 | } 80 | #sidebar > ul ul:after { 81 | border-right: 6px solid #222222; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /static/css/calendar.css: -------------------------------------------------------------------------------- 1 | .calendar{z-index:99;position:relative;display:none;background:#fff;border:2px solid #000;font-size:11px;color:#000;cursor:default;font-family:Arial,Helvetica,sans-serif; 2 | border-radius: 10px; 3 | -moz-border-radius: 10px; 4 | -webkit-border-radius: 10px; 5 | }.calendar table{margin:0px;font-size:11px;color:#000;cursor:default;font-family:tahoma,verdana,sans-serif;}.calendar .button{text-align:center;padding:1px;color:#fff;background:#000;}.calendar .nav{background:#000;color:#fff}.calendar thead .title{font-weight:bold;padding:1px;background:#000;color:#fff;text-align:center;}.calendar thead .name{padding:2px;text-align:center;background:#bbb;}.calendar thead .weekend{color:#f00;}.calendar thead .hilite {background-color:#666;}.calendar thead .active{padding:2px 0 0 2px;background-color:#c4c0b8;}.calendar tbody .day{width:2em;text-align:right;padding:2px 4px 2px 2px;}.calendar tbody .day.othermonth{color:#aaa;}.calendar tbody .day.othermonth.oweekend{color:#faa;}.calendar table .wn{padding:2px 3px 2px 2px;background:#bbb;}.calendar tbody .rowhilite td{background:#ddd;}.calendar tbody td.hilite{background:#bbb;}.calendar tbody td.active{background:#bbb;}.calendar tbody td.selected{font-weight:bold;background:#ddd;}.calendar tbody td.weekend{color:#f00;}.calendar tbody td.today{font-weight:bold;color:#00f;}.calendar tbody .disabled{color:#999;}.calendar tbody .emptycell{visibility:hidden;}.calendar tbody .emptyrow{display:none;}.calendar tfoot .ttip{background:#bbb;padding:1px;background:#000;color:#fff;text-align:center;}.calendar tfoot .hilite{background:#ddd;}.calendar tfoot .active{}.calendar .combo{position:absolute;display:none;width:4em;top:0;left:0;cursor:default;background:#e4e0d8;padding:1px;z-index:100;}.calendar .combo .label,.calendar .combo .label-IEfix{text-align:center;padding:1px;}.calendar .combo .label-IEfix{width:4em;}.calendar .combo .active{background:#c4c0b8;}.calendar .combo .hilite{background:#048;color:#fea;}.calendar td.time{padding:1px 0;text-align:center;background-color:#bbb;}.calendar td.time .hour,.calendar td.time .minute,.calendar td.time .ampm{padding:0 3px 0 4px;font-weight:bold;}.calendar td.time .ampm{text-align:center;}.calendar td.time .colon{padding:0 2px 0 3px;font-weight:bold;}.calendar td.time span.hilite{}.calendar td.time span.active{border-color:#f00;background-color:#000;color:#0f0;}.hour,.minute{font-size:2em;} 6 | 7 | #CP_hourcont{z-index:99;padding:0;position:absolute;border:1px dashed #666;background-color:#eee;display:none;}#CP_minutecont{z-index:99;background-color:#ddd;padding:1px;position:absolute;width:45px;display:none;}.floatleft{float:left;}.CP_hour{z-index:99;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:35px;}.CP_minute{z-index:99;padding:1px;font-family:Arial,Helvetica,sans-serif;font-size:9px;white-space:nowrap;cursor:pointer;width:auto;}.CP_over{background-color:#fff;z-index:99} 8 | -------------------------------------------------------------------------------- /views/generic.map: -------------------------------------------------------------------------------- 1 | {{""" 2 | this is an example of usage of google map 3 | the web2py action should be something like: 4 | 5 | def map(): 6 | return dict( 7 | googlemap_key='...', 8 | center_latitude = 41.878, 9 | center_longitude = -87.629, 10 | scale = 7, 11 | maker = lambda point: A(row.id,_href='...') 12 | points = db(db.point).select() where a points have latitute and longitude 13 | ) 14 | 15 | the corresponding views/defaut/map.html should be something like: 16 | 17 | \{\{extend 'layout.html'\}\} 18 |
\{\{include 'generic.map'\}\}
19 | 20 | """}} 21 | 22 | 68 |
69 | 70 | -------------------------------------------------------------------------------- /static/css/team.css: -------------------------------------------------------------------------------- 1 | li { 2 | list-style: none; 3 | } 4 | 5 | .italic { 6 | font-style: italic; 7 | } 8 | 9 | .role_team { 10 | width: 180px; 11 | display:none; 12 | background-color:#fff; 13 | text-align: left; 14 | position: absolute; 15 | top: -5px; 16 | z-index: 9999; 17 | padding: 5px; 18 | border: 2px solid rgb(179, 179, 179); 19 | } 20 | 21 | .role_team p { 22 | color: rgb(114, 114, 114); 23 | } 24 | 25 | .question_role { 26 | font-style: italic; 27 | /*font-weight: bold;*/ 28 | font-size: 12.5px; 29 | } 30 | 31 | .edit_role { 32 | cursor: pointer; 33 | text-decoration: underline; 34 | font-style: italic; 35 | } 36 | 37 | .role_content { 38 | background-color: rgb(238, 235, 235); 39 | padding: 5px; 40 | margin-bottom: 5px; 41 | } 42 | 43 | .role_content hr { 44 | margin-top: 5px; 45 | margin-bottom: 10px; 46 | } 47 | 48 | .edit_role:hover { 49 | text-decoration: none; 50 | } 51 | 52 | #right_content { 53 | margin-left: 20px; 54 | } 55 | 56 | #addUsers_icons i.icon-user { 57 | font-size: 30px; 58 | color: #444444; 59 | } 60 | 61 | #addUsers_icons i.icon-plus { 62 | position: relative; 63 | top: 4px; 64 | right: 20px; 65 | color: rgb(126, 126, 126); 66 | font-size: 14px; 67 | text-shadow: -1px 0 #fff, 0 1px #fff, 1px 0 #fff, 0 -1px #fff; 68 | } 69 | 70 | #search_users, .select2-container, .select2-container-multi { 71 | width: 91%; 72 | } 73 | 74 | #search_users button { 75 | position: relative; 76 | right: 33px; 77 | } 78 | 79 | .thumbnails { 80 | text-align: center; 81 | min-height: 300px; 82 | } 83 | 84 | .users { 85 | min-height: 240px; 86 | } 87 | 88 | .thumbnails img { 89 | margin: 0 auto; 90 | } 91 | 92 | img.thumbnail_owner_project { 93 | background-color: #8ac401; 94 | box-shadow: 0px 1px 1px 1px #bb; 95 | webkit-box-shadow: 0px 1px 1px 1px #bb; 96 | /*padding-bottom: 20px; */ 97 | } 98 | 99 | 100 | .avatar-frame,.avatar-frame img{ 101 | -webkit-border-radius: 50px !important; 102 | border-radius: 50px !important; 103 | -moz-border-radius: 50px !important; 104 | } 105 | 106 | #owner_project { 107 | position: relative; 108 | bottom: 30px; 109 | color: #fff; 110 | text-shadow: 0px 0px 4px #000; 111 | font-weight: bold; 112 | } 113 | 114 | #owner_container { 115 | position: relative; 116 | bottom: 20px; 117 | } 118 | 119 | .users_container { 120 | position: relative; 121 | /*top: 15px;*/ 122 | } 123 | 124 | .users_container h5 { 125 | white-space: nowrap; 126 | overflow: hidden; 127 | text-overflow: ellipsis; 128 | } 129 | 130 | .cancel, .addrole { 131 | display:block; 132 | width: 45%!important; 133 | border-radius: 0px; 134 | background-color: rgb(228, 223, 223); 135 | color: #000; 136 | padding: 5px; 137 | text-align: center; 138 | } 139 | 140 | .addrole { 141 | float: left; 142 | } 143 | 144 | .cancel { 145 | float: right; 146 | } 147 | 148 | .cancel:hover { 149 | background-color: #ccc; 150 | color: #000; 151 | } 152 | 153 | .addrole:hover { 154 | background-color: #ccc!important; 155 | } 156 | -------------------------------------------------------------------------------- /static/js/highcharts/adapters/prototype-adapter.js: -------------------------------------------------------------------------------- 1 | /* 2 | Highcharts JS v3.0.1 (2013-04-09) 3 | Prototype adapter 4 | 5 | @author Michael Nelson, Torstein Hønsi. 6 | 7 | Feel free to use and modify this script. 8 | Highcharts license: www.highcharts.com/license. 9 | */ 10 | var HighchartsAdapter=function(){var f=typeof Effect!=="undefined";return{init:function(a){if(f)Effect.HighchartsTransition=Class.create(Effect.Base,{initialize:function(c,b,d,g){var e;this.element=c;this.key=b;e=c.attr?c.attr(b):$(c).getStyle(b);if(b==="d")this.paths=a.init(c,c.d,d),this.toD=d,e=0,d=1;this.start(Object.extend(g||{},{from:e,to:d,attribute:b}))},setup:function(){HighchartsAdapter._extend(this.element);if(!this.element._highchart_animation)this.element._highchart_animation={};this.element._highchart_animation[this.key]= 11 | this},update:function(c){var b=this.paths,d=this.element;b&&(c=a.step(b[0],b[1],c,this.toD));d.attr?d.element&&d.attr(this.options.attribute,c):(b={},b[this.options.attribute]=c,$(d).setStyle(b))},finish:function(){this.element&&this.element._highchart_animation&&delete this.element._highchart_animation[this.key]}})},adapterRun:function(a,c){return parseInt($(a).getStyle(c),10)},getScript:function(a,c){var b=$$("head")[0];b&&b.appendChild((new Element("script",{type:"text/javascript",src:a})).observe("load", 12 | c))},addNS:function(a){var c=/^(?:click|mouse(?:down|up|over|move|out))$/;return/^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/.test(a)||c.test(a)?a:"h:"+a},addEvent:function(a,c,b){a.addEventListener||a.attachEvent?Event.observe($(a),HighchartsAdapter.addNS(c),b):(HighchartsAdapter._extend(a),a._highcharts_observe(c,b))},animate:function(a,c,b){var d,b=b||{};b.delay=0;b.duration=(b.duration||500)/1E3;b.afterFinish=b.complete;if(f)for(d in c)new Effect.HighchartsTransition($(a), 13 | d,c[d],b);else{if(a.attr)for(d in c)a.attr(d,c[d]);b.complete&&b.complete()}a.attr||$(a).setStyle(c)},stop:function(a){var c;if(a._highcharts_extended&&a._highchart_animation)for(c in a._highchart_animation)a._highchart_animation[c].cancel()},each:function(a,c){$A(a).each(c)},inArray:function(a,c){return c.indexOf(a)},offset:function(a){return $(a).cumulativeOffset()},fireEvent:function(a,c,b,d){a.fire?a.fire(HighchartsAdapter.addNS(c),b):a._highcharts_extended&&(b=b||{},a._highcharts_fire(c,b)); 14 | b&&b.defaultPrevented&&(d=null);d&&d(b)},removeEvent:function(a,c,b){$(a).stopObserving&&(c&&(c=HighchartsAdapter.addNS(c)),$(a).stopObserving(c,b));window===a?Event.stopObserving(a,c,b):(HighchartsAdapter._extend(a),a._highcharts_stop_observing(c,b))},washMouseEvent:function(a){return a},grep:function(a,c){return a.findAll(c)},map:function(a,c){return a.map(c)},_extend:function(a){a._highcharts_extended||Object.extend(a,{_highchart_events:{},_highchart_animation:null,_highcharts_extended:!0,_highcharts_observe:function(c, 15 | a){this._highchart_events[c]=[this._highchart_events[c],a].compact().flatten()},_highcharts_stop_observing:function(a,b){a?b?this._highchart_events[a]=[this._highchart_events[a]].compact().flatten().without(b):delete this._highchart_events[a]:this._highchart_events={}},_highcharts_fire:function(a,b){var d=this;(this._highchart_events[a]||[]).each(function(a){if(!b.stopped)b.preventDefault=function(){b.defaultPrevented=!0},b.target=d,a.bind(this)(b)===!1&&b.preventDefault()}.bind(this))}})}}}(); 16 | -------------------------------------------------------------------------------- /static/js/bootstrap-custom-modal.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bootstrap.js by @fat & @mdo 3 | * plugins: bootstrap-modal.js 4 | * Copyright 2012 Twitter, Inc. 5 | * http://www.apache.org/licenses/LICENSE-2.0.txt 6 | */ 7 | !function(a){var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in").attr("aria-hidden",!1),b.enforceFocus(),c?b.$element.one(a.support.transition.end,function(){b.$element.focus().trigger("shown")}):b.$element.focus().trigger("shown")})},hide:function(b){b&&b.preventDefault();var c=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,this.escape(),a(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),a.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var b=this;a(document).on("focusin.modal",function(a){b.$element[0]!==a.target&&!b.$element.has(a.target).length&&b.$element.focus()})},escape:function(){var a=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(b){b.which==27&&a.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),b.hideModal()},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),b.hideModal()})},hideModal:function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a(''); 44 | // positioning 45 | var offset = $(element).closest(".task_container").offset(); 46 | 47 | var teamPosition = $(".users_team").outerWidth() + offset.left, 48 | teamPlacement = offset.left - $(".users_team").outerWidth() - 40; 49 | 50 | if(teamPosition > $(window).width()) { 51 | $(".users_team").css({left:teamPlacement,top:offset.top}); 52 | 53 | } else { 54 | $(".users_team").css({lef:offset.left,top:offset.top}); 55 | } 56 | 57 | $.getJSON(url.team_project, 58 | function(data) { 59 | if (data === "no_role" || data === "no_team") { 60 | html += '
' + msg[i] + '
' 61 | html += '' + txt.team_page + ''; 62 | 63 | } else { 64 | for (i in data) { 65 | html += '
' + data[i]["person_name"] + '
' + data[i]["person_role"] + '
' 66 | } 67 | html += '
Remove
' 68 | } 69 | $(".loading").hide(); 70 | self.closest(".task_container").find(".users_team").append(html); 71 | }); 72 | } 73 | 74 | // edit owner task 75 | $(document).on("click", ".project_member", function() { 76 | var task = $(this).closest(".card_container").find('.task_item'), 77 | alredy_exist = task.attr('data-update'), 78 | task_id = task.attr('data-pk'), 79 | person_id = $(this).attr('data-person'); 80 | 81 | if(person_id === "remove") { 82 | console.log(alredy_exist); 83 | ajax(url.edit_owner_task + '?task_id=' + task_id + '&person_id=' + person_id, [''], 'target_ajax'); 84 | statusAction("remove_owner", "", $(this)); 85 | return 86 | } 87 | 88 | if (alredy_exist === undefined) { 89 | alert(msg.task_no_exist) 90 | } else { 91 | ajax(url.edit_owner_task + '?task_id=' + task_id + '&person_id=' + person_id, [''], 'target_ajax'); 92 | statusAction("choose_owner", "", $(this)); 93 | } 94 | 95 | }); -------------------------------------------------------------------------------- /static/js/realtime.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | "use strict"; 3 | 4 | var host = window.location.host, 5 | window_focus = true, 6 | myGroup = "project" + infoGlobal.project_id, 7 | wsUri, 8 | ws, 9 | obj, 10 | querystring, 11 | container, 12 | selectorSortable, 13 | selector; 14 | 15 | // verify windows focus 16 | window.onblur = function() { window_focus = false; } 17 | window.onfocus = function() { window_focus = true; } 18 | 19 | if (host === "localhost:8000") { 20 | host = "127.0.0.1"; 21 | } else { 22 | host = "scrumfor.me"; 23 | } 24 | //create a new WebSocket object. 25 | wsUri = 'ws://' + host + ':8888/realtime/' + myGroup; 26 | 27 | ws = new WebSocket(wsUri); 28 | 29 | ws.onopen = function () { 30 | // Web Socket is connected 31 | // call users chat 32 | callChat(); 33 | // set this user online 34 | setTimeout(function () { 35 | usersOnlineNow(); 36 | },3000); 37 | }; 38 | ws.onmessage = function (event) { 39 | 40 | if (event.data === "+anonymous" || event.data === "-anonymous") { 41 | return false; 42 | } else { 43 | obj = JSON.parse(event.data); 44 | } 45 | 46 | if (obj.hasOwnProperty("page")) { 47 | 48 | if (obj.page === "board") { 49 | selector = '.item_container[data-definitionready="' + obj.definition_ready_id + '"]'; 50 | selectorSortable = selector + '> *'; 51 | 52 | } else if (obj.page === "product_backlog") { 53 | $("#backlog .project-items").load(window.location.href + ' #backlog .project-items > *'); 54 | selector = '#sprint .project-items'; 55 | selectorSortable = selector; 56 | } 57 | 58 | container = $(selector); 59 | container.load(window.location.href + ' ' + selector + '> *', function () { 60 | // these sortableOptions came from the file board.js 61 | $(selectorSortable).sortable(sortableOptions); 62 | }); 63 | 64 | } else if (obj.hasOwnProperty("chat")) { 65 | var message = urlize(obj.message, {nofollow: true, autoescape: true, target: "_blank"}), 66 | html = '

' + obj.name + ' - ' + obj.time + '' + message + '

', 67 | chat_timeline = $(".chat-content"), 68 | bottomChat = $("#bottom-chat"), 69 | atBottom = (chat_timeline[0].scrollHeight - chat_timeline.scrollTop() + 1 == chat_timeline.outerHeight()); 70 | chat_timeline.append(html); 71 | 72 | if (atBottom) { 73 | chat_timeline.scrollTop(chat_timeline[0].scrollHeight); 74 | 75 | if (bottomChat.is(":visible")) { 76 | bottomChat.fadeOut(); 77 | } 78 | 79 | } else { 80 | bottomChat.fadeIn(); 81 | } 82 | 83 | 84 | if(!window_focus) { 85 | // play sound on message 86 | $('#chatAudio')[0].play(); 87 | notify(obj.avatar, obj.name, message); 88 | } 89 | 90 | } else if (obj.hasOwnProperty("online")) { 91 | var usuario = $('.user_online[data-id="' + obj.person_id + '"]'); 92 | usuario.find(".status").attr("title","online"); 93 | usuario.find("i").addClass("color-green"); 94 | } 95 | 96 | }; 97 | ws.onerror = function(event){ 98 | console.log("Error Occurred - "+event.data); 99 | }; 100 | ws.onclose = function() { 101 | // websocket is closed. 102 | console.log("Connection is closed..."); 103 | }; 104 | }); 105 | -------------------------------------------------------------------------------- /views/default/check_your_email.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 13 | 14 | 17 | Scrumforme | {{=response.title or request.function}} 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 59 | 60 | 61 | 62 | 63 |
64 |
65 |
66 |
67 |
68 |

69 |
70 |
71 | 74 |
75 |
76 |
77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /static/css/home-syle.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | background-color: #34abbd; 4 | background-repeat: no-repeat; 5 | background-position: center; 6 | } 7 | 8 | ul { 9 | margin: 0; 10 | } 11 | 12 | header { 13 | width: 80%; 14 | margin: 0 auto; 15 | } 16 | 17 | p { 18 | font-family: 'Helvetica', cursive; 19 | color: #197a8b; 20 | font-size: 20px; 21 | text-align: center; 22 | } 23 | 24 | .color-logo{ 25 | color: #00A0B1; 26 | } 27 | 28 | #login { 29 | margin-top: 20px; 30 | } 31 | 32 | .dropdown { 33 | list-style: none; 34 | } 35 | 36 | /*#register { 37 | width: 40%; 38 | margin-top: 20px; 39 | text-transform: uppercase; 40 | font-weight: bold; 41 | }*/ 42 | 43 | .container { 44 | min-height: 100%; 45 | height: auto !important; 46 | height: 100%; 47 | margin: 0 auto -100px; /* the bottom margin is the negative value of the footer's height */ 48 | } 49 | 50 | .content-center { 51 | color: #fff; 52 | text-align: center; 53 | padding-top: 96px; 54 | } 55 | 56 | .content-center h2{ 57 | font-weight:normal; 58 | font-family: 'Quicksand', sans-serif; 59 | text-transform:uppercase; 60 | font-size:60px; 61 | line-height:55px; 62 | } 63 | 64 | .content-center p{ 65 | font-size:18px; 66 | padding:10px; 67 | line-height:25px; 68 | font-family:'Oswald',Arial,Helvetica,sans-serif; 69 | } 70 | 71 | footer { 72 | background-color: #18798a; 73 | height: 3em; 74 | width: 100%; 75 | position: absolute; 76 | left: 0; 77 | bottom: 0; 78 | } 79 | 80 | footer p { 81 | color: #ffffff; 82 | font-size: .8rem; 83 | margin-top: 12px; 84 | text-align: center; 85 | } 86 | 87 | footer p a, footer p a:visited{ 88 | color: #c2e6eb; 89 | font-size: .8rem; 90 | margin-top: 12px; 91 | text-align: center; 92 | } 93 | 94 | footer p a:hover{ 95 | text-decoration: underline; 96 | color: #c2e6eb; 97 | font-size: .8rem; 98 | margin-top: 12px; 99 | text-align: center; 100 | } 101 | 102 | .push { 103 | height: 96px; /* .push must be the same height as .footer */ 104 | } 105 | 106 | footer img { 107 | margin: 0 auto; 108 | display: block; 109 | } 110 | #texto-logo { 111 | width: 390px; 112 | margin-top: 45px; 113 | display: inline-block; 114 | } 115 | 116 | #texto-logo p { 117 | text-align: left; 118 | font-size: 1.5em; 119 | line-height: 25px; 120 | } 121 | 122 | @media (max-width: 480px) { 123 | body{ 124 | margin: 0px; 125 | border: 0px; 126 | padding: 0px; 127 | } 128 | #texto-logo img{ 129 | width: 294px; 130 | height: 54px; 131 | margin: 0 auto; 132 | } 133 | html,body { 134 | background-image: none; 135 | } 136 | #texto-logo{ 137 | width: 305px; 138 | margin: 0 auto; 139 | } 140 | #texto-logo p{ 141 | font-size: 14px; 142 | } 143 | .bloco_grande{ 144 | width: 275px; 145 | margin: 0 auto; 146 | margin-top: 30px; 147 | float: none; 148 | } 149 | header{ 150 | width: 100%; 151 | } 152 | 153 | } 154 | @media (min-width: 481px) and (max-width: 768px) { 155 | body{ 156 | margin: 0px; 157 | border: 0px; 158 | padding: 0px; 159 | } 160 | #texto-logo img{ 161 | width: 80%; 162 | margin: 0 auto; 163 | } 164 | html,body { 165 | background-image: none; 166 | } 167 | #texto-logo{ 168 | width: 80%; 169 | margin: 0 auto; 170 | } 171 | #texto-logo p{ 172 | font-size: 18px; 173 | } 174 | .bloco_grande{ 175 | width: 350px; 176 | margin: 0 auto; 177 | margin-top: 30px; 178 | float: none; 179 | } 180 | header{ 181 | width: 100%; 182 | } 183 | } 184 | @media (min-width: 769px) and (max-width: 1024px) { 185 | #texto-logo{ 186 | margin-left: -50px; 187 | } 188 | .bloco_grande { 189 | height: 349px; 190 | float: right; 191 | margin-right: -60px; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /static/js/date.format.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Date Format 1.2.3 3 | * (c) 2007-2009 Steven Levithan 4 | * MIT license 5 | * 6 | * Includes enhancements by Scott Trenda 7 | * and Kris Kowal 8 | * 9 | * Accepts a date, a mask, or a date and a mask. 10 | * Returns a formatted version of the given date. 11 | * The date defaults to the current date/time. 12 | * The mask defaults to dateFormat.masks.default. 13 | */ 14 | 15 | var dateFormat = function () { 16 | var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, 17 | timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g, 18 | timezoneClip = /[^-+\dA-Z]/g, 19 | pad = function (val, len) { 20 | val = String(val); 21 | len = len || 2; 22 | while (val.length < len) val = "0" + val; 23 | return val; 24 | }; 25 | 26 | // Regexes and supporting functions are cached through closure 27 | return function (date, mask, utc) { 28 | var dF = dateFormat; 29 | 30 | // You can't provide utc if you skip other args (use the "UTC:" mask prefix) 31 | if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) { 32 | mask = date; 33 | date = undefined; 34 | } 35 | 36 | // Passing date through Date applies Date.parse, if necessary 37 | date = date ? new Date(date) : new Date; 38 | if (isNaN(date)) throw SyntaxError("invalid date"); 39 | 40 | mask = String(dF.masks[mask] || mask || dF.masks["default"]); 41 | 42 | // Allow setting the utc argument via the mask 43 | if (mask.slice(0, 4) == "UTC:") { 44 | mask = mask.slice(4); 45 | utc = true; 46 | } 47 | 48 | var _ = utc ? "getUTC" : "get", 49 | d = date[_ + "Date"](), 50 | D = date[_ + "Day"](), 51 | m = date[_ + "Month"](), 52 | y = date[_ + "FullYear"](), 53 | H = date[_ + "Hours"](), 54 | M = date[_ + "Minutes"](), 55 | s = date[_ + "Seconds"](), 56 | L = date[_ + "Milliseconds"](), 57 | o = utc ? 0 : date.getTimezoneOffset(), 58 | flags = { 59 | d: d, 60 | dd: pad(d), 61 | ddd: dF.i18n.dayNames[D], 62 | dddd: dF.i18n.dayNames[D + 7], 63 | m: m + 1, 64 | mm: pad(m + 1), 65 | mmm: dF.i18n.monthNames[m], 66 | mmmm: dF.i18n.monthNames[m + 12], 67 | yy: String(y).slice(2), 68 | yyyy: y, 69 | h: H % 12 || 12, 70 | hh: pad(H % 12 || 12), 71 | H: H, 72 | HH: pad(H), 73 | M: M, 74 | MM: pad(M), 75 | s: s, 76 | ss: pad(s), 77 | l: pad(L, 3), 78 | L: pad(L > 99 ? Math.round(L / 10) : L), 79 | t: H < 12 ? "a" : "p", 80 | tt: H < 12 ? "am" : "pm", 81 | T: H < 12 ? "A" : "P", 82 | TT: H < 12 ? "AM" : "PM", 83 | Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""), 84 | o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), 85 | S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] 86 | }; 87 | 88 | return mask.replace(token, function ($0) { 89 | return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); 90 | }); 91 | }; 92 | }(); 93 | 94 | // Some common format strings 95 | dateFormat.masks = { 96 | "default": "ddd mmm dd yyyy HH:MM:ss", 97 | shortDate: "m/d/yy", 98 | mediumDate: "mmm d, yyyy", 99 | longDate: "mmmm d, yyyy", 100 | fullDate: "dddd, mmmm d, yyyy", 101 | shortTime: "h:MM TT", 102 | mediumTime: "h:MM:ss TT", 103 | longTime: "h:MM:ss TT Z", 104 | isoDate: "yyyy-mm-dd", 105 | isoTime: "HH:MM:ss", 106 | isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", 107 | isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" 108 | }; 109 | 110 | // Internationalization strings 111 | dateFormat.i18n = { 112 | dayNames: [ 113 | "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 114 | "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" 115 | ], 116 | monthNames: [ 117 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 118 | "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" 119 | ] 120 | }; 121 | 122 | // For convenience... 123 | Date.prototype.format = function (mask, utc) { 124 | return dateFormat(this, mask, utc); 125 | }; 126 | 127 | -------------------------------------------------------------------------------- /static/css/web2py_bootstrap_nojs.css: -------------------------------------------------------------------------------- 1 | /*============================================================= 2 | BOOTSTRAP DROPDOWN MENU 3 | ==============================================================*/ 4 | 5 | .dropdown-menu ul{ 6 | left:100%; 7 | position:absolute; 8 | top:0; 9 | visibility:hidden; 10 | margin-top:-1px; 11 | } 12 | .dropdown-menu li:hover ul{visibility:visible;} 13 | .navbar .dropdown-menu ul:before{ 14 | border-bottom:7px solid transparent; 15 | border-left:none; 16 | border-right:7px solid rgba(0, 0, 0, 0.2); 17 | border-top:7px solid transparent; 18 | left:-7px; 19 | top:5px; 20 | } 21 | .nav > li.dropdown > a:after { 22 | border-left: 4px solid transparent; 23 | border-right: 4px solid transparent; 24 | border-top: 4px solid #000000; 25 | content: ""; 26 | display: inline-block; 27 | height: 0; 28 | opacity: 0.7; 29 | vertical-align: top; 30 | width: 0; 31 | 32 | margin-left: 2px; 33 | margin-top: 8px; 34 | 35 | border-bottom-color: #FFFFFF; 36 | border-top-color: #FFFFFF; 37 | } 38 | .dropdown-menu span{display:inline-block;} 39 | ul.dropdown-menu li.dropdown > a:after { 40 | border-left: 4px solid #000; 41 | border-right: 4px solid transparent; 42 | border-bottom: 4px solid transparent; 43 | border-top: 4px solid transparent; 44 | content: ""; 45 | display: inline-block; 46 | height: 0; 47 | opacity: 0.7; 48 | vertical-align: top; 49 | width: 0; 50 | 51 | margin-left: 8px; 52 | margin-top: 6px; 53 | } 54 | 55 | ul.nav li.dropdown:hover ul.dropdown-menu { 56 | display: block; 57 | } 58 | 59 | .open >.dropdown-menu ul{display:block;} /* fix menu issue when BS2.0.4 is applied */ 60 | 61 | /*============================================================= 62 | BOOTSTRAP SUBMIT BUTTON 63 | ==============================================================*/ 64 | 65 | input[type='submit']:not(.btn) { 66 | display: inline-block; 67 | padding: 4px 14px; 68 | margin-bottom: 0; 69 | font-size: 14px; 70 | line-height: 20px; 71 | color: #333; 72 | text-align: center; 73 | text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); 74 | vertical-align: middle; 75 | cursor: pointer; 76 | background-color: whiteSmoke; 77 | background-image: -webkit-gradient(linear,0 0,0 100%,from(white),to(#E6E6E6)); 78 | background-image: -webkit-linear-gradient(top,white,#E6E6E6); 79 | background-image: -o-linear-gradient(top,white,#E6E6E6); 80 | background-image: linear-gradient(to bottom,white,#E6E6E6); 81 | background-image: -moz-linear-gradient(top,white,#E6E6E6); 82 | background-repeat: repeat-x; 83 | border: 1px solid #BBB; 84 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 85 | border-bottom-color: #A2A2A2; 86 | -webkit-border-radius: 4px; 87 | -moz-border-radius: 4px; 88 | border-radius: 4px; 89 | filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0); 90 | filter: progid:dximagetransform.microsoft.gradient(enabled=false); 91 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05); 92 | -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05); 93 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05); 94 | } 95 | 96 | input[type='submit']:not(.btn):hover { 97 | color: #333; 98 | text-decoration: none; 99 | background-color: #E6E6E6; 100 | background-position: 0 -15px; 101 | -webkit-transition: background-position .1s linear; 102 | -moz-transition: background-position .1s linear; 103 | -o-transition: background-position .1s linear; 104 | transition: background-position .1s linear; 105 | } 106 | 107 | input[type='submit']:not(.btn).active, input[type='submit']:not(.btn):active { 108 | background-color: #E6E6E6; 109 | background-color: #D9D9D9 9; 110 | background-image: none; 111 | outline: 0; 112 | -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 113 | -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05); 114 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 115 | } 116 | 117 | /*============================================================= 118 | OTHER 119 | ==============================================================*/ 120 | 121 | .ie-lte8 .navbar-fixed-top {position:static;} 122 | 123 | -------------------------------------------------------------------------------- /static/js/sprints-modal.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | "use strict"; 3 | 4 | var body = $("body"); 5 | /* 6 | ============ 7 | OPEN MODAL 8 | ============ 9 | */ 10 | $(document).on("click", ".card-modal", function () { 11 | $(".loading_item").fadeIn("fast"); 12 | 13 | var task_id = $(this).find(".task_item").attr("data-pk"); 14 | // store card element 15 | // body.data('card_element', card_element); 16 | 17 | // remove last append modal in body 18 | $("#card_modal").remove(); 19 | // loading modal content 20 | $.getJSON(url.card_modal + "?task_id=" + task_id + "&project_id=" + info.project_id, 21 | function (data) { 22 | if (data === false) { 23 | $(".loading_item").fadeOut("fast"); 24 | alert(msg.no_team); 25 | 26 | } else { 27 | // console.log(data); 28 | $(".loading_item").fadeOut("fast"); 29 | var modal = ''; 30 | // insert modal in body 31 | var screenTop = $(document).scrollTop(); 32 | $(modal).css({top: screenTop + 30 }).appendTo(body); 33 | 34 | var modal_element = $("#card_modal"), 35 | modal_content = modal_element.find("#modal_content"), 36 | member_modal = modal_element.find("#member_modal"), 37 | date_element = modal_element.find('#started_calendar'), 38 | html = ""; 39 | 40 | html += ''; 41 | modal_content.append(html); 42 | 43 | // sidebar user 44 | member_modal.html('

' + data.user_relationship.member_name + '

'); 45 | 46 | // call the modal 47 | modal_element.modal('show').attr("data-task", task_id); 48 | 49 | // commentbox 50 | var comment_box = ''; 51 | modal_content.append(comment_box); 52 | 53 | // start comments 54 | if (data.comments) { 55 | // console.log(data.comments); 56 | var keys = Object.keys(data.comments), // or loop over the object to get the array 57 | key = "", 58 | value = "", 59 | new_comment = "", 60 | person_owner_comment = ""; 61 | keys.reverse(); // maybe use custom reverse, to change direction use .sort() 62 | // keys now will be in wanted order 63 | for (var i = 0; i < keys.length; i++ ) { // now lets iterate in reverse order 64 | key = keys[i]; 65 | value = data.comments[key]; 66 | // url parse to link 67 | new_comment = urlize(value["text"], {nofollow: true, autoescape: true, target: "_blank"}); 68 | $("#modal_comments").append('

' + value["name"] + ' - ' + value["role"] + '

' + new_comment + '

  • ' + value["date"] + '
'); 69 | } // end loop 70 | } // end comments 71 | } // data via ajax 72 | 73 | // hide gif loading 74 | $(".loading").hide(); 75 | // prevent link default 76 | var nav = modal_element.find(".nav"); 77 | nav.click(function(e){ 78 | e.preventDefault(); 79 | }); 80 | 81 | }); // end getJSON 82 | }); 83 | 84 | })(); -------------------------------------------------------------------------------- /views/default/chat.html: -------------------------------------------------------------------------------- 1 | 16 | 17 | -------------------------------------------------------------------------------- /models/00_db.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ######################################################################### 4 | ## This scaffolding model makes your app work on Google App Engine too 5 | ## File is released under public domain and you can use without limitations 6 | ######################################################################### 7 | 8 | ## if SSL/HTTPS is properly configured and you want all HTTP requests to 9 | ## be redirected to HTTPS, uncomment the line below: 10 | # request.requires_https() 11 | 12 | if not request.env.web2py_runtime_gae: 13 | ## if NOT running on Google App Engine use SQLite or other DB 14 | db = DAL('sqlite://storage.sqlite',pool_size=1,check_reserved=['all']) 15 | else: 16 | ## connect to Google BigTable (optional 'google:datastore://namespace') 17 | db = DAL('google:datastore') 18 | ## store sessions and tickets there 19 | session.connect(request, response, db=db) 20 | ## or store session in Memcache, Redis, etc. 21 | ## from gluon.contrib.memdb import MEMDB 22 | ## from google.appengine.api.memcache import Client 23 | ## session.connect(request, response, db = MEMDB(Client())) 24 | 25 | ## by default give a view/generic.extension to all actions from localhost 26 | ## none otherwise. a pattern can be 'controller/function.extension' 27 | response.generic_patterns = ['*'] if request.is_local else [] 28 | ## (optional) optimize handling of static files 29 | # response.optimize_css = 'concat,minify,inline' 30 | # response.optimize_js = 'concat,minify,inline' 31 | 32 | ######################################################################### 33 | ## Here is sample code if you need for 34 | ## - email capabilities 35 | ## - authentication (registration, login, logout, ... ) 36 | ## - authorization (role based authorization) 37 | ## - services (xml, csv, json, xmlrpc, jsonrpc, amf, rss) 38 | ## - old style crud actions 39 | ## (more options discussed in gluon/tools.py) 40 | ######################################################################### 41 | 42 | from gluon.tools import Auth, Crud, Service, PluginManager, prettydate, Mail 43 | auth = Auth(db) 44 | crud, service, plugins = Crud(db), Service(), PluginManager() 45 | 46 | # extra fields 47 | auth.settings.extra_fields['auth_user']= [ 48 | Field("type_network", "string", length=128, default=""), 49 | Field("token", "string", length=128, default=""), 50 | Field("first_time", "boolean", default=True), 51 | ] 52 | 53 | 54 | ## create all tables needed by auth if not custom tables 55 | auth.define_tables(username=False, signature=False) 56 | 57 | # hide fields 58 | fields_to_hide = [ 59 | 'type_network', 'token', 'first_time'] 60 | 61 | for fieldname in fields_to_hide: 62 | field = db.auth_user[fieldname] 63 | field.readable = field.writable = False 64 | 65 | ## imported variables 66 | from data_config import EMAIL_SERVER, CLIENT_EMAIL, CLIENT_LOGIN 67 | 68 | ## configure email 69 | mail = Mail() 70 | mail.settings.server = EMAIL_SERVER 71 | mail.settings.sender = CLIENT_EMAIL 72 | mail.settings.login = CLIENT_LOGIN 73 | auth.settings.mailer = mail 74 | 75 | ## configure auth policy 76 | auth.settings.registration_requires_verification = True 77 | auth.settings.registration_requires_approval = False 78 | auth.settings.reset_password_requires_verification = True 79 | 80 | # 81 | # see file 'auth_settings' for more details 82 | # 83 | 84 | # import the gravatar 85 | try: 86 | from gravatar import Gravatar 87 | except ImportError: 88 | from gluon.contrib.gravatar import Gravatar 89 | 90 | # multiples languages 91 | if 'siteLanguage' in request.cookies and not (request.cookies['siteLanguage'] is None): 92 | T.force(request.cookies['siteLanguage'].value) 93 | 94 | ## if you need to use OpenID, Facebook, MySpace, Twitter, Linkedin, etc. 95 | ## register with janrain.com, write your domain:api_key in private/janrain.key 96 | from gluon.contrib.login_methods.rpx_account import use_janrain 97 | use_janrain(auth, filename='private/janrain.key') 98 | 99 | ######################################################################### 100 | ## Define your tables below (or better in another model file) for example 101 | ## 102 | ## >>> db.define_table('mytable',Field('myfield','string')) 103 | ## 104 | ## Fields can be 'string','text','password','integer','double','boolean' 105 | ## 'date','time','datetime','blob','upload', 'reference TABLENAME' 106 | ## There is an implicit 'id integer autoincrement' field 107 | ## Consult manual for more options, validators, etc. 108 | ## 109 | ## More API examples for controllers: 110 | ## 111 | ## >>> db.mytable.insert(myfield='value') 112 | ## >>> rows=db(db.mytable.myfield=='value').select(db.mytable.ALL) 113 | ## >>> for row in rows: print row.id, row.myfield 114 | ######################################################################### 115 | 116 | ## after defining tables, uncomment below to enable auditing 117 | # auth.enable_record_versioning(db) 118 | -------------------------------------------------------------------------------- /static/css/user.css: -------------------------------------------------------------------------------- 1 | /* =Register or Sign in Page 2 | -------------------------------------------------------------- */ 3 | body { 4 | margin: 0; 5 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 6 | font-size: 14px; 7 | line-height: 20px; 8 | color: #333333; 9 | background-color: #f3f3f3; 10 | -webkit-font-smoothing: antialiased; 11 | background-color: #34abbd; 12 | } 13 | 14 | h1, h2, h3, h4, h5, h6 { 15 | margin: 10px 0; 16 | font-family: inherit; 17 | font-weight: bold; 18 | line-height: 20px; 19 | color: inherit; 20 | text-rendering: optimizelegibility; 21 | font-family: 'Helvetica', cursive; 22 | color: #FFF; 23 | font-size: 20px; 24 | text-align: center; 25 | } 26 | 27 | form table { 28 | margin: 0 auto; 29 | } 30 | 31 | .error { 32 | color: red; 33 | } 34 | 35 | .hgroup { 36 | border-bottom: 1px solid #cccccc; 37 | margin: 15px 0px; 38 | padding: 10px 0 10px 0; 39 | } 40 | 41 | .hgroup h1 { 42 | font-size: 30px; 43 | font-weight: 300; 44 | line-height: 1em; 45 | margin: 0 0 0.3em 0; 46 | padding: 0; 47 | } 48 | 49 | .signin, .signup { 50 | margin: 10px; 51 | } 52 | 53 | .signin { 54 | text-align: center; 55 | background-color: #ffffff; 56 | padding: 40px 40px 10px 40px; 57 | border: solid 1px #e7e7e7; 58 | margin-bottom: 24px; 59 | -webkit-box-sizing: border-box; 60 | -moz-box-sizing: border-box; 61 | box-sizing: border-box; 62 | -webkit-box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.1); 63 | -moz-box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.1); 64 | box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.1); 65 | -webkit-border-radius: 3px; 66 | -moz-border-radius: 3px; 67 | border-radius: 3px; 68 | } 69 | .signin form .forgot { 70 | padding: 0 0 20px 0; 71 | font-weight: 300; 72 | } 73 | .signin form .forgot label.checkbox { 74 | font-weight: 300; 75 | } 76 | .signin form .forgot label.checkbox input[type="checkbox"] { 77 | float: none; 78 | position: relative; 79 | left: 0; 80 | top: -3px; 81 | } 82 | .social_sign h3 { 83 | font-weight: 300; 84 | font-size: 20px; 85 | margin-bottom: 30px; 86 | line-height: 22px; 87 | } 88 | .social_sign a { 89 | background-color: #0085c8; 90 | color: #ffffff; 91 | text-align: center; 92 | display: inline-block; 93 | margin: 0 8px; 94 | -webkit-border-radius: 500px; 95 | -moz-border-radius: 500px; 96 | border-radius: 500px; 97 | font-size: 30px; 98 | width: 30px; 99 | height: 30px; 100 | padding: 18px; 101 | -webkit-transition: all 100ms linear; 102 | -moz-transition: all 100ms linear; 103 | -o-transition: all 100ms linear; 104 | transition: all 100ms linear; 105 | } 106 | .social_sign a.fb { 107 | background-color: #3B5998; 108 | } 109 | .icon-facebook { 110 | /*background-color: #fff;*/ 111 | /*color: #3B5998;*/ 112 | /*background-color: #3B5998;*/ 113 | } 114 | .social_sign a.tw { 115 | background-color: #00ACEE; 116 | } 117 | .social_sign a.gp { 118 | background-color: #E44B39; 119 | } 120 | .social_sign a:link, 121 | .social_sign a:visited { 122 | color: #ffffff; 123 | } 124 | .social_sign a:hover, 125 | .social_sign a:active { 126 | -moz-transform: scale(1.1) rotate(0deg) translateX(0px) translateY(0px) skewX(0deg) skewY(0deg); 127 | -webkit-transform: scale(1.1) rotate(0deg) translateX(0px) translateY(0px) skewX(0deg) skewY(0deg); 128 | -o-transform: scale(1.1) rotate(0deg) translateX(0px) translateY(0px) skewX(0deg) skewY(0deg); 129 | -ms-transform: scale(1.1) rotate(0deg) translateX(0px) translateY(0px) skewX(0deg) skewY(0deg); 130 | transform: scale(1.1) rotate(0deg) translateX(0px) translateY(0px) skewX(0deg) skewY(0deg); 131 | text-decoration: none; 132 | } 133 | .or { 134 | overflow: hidden; 135 | text-align: center; 136 | padding: 30px 0 0 0; 137 | } 138 | .or .or_l, 139 | .or .or_r { 140 | width: 40%; 141 | border-bottom: solid 1px #cccccc; 142 | display: inline-block; 143 | position: relative; 144 | left: 0px; 145 | top: -4px; 146 | } 147 | .or span { 148 | width: 8%; 149 | display: inline-block; 150 | } 151 | p.sign_title { 152 | font-weight: 300; 153 | padding: 30px 0 20px 0; 154 | } 155 | .signup { 156 | text-align: center; 157 | background-color: #ffffff; 158 | padding: 40px 40px 10px 40px; 159 | border: solid 1px #e7e7e7; 160 | margin-bottom: 24px; 161 | -webkit-box-sizing: border-box; 162 | -moz-box-sizing: border-box; 163 | box-sizing: border-box; 164 | -webkit-box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.1); 165 | -moz-box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.1); 166 | box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 0.1); 167 | -webkit-border-radius: 3px; 168 | -moz-border-radius: 3px; 169 | border-radius: 3px; 170 | } 171 | .signup .social_sign a { 172 | position: relative; 173 | bottom: 15px; 174 | } 175 | .signup form label.checkbox { 176 | font-weight: 300; 177 | } 178 | .signup form label.checkbox input[type="checkbox"] { 179 | float: none; 180 | position: relative; 181 | left: 0; 182 | top: -3px; 183 | } 184 | 185 | input[type="text"] , input[type="email"] , input[type="password"]{ 186 | background-color: #a8d9e0; 187 | height: 20px; 188 | width: 70%; 189 | } 190 | 191 | input[type='submit'] { 192 | color: #fff; 193 | } 194 | 195 | .signup form .btn { 196 | margin-top: 50px; 197 | } 198 | -------------------------------------------------------------------------------- /views/default/team.html: -------------------------------------------------------------------------------- 1 | {{extend 'default/layout_base.html'}} 2 | 17 | 18 |
19 | {{include "default/project_info.html"}} 20 |
21 |
22 | {{ if owner_project or project_admin: }} 23 |

{{=T("Add professionals in your project team")}}

24 |
25 | 26 | 27 |
28 |
29 | 30 | 31 |
32 | {{pass}} 33 |
34 |
35 |
36 |
37 | 38 |
39 | 40 | 41 | {{if team_members:}} 42 |

{{=T('Members')}}:

43 |
    44 | {{ for member in team_members: }} 45 |
  • 46 | {{if member.sharing.person_id == owner_project_person_id: }} 47 | {{=member.sharing.person_id.name}} 48 |

    {{=T("Owner")}}

    49 |
    50 | {{else:}} 51 | {{=member.sharing.person_id.name}} 52 |
    53 | {{pass}} 54 |
    {{=member.sharing.person_id.name}}
    55 | {{if owner_project or project_admin:}} 56 | 57 | {{if member.sharing.role_id:}} 58 | {{=T(member.sharing.role_id.name)}} 59 | {{else:}} 60 | {{=T("Define role")}} 61 | {{pass}} 62 | 63 | {{else:}} 64 | {{if member.sharing.role_id:}} 65 |

    {{=T(member.sharing.role_id.name)}}

    66 | {{else:}} 67 |

    {{=T("No role")}}

    68 | {{pass}} 69 | {{pass}} 70 | {{if owner_project or project_admin:}} 71 |
    72 |
    73 | 74 | {{pass}} 75 |
    76 |

    {{=T("Manage User")}}

    77 |
    78 |

    {{=T("What role this person will perform in the project?")}}

    79 | {{ for role in roles: }} 80 | {{ if member.sharing.role_id:}} 81 | 86 | {{else:}} 87 | 90 | {{ pass }} 91 | {{ pass }} 92 |
    93 | 97 |
    98 | 99 | {{=T("Cancel")}} 100 |
    101 |
    102 |
    103 |
  • 104 | {{ pass }} 105 |
106 | {{pass}} 107 | 108 |
109 | -------------------------------------------------------------------------------- /languages/default.py: -------------------------------------------------------------------------------- 1 | # coding: utf8 2 | { 3 | '!langcode!': 'en-us', 4 | '!langname!': 'English (US)', 5 | '%s %%(shop)': '%s %%(shop)', 6 | '%s %%(shop[0])': '%s %%(shop[0])', 7 | '%s %%{quark[0]}': '%s %%{quark[0]}', 8 | '%s %%{shop[0]}': '%s %%{shop[0]}', 9 | '%s %%{shop}': '%s %%{shop}', 10 | '%Y-%m-%d': '%Y-%m-%d', 11 | '%Y-%m-%d %H:%M:%S': '%Y-%m-%d %H:%M:%S', 12 | '@markmin\x01**Hello World**': '**Hello World**', 13 | 'About': 'About', 14 | 'Access Control': 'Access Control', 15 | 'Administrative Interface': 'Administrative Interface', 16 | 'Ajax Recipes': 'Ajax Recipes', 17 | 'Are you sure you want to delete this object?': 'Are you sure you want to delete this object?', 18 | 'Buy this book': 'Buy this book', 19 | 'Cannot be empty': 'Cannot be empty', 20 | 'Check to delete': 'Check to delete', 21 | 'Client IP': 'Client IP', 22 | 'Community': 'Community', 23 | 'Components and Plugins': 'Components and Plugins', 24 | 'Controller': 'Controller', 25 | 'Copyright': 'Copyright', 26 | 'Created By': 'Created By', 27 | 'Created On': 'Created On', 28 | 'customize me!': 'customize me!', 29 | 'Database': 'Database', 30 | 'DB Model': 'DB Model', 31 | 'Demo': 'Demo', 32 | 'Deployment Recipes': 'Deployment Recipes', 33 | 'Description': 'Description', 34 | 'Documentation': 'Documentation', 35 | "Don't know what to do?": "Don't know what to do?", 36 | 'Download': 'Download', 37 | 'E-mail': 'E-mail', 38 | 'Email and SMS': 'Email and SMS', 39 | 'enter an integer between %(min)g and %(max)g': 'enter an integer between %(min)g and %(max)g', 40 | 'enter date and time as %(format)s': 'enter date and time as %(format)s', 41 | 'Errors': 'Errors', 42 | 'FAQ': 'FAQ', 43 | 'First name': 'First name', 44 | 'Forms and Validators': 'Forms and Validators', 45 | 'Free Applications': 'Free Applications', 46 | 'Group %(group_id)s created': 'Group %(group_id)s created', 47 | 'Group ID': 'Group ID', 48 | 'Group uniquely assigned to user %(id)s': 'Group uniquely assigned to user %(id)s', 49 | 'Groups': 'Groups', 50 | 'Hello World': 'Hello World', 51 | 'Hello World ## comment': 'Hello World ', 52 | 'Hello World## comment': 'Hello World', 53 | 'Home': 'Home', 54 | 'How did you get here?': 'How did you get here?', 55 | 'Introduction': 'Introduction', 56 | 'Invalid email': 'Invalid email', 57 | 'Is Active': 'Is Active', 58 | 'Last name': 'Last name', 59 | 'Layout': 'Layout', 60 | 'Layout Plugins': 'Layout Plugins', 61 | 'Layouts': 'Layouts', 62 | 'Live Chat': 'Live Chat', 63 | 'Logged in': 'Logged in', 64 | 'Logged out': 'Logged out', 65 | 'Login': 'Login', 66 | 'Logout': 'Logout', 67 | 'Lost Password': 'Lost Password', 68 | 'Lost password?': 'Lost password?', 69 | 'Menu Model': 'Menu Model', 70 | 'Modified By': 'Modified By', 71 | 'Modified On': 'Modified On', 72 | 'My Sites': 'My Sites', 73 | 'Name': 'Name', 74 | 'Object or table name': 'Object or table name', 75 | 'Online examples': 'Online examples', 76 | 'Origin': 'Origin', 77 | 'Other Plugins': 'Other Plugins', 78 | 'Other Recipes': 'Other Recipes', 79 | 'Overview': 'Overview', 80 | 'Password': 'Password', 81 | "Password fields don't match": "Password fields don't match", 82 | 'please input your password again': 'please input your password again', 83 | 'Plugins': 'Plugins', 84 | 'Powered by': 'Powered by', 85 | 'Preface': 'Preface', 86 | 'Profile': 'Profile', 87 | 'Python': 'Python', 88 | 'Quick Examples': 'Quick Examples', 89 | 'Recipes': 'Recipes', 90 | 'Record ID': 'Record ID', 91 | 'Register': 'Register', 92 | 'Registration identifier': 'Registration identifier', 93 | 'Registration key': 'Registration key', 94 | 'Registration successful': 'Registration successful', 95 | 'Remember me (for 30 days)': 'Remember me (for 30 days)', 96 | 'Reset Password key': 'Reset Password key', 97 | 'Role': 'Role', 98 | 'Semantic': 'Semantic', 99 | 'Services': 'Services', 100 | 'Stylesheet': 'Stylesheet', 101 | 'Support': 'Support', 102 | 'The Core': 'The Core', 103 | 'The output of the file is a dictionary that was rendered by the view %s': 'The output of the file is a dictionary that was rendered by the view %s', 104 | 'The Views': 'The Views', 105 | 'This App': 'This App', 106 | 'Timestamp': 'Timestamp', 107 | 'Twitter': 'Twitter', 108 | 'User %(id)s Logged-in': 'User %(id)s Logged-in', 109 | 'User %(id)s Logged-out': 'User %(id)s Logged-out', 110 | 'User %(id)s Registered': 'User %(id)s Registered', 111 | 'User ID': 'User ID', 112 | 'value already in database or empty': 'value already in database or empty', 113 | 'Verify Password': 'Verify Password', 114 | 'Videos': 'Videos', 115 | 'View': 'View', 116 | 'Welcome': 'Welcome', 117 | 'Welcome to web2py!': 'Welcome to web2py!', 118 | 'Which called the function %s located in the file %s': 'Which called the function %s located in the file %s', 119 | 'You are successfully running web2py': 'You are successfully running web2py', 120 | 'You can modify this application and adapt it to your needs': 'You can modify this application and adapt it to your needs', 121 | 'You visited the url %s': 'You visited the url %s', 122 | 'Welcome to scrumforme!': 'Welcome to scrumforme!', 123 | 'The field name can not be empty!': 'The field name can not be empty!', 124 | 'This field can not be empty!': 'This field can not be empty!', 125 | 'Choose how many weeks for your sprint!': 'Choose how many weeks for your sprint!', 126 | 'Name': 'Name', 127 | 'Description': 'Description', 128 | 'Date': 'Date', 129 | 'CREATE': 'CREATE', 130 | 'Title': 'Title', 131 | 'Benefit': 'Benefit', 132 | 'Story points': 'Story points', 133 | 'Projects': 'Projects', 134 | 'Stories': 'Stories', 135 | 'Create Story': 'Create Story', 136 | 'Choose a value': 'Choose a value', 137 | 'Form contains errors. Please check!': 'Formulário contem erros. Por favor, verifique!', 138 | } 139 | -------------------------------------------------------------------------------- /static/js/highcharts/themes/dark-green.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dark blue theme for Highcharts JS 3 | * @author Torstein Hønsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#DDDF0D", "#55BF3B", "#DF5353", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", 8 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 9 | chart: { 10 | backgroundColor: { 11 | linearGradient: [0, 0, 250, 500], 12 | stops: [ 13 | [0, 'rgb(48, 96, 48)'], 14 | [1, 'rgb(0, 0, 0)'] 15 | ] 16 | }, 17 | borderColor: '#000000', 18 | borderWidth: 2, 19 | className: 'dark-container', 20 | plotBackgroundColor: 'rgba(255, 255, 255, .1)', 21 | plotBorderColor: '#CCCCCC', 22 | plotBorderWidth: 1 23 | }, 24 | title: { 25 | style: { 26 | color: '#C0C0C0', 27 | font: 'bold 16px "Trebuchet MS", Verdana, sans-serif' 28 | } 29 | }, 30 | subtitle: { 31 | style: { 32 | color: '#666666', 33 | font: 'bold 12px "Trebuchet MS", Verdana, sans-serif' 34 | } 35 | }, 36 | xAxis: { 37 | gridLineColor: '#333333', 38 | gridLineWidth: 1, 39 | labels: { 40 | style: { 41 | color: '#A0A0A0' 42 | } 43 | }, 44 | lineColor: '#A0A0A0', 45 | tickColor: '#A0A0A0', 46 | title: { 47 | style: { 48 | color: '#CCC', 49 | fontWeight: 'bold', 50 | fontSize: '12px', 51 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 52 | 53 | } 54 | } 55 | }, 56 | yAxis: { 57 | gridLineColor: '#333333', 58 | labels: { 59 | style: { 60 | color: '#A0A0A0' 61 | } 62 | }, 63 | lineColor: '#A0A0A0', 64 | minorTickInterval: null, 65 | tickColor: '#A0A0A0', 66 | tickWidth: 1, 67 | title: { 68 | style: { 69 | color: '#CCC', 70 | fontWeight: 'bold', 71 | fontSize: '12px', 72 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 73 | } 74 | } 75 | }, 76 | tooltip: { 77 | backgroundColor: 'rgba(0, 0, 0, 0.75)', 78 | style: { 79 | color: '#F0F0F0' 80 | } 81 | }, 82 | toolbar: { 83 | itemStyle: { 84 | color: 'silver' 85 | } 86 | }, 87 | plotOptions: { 88 | line: { 89 | dataLabels: { 90 | color: '#CCC' 91 | }, 92 | marker: { 93 | lineColor: '#333' 94 | } 95 | }, 96 | spline: { 97 | marker: { 98 | lineColor: '#333' 99 | } 100 | }, 101 | scatter: { 102 | marker: { 103 | lineColor: '#333' 104 | } 105 | }, 106 | candlestick: { 107 | lineColor: 'white' 108 | } 109 | }, 110 | legend: { 111 | itemStyle: { 112 | font: '9pt Trebuchet MS, Verdana, sans-serif', 113 | color: '#A0A0A0' 114 | }, 115 | itemHoverStyle: { 116 | color: '#FFF' 117 | }, 118 | itemHiddenStyle: { 119 | color: '#444' 120 | } 121 | }, 122 | credits: { 123 | style: { 124 | color: '#666' 125 | } 126 | }, 127 | labels: { 128 | style: { 129 | color: '#CCC' 130 | } 131 | }, 132 | 133 | 134 | navigation: { 135 | buttonOptions: { 136 | symbolStroke: '#DDDDDD', 137 | hoverSymbolStroke: '#FFFFFF', 138 | theme: { 139 | fill: { 140 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 141 | stops: [ 142 | [0.4, '#606060'], 143 | [0.6, '#333333'] 144 | ] 145 | }, 146 | stroke: '#000000' 147 | } 148 | } 149 | }, 150 | 151 | // scroll charts 152 | rangeSelector: { 153 | buttonTheme: { 154 | fill: { 155 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 156 | stops: [ 157 | [0.4, '#888'], 158 | [0.6, '#555'] 159 | ] 160 | }, 161 | stroke: '#000000', 162 | style: { 163 | color: '#CCC', 164 | fontWeight: 'bold' 165 | }, 166 | states: { 167 | hover: { 168 | fill: { 169 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 170 | stops: [ 171 | [0.4, '#BBB'], 172 | [0.6, '#888'] 173 | ] 174 | }, 175 | stroke: '#000000', 176 | style: { 177 | color: 'white' 178 | } 179 | }, 180 | select: { 181 | fill: { 182 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 183 | stops: [ 184 | [0.1, '#000'], 185 | [0.3, '#333'] 186 | ] 187 | }, 188 | stroke: '#000000', 189 | style: { 190 | color: 'yellow' 191 | } 192 | } 193 | } 194 | }, 195 | inputStyle: { 196 | backgroundColor: '#333', 197 | color: 'silver' 198 | }, 199 | labelStyle: { 200 | color: 'silver' 201 | } 202 | }, 203 | 204 | navigator: { 205 | handles: { 206 | backgroundColor: '#666', 207 | borderColor: '#AAA' 208 | }, 209 | outlineColor: '#CCC', 210 | maskFill: 'rgba(16, 16, 16, 0.5)', 211 | series: { 212 | color: '#7798BF', 213 | lineColor: '#A6C7ED' 214 | } 215 | }, 216 | 217 | scrollbar: { 218 | barBackgroundColor: { 219 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 220 | stops: [ 221 | [0.4, '#888'], 222 | [0.6, '#555'] 223 | ] 224 | }, 225 | barBorderColor: '#CCC', 226 | buttonArrowColor: '#CCC', 227 | buttonBackgroundColor: { 228 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 229 | stops: [ 230 | [0.4, '#888'], 231 | [0.6, '#555'] 232 | ] 233 | }, 234 | buttonBorderColor: '#CCC', 235 | rifleColor: '#FFF', 236 | trackBackgroundColor: { 237 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 238 | stops: [ 239 | [0, '#000'], 240 | [1, '#333'] 241 | ] 242 | }, 243 | trackBorderColor: '#666' 244 | }, 245 | 246 | // special colors for some of the 247 | legendBackgroundColor: 'rgba(0, 0, 0, 0.5)', 248 | legendBackgroundColorSolid: 'rgb(35, 35, 70)', 249 | dataLabelsColor: '#444', 250 | textColor: '#C0C0C0', 251 | maskColor: 'rgba(255,255,255,0.3)' 252 | }; 253 | 254 | // Apply the theme 255 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 256 | -------------------------------------------------------------------------------- /static/js/highcharts/themes/dark-blue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Dark blue theme for Highcharts JS 3 | * @author Torstein Hønsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#DDDF0D", "#55BF3B", "#DF5353", "#7798BF", "#aaeeee", "#ff0066", "#eeaaee", 8 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 9 | chart: { 10 | backgroundColor: { 11 | linearGradient: { x1: 0, y1: 0, x2: 1, y2: 1 }, 12 | stops: [ 13 | [0, 'rgb(48, 48, 96)'], 14 | [1, 'rgb(0, 0, 0)'] 15 | ] 16 | }, 17 | borderColor: '#000000', 18 | borderWidth: 2, 19 | className: 'dark-container', 20 | plotBackgroundColor: 'rgba(255, 255, 255, .1)', 21 | plotBorderColor: '#CCCCCC', 22 | plotBorderWidth: 1 23 | }, 24 | title: { 25 | style: { 26 | color: '#C0C0C0', 27 | font: 'bold 16px "Trebuchet MS", Verdana, sans-serif' 28 | } 29 | }, 30 | subtitle: { 31 | style: { 32 | color: '#666666', 33 | font: 'bold 12px "Trebuchet MS", Verdana, sans-serif' 34 | } 35 | }, 36 | xAxis: { 37 | gridLineColor: '#333333', 38 | gridLineWidth: 1, 39 | labels: { 40 | style: { 41 | color: '#A0A0A0' 42 | } 43 | }, 44 | lineColor: '#A0A0A0', 45 | tickColor: '#A0A0A0', 46 | title: { 47 | style: { 48 | color: '#CCC', 49 | fontWeight: 'bold', 50 | fontSize: '12px', 51 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 52 | 53 | } 54 | } 55 | }, 56 | yAxis: { 57 | gridLineColor: '#333333', 58 | labels: { 59 | style: { 60 | color: '#A0A0A0' 61 | } 62 | }, 63 | lineColor: '#A0A0A0', 64 | minorTickInterval: null, 65 | tickColor: '#A0A0A0', 66 | tickWidth: 1, 67 | title: { 68 | style: { 69 | color: '#CCC', 70 | fontWeight: 'bold', 71 | fontSize: '12px', 72 | fontFamily: 'Trebuchet MS, Verdana, sans-serif' 73 | } 74 | } 75 | }, 76 | tooltip: { 77 | backgroundColor: 'rgba(0, 0, 0, 0.75)', 78 | style: { 79 | color: '#F0F0F0' 80 | } 81 | }, 82 | toolbar: { 83 | itemStyle: { 84 | color: 'silver' 85 | } 86 | }, 87 | plotOptions: { 88 | line: { 89 | dataLabels: { 90 | color: '#CCC' 91 | }, 92 | marker: { 93 | lineColor: '#333' 94 | } 95 | }, 96 | spline: { 97 | marker: { 98 | lineColor: '#333' 99 | } 100 | }, 101 | scatter: { 102 | marker: { 103 | lineColor: '#333' 104 | } 105 | }, 106 | candlestick: { 107 | lineColor: 'white' 108 | } 109 | }, 110 | legend: { 111 | itemStyle: { 112 | font: '9pt Trebuchet MS, Verdana, sans-serif', 113 | color: '#A0A0A0' 114 | }, 115 | itemHoverStyle: { 116 | color: '#FFF' 117 | }, 118 | itemHiddenStyle: { 119 | color: '#444' 120 | } 121 | }, 122 | credits: { 123 | style: { 124 | color: '#666' 125 | } 126 | }, 127 | labels: { 128 | style: { 129 | color: '#CCC' 130 | } 131 | }, 132 | 133 | navigation: { 134 | buttonOptions: { 135 | symbolStroke: '#DDDDDD', 136 | hoverSymbolStroke: '#FFFFFF', 137 | theme: { 138 | fill: { 139 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 140 | stops: [ 141 | [0.4, '#606060'], 142 | [0.6, '#333333'] 143 | ] 144 | }, 145 | stroke: '#000000' 146 | } 147 | } 148 | }, 149 | 150 | // scroll charts 151 | rangeSelector: { 152 | buttonTheme: { 153 | fill: { 154 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 155 | stops: [ 156 | [0.4, '#888'], 157 | [0.6, '#555'] 158 | ] 159 | }, 160 | stroke: '#000000', 161 | style: { 162 | color: '#CCC', 163 | fontWeight: 'bold' 164 | }, 165 | states: { 166 | hover: { 167 | fill: { 168 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 169 | stops: [ 170 | [0.4, '#BBB'], 171 | [0.6, '#888'] 172 | ] 173 | }, 174 | stroke: '#000000', 175 | style: { 176 | color: 'white' 177 | } 178 | }, 179 | select: { 180 | fill: { 181 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 182 | stops: [ 183 | [0.1, '#000'], 184 | [0.3, '#333'] 185 | ] 186 | }, 187 | stroke: '#000000', 188 | style: { 189 | color: 'yellow' 190 | } 191 | } 192 | } 193 | }, 194 | inputStyle: { 195 | backgroundColor: '#333', 196 | color: 'silver' 197 | }, 198 | labelStyle: { 199 | color: 'silver' 200 | } 201 | }, 202 | 203 | navigator: { 204 | handles: { 205 | backgroundColor: '#666', 206 | borderColor: '#AAA' 207 | }, 208 | outlineColor: '#CCC', 209 | maskFill: 'rgba(16, 16, 16, 0.5)', 210 | series: { 211 | color: '#7798BF', 212 | lineColor: '#A6C7ED' 213 | } 214 | }, 215 | 216 | scrollbar: { 217 | barBackgroundColor: { 218 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 219 | stops: [ 220 | [0.4, '#888'], 221 | [0.6, '#555'] 222 | ] 223 | }, 224 | barBorderColor: '#CCC', 225 | buttonArrowColor: '#CCC', 226 | buttonBackgroundColor: { 227 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 228 | stops: [ 229 | [0.4, '#888'], 230 | [0.6, '#555'] 231 | ] 232 | }, 233 | buttonBorderColor: '#CCC', 234 | rifleColor: '#FFF', 235 | trackBackgroundColor: { 236 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 237 | stops: [ 238 | [0, '#000'], 239 | [1, '#333'] 240 | ] 241 | }, 242 | trackBorderColor: '#666' 243 | }, 244 | 245 | // special colors for some of the 246 | legendBackgroundColor: 'rgba(0, 0, 0, 0.5)', 247 | legendBackgroundColorSolid: 'rgb(35, 35, 70)', 248 | dataLabelsColor: '#444', 249 | textColor: '#C0C0C0', 250 | maskColor: 'rgba(255,255,255,0.3)' 251 | }; 252 | 253 | // Apply the theme 254 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 255 | -------------------------------------------------------------------------------- /views/default/header.html: -------------------------------------------------------------------------------- 1 | {{ g_project = G_projects() }} 2 | {{ new_project = g_project.newProject() }} 3 | {{ person = g_project.projects() }} 4 | 5 | 95 | -------------------------------------------------------------------------------- /static/js/highcharts/themes/gray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Gray theme for Highcharts JS 3 | * @author Torstein Hønsi 4 | */ 5 | 6 | Highcharts.theme = { 7 | colors: ["#DDDF0D", "#7798BF", "#55BF3B", "#DF5353", "#aaeeee", "#ff0066", "#eeaaee", 8 | "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"], 9 | chart: { 10 | backgroundColor: { 11 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 12 | stops: [ 13 | [0, 'rgb(96, 96, 96)'], 14 | [1, 'rgb(16, 16, 16)'] 15 | ] 16 | }, 17 | borderWidth: 0, 18 | borderRadius: 15, 19 | plotBackgroundColor: null, 20 | plotShadow: false, 21 | plotBorderWidth: 0 22 | }, 23 | title: { 24 | style: { 25 | color: '#FFF', 26 | font: '16px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 27 | } 28 | }, 29 | subtitle: { 30 | style: { 31 | color: '#DDD', 32 | font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 33 | } 34 | }, 35 | xAxis: { 36 | gridLineWidth: 0, 37 | lineColor: '#999', 38 | tickColor: '#999', 39 | labels: { 40 | style: { 41 | color: '#999', 42 | fontWeight: 'bold' 43 | } 44 | }, 45 | title: { 46 | style: { 47 | color: '#AAA', 48 | font: 'bold 12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 49 | } 50 | } 51 | }, 52 | yAxis: { 53 | alternateGridColor: null, 54 | minorTickInterval: null, 55 | gridLineColor: 'rgba(255, 255, 255, .1)', 56 | minorGridLineColor: 'rgba(255,255,255,0.07)', 57 | lineWidth: 0, 58 | tickWidth: 0, 59 | labels: { 60 | style: { 61 | color: '#999', 62 | fontWeight: 'bold' 63 | } 64 | }, 65 | title: { 66 | style: { 67 | color: '#AAA', 68 | font: 'bold 12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif' 69 | } 70 | } 71 | }, 72 | legend: { 73 | itemStyle: { 74 | color: '#CCC' 75 | }, 76 | itemHoverStyle: { 77 | color: '#FFF' 78 | }, 79 | itemHiddenStyle: { 80 | color: '#333' 81 | } 82 | }, 83 | labels: { 84 | style: { 85 | color: '#CCC' 86 | } 87 | }, 88 | tooltip: { 89 | backgroundColor: { 90 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 91 | stops: [ 92 | [0, 'rgba(96, 96, 96, .8)'], 93 | [1, 'rgba(16, 16, 16, .8)'] 94 | ] 95 | }, 96 | borderWidth: 0, 97 | style: { 98 | color: '#FFF' 99 | } 100 | }, 101 | 102 | 103 | plotOptions: { 104 | series: { 105 | shadow: true 106 | }, 107 | line: { 108 | dataLabels: { 109 | color: '#CCC' 110 | }, 111 | marker: { 112 | lineColor: '#333' 113 | } 114 | }, 115 | spline: { 116 | marker: { 117 | lineColor: '#333' 118 | } 119 | }, 120 | scatter: { 121 | marker: { 122 | lineColor: '#333' 123 | } 124 | }, 125 | candlestick: { 126 | lineColor: 'white' 127 | } 128 | }, 129 | 130 | toolbar: { 131 | itemStyle: { 132 | color: '#CCC' 133 | } 134 | }, 135 | 136 | navigation: { 137 | buttonOptions: { 138 | symbolStroke: '#DDDDDD', 139 | hoverSymbolStroke: '#FFFFFF', 140 | theme: { 141 | fill: { 142 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 143 | stops: [ 144 | [0.4, '#606060'], 145 | [0.6, '#333333'] 146 | ] 147 | }, 148 | stroke: '#000000' 149 | } 150 | } 151 | }, 152 | 153 | // scroll charts 154 | rangeSelector: { 155 | buttonTheme: { 156 | fill: { 157 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 158 | stops: [ 159 | [0.4, '#888'], 160 | [0.6, '#555'] 161 | ] 162 | }, 163 | stroke: '#000000', 164 | style: { 165 | color: '#CCC', 166 | fontWeight: 'bold' 167 | }, 168 | states: { 169 | hover: { 170 | fill: { 171 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 172 | stops: [ 173 | [0.4, '#BBB'], 174 | [0.6, '#888'] 175 | ] 176 | }, 177 | stroke: '#000000', 178 | style: { 179 | color: 'white' 180 | } 181 | }, 182 | select: { 183 | fill: { 184 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 185 | stops: [ 186 | [0.1, '#000'], 187 | [0.3, '#333'] 188 | ] 189 | }, 190 | stroke: '#000000', 191 | style: { 192 | color: 'yellow' 193 | } 194 | } 195 | } 196 | }, 197 | inputStyle: { 198 | backgroundColor: '#333', 199 | color: 'silver' 200 | }, 201 | labelStyle: { 202 | color: 'silver' 203 | } 204 | }, 205 | 206 | navigator: { 207 | handles: { 208 | backgroundColor: '#666', 209 | borderColor: '#AAA' 210 | }, 211 | outlineColor: '#CCC', 212 | maskFill: 'rgba(16, 16, 16, 0.5)', 213 | series: { 214 | color: '#7798BF', 215 | lineColor: '#A6C7ED' 216 | } 217 | }, 218 | 219 | scrollbar: { 220 | barBackgroundColor: { 221 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 222 | stops: [ 223 | [0.4, '#888'], 224 | [0.6, '#555'] 225 | ] 226 | }, 227 | barBorderColor: '#CCC', 228 | buttonArrowColor: '#CCC', 229 | buttonBackgroundColor: { 230 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 231 | stops: [ 232 | [0.4, '#888'], 233 | [0.6, '#555'] 234 | ] 235 | }, 236 | buttonBorderColor: '#CCC', 237 | rifleColor: '#FFF', 238 | trackBackgroundColor: { 239 | linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, 240 | stops: [ 241 | [0, '#000'], 242 | [1, '#333'] 243 | ] 244 | }, 245 | trackBorderColor: '#666' 246 | }, 247 | 248 | // special colors for some of the demo examples 249 | legendBackgroundColor: 'rgba(48, 48, 48, 0.8)', 250 | legendBackgroundColorSolid: 'rgb(70, 70, 70)', 251 | dataLabelsColor: '#444', 252 | textColor: '#E0E0E0', 253 | maskColor: 'rgba(255,255,255,0.3)' 254 | }; 255 | 256 | // Apply the theme 257 | var highchartsOptions = Highcharts.setOptions(Highcharts.theme); 258 | -------------------------------------------------------------------------------- /models/10_define_my_own_tables.py: -------------------------------------------------------------------------------- 1 | if not "person" in db.tables: 2 | Person = db.define_table("person", 3 | Field("name", "string", length=128, default=""), 4 | Field("last_projects", "string", default=None), 5 | format='%(name)s', 6 | migrate="person.table") 7 | 8 | if not "auth_user" in db.tables: 9 | db.define_table("auth_user", 10 | Field("type_network", "string", length=128, default=""), 11 | Field("token", "string", length=128, default=""), 12 | Field("first_time", "boolean", default=True), 13 | migrate="auth_user.table") 14 | 15 | if not "role" in db.tables: 16 | Role = db.define_table("role", 17 | Field("name", "string", length=100, default=None), 18 | format='%(name)s', 19 | migrate="role.table") 20 | 21 | if not "project" in db.tables: 22 | Project = db.define_table("project", 23 | Field("created_by", db.person, default=None), 24 | Field("name", "string", length=128, default=None), 25 | Field("date_", "date", default=None), 26 | Field("description", "string", length=256, default=None), 27 | Field("url", "string", length=128, default=None), 28 | Field("thumbnail", "upload", default=None), 29 | format='%(name)s', 30 | migrate="project.table") 31 | 32 | if not "sprint" in db.tables: 33 | Sprint = db.define_table("sprint", 34 | Field("project_id", db.project, default=None), 35 | Field("name", "string", length=128, default=None), 36 | Field("weeks", "integer", default=None), 37 | Field("story_points", "integer", default=None), 38 | Field("started", "date", default=None), 39 | Field("ended", "date", default=None), 40 | format='%(name)s', 41 | migrate="sprint.table") 42 | 43 | if not "story" in db.tables: 44 | Story = db.define_table("story", 45 | Field("project_id", db.project, default=None), 46 | Field("sprint_id", db.sprint, default=None), 47 | Field("title", "string", length=128, default=None), 48 | Field("benefit", "string", default=None), 49 | Field("story_points", "integer", default=None), 50 | Field("position_dom", "integer", default=0), 51 | Field("concluded", "boolean", default=False), 52 | format='%(title)s', 53 | migrate="story.table") 54 | 55 | if not "definition_ready" in db.tables: 56 | Definition_ready = db.define_table("definition_ready", 57 | Field("story_id", db.story, default=None), 58 | Field("title", "string", default=None), 59 | Field("concluded", "boolean", default=False), 60 | format='%(title)s', 61 | migrate="definition_ready.table") 62 | 63 | if not "task" in db.tables: 64 | Task = db.define_table("task", 65 | Field("definition_ready_id", db.definition_ready, default=None), 66 | Field("title", "string", length=256, default=None), 67 | Field("started", "date", default=None), 68 | Field("ended", "date", default=None), 69 | Field("position_dom", "integer", default=None), 70 | Field("status", "string", length=128, default=None), 71 | Field("owner_task", db.person, default=None), 72 | format='%(title)s', 73 | migrate="task.table") 74 | 75 | if not "task_comment" in db.tables: 76 | Task_comment = db.define_table("task_comment", 77 | Field("task_id", db.task, default=None), 78 | Field("text_", "string", length=256, default=None), 79 | Field("date_", "datetime", default=None), 80 | Field("owner_comment", db.person, default=None), 81 | format='%(text)s', 82 | migrate="task_comment.table") 83 | 84 | if not "user_relationship" in db.tables: 85 | User_relationship = db.define_table("user_relationship", 86 | Field("auth_user_id", db.auth_user, default=None), 87 | Field("person_id", db.person, default=None), 88 | migrate="user_relationship.table") 89 | 90 | if not "sharing" in db.tables: 91 | Sharing = db.define_table("sharing", 92 | Field("project_id", db.project, default=None), 93 | Field("person_id", db.person, default=None), 94 | Field("role_id", db.role, default=None), 95 | Field("project_admin", "boolean", default=False), 96 | migrate="sharing.table") 97 | 98 | if not "burndown" in db.tables: 99 | Burndown = db.define_table("burndown", 100 | Field("sprint_id", db.sprint, default=None), 101 | Field("date_", "date", default=None), 102 | Field("points", "integer", length=128, default=None), 103 | migrate="burndown.table") 104 | 105 | """ Relations between tables (remove fields you don't need from requires) """ 106 | db.project.created_by.requires = IS_IN_DB(db, 'person.id', db.person._format) 107 | db.sprint.project_id.requires = IS_IN_DB(db, 'project.id', db.project._format) 108 | db.story.project_id.requires = IS_IN_DB(db, 'project.id', db.project._format) 109 | db.story.sprint_id.requires = IS_IN_DB(db, 'sprint.id', db.sprint._format) 110 | db.definition_ready.story_id.requires = IS_IN_DB(db, 'story.id', db.story._format) 111 | db.task.definition_ready_id.requires = IS_IN_DB(db, 'definition_ready.id', db.definition_ready._format) 112 | db.task.owner_task.requires = IS_IN_DB(db, 'person.id', db.person._format) 113 | db.task_comment.task_id.requires = IS_IN_DB(db, 'task.id', db.task._format) 114 | db.task_comment.owner_comment.requires = IS_IN_DB(db, 'person.id', db.person._format) 115 | db.user_relationship.auth_user_id.requires = IS_IN_DB(db, 'auth_user.id', db.auth_user._format) 116 | db.user_relationship.person_id.requires = IS_IN_DB(db, 'person.id', db.person._format) 117 | db.sharing.project_id.requires = IS_IN_DB(db, 'project.id', db.project._format) 118 | db.sharing.person_id.requires = IS_IN_DB(db, 'person.id', db.person._format) 119 | db.sharing.role_id.requires = IS_IN_DB(db, 'role.id', db.role._format) 120 | db.burndown.sprint_id.requires = IS_IN_DB(db, 'sprint.id', db.sprint._format) 121 | -------------------------------------------------------------------------------- /modules/gravatar.py: -------------------------------------------------------------------------------- 1 | """ 2 | Python module for interacting with Gravatar. 3 | """ 4 | __author__ = 'Eric Seidel' 5 | __version__ = '0.0.2' 6 | __email__ = 'gridaphobe@gmail.com' 7 | 8 | from urllib import urlencode 9 | from urllib2 import urlopen 10 | from hashlib import md5 11 | import json 12 | 13 | BASE_URL = 'http://www.gravatar.com/avatar/' 14 | SECURE_BASE_URL = 'https://secure.gravatar.com/avatar/' 15 | PROFILE_URL = 'http://www.gravatar.com/' 16 | RATINGS = ['g', 'pg', 'r', 'x'] 17 | MAX_SIZE = 512 18 | MIN_SIZE = 1 19 | DEFAULTS = ['404', 'mm', 'identicon', 'monsterid', 'wavatar', 'retro'] 20 | 21 | class Gravatar(object): 22 | """ 23 | Represents a Gravatar user. 24 | """ 25 | 26 | def __init__(self, email, secure = False, rating = 'g', size = 80, 27 | default = None): 28 | self._email_hash = md5(email.strip().lower()).hexdigest() 29 | self._secure = secure 30 | self._rating = rating 31 | self._size = size 32 | self._default = default 33 | self._thumb = self._link_to_img() 34 | self._profile = None 35 | 36 | @property 37 | def secure(self): 38 | """Return the secure parameter.""" 39 | return self._secure 40 | 41 | @secure.setter 42 | def secure(self, value): 43 | """Set the secure parameter and regenerate the thumbnail link.""" 44 | self._secure = value 45 | self._thumb = self._link_to_img() 46 | 47 | @property 48 | def rating(self): 49 | """Return the rating parameter.""" 50 | return self._rating 51 | 52 | @rating.setter 53 | def rating(self, value): 54 | """Set the rating parameter and regenerate the thumbnail link.""" 55 | self._rating = value 56 | self._thumb = self._link_to_img() 57 | 58 | @property 59 | def size(self): 60 | """Return the size parameter.""" 61 | return self._size 62 | 63 | @size.setter 64 | def size(self, value): 65 | """Set the size parameter and regenerate the thumbnail link.""" 66 | self._size = value 67 | self._thumb = self._link_to_img() 68 | 69 | @property 70 | def default(self): 71 | """Return the default parameter.""" 72 | return self._default 73 | 74 | @default.setter 75 | def default(self, value): 76 | """Set the default parameter and regenerate the thumbnail link.""" 77 | self._default = value 78 | self._thumb = self._link_to_img() 79 | 80 | @property 81 | def thumb(self): 82 | """Return the link to the gravatar thumbnail.""" 83 | return self._thumb 84 | 85 | def _link_to_img(self): 86 | """ 87 | Generates a link to the user's Gravatar. 88 | 89 | >>> Gravatar('gridaphobe@gmail.com')._link_to_img() 90 | 'http://www.gravatar.com/avatar/16b87da510d278999c892cdbdd55c1b6?s=80&r=g' 91 | """ 92 | # make sure options are valid 93 | if self.rating.lower() not in RATINGS: 94 | raise InvalidRatingError(self.rating) 95 | if not (MIN_SIZE <= self.size <= MAX_SIZE): 96 | raise InvalidSizeError(self.size) 97 | 98 | url = '' 99 | if self.secure: 100 | url = SECURE_BASE_URL 101 | else: 102 | url = BASE_URL 103 | 104 | options = {'s' : self.size, 'r' : self.rating} 105 | if self.default is not None: 106 | options['d'] = self.default 107 | url += self.hash + '?' + urlencode(options) 108 | return url 109 | 110 | def _get_profile(self): 111 | """ 112 | Retrieves the profile data of the user and formats it as a 113 | Python dictionary. 114 | """ 115 | url = PROFILE_URL + self.hash + '.json' 116 | profile = json.load(urlopen(url)) 117 | # set the profile as an instance variable 118 | self._profile = profile['entry'][0] 119 | 120 | @property 121 | def hash(self): 122 | """ 123 | Return email hash. 124 | """ 125 | return self._email_hash 126 | 127 | @property 128 | def profile(self): 129 | """ 130 | Return the user's profile. 131 | """ 132 | if self._profile is None: 133 | self._get_profile() 134 | return self._profile 135 | 136 | @property 137 | def urls(self): 138 | """ 139 | Return a list of user's urls. 140 | """ 141 | return self.profile['urls'] 142 | 143 | @property 144 | def accounts(self): 145 | """ 146 | Return a list of user's linked accounts. 147 | """ 148 | return self.profile['accounts'] 149 | 150 | @property 151 | def verified_accounts(self): 152 | """ 153 | Return a list of user's verified accounts. 154 | """ 155 | return [a for a in self.accounts if a['verified'] == 'true'] 156 | 157 | @property 158 | def ims(self): 159 | """ 160 | Return a list of user's IM accounts. 161 | """ 162 | return self.profile['accounts'] 163 | 164 | @property 165 | def photos(self): 166 | """ 167 | Return a list of user's photos. 168 | """ 169 | return self.profile['photos'] 170 | 171 | @property 172 | def emails(self): 173 | """ 174 | Return a list of user's emails. 175 | """ 176 | return self.profile['emails'] 177 | 178 | 179 | class InvalidRatingError(Exception): 180 | def __init__(self, value): 181 | self.value = value 182 | def __str__(self): 183 | return self.value + " is not a valid gravatar rating" 184 | 185 | class InvalidSizeError(Exception): 186 | def __init__(self, value): 187 | self.value = value 188 | def __str__(self): 189 | return self.value + " is not a valid image size" 190 | 191 | ############################################################################## 192 | if __name__ == '__main__': 193 | import doctest 194 | doctest.testmod() -------------------------------------------------------------------------------- /views/default/sprints.html: -------------------------------------------------------------------------------- 1 | {{extend 'default/layout_base.html'}} 2 | 3 | 15 | 16 |
17 | {{include "default/project_info.html"}} 18 | 19 |
20 |
21 |

{{=T("Historic of Sprints")}}

22 |
23 | 24 |
25 |

{{=T('Since')}}: {{=g_blank_fulldate_check(sprints[-1].ended)}}

26 |

{{=T('Until')}}: {{=g_blank_fulldate_check(sprints[0].ended)}}

27 |
28 | 29 |
30 | 45 |
46 |
47 |
48 | 49 |
50 | {{for sprint in sprints:}} 51 |
52 |
53 |
54 |
{{=sprint.name}} - {{=T('Started in')}}: {{=g_blank_fulldate_check(sprint.started)}} - {{=T('Closed')}}: {{=g_blank_fulldate_check(sprint.ended)}}
55 |
56 |
57 | 60 |
61 |
62 |
63 | {{for story in stories[sprint.id]:}} 64 |
65 |
66 |
67 |
{{=story.title}}
68 |
69 |
70 | 73 |
74 |
75 |
76 |
77 | {{for n,df in enumerate(definition_ready[story.id]):}} 78 |
79 |
80 | {{if definition_ready[story.id][n] == definition_ready[story.id][0]:}} 81 |
{{=T("Definitions of Ready")}}
82 | {{pass}} 83 |

{{=definition_ready[story.id][n].title}}

84 |
85 |
86 | {{for task in tasks[definition_ready[story.id][n].id]:}} 87 | 88 |
    89 |
  • 90 |
    91 | {{ for member in team_members: }} 92 | {{ if task["owner_task"] == member.sharing.person_id: }} 93 | {{=member.sharing.person_id.name}} - {{=member.sharing.role_id.name}} 94 | {{pass}} 95 | {{pass}} 96 |
    97 |
    98 | {{=task["title"]}} 99 |
    100 | {{if len(card_comments[task["id"]]) > 0:}} 101 | {{ =g_format_number( len(card_comments[task["id"]]) ) }} 102 | {{pass}} 103 |
    104 |
    105 |
    106 |
  • 107 |
108 | 109 | {{pass}} 110 |
111 |
112 | {{pass}} 113 |
114 | 115 |
116 | {{pass}} 117 |
118 | {{pass}} 119 |
120 | 121 | -------------------------------------------------------------------------------- /views/default/card.html: -------------------------------------------------------------------------------- 1 | {{extend 'default/layout_base.html'}} 2 | 55 | 56 | 57 | 58 | 113 | 114 | -------------------------------------------------------------------------------- /static/js/base.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | // sidebar height 3 | $(".sidebar-fixed").height($(window).height()); 4 | 5 | // to find the largest index of the array 6 | Array.max = function( array ){ 7 | return Math.max.apply( Math, array ); 8 | }; 9 | 10 | // to find the less index of the array 11 | Array.min = function( array ){ 12 | return Math.min.apply( Math, array ); 13 | }; 14 | 15 | // autogrow textarea 16 | $(document).on("keyup", ".editable-input > textarea, .autoheight", function() { 17 | autoGrownTextarea(this); 18 | }); 19 | 20 | // autogrow click link to call textarea 21 | $(document).on("click", ".editable", function() { 22 | autoGrownTextarea(this); 23 | }); 24 | 25 | function autoGrownTextarea (parentElement) { 26 | var element = $(parentElement).parent().find("textarea"), 27 | new_size = element.prop('scrollHeight') + parseFloat(element.css("borderTopWidth")) + parseFloat(element.css("borderBottomWidth")); 28 | while(element.outerHeight() < new_size) { 29 | element.height(element.height()+1); 30 | }; 31 | } 32 | 33 | // === New project === // 34 | 35 | $('.dropdown_new_project').on("click", function() { 36 | $(".dropdown-menu").toggle(); 37 | // event.preventDefault(); 38 | }); 39 | 40 | // create thumbnail 41 | $('#projects_thumbnail').awesomeCropper( 42 | { width: 150, height: 150 } 43 | ); 44 | 45 | // update thumbnail 46 | try { 47 | $('#update_thumbnail').ajaxAwesomeCropper( 48 | { width: 150, height: 150 } 49 | ); 50 | } 51 | catch (e) { 52 | // statements to handle any exceptions 53 | // console.log(e); // pass exception object to error handler 54 | } 55 | 56 | $(".btn_file").on('click', function() { 57 | $('#update_thumbnail').val(""); 58 | $(this).parent().find('.input_file').click(); 59 | }); 60 | 61 | $(".preview, #change_image_label").on('click', function() { 62 | $('#update_thumbnail').val(""); 63 | $('.preview').removeAttr("src"); 64 | $(this).parent().find('.input_file').click(); 65 | }); 66 | 67 | $("#update_thumbnail_project").on('click', function() { 68 | var thumb = $('#update_thumbnail').val(); 69 | 70 | if(thumb != "") { 71 | $(".loading_item").fadeIn("fast"); 72 | 73 | } else { 74 | return false 75 | } 76 | }); 77 | 78 | // === Sidebar navigation === // 79 | 80 | $('.submenu > a').click(function(e) 81 | { 82 | e.preventDefault(); 83 | var submenu = $(this).siblings('ul'); 84 | var li = $(this).parents('li'); 85 | var submenus = $('#sidebar li.submenu ul'); 86 | var submenus_parents = $('#sidebar li.submenu'); 87 | if(li.hasClass('open')) 88 | { 89 | if(($(window).width() > 768) || ($(window).width() < 479)) { 90 | submenu.slideUp(); 91 | } else { 92 | submenu.fadeOut(250); 93 | } 94 | li.removeClass('open'); 95 | } else 96 | { 97 | if(($(window).width() > 768) || ($(window).width() < 479)) { 98 | submenus.slideUp(); 99 | submenu.slideDown(); 100 | } else { 101 | submenus.fadeOut(250); 102 | submenu.fadeIn(250); 103 | } 104 | submenus_parents.removeClass('open'); 105 | li.addClass('open'); 106 | } 107 | }); 108 | 109 | var ul = $('#sidebar > ul'); 110 | 111 | $('#sidebar > a').click(function(e) 112 | { 113 | e.preventDefault(); 114 | var sidebar = $('#sidebar'); 115 | if(sidebar.hasClass('open')) 116 | { 117 | sidebar.removeClass('open'); 118 | ul.slideUp(250); 119 | } else 120 | { 121 | sidebar.addClass('open'); 122 | ul.slideDown(250); 123 | } 124 | }); 125 | 126 | // === Resize window related === // 127 | $(window).resize(function() 128 | { 129 | if($(window).width() > 479) 130 | { 131 | ul.css({'display':'block'}); 132 | $('#content-header .btn-group').css({width:'auto'}); 133 | } 134 | if($(window).width() < 479) 135 | { 136 | ul.css({'display':'none'}); 137 | fix_position(); 138 | } 139 | if($(window).width() > 768) 140 | { 141 | $('#user-nav > ul').css({width:'auto',margin:'0'}); 142 | $('#content-header .btn-group').css({width:'auto'}); 143 | } 144 | }); 145 | 146 | if($(window).width() < 468) 147 | { 148 | ul.css({'display':'none'}); 149 | fix_position(); 150 | } 151 | if($(window).width() > 479) 152 | { 153 | $('#content-header .btn-group').css({width:'auto'}); 154 | ul.css({'display':'block'}); 155 | } 156 | 157 | // === Tooltips === // 158 | $('.tip').tooltip(); 159 | $('.tip-left').tooltip({ placement: 'left' }); 160 | $('.tip-right').tooltip({ placement: 'right' }); 161 | $('.tip-top').tooltip({ placement: 'top' }); 162 | $('.tip-bottom').tooltip({ placement: 'bottom' }); 163 | 164 | // === Search input typeahead === // 165 | $('#search input[type=text]').typeahead({ 166 | source: ['Dashboard','Form elements','Common Elements','Validation','Wizard','Buttons','Icons','Interface elements','Support','Calendar','Gallery','Reports','Charts','Graphs','Widgets'], 167 | items: 4 168 | }); 169 | 170 | // === Fixes the position of buttons group in content header and top user navigation === // 171 | function fix_position() 172 | { 173 | var uwidth = $('#user-nav > ul').width(); 174 | $('#user-nav > ul').css({width:uwidth,'margin-left':'-' + uwidth / 2 + 'px'}); 175 | 176 | var cwidth = $('#content-header .btn-group').width(); 177 | $('#content-header .btn-group').css({width:cwidth,'margin-left':'-' + uwidth / 2 + 'px'}); 178 | } 179 | 180 | // === Style switcher === // 181 | // $('#style-switcher i').click(function() 182 | // { 183 | // if($(this).hasClass('open')) 184 | // { 185 | // $(this).parent().animate({marginRight:'-=220'}); 186 | // $(this).removeClass('open'); 187 | // } else 188 | // { 189 | // $(this).parent().animate({marginRight:'+=220'}); 190 | // $(this).addClass('open'); 191 | // } 192 | // $(this).toggleClass('icon-arrow-left'); 193 | // $(this).toggleClass('icon-arrow-right'); 194 | // }); 195 | 196 | // $('#style-switcher a').click(function() 197 | // { 198 | // var style = $(this).attr('href').replace('#',''); 199 | // $('.skin-color').attr('href','css/unicorn.'+style+'.css'); 200 | // $(this).siblings('a').css({'border-color':'transparent'}); 201 | // $(this).css({'border-color':'#aaaaaa'}); 202 | // }); 203 | 204 | // === My modifications === // 205 | $("#toogle_sidebar").click(function(){ 206 | $("body").toggleClass("close_sidebar"); 207 | $("#toogle_sidebar") 208 | .find("i") 209 | .toggleClass("icon-chevron-left") 210 | .toggleClass("icon-chevron-right"); 211 | }); 212 | 213 | }); 214 | -------------------------------------------------------------------------------- /static/js/dd_belatedpng.js: -------------------------------------------------------------------------------- 1 | /** 2 | * DD_belatedPNG: Adds IE6 support: PNG images for CSS background-image and HTML . 3 | * Author: Drew Diller 4 | * Email: drew.diller@gmail.com 5 | * URL: http://www.dillerdesign.com/experiment/DD_belatedPNG/ 6 | * Version: 0.0.8a 7 | * Licensed under the MIT License: http://dillerdesign.com/experiment/DD_belatedPNG/#license 8 | * 9 | * Example usage: 10 | * DD_belatedPNG.fix('.png_bg'); // argument is a CSS selector 11 | * DD_belatedPNG.fixPng( someNode ); // argument is an HTMLDomElement 12 | **/ 13 | var DD_belatedPNG={ns:"DD_belatedPNG",imgSize:{},delay:10,nodesFixed:0,createVmlNameSpace:function(){if(document.namespaces&&!document.namespaces[this.ns]){document.namespaces.add(this.ns,"urn:schemas-microsoft-com:vml")}},createVmlStyleSheet:function(){var b,a;b=document.createElement("style");b.setAttribute("media","screen");document.documentElement.firstChild.insertBefore(b,document.documentElement.firstChild.firstChild);if(b.styleSheet){b=b.styleSheet;b.addRule(this.ns+"\\:*","{behavior:url(#default#VML)}");b.addRule(this.ns+"\\:shape","position:absolute;");b.addRule("img."+this.ns+"_sizeFinder","behavior:none; border:none; position:absolute; z-index:-1; top:-10000px; visibility:hidden;");this.screenStyleSheet=b;a=document.createElement("style");a.setAttribute("media","print");document.documentElement.firstChild.insertBefore(a,document.documentElement.firstChild.firstChild);a=a.styleSheet;a.addRule(this.ns+"\\:*","{display: none !important;}");a.addRule("img."+this.ns+"_sizeFinder","{display: none !important;}")}},readPropertyChange:function(){var b,c,a;b=event.srcElement;if(!b.vmlInitiated){return}if(event.propertyName.search("background")!=-1||event.propertyName.search("border")!=-1){DD_belatedPNG.applyVML(b)}if(event.propertyName=="style.display"){c=(b.currentStyle.display=="none")?"none":"block";for(a in b.vml){if(b.vml.hasOwnProperty(a)){b.vml[a].shape.style.display=c}}}if(event.propertyName.search("filter")!=-1){DD_belatedPNG.vmlOpacity(b)}},vmlOpacity:function(b){if(b.currentStyle.filter.search("lpha")!=-1){var a=b.currentStyle.filter;a=parseInt(a.substring(a.lastIndexOf("=")+1,a.lastIndexOf(")")),10)/100;b.vml.color.shape.style.filter=b.currentStyle.filter;b.vml.image.fill.opacity=a}},handlePseudoHover:function(a){setTimeout(function(){DD_belatedPNG.applyVML(a)},1)},fix:function(a){if(this.screenStyleSheet){var c,b;c=a.split(",");for(b=0;bn.H){i.B=n.H}d.vml.image.shape.style.clip="rect("+i.T+"px "+(i.R+a)+"px "+i.B+"px "+(i.L+a)+"px)"}else{d.vml.image.shape.style.clip="rect("+f.T+"px "+f.R+"px "+f.B+"px "+f.L+"px)"}},figurePercentage:function(d,c,f,a){var b,e;e=true;b=(f=="X");switch(a){case"left":case"top":d[f]=0;break;case"center":d[f]=0.5;break;case"right":case"bottom":d[f]=1;break;default:if(a.search("%")!=-1){d[f]=parseInt(a,10)/100}else{e=false}}d[f]=Math.ceil(e?((c[b?"W":"H"]*d[f])-(c[b?"w":"h"]*d[f])):parseInt(a,10));if(d[f]%2===0){d[f]++}return d[f]},fixPng:function(c){c.style.behavior="none";var g,b,f,a,d;if(c.nodeName=="BODY"||c.nodeName=="TD"||c.nodeName=="TR"){return}c.isImg=false;if(c.nodeName=="IMG"){if(c.src.toLowerCase().search(/\.png$/)!=-1){c.isImg=true;c.style.visibility="hidden"}else{return}}else{if(c.currentStyle.backgroundImage.toLowerCase().search(".png")==-1){return}}g=DD_belatedPNG;c.vml={color:{},image:{}};b={shape:{},fill:{}};for(a in c.vml){if(c.vml.hasOwnProperty(a)){for(d in b){if(b.hasOwnProperty(d)){f=g.ns+":"+d;c.vml[a][d]=document.createElement(f)}}c.vml[a].shape.stroked=false;c.vml[a].shape.appendChild(c.vml[a].fill);c.parentNode.insertBefore(c.vml[a].shape,c)}}c.vml.image.shape.fillcolor="none";c.vml.image.fill.type="tile";c.vml.color.fill.on=false;g.attachHandlers(c);g.giveLayout(c);g.giveLayout(c.offsetParent);c.vmlInitiated=true;g.applyVML(c)}};try{document.execCommand("BackgroundImageCache",false,true)}catch(r){}DD_belatedPNG.createVmlNameSpace();DD_belatedPNG.createVmlStyleSheet(); 14 | --------------------------------------------------------------------------------