logical_tabs 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Javascript code to support switching, memorizing, and preselecting
3
+ * tabs in a tabbed_panel structure for the plugin logical_tabs.
4
+ *
5
+ * NOTE: Includes a full copy of CookieJar by Lalit Patel, see below.
6
+ *
7
+ * Author : Evan Dorn
8
+ * Website: http://lrdesign.com/tools
9
+ * License: MIT License, see included LICENSE file.
10
+ * Version: 1.0
11
+ * Updated: April 22, 2010
12
+ *
13
+ */
14
+
15
+ // Set up the observer on the tabs, and
16
+ window.onload = function() {
17
+ $$('.tabbed_panel li.tab a.tab_link').invoke('observe', 'click', handle_tab_click);
18
+ $$('.tabbed_panel').each(function(item, index){ pre_select_tab(item)});
19
+ }
20
+
21
+ // Given a tabbed_panel div element, checks to see if there's a pre-stored
22
+ // tab association. If there is, select that tab.
23
+ function pre_select_tab(tabbed_panel) {
24
+ tab_memory = get_tab_memory();
25
+ tab_id = tab_memory[memory_key_from_tabbed_panel(tabbed_panel.identify())]
26
+ if(tab_id != null) {
27
+ select_tab(tab_id);
28
+ }
29
+ }
30
+
31
+ // Select a tab that's been clicked on and store that preference in a cookie.
32
+ function handle_tab_click(event) {
33
+ tab_id = Event.element(event).up().identify();
34
+ select_tab(tab_id);
35
+ store_tab_preference(tab_id);
36
+ }
37
+
38
+ // Handle the display changes necessary for selecting a new tab.
39
+ // iterate the tabs of the parent tabbed_panel and set them and their panes
40
+ // selected or not based on whether they match the clicked-on
41
+ // tab.
42
+ function select_tab(tab_id) {
43
+ $(get_tabbed_panel_id(tab_id)).select('li.tab').each(function(tab, index){
44
+ pane_id = tab.identify().replace(/_tab$/,"_pane");
45
+ pane = $(pane_id);
46
+ if(tab.identify() == tab_id) {
47
+ tab.removeClassName('tab_unselected');
48
+ tab.addClassName('tab_selected');
49
+ pane.removeClassName('pane_unselected');
50
+ pane.addClassName('pane_selected');
51
+ } else {
52
+ tab.removeClassName('tab_selected');
53
+ tab.addClassName('tab_unselected');
54
+ pane.removeClassName('pane_selected');
55
+ pane.addClassName('pane_unselected');
56
+ }
57
+ });
58
+ }
59
+
60
+ // extract the containing tabbed panel's ID from the tab's ID
61
+ function get_tabbed_panel_id(tab_id) {
62
+ return tab_id.substring(0, tab_id.indexOf("_tp_"));
63
+ }
64
+
65
+ // Generate the key associated with this page's path and this tabbed_panel,
66
+ // starting from the id of an individual tab.
67
+ function memory_key_from_tab(tab_id) {
68
+ return (location.pathname + "--" + get_tabbed_panel_id(tab_id)).replace(/^\//,'')
69
+ }
70
+
71
+ // Generate the key associated with this page's path and this tabbed_panel,
72
+ // starting from the id of the tabbed panel.
73
+ function memory_key_from_tabbed_panel(tabbed_panel_id) {
74
+ return (location.pathname + "--" + tabbed_panel_id).replace(/^\//,'')
75
+ }
76
+
77
+ // Store which tab was selected for this URL and tabbed panel combination
78
+ function store_tab_preference(tab_id) {
79
+ tab_memory = get_tab_memory();
80
+ if (tab_memory == null) {
81
+ tab_memory = new Object();
82
+ }
83
+ tab_memory[memory_key_from_tab(tab_id)] = tab_id;
84
+ tab_memory_cookie.put('tab_memory', tab_memory);
85
+ }
86
+
87
+ // Retrieve the array of memorized tabs from the cookie.
88
+ function get_tab_memory() {
89
+ return tab_memory_cookie.get('tab_memory');
90
+ }
91
+
92
+
93
+ /**
94
+ * Javascript code to store data as JSON strings in cookies.
95
+ * It uses prototype.js 1.5.1 (http://www.prototypejs.org)
96
+ *
97
+ * Author : Lalit Patel
98
+ * Website: http://www.lalit.org/lab/jsoncookies
99
+ * License: Apache Software License 2
100
+ * http://www.apache.org/licenses/LICENSE-2.0
101
+ * Version: 0.5
102
+ * Updated: Jan 26, 2009
103
+ *
104
+ * Chnage Log:
105
+ * v 0.5
106
+ * - Changed License from CC to Apache 2
107
+ * v 0.4
108
+ * - Removed a extra comma in options (was breaking in IE and Opera). (Thanks Jason)
109
+ * - Removed the parameter name from the initialize function
110
+ * - Changed the way expires date was being calculated. (Thanks David)
111
+ * v 0.3
112
+ * - Removed dependancy on json.js (http://www.json.org/json.js)
113
+ * - empty() function only deletes the cookies set by CookieJar
114
+ */
115
+
116
+ var CookieJar = Class.create();
117
+
118
+ CookieJar.prototype = {
119
+
120
+ /**
121
+ * Append before all cookie names to differntiate them.
122
+ */
123
+ appendString: "__CJ_",
124
+
125
+ /**
126
+ * Initializes the cookie jar with the options.
127
+ */
128
+ initialize: function(options) {
129
+ this.options = {
130
+ expires: 3600, // seconds (1 hr)
131
+ path: '', // cookie path
132
+ domain: '', // cookie domain
133
+ secure: '' // secure ?
134
+ };
135
+ Object.extend(this.options, options || {});
136
+
137
+ if (this.options.expires != '') {
138
+ var date = new Date();
139
+ date = new Date(date.getTime() + (this.options.expires * 1000));
140
+ this.options.expires = '; expires=' + date.toGMTString();
141
+ }
142
+ if (this.options.path != '') {
143
+ this.options.path = '; path=' + escape(this.options.path);
144
+ }
145
+ if (this.options.domain != '') {
146
+ this.options.domain = '; domain=' + escape(this.options.domain);
147
+ }
148
+ if (this.options.secure == 'secure') {
149
+ this.options.secure = '; secure';
150
+ } else {
151
+ this.options.secure = '';
152
+ }
153
+ },
154
+
155
+ /**
156
+ * Adds a name values pair.
157
+ */
158
+ put: function(name, value) {
159
+ name = this.appendString + name;
160
+ cookie = this.options;
161
+ var type = typeof value;
162
+ switch(type) {
163
+ case 'undefined':
164
+ case 'function' :
165
+ case 'unknown' : return false;
166
+ case 'boolean' :
167
+ case 'string' :
168
+ case 'number' : value = String(value.toString());
169
+ }
170
+ var cookie_str = name + "=" + escape(Object.toJSON(value));
171
+ try {
172
+ document.cookie = cookie_str + cookie.expires + cookie.path + cookie.domain + cookie.secure;
173
+ } catch (e) {
174
+ return false;
175
+ }
176
+ return true;
177
+ },
178
+
179
+ /**
180
+ * Removes a particular cookie (name value pair) form the Cookie Jar.
181
+ */
182
+ remove: function(name) {
183
+ name = this.appendString + name;
184
+ cookie = this.options;
185
+ try {
186
+ var date = new Date();
187
+ date.setTime(date.getTime() - (3600 * 1000));
188
+ var expires = '; expires=' + date.toGMTString();
189
+ document.cookie = name + "=" + expires + cookie.path + cookie.domain + cookie.secure;
190
+ } catch (e) {
191
+ return false;
192
+ }
193
+ return true;
194
+ },
195
+
196
+ /**
197
+ * Return a particular cookie by name;
198
+ */
199
+ get: function(name) {
200
+ name = this.appendString + name;
201
+ var cookies = document.cookie.match(name + '=(.*?)(;|$)');
202
+ if (cookies) {
203
+ return (unescape(cookies[1])).evalJSON();
204
+ } else {
205
+ return null;
206
+ }
207
+ },
208
+
209
+ /**
210
+ * Empties the Cookie Jar. Deletes all the cookies.
211
+ */
212
+ empty: function() {
213
+ keys = this.getKeys();
214
+ size = keys.size();
215
+ for(i=0; i<size; i++) {
216
+ this.remove(keys[i]);
217
+ }
218
+ },
219
+
220
+ /**
221
+ * Returns all cookies as a single object
222
+ */
223
+ getPack: function() {
224
+ pack = {};
225
+ keys = this.getKeys();
226
+
227
+ size = keys.size();
228
+ for(i=0; i<size; i++) {
229
+ pack[keys[i]] = this.get(keys[i]);
230
+ }
231
+ return pack;
232
+ },
233
+
234
+ /**
235
+ * Returns all keys.
236
+ */
237
+ getKeys: function() {
238
+ keys = $A();
239
+ keyRe= /[^=; ]+(?=\=)/g;
240
+ str = document.cookie;
241
+ CJRe = new RegExp("^" + this.appendString);
242
+ while((match = keyRe.exec(str)) != undefined) {
243
+ if (CJRe.test(match[0].strip())) {
244
+ keys.push(match[0].strip().gsub("^" + this.appendString,""));
245
+ }
246
+ }
247
+ return keys;
248
+ }
249
+ };
250
+
251
+ // set up tab memory cookie
252
+ tab_memory_cookie = new CookieJar({
253
+ expires: 3600 * 24 * 365, // one year
254
+ path: '/',
255
+ name: 'tab_memory'
256
+ })
@@ -0,0 +1,69 @@
1
+ .tabbed_panel {
2
+ padding: 0px;
3
+ clear: both;
4
+ width: 100%;
5
+ margin-top: 1em; }
6
+
7
+ .panes {
8
+ clear: both;
9
+ border-left: solid 1px #cccccc;
10
+ border-bottom: solid 1px #cccccc;
11
+ border-top: solid 1px #999999;
12
+ border-right: solid 1px #999999;
13
+ background-color: white;
14
+ padding: 10px;
15
+ margin: 0; }
16
+
17
+ @media screen, projection {
18
+ .pane_print_header {
19
+ display: none; }
20
+
21
+ .pane_selected {
22
+ display: block; }
23
+
24
+ .pane_unselected {
25
+ display: none; }
26
+
27
+ li.tab {
28
+ position: relative;
29
+ top: 1px;
30
+ float: left;
31
+ padding: 0;
32
+ margin: 0px 3px 0px 0px;
33
+ font: bold 1.2em sans-serif;
34
+ list-style: none;
35
+ border-left: solid 1px #cccccc;
36
+ border-bottom: solid 1px #999999;
37
+ border-top: solid 1px #999999;
38
+ border-right: solid 1px #999999;
39
+ -moz-user-select: none;
40
+ -khtml-user-select: none;
41
+ cursor: pointer;
42
+ font-size: 11px; }
43
+
44
+ li.tab_selected {
45
+ background-color: white;
46
+ border-bottom: 1px solid white; }
47
+
48
+ li.tab_unselected {
49
+ background-color: #aaaacc; }
50
+
51
+ li.tab_unselected:hover {
52
+ background-color: #aa7777; }
53
+
54
+ li.tab a {
55
+ display: block;
56
+ float: left;
57
+ padding: 4px 10px;
58
+ color: black;
59
+ text-decoration: none; }
60
+
61
+ li.tab a:hover {
62
+ color: #000099; } }
63
+
64
+ @media print, handheld {
65
+ .tabbed_panel ul.tabs, .tabbed_panel ul.tabs li {
66
+ display: none;
67
+ visibility: hidden; }
68
+ .tabbed_panel .pane_unselected {
69
+ display: block; } }
@@ -0,0 +1,69 @@
1
+ .tabbed_panel
2
+ :padding 0px
3
+ :clear both
4
+ :width 100%
5
+ :margin-top 1em
6
+
7
+ .panes
8
+ :clear both
9
+ :border-left solid 1px #CCC
10
+ :border-bottom solid 1px #CCC
11
+ :border-top solid 1px #999
12
+ :border-right solid 1px #999
13
+ :background-color white
14
+ :padding 10px
15
+ :margin 0
16
+
17
+ @media screen, projection
18
+ .pane_print_header
19
+ :display none
20
+ .pane_selected
21
+ :display block
22
+
23
+ .pane_unselected
24
+ :display none
25
+
26
+ li.tab
27
+ :position relative
28
+ :top 1px
29
+ :float left
30
+ :padding 0
31
+ :margin 0px 3px 0px 0px
32
+ :font bold 1.2em sans-serif
33
+ :list-style none
34
+ :border-left solid 1px #CCC
35
+ :border-bottom solid 1px #999
36
+ :border-top solid 1px #999
37
+ :border-right solid 1px #999
38
+ :-moz-user-select none
39
+ :-khtml-user-select none
40
+ :cursor pointer
41
+ :font-size 11px
42
+
43
+ li.tab_selected
44
+ :background-color white
45
+ :border-bottom 1px solid white
46
+
47
+ li.tab_unselected
48
+ :background-color #aac
49
+
50
+ li.tab_unselected:hover
51
+ :background-color #A77
52
+
53
+ li.tab a
54
+ :display block
55
+ :float left
56
+ :padding 4px 10px
57
+ :color black
58
+ :text-decoration none
59
+
60
+ li.tab a:hover
61
+ :color #009
62
+
63
+ @media print, handheld
64
+ .tabbed_panel
65
+ ul.tabs, ul.tabs li
66
+ :display none
67
+ :visibility hidden
68
+ .pane_unselected
69
+ :display block
@@ -0,0 +1,8 @@
1
+
2
+ module LogicalTabs
3
+ class Railtie < Rails::Railtie
4
+ require 'logical_tabs/helper'
5
+
6
+ ActionController::Base.helper(LogicalTabs::Helper)
7
+ end
8
+ end
@@ -0,0 +1,24 @@
1
+ module LogicalTabs
2
+ require 'logical_tabs/tabbed_panel'
3
+
4
+ module Helper
5
+ def tabbed_panel( options = {}, &block)
6
+ @panel_count = defined?(@panel_count) ? @panel_count + 1 : 0
7
+ options.merge!({:seq => @panel_count}) unless options[:base_id]
8
+ tabbed_panel = TabbedPanel.new(self, options)
9
+
10
+ if block_given?
11
+ yield(tabbed_panel)
12
+ output = tabbed_panel.render
13
+ output
14
+ end
15
+ return output
16
+ end
17
+
18
+ alias_method :create_tabbed_panel, :tabbed_panel
19
+
20
+ def wrap_in_div(id, &block)
21
+ content_tag(:div, capture(&block), :class => 'wrapper', :id => id)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,74 @@
1
+ module LogicalTabs
2
+ require 'logical_tabs/tabbed_panel'
3
+
4
+ # This contains the info for a single tab and pane
5
+ class TabPane
6
+ attr_accessor :tabbed_panel, :name, :base_id, :content, :tab_text, :pane_content
7
+
8
+ # tabbed_panel must be an instance of TabbedPanel
9
+ #
10
+ # Name is required, is used as the primary reference to this tab
11
+ #
12
+ # Other options:
13
+ # :base_id The string used as the beginning of the ID for CSS
14
+ # IDs for the tab and pane. :base_id => 'foo' will
15
+ # generate a tab with ID 'foo_tab' and a panel with ID
16
+ # 'foo_panel'. Defaults to name.downcase
17
+ #
18
+ # :tab_text The text to display in the tab. Defaults to name.
19
+ #
20
+ # :content The content for the panel itself, in HTML
21
+ #
22
+ def initialize(tabbed_panel, name, options = {})
23
+ @tabbed_panel = tabbed_panel
24
+ @name = name
25
+ @base_id = options[:base_id] || name.underscore.gsub(/\s+/,'_')
26
+ @tab_text = options[:tab_text] || name
27
+ @content = options[:content] || ''
28
+ end
29
+
30
+ # Generates output for the tab.
31
+ # Pass "true" to set this as the selected tab.
32
+ def render_tab(selected = false)
33
+ v.content_tag(:li,
34
+ tab_link,
35
+ :id => (composite_id + "_tab").html_safe,
36
+ :class => ("tab " + (selected ? "tab_selected" : "tab_unselected")).html_safe
37
+ ).html_safe
38
+ end
39
+
40
+ def render_header(selected = false)
41
+ v.content_tag(:h3,
42
+ @tab_text,
43
+ :class => ("pane_print_header ").html_safe
44
+ ).html_safe
45
+ end
46
+
47
+
48
+ def tab_link
49
+ v.content_tag(:a, @tab_text, :href => '#', :class => 'tab_link' ).html_safe
50
+ end
51
+
52
+ # generates an ID for this tab_pane that includes the base_id of the
53
+ # containing tabbed_panel and the base_id of this tab_pane.
54
+ def composite_id
55
+ (@tabbed_panel.base_id + "_tp_" + @base_id).html_safe
56
+ end
57
+
58
+ # Generates HTML output for the panel
59
+ # Pass "true" to set this as the selected/visible panel
60
+ def render_pane(selected = false)
61
+ v.content_tag(:div,
62
+ render_header + @content,
63
+ :id => (composite_id + "_pane").html_safe,
64
+ :class => "pane " + (selected ? "pane_selected" : "pane_unselected")
65
+ ).html_safe
66
+ end
67
+
68
+
69
+ private
70
+ # Shortcut to the view
71
+ def v; @tabbed_panel.v; end
72
+
73
+ end
74
+ end