cms9 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +192 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/config/cms9_manifest.js +2 -0
  6. data/app/assets/images/cms9/cms9_logo.png +0 -0
  7. data/app/assets/images/cms9/cms9_logo_readme.png +0 -0
  8. data/app/assets/images/cms9/favicon-128.png +0 -0
  9. data/app/assets/images/cms9/favicon-16.png +0 -0
  10. data/app/assets/images/cms9/favicon-32.png +0 -0
  11. data/app/assets/images/cms9/favicon-64.png +0 -0
  12. data/app/assets/images/cms9/iCheck/flat/blue.png +0 -0
  13. data/app/assets/images/cms9/iCheck/flat/blue@2x.png +0 -0
  14. data/app/assets/javascripts/cms9/admin_lte.js +763 -0
  15. data/app/assets/javascripts/cms9/application.js +18 -0
  16. data/app/assets/javascripts/cms9/cable.js +13 -0
  17. data/app/assets/javascripts/cms9/multiple_values_selection.js +70 -0
  18. data/app/assets/javascripts/cms9/post_fields.js +5 -0
  19. data/app/assets/javascripts/cms9/posts.js +37 -0
  20. data/app/assets/stylesheets/cms9/admin_lte.scss +4932 -0
  21. data/app/assets/stylesheets/cms9/admin_lte_skins.css +1770 -0
  22. data/app/assets/stylesheets/cms9/application.scss +7 -0
  23. data/app/assets/stylesheets/cms9/fields.scss +3 -0
  24. data/app/assets/stylesheets/cms9/post_definitions.scss +28 -0
  25. data/app/assets/stylesheets/cms9/posts.scss +3 -0
  26. data/app/assets/stylesheets/cms9/welcome.scss +20 -0
  27. data/app/controllers/cms9/application_controller.rb +34 -0
  28. data/app/controllers/cms9/fields_controller.rb +4 -0
  29. data/app/controllers/cms9/post_definitions_controller.rb +85 -0
  30. data/app/controllers/cms9/post_fields_controller.rb +108 -0
  31. data/app/controllers/cms9/posts_controller.rb +76 -0
  32. data/app/controllers/cms9/welcome_controller.rb +8 -0
  33. data/app/helpers/cms9/application_helper.rb +58 -0
  34. data/app/helpers/cms9/fields_helper.rb +4 -0
  35. data/app/helpers/cms9/post_definitions_helper.rb +4 -0
  36. data/app/helpers/cms9/post_fields_helper.rb +4 -0
  37. data/app/helpers/cms9/posts_helper.rb +4 -0
  38. data/app/helpers/cms9/welcome_helper.rb +4 -0
  39. data/app/jobs/cms9/application_job.rb +4 -0
  40. data/app/mailers/cms9/application_mailer.rb +6 -0
  41. data/app/models/ckeditor/asset.rb +9 -0
  42. data/app/models/ckeditor/attachment_file.rb +9 -0
  43. data/app/models/ckeditor/picture.rb +14 -0
  44. data/app/models/cms9/application_record.rb +5 -0
  45. data/app/models/cms9/event.rb +7 -0
  46. data/app/models/cms9/field.rb +20 -0
  47. data/app/models/cms9/post.rb +16 -0
  48. data/app/models/cms9/post_definition.rb +25 -0
  49. data/app/models/cms9/post_field.rb +23 -0
  50. data/app/views/cms9/fields/index.html.erb +0 -0
  51. data/app/views/cms9/post_definitions/edit.html.erb +81 -0
  52. data/app/views/cms9/post_definitions/index.html.erb +48 -0
  53. data/app/views/cms9/post_definitions/new.html.erb +41 -0
  54. data/app/views/cms9/post_fields/_field_form.html.erb +46 -0
  55. data/app/views/cms9/post_fields/_image_sizer.html.erb +2 -0
  56. data/app/views/cms9/post_fields/_select.html.erb +24 -0
  57. data/app/views/cms9/post_fields/_select_blank.html.erb +10 -0
  58. data/app/views/cms9/post_fields/edit.html.erb +14 -0
  59. data/app/views/cms9/post_fields/new.html.erb +14 -0
  60. data/app/views/cms9/posts/_post_form.html.erb +13 -0
  61. data/app/views/cms9/posts/edit.html.erb +14 -0
  62. data/app/views/cms9/posts/index.html.erb +42 -0
  63. data/app/views/cms9/posts/inputs/_date.html.erb +2 -0
  64. data/app/views/cms9/posts/inputs/_date_time.html.erb +2 -0
  65. data/app/views/cms9/posts/inputs/_image.html.erb +19 -0
  66. data/app/views/cms9/posts/inputs/_number.html.erb +2 -0
  67. data/app/views/cms9/posts/inputs/_select_multiple.html.erb +7 -0
  68. data/app/views/cms9/posts/inputs/_select_single.html.erb +2 -0
  69. data/app/views/cms9/posts/inputs/_text.html.erb +2 -0
  70. data/app/views/cms9/posts/inputs/_text_area.html.erb +2 -0
  71. data/app/views/cms9/posts/inputs/_time.html.erb +2 -0
  72. data/app/views/cms9/posts/new.html.erb +14 -0
  73. data/app/views/cms9/welcome/_post.html.erb +46 -0
  74. data/app/views/cms9/welcome/_post_definition.html.erb +36 -0
  75. data/app/views/cms9/welcome/index.html.erb +57 -0
  76. data/app/views/layouts/cms9/application.html.erb +100 -0
  77. data/config/initializers/assets.rb +4 -0
  78. data/config/initializers/ckeditor.rb +59 -0
  79. data/config/initializers/ckeditor_dragonfly.rb +19 -0
  80. data/config/initializers/ckeditor_init.rb +3 -0
  81. data/config/initializers/dragonfly.rb +26 -0
  82. data/config/routes.rb +11 -0
  83. data/db/migrate/cms9_create.rb +73 -0
  84. data/db/schema.rb +49 -0
  85. data/db/seeds.rb +7 -0
  86. data/lib/cms9.rb +24 -0
  87. data/lib/cms9/engine.rb +24 -0
  88. data/lib/cms9/version.rb +3 -0
  89. data/lib/events/cms9_events.rb +50 -0
  90. data/lib/generators/cms9/install/install_generator.rb +81 -0
  91. data/lib/generators/cms9/install/templates/ckeditor_config.js +14 -0
  92. data/lib/generators/cms9/install/templates/cms9_configurator.rb +4 -0
  93. data/lib/sdk/cms9.rb +138 -0
  94. data/lib/tasks/cms9_tasks.rake +4 -0
  95. metadata +423 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 39671969df29f084dc50386b34c30986abd7cf40
4
+ data.tar.gz: a5d9ee92ba34f3ddc4b35bf41b815eafad32da36
5
+ SHA512:
6
+ metadata.gz: ca9af03a530830533930fd948b812300654a9cbadf72334685808353d8e1c1bb19fab4534a9525c4a85b147f7e9d48e06e22ce7cd7ab32da6b5e5bc0b99bd804
7
+ data.tar.gz: 11a5d8d5e2dfcdbba45f4468f598f1bffb26c8559595a38b43947ca07043d627a55c19d30fd51c68fddbef66a18e8b8583ab7a7721c293e6424895588303527c
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Klika.ba
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,192 @@
1
+ ![Cms9 Logo](https://raw.githubusercontent.com/klikaba/cms9/master/app/assets/images/cms9/cms9_logo_readme.png)
2
+
3
+ # Cms9
4
+
5
+ Small CMS Admin module for developers.
6
+
7
+ [Demo Application](https://github.com/klikaba/cms9-demo) running on Cms9.
8
+
9
+ ## What Is Cms9?
10
+
11
+ Cms9 is not standard CMS - it is targeted for developers to ease process of embedding CMS functionality to any site.
12
+
13
+ Cms9 provides admin dashboard where user can:
14
+ * Define different types of forms (News, BlogPost, Ads, Jobs, ...)
15
+ * Adding user defined fields to forms
16
+ * Currently we are supporting following field types
17
+ * Text field
18
+ * Text Area (WYSIWYG-ed text area using ckedit)
19
+ * Number
20
+ * Choose Single
21
+ * Choose Multiple
22
+ * Date
23
+ * Time
24
+ * Date & Time
25
+ * Image
26
+ * Manage data for each form
27
+
28
+ Cms9 does not have any functionality regarding displaying content - it is firstly there to provide Admin dashboard where data can be defined and managed. On the other side it exposes simple interface to access that data.
29
+
30
+ ### Features
31
+ * Rails 5+
32
+ * Automatic form validation
33
+ * Events history (record actions like create/update/delete on Post Types and their Posts)
34
+ * Authentication customizable (via [Devise](https://github.com/plataformatec/devise) or similar frameworks)
35
+ * [Dragonfly](https://github.com/markevans/dragonfly) for handling images and other attachments
36
+ * [Ckeditor](https://github.com/galetahub/ckeditor) as default WYSIWYG text editor
37
+ * Bootstrap 3+ with Admin LTE template
38
+
39
+
40
+ ## Getting Started
41
+
42
+ Add Cms9 to your Gemfile:
43
+
44
+ ```ruby
45
+ # Gemfile
46
+ gem "cms9"
47
+ ```
48
+
49
+ Run the installer:
50
+
51
+ ```bash
52
+ $ rails generate cms9:install [DEF_ROUTE]
53
+ ```
54
+
55
+ Where [DEF_ROUTE] is optional and presents where your Cms9 route will be mounted, by default it's /cms9
56
+
57
+ Install generator will mount Cms9 route, add current_user configurator initializer and additional configuration for Ckeditor.
58
+
59
+ Then run:
60
+
61
+ ```bash
62
+ $ rails db:migrate
63
+ ```
64
+
65
+ Open http://localhost:3000/cms9 to see your new Cms9 dashboard in action.
66
+
67
+ ## Managing Content
68
+ Content is managed by creating Post Types (aka Post Definitions). Post Type represents form for specific data - in case of news site it can be *News Form* that have multiple fields for *Title*, *Content*, *CoverImage*, *PublishedStatus*. Each of those fields can be created from Dashboard.
69
+
70
+ Once Post Type with specific name is created and all fields are added CMS9 Admin can start creating data (Posts) based on those Post Types.
71
+
72
+ Cms9 doesn't have any functionality to display content but exposes simple interface to retrieving data. E.g inside News app you can access all Posts with:
73
+
74
+ ```html
75
+ <% @Cms9::Post.each do |post| %>
76
+ <%= post.field('Title) %>
77
+ <% end %>
78
+ ```
79
+
80
+ You can make any kind of layout for your posts and showed them however you want. Once you made a simple layout, you are ready to create as many posts as you want. It's that easy.
81
+
82
+
83
+ ## Data Interface
84
+ All Data Interface classes are ActveRecord models.
85
+
86
+ **Cms9::PostDefinition** - Represents Form Defintion e.g. News, Jobs, Ads,
87
+ **Cms9::PostField** - each PostDefinition contains multiple fields that describes type of data
88
+ **Cms9::Post** - Represents post with data. Each Post belongs to one of PostDefinitions
89
+ **Cms9::Field** - Represents value for each field and belongs to Post
90
+
91
+
92
+ #### Cms9::PostDefinition
93
+ Methods:
94
+ fields() - returns list of fields that defines PostDefinition
95
+ field(name) - returns field by name
96
+
97
+ E.g. If user Created PostDefinition called 'News' with Title and Content fields we can retrieve it by:
98
+
99
+ Cms9::PostDefinition.all - returns all post definitions
100
+ Cms9::PostDefinition.all.first.fields() - returns all fields for this Post Type
101
+ Cms9::PostDefinition.all.first.field('Title') - returns field that describes field named 'Title'
102
+
103
+ #### Cms9::PostFields
104
+ Class represents definition of Post Type field. Each class have 'name' (unique in context of one PostDefintion), 'Type' and extra parameters depending on type. Currently we are supporting following types: Text field, Text Area (WYSIWYG-ed text area using ckedit), Number, Choose Single, Choose Multiple, Date, Time, Date & Time, Image.
105
+
106
+ #### Cms9::Post
107
+ field(name) - Returns Cms9::Field by name
108
+
109
+ #### Cms9::Field
110
+ Represents value for particular field. Depending on the PostField type 'value' column is serialized differently.
111
+
112
+ Following helpers can be applied to Cms9::Field for easier data extraction/displaying:
113
+
114
+ cms9\_field(field)
115
+
116
+ ## Configuration
117
+
118
+ Authorization should be added using the current_user method. If you pass a block it will be triggered through a
119
+ before filter on first action in Cms9.
120
+
121
+ To begin with, you may be interested in setting up [Devise](https://github.com/sferik/rails_admin/wiki/Devise) or
122
+ something similar.
123
+
124
+ After, in your User model, you need to implement method **cms9_admin?** which will be used to recognize users and
125
+ give them permission to access Cms9 dashboard:
126
+
127
+ #### Example of User Model:
128
+
129
+ ```ruby
130
+ class User < ApplicationRecord
131
+ devise :database_authenticatable, :registerable,
132
+ :recoverable, :rememberable, :trackable, :validatable
133
+
134
+ def cms9_admin?
135
+ return true # All users have access to Cms9 dashboard
136
+ end
137
+ end
138
+ ```
139
+
140
+ In `config/initializers/cms9_configurator.rb` we are passing Devise **current_user** method (or whatever you use
141
+ to recognize user) and **destroy_user_session_path** which is default path for deleting users session (logout):
142
+
143
+ ```ruby
144
+ Cms9.configure do |config|
145
+ config.current_user = :current_user
146
+ config.destroy_user_session = :destroy_user_session_path
147
+ end
148
+ ```
149
+
150
+ **Note**: In Devise, **current_user** method and **destroy_user_session_path** are used by default, it will work without passing it to Cms9
151
+ configuration. Be sure, if you are using something else, to pass that method and path.
152
+
153
+ ### Dependencies
154
+
155
+ * Install ImageMagick for Dragonfly's image processing
156
+ * If you will use Dragonfly data stores (which are not included in core of Dragonfly) you need to include them in Gemfile: [Amazon S3](https://github.com/markevans/dragonfly-s3_data_store), [Couch](https://github.com/markevans/dragonfly-couch_data_store) or [Mongo](https://github.com/markevans/dragonfly-mongo_data_store)
157
+ * In case you need data store which is not listed, you can also build a custom data store - [Building a custom data store](http://markevans.github.io/dragonfly/data-stores/#building-a-custom-data-store)
158
+
159
+ ### Dragonfly data stores
160
+
161
+ By default Dragonfly is using datastore:file. If you plan to use any other data store, after including gem and
162
+ install you need to override Dragonflys configuration.
163
+
164
+ For example if you are going to use Amazon S3 as your default data store, you need to make initializer
165
+ (e.g `config/initializers/init_dragonfly_s3.rb`)which will override configuration (one for Dragonfly uploader, and second for Ckeditor assets uploader):
166
+
167
+ ```ruby
168
+ require 'dragonfly/s3_data_store'
169
+
170
+ Dragonfly.app.configure do
171
+ ...
172
+ datastore :s3,
173
+ bucket_name: 'mybucket',
174
+ access_key_id: 'my_access_key_id',
175
+ secret_access_key: 'my_secret_access_key'
176
+ ...
177
+ end
178
+
179
+ Dragonfly.app(:ckeditor).configure do
180
+ ...
181
+
182
+ datastore :s3,
183
+ bucket_name: 'mybucket',
184
+ access_key_id: 'my_access_key_id',
185
+ secret_access_key: 'my_secret_access_key'
186
+
187
+ ...
188
+ end
189
+ ```
190
+
191
+ ## License
192
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Cms9'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ require 'bundler/gem_tasks'
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,2 @@
1
+ //= link_directory ../javascripts/cms9 .js
2
+ //= link_directory ../stylesheets/cms9 .css
@@ -0,0 +1,763 @@
1
+ /*! AdminLTE app.js
2
+ * ================
3
+ * Main JS application file for AdminLTE v2. This file
4
+ * should be included in all pages. It controls some layout
5
+ * options and implements exclusive AdminLTE plugins.
6
+ *
7
+ * @Author Almsaeed Studio
8
+ * @Support <http://www.almsaeedstudio.com>
9
+ * @Email <abdullah@almsaeedstudio.com>
10
+ * @version 2.3.6
11
+ * @license MIT <http://opensource.org/licenses/MIT>
12
+ */
13
+
14
+ //Make sure jQuery has been loaded before app.js
15
+ if (typeof jQuery === "undefined") {
16
+ throw new Error("AdminLTE requires jQuery");
17
+ }
18
+
19
+ /* AdminLTE
20
+ *
21
+ * @type Object
22
+ * @description $.AdminLTE is the main object for the template's app.
23
+ * It's used for implementing functions and options related
24
+ * to the template. Keeping everything wrapped in an object
25
+ * prevents conflict with other plugins and is a better
26
+ * way to organize our code.
27
+ */
28
+ $.AdminLTE = {};
29
+
30
+ /* --------------------
31
+ * - AdminLTE Options -
32
+ * --------------------
33
+ * Modify these options to suit your implementation
34
+ */
35
+ $.AdminLTE.options = {
36
+ //Add slimscroll to navbar menus
37
+ //This requires you to load the slimscroll plugin
38
+ //in every page before app.js
39
+ navbarMenuSlimscroll: true,
40
+ navbarMenuSlimscrollWidth: "3px", //The width of the scroll bar
41
+ navbarMenuHeight: "200px", //The height of the inner menu
42
+ //General animation speed for JS animated elements such as box collapse/expand and
43
+ //sidebar treeview slide up/down. This options accepts an integer as milliseconds,
44
+ //'fast', 'normal', or 'slow'
45
+ animationSpeed: 500,
46
+ //Sidebar push menu toggle button selector
47
+ sidebarToggleSelector: "[data-toggle='offcanvas']",
48
+ //Activate sidebar push menu
49
+ sidebarPushMenu: true,
50
+ //Activate sidebar slimscroll if the fixed layout is set (requires SlimScroll Plugin)
51
+ sidebarSlimScroll: true,
52
+ //Enable sidebar expand on hover effect for sidebar mini
53
+ //This option is forced to true if both the fixed layout and sidebar mini
54
+ //are used together
55
+ sidebarExpandOnHover: false,
56
+ //BoxRefresh Plugin
57
+ enableBoxRefresh: true,
58
+ //Bootstrap.js tooltip
59
+ enableBSToppltip: true,
60
+ BSTooltipSelector: "[data-toggle='tooltip']",
61
+ //Enable Fast Click. Fastclick.js creates a more
62
+ //native touch experience with touch devices. If you
63
+ //choose to enable the plugin, make sure you load the script
64
+ //before AdminLTE's app.js
65
+ enableFastclick: false,
66
+ //Control Sidebar Options
67
+ enableControlSidebar: true,
68
+ controlSidebarOptions: {
69
+ //Which button should trigger the open/close event
70
+ toggleBtnSelector: "[data-toggle='control-sidebar']",
71
+ //The sidebar selector
72
+ selector: ".control-sidebar",
73
+ //Enable slide over content
74
+ slide: true
75
+ },
76
+ //Box Widget Plugin. Enable this plugin
77
+ //to allow boxes to be collapsed and/or removed
78
+ enableBoxWidget: true,
79
+ //Box Widget plugin options
80
+ boxWidgetOptions: {
81
+ boxWidgetIcons: {
82
+ //Collapse icon
83
+ collapse: 'fa-minus',
84
+ //Open icon
85
+ open: 'fa-plus',
86
+ //Remove icon
87
+ remove: 'fa-times'
88
+ },
89
+ boxWidgetSelectors: {
90
+ //Remove button selector
91
+ remove: '[data-widget="remove"]',
92
+ //Collapse button selector
93
+ collapse: '[data-widget="collapse"]'
94
+ }
95
+ },
96
+ //Direct Chat plugin options
97
+ directChat: {
98
+ //Enable direct chat by default
99
+ enable: true,
100
+ //The button to open and close the chat contacts pane
101
+ contactToggleSelector: '[data-widget="chat-pane-toggle"]'
102
+ },
103
+ //Define the set of colors to use globally around the website
104
+ colors: {
105
+ lightBlue: "#3c8dbc",
106
+ red: "#f56954",
107
+ green: "#00a65a",
108
+ aqua: "#00c0ef",
109
+ yellow: "#f39c12",
110
+ blue: "#0073b7",
111
+ navy: "#001F3F",
112
+ teal: "#39CCCC",
113
+ olive: "#3D9970",
114
+ lime: "#01FF70",
115
+ orange: "#FF851B",
116
+ fuchsia: "#F012BE",
117
+ purple: "#8E24AA",
118
+ maroon: "#D81B60",
119
+ black: "#222222",
120
+ gray: "#d2d6de"
121
+ },
122
+ //The standard screen sizes that bootstrap uses.
123
+ //If you change these in the variables.less file, change
124
+ //them here too.
125
+ screenSizes: {
126
+ xs: 480,
127
+ sm: 768,
128
+ md: 992,
129
+ lg: 1200
130
+ }
131
+ };
132
+
133
+ /* ------------------
134
+ * - Implementation -
135
+ * ------------------
136
+ * The next block of code implements AdminLTE's
137
+ * functions and plugins as specified by the
138
+ * options above.
139
+ */
140
+ $(function () {
141
+ "use strict";
142
+
143
+ //Fix for IE page transitions
144
+ $("body").removeClass("hold-transition");
145
+
146
+ //Extend options if external options exist
147
+ if (typeof AdminLTEOptions !== "undefined") {
148
+ $.extend(true,
149
+ $.AdminLTE.options,
150
+ AdminLTEOptions);
151
+ }
152
+
153
+ //Easy access to options
154
+ var o = $.AdminLTE.options;
155
+
156
+ //Set up the object
157
+ _init();
158
+
159
+ //Activate the layout maker
160
+ $.AdminLTE.layout.activate();
161
+
162
+ //Enable sidebar tree view controls
163
+ $.AdminLTE.tree('.sidebar');
164
+
165
+ //Enable control sidebar
166
+ if (o.enableControlSidebar) {
167
+ $.AdminLTE.controlSidebar.activate();
168
+ }
169
+
170
+ //Add slimscroll to navbar dropdown
171
+ if (o.navbarMenuSlimscroll && typeof $.fn.slimscroll != 'undefined') {
172
+ $(".navbar .menu").slimscroll({
173
+ height: o.navbarMenuHeight,
174
+ alwaysVisible: false,
175
+ size: o.navbarMenuSlimscrollWidth
176
+ }).css("width", "100%");
177
+ }
178
+
179
+ //Activate sidebar push menu
180
+ if (o.sidebarPushMenu) {
181
+ $.AdminLTE.pushMenu.activate(o.sidebarToggleSelector);
182
+ }
183
+
184
+ //Activate Bootstrap tooltip
185
+ if (o.enableBSToppltip) {
186
+ $('body').tooltip({
187
+ selector: o.BSTooltipSelector
188
+ });
189
+ }
190
+
191
+ //Activate box widget
192
+ if (o.enableBoxWidget) {
193
+ $.AdminLTE.boxWidget.activate();
194
+ }
195
+
196
+ //Activate fast click
197
+ if (o.enableFastclick && typeof FastClick != 'undefined') {
198
+ FastClick.attach(document.body);
199
+ }
200
+
201
+ //Activate direct chat widget
202
+ if (o.directChat.enable) {
203
+ $(document).on('click', o.directChat.contactToggleSelector, function () {
204
+ var box = $(this).parents('.direct-chat').first();
205
+ box.toggleClass('direct-chat-contacts-open');
206
+ });
207
+ }
208
+
209
+ /*
210
+ * INITIALIZE BUTTON TOGGLE
211
+ * ------------------------
212
+ */
213
+ $('.btn-group[data-toggle="btn-toggle"]').each(function () {
214
+ var group = $(this);
215
+ $(this).find(".btn").on('click', function (e) {
216
+ group.find(".btn.active").removeClass("active");
217
+ $(this).addClass("active");
218
+ e.preventDefault();
219
+ });
220
+
221
+ });
222
+ });
223
+
224
+ /* ----------------------------------
225
+ * - Initialize the AdminLTE Object -
226
+ * ----------------------------------
227
+ * All AdminLTE functions are implemented below.
228
+ */
229
+ function _init() {
230
+ 'use strict';
231
+ /* Layout
232
+ * ======
233
+ * Fixes the layout height in case min-height fails.
234
+ *
235
+ * @type Object
236
+ * @usage $.AdminLTE.layout.activate()
237
+ * $.AdminLTE.layout.fix()
238
+ * $.AdminLTE.layout.fixSidebar()
239
+ */
240
+ $.AdminLTE.layout = {
241
+ activate: function () {
242
+ var _this = this;
243
+ _this.fix();
244
+ _this.fixSidebar();
245
+ $(window, ".wrapper").resize(function () {
246
+ _this.fix();
247
+ _this.fixSidebar();
248
+ });
249
+ },
250
+ fix: function () {
251
+ //Get window height and the wrapper height
252
+ var neg = $('.main-header').outerHeight() + $('.main-footer').outerHeight();
253
+ var window_height = $(window).height();
254
+ var sidebar_height = $(".sidebar").height();
255
+ //Set the min-height of the content and sidebar based on the
256
+ //the height of the document.
257
+ if ($("body").hasClass("fixed")) {
258
+ $(".content-wrapper, .right-side").css('min-height', window_height - $('.main-footer').outerHeight());
259
+ } else {
260
+ var postSetWidth;
261
+ if (window_height >= sidebar_height) {
262
+ $(".content-wrapper, .right-side").css('min-height', window_height - neg);
263
+ postSetWidth = window_height - neg;
264
+ } else {
265
+ $(".content-wrapper, .right-side").css('min-height', sidebar_height);
266
+ postSetWidth = sidebar_height;
267
+ }
268
+
269
+ //Fix for the control sidebar height
270
+ var controlSidebar = $($.AdminLTE.options.controlSidebarOptions.selector);
271
+ if (typeof controlSidebar !== "undefined") {
272
+ if (controlSidebar.height() > postSetWidth)
273
+ $(".content-wrapper, .right-side").css('min-height', controlSidebar.height());
274
+ }
275
+
276
+ }
277
+ },
278
+ fixSidebar: function () {
279
+ //Make sure the body tag has the .fixed class
280
+ if (!$("body").hasClass("fixed")) {
281
+ if (typeof $.fn.slimScroll != 'undefined') {
282
+ $(".sidebar").slimScroll({destroy: true}).height("auto");
283
+ }
284
+ return;
285
+ } else if (typeof $.fn.slimScroll == 'undefined' && window.console) {
286
+ window.console.error("Error: the fixed layout requires the slimscroll plugin!");
287
+ }
288
+ //Enable slimscroll for fixed layout
289
+ if ($.AdminLTE.options.sidebarSlimScroll) {
290
+ if (typeof $.fn.slimScroll != 'undefined') {
291
+ //Destroy if it exists
292
+ $(".sidebar").slimScroll({destroy: true}).height("auto");
293
+ //Add slimscroll
294
+ $(".sidebar").slimscroll({
295
+ height: ($(window).height() - $(".main-header").height()) + "px",
296
+ color: "rgba(0,0,0,0.2)",
297
+ size: "3px"
298
+ });
299
+ }
300
+ }
301
+ }
302
+ };
303
+
304
+ /* PushMenu()
305
+ * ==========
306
+ * Adds the push menu functionality to the sidebar.
307
+ *
308
+ * @type Function
309
+ * @usage: $.AdminLTE.pushMenu("[data-toggle='offcanvas']")
310
+ */
311
+ $.AdminLTE.pushMenu = {
312
+ activate: function (toggleBtn) {
313
+ //Get the screen sizes
314
+ var screenSizes = $.AdminLTE.options.screenSizes;
315
+
316
+ //Enable sidebar toggle
317
+ $(document).on('click', toggleBtn, function (e) {
318
+ e.preventDefault();
319
+
320
+ //Enable sidebar push menu
321
+ if ($(window).width() > (screenSizes.sm - 1)) {
322
+ if ($("body").hasClass('sidebar-collapse')) {
323
+ $("body").removeClass('sidebar-collapse').trigger('expanded.pushMenu');
324
+ } else {
325
+ $("body").addClass('sidebar-collapse').trigger('collapsed.pushMenu');
326
+ }
327
+ }
328
+ //Handle sidebar push menu for small screens
329
+ else {
330
+ if ($("body").hasClass('sidebar-open')) {
331
+ $("body").removeClass('sidebar-open').removeClass('sidebar-collapse').trigger('collapsed.pushMenu');
332
+ } else {
333
+ $("body").addClass('sidebar-open').trigger('expanded.pushMenu');
334
+ }
335
+ }
336
+ });
337
+
338
+ $(".content-wrapper").click(function () {
339
+ //Enable hide menu when clicking on the content-wrapper on small screens
340
+ if ($(window).width() <= (screenSizes.sm - 1) && $("body").hasClass("sidebar-open")) {
341
+ $("body").removeClass('sidebar-open');
342
+ }
343
+ });
344
+
345
+ //Enable expand on hover for sidebar mini
346
+ if ($.AdminLTE.options.sidebarExpandOnHover
347
+ || ($('body').hasClass('fixed')
348
+ && $('body').hasClass('sidebar-mini'))) {
349
+ this.expandOnHover();
350
+ }
351
+ },
352
+ expandOnHover: function () {
353
+ var _this = this;
354
+ var screenWidth = $.AdminLTE.options.screenSizes.sm - 1;
355
+ //Expand sidebar on hover
356
+ $('.main-sidebar').hover(function () {
357
+ if ($('body').hasClass('sidebar-mini')
358
+ && $("body").hasClass('sidebar-collapse')
359
+ && $(window).width() > screenWidth) {
360
+ _this.expand();
361
+ }
362
+ }, function () {
363
+ if ($('body').hasClass('sidebar-mini')
364
+ && $('body').hasClass('sidebar-expanded-on-hover')
365
+ && $(window).width() > screenWidth) {
366
+ _this.collapse();
367
+ }
368
+ });
369
+ },
370
+ expand: function () {
371
+ $("body").removeClass('sidebar-collapse').addClass('sidebar-expanded-on-hover');
372
+ },
373
+ collapse: function () {
374
+ if ($('body').hasClass('sidebar-expanded-on-hover')) {
375
+ $('body').removeClass('sidebar-expanded-on-hover').addClass('sidebar-collapse');
376
+ }
377
+ }
378
+ };
379
+
380
+ /* Tree()
381
+ * ======
382
+ * Converts the sidebar into a multilevel
383
+ * tree view menu.
384
+ *
385
+ * @type Function
386
+ * @Usage: $.AdminLTE.tree('.sidebar')
387
+ */
388
+ $.AdminLTE.tree = function (menu) {
389
+ var _this = this;
390
+ var animationSpeed = $.AdminLTE.options.animationSpeed;
391
+ $(document).off('click', menu + ' li a')
392
+ .on('click', menu + ' li a', function (e) {
393
+ //Get the clicked link and the next element
394
+ var $this = $(this);
395
+ var checkElement = $this.next();
396
+
397
+ //Check if the next element is a menu and is visible
398
+ if ((checkElement.is('.treeview-menu')) && (checkElement.is(':visible')) && (!$('body').hasClass('sidebar-collapse'))) {
399
+ //Close the menu
400
+ checkElement.slideUp(animationSpeed, function () {
401
+ checkElement.removeClass('menu-open');
402
+ //Fix the layout in case the sidebar stretches over the height of the window
403
+ //_this.layout.fix();
404
+ });
405
+ checkElement.parent("li").removeClass("active");
406
+ }
407
+ //If the menu is not visible
408
+ else if ((checkElement.is('.treeview-menu')) && (!checkElement.is(':visible'))) {
409
+ //Get the parent menu
410
+ var parent = $this.parents('ul').first();
411
+ //Close all open menus within the parent
412
+ var ul = parent.find('ul:visible').slideUp(animationSpeed);
413
+ //Remove the menu-open class from the parent
414
+ ul.removeClass('menu-open');
415
+ //Get the parent li
416
+ var parent_li = $this.parent("li");
417
+
418
+ //Open the target menu and add the menu-open class
419
+ checkElement.slideDown(animationSpeed, function () {
420
+ //Add the class active to the parent li
421
+ checkElement.addClass('menu-open');
422
+ parent.find('li.active').removeClass('active');
423
+ parent_li.addClass('active');
424
+ //Fix the layout in case the sidebar stretches over the height of the window
425
+ _this.layout.fix();
426
+ });
427
+ }
428
+ //if this isn't a link, prevent the page from being redirected
429
+ if (checkElement.is('.treeview-menu')) {
430
+ e.preventDefault();
431
+ }
432
+ });
433
+ };
434
+
435
+ /* ControlSidebar
436
+ * ==============
437
+ * Adds functionality to the right sidebar
438
+ *
439
+ * @type Object
440
+ * @usage $.AdminLTE.controlSidebar.activate(options)
441
+ */
442
+ $.AdminLTE.controlSidebar = {
443
+ //instantiate the object
444
+ activate: function () {
445
+ //Get the object
446
+ var _this = this;
447
+ //Update options
448
+ var o = $.AdminLTE.options.controlSidebarOptions;
449
+ //Get the sidebar
450
+ var sidebar = $(o.selector);
451
+ //The toggle button
452
+ var btn = $(o.toggleBtnSelector);
453
+
454
+ //Listen to the click event
455
+ btn.on('click', function (e) {
456
+ e.preventDefault();
457
+ //If the sidebar is not open
458
+ if (!sidebar.hasClass('control-sidebar-open')
459
+ && !$('body').hasClass('control-sidebar-open')) {
460
+ //Open the sidebar
461
+ _this.open(sidebar, o.slide);
462
+ } else {
463
+ _this.close(sidebar, o.slide);
464
+ }
465
+ });
466
+
467
+ //If the body has a boxed layout, fix the sidebar bg position
468
+ var bg = $(".control-sidebar-bg");
469
+ _this._fix(bg);
470
+
471
+ //If the body has a fixed layout, make the control sidebar fixed
472
+ if ($('body').hasClass('fixed')) {
473
+ _this._fixForFixed(sidebar);
474
+ } else {
475
+ //If the content height is less than the sidebar's height, force max height
476
+ if ($('.content-wrapper, .right-side').height() < sidebar.height()) {
477
+ _this._fixForContent(sidebar);
478
+ }
479
+ }
480
+ },
481
+ //Open the control sidebar
482
+ open: function (sidebar, slide) {
483
+ //Slide over content
484
+ if (slide) {
485
+ sidebar.addClass('control-sidebar-open');
486
+ } else {
487
+ //Push the content by adding the open class to the body instead
488
+ //of the sidebar itself
489
+ $('body').addClass('control-sidebar-open');
490
+ }
491
+ },
492
+ //Close the control sidebar
493
+ close: function (sidebar, slide) {
494
+ if (slide) {
495
+ sidebar.removeClass('control-sidebar-open');
496
+ } else {
497
+ $('body').removeClass('control-sidebar-open');
498
+ }
499
+ },
500
+ _fix: function (sidebar) {
501
+ var _this = this;
502
+ if ($("body").hasClass('layout-boxed')) {
503
+ sidebar.css('position', 'absolute');
504
+ sidebar.height($(".wrapper").height());
505
+ if (_this.hasBindedResize) {
506
+ return;
507
+ }
508
+ $(window).resize(function () {
509
+ _this._fix(sidebar);
510
+ });
511
+ _this.hasBindedResize = true;
512
+ } else {
513
+ sidebar.css({
514
+ 'position': 'fixed',
515
+ 'height': 'auto'
516
+ });
517
+ }
518
+ },
519
+ _fixForFixed: function (sidebar) {
520
+ sidebar.css({
521
+ 'position': 'fixed',
522
+ 'max-height': '100%',
523
+ 'overflow': 'auto',
524
+ 'padding-bottom': '50px'
525
+ });
526
+ },
527
+ _fixForContent: function (sidebar) {
528
+ $(".content-wrapper, .right-side").css('min-height', sidebar.height());
529
+ }
530
+ };
531
+
532
+ /* BoxWidget
533
+ * =========
534
+ * BoxWidget is a plugin to handle collapsing and
535
+ * removing boxes from the screen.
536
+ *
537
+ * @type Object
538
+ * @usage $.AdminLTE.boxWidget.activate()
539
+ * Set all your options in the main $.AdminLTE.options object
540
+ */
541
+ $.AdminLTE.boxWidget = {
542
+ selectors: $.AdminLTE.options.boxWidgetOptions.boxWidgetSelectors,
543
+ icons: $.AdminLTE.options.boxWidgetOptions.boxWidgetIcons,
544
+ animationSpeed: $.AdminLTE.options.animationSpeed,
545
+ activate: function (_box) {
546
+ var _this = this;
547
+ if (!_box) {
548
+ _box = document; // activate all boxes per default
549
+ }
550
+ //Listen for collapse event triggers
551
+ $(_box).on('click', _this.selectors.collapse, function (e) {
552
+ e.preventDefault();
553
+ _this.collapse($(this));
554
+ });
555
+
556
+ //Listen for remove event triggers
557
+ $(_box).on('click', _this.selectors.remove, function (e) {
558
+ e.preventDefault();
559
+ _this.remove($(this));
560
+ });
561
+ },
562
+ collapse: function (element) {
563
+ var _this = this;
564
+ //Find the box parent
565
+ var box = element.parents(".box").first();
566
+ //Find the body and the footer
567
+ var box_content = box.find("> .box-body, > .box-footer, > form >.box-body, > form > .box-footer");
568
+ if (!box.hasClass("collapsed-box")) {
569
+ //Convert minus into plus
570
+ element.children(":first")
571
+ .removeClass(_this.icons.collapse)
572
+ .addClass(_this.icons.open);
573
+ //Hide the content
574
+ box_content.slideUp(_this.animationSpeed, function () {
575
+ box.addClass("collapsed-box");
576
+ });
577
+ } else {
578
+ //Convert plus into minus
579
+ element.children(":first")
580
+ .removeClass(_this.icons.open)
581
+ .addClass(_this.icons.collapse);
582
+ //Show the content
583
+ box_content.slideDown(_this.animationSpeed, function () {
584
+ box.removeClass("collapsed-box");
585
+ });
586
+ }
587
+ },
588
+ remove: function (element) {
589
+ //Find the box parent
590
+ var box = element.parents(".box").first();
591
+ box.slideUp(this.animationSpeed);
592
+ }
593
+ };
594
+ }
595
+
596
+ /* ------------------
597
+ * - Custom Plugins -
598
+ * ------------------
599
+ * All custom plugins are defined below.
600
+ */
601
+
602
+ /*
603
+ * BOX REFRESH BUTTON
604
+ * ------------------
605
+ * This is a custom plugin to use with the component BOX. It allows you to add
606
+ * a refresh button to the box. It converts the box's state to a loading state.
607
+ *
608
+ * @type plugin
609
+ * @usage $("#box-widget").boxRefresh( options );
610
+ */
611
+ (function ($) {
612
+
613
+ "use strict";
614
+
615
+ $.fn.boxRefresh = function (options) {
616
+
617
+ // Render options
618
+ var settings = $.extend({
619
+ //Refresh button selector
620
+ trigger: ".refresh-btn",
621
+ //File source to be loaded (e.g: ajax/src.php)
622
+ source: "",
623
+ //Callbacks
624
+ onLoadStart: function (box) {
625
+ return box;
626
+ }, //Right after the button has been clicked
627
+ onLoadDone: function (box) {
628
+ return box;
629
+ } //When the source has been loaded
630
+
631
+ }, options);
632
+
633
+ //The overlay
634
+ var overlay = $('<div class="overlay"><div class="fa fa-refresh fa-spin"></div></div>');
635
+
636
+ return this.each(function () {
637
+ //if a source is specified
638
+ if (settings.source === "") {
639
+ if (window.console) {
640
+ window.console.log("Please specify a source first - boxRefresh()");
641
+ }
642
+ return;
643
+ }
644
+ //the box
645
+ var box = $(this);
646
+ //the button
647
+ var rBtn = box.find(settings.trigger).first();
648
+
649
+ //On trigger click
650
+ rBtn.on('click', function (e) {
651
+ e.preventDefault();
652
+ //Add loading overlay
653
+ start(box);
654
+
655
+ //Perform ajax call
656
+ box.find(".box-body").load(settings.source, function () {
657
+ done(box);
658
+ });
659
+ });
660
+ });
661
+
662
+ function start(box) {
663
+ //Add overlay and loading img
664
+ box.append(overlay);
665
+
666
+ settings.onLoadStart.call(box);
667
+ }
668
+
669
+ function done(box) {
670
+ //Remove overlay and loading img
671
+ box.find(overlay).remove();
672
+
673
+ settings.onLoadDone.call(box);
674
+ }
675
+
676
+ };
677
+
678
+ })(jQuery);
679
+
680
+ /*
681
+ * EXPLICIT BOX CONTROLS
682
+ * -----------------------
683
+ * This is a custom plugin to use with the component BOX. It allows you to activate
684
+ * a box inserted in the DOM after the app.js was loaded, toggle and remove box.
685
+ *
686
+ * @type plugin
687
+ * @usage $("#box-widget").activateBox();
688
+ * @usage $("#box-widget").toggleBox();
689
+ * @usage $("#box-widget").removeBox();
690
+ */
691
+ (function ($) {
692
+
693
+ 'use strict';
694
+
695
+ $.fn.activateBox = function () {
696
+ $.AdminLTE.boxWidget.activate(this);
697
+ };
698
+
699
+ $.fn.toggleBox = function () {
700
+ var button = $($.AdminLTE.boxWidget.selectors.collapse, this);
701
+ $.AdminLTE.boxWidget.collapse(button);
702
+ };
703
+
704
+ $.fn.removeBox = function () {
705
+ var button = $($.AdminLTE.boxWidget.selectors.remove, this);
706
+ $.AdminLTE.boxWidget.remove(button);
707
+ };
708
+
709
+ })(jQuery);
710
+
711
+ /*
712
+ * TODO LIST CUSTOM PLUGIN
713
+ * -----------------------
714
+ * This plugin depends on iCheck plugin for checkbox and radio inputs
715
+ *
716
+ * @type plugin
717
+ * @usage $("#todo-widget").todolist( options );
718
+ */
719
+ (function ($) {
720
+
721
+ 'use strict';
722
+
723
+ $.fn.todolist = function (options) {
724
+ // Render options
725
+ var settings = $.extend({
726
+ //When the user checks the input
727
+ onCheck: function (ele) {
728
+ return ele;
729
+ },
730
+ //When the user unchecks the input
731
+ onUncheck: function (ele) {
732
+ return ele;
733
+ }
734
+ }, options);
735
+
736
+ return this.each(function () {
737
+
738
+ if (typeof $.fn.iCheck != 'undefined') {
739
+ $('input', this).on('ifChecked', function () {
740
+ var ele = $(this).parents("li").first();
741
+ ele.toggleClass("done");
742
+ settings.onCheck.call(ele);
743
+ });
744
+
745
+ $('input', this).on('ifUnchecked', function () {
746
+ var ele = $(this).parents("li").first();
747
+ ele.toggleClass("done");
748
+ settings.onUncheck.call(ele);
749
+ });
750
+ } else {
751
+ $('input', this).on('change', function () {
752
+ var ele = $(this).parents("li").first();
753
+ ele.toggleClass("done");
754
+ if ($('input', ele).is(":checked")) {
755
+ settings.onCheck.call(ele);
756
+ } else {
757
+ settings.onUncheck.call(ele);
758
+ }
759
+ });
760
+ }
761
+ });
762
+ };
763
+ }(jQuery));