logical_tabs 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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