├── .document ├── .gitignore ├── .ruby-version ├── Gemfile ├── LICENSE.txt ├── README.rdoc ├── Rakefile ├── app ├── assets │ ├── images │ │ └── inline_forms │ │ │ └── glass_plate.gif │ ├── javascripts │ │ └── inline_forms │ │ │ └── inline_forms.js │ └── stylesheets │ │ └── inline_forms │ │ ├── devise.scss │ │ ├── foundation_and_overrides.scss │ │ └── inline_forms.scss ├── controllers │ ├── concerns │ │ ├── cancan_concern.rb │ │ └── versions_concern.rb │ ├── geo_code_curacao_controller.rb │ ├── inline_forms_application_controller.rb │ └── inline_forms_controller.rb ├── helpers │ ├── form_elements │ │ ├── absence_list.rb │ │ ├── audio_field.rb │ │ ├── check_box.rb │ │ ├── check_list.rb │ │ ├── chicas_dropdown_with_family_members.rb │ │ ├── chicas_family_photo_list.rb │ │ ├── chicas_photo_list.rb │ │ ├── ckeditor.rb │ │ ├── date.rb │ │ ├── decimal_field.rb │ │ ├── devise_password_field.rb │ │ ├── dns_records.rb │ │ ├── dropdown.rb │ │ ├── dropdown_with_integers.rb │ │ ├── dropdown_with_other.rb │ │ ├── dropdown_with_values.rb │ │ ├── dropdown_with_values_with_stars.rb │ │ ├── file_field.rb │ │ ├── geo_code_curacao.rb │ │ ├── header.rb │ │ ├── image_field.rb │ │ ├── info.rb │ │ ├── info_list.rb │ │ ├── integer_field.rb │ │ ├── kansen_slider.rb │ │ ├── money_field.rb │ │ ├── month_select.rb │ │ ├── month_year_picker.rb │ │ ├── move.rb │ │ ├── multi_image_field.rb │ │ ├── pdf_link.rb │ │ ├── plain_text_area.rb │ │ ├── question_list.rb │ │ ├── radio_button.rb │ │ ├── scale_with_integers.rb │ │ ├── scale_with_values.rb │ │ ├── simple_file_field.rb │ │ ├── slider_with_values.rb │ │ ├── text_area.rb │ │ ├── text_area_without_ckeditor.rb │ │ ├── text_field.rb │ │ └── time.rb │ └── inline_forms_helper.rb ├── models │ ├── concerns │ │ └── inline_forms │ │ │ └── soft_deletable.rb │ └── geo_code_curacao.rb ├── validators │ ├── curacao_id_number_validator.rb │ ├── is_curacao_phone_validator.rb │ ├── is_email_address_validator.rb │ └── must_be_a_value_validator.rb └── views │ ├── devise │ ├── inline_forms │ │ ├── _content_for_devise_login.html.erb │ │ ├── _content_for_passwords_edit.html.erb │ │ └── _content_for_passwords_new.html.erb │ ├── passwords │ │ ├── _top-bar-and-flash.html.erb │ │ ├── edit.html.erb │ │ └── new.html.erb │ ├── sessions │ │ ├── _flash.html.erb │ │ ├── _form.html.erb │ │ ├── _top-bar-and-flash.html.erb │ │ ├── _top-bar.html.erb │ │ └── new.html.erb │ └── shared │ │ ├── _header_and_errors.html.erb │ │ └── _links.erb │ ├── geo_code_curacao │ ├── list_streets.html.erb │ └── list_streets.js.erb │ ├── inline_forms │ ├── _close.html.erb │ ├── _edit.html.erb │ ├── _flash.html.erb │ ├── _header.html.erb │ ├── _list.html.erb │ ├── _new.html.erb │ ├── _new_nested.html.erb │ ├── _show.html.erb │ ├── _tree.html.erb │ ├── _versions.html.erb │ ├── _versions_list.html.erb │ ├── close.js.erb │ ├── edit.js.erb │ ├── extract_translations.erb │ ├── list.js.erb │ ├── new.js.erb │ ├── record_destroyed.js.erb │ ├── show.js.erb │ ├── show_element.js.erb │ ├── show_undo.js.erb │ ├── update.js.erb │ ├── versions.js.erb │ └── versions_list.js.erb │ └── layouts │ ├── application.html.erb │ ├── devise.html.erb │ └── inline_forms.html.erb ├── bin ├── inline_forms ├── inline_forms_app_template.rb └── inline_forms_installer_core.rb ├── inline_forms.gemspec └── lib ├── generators ├── USAGE ├── assets │ ├── javascripts │ │ └── ckeditor │ │ │ └── config.js │ └── stylesheets │ │ ├── inline_forms.scss │ │ └── inline_forms_devise.css ├── inline_forms_generator.rb └── templates │ ├── _inline_forms_tabs.html.erb │ ├── application_record.rb │ ├── capistrano │ ├── Capfile │ ├── deploy.rb │ └── production.rb │ ├── controller.erb │ ├── migration.erb │ ├── model.erb │ ├── test.erb │ └── unicorn │ └── production.rb ├── inline_forms.rb ├── inline_forms └── version.rb ├── locales ├── inline_forms.en.yml └── inline_forms.nl.yml ├── otherstuff ├── 20120310065554_inline_forms_create_view_for_translations.rb ├── add_roles.sql ├── mkiftrans ├── mkrole └── roles_users.sql └── vagrant └── vagrantbox-inline_forms.zip /.document: -------------------------------------------------------------------------------- 1 | lib/**/*.rb 2 | bin/* 3 | - 4 | features/**/*.feature 5 | LICENSE.txt 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # rcov generated 2 | coverage 3 | 4 | # rdoc generated 5 | rdoc 6 | 7 | # yard generated 8 | doc 9 | .yardoc 10 | 11 | # bundler 12 | .bundle 13 | 14 | # jeweler generated 15 | pkg 16 | 17 | # other (Lemuel I think) 18 | .project 19 | .vscode 20 | 21 | # Builds 22 | *.gem 23 | 24 | Gemfile.lock 25 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-3.2.1 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 - 2021 Ace Suares 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = inline_forms 2 | 3 | Inline Forms is almost a complete admin application. You can try it out easily. 4 | 5 | = Usage 6 | 7 | gem install inline_forms 8 | 9 | If you want to just start a new app called MyApp: 10 | 11 | inline_forms create MyApp 12 | 13 | If you want to use mysql instead of sqlite as development database: 14 | 15 | inline_forms create MyApp --database mysql 16 | 17 | If you want to install the example application: 18 | 19 | inline_forms create MyApp -d sqlite --example 20 | 21 | Then point your browser to http://localhost:3000/apartments and log in with admin@example.com / admin999 22 | 23 | You can install the example application manually if you like: 24 | 25 | inline_forms create MyApp 26 | cd MyApp 27 | rails g inline_forms Picture name:string caption:string image:image_field description:text apartment:belongs_to _presentation:'#{name}' 28 | rails generate uploader Image 29 | rails g inline_forms Apartment name:string title:string description:text pictures:has_many pictures:associated _enabled:yes _presentation:'#{name}' 30 | bundle exec rake db:migrate 31 | rails s 32 | 33 | Then point your browser to http://localhost:3000/apartments and log in with admin@example.com / admin999 34 | 35 | = Build a vagrant virtualbox box for easier development 36 | 37 | Go ahead and unzip lib/vagrant/vagrantbox-inline_forms.zip. Enter the created directory with 38 | 39 | cd vagrantbox-inline_forms 40 | 41 | then issue 42 | 43 | vagrant up 44 | 45 | after a while you should be able to use the created box like this: 46 | 47 | vagrant ssh 48 | 49 | Once inside the box, goto /vagrant and install_stuff: 50 | 51 | cd /vagrant 52 | ./install_stuff 53 | 54 | This should update your box, install rvm and ruby and inline_forms, and create an example app. 55 | 56 | 57 | == Disclaimer 58 | 59 | It's work in progress. Until I learn to use git branch, new releases break as easy as Elijah Price's bones. 60 | 61 | 62 | == Copyright 63 | 64 | Copyright (c) 2011-2015 Ace Suares. See LICENSE.txt for further details. 65 | 66 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler' 2 | Bundler::GemHelper.install_tasks 3 | -------------------------------------------------------------------------------- /app/assets/images/inline_forms/glass_plate.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/acesuares/inline_forms/9d25349c247f9473a09ccdb2655d17532598b6a5/app/assets/images/inline_forms/glass_plate.gif -------------------------------------------------------------------------------- /app/assets/javascripts/inline_forms/inline_forms.js: -------------------------------------------------------------------------------- 1 | //= require jquery 2 | //= require jquery_ujs 3 | //= require jquery.ui.all 4 | //= require jquery.timepicker.js 5 | //= require foundation 6 | //= require jquery.remotipart 7 | //= require autocomplete-rails 8 | 9 | $(function(){ $(document).foundation(); }); 10 | // initialize datepickers 11 | $(document).ready(function() { 12 | $.datepicker.setDefaults({ 13 | changeMonth : true, 14 | changeYear : true, 15 | yearRange: '-100:+100', 16 | dateFormat: 'dd-mm-yy' 17 | }); 18 | }); 19 | 20 | // get rid of translation_missing tooltips 21 | $(document).ready(function() { 22 | $(this).on('mouseover', '.translation_missing', function() { 23 | $(this).attr('title', ''); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /app/assets/stylesheets/inline_forms/devise.scss: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=Open+Sans:400,400italic); 2 | @import 'foundation_and_overrides'; 3 | 4 | .contain-to-grid { 5 | background-color: $body-bg !important; 6 | } 7 | 8 | #inline_forms_devise_outer_container a { 9 | color: #A3381E; 10 | } 11 | 12 | #inline_forms_devise_top_nav_bar { 13 | background-color: #A3381E; 14 | a { 15 | color: #FFFFFF; 16 | } 17 | } 18 | 19 | #inline_forms_devise_flash_div { 20 | border-top: 0.5em solid #fade7a; 21 | .flash { 22 | margin-top: 0.2em; 23 | padding: 0.5em; 24 | color: #A3381E; 25 | font-size: 130%; 26 | font-weight: bold; 27 | line-height: 120%; 28 | background-color: white; 29 | border: none; 30 | } 31 | } 32 | 33 | #inline_forms_devise_header_row{ 34 | h1 { 35 | text-align: center; 36 | margin: 30px 0; 37 | color: #A3381E; 38 | } 39 | } 40 | 41 | #inline_forms_devise_container { 42 | .row { 43 | margin-bottom: 30px; 44 | } 45 | } 46 | 47 | #inline_forms_devise_form_column { 48 | } 49 | 50 | #inline_forms_devise_form { 51 | label { 52 | padding-bottom: 0.2em; 53 | padding-left: 0.3em; 54 | } 55 | input[type=checkbox] { 56 | position: relative; 57 | top: 2px; 58 | } 59 | .lower { 60 | top: 15px; 61 | } 62 | #error_explanation { 63 | color: #A3381E; 64 | h2 { 65 | color: #A3381E; 66 | font-size: 120%; 67 | font-weight: bolder; 68 | } 69 | } 70 | } 71 | 72 | #inline_forms_devise_content_column { 73 | hr { 74 | width: 96%; 75 | margin: auto; 76 | } 77 | } 78 | 79 | #inline_forms_devise_content { 80 | padding: 0 1em 1em 3em; 81 | h1 { 82 | text-align: center; 83 | margin: 0 0 0.5em 0; 84 | color: #A3381E; 85 | font-weight: bolder; 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /app/assets/stylesheets/inline_forms/foundation_and_overrides.scss: -------------------------------------------------------------------------------- 1 | @import 'foundation/functions'; 2 | 3 | $include-html-classes: true; 4 | $include-html-global-classes: $include-html-classes; 5 | $font-family-sans-serif: "Open Sans", sans-serif; 6 | 7 | @import 'foundation'; 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/inline_forms/inline_forms.scss: -------------------------------------------------------------------------------- 1 | // inline_forms 2 | @import url(http://fonts.googleapis.com/css?family=Open+Sans:400,400italic); 3 | @import 'foundation-icons'; 4 | @import 'themes/jquery.ui.sunny'; 5 | @import 'jquery.ui.all'; 6 | @import 'foundation_and_overrides'; 7 | 8 | .contain-to-grid { 9 | background-color: $body-bg !important; 10 | } 11 | 12 | input { 13 | margin: 2px 0 !important; 14 | } 15 | 16 | select { 17 | background-color: #fff8e0 !important; 18 | border: 0 !important; 19 | margin: 2px 0 !important; 20 | padding: 0; 21 | 22 | } 23 | select:hover, select:focus { 24 | background-color: lighten(#fff8e0, 2%) !important; 25 | border: 0 !important; 26 | } 27 | 28 | #inline_forms_application_top_bar { 29 | background-color: #A3381E; 30 | color: #FFFFFF; 31 | .top-bar-section li a { 32 | background-color: #A3381E; 33 | } 34 | } 35 | 36 | #inline_forms_model_top_bar { 37 | background-color: #E1C150; 38 | padding-top: 45px; 39 | height: 90px; 40 | .top-bar-section { 41 | .right, li, .has-form { 42 | background-color: #E1C150; 43 | } 44 | .inline_forms_model_top_bar_buttons { 45 | top: 4px !important; 46 | padding: 7px 0 7px 0 !important; 47 | margin: 0 !important; 48 | } 49 | .new_button { 50 | background-color: #E1C150; 51 | color: #B94C32; 52 | font-size: 1.3rem; 53 | padding: 0 2rem 0 1rem; 54 | } 55 | .new_button:hover, .new_button:focus { 56 | color: white; 57 | -webkit-transition-property: color; 58 | transition-property: color; 59 | } 60 | input[type=text]:hover, input[type=text]:focus { 61 | background-color: lighten(#fff8e0, 5%); 62 | -webkit-transition-property: background-color; 63 | transition-property: background-color; 64 | } 65 | } 66 | } 67 | 68 | #inline_forms_model_top_bar_container { 69 | z-index: 9; 70 | } 71 | 72 | #outer_container { 73 | width: 100%; 74 | position: absolute; 75 | top: 90px; 76 | } 77 | 78 | .top-level a { 79 | font-weight: bold; 80 | font-size: 110%; 81 | } 82 | .list_container { 83 | .row { 84 | font-size: 1.2rem; 85 | font-weight: normal; 86 | line-height: 2.2rem; 87 | margin: 0 auto !important; 88 | } 89 | .odd { 90 | background-color: #FBE38E; 91 | } 92 | .even { 93 | background-color: #FBEEC1; 94 | } 95 | } 96 | 97 | .inline_forms_list, .new_record { 98 | .row.odd, .row.even { 99 | font-size: 1rem !important; 100 | font-weight: normal !important; 101 | } 102 | .row.form_element_header { 103 | border-top: 1px solid #B94C32; 104 | background-color: rgb(239, 202, 75); 105 | font-weight: normal !important; 106 | font-size: 1.3rem !important; 107 | } 108 | } 109 | 110 | .new_record { 111 | .button { 112 | margin: 0; 113 | padding: 0.5rem; 114 | } 115 | } 116 | 117 | .object_presentation { 118 | background-color: #B94C32; 119 | color: white; 120 | .close_button { 121 | background-color: #B94C32; 122 | font-size: 1.3rem; 123 | padding: 0 1rem 0 1rem; 124 | margin: 0; 125 | } 126 | .close_button:hover, .close_button:focus { 127 | background-color: #B94C32; 128 | color: #FBEEC1; 129 | -webkit-transition-property: color; 130 | transition-property: color; 131 | } 132 | } 133 | 134 | .list_container { 135 | .row.odd, .row.even { 136 | font-size: 1rem !important; 137 | font-weight: normal !important; 138 | } 139 | .row.form_element_header { 140 | border-top: 1px solid #B94C32; 141 | background-color: rgb(239, 202, 75); 142 | font-weight: normal !important; 143 | font-size: 1.3rem !important; 144 | } 145 | } 146 | 147 | 148 | 149 | .associated_auto_header { 150 | border-top: 1px solid #B94C32; 151 | .new_button { 152 | background-color: rgb(239, 202, 75); 153 | font-size: 1.5rem; 154 | color: #B94C32; 155 | padding: 0 0.5rem 0 1rem; 156 | margin: 0; 157 | } 158 | .new_button:hover, .new_button:focus { 159 | background-color: rgb(239, 202, 75); 160 | color: white; 161 | -webkit-transition-property: color; 162 | transition-property: color; 163 | } 164 | .close_button { 165 | background-color: rgb(239, 202, 75); 166 | font-size: 1.5rem; 167 | color: #B94C32; 168 | padding: 0 0.5rem 0 1rem; 169 | margin: 0; 170 | } 171 | .close_button:hover, .new_button:focus { 172 | background-color: rgb(239, 202, 75); 173 | color: white; 174 | -webkit-transition-property: color; 175 | transition-property: color; 176 | } 177 | } 178 | 179 | .pagination { 180 | font-weight: normal; 181 | font-size: 0.9em; 182 | a:hover { 183 | color: #B94C32; 184 | -webkit-transition-property: color; 185 | -webkit-transition-duration: 0.3s; 186 | transition-property: color; 187 | transition-duration: 0.3s; 188 | } 189 | em { 190 | color: #B94C32; 191 | font-weight: bold; 192 | font-style: normal; 193 | } 194 | span.disabled { 195 | color: #AAA; 196 | } 197 | } 198 | 199 | .record_footer { 200 | background-color: rgb(239, 202, 75); 201 | height: 0.2em; 202 | border-bottom: 1px solid #B94C32; 203 | margin-bottom: 1.5em; 204 | } 205 | 206 | .custom-combobox { 207 | position: relative; 208 | display: inline-block; 209 | } 210 | .custom-combobox-toggle { 211 | position: absolute; 212 | top: 0; 213 | bottom: 0; 214 | margin-left: -1px; 215 | padding: 0; 216 | /* support: IE7 */ 217 | *height: 1.7em; 218 | *top: 0.1em; 219 | } 220 | .custom-combobox-input { 221 | margin: 0; 222 | padding: 0.3em; 223 | } 224 | 225 | 226 | .column { 227 | padding-right: 0 !important; 228 | } 229 | 230 | .top-bar input, .top-bar .button { 231 | top: 4px !important; 232 | } 233 | 234 | .top-bar-section { 235 | padding-left: rem-calc(12) !important; 236 | padding-right: rem-calc(12) !important; 237 | } 238 | 239 | .first-bar { 240 | margin-bottom: 0 !important; 241 | } 242 | .second-bar { 243 | margin-top: 1px !important; 244 | margin-bottom: 0 !important; 245 | } 246 | 247 | #switch_user_identifier { 248 | font-size: smaller; 249 | select { 250 | width: 5em; 251 | } 252 | } 253 | 254 | .flash { 255 | padding: 0.3em; 256 | color: #A3381E; 257 | font-size: 130%; 258 | font-weight: bold; 259 | line-height: 120%; 260 | background-color: white; 261 | border-top: 0.3em solid #fade7a; 262 | } 263 | 264 | .error { 265 | color: #ffffff; 266 | font-weight: bold; 267 | background-color: #a70f0f; 268 | padding: 0.3em; 269 | margin-bottom: 0.5em; 270 | } 271 | .success { 272 | color: #ffffff; 273 | font-weight: bold; 274 | border-bottom: 1px solid #cccccc; 275 | background-color: #4f8d0d; 276 | padding: 0.3em; 277 | margin-bottom: 0.5em; 278 | } 279 | 280 | .ckeditor_area { 281 | position: relative; 282 | } 283 | 284 | .ckeditor_area .glass_plate { 285 | position: absolute; 286 | top: -1px; 287 | width: 98%; 288 | height: 232px; 289 | border: 0; 290 | } 291 | 292 | .ckeditor_area .cke_top, .ckeditor_area .cke_bottom, .ckeditor_area .cke_border { 293 | display: none; 294 | } 295 | 296 | /* jQuery ui Slider 8 */ 297 | .slider { 298 | width: 300px; 299 | float: left; 300 | } 301 | .slider_value { 302 | float: left; 303 | min-width: 60px; 304 | text-align: right; 305 | font-family: monospace; 306 | } 307 | 308 | 309 | /* LEFT */ 310 | 311 | #category_id { 312 | margin-top: -2px !important; 313 | } 314 | 315 | #input_search { 316 | border: none !important; 317 | margin-top: -2px; 318 | } 319 | 320 | #inline_forms_model_top_bar .top-bar-section .inline_forms_model_top_bar_buttons { 321 | top: 6px !important; 322 | } 323 | -------------------------------------------------------------------------------- /app/controllers/concerns/cancan_concern.rb: -------------------------------------------------------------------------------- 1 | module CancanConcern 2 | extend ActiveSupport::Concern 3 | 4 | included do 5 | helper_method :cancan_disabled?, :cancan_enabled? 6 | end 7 | 8 | class_methods do 9 | def cancan_enabled? 10 | begin 11 | CanCan::Ability && true 12 | rescue NameError 13 | false 14 | end 15 | end 16 | end 17 | 18 | def cancan_enabled? 19 | self.class.cancan_enabled? 20 | end 21 | 22 | def cancan_disabled? 23 | ! self.class.cancan_enabled? 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/controllers/concerns/versions_concern.rb: -------------------------------------------------------------------------------- 1 | module VersionsConcern 2 | extend ActiveSupport::Concern 3 | 4 | included do 5 | before_action :set_paper_trail_whodunnit 6 | end 7 | 8 | def list_versions 9 | @update_span = params[:update] 10 | @object = referenced_object 11 | close = params[:close] || false 12 | if close 13 | respond_to do |format| 14 | format.js { render :versions } 15 | end 16 | else 17 | respond_to do |format| 18 | format.html { } unless @Klass.not_accessible_through_html? 19 | format.js { render :versions_list } 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /app/controllers/geo_code_curacao_controller.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | # Used in autocomplete 3 | # 4 | class GeoCodeCuracaoController < ApplicationController 5 | def list_streets 6 | @term = params[:term] 7 | @streets = GeoCodeCuracao.lookup('%' + @term + '%') 8 | end 9 | 10 | end 11 | -------------------------------------------------------------------------------- /app/controllers/inline_forms_application_controller.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | class InlineFormsApplicationController < ActionController::Base 3 | protect_from_forgery 4 | layout 'devise' if :devise_controller? 5 | 6 | # limit available locales by setting this. Override in applicaton_controller. 7 | I18n.available_locales = [ :en, :nl, :pp ] 8 | 9 | #set the locale based on the subdomain 10 | def set_locale 11 | I18n.locale = extract_locale_from_subdomain || I18n.default_locale 12 | end 13 | 14 | # Get locale code from request subdomain (like http://it.application.local:3000) 15 | def extract_locale_from_subdomain 16 | locale = request.subdomains.first 17 | return nil if locale.nil? 18 | I18n.available_locales.include?(locale.to_sym) ? locale.to_s : nil 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /app/controllers/inline_forms_controller.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | # == Generic controller for the inline_forms plugin. 3 | # === Usage 4 | # If you have an Example class, make an ExampleController 5 | # that is a subclass of InlineFormsController 6 | # class ExampleController < InlineFormsController 7 | # end 8 | # That's it! It'll work. But please read about the InlineForms::InlineFormsGenerator first! 9 | # 10 | # You can override the methods in your ExampleController 11 | # def index 12 | # @objects=@Klass.all 13 | # end 14 | # 15 | # 16 | # @objects holds the objects (in this case Examples) 17 | # and @Klass will be set to Example by the getKlass before filter. 18 | # 19 | # === How it works 20 | # The getKlass before_action extracts the class and puts it in @Klass 21 | # 22 | # @Klass is used in the InlineFormsHelper 23 | # 24 | class InlineFormsController < ApplicationController 25 | include CancanConcern 26 | include VersionsConcern 27 | 28 | before_action :getKlass 29 | 30 | load_and_authorize_resource :except => :revert, :no_params => true if cancan_enabled? 31 | # :index shows a list of all objects from class @Klass, using will_paginate, 32 | # including a link to 'new', that allows you to create a new record. 33 | def index 34 | @update_span = params[:update] 35 | @parent_class = params[:parent_class] 36 | @parent_id = params[:parent_id] 37 | @ul_needed = params[:ul_needed] 38 | # if the parent_class is not nill, we are in associated list and we don't search there. 39 | # also, make sure the Model that you want to do a search on has a :name attribute. TODO 40 | conditions = nil 41 | if @parent_class.nil? || @Klass.reflect_on_association(@parent_class.underscore.to_sym).nil? 42 | conditions = [ @Klass.table_name + "." + @Klass.order_by_clause + " like ?", "%#{params[:search]}%" ] if @Klass.respond_to?(:order_by_clause) && ! @Klass.order_by_clause.nil? 43 | else 44 | foreign_key = @Klass.reflect_on_association(@parent_class.underscore.to_sym).options[:foreign_key] || @parent_class.foreign_key 45 | conditions = [ "#{foreign_key} = ?", @parent_id ] 46 | end 47 | # if we are using cancan, then make sure to select only accessible records 48 | @objects ||= @Klass.accessible_by(current_ability) if cancan_enabled? 49 | @objects ||= @Klass 50 | @objects = @objects.order(@Klass.table_name + "." + @Klass.order_by_clause) if @Klass.respond_to?(:order_by_clause) && ! @Klass.order_by_clause.nil? 51 | @objects = @objects.where(conditions).paginate(:page => params[:page]) 52 | respond_to do |format| 53 | format.html { render 'inline_forms/_list', :layout => 'inline_forms' } unless @Klass.not_accessible_through_html? 54 | format.js { render :list } 55 | end 56 | end 57 | 58 | # :new prepares a new object, updates the list of objects and replaces it with 59 | # an empty form. After pressing OK or Cancel, the list of objects is retrieved 60 | # in the same way as :index 61 | def new 62 | @object ||= @Klass.new 63 | @update_span = params[:update] 64 | @parent_class = params[:parent_class] 65 | begin 66 | @parent_id = params[:parent_id] 67 | foreign_key = @Klass.reflect_on_association(@parent_class.underscore.to_sym).options[:foreign_key] || @parent_class.foreign_key 68 | @object[foreign_key] = @parent_id 69 | end unless @parent_class.nil? || @Klass.reflect_on_association(@parent_class.underscore.to_sym).nil? 70 | 71 | @object.inline_forms_attribute_list = @inline_forms_attribute_list if @inline_forms_attribute_list 72 | respond_to do |format| 73 | format.html { render 'inline_forms/_new', :layout => 'inline_forms' } unless @Klass.not_accessible_through_html? 74 | format.js { } 75 | end 76 | end 77 | 78 | # :edit presents a form to edit one specific attribute from an object 79 | def edit 80 | @object = referenced_object 81 | @attribute = params[:attribute] 82 | @form_element = params[:form_element] 83 | @sub_id = params[:sub_id] 84 | @update_span = params[:update] 85 | respond_to do |format| 86 | format.html { } unless @Klass.not_accessible_through_html? 87 | format.js { } 88 | end 89 | end 90 | 91 | # :create creates the object made with :new. 92 | # It then presents the list of objects. 93 | def create 94 | @object ||= @Klass.new 95 | @update_span = params[:update] 96 | attributes = @inline_forms_attribute_list || @object.inline_forms_attribute_list 97 | attributes.each do | attribute, name, form_element | 98 | send("#{form_element.to_s}_update", @object, attribute) unless form_element == :tree || form_element == :associated || (cancan_enabled? && cannot?(:read, @object, attribute)) 99 | end 100 | @parent_class = params[:parent_class] 101 | @parent_id = params[:parent_id] 102 | # for the logic behind the :conditions see the #index method. 103 | conditions = nil 104 | if @parent_class.nil? || @Klass.reflect_on_association(@parent_class.underscore.to_sym).nil? 105 | conditions = [ @Klass.table_name + "." + @Klass.order_by_clause + " like ?", "%#{params[:search]}%" ] if @Klass.respond_to?(:order_by_clause) && ! @Klass.order_by_clause.nil? 106 | else 107 | foreign_key = @Klass.reflect_on_association(@parent_class.underscore.to_sym).options[:foreign_key] || @parent_class.foreign_key 108 | conditions = [ "#{foreign_key} = ?", @parent_id ] 109 | @object[foreign_key] = @parent_id 110 | end 111 | 112 | if @object.save 113 | flash.now[:success] = t('success', :message => @object.class.model_name.human) 114 | @objects = @Klass 115 | @objects = @Klass.accessible_by(current_ability) if cancan_enabled? 116 | @objects = @objects.order(@Klass.table_name + "." + @Klass.order_by_clause) if @Klass.respond_to?(:order_by_clause) && ! @Klass.order_by_clause.nil? 117 | @objects = @objects.where(conditions).paginate(:page => params[:page]) 118 | @object = nil 119 | respond_to do |format| 120 | format.js { render :list} 121 | end 122 | else 123 | flash.now[:header] = ["Kan #{@object.class.to_s.underscore} niet aanmaken."] 124 | flash.now[:error] = @object.errors.to_a 125 | respond_to do |format| 126 | @object.inline_forms_attribute_list = attributes 127 | format.js { render :new} 128 | end 129 | end 130 | end 131 | 132 | # :update updates a specific attribute from an object. 133 | def update 134 | @object = referenced_object 135 | @attribute = params[:attribute] 136 | @form_element = params[:form_element] 137 | @sub_id = params[:sub_id] 138 | @update_span = params[:update] 139 | send("#{@form_element.to_s}_update", @object, @attribute) 140 | @object.save 141 | respond_to do |format| 142 | format.html { } unless @Klass.not_accessible_through_html? 143 | format.js { } 144 | end 145 | end 146 | 147 | # :show shows one attribute (attribute) from a record (object). 148 | # It includes the link to 'edit' 149 | def show 150 | @object = referenced_object 151 | @attribute = params[:attribute] 152 | @form_element = params[:form_element] 153 | close = params[:close] || false 154 | if @form_element == "associated" 155 | @sub_id = params[:sub_id] 156 | if @sub_id.to_i > 0 157 | @associated_record_id = @object.send(@attribute.to_s.singularize + "_ids").index(@sub_id.to_i) 158 | @associated_record = @object.send(@attribute)[@associated_record_id] 159 | end 160 | end 161 | if @form_element == "has_one" 162 | @associated_record = @object.send(@attribute) 163 | @associated_record_id = @associated_record.id 164 | end 165 | @update_span = params[:update] 166 | if @attribute.nil? 167 | respond_to do |format| 168 | @attributes = @object.inline_forms_attribute_list 169 | if close 170 | format.js { render :close } 171 | else 172 | format.js { } 173 | end 174 | end 175 | else 176 | respond_to do |format| 177 | format.html { } unless @Klass.not_accessible_through_html? 178 | format.js { render :show_element } 179 | end 180 | end 181 | end 182 | 183 | # :soft_delete 184 | def soft_delete 185 | @update_span = params[:update] 186 | @object = referenced_object 187 | # destroy the object 188 | @object.soft_delete(current_user) 189 | respond_to do |format| 190 | format.html { } unless @Klass.not_accessible_through_html? 191 | format.js { render :close } 192 | end 193 | end 194 | 195 | # :soft_restore 196 | def soft_restore 197 | @update_span = params[:update] 198 | @object = referenced_object 199 | # restore the object 200 | @object.soft_restore 201 | respond_to do |format| 202 | format.html { } unless @Klass.not_accessible_through_html? 203 | format.js { render :close } 204 | end 205 | end 206 | 207 | # :destroy destroys the record. There is no undo! 208 | def destroy 209 | @update_span = params[:update] 210 | @object = referenced_object 211 | if current_user.role? :superadmin 212 | # destroy the object 213 | @undo_object = @object.versions.last 214 | @object.destroy 215 | respond_to do |format| 216 | format.html { } unless @Klass.not_accessible_through_html? 217 | format.js { render :record_destroyed } 218 | end 219 | end 220 | end 221 | 222 | # :revert works like undo. 223 | # Thanks Ryan Bates: http://railscasts.com/episodes/255-undo-with-paper-trail 224 | def revert 225 | @update_span = params[:update] 226 | @object = referenced_object 227 | if current_user.role? :superadmin 228 | @version = PaperTrail::Version.find(params[:id]) 229 | @version.reify.save! 230 | @object = @Klass.find(@version.item_id) 231 | authorize!(:revert, @object) if cancan_enabled? 232 | respond_to do |format| 233 | format.html { } unless @Klass.not_accessible_through_html? 234 | format.js { render :close } 235 | end 236 | end 237 | end 238 | 239 | def extract_translations 240 | keys_array = [] 241 | I18n::Backend::ActiveRecord::Translation.order(:locale, :thekey).each do |t| 242 | keys_array << deep_hashify([ t.locale, t.thekey.split('.'), t.value ].flatten) 243 | end 244 | keys_hash = {} 245 | keys_array.each do |h| 246 | keys_hash = deep_merge(keys_hash, h) 247 | end 248 | @display_array = unravel(keys_hash) 249 | end 250 | 251 | private 252 | # Get the class from the controller name. 253 | # CountryController < InlineFormsController, so what class are we? 254 | # TODO think about this a bit more. 255 | def getKlass #:doc: 256 | @Klass = self.controller_name.classify.constantize 257 | @Klass 258 | end 259 | 260 | def referenced_object 261 | @Klass.find(object_id_params) 262 | end 263 | 264 | def object_id_params 265 | params.require(:id) 266 | end 267 | 268 | def deep_hashify(ary) 269 | return ary.to_s if ary.length == 1 270 | { ary.shift => deep_hashify(ary) } 271 | end 272 | 273 | def deep_merge(h1, h2) 274 | return h1.merge(h2) unless h2.first[1].is_a? Hash 275 | h1.merge(h2){|key, first, second| deep_merge(first, second)} 276 | end 277 | 278 | def unravel(deep_hash, level=-1) 279 | level += 1 280 | return "#{' '*level}\"#{deep_hash.first[0]}\": \"#{deep_hash.first[1]}\"\n" unless deep_hash.first[1].is_a? Hash 281 | a = "#{' '*level}\"#{deep_hash.first[0]}\":\n" 282 | deep_hash.first[1].each do |k,v| 283 | a << unravel( { k => v}, level) 284 | end 285 | a 286 | end 287 | 288 | def revert_params 289 | params.require(:id).permit(:update) 290 | end 291 | 292 | end 293 | -------------------------------------------------------------------------------- /app/helpers/form_elements/absence_list.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | #InlineForms::SPECIAL_COLUMN_TYPES[:absence_list]=:no_migration 3 | 4 | # checklist 5 | def absence_list_show(object, attribute) # the object is the lesson, attribute should be absences??? 6 | absence_status = { 1 => 'aanwezig', 3 => 'laat met reden', 4 => 'laat' , 5 => 'afwezig met reden', 6 => 'afwezig' } 7 | out = '
82 | # 83 | # 84 | #
85 | # 86 | # 87 | # 88 | #84 | # 85 | # 86 | #
87 | # 88 | # 89 | # 90 | #
4 | Create the file
5 | app/views/devise/inline_forms/_content_for_devise_login.html.erb
6 | and the contents will be displayed here.
7 |
9 | Change application title, title_for_devise, welcome_for_devise in
10 | config/locales/inline_forms.en.yml
11 |
If you do, just type in your new password and confirm it.
3 | -------------------------------------------------------------------------------- /app/views/devise/inline_forms/_content_for_passwords_new.html.erb: -------------------------------------------------------------------------------- 1 |3 | We will send you instructions on how to change your password. 4 |
5 |6 | Just provide your email address and press 'send instructions'! 7 |
8 | -------------------------------------------------------------------------------- /app/views/devise/passwords/_top-bar-and-flash.html.erb: -------------------------------------------------------------------------------- 1 |<%= attribute %> | 62 |63 | | |
---|---|---|
old value | 66 |new value | 67 ||
<%= value[0] %> | 70 |<%= value[1] %> | 71 |
3 | <%= @display_array%> 4 |-------------------------------------------------------------------------------- /app/views/inline_forms/list.js.erb: -------------------------------------------------------------------------------- 1 | $('#<%= @update_span %>').html('<%= escape_javascript(render(:partial => 'inline_forms/list' ))%>') 2 | -------------------------------------------------------------------------------- /app/views/inline_forms/new.js.erb: -------------------------------------------------------------------------------- 1 | $('#<%= @update_span %>').html('<%= escape_javascript(render(:partial => 'inline_forms/new' ))%>') 2 | -------------------------------------------------------------------------------- /app/views/inline_forms/record_destroyed.js.erb: -------------------------------------------------------------------------------- 1 | $('#<%= @update_span %>').fadeOut("slow") 2 | -------------------------------------------------------------------------------- /app/views/inline_forms/show.js.erb: -------------------------------------------------------------------------------- 1 | $('#<%= @update_span %>').html('<%= escape_javascript(render(:partial => 'inline_forms/show' ))%>') 2 | -------------------------------------------------------------------------------- /app/views/inline_forms/show_element.js.erb: -------------------------------------------------------------------------------- 1 | $('#<%= @update_span %>').html('<%= escape_javascript(send("#{@form_element}_show", @object, @attribute))%>') 2 | -------------------------------------------------------------------------------- /app/views/inline_forms/show_undo.js.erb: -------------------------------------------------------------------------------- 1 | $('#<%= @update_span %>').html('<%= escape_javascript(link_to t('inline_forms.view.undo'), send('revert_' + @object.class.to_s.underscore + "_path", @object.versions.scope.last, :update => @update_span), :remote => true, :method => :post)%>') 2 | -------------------------------------------------------------------------------- /app/views/inline_forms/update.js.erb: -------------------------------------------------------------------------------- 1 | $('#<%= @update_span %>').html('<%= escape_javascript(send("#{@form_element.to_s}_show", @object, @attribute))%>') 2 | -------------------------------------------------------------------------------- /app/views/inline_forms/versions.js.erb: -------------------------------------------------------------------------------- 1 | $('#<%= @update_span %>').fadeOut("slow", function() { 2 | $(this).html('<%= escape_javascript(render(:partial => 'inline_forms/versions' ))%>'); 3 | $(this).fadeIn("slow"); 4 | }); 5 | -------------------------------------------------------------------------------- /app/views/inline_forms/versions_list.js.erb: -------------------------------------------------------------------------------- 1 | $('#<%= @update_span %>').html('<%= escape_javascript(render(:partial => 'inline_forms/versions_list' ))%>') 2 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |