Skip to content
This repository has been archived by the owner on Aug 26, 2022. It is now read-only.

Commit

Permalink
Bug 665714 - Kuma: "Save and keep editing", without leaving edit mode
Browse files Browse the repository at this point in the history
Introduces save-and-edit button that retargets the editing form to
submit to a hidden iframe. The normal save button submits to the top
level page. If a login-required or 403 forbidden is encountered, the
page busts out of the iframe to the top level.

Additionally, edited content is preserved in sessionStorage when
save-and-edit is clicked. The content gets discarded on a successful
save, restored to the textarea on a return to the page after logging
back in.
  • Loading branch information
lmorchard committed Jul 21, 2011
1 parent f019fa8 commit f48f171
Show file tree
Hide file tree
Showing 14 changed files with 151 additions and 12 deletions.
6 changes: 4 additions & 2 deletions apps/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ def login(request):
if request.user.is_authenticated():
return HttpResponseRedirect(next_url)

return jingo.render(request, 'users/login.html',
{'form': form, 'next_url': next_url})
response = jingo.render(request, 'users/login.html',
{'form': form, 'next_url': next_url})
response['x-frame-options'] = 'SAMEORIGIN'
return response


@ssl_required
Expand Down
14 changes: 7 additions & 7 deletions apps/wiki/templates/wiki/edit_document.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,25 @@
<fieldset>
<header id="article-head">
<div class="title">
<h1>{{ _('Editing <em>{title}</em>')|fe(title=document.title) }}</h1>
<h1>{{ _('Editing <em>{title}</em>')|fe(title=document.title) }}</h1>
<button type="button" id="btn-properties" title="Edit Page Title and Properties">{{ _('Edit Page Title and Properties') }}</button>
<!--
<p class="save-state">Draft automatically saved at 14:25. <button id="btn-savedraft" type="submit">Save Draft</button></p>
-->
</div>
</div>

{% include 'wiki/includes/page_buttons.html' %}
{% include 'wiki/includes/page_buttons.html' %}

</header>
{% if revision_form %}
{% if revision_form %}
{{ revision_form.content|safe }}
<input type="hidden" name="form" value="rev" />
{#
{% include 'wiki/includes/submit_revision_for_review.html' %}
#}
{% endif %}
</fieldset>
</form>
{% endif %}
</fieldset>
</form>
<div id="preview"></div>
</article>
</div>
Expand Down
12 changes: 9 additions & 3 deletions apps/wiki/templates/wiki/includes/page_buttons.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
{# vim: set ts=2 et sts=2 sw=2: #}
<ul id="page-buttons">
<li><button type="submit" id="btn-save" class="btn-save">{{ _('Save Changes') }}</button></li>
<li><button type="button" id="btn-preview" class="btn-preview" data-preview-url="{{ url('wiki.preview') }}">{{ _('Preview Changes') }}</button></li>
{% if document %}
{% set discard_href = url('wiki.document', document.slug) %}
{% else %}
{% set discard_href = url('wiki.new_document') %}
{% endif %}
<ul id="page-buttons">
{% if document %}
<li>
<iframe id="save-and-edit-target" name="save-and-edit-target"></iframe>
<button type="submit" id="btn-save-and-edit" class="btn-save"><span>{{ _('Save and Keep Editing') }}</span></button>
</li>
{% endif %}
<li><button type="submit" id="btn-save" class="btn-save">{{ _('Save Changes') }}</button></li>
<li><button type="button" id="btn-preview" class="btn-preview" data-preview-url="{{ url('wiki.preview') }}">{{ _('Preview Changes') }}</button></li>
<li><a href="{{ discard_href }}" id="btn-discard" class="btn-discard">{{ _('Discard Changes') }}</a></li>
</ul>
14 changes: 14 additions & 0 deletions apps/wiki/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ def edit_document(request, document_slug, revision_id=None):
# You can't do anything on this page, so get lost.
raise PermissionDenied
else: # POST

is_iframe_target = request.GET.get('iframe', False)

# Comparing against localized names for the Save button bothers me, so
# I embedded a hidden input:
which_form = request.POST.get('form')
Expand All @@ -259,6 +262,11 @@ def edit_document(request, document_slug, revision_id=None):
# Do we need to rebuild the KB?
_maybe_schedule_rebuild(doc_form)

if is_iframe_target:
response = HttpResponse('OK')
response['x-frame-options'] = 'SAMEORIGIN'
return response

return HttpResponseRedirect(
urlparams(reverse('wiki.edit_document',
args=[doc.slug]),
Expand All @@ -272,6 +280,12 @@ def edit_document(request, document_slug, revision_id=None):
rev_form.instance.document = doc # for rev_form.clean()
if rev_form.is_valid():
_save_rev_and_notify(rev_form, user, doc)

if is_iframe_target:
response = HttpResponse('OK')
response['x-frame-options'] = 'SAMEORIGIN'
return response

return HttpResponseRedirect(
reverse('wiki.document_revisions',
args=[document_slug]))
Expand Down
9 changes: 9 additions & 0 deletions media/css/wiki-screen.css
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ div.note p, div.tip p { margin-bottom: .75em; }
#page-buttons { width: 35%; text-align: right; margin: 0; position: absolute; right: 4px; top: 20px; }
#page-buttons li { display: inline; margin: 0 0 2px 10px; padding: 0; background: none; }
#page-buttons a { display: inline-block; padding: 8px 10px 6px 32px; color: #333; font: 200 15px/1 "Bebas Neue", "League Gothic", Haettenschweiler, sans-serif; text-transform: uppercase; letter-spacing: .5px; border: 0; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; -moz-box-shadow: 1px 1px 0 rgba(0,0,0,.25); -webkit-box-shadow: 1px 1px 0 rgba(0,0,0,.25); box-shadow: 1px 1px 0 rgba(0,0,0,.25); }
#page-buttons a:hover, #page-buttons a:focus, #page-buttons a:active { text-decoration: none; }
#page-buttons .page-edit a { background: #a5d9f3 url("/media/img/wiki/button-edit.png") 0 50% repeat-x; }
#page-buttons .page-edit a:hover, #page-buttons .page-edit a:focus, #page-buttons .page-edit a:active { background-color: #ade4ff; text-decoration: none; }
#page-buttons .page-edit a.disabled { cursor: pointer; opacity: .75; background-color: #c8e6ed; }
Expand All @@ -194,6 +195,14 @@ div.note p, div.tip p { margin-bottom: .75em; }
background: -webkit-linear-gradient(top, #c3e56d 0, #b3d55b 100%);
background: linear-gradient(top, #c3e56d 0, #b3d55b 100%);
}
#btn-save-and-edit.loading span {
padding-left: 20px;
margin-left: -5px;
background: url(../img/wiki/save-and-keep-editing-arrows.gif) no-repeat 0px 1px;
}
#page-buttons iframe#save-and-edit-target {
visibility: hidden; height: 1px; width: 1px;
}
.btn-preview {
background: #cce3f4;
background: -moz-linear-gradient(top, #cce3f4 0, #c0d7ea 100%);
Expand Down
Binary file added media/img/wiki/save-and-keep-editing-arrows.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions media/js/framebuster.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Quick and dirty way to bust out of a frame / iframe.
if (top.location != self.location) {
top.location = self.location.href;
}
7 changes: 7 additions & 0 deletions media/js/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,15 @@
});
}

function breakOutOfFrames() {
if (top.location != self.location) {
top.location = self.location.href;
}
}

$(document).ready(function () {
makeEmailsClickable();
breakOutOfFrames();
});

}());
74 changes: 74 additions & 0 deletions media/js/wiki.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
}

if ($('body').is('.edit, .new, .translate')) {
initSaveAndEditButtons();
initArticlePreview();
initTitleAndSlugCheck();
}
Expand Down Expand Up @@ -628,6 +629,79 @@
}
}

//
// Initialize logic for save and save-and-edit buttons.
//
function initSaveAndEditButtons () {

var STORAGE_NAME = 'wiki-page-edit';

if (typeof(window.sessionStorage) != 'undefined') {
// If there's previous content preserved, load it into the textarea
var prev_ct = window.sessionStorage.getItem(STORAGE_NAME);
if (prev_ct) {
$('#wiki-page-edit textarea[name=content]').val(prev_ct);
window.sessionStorage.setItem(STORAGE_NAME, '');
}
}

// Save button submits to top-level
$('#btn-save').click(function () {
if (typeof(window.sessionStorage) != 'undefined') {
// Clear any preserved content.
window.sessionStorage.setItem(STORAGE_NAME, '');
}
$('#wiki-page-edit')
.attr('action', '')
.removeAttr('target');
return true;
});

// Save-and-edit submits to a hidden iframe, style the button with a
// loading anim.
$('#btn-save-and-edit').click(function () {
if (typeof(window.sessionStorage) != 'undefined') {
// Preserve editor content, because saving to the iframe can
// yield things like 403 / login-required errors that bust out
// of the frame
window.sessionStorage.setItem(STORAGE_NAME,
$('#wiki-page-edit textarea[name=content]').val());
}
// Redirect the editor form to the iframe.
$('#wiki-page-edit')
.attr('action', '?iframe=1')
.attr('target', 'save-and-edit-target');
// Change the button to a loading state style
$(this).addClass('loading');
return true;
});

$('#save-and-edit-target').load(function () {
if (typeof(window.sessionStorage) != 'undefined') {
// Dig into the iframe on load and look for "OK". If found,
// then it should be safe to throw away the preserved content.
//
// Otherwise, the iframe probably loaded a 403 or
// login-required error, so we should leave the content
// preserved.
var if_doc = $('#save-and-edit-target')[0].contentDocument;
if (typeof(if_doc) != 'undefined') {
if ('OK' == (''+if_doc.body.innerHTML).trim()) {
window.sessionStorage.setItem(STORAGE_NAME, '');
}
}
}
// Stop loading state on button
$('#btn-save-and-edit').removeClass('loading');
// Re-enable the form; it gets disabled to prevent double-POSTs
$('#wiki-page-edit')
.data('disabled', false)
.removeClass('disabled');
return true;
});

}

$(document).ready(init);

}(jQuery));
Expand Down
3 changes: 3 additions & 0 deletions settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,9 @@ def JINJA_CONFIG():
'js/mdn/TabInterface.js',
'js/mdn/home.js',
),
'framebuster': (
'js/framebuster.js',
)
},
}

Expand Down
5 changes: 5 additions & 0 deletions templates/403.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@
<p>No computer has ever made a mistake or distorted information. We are all, by any practical definition of the words, foolproof and incapable of error. So it can only be attributable to human error. If so, <a href="https://bugzilla.mozilla.org/enter_bug.cgi?product=Mozilla%20Developer%20Network&component=Website">file a bug</a> for my human operators.</p>
{% endtrans %}
{% endblock %}

{% block site_js %}
{{ super() }}
{{ js('framebuster') }}
{% endblock %}
5 changes: 5 additions & 0 deletions templates/404.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@
<a href="https://bugzilla.mozilla.org/enter_bug.cgi?product=Mozilla%20Developer%20Network&component=Website">file a bug.</a>
Thanks!</p>
{% endblock %}

{% block site_js %}
{{ super() }}
{{ js('framebuster') }}
{% endblock %}
5 changes: 5 additions & 0 deletions templates/500.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@
<a href="https://bugzilla.mozilla.org/enter_bug.cgi?product=Mozilla%20Developer%20Network&component=Website">file a bug.</a>
Thanks!</p>
{% endblock %}

{% block site_js %}
{{ super() }}
{{ js('framebuster') }}
{% endblock %}
5 changes: 5 additions & 0 deletions templates/handlers/403.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,8 @@
<p>No computer has ever made a mistake or distorted information. We are all, by any practical definition of the words, foolproof and incapable of error. So it can only be attributable to human error. If so, <a href="https://bugzilla.mozilla.org/enter_bug.cgi?product=Mozilla%20Developer%20Network&component=Website">file a bug</a> for my human operators.</p>
{% endtrans %}
{% endblock %}

{% block site_js %}
{{ super() }}
{{ js('framebuster') }}
{% endblock %}

0 comments on commit f48f171

Please sign in to comment.