muck-contents 0.2.25 → 0.2.26

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.
Files changed (28) hide show
  1. data/README.rdoc +10 -0
  2. data/VERSION +1 -1
  3. data/app/controllers/muck/contents_controller.rb +2 -1
  4. data/lib/active_record/acts/muck_content.rb +6 -0
  5. data/muck-contents.gemspec +21 -2
  6. data/test/rails_root/public/images/icon_no.gif +0 -0
  7. data/test/rails_root/public/images/icon_success.gif +0 -0
  8. data/test/rails_root/public/javascripts/jquery/fg.menu.js +517 -0
  9. data/test/rails_root/public/javascripts/muck_admin.js +13 -0
  10. data/test/rails_root/public/stylesheets/admin.css +22 -0
  11. data/test/rails_root/public/stylesheets/fgmenu/fg.menu.css +114 -0
  12. data/test/rails_root/public/stylesheets/flick/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  13. data/test/rails_root/public/stylesheets/flick/images/ui-bg_flat_0_eeeeee_40x100.png +0 -0
  14. data/test/rails_root/public/stylesheets/flick/images/ui-bg_flat_55_ffffff_40x100.png +0 -0
  15. data/test/rails_root/public/stylesheets/flick/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  16. data/test/rails_root/public/stylesheets/flick/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  17. data/test/rails_root/public/stylesheets/flick/images/ui-bg_highlight-soft_100_f6f6f6_1x100.png +0 -0
  18. data/test/rails_root/public/stylesheets/flick/images/ui-bg_highlight-soft_25_0073ea_1x100.png +0 -0
  19. data/test/rails_root/public/stylesheets/flick/images/ui-bg_highlight-soft_50_dddddd_1x100.png +0 -0
  20. data/test/rails_root/public/stylesheets/flick/images/ui-icons_0073ea_256x240.png +0 -0
  21. data/test/rails_root/public/stylesheets/flick/images/ui-icons_454545_256x240.png +0 -0
  22. data/test/rails_root/public/stylesheets/flick/images/ui-icons_666666_256x240.png +0 -0
  23. data/test/rails_root/public/stylesheets/flick/images/ui-icons_ff0084_256x240.png +0 -0
  24. data/test/rails_root/public/stylesheets/flick/images/ui-icons_ffffff_256x240.png +0 -0
  25. data/test/rails_root/public/stylesheets/flick/jquery-ui-1.8.1.custom.css +486 -0
  26. data/test/rails_root/test/functional/contents_controller_test.rb +59 -0
  27. data/test/rails_root/test/unit/content_test.rb +8 -0
  28. metadata +23 -4
data/README.rdoc CHANGED
@@ -227,6 +227,16 @@ NOTE: you must define icon, thumb, small, medium and large as styles. They can
227
227
 
228
228
  end
229
229
 
230
+ == Tips
231
+ If friendly_id starts producing errors like this then you need to redo your slugs:
232
+ ActiveRecord::StatementInvalid (Mysql::Error: Duplicate entry 'my-content-page-/-2' for key 2: UPDATE `slugs` SET `scope` = '/', `sequence` = 2 WHERE `id` = 189):
233
+
234
+ Run this and you should be good to go:
235
+ rake friendly_id:redo_slugs MODEL=Content
236
+
237
+ Cleanup old slugs with:
238
+ rake friendly_id:remove_old_slugs MODEL=Content
239
+
230
240
  == Testing
231
241
  This gem uses a full rails application in the test directory for testing and development. By default there isn't a global_config.yml setup.
232
242
  Use global_config.sample.yml to set one up.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.25
1
+ 0.2.26
@@ -106,6 +106,7 @@ class Muck::ContentsController < ApplicationController
106
106
  #
107
107
  def edit
108
108
  @page_title = @content.locale_title(I18n.locale)
109
+ @content.setup_uri_path # be sure to recover uri_path or scope will get messed up when the content is saved.
109
110
  respond_to do |format|
110
111
  format.html { render :template => @edit_template || 'contents/edit'}
111
112
  format.pjs { render :template => @edit_template || 'contents/edit', :layout => 'popup'}
@@ -214,7 +215,7 @@ class Muck::ContentsController < ApplicationController
214
215
  # Pass the numeric id to this method to ensure that the operations update and delete occur on the correct object
215
216
  def get_secure_content
216
217
  @content = Content.find(params[:id])
217
- unless @content.can_edit?(current_user)
218
+ if !@content.can_edit?(current_user)
218
219
  respond_to do |format|
219
220
  format.html do
220
221
  flash[:notice] = I18n.t('muck.contents.cant_delete_content')
@@ -141,6 +141,12 @@ module ActiveRecord
141
141
  File.join(self.scope, self.to_param)
142
142
  end
143
143
 
144
+ # uri_path is used to calculate scope on save and therefore must be recovered
145
+ # before a save is executed. Use this method to set it from the uri method.
146
+ def setup_uri_path
147
+ self.uri_path = self.class.scope_from_uri(self.uri)
148
+ end
149
+
144
150
  # get scope from the slug
145
151
  def scope
146
152
  self.slug.scope
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{muck-contents}
8
- s.version = "0.2.25"
8
+ s.version = "0.2.26"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Justin Ball", "Joel Duffin"]
12
- s.date = %q{2010-05-27}
12
+ s.date = %q{2010-07-14}
13
13
  s.email = %q{justin@tatemae.com}
14
14
  s.extra_rdoc_files = [
15
15
  "README.rdoc"
@@ -1626,6 +1626,8 @@ Gem::Specification.new do |s|
1626
1626
  "test/rails_root/public/images/file_icons/text.gif",
1627
1627
  "test/rails_root/public/images/file_icons/text.png",
1628
1628
  "test/rails_root/public/images/file_icons/word.gif",
1629
+ "test/rails_root/public/images/icon_no.gif",
1630
+ "test/rails_root/public/images/icon_success.gif",
1629
1631
  "test/rails_root/public/images/icons/accept.png",
1630
1632
  "test/rails_root/public/images/icons/add.png",
1631
1633
  "test/rails_root/public/images/icons/blue_guy.png",
@@ -2011,6 +2013,7 @@ Gem::Specification.new do |s|
2011
2013
  "test/rails_root/public/javascripts/effects.js",
2012
2014
  "test/rails_root/public/javascripts/fancyzoom.min.js",
2013
2015
  "test/rails_root/public/javascripts/jquery/colorpicker.js",
2016
+ "test/rails_root/public/javascripts/jquery/fg.menu.js",
2014
2017
  "test/rails_root/public/javascripts/jquery/jquery-ui.js",
2015
2018
  "test/rails_root/public/javascripts/jquery/jquery.autocomplete.js.readme",
2016
2019
  "test/rails_root/public/javascripts/jquery/jquery.autocomplete.min.js",
@@ -2033,6 +2036,7 @@ Gem::Specification.new do |s|
2033
2036
  "test/rails_root/public/javascripts/muck-users.js",
2034
2037
  "test/rails_root/public/javascripts/muck.js",
2035
2038
  "test/rails_root/public/javascripts/muck_activities.js",
2039
+ "test/rails_root/public/javascripts/muck_admin.js",
2036
2040
  "test/rails_root/public/javascripts/muck_time/en.js",
2037
2041
  "test/rails_root/public/javascripts/prototype.js",
2038
2042
  "test/rails_root/public/javascripts/scriptaculous.js",
@@ -3429,6 +3433,21 @@ Gem::Specification.new do |s|
3429
3433
  "test/rails_root/public/stylesheets/blueprint/src/print.css",
3430
3434
  "test/rails_root/public/stylesheets/blueprint/src/reset.css",
3431
3435
  "test/rails_root/public/stylesheets/blueprint/src/typography.css",
3436
+ "test/rails_root/public/stylesheets/fgmenu/fg.menu.css",
3437
+ "test/rails_root/public/stylesheets/flick/images/ui-bg_flat_0_aaaaaa_40x100.png",
3438
+ "test/rails_root/public/stylesheets/flick/images/ui-bg_flat_0_eeeeee_40x100.png",
3439
+ "test/rails_root/public/stylesheets/flick/images/ui-bg_flat_55_ffffff_40x100.png",
3440
+ "test/rails_root/public/stylesheets/flick/images/ui-bg_flat_75_ffffff_40x100.png",
3441
+ "test/rails_root/public/stylesheets/flick/images/ui-bg_glass_65_ffffff_1x400.png",
3442
+ "test/rails_root/public/stylesheets/flick/images/ui-bg_highlight-soft_100_f6f6f6_1x100.png",
3443
+ "test/rails_root/public/stylesheets/flick/images/ui-bg_highlight-soft_25_0073ea_1x100.png",
3444
+ "test/rails_root/public/stylesheets/flick/images/ui-bg_highlight-soft_50_dddddd_1x100.png",
3445
+ "test/rails_root/public/stylesheets/flick/images/ui-icons_0073ea_256x240.png",
3446
+ "test/rails_root/public/stylesheets/flick/images/ui-icons_454545_256x240.png",
3447
+ "test/rails_root/public/stylesheets/flick/images/ui-icons_666666_256x240.png",
3448
+ "test/rails_root/public/stylesheets/flick/images/ui-icons_ff0084_256x240.png",
3449
+ "test/rails_root/public/stylesheets/flick/images/ui-icons_ffffff_256x240.png",
3450
+ "test/rails_root/public/stylesheets/flick/jquery-ui-1.8.1.custom.css",
3432
3451
  "test/rails_root/public/stylesheets/jquery/cupertino/images/ui-bg_diagonals-small_0_aaaaaa_40x40.png",
3433
3452
  "test/rails_root/public/stylesheets/jquery/cupertino/images/ui-bg_diagonals-thick_15_444444_40x40.png",
3434
3453
  "test/rails_root/public/stylesheets/jquery/cupertino/images/ui-bg_glass_100_f0f0f0_1x400.png",
@@ -0,0 +1,517 @@
1
+ /*--------------------------------------------------------------------
2
+ Scripts for creating and manipulating custom menus based on standard <ul> markup
3
+ Version: 3.0, 03.31.2009
4
+
5
+ By: Maggie Costello Wachs (maggie@filamentgroup.com) and Scott Jehl (scott@filamentgroup.com)
6
+ http://www.filamentgroup.com
7
+ * reference articles: http://www.filamentgroup.com/lab/jquery_ipod_style_drilldown_menu/
8
+
9
+ Copyright (c) 2009 Filament Group
10
+ Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
11
+ --------------------------------------------------------------------*/
12
+
13
+
14
+ var allUIMenus = [];
15
+
16
+ $.fn.menu = function(options){
17
+ var caller = this;
18
+ var options = options;
19
+ var m = new Menu(caller, options);
20
+ allUIMenus.push(m);
21
+
22
+ $(this)
23
+ .mousedown(function(){
24
+ if (!m.menuOpen) { m.showLoading(); };
25
+ })
26
+ .click(function(){
27
+ if (m.menuOpen == false) { m.showMenu(); }
28
+ else { m.kill(); };
29
+ return false;
30
+ });
31
+ };
32
+
33
+ function Menu(caller, options){
34
+ var menu = this;
35
+ var caller = $(caller);
36
+ var container = $('<div class="fg-menu-container ui-widget ui-widget-content ui-corner-all">'+options.content+'</div>');
37
+
38
+ this.menuOpen = false;
39
+ this.menuExists = false;
40
+
41
+ var options = jQuery.extend({
42
+ content: null,
43
+ width: 180, // width of menu container, must be set or passed in to calculate widths of child menus
44
+ maxHeight: 180, // max height of menu (if a drilldown: height does not include breadcrumb)
45
+ positionOpts: {
46
+ posX: 'left',
47
+ posY: 'bottom',
48
+ offsetX: 0,
49
+ offsetY: 0,
50
+ directionH: 'right',
51
+ directionV: 'down',
52
+ detectH: true, // do horizontal collision detection
53
+ detectV: true, // do vertical collision detection
54
+ linkToFront: false
55
+ },
56
+ showSpeed: 200, // show/hide speed in milliseconds
57
+ callerOnState: 'ui-state-active', // class to change the appearance of the link/button when the menu is showing
58
+ loadingState: 'ui-state-loading', // class added to the link/button while the menu is created
59
+ linkHover: 'ui-state-hover', // class for menu option hover state
60
+ linkHoverSecondary: 'li-hover', // alternate class, may be used for multi-level menus
61
+ // ----- multi-level menu defaults -----
62
+ crossSpeed: 200, // cross-fade speed for multi-level menus
63
+ crumbDefaultText: 'Choose an option:',
64
+ backLink: true, // in the ipod-style menu: instead of breadcrumbs, show only a 'back' link
65
+ backLinkText: 'Back',
66
+ flyOut: false, // multi-level menus are ipod-style by default; this parameter overrides to make a flyout instead
67
+ flyOutOnState: 'ui-state-default',
68
+ nextMenuLink: 'ui-icon-triangle-1-e', // class to style the link (specifically, a span within the link) used in the multi-level menu to show the next level
69
+ topLinkText: 'All',
70
+ nextCrumbLink: 'ui-icon-carat-1-e'
71
+ }, options);
72
+
73
+ var killAllMenus = function(){
74
+ $.each(allUIMenus, function(i){
75
+ if (allUIMenus[i].menuOpen) { allUIMenus[i].kill(); };
76
+ });
77
+ };
78
+
79
+ this.kill = function(){
80
+ caller
81
+ .removeClass(options.loadingState)
82
+ .removeClass('fg-menu-open')
83
+ .removeClass(options.callerOnState);
84
+ container.find('li').removeClass(options.linkHoverSecondary).find('a').removeClass(options.linkHover);
85
+ if (options.flyOutOnState) { container.find('li a').removeClass(options.flyOutOnState); };
86
+ if (options.callerOnState) { caller.removeClass(options.callerOnState); };
87
+ if (container.is('.fg-menu-ipod')) { menu.resetDrilldownMenu(); };
88
+ if (container.is('.fg-menu-flyout')) { menu.resetFlyoutMenu(); };
89
+ container.parent().hide();
90
+ menu.menuOpen = false;
91
+ $(document).unbind('click', killAllMenus);
92
+ $(document).unbind('keydown');
93
+ };
94
+
95
+ this.showLoading = function(){
96
+ caller.addClass(options.loadingState);
97
+ };
98
+
99
+ this.showMenu = function(){
100
+ killAllMenus();
101
+ if (!menu.menuExists) { menu.create() };
102
+ caller
103
+ .addClass('fg-menu-open')
104
+ .addClass(options.callerOnState);
105
+ container.parent().show().click(function(){ menu.kill(); return false; });
106
+ container.hide().slideDown(options.showSpeed).find('.fg-menu:eq(0)');
107
+ menu.menuOpen = true;
108
+ caller.removeClass(options.loadingState);
109
+ $(document).click(killAllMenus);
110
+
111
+ // assign key events
112
+ $(document).keydown(function(event){
113
+ var e;
114
+ if (event.which !="") { e = event.which; }
115
+ else if (event.charCode != "") { e = event.charCode; }
116
+ else if (event.keyCode != "") { e = event.keyCode; }
117
+
118
+ var menuType = ($(event.target).parents('div').is('.fg-menu-flyout')) ? 'flyout' : 'ipod' ;
119
+
120
+ switch(e) {
121
+ case 37: // left arrow
122
+ if (menuType == 'flyout') {
123
+ $(event.target).trigger('mouseout');
124
+ if ($('.'+options.flyOutOnState).size() > 0) { $('.'+options.flyOutOnState).trigger('mouseover'); };
125
+ };
126
+
127
+ if (menuType == 'ipod') {
128
+ $(event.target).trigger('mouseout');
129
+ if ($('.fg-menu-footer').find('a').size() > 0) { $('.fg-menu-footer').find('a').trigger('click'); };
130
+ if ($('.fg-menu-header').find('a').size() > 0) { $('.fg-menu-current-crumb').prev().find('a').trigger('click'); };
131
+ if ($('.fg-menu-current').prev().is('.fg-menu-indicator')) {
132
+ $('.fg-menu-current').prev().trigger('mouseover');
133
+ };
134
+ };
135
+ return false;
136
+ break;
137
+
138
+ case 38: // up arrow
139
+ if ($(event.target).is('.' + options.linkHover)) {
140
+ var prevLink = $(event.target).parent().prev().find('a:eq(0)');
141
+ if (prevLink.size() > 0) {
142
+ $(event.target).trigger('mouseout');
143
+ prevLink.trigger('mouseover');
144
+ };
145
+ }
146
+ else { container.find('a:eq(0)').trigger('mouseover'); }
147
+ return false;
148
+ break;
149
+
150
+ case 39: // right arrow
151
+ if ($(event.target).is('.fg-menu-indicator')) {
152
+ if (menuType == 'flyout') {
153
+ $(event.target).next().find('a:eq(0)').trigger('mouseover');
154
+ }
155
+ else if (menuType == 'ipod') {
156
+ $(event.target).trigger('click');
157
+ setTimeout(function(){
158
+ $(event.target).next().find('a:eq(0)').trigger('mouseover');
159
+ }, options.crossSpeed);
160
+ };
161
+ };
162
+ return false;
163
+ break;
164
+
165
+ case 40: // down arrow
166
+ if ($(event.target).is('.' + options.linkHover)) {
167
+ var nextLink = $(event.target).parent().next().find('a:eq(0)');
168
+ if (nextLink.size() > 0) {
169
+ $(event.target).trigger('mouseout');
170
+ nextLink.trigger('mouseover');
171
+ };
172
+ }
173
+ else { container.find('a:eq(0)').trigger('mouseover'); }
174
+ return false;
175
+ break;
176
+
177
+ case 27: // escape
178
+ killAllMenus();
179
+ break;
180
+
181
+ case 13: // enter
182
+ if ($(event.target).is('.fg-menu-indicator') && menuType == 'ipod') {
183
+ $(event.target).trigger('click');
184
+ setTimeout(function(){
185
+ $(event.target).next().find('a:eq(0)').trigger('mouseover');
186
+ }, options.crossSpeed);
187
+ };
188
+ break;
189
+ };
190
+ });
191
+ };
192
+
193
+ this.create = function(){
194
+ container.css({ width: options.width }).appendTo('body').find('ul:first').not('.fg-menu-breadcrumb').addClass('fg-menu');
195
+ container.find('ul, li a').addClass('ui-corner-all');
196
+
197
+ // aria roles & attributes
198
+ container.find('ul').attr('role', 'menu').eq(0).attr('aria-activedescendant','active-menuitem').attr('aria-labelledby', caller.attr('id'));
199
+ container.find('li').attr('role', 'menuitem');
200
+ container.find('li:has(ul)').attr('aria-haspopup', 'true').find('ul').attr('aria-expanded', 'false');
201
+ container.find('a').attr('tabindex', '-1');
202
+
203
+ // when there are multiple levels of hierarchy, create flyout or drilldown menu
204
+ if (container.find('ul').size() > 1) {
205
+ if (options.flyOut) { menu.flyout(container, options); }
206
+ else { menu.drilldown(container, options); }
207
+ }
208
+ else {
209
+ container.find('a').click(function(){
210
+ menu.chooseItem(this);
211
+ return false;
212
+ });
213
+ };
214
+
215
+ if (options.linkHover) {
216
+ var allLinks = container.find('.fg-menu li a');
217
+ allLinks.hover(
218
+ function(){
219
+ var menuitem = $(this);
220
+ $('.'+options.linkHover).removeClass(options.linkHover).blur().parent().removeAttr('id');
221
+ $(this).addClass(options.linkHover).focus().parent().attr('id','active-menuitem');
222
+ },
223
+ function(){
224
+ $(this).removeClass(options.linkHover).blur().parent().removeAttr('id');
225
+ }
226
+ );
227
+ };
228
+
229
+ if (options.linkHoverSecondary) {
230
+ container.find('.fg-menu li').hover(
231
+ function(){
232
+ $(this).siblings('li').removeClass(options.linkHoverSecondary);
233
+ if (options.flyOutOnState) { $(this).siblings('li').find('a').removeClass(options.flyOutOnState); }
234
+ $(this).addClass(options.linkHoverSecondary);
235
+ },
236
+ function(){ $(this).removeClass(options.linkHoverSecondary); }
237
+ );
238
+ };
239
+
240
+ menu.setPosition(container, caller, options);
241
+ menu.menuExists = true;
242
+ };
243
+
244
+ this.chooseItem = function(item){
245
+ // edit this for your own custom function/callback:
246
+ if ($(item).attr('alt') == "pop")
247
+ {
248
+ var d = jQuery('<div class="dialog"><div style="width:32px; margin:20px auto 0px auto"><img src="/images/loading-spinner.gif"/></div></div>').appendTo("body");
249
+ d.dialog({ modal: true, autoOpen: true, width: 'auto', title: $(item).attr('title') });
250
+ d.load($(item).attr('href'), '', function(){
251
+ d.dialog("open");
252
+ apply_ajax_forms();
253
+ });
254
+ }
255
+ else
256
+ {
257
+ location.href = $(item).attr('href');
258
+ }
259
+ menu.kill();
260
+ };
261
+ };
262
+
263
+ Menu.prototype.flyout = function(container, options) {
264
+ var menu = this;
265
+
266
+ this.resetFlyoutMenu = function(){
267
+ var allLists = container.find('ul ul');
268
+ allLists.removeClass('ui-widget-content').hide();
269
+ };
270
+
271
+ container.addClass('fg-menu-flyout').find('li:has(ul)').each(function(){
272
+ var linkWidth = container.width();
273
+ var showTimer, hideTimer;
274
+ var allSubLists = $(this).find('ul');
275
+
276
+ allSubLists.css({ left: linkWidth, width: linkWidth }).hide();
277
+
278
+ $(this).find('a:eq(0)').addClass('fg-menu-indicator').html('<span>' + $(this).find('a:eq(0)').text() + '</span><span class="ui-icon '+options.nextMenuLink+'"></span>').hover(
279
+ function(){
280
+ clearTimeout(hideTimer);
281
+ var subList = $(this).next();
282
+ if (!fitVertical(subList, $(this).offset().top)) { subList.css({ top: 'auto', bottom: 0 }); };
283
+ if (!fitHorizontal(subList, $(this).offset().left + 100)) { subList.css({ left: 'auto', right: linkWidth, 'z-index': 999 }); };
284
+ showTimer = setTimeout(function(){
285
+ subList.addClass('ui-widget-content').show(options.showSpeed).attr('aria-expanded', 'true');
286
+ }, 300);
287
+ },
288
+ function(){
289
+ clearTimeout(showTimer);
290
+ var subList = $(this).next();
291
+ hideTimer = setTimeout(function(){
292
+ subList.removeClass('ui-widget-content').hide(options.showSpeed).attr('aria-expanded', 'false');
293
+ }, 400);
294
+ }
295
+ );
296
+
297
+ $(this).find('ul a').hover(
298
+ function(){
299
+ clearTimeout(hideTimer);
300
+ if ($(this).parents('ul').prev().is('a.fg-menu-indicator')) {
301
+ $(this).parents('ul').prev().addClass(options.flyOutOnState);
302
+ }
303
+ },
304
+ function(){
305
+ hideTimer = setTimeout(function(){
306
+ allSubLists.hide(options.showSpeed);
307
+ container.find(options.flyOutOnState).removeClass(options.flyOutOnState);
308
+ }, 500);
309
+ }
310
+ );
311
+ });
312
+
313
+ container.find('a').click(function(){
314
+ menu.chooseItem(this);
315
+ alert("FOO");
316
+ return false;
317
+ });
318
+ };
319
+
320
+
321
+ /* Menu.prototype.setPosition parameters (defaults noted with *):
322
+ referrer = the link (or other element) used to show the overlaid object
323
+ settings = can override the defaults:
324
+ - posX/Y: where the top left corner of the object should be positioned in relation to its referrer.
325
+ X: left*, center, right
326
+ Y: top, center, bottom*
327
+ - offsetX/Y: the number of pixels to be offset from the x or y position. Can be a positive or negative number.
328
+ - directionH/V: where the entire menu should appear in relation to its referrer.
329
+ Horizontal: left*, right
330
+ Vertical: up, down*
331
+ - detectH/V: detect the viewport horizontally / vertically
332
+ - linkToFront: copy the menu link and place it on top of the menu (visual effect to make it look like it overlaps the object) */
333
+
334
+ Menu.prototype.setPosition = function(widget, caller, options) {
335
+ var el = widget;
336
+ var referrer = caller;
337
+ var dims = {
338
+ refX: referrer.offset().left,
339
+ refY: referrer.offset().top,
340
+ refW: referrer.getTotalWidth(),
341
+ refH: referrer.getTotalHeight()
342
+ };
343
+ var options = options;
344
+ var xVal, yVal;
345
+
346
+ var helper = $('<div class="positionHelper"></div>');
347
+ helper.css({ position: 'absolute', left: dims.refX, top: dims.refY, width: dims.refW, height: dims.refH });
348
+ el.wrap(helper);
349
+
350
+ // get X pos
351
+ switch(options.positionOpts.posX) {
352
+ case 'left': xVal = 0;
353
+ break;
354
+ case 'center': xVal = dims.refW / 2;
355
+ break;
356
+ case 'right': xVal = dims.refW;
357
+ break;
358
+ };
359
+
360
+ // get Y pos
361
+ switch(options.positionOpts.posY) {
362
+ case 'top': yVal = 0;
363
+ break;
364
+ case 'center': yVal = dims.refH / 2;
365
+ break;
366
+ case 'bottom': yVal = dims.refH;
367
+ break;
368
+ };
369
+
370
+ // add the offsets (zero by default)
371
+ xVal += options.positionOpts.offsetX;
372
+ yVal += options.positionOpts.offsetY;
373
+
374
+ // position the object vertically
375
+ if (options.positionOpts.directionV == 'up') {
376
+ el.css({ top: 'auto', bottom: yVal });
377
+ if (options.positionOpts.detectV && !fitVertical(el)) {
378
+ el.css({ bottom: 'auto', top: yVal });
379
+ }
380
+ }
381
+ else {
382
+ el.css({ bottom: 'auto', top: yVal });
383
+ if (options.positionOpts.detectV && !fitVertical(el)) {
384
+ el.css({ top: 'auto', bottom: yVal });
385
+ }
386
+ };
387
+
388
+ // and horizontally
389
+ if (options.positionOpts.directionH == 'left') {
390
+ el.css({ left: 'auto', right: xVal });
391
+ if (options.positionOpts.detectH && !fitHorizontal(el)) {
392
+ el.css({ right: 'auto', left: xVal });
393
+ }
394
+ }
395
+ else {
396
+ el.css({ right: 'auto', left: xVal });
397
+ if (options.positionOpts.detectH && !fitHorizontal(el)) {
398
+ el.css({ left: 'auto', right: xVal });
399
+ }
400
+ };
401
+
402
+ // if specified, clone the referring element and position it so that it appears on top of the menu
403
+ if (options.positionOpts.linkToFront) {
404
+ referrer.clone().addClass('linkClone').css({
405
+ position: 'absolute',
406
+ top: 0,
407
+ right: 'auto',
408
+ bottom: 'auto',
409
+ left: 0,
410
+ width: referrer.width(),
411
+ height: referrer.height()
412
+ }).insertAfter(el);
413
+ };
414
+ };
415
+
416
+
417
+ /* Utilities to sort and find viewport dimensions */
418
+
419
+ function sortBigToSmall(a, b) { return b - a; };
420
+
421
+ jQuery.fn.getTotalWidth = function(){
422
+ return $(this).width() + parseInt($(this).css('paddingRight')) + parseInt($(this).css('paddingLeft')) + parseInt($(this).css('borderRightWidth')) + parseInt($(this).css('borderLeftWidth'));
423
+ };
424
+
425
+ jQuery.fn.getTotalHeight = function(){
426
+ return $(this).height() + parseInt($(this).css('paddingTop')) + parseInt($(this).css('paddingBottom')) + parseInt($(this).css('borderTopWidth')) + parseInt($(this).css('borderBottomWidth'));
427
+ };
428
+
429
+ function getScrollTop(){
430
+ return self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
431
+ };
432
+
433
+ function getScrollLeft(){
434
+ return self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;
435
+ };
436
+
437
+ function getWindowHeight(){
438
+ var de = document.documentElement;
439
+ return self.innerHeight || (de && de.clientHeight) || document.body.clientHeight;
440
+ };
441
+
442
+ function getWindowWidth(){
443
+ var de = document.documentElement;
444
+ return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
445
+ };
446
+
447
+ /* Utilities to test whether an element will fit in the viewport
448
+ Parameters:
449
+ el = element to position, required
450
+ leftOffset / topOffset = optional parameter if the offset cannot be calculated (i.e., if the object is in the DOM but is set to display: 'none') */
451
+
452
+ function fitHorizontal(el, leftOffset){
453
+ var leftVal = parseInt(leftOffset) || $(el).offset().left;
454
+ return (leftVal + $(el).width() <= getWindowWidth() + getScrollLeft() && leftVal - getScrollLeft() >= 0);
455
+ };
456
+
457
+ function fitVertical(el, topOffset){
458
+ var topVal = parseInt(topOffset) || $(el).offset().top;
459
+ return (topVal + $(el).height() <= getWindowHeight() + getScrollTop() && topVal - getScrollTop() >= 0);
460
+ };
461
+
462
+ /*--------------------------------------------------------------------
463
+ * javascript method: "pxToEm"
464
+ * by:
465
+ Scott Jehl (scott@filamentgroup.com)
466
+ Maggie Wachs (maggie@filamentgroup.com)
467
+ http://www.filamentgroup.com
468
+ *
469
+ * Copyright (c) 2008 Filament Group
470
+ * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
471
+ *
472
+ * Description: Extends the native Number and String objects with pxToEm method. pxToEm converts a pixel value to ems depending on inherited font size.
473
+ * Article: http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/
474
+ * Demo: http://www.filamentgroup.com/examples/pxToEm/
475
+ *
476
+ * Options:
477
+ scope: string or jQuery selector for font-size scoping
478
+ reverse: Boolean, true reverses the conversion to em-px
479
+ * Dependencies: jQuery library
480
+ * Usage Example: myPixelValue.pxToEm(); or myPixelValue.pxToEm({'scope':'#navigation', reverse: true});
481
+ *
482
+ * Version: 2.0, 08.01.2008
483
+ * Changelog:
484
+ * 08.02.2007 initial Version 1.0
485
+ * 08.01.2008 - fixed font-size calculation for IE
486
+ --------------------------------------------------------------------*/
487
+
488
+ Number.prototype.pxToEm = String.prototype.pxToEm = function(settings){
489
+ //set defaults
490
+ settings = jQuery.extend({
491
+ scope: 'body',
492
+ reverse: false
493
+ }, settings);
494
+
495
+ var pxVal = (this == '') ? 0 : parseFloat(this);
496
+ var scopeVal;
497
+ var getWindowWidth = function(){
498
+ var de = document.documentElement;
499
+ return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
500
+ };
501
+
502
+ /* When a percentage-based font-size is set on the body, IE returns that percent of the window width as the font-size.
503
+ For example, if the body font-size is 62.5% and the window width is 1000px, IE will return 625px as the font-size.
504
+ When this happens, we calculate the correct body font-size (%) and multiply it by 16 (the standard browser font size)
505
+ to get an accurate em value. */
506
+
507
+ if (settings.scope == 'body' && $.browser.msie && (parseFloat($('body').css('font-size')) / getWindowWidth()).toFixed(1) > 0.0) {
508
+ var calcFontSize = function(){
509
+ return (parseFloat($('body').css('font-size'))/getWindowWidth()).toFixed(3) * 16;
510
+ };
511
+ scopeVal = calcFontSize();
512
+ }
513
+ else { scopeVal = parseFloat(jQuery(settings.scope).css("font-size")); };
514
+
515
+ var result = (settings.reverse == true) ? (pxVal * scopeVal).toFixed(2) + 'px' : (pxVal / scopeVal).toFixed(2) + 'em';
516
+ return result;
517
+ };
@@ -0,0 +1,13 @@
1
+ jQuery(function(){
2
+ // BUTTONS
3
+ jQuery('.fg-button').hover(
4
+ function(){ jQuery(this).removeClass('ui-state-default').addClass('ui-state-focus'); },
5
+ function(){ jQuery(this).removeClass('ui-state-focus').addClass('ui-state-default'); }
6
+ );
7
+ jQuery('.flat').each(function() {
8
+ jQuery(this).menu({
9
+ content: jQuery(this).next().html(), // grab content from this page
10
+ showSpeed: 200
11
+ });
12
+ });
13
+ });
@@ -31,6 +31,8 @@ ul.admin-list li a{font-size:1.2em;}
31
31
  #admin-messages{display:none;}
32
32
  /* ui elements */
33
33
  #ui-datepicker-div{z-index:2005;}
34
+ /* jquery-ui theme overrides */
35
+ .ui-widget {font-size:.8em;}
34
36
  /* tables */
35
37
  .adminTable{margin:5px 0 0 0;padding:0 0 40px 0px;width:980px;}
36
38
  .adminTable a{color:#000;text-decoration:none;font-weight:bold;}
@@ -38,3 +40,23 @@ ul.admin-list li a{font-size:1.2em;}
38
40
  .adminTable tr{background-color:#fff;}
39
41
  .adminTable table{border:2px solid #c4ad63;}
40
42
  .adminTable tr td{font-size:1.1em;font-weight:bold;padding:5px;border-bottom:1px solid #eee;}
43
+ /* menu styles*/
44
+ .hidden { position:absolute; top:0; left:-9999px; width:1px; height:1px; overflow:hidden; }
45
+ .fg-button { font-size:11px; clear:left; padding: .4em 1em; text-decoration:none !important; cursor:pointer; position: relative; text-align: center; zoom: 1; }
46
+ .fg-button .ui-icon { position: absolute; top: 50%; margin-top: -8px; left: 50%; margin-left: -8px; }
47
+ a.fg-button { float:left; }
48
+ button.fg-button { width:auto; overflow:visible; } /* removes extra button width in IE */
49
+ .fg-button-icon-left { padding-left: 2.1em; }
50
+ .fg-button-icon-right { padding-right: 2.1em; }
51
+ .fg-button-icon-left .ui-icon { right: auto; left: .2em; margin-left: 0; }
52
+ .fg-button-icon-right .ui-icon { left: auto; right: .2em; margin-left: 0; }
53
+ .fg-button-icon-solo { display:block; width:8px; text-indent: -9999px; } /* solo icon buttons must have block properties for the text-indent to work */
54
+ .fg-button.ui-state-loading .ui-icon { background: url(spinner_bar.gif) no-repeat 0 0;}
55
+ /*tabs*/
56
+ .tabs{font-size:1.2em;border-bottom:solid 2px #000;position:relative;}
57
+ .tabs ul{list-style-type:none;}
58
+ .tabs ul li{float:left;display:inline;margin-right:20px;}
59
+ .tabs ul li a{color:#000;text-decoration:none;}
60
+ .tabs ul li a:hover{color:#333;}
61
+ .tabs ul li a.active{background-position:0 bottom;color:#fff;}
62
+ .tabs ul li a.active span{background-position:right bottom;}