cms9 0.2.0

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