Last active
October 7, 2018 12:15
-
-
Save tomasc/6cefaa701702f0126b70b2b04cbd7926 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Modulor | |
module ResourceSelect | |
class BaseController < ApplicationController | |
def index | |
authorize! :read, resource_class | |
respond_to do |format| | |
format.json do | |
render json: collection_query, | |
serializer: ActiveModel::Serializer::CollectionSerializer, | |
each_serializer: serializer_class | |
end | |
end | |
end | |
private | |
def collection_query | |
raise NotImplementedError, 'controller has to defined collection_query' | |
end | |
def resource_class | |
raise NotImplementedError, 'controller has to defined resource_class' | |
end | |
def serializer_class | |
raise NotImplementedError, 'controller has to defined serializer_class' | |
end | |
def filter_params | |
permitted_attributes = %i() | |
params.permit(*permitted_attributes) | |
end | |
def query | |
params.permit(:query)[:query] | |
end | |
def max_options | |
params.permit(:max_options)[:max_options] | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Modulor | |
module ResourceSelect | |
class BaseSerializer < ApplicationSerializer | |
attribute :class_name do | |
object.model_name.to_s | |
end | |
attribute :class_name_human do | |
object.model_name.human | |
end | |
end | |
end | |
endp |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Modulor | |
module ResourceSelect | |
class CrudResourcesController < BaseController | |
private | |
def collection_query | |
Modulor::ResourceSelect::CrudResourcesQuery.call( | |
resource_class.accessible_by(current_ability), | |
{ search_results: search_results }.merge(filter_params.to_h) | |
) | |
end | |
def search_results | |
@search_results ||= Modulor::ResourceSelect::CrudResourcesSearch.call( | |
resource_class, | |
query, | |
{ | |
ability: current_ability, | |
search_size: max_options | |
}.merge(filter_params.to_h) | |
) | |
end | |
def resource_class | |
resource_class_name.constantize | |
end | |
def resource_class_name | |
params[:resource_class_name] | |
end | |
def serializer_class | |
Modulor::ResourceSelect::CrudResourcesSerializer | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Modulor | |
module ResourceSelect | |
class CrudResourcesSerializer < BaseSerializer | |
attribute :to_s do | |
object.to_s | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default class ResourceSelectInput extends Modulor.Plugin | |
@defaults = | |
debug: false | |
@selector: "input" + "bems(modulor_resource_select_input)" | |
on_init: -> | |
selectize = await `import('selectize/dist/js/standalone/selectize.js' /* webpackChunkName: "selectize" */)` | |
@Handlebars = await `import('handlebars/dist/handlebars.min.js' /* webpackChunkName: "handlebars" */)` | |
console.error('missing options data') unless !!@get_options() | |
console.error('missing value field') unless !!@get_value_field() | |
console.error('missing rendering template') unless !!@get_rendering_template() | |
@$element.selectize | |
create: false | |
dropdownParent: 'body' # so that the dropdown can go out of modal dialog | |
delimiter: ' ' | |
options: @get_options() | |
maxItems: @get_max_items() | |
maxOptions: @get_max_options() | |
plugins: @get_selectize_plugins() | |
valueField: @get_value_field() | |
render: | |
item: (item, escape) => @get_rendering_template()(item) | |
option: (item, escape) => @get_rendering_template()(item) | |
score: (query) -> (item) -> 1 | |
load: (query, callback) => | |
return callback() unless !!@get_path() | |
return callback() unless !!query.length | |
$.ajax | |
dataType: 'json' | |
data: | |
query: encodeURIComponent(query) | |
max_options: @get_max_options() | |
resource_class_name: @get_resource_class_name() | |
resource_class_names: @get_resource_class_names() | |
url: @get_path() | |
type: 'GET' | |
error: -> callback() | |
success: (res) => | |
instance = @get_instance() | |
# clear options | |
instance.options = instance.sifter.items = {} | |
callback(res['data']) | |
on_destroy: -> | |
if !!@get_instance() | |
@$element.selectize('destroy') | |
# --------------------------------------------------------------------- | |
set_resource_class_name: (resource_class_name) -> | |
return if resource_class_name == @get_resource_class_name() | |
if !!@get_instance() | |
@get_instance().clearCache() | |
@get_instance().clearOptions() | |
@$element.data 'resource-class-name', resource_class_name | |
# --------------------------------------------------------------------- | |
get_instance: -> @element.selectize | |
get_options: -> @$element.data('options').data | |
get_max_items: -> @$element.data('max-items') | |
get_max_options: -> @$element.data('max-options') | |
get_path: -> @$element.data('path') | |
get_rendering_template: -> @Handlebars.compile(@$element.data('rendering-template'), noEscape: true) | |
get_resource_class_name: -> @$element.data('resource-class-name') | |
get_resource_class_names: -> @$element.data('resource-class-names') | |
get_selectize_plugins: -> @$element.data('selectize-plugins') | |
get_value_field: -> @$element.data('value-field') | |
ResourceSelectInput.register() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# = form.input :page, as: :resource_select | |
# | |
# Options: | |
# input_html: { | |
# max_items: 1, # max number of items that can be selected | |
# max_options: 5, # max number options to be displayed in the dropdown | |
# options: [], # JSON data of the available options | |
# path: modulor.modulor_resource_select_pages_path, # path to JSON endpoint providing available options based on `query` param | |
# relation_name: … | |
# relation_is_many: … # inferred from the relation by default | |
# rendering_template: '<div>{{attributes.title}}</div>' # Handlebars template displayed in dropdown | |
# resource_class_name: %w(Modulor::Page) # base class name | |
# resource_class_names: %w(ExhibitionPage CoursePage) # filter class names | |
# selectize_plugins: %w(restore_on_backspace remove_button) | |
# serializer_class_name: … | |
# value_field: 'id', # value of which get sent to the server | |
# } | |
class ResourceSelectInput < SimpleForm::Inputs::Base | |
concerning :Tags do | |
def input(_wrapper_options) | |
@builder.text_field( | |
relation_attribute_name, | |
merged_input_html_options.except( | |
:options, :path, :max_options, :rendering_template, :plugins, :value_field, :resource_class_name | |
) | |
).html_safe | |
end | |
private | |
def merged_input_html_options | |
input_html_options.tap do |options| | |
merged_classes = options.fetch(:class, []).concat(dom_classes) | |
merged_data = options.fetch(:data, {}).deep_merge(dom_data) | |
options[:class] = merged_classes | |
options[:data] = merged_data | |
end | |
end | |
end | |
concerning :Dom do | |
private | |
def dom_classes | |
[ | |
Bem.bem(:modulor_selectize), | |
Bem.bem(:modulor_resource_select_input) | |
] | |
end | |
def dom_data | |
{ | |
max_items: max_items, | |
max_options: max_options, | |
options: selectize_options, | |
path: path, | |
rendering_template: rendering_template, | |
resource_class_name: resource_class_name, | |
resource_class_names: resource_class_names, | |
selectize_plugins: selectize_plugins, | |
value_field: value_field | |
}.delete_if { |_, v| v.blank? } | |
end | |
end | |
concerning :SelectizeOptions do | |
private | |
def selectize_options | |
input_html_options.fetch(:options, default_selectize_options) | |
end | |
def default_selectize_options | |
ActiveModelSerializers::SerializableResource.new( | |
Array(relation), | |
each_serializer: serializer_class, | |
serializer: ActiveModel::Serializer::CollectionSerializer | |
).as_json | |
end | |
end | |
concerning :Path do | |
private | |
def path | |
input_html_options.fetch(:path, default_path) | |
end | |
def default_path | |
params = {} | |
params = params.merge(locale: ::I18n.locale) if multiple_locales? | |
if resource_class <= Modulor::Page | |
Modulor::Engine.routes.url_helpers.modulor_resource_select_pages_path(params) | |
elsif CrudResourceListModule.resource_classes.include?(resource_class) | |
Modulor::Engine.routes.url_helpers.modulor_resource_select_crud_resources_path(params) | |
end | |
end | |
def multiple_locales? | |
::I18n.available_locales.count > 1 | |
end | |
end | |
concerning :Max do | |
private | |
def max_items | |
input_html_options.fetch(:max_items, default_max_items) | |
end | |
def default_max_items | |
1 unless relation_is_many? | |
end | |
def max_options | |
input_html_options.fetch(:max_options, default_max_options) | |
end | |
def default_max_options | |
5 | |
end | |
end | |
concerning :RenderingTemplate do | |
private | |
def rendering_template | |
input_html_options.fetch(:rendering_template, default_rendering_template) | |
end | |
def default_rendering_template | |
if resource_class <= Modulor::Page | |
%(<div class='#{Bem.bem(:modulor_selectize, Modulor::Page)}'> | |
<span class='#{Bem.bem(Modulor::SubjectType)}' data-subject-type='{{attributes.class-name}}'>{{attributes.class-name-human}}</span> | |
<div class='#{Bem.bem(:modulor_selectize, Modulor::Page, :title)}'>{{attributes.title}}</div> | |
<div class='#{Bem.bem(:modulor_selectize, Modulor::Page, :path)}'>/{{attributes.path}}</div> | |
</div>) | |
elsif resource_class <= Modulor::Attachment::Glyph | |
%(<div class='#{Bem.bem(:modulor_selectize, :modulor_attachment_glyph)}'> | |
<span class='#{Bem.bem(Modulor::SubjectType)}' data-subject-type='{{attributes.class-name}}'>{{attributes.class-name-human}}</span> | |
<div class='#{Bem.bem(:modulor_selectize, :modulor_attachment_glyph, :to_s)}'>{{attributes.to-s}}</div> | |
<div class='#{Bem.bem(:modulor_selectize, :modulor_attachment_glyph, :inline_svg)}'>{{attributes.inline-svg}}</div> | |
</div>) | |
elsif CrudResourceListModule.resource_classes.include?(resource_class) | |
%(<div class='#{Bem.bem(:modulor_selectize, :modulor_crud_resource)}'> | |
<span class='#{Bem.bem(Modulor::SubjectType)}' data-subject-type='{{attributes.class-name}}'>{{attributes.class-name-human}}</span> | |
<div class='#{Bem.bem(:modulor_selectize, :modulor_crud_resource, :to_s)}'>{{attributes.to-s}}</div> | |
</div>) | |
end | |
end | |
end | |
concerning :Plugins do | |
private | |
def selectize_plugins | |
input_html_options.fetch(:plugins, default_selectize_plugins) | |
end | |
def default_selectize_plugins | |
[] | |
end | |
end | |
concerning :ValueField do | |
private | |
def value_field | |
input_html_options.fetch(:value_field, default_value_field) | |
end | |
def default_value_field | |
'id' | |
end | |
end | |
concerning :Resource do | |
private | |
def resource_class_name | |
input_html_options.fetch(:resource_class_name, default_resource_class_name) | |
end | |
def resource_class | |
resource_class_name.constantize | |
end | |
def default_resource_class_name | |
@builder.object.relations[attribute_name.to_s].try(:class_name) | |
end | |
def resource_class_names | |
input_html_options.fetch(:resource_class_names, nil) | |
end | |
end | |
concerning :Serializer do | |
private | |
def serializer_class_name | |
input_html_options.fetch(:serializer_class_name, default_serializer_class_name) | |
end | |
def default_serializer_class_name | |
if resource_class <= Modulor::Page | |
Modulor::ResourceSelect::PagesSerializer.to_s | |
elsif resource_class <= Modulor::Attachment::Glyph | |
Modulor::ResourceSelect::GlyphSerializer.to_s | |
elsif CrudResourceListModule.resource_classes.include?(resource_class) | |
Modulor::ResourceSelect::CrudResourcesSerializer.to_s | |
end | |
end | |
def serializer_class | |
serializer_class_name.constantize | |
end | |
end | |
concerning :Relation do | |
private | |
def relation_attribute_name | |
input_html_options.fetch(:relation_attribute_name, default_relation_attribute_name) | |
end | |
def default_relation_attribute_name | |
@builder.object.relations[attribute_name.to_s].try(:key) || | |
attribute_name | |
end | |
def relation_name | |
input_html_options.fetch(:relation_name, default_relation_name) | |
end | |
def default_relation_name | |
attribute_name | |
end | |
def relation | |
@builder.object.send(relation_name) | |
end | |
def relation_is_many? | |
input_html_options.fetch(:relation_is_many, default_relation_is_many?) | |
end | |
def default_relation_is_many? | |
[Mongoid::Association::Embedded::EmbedsMany, | |
Mongoid::Association::Referenced::HasMany, | |
Mongoid::Association::Referenced::HasAndBelongsToMany].any? { |cls| relation.is_a?(cls) } || | |
[Array].any? { |cls| @builder.object.fields[relation_attribute_name.to_s].options[:type] == cls if @builder.object.fields[relation_attribute_name.to_s] } || | |
[Array].any? { |cls| @builder.object.send(relation_attribute_name).class if @builder.object.respond_to?(relation_attribute_name) } | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment