alchemy_cms 2.4.rc2 → 2.4.rc4

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 (122) hide show
  1. data/.gitignore +2 -1
  2. data/.travis.yml +7 -4
  3. data/README.md +1 -0
  4. data/alchemy_cms.gemspec +19 -1
  5. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js +5 -2
  6. data/app/assets/javascripts/alchemy/alchemy.link_overlay.js.coffee +1 -1
  7. data/app/assets/javascripts/alchemy/alchemy.preview_window.js +4 -21
  8. data/app/assets/javascripts/alchemy/alchemy.windows.js +0 -1
  9. data/app/assets/stylesheets/alchemy/base.scss +4 -0
  10. data/app/assets/stylesheets/alchemy/elements.scss +59 -60
  11. data/app/assets/stylesheets/alchemy/flash.scss +3 -3
  12. data/app/assets/stylesheets/alchemy/form_elements.scss +15 -2
  13. data/app/assets/stylesheets/alchemy/jquery-ui.scss +11 -3
  14. data/app/assets/stylesheets/alchemy/mixins.scss +9 -0
  15. data/app/assets/stylesheets/alchemy/tinymce_content.css.scss +1 -1
  16. data/app/assets/stylesheets/alchemy/tinymce_dialog.css.scss +4 -0
  17. data/app/assets/stylesheets/alchemy/variables.scss +5 -1
  18. data/app/controllers/alchemy/admin/base_controller.rb +18 -3
  19. data/app/controllers/alchemy/admin/elements_controller.rb +4 -7
  20. data/app/controllers/alchemy/admin/pages_controller.rb +3 -4
  21. data/app/controllers/alchemy/admin/resources_controller.rb +1 -18
  22. data/app/controllers/alchemy/admin/users_controller.rb +8 -5
  23. data/app/helpers/alchemy/admin/pages_helper.rb +6 -1
  24. data/app/models/alchemy/content.rb +26 -5
  25. data/app/models/alchemy/element.rb +1 -0
  26. data/app/models/alchemy/essence_richtext.rb +1 -1
  27. data/app/models/alchemy/page.rb +131 -88
  28. data/app/views/alchemy/admin/clipboard/insert.js.erb +1 -1
  29. data/app/views/alchemy/admin/elements/create.js.erb +6 -1
  30. data/app/views/alchemy/admin/elements/trash.js.erb +1 -3
  31. data/app/views/alchemy/admin/resources/_form.html.erb +13 -1
  32. data/app/views/alchemy/admin/trash/index.html.erb +1 -1
  33. data/app/views/alchemy/base/remote_errors.js.erb +5 -1
  34. data/app/views/alchemy/essences/_essence_link_view.html.erb +2 -0
  35. data/app/views/alchemy/essences/_essence_richtext_editor.html.erb +1 -1
  36. data/config/locales/alchemy.de.yml +11 -4
  37. data/lib/alchemy/capistrano.rb +59 -1
  38. data/lib/alchemy/essence.rb +1 -0
  39. data/lib/alchemy/seeder.rb +39 -49
  40. data/lib/alchemy/tinymce.rb +1 -1
  41. data/lib/alchemy/version.rb +1 -1
  42. data/lib/rails/generators/alchemy/deploy_script/deploy_script_generator.rb +1 -1
  43. data/lib/rails/generators/alchemy/deploy_script/templates/deploy.rb.tt +3 -0
  44. data/lib/rails/generators/alchemy/elements/templates/view.html.haml +2 -2
  45. data/lib/rails/generators/alchemy/elements/templates/view.html.slim +2 -2
  46. data/lib/tasks/database.rake +25 -0
  47. data/lib/tasks/install.rake +5 -14
  48. data/spec/factories.rb +10 -0
  49. data/spec/integration/admin/resources_integration_spec.rb +64 -23
  50. data/spec/integration/pages_controller_spec.rb +0 -2
  51. data/spec/libraries/resources_helper_spec.rb +6 -2
  52. data/spec/models/content_spec.rb +31 -0
  53. data/spec/models/element_spec.rb +7 -2
  54. data/spec/models/page_spec.rb +36 -0
  55. data/vendor/assets/javascripts/jquery_plugins/jquery.dialogextend.1_0_1.js +676 -0
  56. data/vendor/assets/javascripts/jquery_plugins/jquery.ui.tabspaging.js +298 -238
  57. data/vendor/assets/javascripts/tiny_mce/langs/de.js +1 -1
  58. data/vendor/assets/javascripts/tiny_mce/langs/en.js +1 -1
  59. data/vendor/assets/javascripts/tiny_mce/license.txt +6 -6
  60. data/vendor/assets/javascripts/tiny_mce/plugins/fullscreen/editor_plugin.js +1 -1
  61. data/vendor/assets/javascripts/tiny_mce/plugins/fullscreen/fullscreen.htm +97 -97
  62. data/vendor/assets/javascripts/tiny_mce/plugins/inlinepopups/template.htm +376 -386
  63. data/vendor/assets/javascripts/tiny_mce/plugins/paste/editor_plugin.js +1 -1
  64. data/vendor/assets/javascripts/tiny_mce/plugins/paste/js/pastetext.js +30 -30
  65. data/vendor/assets/javascripts/tiny_mce/plugins/paste/js/pasteword.js +45 -45
  66. data/vendor/assets/javascripts/tiny_mce/plugins/paste/langs/de_dlg.js +1 -1
  67. data/vendor/assets/javascripts/tiny_mce/plugins/paste/pastetext.htm +17 -20
  68. data/vendor/assets/javascripts/tiny_mce/plugins/paste/pasteword.htm +12 -12
  69. data/vendor/assets/javascripts/tiny_mce/plugins/table/cell.htm +173 -183
  70. data/vendor/assets/javascripts/tiny_mce/plugins/table/css/cell.css +4 -4
  71. data/vendor/assets/javascripts/tiny_mce/plugins/table/css/row.css +7 -7
  72. data/vendor/assets/javascripts/tiny_mce/plugins/table/css/table.css +3 -3
  73. data/vendor/assets/javascripts/tiny_mce/plugins/table/editor_plugin.js +1 -1
  74. data/vendor/assets/javascripts/tiny_mce/plugins/table/js/cell.js +280 -282
  75. data/vendor/assets/javascripts/tiny_mce/plugins/table/js/merge_cells.js +15 -15
  76. data/vendor/assets/javascripts/tiny_mce/plugins/table/js/row.js +221 -204
  77. data/vendor/assets/javascripts/tiny_mce/plugins/table/js/table.js +448 -435
  78. data/vendor/assets/javascripts/tiny_mce/plugins/table/langs/de_dlg.js +1 -1
  79. data/vendor/assets/javascripts/tiny_mce/plugins/table/merge_cells.htm +22 -24
  80. data/vendor/assets/javascripts/tiny_mce/plugins/table/row.htm +136 -144
  81. data/vendor/assets/javascripts/tiny_mce/plugins/table/table.htm +168 -184
  82. data/vendor/assets/javascripts/tiny_mce/themes/advanced/about.htm +46 -62
  83. data/vendor/assets/javascripts/tiny_mce/themes/advanced/anchor.htm +16 -17
  84. data/vendor/assets/javascripts/tiny_mce/themes/advanced/charmap.htm +47 -56
  85. data/vendor/assets/javascripts/tiny_mce/themes/advanced/color_picker.htm +52 -69
  86. data/vendor/assets/javascripts/tiny_mce/themes/advanced/editor_template.js +1 -852
  87. data/vendor/assets/javascripts/tiny_mce/themes/advanced/image.htm +69 -79
  88. data/vendor/assets/javascripts/tiny_mce/themes/advanced/img/icons.gif +0 -0
  89. data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/about.js +48 -48
  90. data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/anchor.js +50 -37
  91. data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/charmap.js +317 -317
  92. data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/color_picker.js +345 -331
  93. data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/image.js +248 -246
  94. data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/link.js +152 -146
  95. data/vendor/assets/javascripts/tiny_mce/themes/advanced/js/source_editor.js +53 -31
  96. data/vendor/assets/javascripts/tiny_mce/themes/advanced/langs/de.js +1 -1
  97. data/vendor/assets/javascripts/tiny_mce/themes/advanced/langs/de_dlg.js +1 -1
  98. data/vendor/assets/javascripts/tiny_mce/themes/advanced/langs/en.js +1 -1
  99. data/vendor/assets/javascripts/tiny_mce/themes/advanced/langs/en_dlg.js +1 -1
  100. data/vendor/assets/javascripts/tiny_mce/themes/advanced/link.htm +46 -53
  101. data/vendor/assets/javascripts/tiny_mce/themes/advanced/shortcuts.htm +45 -57
  102. data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/default/content.css +47 -182
  103. data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/default/dialog.css +93 -399
  104. data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/default/ui.css +191 -890
  105. data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/highcontrast/content.css +24 -102
  106. data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/highcontrast/dialog.css +79 -377
  107. data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/highcontrast/ui.css +80 -451
  108. data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/o2k7/content.css +45 -167
  109. data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/o2k7/dialog.css +93 -399
  110. data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/o2k7/ui.css +194 -889
  111. data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/o2k7/ui_black.css +7 -33
  112. data/vendor/assets/javascripts/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css +4 -15
  113. data/vendor/assets/javascripts/tiny_mce/themes/advanced/source_editor.htm +16 -19
  114. data/vendor/assets/javascripts/tiny_mce/tiny_mce.js +1 -1
  115. data/vendor/assets/javascripts/tiny_mce/tiny_mce_popup.js +1 -1
  116. data/vendor/assets/javascripts/tiny_mce/utils/editable_selects.js +46 -46
  117. data/vendor/assets/javascripts/tiny_mce/utils/form_utils.js +124 -124
  118. data/vendor/assets/javascripts/tiny_mce/utils/mctabs.js +112 -112
  119. data/vendor/assets/javascripts/tiny_mce/utils/validate.js +213 -213
  120. metadata +11 -6
  121. data/spec/dummy/public/404.html.bak +0 -26
  122. data/vendor/assets/javascripts/jquery_plugins/jquery.dialogextend.min.js +0 -8
data/spec/factories.rb CHANGED
@@ -97,4 +97,14 @@ FactoryGirl.define do
97
97
  upload_hash Time.now.hash
98
98
  end
99
99
 
100
+ factory :event do
101
+ name 'My Event'
102
+ hidden_name 'not shown'
103
+ starts_at DateTime.new(2012, 03, 02, 8, 15)
104
+ ends_at DateTime.new(2012, 03, 02, 19, 30)
105
+ description "something\nfancy"
106
+ published false
107
+ entrance_fee 12.3
108
+ end
109
+
100
110
  end
@@ -2,22 +2,12 @@ require 'spec_helper'
2
2
 
3
3
  describe "Resources" do
4
4
 
5
+ let(:event) { FactoryGirl.create(:event) }
6
+ let(:second_event) { FactoryGirl.create(:event, :name => 'My second Event', :entrance_fee => 12.32) }
7
+
5
8
  before do
6
9
  load_authorization_rules
7
10
  authorize_as_admin
8
- Event.create!(:name => 'My Event',
9
- :hidden_name => 'not shown',
10
- :starts_at => DateTime.new(2012, 03, 02, 8, 15),
11
- :ends_at => DateTime.new(2012, 03, 02, 19, 30),
12
- :description => "something\nfancy",
13
- :published => false,
14
- :entrance_fee => 12.32)
15
- Event.create!(:name => 'My second Event',
16
- :starts_at => DateTime.new(2012, 03, 02, 8, 15),
17
- :ends_at => DateTime.new(2012, 03, 02, 19, 30),
18
- :description => "something\nfancy",
19
- :published => false,
20
- :entrance_fee => 12.32)
21
11
  end
22
12
 
23
13
  describe "index view" do
@@ -28,60 +18,111 @@ describe "Resources" do
28
18
  end
29
19
 
30
20
  it "should list existing items" do
21
+ event
22
+ second_event
31
23
  visit '/admin/events'
32
24
  page.should have_content("My Event")
33
25
  page.should have_content("something fancy")
34
26
  page.should have_content("12.32")
35
27
  end
36
28
 
37
- it "should list existing resource-items nicely formatted"
29
+ it "should list existing resource-items nicely formatted" do
30
+ event
31
+ visit '/admin/events'
32
+ page.should have_selector('div#archive_all table.list')
33
+ end
38
34
 
39
35
  end
40
36
 
41
37
  describe "form for creating and updating items" do
42
- it "renders an input field according to the attribute's type"
38
+ it "renders an input field according to the attribute's type" do
39
+ visit '/admin/events/new'
40
+ page.should have_selector('input#event_name[type="text"]')
41
+ page.should have_selector('input#event_starts_at[type="date"]')
42
+ page.should have_selector('textarea#event_description')
43
+ page.should have_selector('input#event_published[type="checkbox"]')
44
+ end
43
45
  end
44
46
 
45
47
  describe "create resource item" do
46
48
 
47
49
  context "when form filled with valid data" do
48
- it "lists the new item" do
50
+ before do
49
51
  visit '/admin/events/new'
50
52
  fill_in 'event_name', :with => 'My second event'
51
53
  fill_in 'event_starts_at', :with => DateTime.new(2012, 03, 03, 20, 00)
52
54
  click_on 'Save'
55
+ end
56
+
57
+ it "lists the new item" do
53
58
  page.should have_content "My second event"
54
59
  page.should have_content "2012-03-03"
55
60
  end
61
+
62
+ it "shows a success message" do
63
+ page.should have_content("Succesfully created")
64
+ end
56
65
  end
57
66
 
58
67
  context "when form filled with invalid data" do
59
- it "shows the form again" do
68
+ before do
60
69
  visit '/admin/events/new'
61
70
  fill_in 'event_name', :with => '' #invalid!
62
71
  click_on 'Save'
63
- page.should have_selector "input#event_name"
64
72
  end
65
- it "lists invalid fields"
73
+
74
+ it "shows the form again" do
75
+ page.should have_selector "form input#event_name"
76
+ end
77
+
78
+ it "lists invalid fields" do
79
+ within('#errors') {
80
+ page.should have_content("Name can't be blank")
81
+ }
82
+ end
83
+
84
+ it "should not display success notice" do
85
+ page.should_not have_content("successfully created")
86
+ end
66
87
  end
67
88
 
68
89
  end
69
90
 
70
91
  describe "updating an item" do
71
- it "shows the updated value"
72
- end
92
+ before do
93
+ visit("/admin/events/#{event.id}/edit")
94
+ fill_in 'event_name', :with => 'New event name'
95
+ click_on 'Save'
96
+ end
97
+
98
+ it "shows the updated value" do
99
+ page.should have_content("New event name")
100
+ end
73
101
 
74
- describe "destroying an item" do
102
+ it "shows a success message" do
103
+ page.should have_content("Succesfully updated")
104
+ end
105
+ end
75
106
 
76
- it "should'n be on the list anymore", :js => true do
107
+ describe "destroying an item", :js => true do
108
+ before do
109
+ event
110
+ second_event
77
111
  visit '/admin/events'
78
112
  within('tr', :text => 'My second Event') do
79
113
  click_on 'Delete'
80
114
  end
81
115
  click_on 'Yes'
116
+ end
117
+
118
+ it "should'n be on the list anymore" do
82
119
  page.should have_content "My Event"
83
120
  page.should_not have_content "My second Event"
84
121
  end
122
+
123
+ it "should display success message" do
124
+ page.should have_content("Succesfully removed")
125
+ end
85
126
  end
86
127
 
87
128
  end
@@ -315,8 +315,6 @@ module Alchemy
315
315
  within("title") { page.should have_content("404") }
316
316
  end
317
317
 
318
- it "can be handled by matching /404 and routing it to a controller of choice when no public/404.html exists"
319
-
320
318
  end
321
319
  end
322
320
  end
@@ -1,3 +1,4 @@
1
+ require 'ostruct'
1
2
  require File.dirname(__FILE__) + "/../../lib/alchemy/resource"
2
3
  require File.dirname(__FILE__) + "/../../lib/alchemy/resources_helper"
3
4
 
@@ -103,6 +104,9 @@ describe Alchemy::ResourcesHelper do
103
104
  end
104
105
 
105
106
  describe "resource_window_size" do
106
- it "should do something"
107
+ it "should return overlay size string depending on resource attributes length" do
108
+ @controller.stub(:resource_handler).and_return(OpenStruct.new(:attributes => OpenStruct.new(:length => 4)))
109
+ @controller.resource_window_size.should == "400x240"
110
+ end
107
111
  end
108
- end
112
+ end
@@ -99,5 +99,36 @@ module Alchemy
99
99
 
100
100
  end
101
101
 
102
+ describe '.create' do
103
+ let (:element) { FactoryGirl.create(:element, :name => 'headline') }
104
+
105
+ context "with default value present" do
106
+ before do
107
+ element.stub(:content_description_for).and_return({'name' => 'headline', 'type' => 'EssenceText', 'default' => 'Welcome'})
108
+ end
109
+
110
+ it "should have the ingredient column filled with default value." do
111
+ Content.create_from_scratch(element, :name => 'headline').ingredient.should == "Welcome"
112
+ end
113
+ end
114
+ end
115
+
116
+ describe '#ingredient=' do
117
+ it "should set the given value to the ingredient column of essence" do
118
+ c = Content.create_from_scratch(element, :name => 'headline')
119
+ c.ingredient = "Welcome"
120
+ c.ingredient.should == "Welcome"
121
+ end
122
+
123
+ context "no essence associated" do
124
+ let (:element) { FactoryGirl.create(:element, :name => 'headline') }
125
+
126
+ it "should raise error" do
127
+ c = Content.create(:element_id => element.id, :name => 'headline')
128
+ expect { c.ingredient = "Welcome" }.to raise_error
129
+ end
130
+ end
131
+ end
132
+
102
133
  end
103
134
  end
@@ -263,9 +263,9 @@ module Alchemy
263
263
 
264
264
  end
265
265
 
266
- describe '#copy' do
266
+ describe '.copy' do
267
267
 
268
- let(:element) { FactoryGirl.create(:element, :create_contents_after_create => true) }
268
+ let(:element) { FactoryGirl.create(:element, :create_contents_after_create => true, :tag_list => 'red, yellow') }
269
269
 
270
270
  it "should not create contents from scratch" do
271
271
  copy = Element.copy(element)
@@ -282,6 +282,11 @@ module Alchemy
282
282
  copy.contents.collect(&:id).should_not == element.contents.collect(&:id)
283
283
  end
284
284
 
285
+ it "the copy should include source element tags" do
286
+ copy = Element.copy(element)
287
+ copy.tag_list.should == element.tag_list
288
+ end
289
+
285
290
  end
286
291
 
287
292
  describe "Finding previous or next element." do
@@ -646,5 +646,41 @@ module Alchemy
646
646
 
647
647
  end
648
648
 
649
+ describe '.copy' do
650
+ let (:page) { FactoryGirl.create(:page, :name => 'Source') }
651
+ subject { Page.copy(page) }
652
+
653
+ it "the copy should have added (copy) to name" do
654
+ subject.name.should == "#{page.name} (Copy)"
655
+ end
656
+
657
+ context "page with tags" do
658
+ before { page.tag_list = 'red, yellow'; page.save }
659
+
660
+ it "the copy should have source tag_list" do
661
+ subject.tag_list.should_not be_empty
662
+ subject.tag_list.should == page.tag_list
663
+ end
664
+ end
665
+
666
+ context "page with elements" do
667
+ before { page.elements << FactoryGirl.create(:element) }
668
+
669
+ it "the copy should have source elements" do
670
+ subject.elements.should_not be_empty
671
+ subject.elements.count.should == page.elements.count
672
+ end
673
+ end
674
+
675
+ context "page with cells" do
676
+ before { page.cells << FactoryGirl.create(:cell) }
677
+
678
+ it "the copy should have source cells" do
679
+ subject.cells.should_not be_empty
680
+ subject.cells.count.should == page.cells.length # It must be length, because!
681
+ end
682
+ end
683
+ end
684
+
649
685
  end
650
686
  end
@@ -0,0 +1,676 @@
1
+ /*!
2
+ * jQuery DialogExtend 1.0.1
3
+ *
4
+ * tvd: fixes for jQuery UI 1.9 and adjusts sizes.
5
+ *
6
+ * Copyright (c) 2010 Shum Ting Hin
7
+ *
8
+ * Licensed under MIT
9
+ * http:// www.opensource.org/licenses/mit-license.php
10
+ *
11
+ * Project Home:
12
+ * http:// code.google.com/p/jquery-dialogextend/
13
+ *
14
+ * Depends:
15
+ * jQuery 1.7.2
16
+ * jQuery UI Dialog 1.8.22
17
+ *
18
+ */
19
+ (function($){
20
+
21
+ // default settings
22
+ var defaults = {
23
+ "close" : true,
24
+ "maximize" : false,
25
+ "minimize" : false,
26
+ "dblclick" : false,
27
+ "titlebar" : false,
28
+ "icons" : {
29
+ "close" : "ui-icon-closethick",
30
+ "maximize" : "ui-icon-extlink",
31
+ "minimize" : "ui-icon-minus",
32
+ "restore" : "ui-icon-newwin"
33
+ },
34
+ "events" : {
35
+ "load" : null,
36
+ "beforeCollapse" : null,
37
+ "beforeMaximize" : null,
38
+ "beforeMinimize" : null,
39
+ "beforeRestore" : null,
40
+ "collapse" : null,
41
+ "maximize" : null,
42
+ "minimize" : null,
43
+ "restore" : null
44
+ }
45
+ };
46
+
47
+ // plugin settings (will be modified during init)
48
+ var settings;
49
+
50
+ // plubic methods
51
+ var methods = {
52
+
53
+ "init" : function( options ){
54
+ var self = this;
55
+ // validation
56
+ if ( !$(self).dialog ) {
57
+ $.error( "jQuery.dialogExtend Error : Only jQuery UI Dialog element is accepted" );
58
+ }
59
+ // merge defaults & options, without modifying the defaults
60
+ options = options || {};
61
+ options.icons = options.icons || {};
62
+ options.events = options.events || {};
63
+ settings = $.extend({}, defaults, options);
64
+ settings.icons = $.extend({}, defaults.icons, options.icons);
65
+ settings.events = $.extend({}, defaults.events, options.events);
66
+ // initiate plugin...
67
+ $(self).each(function(){
68
+ $(this)
69
+ // do bunch of things...
70
+ .dialogExtend("_verifySettings")
71
+ .dialogExtend("_initEvents")
72
+ .dialogExtend("_initStyles")
73
+ .dialogExtend("_initButtons")
74
+ .dialogExtend("_initTitleBar")
75
+ // set default dialog state
76
+ .dialogExtend("_setState", "normal")
77
+ // trigger custom event when done
78
+ .dialogExtend("_trigger", "load");
79
+ });
80
+ // maintain chainability
81
+ return self;
82
+ },
83
+
84
+ "state" : function(){
85
+ return $(this).data("dialog-extend-state");
86
+ },
87
+
88
+ "collapse" : function(){
89
+ var self = this;
90
+ // calculate new dimension
91
+ var newHeight = $(this).dialog("widget").find(".ui-dialog-titlebar").height()+15;
92
+ // start!
93
+ $(self)
94
+ // trigger custom event
95
+ .dialogExtend("_trigger", "beforeCollapse")
96
+ // remember original state
97
+ .dialogExtend("_saveSnapshot")
98
+ // modify dialog size (after hiding content)
99
+ .dialog("option", {
100
+ "resizable" : false,
101
+ "height" : newHeight,
102
+ "maxHeight" : newHeight
103
+ })
104
+ // hide content
105
+ // hide button-pane
106
+ // make title-bar no-wrap
107
+ .hide()
108
+ .dialog("widget")
109
+ .find(".ui-dialog-buttonpane:visible").hide().end()
110
+ .find(".ui-dialog-titlebar").css("white-space", "nowrap").end()
111
+ .find(".ui-dialog-content")
112
+ // mark new state
113
+ .dialogExtend("_setState", "collapsed")
114
+ // trigger custom event
115
+ .dialogExtend("_trigger", "collapse");
116
+ // maintain chainability
117
+ return self;
118
+ },
119
+
120
+ "maximize" : function(){
121
+ var self = this;
122
+ // caculate new dimension
123
+ var newHeight = $(window).height()+10;
124
+ var newWidth = $(window).width()-4;
125
+ // start!
126
+ $(self)
127
+ // trigger custom event
128
+ .dialogExtend("_trigger", "beforeMaximize")
129
+ // restore to normal state first (when necessary)
130
+ .each(function(){
131
+ if ( $(this).dialogExtend("state") != "normal" ) {
132
+ $(this).dialogExtend("_restoreWithoutTriggerEvent");
133
+ }
134
+ })
135
+ // remember original state
136
+ .dialogExtend("_saveSnapshot")
137
+ // fix dialog from scrolling
138
+ .dialog("widget")
139
+ .css({
140
+ // ie6 does not support {position:fixed} ===> simply use {absolute}
141
+ "position" : ( $.browser.msie && parseInt($.browser.version) <= 6 ) ? "absolute" : "fixed"
142
+ })
143
+ .find(".ui-dialog-content")
144
+ // show content
145
+ // show button-pane (when minimized/collapsed)
146
+ .show()
147
+ .dialog("widget")
148
+ .find(".ui-dialog-buttonpane").show().end()
149
+ .find(".ui-dialog-content")
150
+ // modify dialog with new config
151
+ .dialog("option", {
152
+ "resizable" : false,
153
+ "draggable" : false,
154
+ "height" : newHeight,
155
+ "width" : newWidth,
156
+ "position" : [1, 1]
157
+ })
158
+ // disable draggable-handle (for <titlebar=none> only)
159
+ .dialog("widget")
160
+ .find(".ui-dialog-draggable-handle").css("cursor", "text").end()
161
+ .find(".ui-dialog-content")
162
+ // mark new state
163
+ .dialogExtend("_setState", "maximized")
164
+ // modify dialog buttons according to new state
165
+ .dialogExtend("_toggleButtons")
166
+ // trigger custom event
167
+ .dialogExtend("_trigger", "maximize");
168
+ // maintain chainability
169
+ return self;
170
+ },
171
+
172
+ "minimize" : function(){
173
+ var self = this;
174
+ // caculate new dimension
175
+ var newHeight = $(this).dialog("widget").find(".ui-dialog-titlebar").height()+15;
176
+ var newWidth = 200;
177
+ // create container for (multiple) minimized dialogs (when necessary)
178
+ if ( $("#dialog-extend-fixed-container").length ) {
179
+ var fixedContainer = $("#dialog-extend-fixed-container");
180
+ } else {
181
+ var fixedContainer = $('<div id="dialog-extend-fixed-container"></div>').appendTo("body");
182
+ }
183
+ $(fixedContainer).css({
184
+ // ie6 does not support {position:fixed} ===> simply use {absolute}
185
+ "position" : ( $.browser.mise && parseInt($.browser.version) <= 6 ) ? "absolute" : "fixed",
186
+ "bottom" : 1,
187
+ "left" : 1,
188
+ "z-index" : 9999
189
+ });
190
+ // start!
191
+ $(self)
192
+ // trigger custom event
193
+ .dialogExtend("_trigger", "beforeMinimize")
194
+ // remember original state
195
+ .dialogExtend("_saveSnapshot")
196
+ // move dialog from body to container (at lower-left-hand corner)
197
+ .dialog("widget")
198
+ .css({
199
+ // float is essential for stacking dialog when there are many many minimized dialogs
200
+ "float" : "left",
201
+ "margin" : 1,
202
+ "position" : "static"
203
+ })
204
+ .appendTo(fixedContainer)
205
+ .find(".ui-dialog-content")
206
+ // modify dialog with new config
207
+ .dialog("option", {
208
+ "resizable" : false,
209
+ //"draggable" : false,
210
+ "height" : newHeight,
211
+ "width" : newWidth
212
+ })
213
+ // avoid title text overlap buttons
214
+ .dialog("widget")
215
+ .find(".ui-dialog-titlebar").each(function(){
216
+ var titlebar = this;
217
+ var buttonPane = $(this).find(".ui-dialog-titlebar-buttonpane");
218
+ var titleText = $(this).find(".ui-dialog-title");
219
+ $(titleText).css({
220
+ 'overflow': 'hidden',
221
+ 'width' : $(titlebar).width() - $(buttonPane).width() + 10
222
+ });
223
+ }).end()
224
+ .find(".ui-dialog-content")
225
+ // hide content
226
+ // hide button-pane
227
+ // make title-bar no-wrap
228
+ .hide()
229
+ .dialog("widget")
230
+ .find(".ui-dialog-buttonpane:visible").hide().end()
231
+ .find(".ui-dialog-titlebar").css("white-space", "nowrap").end()
232
+ .find(".ui-dialog-content")
233
+ // disable draggable-handle (for <titlebar=none> only)
234
+ .dialog("widget")
235
+ .draggable("option", "handle", null)
236
+ .find(".ui-dialog-draggable-handle").css("cursor", "text").end()
237
+ .find(".ui-dialog-content")
238
+ // mark new state
239
+ .dialogExtend("_setState", "minimized")
240
+ // modify dialog button according to new state
241
+ .dialogExtend("_toggleButtons")
242
+ // trigger custom event
243
+ .dialogExtend("_trigger", "minimize");
244
+ // maintain chainability
245
+ return self;
246
+ },
247
+
248
+ "restore" : function(){
249
+ var self = this;
250
+ // start!
251
+ $(self)
252
+ // trigger custom event
253
+ .dialogExtend("_trigger", "beforeRestore")
254
+ // restore to normal
255
+ .dialogExtend("_restoreWithoutTriggerEvent")
256
+ // mark new state ===> must set state *AFTER* restore because '_restoreWithoutTriggerEvent' will check 'beforeState'
257
+ .dialogExtend("_setState", "normal")
258
+ // modify dialog buttons according to new state
259
+ .dialogExtend("_toggleButtons")
260
+ // trigger custom event
261
+ .dialogExtend("_trigger", "restore");
262
+ // maintain chainability
263
+ return self;
264
+ },
265
+
266
+ "_initButtons" : function(){
267
+ var self = this;
268
+ // start operation on titlebar
269
+ var titlebar = $(self).dialog("widget").find(".ui-dialog-titlebar");
270
+ // create container for buttons
271
+ var buttonPane = $('<div class="ui-dialog-titlebar-buttonpane"></div>').appendTo(titlebar);
272
+ $(buttonPane).css({
273
+ "position" : "absolute",
274
+ "top" : "50%",
275
+ "right" : "0.3em",
276
+ "margin-top" : "-10px",
277
+ "height" : "18px"
278
+ });
279
+ // move 'close' button to button-pane
280
+ $(titlebar)
281
+ .find(".ui-dialog-titlebar-close")
282
+ // override some unwanted jquery-ui styles
283
+ .css({ "position" : "static", "top" : "auto", "right" : "auto", "margin" : 0 })
284
+ // change icon
285
+ .find(".ui-icon").removeClass("ui-icon-closethick").addClass(settings.icons.close).end()
286
+ // move to button-pane
287
+ .appendTo(buttonPane)
288
+ .end();
289
+ // append other buttons to button-pane
290
+ $(buttonPane)
291
+ .append('<a class="ui-dialog-titlebar-maximize ui-corner-all" href="#"><span class="ui-icon '+settings.icons.maximize+'">maximize</span></a>')
292
+ .append('<a class="ui-dialog-titlebar-restore ui-corner-all" href="#"><span class="ui-icon '+settings.icons.restore+'">restore</span></a>')
293
+ .append('<a class="ui-dialog-titlebar-minimize ui-corner-all" href="#"><span class="ui-icon '+settings.icons.minimize+'">minimize</span></a>')
294
+ // add effect to buttons
295
+ .find(".ui-dialog-titlebar-maximize,.ui-dialog-titlebar-minimize,.ui-dialog-titlebar-restore")
296
+ .attr("role", "button")
297
+ .mouseover(function(){ $(this).addClass("ui-state-hover"); })
298
+ .mouseout(function(){ $(this).removeClass("ui-state-hover"); })
299
+ .focus(function(){ $(this).addClass("ui-state-focus"); })
300
+ .blur(function(){ $(this).removeClass("ui-state-focus"); })
301
+ .end()
302
+ // default show buttons
303
+ // set button positions
304
+ // on-click-button
305
+ .find(".ui-dialog-titlebar-close")
306
+ .toggle(settings.close)
307
+ .end()
308
+ .find(".ui-dialog-titlebar-maximize")
309
+ .toggle(settings.maximize)
310
+ .click(function(e){
311
+ e.preventDefault();
312
+ $(self).dialogExtend("maximize");
313
+ })
314
+ .end()
315
+ .find(".ui-dialog-titlebar-minimize")
316
+ .toggle(settings.minimize)
317
+ .click(function(e){
318
+ e.preventDefault();
319
+ $(self).dialogExtend("minimize");
320
+ })
321
+ .end()
322
+ .find(".ui-dialog-titlebar-restore")
323
+ .hide()
324
+ .click(function(e){
325
+ e.preventDefault();
326
+ $(self).dialogExtend("restore");
327
+ })
328
+ .end();
329
+ // other titlebar behaviors
330
+ $(titlebar)
331
+ // on-dblclick-titlebar : maximize/minimize/collapse/restore
332
+ .dblclick(function(evt){
333
+ if ( settings.dblclick && settings.dblclick.length ) {
334
+ $(self).dialogExtend( $(self).dialogExtend("state") != "normal" ? "restore" : settings.dblclick );
335
+ }
336
+ })
337
+ // avoid text-highlight when double-click
338
+ .select(function(){
339
+ return false;
340
+ });
341
+ // maintain chainability
342
+ return self;
343
+ },
344
+
345
+ "_initEvents" : function(){
346
+ var self = this;
347
+ // bind event callbacks which specified at init
348
+ $.each(settings.events, function(type){
349
+ if ( $.isFunction( settings.events[type] ) ) {
350
+ $(self).bind(type+".dialogExtend", settings.events[type]);
351
+ }
352
+ });
353
+ // maintain chainability
354
+ return self;
355
+ },
356
+
357
+ "_initStyles" : function(){
358
+ var self = this;
359
+ // append styles for this plugin to body
360
+ if ( !$(".dialog-extend-css").length ) {
361
+ var style = '';
362
+ style += '<style class="dialog-extend-css" type="text/css">';
363
+ style += '.ui-dialog .ui-dialog-titlebar-buttonpane>a { float: right; }';
364
+ style += '.ui-dialog .ui-dialog-titlebar-maximize,';
365
+ style += '.ui-dialog .ui-dialog-titlebar-minimize,';
366
+ style += '.ui-dialog .ui-dialog-titlebar-restore { width: 19px; padding: 1px; height: 18px; }';
367
+ style += '.ui-dialog .ui-dialog-titlebar-maximize span,';
368
+ style += '.ui-dialog .ui-dialog-titlebar-minimize span,';
369
+ style += '.ui-dialog .ui-dialog-titlebar-restore span { display: block; margin: 1px; }';
370
+ style += '.ui-dialog .ui-dialog-titlebar-maximize:hover,';
371
+ style += '.ui-dialog .ui-dialog-titlebar-maximize:focus,';
372
+ style += '.ui-dialog .ui-dialog-titlebar-minimize:hover,';
373
+ style += '.ui-dialog .ui-dialog-titlebar-minimize:focus,';
374
+ style += '.ui-dialog .ui-dialog-titlebar-restore:hover,';
375
+ style += '.ui-dialog .ui-dialog-titlebar-restore:focus { padding: 0; }';
376
+ style += '.ui-dialog .ui-dialog-titlebar ::selection { background-color: transparent; }';
377
+ style += '</style>';
378
+ $(style).appendTo("body");
379
+ }
380
+ // maintain chainability
381
+ return self;
382
+ },
383
+
384
+ "_initTitleBar" : function(){
385
+ var self = this;
386
+ // modify title bar
387
+ switch ( settings.titlebar ) {
388
+ case false:
389
+ // do nothing
390
+ break;
391
+ case "none":
392
+ // create new draggable-handle as substitute of title bar
393
+ if ( $(self).dialog("option", "draggable") ) {
394
+ var handle = $("<div />").addClass("ui-dialog-draggable-handle").css("cursor", "move").height(5);
395
+ $(self).dialog("widget").prepend(handle).draggable("option", "handle", handle);
396
+ }
397
+ // remove title bar and keep it draggable
398
+ $(self)
399
+ .dialog("widget")
400
+ .find(".ui-dialog-titlebar")
401
+ // clear title text
402
+ .find(".ui-dialog-title").html("&nbsp;").end()
403
+ // keep buttons at upper-right-hand corner
404
+ .css({
405
+ "background-color" : "transparent",
406
+ "background-image" : "none",
407
+ "border" : 0,
408
+ "position" : "absolute",
409
+ "right" : 0,
410
+ "top" : 0,
411
+ "z-index" : 9999
412
+ })
413
+ .end();
414
+ break;
415
+ case "transparent":
416
+ // remove title style
417
+ $(self)
418
+ .dialog("widget")
419
+ .find(".ui-dialog-titlebar")
420
+ .css({
421
+ "background-color" : "transparent",
422
+ "background-image" : "none",
423
+ "border" : 0
424
+ });
425
+ break;
426
+ default:
427
+ $.error( "jQuery.dialogExtend Error : Invalid <titlebar> value '" + settings.titlebar + "'" );
428
+ }
429
+ // maintain chainability
430
+ return self;
431
+ },
432
+
433
+ "_loadSnapshot" : function(){
434
+ var self = this;
435
+ return {
436
+ "config" : {
437
+ "resizable" : $(self).data("original-config-resizable"),
438
+ "draggable" : $(self).data("original-config-draggable")
439
+ },
440
+ "size" : {
441
+ "height" : $(self).data("original-size-height"),
442
+ "width" : $(self).data("original-size-width"),
443
+ "maxHeight" : $(self).data("original-size-maxHeight")
444
+ },
445
+ "position" : {
446
+ "mode" : $(self).data("original-position-mode"),
447
+ "left" : $(self).data("original-position-left"),
448
+ "top" : $(self).data("original-position-top")
449
+ },
450
+ "titlebar" : {
451
+ "wrap" : $(self).data("original-titlebar-wrap")
452
+ }
453
+ };
454
+ },
455
+
456
+ "_restoreFromCollapsed" : function(){
457
+ var self = this;
458
+ var original = $(this).dialogExtend("_loadSnapshot");
459
+ // restore dialog
460
+ $(self)
461
+ // show content
462
+ // show button-pane
463
+ // fix title-bar wrap
464
+ .show()
465
+ .dialog("widget")
466
+ .find(".ui-dialog-buttonpane:hidden").show().end()
467
+ .find(".ui-dialog-titlebar").css("white-space", original.titlebar.wrap).end()
468
+ .find(".ui-dialog-content")
469
+ // restore config & size
470
+ .dialog("option", {
471
+ "resizable" : original.config.resizable,
472
+ "height" : original.size.height,
473
+ "maxHeight" : original.size.maxHeight
474
+ });
475
+ // maintain chainability
476
+ return self;
477
+ },
478
+
479
+ "_restoreFromNormal" : function(){
480
+ // do nothing actually...
481
+ // maintain chainability
482
+ return this;
483
+ },
484
+
485
+ "_restoreFromMaximized" : function(){
486
+ var self = this;
487
+ var original = $(this).dialogExtend("_loadSnapshot");
488
+ // restore dialog
489
+ $(self)
490
+ // free dialog from scrolling
491
+ // fix title-bar wrap (if dialog was minimized/collapsed)
492
+ .dialog("widget")
493
+ .css("position", original.position.mode)
494
+ .find(".ui-dialog-titlebar").css("white-space", original.titlebar.wrap).end()
495
+ .find(".ui-dialog-content")
496
+ // restore config & size
497
+ .dialog("option", {
498
+ "resizable" : original.config.resizable,
499
+ "draggable" : original.config.draggable,
500
+ "height" : original.size.height,
501
+ "width" : original.size.width,
502
+ "maxHeight" : original.size.maxHeight
503
+ })
504
+ // restore position *AFTER* size restored
505
+ .dialog("option", {
506
+ "position" : [ original.position.left, original.position.top ]
507
+ })
508
+ // restore draggable-handle (for <titlebar=none> only)
509
+ .dialog("widget")
510
+ .draggable("option", "handle", $(this).find(".ui-dialog-draggable-handle"))
511
+ .find(".ui-dialog-draggable-handle")
512
+ .css("cursor", "move");
513
+ // maintain chainability
514
+ return self;
515
+ },
516
+
517
+ "_restoreFromMinimized" : function(){
518
+ var self = this;
519
+ var original = $(this).dialogExtend("_loadSnapshot");
520
+ // restore dialog
521
+ $(self)
522
+ // move dialog back from container to body
523
+ .dialog("widget")
524
+ .appendTo("body")
525
+ .css({
526
+ "float" : "none",
527
+ "margin" : 0,
528
+ "position" : original.position.mode
529
+ })
530
+ .find(".ui-dialog-content")
531
+ // revert title text
532
+ .dialog("widget")
533
+ .find(".ui-dialog-title")
534
+ .css({ "width" : "auto" })
535
+ .end()
536
+ .find(".ui-dialog-content")
537
+ // show content
538
+ // show button-pane
539
+ // fix title-bar wrap
540
+ .show()
541
+ .dialog("widget")
542
+ .find(".ui-dialog-buttonpane:hidden").show().end()
543
+ .find(".ui-dialog-titlebar").css("white-space", original.titlebar.wrap).end()
544
+ .find(".ui-dialog-content")
545
+ // restore config & size
546
+ .dialog("option", {
547
+ "resizable" : original.config.resizable,
548
+ "draggable" : original.config.draggable,
549
+ "height" : original.size.height,
550
+ "width" : original.size.width,
551
+ "maxHeight" : original.size.maxHeight
552
+ })
553
+ // restore position *AFTER* size restored
554
+ .dialog("option", {
555
+ "position" : [ original.position.left, original.position.top ]
556
+ })
557
+ // restore draggable-handle (for <titlebar=none> only)
558
+ .dialog("widget")
559
+ .draggable("option", "handle", $(this).find(".ui-dialog-draggable-handle"))
560
+ .find(".ui-dialog-draggable-handle")
561
+ .css("cursor", "move");
562
+ // maintain chainability
563
+ return self;
564
+ },
565
+
566
+ "_restoreWithoutTriggerEvent" : function(){
567
+ var self = this;
568
+ var beforeState = $(self).dialogExtend("state");
569
+ $(self)
570
+ // restore dialog according to previous state
571
+ .dialogExtend(
572
+ beforeState == "maximized" ? "_restoreFromMaximized" :
573
+ beforeState == "minimized" ? "_restoreFromMinimized" :
574
+ beforeState == "collapsed" ? "_restoreFromCollapsed" :
575
+ beforeState == "normal" ? "_restoreFromNormal" :
576
+ $.error( "jQuery.dialogExtend Error : Cannot restore dialog from unknown state '" + beforeState +"'" )
577
+ );
578
+ // maintain chainability
579
+ return self;
580
+ },
581
+
582
+ "_saveSnapshot" : function(){
583
+ var self = this;
584
+ // remember all configs under normal state
585
+ if ( $(self).dialogExtend("state") == "normal" ) {
586
+ $(self)
587
+ .data("original-config-resizable", $(self).dialog("option", "resizable"))
588
+ .data("original-config-draggable", $(self).dialog("option", "draggable"))
589
+ .data("original-size-height", $(self).dialog("widget").height()+14)
590
+ .data("original-size-width", $(self).dialog("option", "width"))
591
+ .data("original-size-maxHeight", $(self).dialog("option", "maxHeight"))
592
+ .data("original-position-mode", $(self).dialog("widget").css("position"))
593
+ .data("original-position-left", $(self).dialog("widget").offset().left)
594
+ .data("original-position-top", $(self).dialog("widget").offset().top)
595
+ .data("original-titlebar-wrap", $(self).dialog("widget").find(".ui-dialog-titlebar").css("white-space"));
596
+ }
597
+ // maintain chainability
598
+ return self;
599
+ },
600
+
601
+ "_setState" : function(state){
602
+ var self = this;
603
+ $(self)
604
+ // toggle data state
605
+ .data("dialog-extend-state", state)
606
+ // toggle class
607
+ .removeClass("ui-dialog-normal ui-dialog-maximized ui-dialog-minimized ui-dialog-collapsed")
608
+ .addClass("ui-dialog-"+state);
609
+ // maintain chainability
610
+ return self;
611
+ },
612
+
613
+ "_toggleButtons" : function(){
614
+ var self = this;
615
+ // show or hide buttons & decide position
616
+ $(self).dialog("widget")
617
+ .find(".ui-dialog-titlebar-maximize")
618
+ .toggle( $(self).dialogExtend("state") != "maximized" && settings.maximize )
619
+ .end()
620
+ .find(".ui-dialog-titlebar-minimize")
621
+ .toggle( $(self).dialogExtend("state") != "minimized" && settings.minimize )
622
+ .end()
623
+ .find(".ui-dialog-titlebar-restore")
624
+ .toggle( $(self).dialogExtend("state") != "normal" && ( settings.maximize || settings.minimize ) )
625
+ .css({ "right" : $(self).dialogExtend("state") == "maximized" ? "1.4em" : $(self).dialogExtend("state") == "minimized" ? !settings.maximize ? "1.4em" : "2.5em" : "-9999em" })
626
+ .end();
627
+ // maintain chainability
628
+ return self;
629
+ },
630
+
631
+ "_trigger" : function( type ){
632
+ var self = this;
633
+ // trigger event with namespace when user bind to it
634
+ $(self).triggerHandler(type+".dialogExtend", this);
635
+ // maintain chainability
636
+ return self;
637
+ },
638
+
639
+ "_verifySettings" : function(){
640
+ var self = this;
641
+ // check <dblclick> option
642
+ if ( !settings.dblclick ) {
643
+ } else if ( settings.dblclick == "maximize" ) {
644
+ } else if ( settings.dblclick == "minimize" ) {
645
+ } else if ( settings.dblclick == "collapse" ) {
646
+ } else {
647
+ $.error( "jQuery.dialogExtend Error : Invalid <dblclick> value '" + settings.dblclick + "'" );
648
+ settings.dblclick = false;
649
+ }
650
+ // check <titlebar> option
651
+ if ( !settings.titlebar ) {
652
+ } else if ( settings.titlebar == "none" ) {
653
+ } else if ( settings.titlebar == "transparent" ) {
654
+ } else {
655
+ $.error( "jQuery.dialogExtend Error : Invalid <titlebar> value '" + settings.titlebar + "'" );
656
+ settings.titlebar = false;
657
+ }
658
+ // maintain chainability
659
+ return self;
660
+ }
661
+
662
+ };
663
+
664
+ // core method
665
+ $.fn.dialogExtend = function( method ){
666
+ // method calling logic
667
+ if ( methods[ method ] ) {
668
+ return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
669
+ } else if ( typeof method === "object" || ! method ) {
670
+ return methods.init.apply( this, arguments );
671
+ } else {
672
+ $.error( "jQuery.dialogExtend Error : Method <" + method + "> does not exist" );
673
+ }
674
+ };
675
+
676
+ }(jQuery));