Skip to content

Commit 72b19f7

Browse files
byrnereesejayallen
authored andcommitted
[#618] Added better state management for clicking on left hand vertical tabs for the Plugin Preferences screen. Improved default state handling. Added support for deep linking into a plugin's preferences.
1 parent dc39252 commit 72b19f7

File tree

6 files changed

+242
-28
lines changed

6 files changed

+242
-28
lines changed

lib/MT/CMS/Plugin.pm

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,7 @@ sub save_config {
121121
$tmpl->param( plugin_config_saved => 1 );
122122
return $app->build_page($tmpl);
123123
}
124-
$app->add_return_arg( saved => 1 );
125-
$app->add_return_arg( plugin => $profile->{object}->id );
124+
$app->add_return_arg( saved => $profile->{object}->id );
126125
$app->call_return;
127126
} ## end sub save_config
128127

mt-static/jquery/jquery.history.js

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/*
2+
* jQuery history plugin
3+
*
4+
* The MIT License
5+
*
6+
* Copyright (c) 2006-2009 Taku Sano (Mikage Sawatari)
7+
* Copyright (c) 2010 Takayuki Miwa
8+
*
9+
* Permission is hereby granted, free of charge, to any person obtaining a copy
10+
* of this software and associated documentation files (the "Software"), to deal
11+
* in the Software without restriction, including without limitation the rights
12+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
* copies of the Software, and to permit persons to whom the Software is
14+
* furnished to do so, subject to the following conditions:
15+
*
16+
* The above copyright notice and this permission notice shall be included in
17+
* all copies or substantial portions of the Software.
18+
*
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
(function($) {
29+
var locationWrapper = {
30+
put: function(hash, win) {
31+
(win || window).location.hash = this.encoder(hash);
32+
},
33+
get: function(win) {
34+
var hash = ((win || window).location.hash).replace(/^#/, '');
35+
try {
36+
return $.browser.mozilla ? hash : decodeURIComponent(hash);
37+
}
38+
catch (error) {
39+
return hash;
40+
}
41+
},
42+
encoder: encodeURIComponent
43+
};
44+
45+
var iframeWrapper = {
46+
id: "__jQuery_history",
47+
init: function() {
48+
var html = '<iframe id="'+ this.id +'" style="display:none" src="javascript:false;" />';
49+
$("body").prepend(html);
50+
return this;
51+
},
52+
_document: function() {
53+
return $("#"+ this.id)[0].contentWindow.document;
54+
},
55+
put: function(hash) {
56+
var doc = this._document();
57+
doc.open();
58+
doc.close();
59+
locationWrapper.put(hash, doc);
60+
},
61+
get: function() {
62+
return locationWrapper.get(this._document());
63+
}
64+
};
65+
66+
function initObjects(options) {
67+
options = $.extend({
68+
unescape: false
69+
}, options || {});
70+
71+
locationWrapper.encoder = encoder(options.unescape);
72+
73+
function encoder(unescape_) {
74+
if(unescape_ === true) {
75+
return function(hash){ return hash; };
76+
}
77+
if(typeof unescape_ == "string" &&
78+
(unescape_ = partialDecoder(unescape_.split("")))
79+
|| typeof unescape_ == "function") {
80+
return function(hash) { return unescape_(encodeURIComponent(hash)); };
81+
}
82+
return encodeURIComponent;
83+
}
84+
85+
function partialDecoder(chars) {
86+
var re = new RegExp($.map(chars, encodeURIComponent).join("|"), "ig");
87+
return function(enc) { return enc.replace(re, decodeURIComponent); };
88+
}
89+
}
90+
91+
var implementations = {};
92+
93+
implementations.base = {
94+
callback: undefined,
95+
type: undefined,
96+
97+
check: function() {},
98+
load: function(hash) {},
99+
init: function(callback, options) {
100+
initObjects(options);
101+
self.callback = callback;
102+
self._options = options;
103+
self._init();
104+
},
105+
106+
_init: function() {},
107+
_options: {}
108+
};
109+
110+
implementations.timer = {
111+
_appState: undefined,
112+
_init: function() {
113+
var current_hash = locationWrapper.get();
114+
self._appState = current_hash;
115+
self.callback(current_hash);
116+
setInterval(self.check, 100);
117+
},
118+
check: function() {
119+
var current_hash = locationWrapper.get();
120+
if(current_hash != self._appState) {
121+
self._appState = current_hash;
122+
self.callback(current_hash);
123+
}
124+
},
125+
load: function(hash) {
126+
if(hash != self._appState) {
127+
locationWrapper.put(hash);
128+
self._appState = hash;
129+
self.callback(hash);
130+
}
131+
}
132+
};
133+
134+
implementations.iframeTimer = {
135+
_appState: undefined,
136+
_init: function() {
137+
var current_hash = locationWrapper.get();
138+
self._appState = current_hash;
139+
iframeWrapper.init().put(current_hash);
140+
self.callback(current_hash);
141+
setInterval(self.check, 100);
142+
},
143+
check: function() {
144+
var iframe_hash = iframeWrapper.get(),
145+
location_hash = locationWrapper.get();
146+
147+
if (location_hash != iframe_hash) {
148+
if (location_hash == self._appState) { // user used Back or Forward button
149+
self._appState = iframe_hash;
150+
locationWrapper.put(iframe_hash);
151+
self.callback(iframe_hash);
152+
} else { // user loaded new bookmark
153+
self._appState = location_hash;
154+
iframeWrapper.put(location_hash);
155+
self.callback(location_hash);
156+
}
157+
}
158+
},
159+
load: function(hash) {
160+
if(hash != self._appState) {
161+
locationWrapper.put(hash);
162+
iframeWrapper.put(hash);
163+
self._appState = hash;
164+
self.callback(hash);
165+
}
166+
}
167+
};
168+
169+
implementations.hashchangeEvent = {
170+
_init: function() {
171+
self.callback(locationWrapper.get());
172+
$(window).bind('hashchange', self.check);
173+
},
174+
check: function() {
175+
self.callback(locationWrapper.get());
176+
},
177+
load: function(hash) {
178+
locationWrapper.put(hash);
179+
}
180+
};
181+
182+
var self = $.extend({}, implementations.base);
183+
184+
if($.browser.msie && ($.browser.version < 8 || document.documentMode < 8)) {
185+
self.type = 'iframeTimer';
186+
} else if("onhashchange" in window) {
187+
self.type = 'hashchangeEvent';
188+
} else {
189+
self.type = 'timer';
190+
}
191+
192+
$.extend(self, implementations[self.type]);
193+
$.history = self;
194+
})(jQuery);

mt-static/js/melody/cfg_plugins.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
function getParameterByName( name )
2+
{
3+
name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
4+
var regexS = "[\\?&]"+name+"=([^&#]*)";
5+
var regex = new RegExp( regexS );
6+
var results = regex.exec( window.location.href );
7+
if( results == null )
8+
return "";
9+
else
10+
return decodeURIComponent(results[1].replace(/\+/g, " "));
11+
}
12+
13+
$(document).ready( function() {
14+
$('#content-nav ul li a').click( function() {
15+
var active = $(this).parents('ul').find('li.active a').attr('id').replace(/-tab$/,'');
16+
var newactive = $(this).attr('id').replace(/-tab$/,'');
17+
//alert('active:'+active+', newactive='+newactive);
18+
if (active != newactive) {
19+
$('#content-nav li.active').removeClass('active');
20+
$('#' + active + '-tab-content').hide();
21+
$('#content-nav li.' + newactive).addClass('active');
22+
}
23+
$('#' + newactive + '-tab-content').show();
24+
$('h2#page-title').html( $(this).attr('title') );
25+
document.title = $(this).attr('title');
26+
window.location.hash = newactive;
27+
});
28+
$.history.init(function(hash){
29+
if (hash == "") {
30+
if (getParameterByName('saved')) {
31+
hash = 'plugin-' + getParameterByName('saved');
32+
} else {
33+
hash = $('#content-nav ul li:first-child a').attr('id').replace(/-tab$/,'');
34+
}
35+
}
36+
//alert('hash='+hash);
37+
$('#content-nav ul li.'+hash+'-tab').addClass('active');
38+
$('#content-nav ul li.'+hash+'-tab a').click();
39+
});
40+
});

mt-static/melody/styles.css

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,6 @@
6363
background-image: url(../images/status_icons/user-enabled-sysadmin.png);
6464
}
6565

66-
66+
/* Refactored Plugin Preferences */
67+
#list-plugins .plugin_form h3.plugin-name { display: none; }
68+
/* END Refactored Plugin Preferences */

tmpl/cms/cfg_plugin.tmpl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
</mt:setvarblock>
4141

4242
<mt:setvarblock name="html_head" append="1">
43+
<script src="<mt:StaticWebPath>jquery/jquery.history.js" type="text/javascript"></script>
44+
<script src="<mt:StaticWebPath>js/melody/cfg_plugins.js" type="text/javascript"></script>
4345
<script type="text/javascript">
4446
/* <![CDATA[ */
4547
var last_shown;
@@ -61,7 +63,7 @@
6163
<mt:loop name="plugin_loop">
6264
<mt:if name="plugin_has_config"><mt:if name="can_config">
6365

64-
<div id="plugin-<$mt:var name="plugin_id" dirify="1"$>" class="plugin_form">
66+
<div id="plugin-<$mt:var name="plugin_id" dirify="1"$>-tab-content" class="plugin_form">
6567

6668
<h3 class="plugin-name"><$mt:var name="plugin_name" escape="html"$></h3>
6769

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,5 @@
1-
<script type="text/javascript">
2-
$(document).ready( function() {
3-
var url = document.URL;
4-
var a = url.match(/#(.+)$/);
5-
$('#content-nav ul li a').click( function() {
6-
var current = $(this).parent().parent().find('.active');
7-
var newactive = $(this).attr('title');
8-
current.removeClass('active');
9-
$('#' + current.find('a').attr('title')).hide();
10-
$(this).parent().addClass('active');
11-
$('#' + newactive).show();
12-
});
13-
<mt:if name="plugin">
14-
$('#content-nav ul li a[title="plugin-<$mt:var name="plugin"$>"]').trigger('click');
15-
<mt:else>
16-
if (a && $('#content-nav ul li a[title="'+a[1]+'"]')) {
17-
$('#content-nav ul li a[title="'+a[1]+'"]').trigger('click');
18-
} else {
19-
$('#content-nav ul li:first-child').find('a').trigger('click');
20-
}
21-
</mt:if>
22-
});
23-
</script>
241
<ul>
252
<mt:loop name="plugin_loop"><mt:if name="plugin_has_config">
26-
<li<mt:if name="plugin" eq="$plugin_id"> class="active"</mt:if>><a href="javascript:void(0)" title="plugin-<$mt:var name="plugin_id" dirify="1"$>"><b><$mt:var name="plugin_name"$></b></a></li>
3+
<li class="plugin-<$mt:var name="plugin_id" dirify="1"$>-tab<mt:if name="plugin" eq="$plugin_id"> active</mt:if>"><a href="javascript:void(0)" id="plugin-<$mt:var name="plugin_id" dirify="1"$>-tab" title="<__trans phrase="[_1] Preferences" params="<$mt:var name="plugin_name" encode_html="1"$>">"><b><$mt:var name="plugin_name"$></b></a></li>
274
</mt:if></mt:loop>
285
</ul>

0 commit comments

Comments
 (0)