diff --git a/README.md b/README.md index b5bc082..cfb5a96 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,46 @@ ## Installation -Add this line to your application's Gemfile: - ```ruby gem 'ouvrages_block' ``` -And then execute: +Append your `application.js` with: + +```js +# app/assets/javascripts/application.js - $ bundle +//= require ouvrages_block +``` -Or install it yourself as: +And import css too. - $ gem install ouvrages_block +```css +# app/assets/stylesheets.scss + +@import 'ouvrages_block'; +``` + +In model you want use `block`: + +```rb +# model.rb + +has_blocks([:block]) +``` + +In form: + +```slim += bootstrap_form_for ... do |f| + = f.blocks_form +``` + +You can generate new block with: + +```sh +rails generate block Name +``` ## Standard blocks @@ -23,8 +50,3 @@ Or install it yourself as: - standard_block_rich_text - standard_block_medium_collection -## Development - -## Contributing - -## License diff --git a/app/assets/javascripts/ouvrages_block.js b/app/assets/javascripts/ouvrages_block.js index 21b73dd..bd85fdc 100644 --- a/app/assets/javascripts/ouvrages_block.js +++ b/app/assets/javascripts/ouvrages_block.js @@ -1,33 +1,32 @@ -//= require scrollTo +//= require jquery +//= require bootstrap-sprockets +//= require sortable-rails-jquery +//= require tinymce-jquery +//= require jquery-fileupload -$(document).on("click", ".collapse-block-buttons", function(e) { +$(document).on("click", ".block-button", function(e) { e.preventDefault(); - - var $button = $(this); - var $buttons = $button.closest(".block-buttons-group").find(".block-button"); - $button.closest(".list-group").find(".block-button").not($buttons).addClass("hide"); - $buttons.toggleClass("hide"); -}); + var $button = $(this); + var $buttonWrapper = $button.closest(".block-form"); + var $blockForms = $button.closest(".ouvrages-blocks").find(".block-forms"); + var buttonsHTML = $blockForms.data("buttons").html; -$(document).on("click", ".block-buttons .block-button", function(e) { - e.preventDefault(); + var $newBlock = generateBlockForm($button, buttonsHTML); - var $button = $(this); + $(this).closest(".collapse").collapse('hide'); - var $newBlock = generateBlockForm($button); - $(".block-forms").append($newBlock); + if ($buttonWrapper.length === 0) { + $blockForms.append($newBlock); + } else { + $newBlock.insertBefore($buttonWrapper); + } updateBlockFormPositions(); $(document).trigger("blocks:add", $newBlock); - - $(document).scrollTo($newBlock, { - offset: $newBlock.outerHeight(), - duration: 500 - }); }); -generateBlockForm = function(button) { +generateBlockForm = function(button, buttonsHTML) { var $button = $(button); var formData = $button.data("form").html; var blocksCount = $(".block-form").length; @@ -35,7 +34,9 @@ generateBlockForm = function(button) { formData = formData.replace(/\[__.+?__\]/g, "[" + blocksCount + "]"); formData = formData.replace(/___NEW__.+?___/g, "_" + blocksCount + "_"); - return $("
" + formData + "
"); + buttonsHTML = buttonsHTML.replace(/__ID__/g, "_" + blocksCount + "_"); + + return $("
" + buttonsHTML + "
" + formData + "
"); }; updateBlockFormPositions = function() { @@ -46,17 +47,6 @@ updateBlockFormPositions = function() { }; createSortable = function() { - $(".block-buttons .list-group .block-buttons-group").sortable({ - group: { - name: "forms", - pull: 'clone', - put: false, - }, - filter: ".collapse-block-buttons", - sort: false, - animation: 150, - }); - $(".block-forms").sortable({ group: { name: "forms", @@ -95,6 +85,9 @@ $.fn.initRichTextareas = function() { $(document).on("blocks:add", function(e, block) { $(block).initRichTextareas(); + $(block).find(".address_picker").each(function(index, element) { + $(element).addressPickerField(); + }); createSortable(); }); @@ -106,19 +99,16 @@ $(document).on("blocks:move", function(e, block) { $(block).initRichTextareas(); }); -$(document).on('turbolinks:before-render', function() { +$(document).on('turbolinks:before-cache', function() { + $(".address_picker").each(function(index, element) { + $(this).find(".address").typeahead("destroy"); + }); tinyMCE.remove(); }); $(document).on('turbolinks:load', function() { $(document.body).initRichTextareas(); createSortable(); - - $("#block-buttons-inner-affix").affix({ - bottom: function() { - return (this.bottom = $(".block-forms").outerHeight() - $("#block-buttons-inner-affix").height()); - }, - }) }); $(document).on("click", ".remove-block-form-button", function(e) { @@ -151,7 +141,11 @@ $(document).on("click", ".collapse-block-form-button", function(e) { } }); +$(document).on("show.bs.collapse", ".block-buttons", function(e) { + $(e.currentTarget).find(".blocks-toggle i").removeClass("glyphicon-plus").addClass("glyphicon-chevron-up"); +}); -$(window).on("scroll", function(e) { - $("#block-buttons-inner-affix.affix").css("top", $(window).height() - $("#block-buttons-inner-affix").outerHeight() + "px"); +$(document).on("hide.bs.collapse", ".block-buttons", function(e) { + $(e.currentTarget).find(".blocks-toggle i").removeClass("glyphicon-chevron-up").addClass("glyphicon-plus"); }); + diff --git a/app/assets/stylesheets/ouvrages_block.css b/app/assets/stylesheets/ouvrages_block.css deleted file mode 100644 index 0245f01..0000000 --- a/app/assets/stylesheets/ouvrages_block.css +++ /dev/null @@ -1,4 +0,0 @@ -.block-deleted, -.sortable-ghost { - opacity: 0.6; -} diff --git a/app/assets/stylesheets/ouvrages_block.scss b/app/assets/stylesheets/ouvrages_block.scss new file mode 100644 index 0000000..15be8ba --- /dev/null +++ b/app/assets/stylesheets/ouvrages_block.scss @@ -0,0 +1,30 @@ +@import 'bootstrap-sprockets'; +@import 'bootstrap'; + +.block-deleted, +.sortable-ghost { + opacity: 0.6; +} + +.btn-circle { + width: 30px; + height: 30px; + text-align: center; + padding: 6px 0; + font-size: 12px; + line-height: 30px; + border-radius: 15px; +} + +.blocks-toggle { + margin-bottom: 10px; +} + +.block-buttons { + padding-bottom: 10px; +} + +.block-panel { + margin-bottom: 10px; +} + diff --git a/app/views/admin/blocks/_blocks_form.html.haml b/app/views/admin/blocks/_blocks_form.html.haml deleted file mode 100644 index a0eac88..0000000 --- a/app/views/admin/blocks/_blocks_form.html.haml +++ /dev/null @@ -1,33 +0,0 @@ -%h3= form.object.class.human_attribute_name(:blocks) - -.row - .block-forms{class: options[:block_left_class] } - - form.object.blocks.each do |block| - .block-form.panel.panel-primary= form.block_form block - - .block-buttons{class: options[:block_right_class] } - #block-buttons-inner-affix.affix-top - - if form.object.block_buttons.is_a?(Hash) - .list-group - - form.object.block_buttons.each do |group_name, block_names| - .block-buttons-group - %button.list-group-item.collapse-block-buttons= group_name - - block_names.each do |block_name| - - new_block = form.block_form block_name.to_s.singularize.classify.constantize.new, template: true - - new_block = new_block.html_safe - %button.block-button.list-group-item{data: { form: { html: new_block }.to_json }, type: "button", class: form.object.block_buttons.keys.size > 1 ? "hide" : nil} - .pull-left - %span.glyphicon.glyphicon-plus - = block_name.to_s.classify.constantize.model_name.human - - - else - .list-group - .block-buttons-group - - form.object.block_buttons.each do |block_name| - - new_block = form.block_form block_name.to_s.singularize.classify.constantize.new, template: true - - new_block = new_block.html_safe - %button.block-button.list-group-item{data: { form: { html: new_block }.to_json }, type: "button"} - .pull-left - %span.glyphicon.glyphicon-plus - = block_name.to_s.classify.constantize.model_name.human - diff --git a/app/views/admin/blocks/_block_form.html.haml b/app/views/blocks/_block_form.html.slim similarity index 73% rename from app/views/admin/blocks/_block_form.html.haml rename to app/views/blocks/_block_form.html.slim index 6ecf4d3..dac32a9 100644 --- a/app/views/admin/blocks/_block_form.html.haml +++ b/app/views/blocks/_block_form.html.slim @@ -4,9 +4,9 @@ .panel-title = block_name.to_s.classify.constantize.model_name.human .pull-right - %span.glyphicon.glyphicon-minus.collapse-block-form-button - %span.glyphicon.glyphicon-trash.remove-block-form-button - %span.glyphicon.glyphicon-resize-vertical.handler + span.glyphicon.glyphicon-minus.collapse-block-form-button + span.glyphicon.glyphicon-trash.remove-block-form-button + span.glyphicon.glyphicon-resize-vertical.handler .panel-body.collapse.in = form.fields_for block_name, block, child_index: index do |t| = t.hidden_field :id, value: block.id diff --git a/app/views/blocks/_blocks_form.html.slim b/app/views/blocks/_blocks_form.html.slim new file mode 100644 index 0000000..b1076fd --- /dev/null +++ b/app/views/blocks/_blocks_form.html.slim @@ -0,0 +1,10 @@ +h3= form.object.class.human_attribute_name(:blocks) + +.ouvrages-blocks + - buttons = render partial: "blocks/buttons", locals: { id: "___ID___", form: form } + .block-forms(data={ buttons: { html: buttons }.to_json }) + - form.object.blocks.each do |block| + .block-form + = render partial: "blocks/buttons", locals: { id: "#{block.class.name.parameterize}-#{block.id}", form: form } + .panel.panel-primary.block-panel= form.block_form block + = render partial: "blocks/buttons", locals: { id: "all", form: form } diff --git a/app/views/blocks/_buttons.html.slim b/app/views/blocks/_buttons.html.slim new file mode 100644 index 0000000..7520ddc --- /dev/null +++ b/app/views/blocks/_buttons.html.slim @@ -0,0 +1,9 @@ +.block-buttons.text-center(data={ target: id }) + button.blocks-toggle.btn.btn-default.btn-circle(type="button" data={ toggle: "collapse", target: "#buttons-#{id}" } title="Ajouter un block") + i.glyphicon.glyphicon-plus + .collapse(id="buttons-#{id}") + - form.object.block_buttons.each do |block_name| + - new_block = form.block_form block_name.to_s.singularize.classify.constantize.new, template: true + - new_block = new_block.html_safe + button.btn.btn-default(data={ form: { html: new_block }.to_json, id: id } type="button" class="block-button") + = block_name.to_s.classify.constantize.model_name.human diff --git a/lib/generators/block/block_generator.rb b/lib/generators/block/block_generator.rb index 5bdd50c..bb7a485 100644 --- a/lib/generators/block/block_generator.rb +++ b/lib/generators/block/block_generator.rb @@ -31,8 +31,8 @@ def create_locale_files end def create_view_files - template "views/admin.html.haml", File.join("app", "views", "admin", standard_block_name_plural, "_block_form.html.haml") - template "views/show.html.haml", File.join("app", "views", standard_block_name_plural, "_#{standard_block_name_singular}.html.haml") + template "views/admin.html.slim", File.join("app", "views", "admin", standard_block_name_plural, "_block_form.html.slim") + template "views/show.html.slim", File.join("app", "views", standard_block_name_plural, "_#{standard_block_name_singular}.html.slim") end private @@ -52,4 +52,28 @@ def standard_block_name_singular def standard_block_name_plural standard_block_name_singular.pluralize end + + def standard_block_class_name + standard_block_name_singular.camelize + end + + def standard_block_migration_name + standard_block_name_plural.camelize + end + + def migration_class_name + if Rails::VERSION::MAJOR >= 5 + "ActiveRecord::Migration[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]" + else + 'ActiveRecord::Migration' + end + end + + def model_class_name + if Rails::VERSION::MAJOR >= 5 + "ApplicationRecord" + else + "ActiveRecord::Base" + end + end end diff --git a/lib/generators/block/templates/migrations/migration.rb b/lib/generators/block/templates/migrations/migration.rb index 020dfa2..7bb42e7 100644 --- a/lib/generators/block/templates/migrations/migration.rb +++ b/lib/generators/block/templates/migrations/migration.rb @@ -1,4 +1,4 @@ -class Create<%= standard_block_name_plural.capitalize %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>] +class Create<%= standard_block_migration_name %> < <%= migration_class_name %> def up create_table :<%= standard_block_name_plural %> do |t| t.references :parent, polymorphic: true diff --git a/lib/generators/block/templates/models/model.rb.erb b/lib/generators/block/templates/models/model.rb.erb index be805b4..f7cafa6 100644 --- a/lib/generators/block/templates/models/model.rb.erb +++ b/lib/generators/block/templates/models/model.rb.erb @@ -1,4 +1,4 @@ -class <%= standard_block_name_singular.capitalize %> < ApplicationRecord +class <%= standard_block_class_name %> < <%= model_class_name %> belongs_to :parent, polymorphic: true def self.permitted_attributes diff --git a/lib/generators/block/templates/views/admin.html.haml b/lib/generators/block/templates/views/admin.html.slim similarity index 100% rename from lib/generators/block/templates/views/admin.html.haml rename to lib/generators/block/templates/views/admin.html.slim diff --git a/lib/generators/block/templates/views/show.html.haml b/lib/generators/block/templates/views/show.html.slim similarity index 100% rename from lib/generators/block/templates/views/show.html.haml rename to lib/generators/block/templates/views/show.html.slim diff --git a/lib/generators/standard_block_rich_text/standard_block_rich_text_generator.rb b/lib/generators/standard_block_rich_text/standard_block_rich_text_generator.rb index 85fd510..7d9c0e6 100644 --- a/lib/generators/standard_block_rich_text/standard_block_rich_text_generator.rb +++ b/lib/generators/standard_block_rich_text/standard_block_rich_text_generator.rb @@ -30,8 +30,8 @@ def create_locale_files end def create_view_files - template "views/admin.html.haml", File.join("app", "views", "admin", standard_block_name_plural, "_block_form.html.haml") - template "views/show.html.haml", File.join("app", "views", standard_block_name_plural, "_#{standard_block_name_singular}.html.haml") + template "views/admin.html.slim", File.join("app", "views", "admin", standard_block_name_plural, "_block_form.html.slim") + template "views/show.html.slim", File.join("app", "views", standard_block_name_plural, "_#{standard_block_name_singular}.html.slim") end private @@ -51,4 +51,28 @@ def standard_block_name_singular def standard_block_name_plural "rich_texts" end + + def standard_block_class_name + standard_block_name_singular.camelize + end + + def standard_block_migration_name + standard_block_name_plural.camelize + end + + def migration_class_name + if Rails::VERSION::MAJOR >= 5 + "ActiveRecord::Migration[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]" + else + 'ActiveRecord::Migration' + end + end + + def model_class_name + if Rails::VERSION::MAJOR >= 5 + "ApplicationRecord" + else + "ActiveRecord::Base" + end + end end diff --git a/lib/generators/standard_block_rich_text/templates/migrations/migration.rb b/lib/generators/standard_block_rich_text/templates/migrations/migration.rb index 970bd2f..146f3e0 100644 --- a/lib/generators/standard_block_rich_text/templates/migrations/migration.rb +++ b/lib/generators/standard_block_rich_text/templates/migrations/migration.rb @@ -1,4 +1,4 @@ -class CreateRichTexts < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>] +class Create<%= standard_block_migration_name %> < <%= migration_class_name %> def up create_table :rich_texts do |t| t.references :parent, polymorphic: true @@ -8,4 +8,8 @@ def up t.timestamps end end + + def down + drop_table :<%= standard_block_name_plural %> + end end diff --git a/lib/generators/standard_block_rich_text/templates/models/rich_text.rb.erb b/lib/generators/standard_block_rich_text/templates/models/rich_text.rb.erb index 3f4a58e..4e0486f 100644 --- a/lib/generators/standard_block_rich_text/templates/models/rich_text.rb.erb +++ b/lib/generators/standard_block_rich_text/templates/models/rich_text.rb.erb @@ -1,4 +1,4 @@ -class RichText < ApplicationRecord +class <%= standard_block_class_name %> < <%= model_class_name %> belongs_to :parent, polymorphic: true def self.permitted_attributes diff --git a/lib/generators/standard_block_rich_text/templates/views/admin.html.haml b/lib/generators/standard_block_rich_text/templates/views/admin.html.slim similarity index 100% rename from lib/generators/standard_block_rich_text/templates/views/admin.html.haml rename to lib/generators/standard_block_rich_text/templates/views/admin.html.slim diff --git a/lib/generators/standard_block_rich_text/templates/views/show.html.haml b/lib/generators/standard_block_rich_text/templates/views/show.html.slim similarity index 100% rename from lib/generators/standard_block_rich_text/templates/views/show.html.haml rename to lib/generators/standard_block_rich_text/templates/views/show.html.slim diff --git a/lib/ouvrages_block.rb b/lib/ouvrages_block.rb index d3434f7..b4d9873 100644 --- a/lib/ouvrages_block.rb +++ b/lib/ouvrages_block.rb @@ -1,67 +1,5 @@ -require 'active_record' -require "bootstrap_form/form_builder" - require "ouvrages_block/version" -require "ouvrages_block/block_field" - -require "scrollto-rails" module OuvragesBlock - - module Rails - class Engine < ::Rails::Engine - end - end - - extend ActiveSupport::Concern - class_methods do - def has_blocks(block_names) - if block_names.is_a?(Hash) - names = block_names.values.flatten - else - names = block_names - end - - names.each do |block_name| - has_many block_name, dependent: :destroy, as: :parent, inverse_of: :parent - accepts_nested_attributes_for block_name, allow_destroy: true - end - - define_singleton_method "block_permitted_attributes" do - names.map do |block_name| - { "#{block_name}_attributes" => block_name.to_s.singularize.classify.constantize.permitted_attributes } - end - end - - define_method "blocks" do - names.map do |block_name| - send(block_name) - end.flatten.sort_by { |block| block.position || 0 } - end - - define_method "block_names" do - names - end - - define_method "block_buttons" do - if block_names.is_a?(Hash) - block_names - else - names - end - end - end - end -end - -ActiveRecord::Base.send(:include, OuvragesBlock) - -module BootstrapFormBlockField - include BlockField -end - -module BootstrapForm - class FormBuilder - include BootstrapFormBlockField - end + require "ouvrages_block/engine" if defined?(Rails) end diff --git a/lib/ouvrages_block/block.rb b/lib/ouvrages_block/block.rb new file mode 100644 index 0000000..d509492 --- /dev/null +++ b/lib/ouvrages_block/block.rb @@ -0,0 +1,45 @@ +module OuvragesBlock + module Block + extend ActiveSupport::Concern + class_methods do + def has_blocks(block_names) + if block_names.is_a?(Hash) + names = block_names.values.flatten + else + names = block_names + end + + names.each do |block_name| + has_many block_name, dependent: :destroy, as: :parent, inverse_of: :parent + accepts_nested_attributes_for block_name, allow_destroy: true + end + + define_singleton_method "block_permitted_attributes" do + names.map do |block_name| + { "#{block_name}_attributes" => block_name.to_s.singularize.classify.constantize.permitted_attributes } + end + end + + define_method "blocks" do + names.map do |block_name| + send(block_name) + end.flatten.sort_by { |block| block.position || 0 } + end + + define_method "block_names" do + names + end + + define_method "block_buttons" do + if block_names.is_a?(Hash) + block_names + else + names + end + end + end + end + end +end + + diff --git a/lib/ouvrages_block/block_field.rb b/lib/ouvrages_block/block_field.rb index 30914cc..a6e0ac2 100644 --- a/lib/ouvrages_block/block_field.rb +++ b/lib/ouvrages_block/block_field.rb @@ -1,6 +1,6 @@ module BlockField - def blocks_form(method = nil, options = { block_left_class: "col-xs-10", block_right_class: "col-xs-2" }) - @template.render partial: "admin/blocks/blocks_form", locals: { form: self, options: options} + def blocks_form(method = nil) + @template.render partial: "blocks/blocks_form", locals: { form: self } end def block_form(block, options = {}) @@ -12,6 +12,6 @@ def block_form(block, options = {}) index = nil end - @template.render partial: "admin/blocks/block_form", locals: { form: self, block: block, index: index } + @template.render partial: "blocks/block_form", locals: { form: self, block: block, index: index } end end diff --git a/lib/ouvrages_block/engine.rb b/lib/ouvrages_block/engine.rb new file mode 100644 index 0000000..c9eab39 --- /dev/null +++ b/lib/ouvrages_block/engine.rb @@ -0,0 +1,26 @@ +require "sass-rails" +require "jquery-rails" +require "bootstrap-sass" +require "sortable/rails" +require "tinymce-rails" +require "tinymce-rails-langs" +require "jquery-fileupload-rails" + +module OuvragesBlock + class Engine < Rails::Engine + ActiveSupport.on_load(:active_record) do + require 'ouvrages_block/block' + include OuvragesBlock::Block + end + end +end + +require "bootstrap_form" +require "bootstrap_form/form_builder" +require "ouvrages_block/block_field" + +module BootstrapForm + class FormBuilder + include BlockField + end +end diff --git a/lib/ouvrages_block/version.rb b/lib/ouvrages_block/version.rb index e5928ef..50cc3bd 100644 --- a/lib/ouvrages_block/version.rb +++ b/lib/ouvrages_block/version.rb @@ -1,3 +1,3 @@ module OuvragesBlock - VERSION = "0.1.1" + VERSION = "2.0.0" end diff --git a/ouvrages_block.gemspec b/ouvrages_block.gemspec index fadfba5..78eaa03 100644 --- a/ouvrages_block.gemspec +++ b/ouvrages_block.gemspec @@ -30,10 +30,13 @@ Gem::Specification.new do |spec| spec.add_development_dependency "bundler", "~> 1.11" spec.add_development_dependency "rake", "~> 10.0" - spec.add_runtime_dependency "activerecord", "~> 5.0" - spec.add_runtime_dependency "bootstrap_form", '>= 2.5.2' - spec.add_runtime_dependency "scrollto-rails" + spec.add_runtime_dependency "activerecord", ">= 4.0" + spec.add_runtime_dependency "sass-rails" + spec.add_runtime_dependency "bootstrap-sass" + spec.add_runtime_dependency "bootstrap_form", '>= 2.3.0' + spec.add_runtime_dependency "jquery-rails" spec.add_runtime_dependency "sortable-rails" spec.add_runtime_dependency "tinymce-rails" + spec.add_runtime_dependency "tinymce-rails-langs" spec.add_runtime_dependency "jquery-fileupload-rails" end