summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--MANIFEST.in1
-rw-r--r--mcrute_theme/__init__.py0
-rw-r--r--mcrute_theme/crute_modernized.py68
-rw-r--r--setup.py42
-rw-r--r--static/dnd-upload.js173
-rw-r--r--static/favicon.icobin0 -> 1150 bytes
-rw-r--r--static/iphone-icon.pngbin0 -> 15261 bytes
-rw-r--r--static/logo.pngbin0 -> 8472 bytes
-rw-r--r--static/mcrute.css90
10 files changed, 377 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0b116e4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
1/*.egg-info
2*.pyc
3.DS_Store
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..f19dc7a
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
include static/*
diff --git a/mcrute_theme/__init__.py b/mcrute_theme/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mcrute_theme/__init__.py
diff --git a/mcrute_theme/crute_modernized.py b/mcrute_theme/crute_modernized.py
new file mode 100644
index 0000000..0e04abe
--- /dev/null
+++ b/mcrute_theme/crute_modernized.py
@@ -0,0 +1,68 @@
1from MoinMoin.theme.modernized import Theme as _Theme
2from MoinMoin.Page import Page
3from MoinMoin import wikiutil
4
5
6class Theme(_Theme):
7
8 # Hook to add an override stylesheet, favicon, iPhone icon, and viewport
9 # tag
10 def universal_edit_button(self, d, **k):
11 return u'\n'.join([
12 ('<meta name="viewport" content="width=device-width, '
13 'initial-scale=1" />'),
14
15 ('<link rel="shortcut icon" href="/WikiStatic?'
16 'action=AttachFile&do=get&target=favicon.ico">'),
17
18 ('<link rel="apple-touch-icon-precomposed" href="/WikiStatic?'
19 'action=AttachFile&do=get&target=iphone-icon.png"/>'),
20
21 ('<link rel="stylesheet" type="text/css" charset="utf-8" '
22 'media="all" href="/WikiStatic?'
23 'action=AttachFile&do=get&target=mcrute.css">'),
24
25 ('<script type="text/javascript" src="/WikiStatic?'
26 'action=AttachFile&do=get&target=dnd-upload.js">'
27 '</script>'),
28 ]) + _Theme.universal_edit_button(self, d, **k)
29
30 # Hook to add a Home link to the header links next to the logo
31 def username(self, d):
32 html = _Theme.username(self, d)
33 first_tag = html.index('>') + 1
34
35 page = wikiutil.getFrontPage(self.request)
36
37 return u'{} {} <span class="sep"> | </span> {}'.format(
38 html[:first_tag], page.link_to_raw(self.request, "Home"),
39 html[first_tag:])
40
41 def editbarItems(self, page):
42 actions = _Theme.editbarItems(self, page)
43
44 # Add quick link actions for starting/stopping activities
45 if page.pi['format'] == 'timecsv':
46 actions.insert(len(actions) - 1, page.link_to(
47 self.request, text='Start Activity',
48 querystr={ 'action': 'StartActivity' }, rel='nofollow'))
49
50 actions.insert(len(actions) - 1, page.link_to(
51 self.request, text='Stop Activity',
52 querystr={ 'action': 'StopActivity' }, rel='nofollow'))
53
54 return actions
55
56 def send_title(self, text, **keywords):
57 if 'editor_mode' in keywords:
58 if 'body_attr' in keywords:
59 keywords['body_attr'] += 'id="page-editor"'
60 else:
61 keywords['body_attr'] = 'id="page-editor"'
62
63 return _Theme.send_title(self, text, **keywords)
64
65
66def execute(request):
67 return Theme(request)
68
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..d9963bd
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,42 @@
1from setuptools import setup, find_packages
2
3setup(
4 name="CruteMoinModernizedTheme",
5 version="1.0",
6 description="",
7 author="Michael Crute <mcrute@gmail.com>",
8 license="MIT",
9 packages=find_packages(),
10 entry_points={
11# "moin.plugins.action": [
12# ],
13# "moin.plugins.converter": [
14# ],
15# "moin.plugins.events": [
16# ],
17# "moin.plugins.filter": [
18# ],
19# "moin.plugins.formatter": [
20# ],
21# "moin.plugins.macro": [
22# ],
23# "moin.plugins.parser": [
24# ],
25 "moin.plugins.theme": [
26 "crute_modernized = mcrute_theme.crute_modernized:Theme",
27 ],
28# "moin.plugins.userprefs": [
29# ],
30# "moin.plugins.xmlrpc": [
31# ],
32 },
33 data_files=[
34 ("static", (
35 "static/dnd-upload.js",
36 "static/favicon.ico",
37 "static/iphone-icon.png",
38 "static/logo.png",
39 "static/mcrute.css",
40 )),
41 ]
42)
diff --git a/static/dnd-upload.js b/static/dnd-upload.js
new file mode 100644
index 0000000..2623cc2
--- /dev/null
+++ b/static/dnd-upload.js
@@ -0,0 +1,173 @@
1function template(text, data) {
2 var render;
3 var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
4 var settings = {
5 evaluate : /<%([\s\S]+?)%>/g,
6 interpolate : /<%=([\s\S]+?)%>/g
7 };
8
9 // Combine delimiters into one regular expression via alternation.
10 var matcher = new RegExp([
11 (settings.interpolate || noMatch).source,
12 (settings.evaluate || noMatch).source
13 ].join('|') + '|$', 'g');
14
15 // Compile the template source, escaping string literals appropriately.
16 var index = 0;
17 var source = "__p+='";
18 text.replace(matcher, function(match, interpolate, evaluate, offset) {
19 source += text.slice(index, offset)
20 .replace(escaper, function(match) { return '\\' + escapes[match]; });
21
22 if (interpolate) {
23 source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
24 }
25 if (evaluate) {
26 source += "';\n" + evaluate + "\n__p+='";
27 }
28 index = offset + match.length;
29 return match;
30 });
31 source += "';\n";
32
33 source = "var __t,__p='',__j=Array.prototype.join," +
34 "print=function(){__p+=__j.call(arguments,'');};\n" +
35 source + "return __p;\n";
36
37 try {
38 render = new Function('obj', source);
39 } catch (e) {
40 e.source = source;
41 throw e;
42 }
43
44 if (data) return render(data);
45 var template = function(data) {
46 return render.call(this, data);
47 };
48
49 // Provide the compiled function source as a convenience for precompilation.
50 template.source = 'function(obj){\n' + source + '}';
51
52 return template;
53}
54
55var tests = {
56 filereader: typeof FileReader != 'undefined',
57 dnd: 'draggable' in document.createElement('span'),
58 formdata: !!window.FormData,
59 progress: "upload" in new XMLHttpRequest
60};
61
62var UploadTemplate = template(
63'<div>' +
64 '<label class="dnd-overwrite">Overwrite files ' +
65 '<input type="checkbox" name="overwrite" id="overwrite-check" checked />' +
66 '</label>' +
67 '<div id="dnd-upload"></div>' +
68'</div>'
69);
70
71var oldOnReady = document.onreadystatechange;
72document.onreadystatechange = function() {
73 if (document.readyState !== "complete") {
74 return;
75 }
76
77 if (typeof oldOnReady === "function") {
78 oldOnReady();
79 }
80
81 if (document.title.indexOf("Attachments for ") == -1) {
82 return;
83 }
84
85 for (key in tests) {
86 if (tests[key] !== true) {
87 return;
88 }
89 }
90
91 document.getElementsByTagName("h2")[0].insertAdjacentHTML('afterend', UploadTemplate());
92 var holder = document.getElementById('dnd-upload');
93
94 holder.ondragover = function () {
95 this.className = 'hover';
96 return false;
97 };
98
99 holder.ondragend = function () {
100 this.className = '';
101 return false;
102 };
103
104 holder.ondrop = function (e) {
105 this.className = '';
106 e.preventDefault();
107 readfiles(e.dataTransfer.files);
108 }
109};
110
111function createElement(tag, attributes, innerHTML) {
112 var element = document.createElement(tag);
113
114 for (key in attributes) {
115 element.setAttribute(key, attributes[key]);
116 }
117
118 if (typeof innerHTML !== "undefined") {
119 element.innerHTML = innerHTML;
120 }
121
122 return element;
123};
124
125function postFile(file) {
126 var size = file.size;
127 var units = ['G', 'M', 'K', 'B'];
128 var xhr = new XMLHttpRequest();
129 var formData = new FormData();
130
131 formData.append('ticket', document.getElementsByName("ticket")[0].value);
132 formData.append('action', 'AttachFile');
133 formData.append('do', 'upload');
134 formData.append('file', file);
135
136 if (document.getElementById("overwrite-check").checked) {
137 formData.append('overwrite', '1');
138 }
139
140 while (size >= 1024) {
141 size = size / 1024 | 0;
142 units.pop();
143 }
144
145 var progress = createElement('progress', { min: 0, max: 100, value: 0 });
146 var progContainer = createElement('div', { "class": "progressbar" });
147 var sizeSpan = createElement("span", { "class": "size" }, size + units[units.length - 1]);
148 var item = createElement('li');
149
150 progContainer.appendChild(progress);
151 progContainer.appendChild(sizeSpan);
152
153 item.appendChild(createElement('span', { "class": "filename" }, file.name));
154 item.appendChild(progContainer);
155
156 document.getElementById("dnd-upload").appendChild(item);
157
158 xhr.open('POST', window.location.pathname);
159 xhr.onload = function() { progress.value = 100; };
160
161 xhr.upload.onprogress = function (event) {
162 if (!event.lengthComputable) { return; }
163 progress.value = (event.loaded / event.total * 100 | 0);
164 }
165
166 xhr.send(formData);
167}
168
169function readfiles(files) {
170 for (var i = 0; i < files.length; i++) {
171 postFile(files[i]);
172 }
173}
diff --git a/static/favicon.ico b/static/favicon.ico
new file mode 100644
index 0000000..6bddf19
--- /dev/null
+++ b/static/favicon.ico
Binary files differ
diff --git a/static/iphone-icon.png b/static/iphone-icon.png
new file mode 100644
index 0000000..a30c344
--- /dev/null
+++ b/static/iphone-icon.png
Binary files differ
diff --git a/static/logo.png b/static/logo.png
new file mode 100644
index 0000000..d01667a
--- /dev/null
+++ b/static/logo.png
Binary files differ
diff --git a/static/mcrute.css b/static/mcrute.css
new file mode 100644
index 0000000..c579ae0
--- /dev/null
+++ b/static/mcrute.css
@@ -0,0 +1,90 @@
1h1, h2, h3, h4, h5 {
2 font-family: Georgia, serif;
3 font-weight: bolder;
4}
5
6ul#pagelocation,
7ul#pagelocation li {
8 font-family: Georgia, serif;
9 font-weight: bolder;
10 color: #0044B3;
11}
12
13table.navigation {
14 float: none;
15 margin: 0px;
16}
17
18table.navigation a {
19 display: block;
20}
21
22pre {
23 font-family: "Courier New", "Courier", monospace;
24}
25
26table.timecsv {
27 width: 50%;
28}
29
30table.timecsv tr.active {
31 background-color: #66FF66;
32}
33
34table.timecsv thead tr {
35 background-color: #CCCCCC;
36}
37
38.hcolumn0, .hcolumn1, .hcolumn2, .hcolumn3, .hcolumn4, .hcolumn5, .hcolumn6,
39.hcolumn7, .hcolumn8, .hcolumn9, .hcolumn10, .hcolumn11, .hcolumn12,
40.hcolumn13, .hcolumn14, .hcolumn15, .hcolumn16, .hcolumn17, .hcolumn18,
41.hcolumn19, .hcolumn20, .hcolumn21, .hcolumn22, .hcolumn23, .hcolumn24,
42.hcolumn25, .hcolumn26, .hcolumn27, .hcolumn28, .hcolumn29, .hcolumn30 {
43 background-color: #CCCCCC;
44}
45
46
47
48/* iPhone */
49@media screen and (max-width: 500px) {
50 #logo, #locationline, #pagetrail, #navibar, #pageline, #pageinfo { display: none; }
51 #page { padding: 0 0.5em; }
52 #header .editbar form { display: none; }
53 table.timecsv { width: 97%; }
54
55 /* Editor Page */
56 #page-editor input[name="button_switch"],
57 #page-editor input[name="button_spellcheck"],
58 #page-editor #chktrivialtop,
59 #page-editor label[for="chktrivialtop"]
60 {
61 display: none !important;
62 }
63
64 #page-editor #header, #page-editor #footer, #page-editor #editor-help, #page-editor form p {
65 display: none;
66 }
67
68 #page-editor #page {
69 margin: 0;
70 padding: 0;
71 }
72
73 #page-editor textarea {
74 border: none;
75 height: 90vh;
76 width: 100%;
77 }
78}
79
80
81/* DND Upload Control */
82#dnd-upload { border: 10px dashed #ccc; min-height: 100px; margin: 20px auto; padding: 1em;}
83#dnd-upload.hover { border: 10px dashed #0c0; }
84.dnd-overwrite { color: red; display: block; text-align: right; }
85
86#dnd-upload li { list-style: none; padding: 1em; }
87#dnd-upload .filename { font-weight: bolder; }
88.progressbar { float: right; }
89.progressbar progress { margin-right: 1em; }
90.progressbar .size { display: inline-block; width: 3em; text-align: right; }