Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
P
panikdb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
radiopanik
panikdb
Commits
44016a34
Commit
44016a34
authored
Aug 31, 2013
by
fred
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
switch to standalone emissions app
parent
62eec5e6
Changes
48
Hide whitespace changes
Inline
Side-by-side
Showing
48 changed files
with
4 additions
and
4607 deletions
+4
-4607
panikdb/aa/models.py
panikdb/aa/models.py
+1
-1
panikdb/emissions/__init__.py
panikdb/emissions/__init__.py
+0
-0
panikdb/emissions/admin.py
panikdb/emissions/admin.py
+0
-51
panikdb/emissions/fixtures/nonstop.json
panikdb/emissions/fixtures/nonstop.json
+0
-83
panikdb/emissions/forms.py
panikdb/emissions/forms.py
+0
-196
panikdb/emissions/management/__init__.py
panikdb/emissions/management/__init__.py
+0
-0
panikdb/emissions/management/commands/__init__.py
panikdb/emissions/management/commands/__init__.py
+0
-0
panikdb/emissions/management/commands/_spip2html.py
panikdb/emissions/management/commands/_spip2html.py
+0
-1073
panikdb/emissions/management/commands/create-sound-files.py
panikdb/emissions/management/commands/create-sound-files.py
+0
-114
panikdb/emissions/management/commands/day-program.py
panikdb/emissions/management/commands/day-program.py
+0
-12
panikdb/emissions/management/commands/load-from-spip.py
panikdb/emissions/management/commands/load-from-spip.py
+0
-544
panikdb/emissions/management/commands/week-program.py
panikdb/emissions/management/commands/week-program.py
+0
-16
panikdb/emissions/management/commands/whatsonair.py
panikdb/emissions/management/commands/whatsonair.py
+0
-11
panikdb/emissions/migrations/0001_initial.py
panikdb/emissions/migrations/0001_initial.py
+0
-150
panikdb/emissions/migrations/0002_auto__add_field_emission_duration.py
...ions/migrations/0002_auto__add_field_emission_duration.py
+0
-72
panikdb/emissions/migrations/0003_auto__add_field_emission_email__add_field_emission_website.py
...__add_field_emission_email__add_field_emission_website.py
+0
-82
panikdb/emissions/migrations/0004_auto__add_field_episode_image__add_field_emission_image.py
...uto__add_field_episode_image__add_field_emission_image.py
+0
-104
panikdb/emissions/migrations/0005_auto__add_field_schedule_weeks.py
...issions/migrations/0005_auto__add_field_schedule_weeks.py
+0
-97
panikdb/emissions/migrations/0006_auto__add_newsitem__add_newscategory.py
...s/migrations/0006_auto__add_newsitem__add_newscategory.py
+0
-131
panikdb/emissions/migrations/0007_auto__add_field_episode_duration__add_field_schedule_duration.py
...dd_field_episode_duration__add_field_schedule_duration.py
+0
-123
panikdb/emissions/migrations/0008_auto__chg_enlarge_titles.py
...kdb/emissions/migrations/0008_auto__chg_enlarge_titles.py
+0
-131
panikdb/emissions/migrations/0009_auto__enlarge_titles_even_more.py
...issions/migrations/0009_auto__enlarge_titles_even_more.py
+0
-131
panikdb/emissions/migrations/0010_auto__add_nonstop.py
panikdb/emissions/migrations/0010_auto__add_nonstop.py
+0
-126
panikdb/emissions/migrations/0011_load_nonstop.py
panikdb/emissions/migrations/0011_load_nonstop.py
+0
-117
panikdb/emissions/migrations/__init__.py
panikdb/emissions/migrations/__init__.py
+0
-0
panikdb/emissions/models.py
panikdb/emissions/models.py
+0
-296
panikdb/emissions/search_indexes.py
panikdb/emissions/search_indexes.py
+0
-57
panikdb/emissions/templates/emissions/category_list.html
panikdb/emissions/templates/emissions/category_list.html
+0
-23
panikdb/emissions/templates/emissions/days.html
panikdb/emissions/templates/emissions/days.html
+0
-21
panikdb/emissions/templates/emissions/emission_detail.html
panikdb/emissions/templates/emissions/emission_detail.html
+0
-72
panikdb/emissions/templates/emissions/emission_form.html
panikdb/emissions/templates/emissions/emission_form.html
+0
-25
panikdb/emissions/templates/emissions/emission_list.html
panikdb/emissions/templates/emissions/emission_list.html
+0
-31
panikdb/emissions/templates/emissions/episode_detail.html
panikdb/emissions/templates/emissions/episode_detail.html
+0
-89
panikdb/emissions/templates/emissions/episode_form.html
panikdb/emissions/templates/emissions/episode_form.html
+0
-35
panikdb/emissions/templates/emissions/soundfile_form.html
panikdb/emissions/templates/emissions/soundfile_form.html
+0
-19
panikdb/emissions/templates/emissions/upload.html
panikdb/emissions/templates/emissions/upload.html
+0
-16
panikdb/emissions/templates/search/indexes/emissions/emission_text.txt
...ions/templates/search/indexes/emissions/emission_text.txt
+0
-5
panikdb/emissions/templates/search/indexes/emissions/episode_text.txt
...sions/templates/search/indexes/emissions/episode_text.txt
+0
-7
panikdb/emissions/templates/search/indexes/emissions/newsitem_text.txt
...ions/templates/search/indexes/emissions/newsitem_text.txt
+0
-9
panikdb/emissions/templatetags/__init__.py
panikdb/emissions/templatetags/__init__.py
+0
-0
panikdb/emissions/templatetags/soundfiles.py
panikdb/emissions/templatetags/soundfiles.py
+0
-19
panikdb/emissions/tests.py
panikdb/emissions/tests.py
+0
-16
panikdb/emissions/urls.py
panikdb/emissions/urls.py
+0
-32
panikdb/emissions/utils.py
panikdb/emissions/utils.py
+0
-212
panikdb/emissions/views.py
panikdb/emissions/views.py
+0
-256
panikdb/settings.py
panikdb/settings.py
+1
-1
panikdb/urls.py
panikdb/urls.py
+1
-1
requirements.txt
requirements.txt
+1
-0
No files found.
panikdb/aa/models.py
View file @
44016a34
...
...
@@ -4,7 +4,7 @@ from django.contrib.auth.models import AbstractUser
from
django.core
import
validators
from
django.db
import
models
from
..
emissions.models
import
Emission
from
emissions.models
import
Emission
class
User
(
AbstractUser
):
emissions
=
models
.
ManyToManyField
(
Emission
)
...
...
panikdb/emissions/__init__.py
deleted
100644 → 0
View file @
62eec5e6
panikdb/emissions/admin.py
deleted
100644 → 0
View file @
62eec5e6
from
django.contrib
import
admin
from
.models
import
Emission
,
Episode
,
Category
,
Schedule
,
\
SoundFile
,
NewsItem
,
NewsCategory
,
Nonstop
class
EmissionAdmin
(
admin
.
ModelAdmin
):
prepopulated_fields
=
{
'slug'
:
(
'title'
,)}
admin
.
site
.
register
(
Emission
,
EmissionAdmin
)
class
EpisodeAdmin
(
admin
.
ModelAdmin
):
prepopulated_fields
=
{
'slug'
:
(
'title'
,)}
admin
.
site
.
register
(
Episode
,
EpisodeAdmin
)
class
CategoryAdmin
(
admin
.
ModelAdmin
):
pass
admin
.
site
.
register
(
Category
,
CategoryAdmin
)
class
ScheduleAdmin
(
admin
.
ModelAdmin
):
pass
admin
.
site
.
register
(
Schedule
,
ScheduleAdmin
)
class
NewsCategoryAdmin
(
admin
.
ModelAdmin
):
pass
admin
.
site
.
register
(
NewsCategory
,
NewsCategoryAdmin
)
class
NewsItemAdmin
(
admin
.
ModelAdmin
):
pass
admin
.
site
.
register
(
NewsItem
,
NewsItemAdmin
)
class
SoundFileAdmin
(
admin
.
ModelAdmin
):
pass
admin
.
site
.
register
(
SoundFile
,
SoundFileAdmin
)
class
NonstopAdmin
(
admin
.
ModelAdmin
):
pass
admin
.
site
.
register
(
Nonstop
,
NonstopAdmin
)
panikdb/emissions/fixtures/nonstop.json
deleted
100644 → 0
View file @
62eec5e6
[
{
"fields"
:
{
"end"
:
"02:00:00"
,
"start"
:
"22:00:00"
,
"title"
:
"Biodiversit
\u
00e9"
},
"model"
:
"emissions.nonstop"
,
"pk"
:
1
},
{
"fields"
:
{
"end"
:
"05:00:00"
,
"start"
:
"02:00:00"
,
"title"
:
"R
\u
00eaveries"
},
"model"
:
"emissions.nonstop"
,
"pk"
:
2
},
{
"fields"
:
{
"end"
:
"07:30:00"
,
"start"
:
"05:00:00"
,
"title"
:
"La Panique"
},
"model"
:
"emissions.nonstop"
,
"pk"
:
3
},
{
"fields"
:
{
"end"
:
"10:00:00"
,
"start"
:
"07:30:00"
,
"title"
:
"Matin tranquille"
},
"model"
:
"emissions.nonstop"
,
"pk"
:
4
},
{
"fields"
:
{
"end"
:
"12:00:00"
,
"start"
:
"10:00:00"
,
"title"
:
"Up Beat Tempo"
},
"model"
:
"emissions.nonstop"
,
"pk"
:
5
},
{
"fields"
:
{
"end"
:
"13:00:00"
,
"start"
:
"12:00:00"
,
"title"
:
"L'heure de pointe"
},
"model"
:
"emissions.nonstop"
,
"pk"
:
6
},
{
"fields"
:
{
"end"
:
"16:00:00"
,
"start"
:
"13:00:00"
,
"title"
:
"Le Mange Disque"
},
"model"
:
"emissions.nonstop"
,
"pk"
:
7
},
{
"fields"
:
{
"end"
:
"19:00:00"
,
"start"
:
"16:00:00"
,
"title"
:
"Hop Bop and co"
},
"model"
:
"emissions.nonstop"
,
"pk"
:
8
},
{
"fields"
:
{
"end"
:
"22:00:00"
,
"start"
:
"19:00:00"
,
"title"
:
"Acouph
\u
00e8ne"
},
"model"
:
"emissions.nonstop"
,
"pk"
:
9
}
]
panikdb/emissions/forms.py
deleted
100644 → 0
View file @
62eec5e6
import
datetime
import
re
import
unicodedata
import
os
import
uuid
from
django
import
forms
from
django.forms
import
fields
from
django.core.files.storage
import
DefaultStorage
from
django.core.urlresolvers
import
reverse
from
django.utils.safestring
import
mark_safe
from
django.conf
import
settings
from
django.template.loader
import
render_to_string
from
taggit.forms
import
TagWidget
import
datetimewidget.widgets
from
.models
import
Emission
,
Episode
,
Diffusion
,
Schedule
,
SoundFile
DATETIME_OPTIONS
=
{
'format'
:
'dd/mm/yyyy hh:ii'
,
'language'
:
'fr'
,
'weekStart'
:
'1'
,
'autoclose'
:
'true'
,
}
class
DateTimeWidget
(
datetimewidget
.
widgets
.
DateTimeWidget
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
super
(
DateTimeWidget
,
self
).
__init__
(
*
args
,
options
=
DATETIME_OPTIONS
,
**
kwargs
)
def
slugify
(
s
):
s
=
unicodedata
.
normalize
(
'NFKD'
,
s
).
encode
(
'ascii'
,
'ignore'
).
lower
()
return
re
.
sub
(
r'\W+'
,
'-'
,
s
)
class
DayAndHourWidget
(
forms
.
MultiWidget
):
def
__init__
(
self
,
attrs
=
None
):
WEEKDAYS
=
[
u'Lundi'
,
u'Mardi'
,
u'Mercredi'
,
u'Jeudi'
,
u'Vendredi'
,
u'Samedi'
,
u'Dimanche'
]
widgets
=
(
forms
.
Select
(
attrs
=
attrs
,
choices
=
([(
weekday
,
WEEKDAYS
[
weekday
])
for
weekday
in
range
(
7
)])),
forms
.
Select
(
attrs
=
attrs
,
choices
=
([(
hour
,
hour
)
for
hour
in
range
(
24
)])),
forms
.
Select
(
attrs
=
attrs
,
choices
=
([(
minute
,
str
(
minute
).
zfill
(
2
))
for
minute
in
range
(
60
)])),
)
super
(
DayAndHourWidget
,
self
).
__init__
(
widgets
,
attrs
)
def
decompress
(
self
,
value
):
if
value
:
return
[
value
.
weekday
(),
value
.
hour
,
value
.
minute
]
return
[
None
,
None
,
None
]
def
value_from_datadict
(
self
,
data
,
files
,
name
):
# we only care about day/hour/minutes, but we conveniently use a
# datetime value to store that; we pick 2007 as reference year as
# it had its January 1st on a Monday.
data_list
=
[
widget
.
value_from_datadict
(
data
,
files
,
name
+
'_%s'
%
i
)
for
i
,
widget
in
enumerate
(
self
.
widgets
)]
if
data_list
:
return
datetime
.
datetime
(
2007
,
1
,
int
(
data_list
[
0
])
+
1
,
int
(
data_list
[
1
]),
int
(
data_list
[
2
]))
return
None
class
JqueryFileUploadFileInput
(
forms
.
FileInput
):
def
render
(
self
,
name
,
value
,
attrs
=
None
):
output
=
render_to_string
(
'emissions/upload.html'
,
{
'upload_url'
:
self
.
url
,
'files'
:
self
.
files
,
'name'
:
name
,
'STATIC_URL'
:
settings
.
STATIC_URL
})
return
mark_safe
(
output
)
class
JqueryFileUploadInput
(
forms
.
MultiWidget
):
needs_multipart_form
=
True
upload_id_re
=
re
.
compile
(
r'^[a-z0-9A-Z-]+$'
)
upload_id
=
None
def
__init__
(
self
,
attrs
=
None
,
choices
=
[],
max_filename_length
=
None
):
self
.
max_filename_length
=
max_filename_length
widget_list
=
(
forms
.
HiddenInput
(
attrs
=
attrs
),
JqueryFileUploadFileInput
(
attrs
=
attrs
))
super
(
JqueryFileUploadInput
,
self
).
__init__
(
widget_list
,
attrs
)
def
decompress
(
self
,
value
):
# map python value to widget contents
if
self
.
upload_id
:
pass
elif
isinstance
(
value
,
(
list
,
tuple
))
and
value
and
value
[
0
]
is
not
None
:
self
.
upload_id
=
str
(
value
[
0
])
else
:
self
.
upload_id
=
str
(
uuid
.
uuid4
())
return
[
self
.
upload_id
,
None
]
def
get_files_for_id
(
self
,
upload_id
):
storage
=
DefaultStorage
()
path
=
os
.
path
.
join
(
'upload'
,
upload_id
)
if
not
storage
.
exists
(
path
):
return
for
filepath
in
storage
.
listdir
(
path
)[
1
]:
name
=
os
.
path
.
basename
(
filepath
)
yield
storage
.
open
(
os
.
path
.
join
(
path
,
name
))
def
value_from_datadict
(
self
,
data
,
files
,
name
):
'''
If some file was submitted, that's the value,
If a regular hidden_id is present, use it to find uploaded files,
otherwise return an empty list
'''
upload_id
,
file_input
=
super
(
JqueryFileUploadInput
,
self
).
value_from_datadict
(
data
,
files
,
name
)
if
file_input
:
pass
elif
JqueryFileUploadInput
.
upload_id_re
.
match
(
upload_id
):
file_input
=
list
(
self
.
get_files_for_id
(
upload_id
))
else
:
file_input
=
[]
return
file_input
[
0
]
def
render
(
self
,
name
,
value
,
attrs
=
None
):
self
.
decompress
(
value
)
self
.
widgets
[
1
].
url
=
'/upload/%s/'
%
self
.
upload_id
self
.
widgets
[
1
].
url
=
reverse
(
'upload'
,
kwargs
=
{
'transaction_id'
:
self
.
upload_id
})
if
self
.
max_filename_length
:
self
.
widgets
[
1
].
url
+=
'?max_filename_length=%d'
%
self
.
max_filename_length
self
.
widgets
[
1
].
files
=
'/upload/%s/'
%
self
.
get_files_for_id
(
self
.
upload_id
)
output
=
super
(
JqueryFileUploadInput
,
self
).
render
(
name
,
value
,
attrs
)
fileinput_id
=
'%s_%s'
%
(
attrs
[
'id'
],
'1'
)
return
output
class
EmissionForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
Emission
exclude
=
(
'slug'
,)
def
save
(
self
,
commit
=
True
):
if
not
self
.
instance
.
slug
:
self
.
instance
.
slug
=
slugify
(
self
.
instance
.
title
)
return
super
(
EmissionForm
,
self
).
save
(
commit
=
commit
)
class
EpisodeForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
Episode
exclude
=
(
'slug'
,)
widgets
=
{
'emission'
:
forms
.
HiddenInput
(),
'tags'
:
TagWidget
()}
def
save
(
self
,
commit
=
True
):
if
not
self
.
instance
.
slug
:
self
.
instance
.
slug
=
slugify
(
self
.
instance
.
title
)
return
super
(
EpisodeForm
,
self
).
save
(
commit
=
commit
)
class
EpisodeNewForm
(
EpisodeForm
):
diffusion
=
forms
.
DateTimeField
(
label
=
'First Diffusion'
,
widget
=
DateTimeWidget
)
def
save
(
self
,
commit
=
True
):
episode
=
super
(
EpisodeNewForm
,
self
).
save
(
commit
=
commit
)
diffusion
=
Diffusion
()
diffusion
.
episode_id
=
episode
.
id
diffusion
.
datetime
=
self
.
cleaned_data
.
get
(
'diffusion'
)
diffusion
.
save
()
return
episode
class
ScheduleForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
Schedule
widgets
=
{
'emission'
:
forms
.
HiddenInput
(),
'datetime'
:
DayAndHourWidget
(),
}
class
SoundFileForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
SoundFile
widgets
=
{
'episode'
:
forms
.
HiddenInput
(),
'file'
:
JqueryFileUploadInput
(),
}
class
DiffusionForm
(
forms
.
ModelForm
):
class
Meta
:
model
=
Diffusion
widgets
=
{
'episode'
:
forms
.
HiddenInput
(),
'datetime'
:
DateTimeWidget
(),
}
panikdb/emissions/management/__init__.py
deleted
100644 → 0
View file @
62eec5e6
panikdb/emissions/management/commands/__init__.py
deleted
100644 → 0
View file @
62eec5e6
panikdb/emissions/management/commands/_spip2html.py
deleted
100644 → 0
View file @
62eec5e6
# -*- coding: utf-8 -*-
#
# Code scavenged from Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
# Romain Chantereau <rchantereau@entrouvert.com>
# Nicolas Clapiès <nclapies@easter-eggs.org>
# Pierre-Antoine Dejace <padejace@entrouvert.be>
# Thierry Dulieu <tdulieu@easter-eggs.com>
# Florent Monnier <monnier@codelutin.com>
# Cédric Musso <cmusso@easter-eggs.org>
# Frédéric Péters <fpeters@entrouvert.be>
# Benjamin Poussin <poussin@codelutin.com>
# Emmanuel Raviart <eraviart@entrouvert.com>
# Sébastien Régnier <regnier@codelutin.com>
# Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
# Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
# Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import
re
import
sys
_non_id_chars
=
re
.
compile
(
'[^a-z0-9]+'
)
_non_id_at_ends
=
re
.
compile
(
'^[-0-9]+|-+$'
)
def
enhanceTypo
(
s
):
# typographic junkie
# idea from: http://daringfireball.net/projects/smartypants/
s
=
s
.
replace
(
'...'
,
'…'
)
# ellipsis (...)
s
=
s
.
replace
(
' -- '
,
' — '
)
# em-dash
s
=
s
.
replace
(
'(c)'
,
'© '
)
# copyright symbol
return
s
def
parseSpipLink
(
link
):
link
=
link
.
replace
(
'
\n
'
,
' '
)
matchObject
=
re
.
match
(
r'(?P<role>alias|art(icle)?|atom|book|card|election|file|'
\
'grade|group|heading|im(g|age)?|person(ne)?|rubri(c|que)'
\
') *(?P<localId>\S+) *(?P<option>\S+)?'
,
link
)
if
matchObject
is
None
:
name
=
link
for
prefix
in
[
'http://'
,
'https://'
,
'ftp://'
,
'mailto:'
]:
if
name
.
startswith
(
prefix
):
if
not
'/'
in
name
[
len
(
prefix
):]:
name
=
name
[
len
(
prefix
):]
break
else
:
name
=
''
return
name
,
link
role
=
matchObject
.
group
(
'role'
)
localId
=
matchObject
.
group
(
'localId'
)
option
=
matchObject
.
group
(
'option'
)
and
\
':%s'
%
matchObject
.
group
(
'option'
)
or
''
return
(
'XXX'
,
'#'
)
class
Formatter
:
def
close
(
self
,
**
keywords
):
return
''
def
list
(
self
,
list
):
def
getListIndent
(
stack
):
if
len
(
stack
)
==
0
:
return
-
1
else
:
return
stack
[
-
1
][
0
]
stack
=
[]
result
=
''
for
line
in
list
:
indent
,
type
,
text
=
line
while
indent
<
getListIndent
(
stack
):
result
+=
self
.
listEnd
(
len
(
stack
),
stack
[
-
1
][
1
])
del
stack
[
-
1
]
if
indent
>
getListIndent
(
stack
):
stack
.
append
((
indent
,
type
))
result
+=
self
.
listBegin
(
len
(
stack
)
-
1
,
type
)
result
+=
self
.
listItem
(
len
(
stack
),
text
)
while
stack
:
result
+=
self
.
listEnd
(
len
(
stack
)
-
1
,
stack
[
-
1
][
1
])
del
stack
[
-
1
]
return
result
def
open
(
self
,
**
keywords
):
return
''
def
prescaleImage
(
self
):
return
1
def
table
(
self
,
table
,
hasHeader
):
result
=
''
rows
=
len
(
table
)
cols
=
max
(
map
(
len
,
table
))
result
+=
self
.
tableBegin
(
rows
,
cols
)
for
i
in
range
(
len
(
table
)):
row
=
table
[
i
]
rowNumber
=
i
if
hasHeader
:
rowNumber
-=
1
result
+=
self
.
tableLineBegin
(
rowNumber
,
isHeader
=
i
==
0
and
hasHeader
)
j
=
0
for
cell
in
row
:
if
type
(
cell
)
in
(
str
,
unicode
)
and
cell
.
strip
()
==
'###'
:
cell
=
rowNumber
+
1
result
+=
self
.
tableCell
(
cell
,
rowNumber
,
j
,
isHeader
=
i
==
0
and
hasHeader
)
j
+=
1
result
+=
self
.
tableLineEnd
(
i
,
isHeader
=
i
==
0
and
hasHeader
)
result
+=
self
.
tableEnd
(
isHeader
=
len
(
table
)
==
1
and
hasHeader
)
return
result
def
text
(
self
,
text
):
return
text
class
FormatterHtml
(
Formatter
):
def
__init__
(
self
):
self
.
states
=
[
''
]
def
intertitle
(
self
,
text
,
sublevel
=
0
):
nameText
=
re
.
sub
(
'<.*?>'
,
''
,
text
).
strip
()
# from docutils/nodes.py, def make_id(string)
nameText
=
_non_id_chars
.
sub
(
'-'
,
' '
.
join
(
nameText
.
lower
().
split
()))
nameText
=
_non_id_at_ends
.
sub
(
''
,
nameText
)
return
'<h%(sectionLevel)d id="%(nameText)s">%(text)s'
\
'</h%(sectionLevel)d>
\n\n
'
%
{
'text'
:
text
.
strip
(),
'sectionLevel'
:
self
.
sectionLevel
+
sublevel
,
'nameText'
:
nameText
,
}
def
lineBreak
(
self
):
return
'<br />
\n
'
def
list
(
self
,
list
):
# FIXME: the Formatter.list method doesn't work for sub-lists, so it is
# rewritten here. Maybe this method should also be used by
# Formatter.list
def
getListIndent
(
stack
):
if
len
(
stack
)
==
0
:
return
-
1
else
:
return
stack
[
-
1
][
0
]
self
.
states
.
append
(
'blockLevel'
)
stack
=
[]
result
=
''
for
line
in
list
:
indent
,
type
,
text
=
line
while
indent
<
getListIndent
(
stack
):
result
+=
self
.
listItemEnd
()
result
+=
self
.
listEnd
(
len
(
stack
),
stack
[
-
1
][
1
])
del
stack
[
-
1
]
if
indent
>
getListIndent
(
stack
):
stack
.
append
((
indent
,
type
))
result
+=
'
\n
'
result
+=
self
.
listBegin
(
len
(
stack
)
-
1
,
type
)
else
:
result
+=
self
.
listItemEnd
()
result
+=
self
.
listItemBegin
(
len
(
stack
),
text
)
while
stack
:
result
+=
self
.
listItemEnd
()
result
+=
self
.
listEnd
(
len
(
stack
)
-
1
,
stack
[
-
1
][
1
])
del
stack
[
-
1
]
return
result
def
listBegin
(
self
,
indent
,
type
):
if
type
:
type
=
'ol'
else
:
type
=
'ul'
return
'%(indent)s<%(type)s>
\n
'
%
{
'indent'
:
' '
*
indent
,
'type'
:
type
,
}
def
listEnd
(
self
,
indent
,
type
):
if
type
:
type
=
'ol'
else
:
type
=
'ul'
return
'%(indent)s</%(type)s>
\n
'
%
{
'indent'
:
' '
*
indent
,
'type'
:
type
,
}
def
listItemBegin
(
self
,
indent
,
item
):
return
'%(indent)s<li>%(item)s'
%
{
'indent'
:
' '
*
indent
,
'item'
:
item
.
strip
(
'*'
),
}
def
listItemEnd
(
self
):
return
'</li>
\n
'
def
nonBreakingSpace
(
self
):
return
' '
def
open
(
self
,
**
keywords
):
self
.
sectionLevel
=
2
if
keywords
.
has_key
(
'sectionLevel'
):
self
.
sectionLevel
=
int
(
keywords
[
'sectionLevel'
])
return
''
def
paragraph
(
self
,
text
):
# turn URL into links
def
repl
(
match
):
m
=
match
.
group
(
0
)
if
m
[
0
]
==
'"'
and
m
[
-
1
]
==
'"'
:
return
m
if
m
[
0
]
in
'>'
and
m
[
-
1
]
==
'<'
:
return
m
m
=
m
.
rstrip
(
'<'
).
lstrip
(
'>'
)
return
'<a href="%s">%s</a>'
%
(
m
,
m
)
t1
=
text
text
=
re
.
sub
(
r'([">]?http[s]?://[a-zA-Z0-9\.\/-]*[<"]?)'
,
repl
,
text
,
re
.
DOTALL
)
if
self
.
states
[
-
1
]
==
'blockLevel'
:
self
.
states
.
pop
()
return
text
def
line80
(
text
):
t
=
[]
i
=
0
while
1
:
val
=
text
[
i
+
70
:].
find
(
' '
)
if
val
==
-
1
:
t
.
append
(
text
[
i
:])
break
part
=
text
[
i
:
i
+
70
+
val
+
1
]
t
.
append
(
part
)
i
+=
len
(
part
)
return
'
\n
'
.
join
(
t
)