def all(self):
return list(self.vstorage.all_pages())
+
+ def history(self, title):
+ return list(self.vstorage.page_history(title))
def _info(self, name):
return self.vstorage.page_meta(name)
except DocumentNotFound:
return - 1
+ @property
def plain_text(self):
return re.sub(self.META_REGEX, '', self.text, 1)
Wersja: <span id="document-revision">{{ document.revision }}</span> <button style="margin-left: 6px" id="save-button">Zapisz</button></div>
<h1><a href="{% url wiki.views.document_list %}">Platforma</a></h1>
<ol id="tabs">
- <li id="simple-view-tab"><span id="document-name">{{ document.name }}</span></li>
- <li id="source-view-tab" class="active">Kod źródłowy</li>
+ <li id="simple-view-tab" ui:related="simple-editor"><span id="document-name">{{ document.name }}</span></li>
+ <li id="source-view-tab" ui:related="source-editor">Kod źródłowy</li>
+ <li id="history-view-tab" ui:related="history-viewer">Historia</li>
</ol>
<div style="clear: both"></div>
</div>
<div id="splitter">
<div id="editor">
- <div id="source-editor">
+ <div id="source-editor" class="editor">
{% toolbar %}
<textarea name="text" id="id_text">{{ document.plain_text }}</textarea>
<input type="hidden" name="name" value="{{ document.name }}" />
<input type="hidden" name="comment" value="no comment" />
<input type="hidden" name="revision" value="{{ document.revision }}" />
</div>
- <div id="simple-editor" style="display: none">
+ <div id="simple-editor" class="editor" style="display: none">
<div class="toolbar">
<button id="insert-theme-button">Wstaw motyw</button> <button id="insert-annotation-button">Wstaw przypis</button>
<div class="toolbar-end"> </div>
<div id="html-view" class="htmlview">
</div>
</div>
+
+ <div id="history-viewer" class="editor" style="display: none">
+ <div class="toolbar"> </div>
+ <div id="history-view">
+ <p class="message-box" style="display:none;"></p>
+ <table>
+ <thead>
+ <th> </th>
+ <th>Numer</th>
+ <th>Opis</th>
+ <th>Użytkownik</th>
+ <th>Data</th>
+ </thead>
+ <tbody id="changes-list">
+ </tbody>
+ </table>
+
+ <p><button type="button" id="make-diff-button">Porównaj</button></p>
+ <!-- <p><button type="button" id="more-history-button">Więcej</button></p> -->
+ <div id="diff-view">
+ </div>
+ </div>
+
+ </div>
</div>
<div class="vsplitbar"> </div>
<div id="sidebar">
from wiki.models import storage, Document, DocumentNotFound
from wiki.forms import DocumentForm
+from datetime import datetime
+
+# import google_diff
+import difflib
+
+
+class DateTimeEncoder(json.JSONEncoder):
+ def default(self, obj):
+ if isinstance(obj, datetime):
+ return datetime.ctime(obj) + " " + (datetime.tzname(obj) or 'GMT')
+ return json.JSONEncoder.default(self, obj)
def document_list(request, template_name = 'wiki/document_list.html'):
return direct_to_template(request, template_name, extra_context = {
form = DocumentForm(request.POST, instance = document)
if form.is_valid():
document = form.save()
- return HttpResponse(json.dumps({'text': document.plain_text(), 'meta': document.meta(), 'revision': document.revision()}))
+ return HttpResponse(json.dumps({'text': document.plain_text, 'meta': document.meta(), 'revision': document.revision()}))
else:
return HttpResponse(json.dumps({'errors': form.errors}))
else:
traceback.print_exc()
raise Http404
+
+def document_diff(request, name, revA, revB):
+ differ = difflib.HtmlDiff(wrapcolumn=60)
+
+ docA = storage.get(name, int(revA))
+ docB = storage.get(name, int(revB))
+
+ return HttpResponse(differ.make_table(
+ docA.plain_text.splitlines(),
+ docB.plain_text.splitlines() ) )
+
+
+def document_history(reuqest, name):
+ return HttpResponse( json.dumps(storage.history(name), cls=DateTimeEncoder), mimetype='application/json')
cursor: e-resize;
}
-#source-editor, #simple-editor {
+#source-editor, #simple-editor, #history-viewer {
position: absolute;
top: 25px;
bottom: 0;
overflow: hidden;
}
-#html-view {
+#html-view, #history-view {
overflow: auto;
position: absolute;
top: 27px;
width: 40px;
}
-
\ No newline at end of file
+
+/* DIFFS */
+ #history-view table {
+ width: 75%;
+ margin: 1em auto;
+ max-height: 400px;
+ overflow-y: auto;
+ }
+
+ #diff-view {
+ border: 2px solid black;
+ background: #fafafa;
+ margin: 1em auto;
+ width: 90%;
+ }
+
+ td.diff_header {
+ display: none;
+ }
+
+ td.diff_next {
+ display: none;
+ }
+
+ .diff_sub {
+ background-color: #ef4040;
+ }
+
+ .diff_chg {
+ background-color: #efef40;
+ }
+
+ .diff_add {
+ background-color: #40ef40;
+ }
});
}
+/*
+ * History
+ */
+
+function refreshHistory(callback){
+ $.blockUI({
+ message: 'Odświeżanie historii...'
+ });
+
+ $.ajax({
+ url: document.location.href + '/history',
+ dataType: 'json',
+ error: function() {
+ $('#history-view .message-box').html('Nie udało się odświeżyć historii').show();
+ $.unblockUI();
+ },
+ success: function(data) {
+ $('#history-view .message-box').hide();
+ var changes_list = $('#changes-list');
+ changes_list.html('');
+
+ $.each(data, function() {
+ var val = this[0];
+ changes_list.append('<tr>'
+ +'<td><input type="radio" name="rev_from" value="'+val+'">'
+ + '<input type="radio" name="rev_to" value="'+val+'">'
+ +'<td>'+ this[0]+'</td>'
+ +'<td>'+ this[3]+'</td>'
+ +'<td>'+ this[2]+'</td>'
+ +'<td>'+ this[1]+'</td></tr>')
+ });
+ $.unblockUI();
+ callback();
+ }
+ });
+};
+
+function historyDiff(callback) {
+ var changelist = $('#changes-list');
+ var rev_a = $("input[name='rev_from']:checked", changelist);
+ var rev_b = $("input[name='rev_to']:checked", changelist);
+
+ if (rev_a.length != 1 || rev_b.length != 1) {
+ window.alert("Musisz zaznaczyć dwie wersje do porównania.");
+ return false;
+ }
+
+ if (rev_a.val() == rev_b.val()) {
+ window.alert("Musisz zaznaczyć dwie różne wersje do porównania.");
+ return false;
+ }
+
+ $.blockUI({
+ message: 'Wczytywanie porównania...'
+ });
+
+ $.ajax({
+ url: document.location.href + '/diff/'+rev_a.val() + '/'+ rev_b.val(),
+ dataType: 'html',
+ error: function() {
+ $.unblockUI();
+ window.alert('Nie udało się wykonać porównania :(.')
+ },
+ success: function(data) {
+ $.unblockUI();
+ var diffview = $('#diff-view');
+ diffview.html(data);
+ diffview.show();
+ }
+ });
+}
+
$(function() {
gallery('#sidebar', $('#document-meta .gallery').html());
},
iframeClass: 'xml-iframe',
textWrapping: true,
- lineNumbers: true,
+ /* lineNumbers: true, */
tabMode: 'spaces',
indentUnit: 0,
initCallback: function(editor) {
$('#save-cancel').click(function() {
$.unblockUI();
});
-
- function changeTab(callback) {
- if ($('#simple-view-tab').hasClass('active')) {
- return;
- }
- $('#simple-view-tab').addClass('active');
- $('#source-view-tab').removeClass('active');
- $('#source-editor').hide();
- $('#simple-editor').show();
+
+ var tabs = $('ol#tabs li');
+
+ tabs.click(function(event, callback) {
+ tabs.removeClass('active');
+ $('.editor').hide();
+ $(this).addClass('active');
+ $('#' + $(this).attr('ui:related')).show();
+ $(this).trigger('wl:tabload', callback);
+ });
+
+
+ $('#simple-view-tab').bind('wl:tabload', function(event, callback) {
transform(editor, callback);
- }
- $('#simple-view-tab').click(function() { changeTab(); });
-
- $('#source-view-tab').click(function() {
- if ($(this).hasClass('active')) {
- return;
- }
- $(this).addClass('active');
- $('#simple-view-tab').removeClass('active');
- $('#simple-editor').hide();
- $('#source-editor').show();
- reverseTransform(editor);
});
+
+ $('#source-view-tab').bind('wl:tabload', function(event, callback) {
+ reverseTransform(editor, callback);
+ });
+
+ $('#history-view-tab').bind('wl:tabload', function(event, callback) {
+ refreshHistory(callback);
+ });
+
+ $('#make-diff-button').click(historyDiff);
$('#source-editor .toolbar button').click(function(event) {
event.preventDefault();
scriptletCenter.scriptlets[$(this).attr('ui:action')](editor, params);
});
- $('.toolbar select').change(function() {
+ $('.toolbar select').change(function(event) {
var slug = $(this).val();
$('.toolbar-buttons-container').hide().filter('[data-group=' + slug + ']').show();
$('.toolbar-buttons-container').hide();
$('.toolbar select').change();
- changeTab(function() { $('#loading-overlay').fadeOut() }, function() { $('#loading-overlay').fadeOut() }, true)
+
+ $('#simple-view-tab').trigger('click',
+ function() {
+ $('#loading-overlay').fadeOut();
+ return false;
+ });
}
});
urlpatterns = patterns('',
url(r'^$', 'wiki.views.document_list'),
url(r'^gallery/(?P<directory>[^/]+)$', 'wiki.views.document_gallery'),
+ url(r'^(?P<name>[^/]+)/history$', 'wiki.views.document_history'),
+ url(r'^(?P<name>[^/]+)/diff/(?P<revA>\d+)/(?P<revB>\d+)$', 'wiki.views.document_diff'),
# Auth
url(r'^accounts/login/$', 'django_cas.views.login', name = 'login'),