[Rt-commit] rt branch, 4.0/rights-editor-tab-state, created. rt-4.0.8-213-gf69b46c
Thomas Sibley
trs at bestpractical.com
Tue Dec 4 01:23:52 EST 2012
The branch, 4.0/rights-editor-tab-state has been created
at f69b46cda25bef472237d08332c289b1792ee7f9 (commit)
- Log -----------------------------------------------------------------
commit 869de6884d7a2e3ab9ea9dda1b810a6ad810ed07
Author: Thomas Sibley <trs at bestpractical.com>
Date: Mon Dec 3 17:16:37 2012 -0800
Default to the previously selected user/group in the rights editor
Prevents confusion across form submission by keeping the rights editor
looking at the same principal panel. Resolves [rt3 #19205].
This works even for newly added principals, which need translation from
a submitted Name to a principal ID. Part of this translation/lookup
logic is refactored out of ProcessACLs() so that both the backend and UI
piece can use the same code (_ParseACLNewPrincipal).
Anchor generation is changed to omit the grouping name to cleanly
separate this code from the principal map generated by
GetPrincipalsMap(), rather than adding assumptions.
Based on an initial implementation by sunnavy.
diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index 3385c49..514a105 100644
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -2206,19 +2206,8 @@ sub ProcessACLs {
# Check if we want to grant rights to a previously rights-less user
for my $type (qw(user group)) {
- my $key = "AddPrincipalForRights-$type";
-
- next unless $ARGSref->{$key};
-
- my $principal;
- if ( $type eq 'user' ) {
- $principal = RT::User->new( $session{'CurrentUser'} );
- $principal->LoadByCol( Name => $ARGSref->{$key} );
- }
- else {
- $principal = RT::Group->new( $session{'CurrentUser'} );
- $principal->LoadUserDefinedGroup( $ARGSref->{$key} );
- }
+ my $principal = _ParseACLNewPrincipal($ARGSref, $type)
+ or next;
unless ($principal->PrincipalId) {
push @results, loc("Couldn't load the specified principal");
@@ -2318,7 +2307,34 @@ sub ProcessACLs {
return (@results);
}
+=head2 _ParseACLNewPrincipal
+
+Takes a hashref of C<%ARGS> and a principal type (C<user> or C<group>). Looks
+for the presence of rights being added on a principal of the specified type,
+and returns undef if no new principal is being granted rights. Otherwise loads
+up an L<RT::User> or L<RT::Group> object and returns it. Note that the object
+may not be successfully loaded, and you should check C<->id> yourself.
+
+=cut
+
+sub _ParseACLNewPrincipal {
+ my $ARGSref = shift;
+ my $type = lc shift;
+ my $key = "AddPrincipalForRights-$type";
+
+ return unless $ARGSref->{$key};
+ my $principal;
+ if ( $type eq 'user' ) {
+ $principal = RT::User->new( $session{'CurrentUser'} );
+ $principal->LoadByCol( Name => $ARGSref->{$key} );
+ }
+ elsif ( $type eq 'group' ) {
+ $principal = RT::Group->new( $session{'CurrentUser'} );
+ $principal->LoadUserDefinedGroup( $ARGSref->{$key} );
+ }
+ return $principal;
+}
=head2 UpdateRecordObj ( ARGSRef => \%ARGS, Object => RT::Record, AttributesRef => \@attribs)
diff --git a/share/html/Admin/Elements/EditRights b/share/html/Admin/Elements/EditRights
index e673593..db653c5 100644
--- a/share/html/Admin/Elements/EditRights
+++ b/share/html/Admin/Elements/EditRights
@@ -66,6 +66,18 @@ unless ( $AddPrincipal ) {
$AddPrincipal = 'user'; # loc
}
}
+
+my $anchor = $DECODED_ARGS->{Anchor} || '';
+if ($anchor =~ /AddPrincipal/) {
+ for my $type ("group", "user") {
+ my $record = _ParseACLNewPrincipal($DECODED_ARGS, $type)
+ or next;
+ if ($record->PrincipalId) {
+ $anchor = "#acl-" . $record->PrincipalId;
+ last;
+ }
+ }
+}
</%init>
%# Principals is an array of arrays, where the inner arrays are like:
%# [ 'Category name' => $CollectionObj => 'DisplayColumn' => 1 ]
@@ -74,16 +86,26 @@ unless ( $AddPrincipal ) {
<script type="text/javascript">
jQuery(function() {
+ function sync_anchor(hash) {
+ if (!hash.length) return;
+ window.location.hash = hash;
+ jQuery(".rights-editor input[name=Anchor]").val(hash);
+ }
+ sync_anchor(<% $anchor |n,j %>);
+
jQuery(".rights-editor").tabs({
select: function(ev, ui) {
- window.location.hash = ui.tab.hash;
+ sync_anchor(ui.tab.hash);
}
});
+
jQuery(".rights-editor .category-tabs").tabs();
});
</script>
<div class="rights-editor clearfix">
+ <input type="hidden" value="" name="Anchor" />
+
<ul>
<%perl>
for my $category (@$Principals) {
@@ -93,8 +115,7 @@ for my $category (@$Principals) {
<%perl>
while ( my $obj = $collection->Next ) {
my $display = ref $col eq 'CODE' ? $col->($obj) : $obj->$col;
- my $id = "acl-$name-" . $obj->PrincipalId;
- $id =~ s/[^a-zA-Z0-9\-]/_/g;
+ my $id = "acl-" . $obj->PrincipalId;
</%perl>
<li><a href="#<% $id %>"><% $loc ? loc($display) : $display %></a></li>
<%perl>
@@ -136,8 +157,7 @@ for my $category (@$Principals) {
my ($name, $collection, $col, $loc) = @$category;
while ( my $obj = $collection->Next ) {
my $display = ref $col eq 'CODE' ? $col->($obj) : $obj->$col;
- my $id = "acl-$name-" . $obj->PrincipalId;
- $id =~ s/[^a-zA-Z0-9\-]/_/g;
+ my $id = "acl-" . $obj->PrincipalId;
</%perl>
<div id="<% $id %>">
commit 4cd6bb6727d0902a583067d51004cb03543e1878
Author: Thomas Sibley <trs at bestpractical.com>
Date: Mon Dec 3 21:42:25 2012 -0800
Stay on the same rights subtab when switching between principals
By hooking the "show" event instead of the "select" event we avoid an
infinite loop when we then select the new tab in each tabset: by the
time "show" fires, the selected tab is already correct.
Based on an initial implementation by sunnavy, which differed primarily
in hooking the "select" event and unregistering/re-registering to work
around the loop.
Resolves [rt3 #19769].
diff --git a/share/html/Admin/Elements/EditRights b/share/html/Admin/Elements/EditRights
index db653c5..c4a17fc 100644
--- a/share/html/Admin/Elements/EditRights
+++ b/share/html/Admin/Elements/EditRights
@@ -99,7 +99,16 @@ if ($anchor =~ /AddPrincipal/) {
}
});
- jQuery(".rights-editor .category-tabs").tabs();
+ jQuery(".rights-editor .category-tabs").tabs({
+ show: function(ev, ui) {
+ jQuery(".rights-editor .category-tabs").not(this).each(function() {
+ var item = jQuery(this);
+ var selected = item.tabs("option", "selected") || 0;
+ if (selected != ui.index)
+ item.tabs("select", ui.index);
+ });
+ }
+ });
});
</script>
commit f69b46cda25bef472237d08332c289b1792ee7f9
Author: Thomas Sibley <trs at bestpractical.com>
Date: Mon Dec 3 22:09:56 2012 -0800
Preserve the selected rights category tab across page reloads
For example: granting a right to "Privileged" from the "Rights for
Administrators" tab will return you to both tabs after submission.
We still need the anchor framework for the principal tabs in order to
translate newly added principals to their correct tab server-side. The
non-newly-added-principal side could be replaced with similar cookie
usage, but it seems not as worthwhile since we'll still be stuck
wrangling anchors. One slightly verbose method is better than two
competing methods.
diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index 0df3e2b..dcc68cc 100755
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -873,6 +873,7 @@ Set(@JSFiles, qw/
jquery-ui-1.8.4.custom.min.js
jquery-ui-timepicker-addon.js
jquery-ui-patch-datepicker.js
+ jquery.cookie.js
titlebox-state.js
util.js
userautocomplete.js
diff --git a/share/html/Admin/Elements/EditRights b/share/html/Admin/Elements/EditRights
index c4a17fc..895e015 100644
--- a/share/html/Admin/Elements/EditRights
+++ b/share/html/Admin/Elements/EditRights
@@ -100,6 +100,7 @@ if ($anchor =~ /AddPrincipal/) {
});
jQuery(".rights-editor .category-tabs").tabs({
+ cookie: { name: "rights-category-tab" /* saves current tab in cookie */ },
show: function(ev, ui) {
jQuery(".rights-editor .category-tabs").not(this).each(function() {
var item = jQuery(this);
diff --git a/share/html/NoAuth/js/jquery.cookie.js b/share/html/NoAuth/js/jquery.cookie.js
new file mode 100644
index 0000000..7b3e701
--- /dev/null
+++ b/share/html/NoAuth/js/jquery.cookie.js
@@ -0,0 +1,89 @@
+/*jslint browser: true */ /*global jQuery: true */
+
+/**
+ * jQuery Cookie plugin
+ *
+ * Copyright (c) 2010 Klaus Hartl (stilbuero.de)
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+
+// TODO JsDoc
+
+/**
+ * Create a cookie with the given key and value and other optional parameters.
+ *
+ * @example $.cookie('the_cookie', 'the_value');
+ * @desc Set the value of a cookie.
+ * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
+ * @desc Create a cookie with all available options.
+ * @example $.cookie('the_cookie', 'the_value');
+ * @desc Create a session cookie.
+ * @example $.cookie('the_cookie', null);
+ * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
+ * used when the cookie was set.
+ *
+ * @param String key The key of the cookie.
+ * @param String value The value of the cookie.
+ * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
+ * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
+ * If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
+ * If set to null or omitted, the cookie will be a session cookie and will not be retained
+ * when the the browser exits.
+ * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
+ * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
+ * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
+ * require a secure protocol (like HTTPS).
+ * @type undefined
+ *
+ * @name $.cookie
+ * @cat Plugins/Cookie
+ * @author Klaus Hartl/klaus.hartl at stilbuero.de
+ */
+
+/**
+ * Get the value of a cookie with the given key.
+ *
+ * @example $.cookie('the_cookie');
+ * @desc Get the value of a cookie.
+ *
+ * @param String key The key of the cookie.
+ * @return The value of the cookie.
+ * @type String
+ *
+ * @name $.cookie
+ * @cat Plugins/Cookie
+ * @author Klaus Hartl/klaus.hartl at stilbuero.de
+ */
+jQuery.cookie = function (key, value, options) {
+
+ // key and value given, set cookie...
+ if (arguments.length > 1 && (value === null || typeof value !== "object")) {
+ options = jQuery.extend({}, options);
+
+ if (value === null) {
+ options.expires = -1;
+ }
+
+ if (typeof options.expires === 'number') {
+ var days = options.expires, t = options.expires = new Date();
+ t.setDate(t.getDate() + days);
+ }
+
+ return (document.cookie = [
+ encodeURIComponent(key), '=',
+ options.raw ? String(value) : encodeURIComponent(String(value)),
+ options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
+ options.path ? '; path=' + options.path : '',
+ options.domain ? '; domain=' + options.domain : '',
+ options.secure ? '; secure' : ''
+ ].join(''));
+ }
+
+ // key and possibly options given, get cookie...
+ options = value || {};
+ var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent;
+ return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null;
+};
-----------------------------------------------------------------------
More information about the Rt-commit
mailing list