Merge with master
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
inherit_from: .rubocop_todo.yml
|
||||
|
||||
AllCops:
|
||||
DisplayCopNames: true
|
||||
DisplayStyleGuide: true
|
||||
Include:
|
||||
- '**/Rakefile'
|
||||
- '**/config.ru'
|
||||
|
||||
@@ -283,7 +283,6 @@ Lint/ParenthesesAsGroupedExpression:
|
||||
# Cop supports --auto-correct.
|
||||
Lint/StringConversionInInterpolation:
|
||||
Exclude:
|
||||
- 'app/models/poll/final_recount.rb'
|
||||
- 'app/models/poll/null_result.rb'
|
||||
- 'app/models/poll/partial_result.rb'
|
||||
- 'app/models/poll/white_result.rb'
|
||||
@@ -455,12 +454,6 @@ Style/ClassVars:
|
||||
- 'app/models/organization.rb'
|
||||
- 'app/models/user.rb'
|
||||
|
||||
# Offense count: 6
|
||||
# Cop supports --auto-correct.
|
||||
Style/ColonMethodCall:
|
||||
Exclude:
|
||||
- 'spec/models/budget/investment_spec.rb'
|
||||
|
||||
# Offense count: 12
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly, IncludeTernaryExpressions.
|
||||
@@ -481,12 +474,6 @@ Style/DoubleNegation:
|
||||
Exclude:
|
||||
- 'app/models/flag.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
Style/EmptyCaseCondition:
|
||||
Exclude:
|
||||
- 'app/models/concerns/verification.rb'
|
||||
|
||||
# Offense count: 2
|
||||
# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms.
|
||||
# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
|
||||
@@ -528,20 +515,6 @@ Style/Lambda:
|
||||
- 'app/models/vote.rb'
|
||||
- 'lib/graph_ql/api_types_creator.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
Style/MethodCallWithoutArgsParentheses:
|
||||
Exclude:
|
||||
- 'app/controllers/management/document_verifications_controller.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: require_parentheses, require_no_parentheses, require_no_parentheses_except_multiline
|
||||
Style/MethodDefParentheses:
|
||||
Exclude:
|
||||
- 'spec/helpers/comments_helper_spec.rb'
|
||||
|
||||
# Offense count: 1
|
||||
Style/MultilineBlockChain:
|
||||
Exclude:
|
||||
@@ -573,25 +546,6 @@ Style/MutableConstant:
|
||||
- 'lib/tag_sanitizer.rb'
|
||||
- 'lib/wysiwyg_sanitizer.rb'
|
||||
|
||||
# Offense count: 29
|
||||
# Cop supports --auto-correct.
|
||||
Style/NestedParenthesizedCalls:
|
||||
Exclude:
|
||||
- 'spec/features/debates_spec.rb'
|
||||
- 'spec/features/emails_spec.rb'
|
||||
- 'spec/features/valuation/budget_investments_spec.rb'
|
||||
- 'spec/features/valuation/spending_proposals_spec.rb'
|
||||
- 'spec/helpers/settings_helper_spec.rb'
|
||||
- 'spec/helpers/verification_helper_spec.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
|
||||
# SupportedStyles: skip_modifier_ifs, always
|
||||
Style/Next:
|
||||
Exclude:
|
||||
- 'app/controllers/officing/results_controller.rb'
|
||||
|
||||
# Offense count: 54
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: Strict.
|
||||
@@ -626,15 +580,6 @@ Style/ParallelAssignment:
|
||||
- 'lib/active_model/dates.rb'
|
||||
- 'spec/support/common_actions.rb'
|
||||
|
||||
# Offense count: 3
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowSafeAssignment.
|
||||
Style/ParenthesesAroundCondition:
|
||||
Exclude:
|
||||
- 'app/controllers/proposals_controller.rb'
|
||||
- 'app/models/debate.rb'
|
||||
- 'app/models/proposal.rb'
|
||||
|
||||
# Offense count: 11
|
||||
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
|
||||
# NamePrefix: is_, has_, have_
|
||||
@@ -669,11 +614,6 @@ Style/RedundantBegin:
|
||||
- 'app/controllers/graphql_controller.rb'
|
||||
- 'app/models/legislation/annotation.rb'
|
||||
|
||||
# Offense count: 55
|
||||
# Cop supports --auto-correct.
|
||||
Style/RedundantParentheses:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
|
||||
@@ -699,22 +639,6 @@ Style/SafeNavigation:
|
||||
Exclude:
|
||||
- 'app/models/signature.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: single_quotes, double_quotes
|
||||
Style/StringLiteralsInInterpolation:
|
||||
Exclude:
|
||||
- 'spec/features/budgets/investments_spec.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyleForMultiline, SupportedStylesForMultiline.
|
||||
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
|
||||
Style/TrailingCommaInArguments:
|
||||
Exclude:
|
||||
- 'app/controllers/legislation/answers_controller.rb'
|
||||
|
||||
# Offense count: 9
|
||||
# Configuration parameters: SupportedStyles.
|
||||
# SupportedStyles: snake_case, camelCase
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
//= require jquery_ujs
|
||||
//= require jquery-ui/widgets/datepicker
|
||||
//= require jquery-ui/i18n/datepicker-es
|
||||
//= require jquery-ui/widgets/autocomplete
|
||||
//= require jquery-fileupload/basic
|
||||
//= require foundation
|
||||
//= require turbolinks
|
||||
@@ -60,9 +61,12 @@
|
||||
//= require legislation_annotatable
|
||||
//= require watch_form_changes
|
||||
//= require followable
|
||||
//= require flaggable
|
||||
//= require documentable
|
||||
//= require imageable
|
||||
//= require tree_navigator
|
||||
//= require custom
|
||||
//= require tag_autocomplete
|
||||
|
||||
var initialize_modules = function() {
|
||||
App.Comments.initialize();
|
||||
@@ -97,10 +101,12 @@ var initialize_modules = function() {
|
||||
App.WatchFormChanges.initialize();
|
||||
App.TreeNavigator.initialize();
|
||||
App.Documentable.initialize();
|
||||
App.Imageable.initialize();
|
||||
App.TagAutocomplete.initialize();
|
||||
};
|
||||
|
||||
$(function(){
|
||||
Turbolinks.enableProgressBar()
|
||||
Turbolinks.enableProgressBar();
|
||||
|
||||
$(document).ready(initialize_modules);
|
||||
$(document).on('page:load', initialize_modules);
|
||||
|
||||
@@ -1,101 +1,156 @@
|
||||
App.Documentable =
|
||||
|
||||
initialize: ->
|
||||
@initializeDirectUploads()
|
||||
@initializeInterface()
|
||||
|
||||
initializeDirectUploads: ->
|
||||
inputFiles = $('.js-document-attachment')
|
||||
$.each inputFiles, (index, input) ->
|
||||
App.Documentable.initializeDirectUploadInput(input)
|
||||
|
||||
$('input.document_ajax_attachment[type=file]').fileupload
|
||||
$('#nested-documents').on 'cocoon:after-remove', (e, insertedItem) ->
|
||||
App.Documentable.unlockUploads()
|
||||
|
||||
paramName: "document[attachment]"
|
||||
$('#nested-documents').on 'cocoon:after-insert', (e, nested_document) ->
|
||||
input = $(nested_document).find('.js-document-attachment')
|
||||
App.Documentable.initializeDirectUploadInput(input)
|
||||
|
||||
if $(nested_document).closest('#nested-documents').find('.document:visible').length >= $('#nested-documents').data('max-documents-allowed')
|
||||
App.Documentable.lockUploads()
|
||||
|
||||
initializeDirectUploadInput: (input) ->
|
||||
|
||||
inputData = @buildData([], input)
|
||||
|
||||
@initializeRemoveCachedDocumentLink(input, inputData)
|
||||
|
||||
$(input).fileupload
|
||||
|
||||
paramName: "attachment"
|
||||
|
||||
formData: null
|
||||
|
||||
add: (e, data) ->
|
||||
wrapper = $(e.target).closest('.document')
|
||||
index = $(e.target).data('index')
|
||||
is_nested_document = $(e.target).data('nested-document')
|
||||
$(wrapper).find('.progress-bar-placeholder').empty()
|
||||
data.progressBar = $(wrapper).find('.progress-bar-placeholder').html('<div class="progress-bar"><div class="loading-bar uploading"></div></div>')
|
||||
$(wrapper).find('.progress-bar-placeholder').css('display','block')
|
||||
data.formData = {
|
||||
"document[title]": $(wrapper).find('input.document-title').val() || data.files[0].name
|
||||
"index": index,
|
||||
"nested_document": is_nested_document
|
||||
}
|
||||
data = App.Documentable.buildFileUploadData(e, data)
|
||||
App.Documentable.clearProgressBar(data)
|
||||
App.Documentable.setProgressBar(data, 'uploading')
|
||||
data.submit()
|
||||
|
||||
change: (e, data) ->
|
||||
wrapper = $(e.target).parent()
|
||||
$.each(data.files, (index, file)->
|
||||
$(wrapper).find('.file-name').text(file.name)
|
||||
)
|
||||
$.each data.files, (index, file) ->
|
||||
App.Documentable.setFilename(inputData, file.name)
|
||||
|
||||
fail: (e, data) ->
|
||||
$(data.cachedAttachmentField).val("")
|
||||
App.Documentable.clearFilename(data)
|
||||
App.Documentable.setProgressBar(data, 'errors')
|
||||
App.Documentable.clearInputErrors(data)
|
||||
App.Documentable.setInputErrors(data)
|
||||
$(data.destroyAttachmentLinkContainer).find("a.delete:not(.remove-nested)").remove()
|
||||
$(data.addAttachmentLabel).addClass('error')
|
||||
$(data.addAttachmentLabel).show()
|
||||
|
||||
done: (e, data) ->
|
||||
$(data.cachedAttachmentField).val(data.result.cached_attachment)
|
||||
App.Documentable.setTitleFromFile(data, data.result.filename)
|
||||
App.Documentable.setProgressBar(data, 'complete')
|
||||
App.Documentable.setFilename(data, data.result.filename)
|
||||
App.Documentable.clearInputErrors(data)
|
||||
$(data.addAttachmentLabel).hide()
|
||||
$(data.wrapper).find(".attachment-actions").removeClass('small-12').addClass('small-6 float-right')
|
||||
$(data.wrapper).find(".attachment-actions .action-remove").removeClass('small-3').addClass('small-12')
|
||||
|
||||
destroyAttachmentLink = $(data.result.destroy_link)
|
||||
$(data.destroyAttachmentLinkContainer).html(destroyAttachmentLink)
|
||||
$(destroyAttachmentLink).on 'click', (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
App.Documentable.doDeleteCachedAttachmentRequest(this.href, data)
|
||||
|
||||
progress: (e, data) ->
|
||||
progress = parseInt(data.loaded / data.total * 100, 10)
|
||||
$(data.progressBar).find('.loading-bar').css 'width', progress + '%'
|
||||
return
|
||||
|
||||
initializeInterface: ->
|
||||
input_files = $('input.document_ajax_attachment[type=file]')
|
||||
buildFileUploadData: (e, data) ->
|
||||
data = @buildData(data, e.target)
|
||||
return data
|
||||
|
||||
$.each input_files, (index, file) ->
|
||||
wrapper = $(file).parent()
|
||||
App.Documentable.watchRemoveDocumentbutton(wrapper)
|
||||
buildData: (data, input) ->
|
||||
wrapper = $(input).closest('.direct-upload')
|
||||
data.input = input
|
||||
data.wrapper = wrapper
|
||||
data.progressBar = $(wrapper).find('.progress-bar-placeholder')
|
||||
data.errorContainer = $(wrapper).find('.attachment-errors')
|
||||
data.fileNameContainer = $(wrapper).find('p.file-name')
|
||||
data.destroyAttachmentLinkContainer = $(wrapper).find('.action-remove')
|
||||
data.addAttachmentLabel = $(wrapper).find('.action-add label')
|
||||
data.cachedAttachmentField = $(wrapper).find("input[name$='[cached_attachment]']")
|
||||
data.titleField = $(wrapper).find("input[name$='[title]']")
|
||||
$(wrapper).find('.progress-bar-placeholder').css('display', 'block')
|
||||
return data
|
||||
|
||||
watchRemoveDocumentbutton: (wrapper) ->
|
||||
remove_document_button = $(wrapper).find('.remove-document')
|
||||
$(remove_document_button).on 'click', (e) ->
|
||||
clearFilename: (data) ->
|
||||
$(data.fileNameContainer).text('')
|
||||
$(data.fileNameContainer).hide()
|
||||
|
||||
clearInputErrors: (data) ->
|
||||
$(data.errorContainer).find('small.error').remove()
|
||||
|
||||
clearProgressBar: (data) ->
|
||||
$(data.progressBar).find('.loading-bar').removeClass('complete errors uploading').css('width', "0px")
|
||||
|
||||
setFilename: (data, file_name) ->
|
||||
$(data.fileNameContainer).text(file_name)
|
||||
$(data.fileNameContainer).show()
|
||||
|
||||
setProgressBar: (data, klass) ->
|
||||
$(data.progressBar).find('.loading-bar').addClass(klass)
|
||||
|
||||
setTitleFromFile: (data, title) ->
|
||||
if $(data.titleField).val() == ""
|
||||
$(data.titleField).val(title)
|
||||
|
||||
setInputErrors: (data) ->
|
||||
errors = '<small class="error">' + data.jqXHR.responseJSON.errors + '</small>'
|
||||
$(data.errorContainer).append(errors)
|
||||
|
||||
lockUploads: ->
|
||||
$('#max-documents-notice').removeClass('hide')
|
||||
$('#new_document_link').addClass('hide')
|
||||
|
||||
unlockUploads: ->
|
||||
$('#max-documents-notice').addClass('hide')
|
||||
$('#new_document_link').removeClass('hide')
|
||||
|
||||
doDeleteCachedAttachmentRequest: (url, data) ->
|
||||
$.ajax
|
||||
type: "POST"
|
||||
url: url
|
||||
dataType: "json"
|
||||
data: { "_method": "delete" }
|
||||
complete: ->
|
||||
$(data.cachedAttachmentField).val("")
|
||||
$(data.addAttachmentLabel).show()
|
||||
|
||||
App.Documentable.clearFilename(data)
|
||||
App.Documentable.clearInputErrors(data)
|
||||
App.Documentable.clearProgressBar(data)
|
||||
|
||||
App.Documentable.unlockUploads()
|
||||
$(data.wrapper).find(".attachment-actions").addClass('small-12').removeClass('small-6 float-right')
|
||||
$(data.wrapper).find(".attachment-actions .action-remove").addClass('small-3').removeClass('small-12')
|
||||
|
||||
if $(data.input).data('nested-document') == true
|
||||
$(data.wrapper).remove()
|
||||
else
|
||||
$(data.wrapper).find('a.remove-cached-attachment').remove()
|
||||
|
||||
initializeRemoveCachedDocumentLink: (input, data) ->
|
||||
wrapper = $(input).closest(".direct-upload")
|
||||
remove_document_link = $(wrapper).find('a.remove-cached-attachment')
|
||||
$(remove_document_link).on 'click', (e) ->
|
||||
e.preventDefault()
|
||||
$(wrapper).remove()
|
||||
$('#new_document_link').show()
|
||||
$('.max-documents-notice').hide()
|
||||
e.stopPropagation()
|
||||
App.Documentable.doDeleteCachedAttachmentRequest(this.href, data)
|
||||
|
||||
uploadNestedDocument: (id, nested_document, result) ->
|
||||
$('#' + id).replaceWith(nested_document)
|
||||
@updateLoadingBar(id, result)
|
||||
@initialize()
|
||||
|
||||
uploadPlainDocument: (id, nested_document, result) ->
|
||||
$('#' + id).replaceWith(nested_document)
|
||||
@updateLoadingBar(id, result)
|
||||
@initialize()
|
||||
|
||||
updateLoadingBar: (id, result) ->
|
||||
if result
|
||||
$('#' + id).find('.loading-bar').addClass 'complete'
|
||||
else
|
||||
$('#' + id).find('.loading-bar').addClass 'errors'
|
||||
$('#' + id).find('.progress-bar-placeholder').css('display','block')
|
||||
|
||||
new: (nested_fields) ->
|
||||
$(".documents-list").append(nested_fields)
|
||||
@initialize()
|
||||
|
||||
destroyNestedDocument: (id, notice) ->
|
||||
removeDocument: (id) ->
|
||||
$('#' + id).remove()
|
||||
@updateNotice(notice)
|
||||
|
||||
replacePlainDocument: (id, notice, plain_document) ->
|
||||
$('#' + id).replaceWith(plain_document)
|
||||
@updateNotice(notice)
|
||||
@initialize()
|
||||
|
||||
updateNotice: (notice) ->
|
||||
if $('[data-alert]').length > 0
|
||||
$('[data-alert]').replaceWith(notice)
|
||||
else
|
||||
$("body").append(notice)
|
||||
|
||||
updateNewDocumentButton: (link) ->
|
||||
if $('.document').length >= $('.documents').data('max-documents')
|
||||
$('#new_document_link').hide()
|
||||
$('.max-documents-notice').removeClass('hide')
|
||||
$('.max-documents-notice').show()
|
||||
else if $('#new_document_link').length > 0
|
||||
$('#new_document_link').replaceWith(link)
|
||||
$('.max-documents-notice').hide()
|
||||
else
|
||||
$('.max-documents-notice').hide()
|
||||
$(link).insertBefore('.documents hr:last')
|
||||
|
||||
4
app/assets/javascripts/flaggable.js.coffee
Normal file
4
app/assets/javascripts/flaggable.js.coffee
Normal file
@@ -0,0 +1,4 @@
|
||||
App.Flaggable =
|
||||
|
||||
update: (resource_id, button) ->
|
||||
$("#" + resource_id + " .js-flag-actions").html(button).foundation()
|
||||
166
app/assets/javascripts/imageable.js.coffee
Normal file
166
app/assets/javascripts/imageable.js.coffee
Normal file
@@ -0,0 +1,166 @@
|
||||
App.Imageable =
|
||||
|
||||
initialize: ->
|
||||
inputFiles = $('.js-image-attachment')
|
||||
$.each inputFiles, (index, input) ->
|
||||
App.Imageable.initializeDirectUploadInput(input)
|
||||
|
||||
$('#nested-image').on 'cocoon:after-remove', (e, item) ->
|
||||
$("#new_image_link").removeClass('hide')
|
||||
|
||||
$('#nested-image').on 'cocoon:before-insert', (e, nested_image) ->
|
||||
if $(".js-image-attachment").length > 0
|
||||
$(".js-image-attachment").closest('.image').remove()
|
||||
|
||||
$('#nested-image').on 'cocoon:after-insert', (e, nested_image) ->
|
||||
$("#new_image_link").addClass('hide')
|
||||
input = $(nested_image).find('.js-image-attachment')
|
||||
App.Imageable.initializeDirectUploadInput(input)
|
||||
|
||||
initializeDirectUploadInput: (input) ->
|
||||
|
||||
inputData = @buildData([], input)
|
||||
|
||||
@initializeRemoveCachedImageLink(input, inputData)
|
||||
|
||||
$(input).fileupload
|
||||
|
||||
paramName: "attachment"
|
||||
|
||||
formData: null
|
||||
|
||||
add: (e, data) ->
|
||||
data = App.Imageable.buildFileUploadData(e, data)
|
||||
App.Imageable.clearProgressBar(data)
|
||||
App.Imageable.setProgressBar(data, 'uploading')
|
||||
data.submit()
|
||||
|
||||
change: (e, data) ->
|
||||
$.each data.files, (index, file) ->
|
||||
App.Imageable.setFilename(inputData, file.name)
|
||||
|
||||
fail: (e, data) ->
|
||||
$(data.cachedAttachmentField).val("")
|
||||
App.Imageable.clearFilename(data)
|
||||
App.Imageable.setProgressBar(data, 'errors')
|
||||
App.Imageable.clearInputErrors(data)
|
||||
App.Imageable.setInputErrors(data)
|
||||
App.Imageable.clearPreview(data)
|
||||
$(data.destroyAttachmentLinkContainer).find("a.delete:not(.remove-nested)").remove()
|
||||
$(data.addAttachmentLabel).addClass('error')
|
||||
$(data.addAttachmentLabel).show()
|
||||
|
||||
done: (e, data) ->
|
||||
$(data.cachedAttachmentField).val(data.result.cached_attachment)
|
||||
App.Imageable.setTitleFromFile(data, data.result.filename)
|
||||
App.Imageable.setProgressBar(data, 'complete')
|
||||
App.Imageable.setFilename(data, data.result.filename)
|
||||
App.Imageable.clearInputErrors(data)
|
||||
$(data.addAttachmentLabel).hide()
|
||||
$(data.wrapper).find(".attachment-actions").removeClass('small-12').addClass('small-6 float-right')
|
||||
$(data.wrapper).find(".attachment-actions .action-remove").removeClass('small-3').addClass('small-12')
|
||||
App.Imageable.setPreview(data)
|
||||
|
||||
destroyAttachmentLink = $(data.result.destroy_link)
|
||||
$(data.destroyAttachmentLinkContainer).html(destroyAttachmentLink)
|
||||
$(destroyAttachmentLink).on 'click', (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
App.Imageable.doDeleteCachedAttachmentRequest(this.href, data)
|
||||
|
||||
progress: (e, data) ->
|
||||
progress = parseInt(data.loaded / data.total * 100, 10)
|
||||
$(data.progressBar).find('.loading-bar').css 'width', progress + '%'
|
||||
return
|
||||
|
||||
buildFileUploadData: (e, data) ->
|
||||
data = @buildData(data, e.target)
|
||||
return data
|
||||
|
||||
buildData: (data, input) ->
|
||||
wrapper = $(input).closest('.direct-upload')
|
||||
data.input = input
|
||||
data.wrapper = wrapper
|
||||
data.progressBar = $(wrapper).find('.progress-bar-placeholder')
|
||||
data.preview = $(wrapper).find('.image-preview')
|
||||
data.errorContainer = $(wrapper).find('.attachment-errors')
|
||||
data.fileNameContainer = $(wrapper).find('p.file-name')
|
||||
data.destroyAttachmentLinkContainer = $(wrapper).find('.action-remove')
|
||||
data.addAttachmentLabel = $(wrapper).find('.action-add label')
|
||||
data.cachedAttachmentField = $(wrapper).find("input[name$='[cached_attachment]']")
|
||||
data.titleField = $(wrapper).find("input[name$='[title]']")
|
||||
$(wrapper).find('.progress-bar-placeholder').css('display', 'block')
|
||||
return data
|
||||
|
||||
clearFilename: (data) ->
|
||||
$(data.fileNameContainer).text('')
|
||||
$(data.fileNameContainer).hide()
|
||||
|
||||
clearInputErrors: (data) ->
|
||||
$(data.errorContainer).find('small.error').remove()
|
||||
|
||||
clearProgressBar: (data) ->
|
||||
$(data.progressBar).find('.loading-bar').removeClass('complete errors uploading').css('width', "0px")
|
||||
|
||||
clearPreview: (data) ->
|
||||
$(data.wrapper).find('.image-preview').remove()
|
||||
|
||||
setFilename: (data, file_name) ->
|
||||
$(data.fileNameContainer).text(file_name)
|
||||
$(data.fileNameContainer).show()
|
||||
|
||||
setProgressBar: (data, klass) ->
|
||||
$(data.progressBar).find('.loading-bar').addClass(klass)
|
||||
|
||||
setTitleFromFile: (data, title) ->
|
||||
if $(data.titleField).val() == ""
|
||||
$(data.titleField).val(title)
|
||||
|
||||
setInputErrors: (data) ->
|
||||
errors = '<small class="error">' + data.jqXHR.responseJSON.errors + '</small>'
|
||||
$(data.errorContainer).append(errors)
|
||||
|
||||
setPreview: (data) ->
|
||||
image_preview = '<div class="small-12 column text-center image-preview"><figure><img src="' + data.result.attachment_url + '" class="cached-image"/></figure></div>'
|
||||
if $(data.preview).length > 0
|
||||
$(data.preview).replaceWith(image_preview)
|
||||
else
|
||||
$(image_preview).insertBefore($(data.wrapper).find(".attachment-actions"))
|
||||
data.preview = $(data.wrapper).find('.image-preview')
|
||||
|
||||
doDeleteCachedAttachmentRequest: (url, data) ->
|
||||
$.ajax
|
||||
type: "POST"
|
||||
url: url
|
||||
dataType: "json"
|
||||
data: { "_method": "delete" }
|
||||
complete: ->
|
||||
$(data.cachedAttachmentField).val("")
|
||||
$(data.addAttachmentLabel).show()
|
||||
|
||||
App.Imageable.clearFilename(data)
|
||||
App.Imageable.clearInputErrors(data)
|
||||
App.Imageable.clearProgressBar(data)
|
||||
App.Imageable.clearPreview(data)
|
||||
|
||||
$('#new_image_link').removeClass('hide')
|
||||
|
||||
$(data.wrapper).find(".attachment-actions").addClass('small-12').removeClass('small-6 float-right')
|
||||
$(data.wrapper).find(".attachment-actions .action-remove").addClass('small-3').removeClass('small-12')
|
||||
|
||||
if $(data.input).data('nested-image') == true
|
||||
$(data.wrapper).remove()
|
||||
else
|
||||
$(data.wrapper).find('a.remove-cached-attachment').remove()
|
||||
|
||||
initializeRemoveCachedImageLink: (input, data) ->
|
||||
wrapper = $(input).closest(".direct-upload")
|
||||
remove_image_link = $(wrapper).find('a.remove-cached-attachment')
|
||||
$(remove_image_link).on 'click', (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
App.Imageable.doDeleteCachedAttachmentRequest(this.href, data)
|
||||
|
||||
removeImage: (id) ->
|
||||
$('#' + id).remove()
|
||||
$("#new_image_link").removeClass('hide')
|
||||
34
app/assets/javascripts/tag_autocomplete.js.coffee
Normal file
34
app/assets/javascripts/tag_autocomplete.js.coffee
Normal file
@@ -0,0 +1,34 @@
|
||||
App.TagAutocomplete =
|
||||
|
||||
split: ( val ) ->
|
||||
return (val.split( /,\s*/ ))
|
||||
|
||||
extractLast: ( term ) ->
|
||||
return (App.TagAutocomplete.split( term ).pop())
|
||||
|
||||
init_autocomplete: ->
|
||||
$('.tag-autocomplete').autocomplete
|
||||
source: (request, response) ->
|
||||
$.ajax
|
||||
url: $('.tag-autocomplete').data('js-url'),
|
||||
data: {search: App.TagAutocomplete.extractLast( request.term )},
|
||||
type: 'GET',
|
||||
dataType: 'json'
|
||||
success: ( data ) ->
|
||||
response( data );
|
||||
|
||||
minLength: 0,
|
||||
search: ->
|
||||
App.TagAutocomplete.extractLast( this.value );
|
||||
focus: ->
|
||||
return false;
|
||||
select: ( event, ui ) -> (
|
||||
terms = App.TagAutocomplete.split( this.value );
|
||||
terms.pop();
|
||||
terms.push( ui.item.value );
|
||||
terms.push( "" );
|
||||
this.value = terms.join( ", " );
|
||||
return false;);
|
||||
|
||||
initialize: ->
|
||||
App.TagAutocomplete.init_autocomplete();
|
||||
@@ -13,33 +13,99 @@
|
||||
// 01. Global styles
|
||||
// -----------------
|
||||
|
||||
$admin-color: #cf3638;
|
||||
$admin-color: #245b80;
|
||||
$sidebar: #245b80;
|
||||
$sidebar-hover: #25597c;
|
||||
$sidebar-active: #f4fcd0;
|
||||
|
||||
.admin {
|
||||
|
||||
h2 {
|
||||
font-weight: 100;
|
||||
margin-bottom: $line-height;
|
||||
|
||||
&.title {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
.back {
|
||||
float: none;
|
||||
}
|
||||
|
||||
.header {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.top-links {
|
||||
background: darken($admin-color, 15%);
|
||||
}
|
||||
|
||||
.back-web {
|
||||
padding-top: $line-height / 4;
|
||||
text-decoration: underline;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
background: $admin-color !important;
|
||||
background: #fff !important;
|
||||
border-bottom: 1px solid #eee;
|
||||
box-shadow: 0 2px 2px #eee;
|
||||
color: #000;
|
||||
height: auto;
|
||||
|
||||
[class^="icon-"]:not(.icon-circle) {
|
||||
font-size: $base-font-size;
|
||||
}
|
||||
}
|
||||
|
||||
.top-bar-title {
|
||||
|
||||
h1 {
|
||||
margin-bottom: 0;
|
||||
margin-top: $line-height / 2;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
margin-left: $line-height / 2;
|
||||
}
|
||||
|
||||
small {
|
||||
color: #000;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: #000 !important;
|
||||
line-height: $line-height !important;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
line-height: $line-height !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.top-bar .menu > li {
|
||||
|
||||
@include breakpoint(medium) {
|
||||
height: auto !important;
|
||||
padding-top: $line-height / 2;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #000 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-icon.dark {
|
||||
|
||||
&::after,
|
||||
&:hover::after {
|
||||
background: #000 !important;
|
||||
box-shadow: 0 7px 0 #000, 0 14px 0 #000 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.notifications .icon-circle {
|
||||
color: $admin-color;
|
||||
}
|
||||
|
||||
.dropdown.menu > .is-dropdown-submenu-parent > a::after {
|
||||
border-color: #000 transparent transparent;
|
||||
}
|
||||
|
||||
.fieldset {
|
||||
@@ -54,7 +120,8 @@ $admin-color: #cf3638;
|
||||
}
|
||||
}
|
||||
|
||||
th, td {
|
||||
th,
|
||||
td {
|
||||
text-align: left;
|
||||
|
||||
&.text-center {
|
||||
@@ -110,6 +177,7 @@ $admin-color: #cf3638;
|
||||
.menu.simple .active {
|
||||
border-bottom: 2px solid $admin-color;
|
||||
color: $admin-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tabs-panel {
|
||||
@@ -195,6 +263,8 @@ $admin-color: #cf3638;
|
||||
// -----------
|
||||
|
||||
.admin-sidebar {
|
||||
background: $sidebar;
|
||||
background: linear-gradient(to bottom, #245b80 0%, #488fb5 100%);
|
||||
border-right: 1px solid $border;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
@@ -208,7 +278,7 @@ $admin-color: #cf3638;
|
||||
padding: 0;
|
||||
|
||||
[class^="icon-"] {
|
||||
color: $admin-color;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
font-size: rem-calc(24);
|
||||
line-height: $line-height;
|
||||
@@ -219,39 +289,32 @@ $admin-color: #cf3638;
|
||||
}
|
||||
|
||||
li {
|
||||
background: #fff;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
|
||||
ul {
|
||||
margin-left: $line-height / 1.5;
|
||||
border-left: 1px solid $border;
|
||||
border-left: 1px solid $sidebar-hover;
|
||||
padding-left: $line-height / 2;
|
||||
}
|
||||
|
||||
&.section-title {
|
||||
border-bottom: 1px solid $border;
|
||||
}
|
||||
|
||||
&.active a {
|
||||
background: #f3f6f7;
|
||||
border-radius: rem-calc(6);
|
||||
color: $admin-color;
|
||||
background: $sidebar-hover;
|
||||
border-left: 2px solid $sidebar-active;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
li a {
|
||||
color: $text;
|
||||
color: #fff;
|
||||
display: block;
|
||||
line-height: rem-calc(48);
|
||||
padding-left: rem-calc(12);
|
||||
vertical-align: top;
|
||||
|
||||
&:hover {
|
||||
background: #f3f6f7;
|
||||
border-radius: rem-calc(6);
|
||||
color: $admin-color;
|
||||
background: $sidebar-hover;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
@@ -259,7 +322,13 @@ $admin-color: #cf3638;
|
||||
.is-accordion-submenu-parent {
|
||||
|
||||
> a::after {
|
||||
border-color: $admin-color transparent transparent;
|
||||
border: 0;
|
||||
content: '\61' !important;
|
||||
font-family: "icons" !important;
|
||||
height: auto;
|
||||
position: absolute !important;
|
||||
right: 30px;
|
||||
top: 6px !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,4 +16,5 @@
|
||||
@import 'annotator_overrides';
|
||||
@import 'jquery-ui/datepicker';
|
||||
@import 'datepicker_overrides';
|
||||
@import 'documentable';
|
||||
@import 'jquery-ui/autocomplete';
|
||||
@import 'autocomplete_overrides';
|
||||
|
||||
40
app/assets/stylesheets/autocomplete_overrides.scss
Normal file
40
app/assets/stylesheets/autocomplete_overrides.scss
Normal file
@@ -0,0 +1,40 @@
|
||||
// Overrides styles of jquery-ui/autocomplete
|
||||
//
|
||||
|
||||
/* Autocomplete
|
||||
----------------------------------*/
|
||||
.ui-autocomplete {
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* workarounds */
|
||||
* html .ui-autocomplete {
|
||||
width: 1px;
|
||||
} /* without this, the menu expands to 100% in IE6 */
|
||||
|
||||
/* Menu
|
||||
----------------------------------*/
|
||||
.ui-menu {
|
||||
list-style: none;
|
||||
padding: $line-height / 4 $line-height / 3;
|
||||
display: block;
|
||||
background: #fff;
|
||||
border: 1px solid $border;
|
||||
font-size: $small-font-size;
|
||||
|
||||
.ui-menu-item {
|
||||
|
||||
.ui-menu-item-wrapper {
|
||||
padding: $line-height / 4 $line-height / 3;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ui-state-hover,
|
||||
.ui-state-active {
|
||||
background: #ececec;
|
||||
border-radius: rem-calc(6);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
.communities-show {
|
||||
.button.disabled, .button[disabled] {
|
||||
.button.disabled,
|
||||
.button[disabled] {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,16 +46,16 @@
|
||||
width: rem-calc(30);
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-datepicker-prev::after {
|
||||
content: '\62';
|
||||
content: '\62';
|
||||
}
|
||||
|
||||
.ui-datepicker-next::after {
|
||||
content: '\63';
|
||||
content: '\63';
|
||||
}
|
||||
|
||||
table {
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
.progress-bar-placeholder {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.document-form {
|
||||
.document .file-name {
|
||||
margin-top: 0;
|
||||
}
|
||||
.progress-bar-placeholder {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.document .loading-bar.errors {
|
||||
margin-top: $line-height * 2;
|
||||
}
|
||||
}
|
||||
|
||||
.document {
|
||||
.button {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
background-color: $light-gray;
|
||||
}
|
||||
|
||||
input.document_ajax_attachment[type=file]{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
margin-top: $line-height / 2;
|
||||
}
|
||||
|
||||
.loading-bar {
|
||||
height: 5px;
|
||||
width: 0;
|
||||
transition: width 500ms ease-out;
|
||||
|
||||
&.uploading {
|
||||
background-color: $dark-gray;
|
||||
}
|
||||
|
||||
&.complete {
|
||||
background-color: $success-color;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.errors {
|
||||
background-color: $alert-color;
|
||||
width: 100%;
|
||||
margin-top: $line-height / 2;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-bar.no-transition {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
@@ -197,6 +197,10 @@
|
||||
content: '\53';
|
||||
}
|
||||
|
||||
.icon-image::before {
|
||||
content: '\68';
|
||||
}
|
||||
|
||||
.icon-notification::before {
|
||||
content: '\6e';
|
||||
}
|
||||
|
||||
@@ -206,19 +206,40 @@ a {
|
||||
|
||||
.menu.simple {
|
||||
border-bottom: 1px solid $border;
|
||||
margin-bottom: $line-height;
|
||||
clear: both;
|
||||
margin-bottom: $line-height / 2;
|
||||
|
||||
li {
|
||||
padding-bottom: rem-calc(7);
|
||||
margin-right: $line-height / 2;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
margin-right: $line-height * 1.5;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $text-medium;
|
||||
color: $text;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
|
||||
&:hover {
|
||||
color: $link;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
border-bottom: 2px solid $brand;
|
||||
color: $brand;
|
||||
}
|
||||
|
||||
&:not(.active) {
|
||||
margin-bottom: $line-height / 3;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: $base-font-size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,10 +334,6 @@ a {
|
||||
}
|
||||
}
|
||||
|
||||
.no-max-width {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.button.float-right ~ .button.float-right {
|
||||
margin: 0 $line-height / 2;
|
||||
}
|
||||
@@ -380,7 +397,11 @@ header {
|
||||
|
||||
.top-bar-title a {
|
||||
@include logo;
|
||||
line-height: rem-calc(80) !important;
|
||||
line-height: rem-calc(80);
|
||||
|
||||
@include breakpoint(medium) {
|
||||
line-height: rem-calc(80);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
@@ -2284,68 +2305,7 @@ table {
|
||||
}
|
||||
}
|
||||
|
||||
// 20. Documents
|
||||
.document-form form {
|
||||
|
||||
.radio-buttons {
|
||||
label {
|
||||
margin-right: $line-height;
|
||||
}
|
||||
}
|
||||
|
||||
.source-option-link {
|
||||
input {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.error {
|
||||
margin-bottom: $line-height;
|
||||
}
|
||||
|
||||
label {
|
||||
&.error {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.source-option-file {
|
||||
.file-name {
|
||||
label {
|
||||
|
||||
@include breakpoint(small medium) {
|
||||
float: none;
|
||||
}
|
||||
|
||||
@include breakpoint(large) {
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
|
||||
@include breakpoint(small medium) {
|
||||
float: none;
|
||||
margin-top: 0;
|
||||
margin-left: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@include breakpoint(large) {
|
||||
float: left;
|
||||
margin-bottom: 0;
|
||||
margin-top: $line-height / 2;
|
||||
margin-left: $line-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.attachment-errors {
|
||||
margin-bottom: $line-height;
|
||||
}
|
||||
}
|
||||
|
||||
// 19. Documents
|
||||
.documents-list {
|
||||
|
||||
table {
|
||||
|
||||
@@ -459,11 +459,11 @@ $border-dark: darken($border, 10%);
|
||||
span {
|
||||
vertical-align: inherit;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
color: $text-medium;
|
||||
}
|
||||
.see-changes {
|
||||
color: $text-medium;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -477,6 +477,7 @@ $border-dark: darken($border, 10%);
|
||||
}
|
||||
|
||||
.draft-allegation {
|
||||
|
||||
@include breakpoint(medium) {
|
||||
display: flex;
|
||||
padding-left: 0.9375rem;
|
||||
@@ -493,7 +494,6 @@ $border-dark: darken($border, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
// Panel calcs for desktop
|
||||
@media screen and (min-width: 40em) {
|
||||
.calc-index {
|
||||
width: calc(35% - 25px);
|
||||
@@ -509,6 +509,7 @@ $border-dark: darken($border, 10%);
|
||||
width: rem-calc(50);
|
||||
|
||||
.draft-panel {
|
||||
|
||||
.panel-title {
|
||||
display: none;
|
||||
}
|
||||
@@ -912,19 +913,15 @@ $border-dark: darken($border, 10%);
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.show-for-medium {
|
||||
.panel-title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 08. Legislation changes
|
||||
// -----------------
|
||||
|
||||
.legislation-changes {
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
margin-left: 0;
|
||||
@@ -936,35 +933,36 @@ $border-dark: darken($border, 10%);
|
||||
margin-right: 0.25rem;
|
||||
content: '—';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.changes-link {
|
||||
display: block;
|
||||
margin-left: 1rem;
|
||||
font-size: $small-font-size;
|
||||
.changes-link {
|
||||
display: block;
|
||||
margin-left: 1rem;
|
||||
font-size: $small-font-size;
|
||||
|
||||
@include breakpoint(medium) {
|
||||
display: inline-block;
|
||||
}
|
||||
@include breakpoint(medium) {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
a {
|
||||
span {
|
||||
text-decoration: underline;
|
||||
}
|
||||
a {
|
||||
|
||||
.icon-external {
|
||||
text-decoration: none;
|
||||
color: #999;
|
||||
line-height: 0;
|
||||
vertical-align: sub;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
span {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&:focus,
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
.icon-external {
|
||||
text-decoration: none;
|
||||
color: #999;
|
||||
line-height: 0;
|
||||
vertical-align: sub;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
&:active,
|
||||
&:focus,
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -972,6 +970,7 @@ $border-dark: darken($border, 10%);
|
||||
|
||||
// 09. Legislation comments
|
||||
// -----------------
|
||||
|
||||
.legislation-comments {
|
||||
|
||||
.pull-right {
|
||||
@@ -1020,6 +1019,7 @@ $border-dark: darken($border, 10%);
|
||||
|
||||
// 10. Legislation draft comment
|
||||
// -----------------
|
||||
|
||||
.legislation-comment {
|
||||
|
||||
.annotation-share-comment {
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//02. Orbit bullet
|
||||
// 02. Orbit bullet
|
||||
// ----------------
|
||||
@mixin orbit-bullets {
|
||||
@include disable-mouse-outline;
|
||||
position: relative;
|
||||
@@ -58,3 +58,72 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 02. Direct uploads
|
||||
// ------------------
|
||||
@mixin direct-uploads {
|
||||
|
||||
.cached-image {
|
||||
max-width: 150px;
|
||||
max-height: 150px;
|
||||
}
|
||||
|
||||
.progress-bar-placeholder {
|
||||
display: none;
|
||||
margin-bottom: $line-height;
|
||||
}
|
||||
|
||||
.document,
|
||||
.image {
|
||||
|
||||
.document-attachment,
|
||||
.image-attachment {
|
||||
padding-left:0;
|
||||
|
||||
p{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
input.js-document-attachment,
|
||||
input.js-image-attachment{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
background-color: $light-gray;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.loading-bar {
|
||||
height: 5px;
|
||||
width: 0;
|
||||
transition: width 500ms ease-out;
|
||||
|
||||
&.uploading {
|
||||
background-color: $dark-gray;
|
||||
}
|
||||
|
||||
&.complete {
|
||||
background-color: $success-color;
|
||||
}
|
||||
|
||||
&.errors {
|
||||
background-color: $alert-color;
|
||||
margin-top: $line-height / 2;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-bar.no-transition {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -249,14 +249,14 @@
|
||||
.proposal-form,
|
||||
.budget-investment-form,
|
||||
.spending-proposal-form,
|
||||
.document-form,
|
||||
.topic-new,
|
||||
.topic-form {
|
||||
.topic-form {
|
||||
|
||||
.icon-debates,
|
||||
.icon-proposals,
|
||||
.icon-budget,
|
||||
.icon-documents {
|
||||
.icon-documents,
|
||||
.icon-image {
|
||||
font-size: rem-calc(50);
|
||||
line-height: $line-height;
|
||||
opacity: 0.5;
|
||||
@@ -267,7 +267,8 @@
|
||||
}
|
||||
|
||||
.icon-proposals,
|
||||
.icon-documents {
|
||||
.icon-documents,
|
||||
.icon-image {
|
||||
color: $proposals;
|
||||
}
|
||||
|
||||
@@ -301,14 +302,22 @@
|
||||
|
||||
.proposal-form,
|
||||
.topic-form,
|
||||
.topic-new,
|
||||
.document-form {
|
||||
.topic-new {
|
||||
|
||||
.recommendations li::before {
|
||||
color: $proposals;
|
||||
}
|
||||
}
|
||||
|
||||
.budget-investment-new,
|
||||
.proposal-form,
|
||||
.proposal-edit,
|
||||
.new_poll_question,
|
||||
.edit_poll_question {
|
||||
@include direct-uploads;
|
||||
}
|
||||
|
||||
|
||||
// 03. Show participation
|
||||
// ----------------------
|
||||
|
||||
@@ -640,6 +649,77 @@
|
||||
}
|
||||
}
|
||||
|
||||
.budget-investments-list .budget-investment,
|
||||
.proposals-list .proposal {
|
||||
|
||||
.no-image {
|
||||
background: $brand;
|
||||
}
|
||||
}
|
||||
|
||||
.budget-investments-list .budget-investment,
|
||||
.proposals-list .proposal {
|
||||
|
||||
@include breakpoint(small) {
|
||||
.no-image {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.no-image::before {
|
||||
content: '';
|
||||
display: block;
|
||||
padding-top: 100%;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.column:first-child {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
@include breakpoint(medium) {
|
||||
.panel {
|
||||
padding: 0 0.75rem 0 0;
|
||||
|
||||
.no-image {
|
||||
height: 245px;
|
||||
width: 140px;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.column:first-child {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.column:nth-child(2) {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.column:last-child:not(:first-child) {
|
||||
padding-top: 0.75rem;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 12rem;
|
||||
}
|
||||
|
||||
.budget-investment-content {
|
||||
ul {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.debate,
|
||||
.proposal,
|
||||
.investment-project,
|
||||
@@ -769,12 +849,6 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.document-form{
|
||||
max-width: 75rem;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.more-info {
|
||||
clear: both;
|
||||
color: $text-medium;
|
||||
@@ -859,6 +933,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
.budget-investment-show {
|
||||
|
||||
figure {
|
||||
margin: rem-calc(10) 0 0;
|
||||
display: inline-block;
|
||||
|
||||
figcaption {
|
||||
font-size: $small-font-size;
|
||||
margin-top: rem-calc(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.investment-project-show .supports,
|
||||
.budget-investment-show .supports {
|
||||
border: 0;
|
||||
|
||||
10
app/controllers/admin/poll/base_controller.rb
Normal file
10
app/controllers/admin/poll/base_controller.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
class Admin::Poll::BaseController < Admin::BaseController
|
||||
helper_method :namespace
|
||||
|
||||
private
|
||||
|
||||
def namespace
|
||||
"admin"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
class Admin::Poll::BoothAssignmentsController < Admin::BaseController
|
||||
class Admin::Poll::BoothAssignmentsController < Admin::Poll::BaseController
|
||||
|
||||
before_action :load_poll, except: [:create, :destroy]
|
||||
|
||||
@@ -15,7 +15,7 @@ class Admin::Poll::BoothAssignmentsController < Admin::BaseController
|
||||
end
|
||||
|
||||
def show
|
||||
@booth_assignment = @poll.booth_assignments.includes(:final_recounts, :voters,
|
||||
@booth_assignment = @poll.booth_assignments.includes(:total_results, :voters,
|
||||
officer_assignments: [officer: [:user]]).find(params[:id])
|
||||
@voters_by_date = @booth_assignment.voters.group_by {|v| v.created_at.to_date}
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class Admin::Poll::BoothsController < Admin::BaseController
|
||||
class Admin::Poll::BoothsController < Admin::Poll::BaseController
|
||||
load_and_authorize_resource class: 'Poll::Booth'
|
||||
|
||||
def index
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class Admin::Poll::OfficerAssignmentsController < Admin::BaseController
|
||||
class Admin::Poll::OfficerAssignmentsController < Admin::Poll::BaseController
|
||||
|
||||
before_action :load_poll
|
||||
before_action :redirect_if_blank_required_params, only: [:by_officer]
|
||||
@@ -18,7 +18,7 @@ class Admin::Poll::OfficerAssignmentsController < Admin::BaseController
|
||||
@officer = ::Poll::Officer.includes(:user).find(officer_assignment_params[:officer_id])
|
||||
@officer_assignments = ::Poll::OfficerAssignment.
|
||||
joins(:booth_assignment).
|
||||
includes(:final_recounts, booth_assignment: :booth).
|
||||
includes(:total_results, booth_assignment: :booth).
|
||||
where("officer_id = ? AND poll_booth_assignments.poll_id = ?", @officer.id, @poll.id).
|
||||
order(:date)
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class Admin::Poll::OfficersController < Admin::BaseController
|
||||
class Admin::Poll::OfficersController < Admin::Poll::BaseController
|
||||
load_and_authorize_resource :officer, class: "Poll::Officer", except: [:edit, :show]
|
||||
|
||||
def index
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class Admin::Poll::PollsController < Admin::BaseController
|
||||
class Admin::Poll::PollsController < Admin::Poll::BaseController
|
||||
load_and_authorize_resource
|
||||
|
||||
before_action :load_search, only: [:search_booths, :search_questions, :search_officers]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class Admin::Poll::QuestionsController < Admin::BaseController
|
||||
class Admin::Poll::QuestionsController < Admin::Poll::BaseController
|
||||
include CommentableActions
|
||||
|
||||
load_and_authorize_resource :poll
|
||||
@@ -22,7 +22,6 @@ class Admin::Poll::QuestionsController < Admin::BaseController
|
||||
|
||||
def create
|
||||
@question.author = @question.proposal.try(:author) || current_user
|
||||
recover_documents_from_cache(@question)
|
||||
|
||||
if @question.save
|
||||
redirect_to admin_question_path(@question)
|
||||
@@ -32,7 +31,6 @@ class Admin::Poll::QuestionsController < Admin::BaseController
|
||||
end
|
||||
|
||||
def show
|
||||
@document = Document.new(documentable: @question)
|
||||
end
|
||||
|
||||
def edit
|
||||
@@ -59,7 +57,7 @@ class Admin::Poll::QuestionsController < Admin::BaseController
|
||||
|
||||
def question_params
|
||||
params.require(:poll_question).permit(:poll_id, :title, :question, :description, :proposal_id, :valid_answers, :video_url,
|
||||
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id])
|
||||
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy])
|
||||
end
|
||||
|
||||
def search_params
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
class Admin::Poll::RecountsController < Admin::BaseController
|
||||
class Admin::Poll::RecountsController < Admin::Poll::BaseController
|
||||
before_action :load_poll
|
||||
|
||||
def index
|
||||
@booth_assignments = @poll.booth_assignments.
|
||||
includes(:booth, :final_recounts, :voters).
|
||||
includes(:booth, :total_results, :voters).
|
||||
order("poll_booths.name").
|
||||
page(params[:page]).per(50)
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class Admin::Poll::ResultsController < Admin::BaseController
|
||||
class Admin::Poll::ResultsController < Admin::Poll::BaseController
|
||||
before_action :load_poll
|
||||
|
||||
def index
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class Admin::Poll::ShiftsController < Admin::BaseController
|
||||
class Admin::Poll::ShiftsController < Admin::Poll::BaseController
|
||||
|
||||
before_action :load_booth
|
||||
before_action :load_polls
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Admin::SettingsController < Admin::BaseController
|
||||
|
||||
def index
|
||||
all_settings = (Setting.all).group_by { |s| s.type }
|
||||
all_settings = Setting.all.group_by { |s| s.type }
|
||||
@settings = all_settings['common']
|
||||
@feature_flags = all_settings['feature']
|
||||
@banner_styles = all_settings['banner-style']
|
||||
|
||||
@@ -44,12 +44,10 @@ module Budgets
|
||||
set_comment_flags(@comment_tree.comments)
|
||||
load_investment_votes(@investment)
|
||||
@investment_ids = [@investment.id]
|
||||
@document = Document.new(documentable: @investment)
|
||||
end
|
||||
|
||||
def create
|
||||
@investment.author = current_user
|
||||
recover_documents_from_cache(@investment)
|
||||
|
||||
if @investment.save
|
||||
Mailer.budget_investment_created(@investment).deliver_later
|
||||
@@ -105,9 +103,11 @@ module Budgets
|
||||
end
|
||||
|
||||
def investment_params
|
||||
params.require(:budget_investment).permit(:title, :description, :external_url, :heading_id, :tag_list,
|
||||
:organization_name, :location, :terms_of_service,
|
||||
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id])
|
||||
params.require(:budget_investment)
|
||||
.permit(:title, :description, :external_url, :heading_id, :tag_list,
|
||||
:organization_name, :location, :terms_of_service,
|
||||
image_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy],
|
||||
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy])
|
||||
end
|
||||
|
||||
def load_ballot
|
||||
|
||||
@@ -62,10 +62,7 @@ module CommentableActions
|
||||
end
|
||||
|
||||
def update
|
||||
resource.assign_attributes(strong_params)
|
||||
recover_documents_from_cache(resource)
|
||||
|
||||
if resource.save
|
||||
if resource.update(strong_params)
|
||||
redirect_to resource, notice: t("flash.actions.update.#{resource_name.underscore}")
|
||||
else
|
||||
load_categories
|
||||
@@ -117,11 +114,4 @@ module CommentableActions
|
||||
nil
|
||||
end
|
||||
|
||||
def recover_documents_from_cache(resource)
|
||||
return false unless resource.try(:documents)
|
||||
resource.documents = resource.documents.each do |document|
|
||||
document.set_attachment_from_cached_attachment if document.cached_attachment.present?
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
49
app/controllers/direct_uploads_controller.rb
Normal file
49
app/controllers/direct_uploads_controller.rb
Normal file
@@ -0,0 +1,49 @@
|
||||
class DirectUploadsController < ApplicationController
|
||||
include DirectUploadsHelper
|
||||
include ActionView::Helpers::UrlHelper
|
||||
before_action :authenticate_user!
|
||||
|
||||
load_and_authorize_resource except: :create
|
||||
skip_authorization_check only: :create
|
||||
|
||||
helper_method :render_destroy_upload_link
|
||||
|
||||
def create
|
||||
@direct_upload = DirectUpload.new(direct_upload_params.merge(user: current_user, attachment: params[:attachment]))
|
||||
|
||||
if @direct_upload.valid?
|
||||
@direct_upload.save_attachment
|
||||
@direct_upload.relation.set_cached_attachment_from_attachment
|
||||
|
||||
render json: { cached_attachment: @direct_upload.relation.cached_attachment,
|
||||
filename: @direct_upload.relation.attachment.original_filename,
|
||||
destroy_link: render_destroy_upload_link(@direct_upload).html_safe,
|
||||
attachment_url: @direct_upload.relation.attachment.url
|
||||
}
|
||||
else
|
||||
@direct_upload.destroy_attachment
|
||||
render json: { errors: @direct_upload.errors[:attachment].join(", ") },
|
||||
status: 422
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@direct_upload = DirectUpload.new(direct_upload_params.merge(user: current_user) )
|
||||
@direct_upload.relation.set_attachment_from_cached_attachment
|
||||
|
||||
if @direct_upload.destroy_attachment
|
||||
render json: :ok
|
||||
else
|
||||
render json: :error
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def direct_upload_params
|
||||
params.require(:direct_upload)
|
||||
.permit(:resource, :resource_type, :resource_id, :resource_relation,
|
||||
:attachment, :cached_attachment, attachment_attributes: [])
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,29 +1,7 @@
|
||||
class DocumentsController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :find_documentable, except: :destroy
|
||||
before_action :prepare_new_document, only: [:new, :new_nested]
|
||||
before_action :prepare_document_for_creation, only: :create
|
||||
|
||||
load_and_authorize_resource except: :upload
|
||||
skip_authorization_check only: :upload
|
||||
|
||||
def new
|
||||
end
|
||||
|
||||
def new_nested
|
||||
end
|
||||
|
||||
def create
|
||||
recover_attachments_from_cache
|
||||
|
||||
if @document.save
|
||||
flash[:notice] = t "documents.actions.create.notice"
|
||||
redirect_to params[:from]
|
||||
else
|
||||
flash[:alert] = t "documents.actions.create.alert"
|
||||
render :new
|
||||
end
|
||||
end
|
||||
load_and_authorize_resource
|
||||
|
||||
def destroy
|
||||
respond_to do |format|
|
||||
@@ -45,57 +23,4 @@ class DocumentsController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_upload
|
||||
@document = Document.new(cached_attachment: params[:path])
|
||||
@document.set_attachment_from_cached_attachment
|
||||
@document.cached_attachment = nil
|
||||
@document.documentable = @documentable
|
||||
|
||||
if @document.attachment.destroy
|
||||
flash.now[:notice] = t "documents.actions.destroy.notice"
|
||||
else
|
||||
flash.now[:alert] = t "documents.actions.destroy.alert"
|
||||
end
|
||||
render :destroy
|
||||
end
|
||||
|
||||
def upload
|
||||
@document = Document.new(document_params.merge(user: current_user))
|
||||
@document.documentable = @documentable
|
||||
|
||||
if @document.valid?
|
||||
@document.attachment.save
|
||||
@document.set_cached_attachment_from_attachment(URI(request.url))
|
||||
else
|
||||
@document.attachment.destroy
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def document_params
|
||||
params.require(:document).permit(:title, :documentable_type, :documentable_id,
|
||||
:attachment, :cached_attachment, :user_id)
|
||||
end
|
||||
|
||||
def find_documentable
|
||||
@documentable = params[:documentable_type].constantize.find_or_initialize_by(id: params[:documentable_id])
|
||||
end
|
||||
|
||||
def prepare_new_document
|
||||
@document = Document.new(documentable: @documentable, user_id: current_user.id)
|
||||
end
|
||||
|
||||
def prepare_document_for_creation
|
||||
@document = Document.new(document_params)
|
||||
@document.documentable = @documentable
|
||||
@document.user = current_user
|
||||
end
|
||||
|
||||
def recover_attachments_from_cache
|
||||
if @document.attachment.blank? && @document.cached_attachment.present?
|
||||
@document.set_attachment_from_cached_attachment
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
26
app/controllers/images_controller.rb
Normal file
26
app/controllers/images_controller.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
class ImagesController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
|
||||
load_and_authorize_resource
|
||||
|
||||
def destroy
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
if @image.destroy
|
||||
flash[:notice] = t "images.actions.destroy.notice"
|
||||
else
|
||||
flash[:alert] = t "images.actions.destroy.alert"
|
||||
end
|
||||
redirect_to params[:from]
|
||||
end
|
||||
format.js do
|
||||
if @image.destroy
|
||||
flash.now[:notice] = t "images.actions.destroy.notice"
|
||||
else
|
||||
flash.now[:alert] = t "images.actions.destroy.alert"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -30,7 +30,7 @@ class Legislation::AnnotationsController < ApplicationController
|
||||
|
||||
def create
|
||||
if !@process.allegations_phase.open? || @draft_version.final_version?
|
||||
render(json: {}, status: :not_found) && (return)
|
||||
render(json: {}, status: :not_found) && return
|
||||
end
|
||||
|
||||
existing_annotation = @draft_version.annotations.where(
|
||||
|
||||
@@ -30,7 +30,7 @@ class Legislation::AnswersController < Legislation::BaseController
|
||||
|
||||
def answer_params
|
||||
params.require(:legislation_answer).permit(
|
||||
:legislation_question_option_id,
|
||||
:legislation_question_option_id
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ class Management::DocumentVerificationsController < Management::BaseController
|
||||
before_action :set_document, only: :check
|
||||
|
||||
def index
|
||||
@document_verification = Verification::Management::Document.new()
|
||||
@document_verification = Verification::Management::Document.new
|
||||
end
|
||||
|
||||
def check
|
||||
|
||||
@@ -7,7 +7,7 @@ class Officing::PollsController < Officing::BaseController
|
||||
|
||||
def final
|
||||
@polls = if current_user.poll_officer?
|
||||
current_user.poll_officer.final_days_assigned_polls.select {|poll| poll.ends_at > 2.week.ago && poll.expired?}
|
||||
current_user.poll_officer.final_days_assigned_polls.select {|poll| poll.ends_at > 2.weeks.ago && poll.expired?}
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
@@ -52,20 +52,19 @@ class Officing::ResultsController < Officing::BaseController
|
||||
go_back_to_new if question.blank?
|
||||
|
||||
results.each_pair do |answer_index, count|
|
||||
if count.present?
|
||||
answer = question.valid_answers[answer_index.to_i]
|
||||
go_back_to_new if question.blank?
|
||||
next unless count.present?
|
||||
answer = question.valid_answers[answer_index.to_i]
|
||||
go_back_to_new if question.blank?
|
||||
|
||||
partial_result = ::Poll::PartialResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
|
||||
date: results_params[:date],
|
||||
question_id: question_id,
|
||||
answer: answer)
|
||||
partial_result.officer_assignment_id = @officer_assignment.id
|
||||
partial_result.amount = count.to_i
|
||||
partial_result.author = current_user
|
||||
partial_result.origin = 'booth'
|
||||
@results << partial_result
|
||||
end
|
||||
partial_result = ::Poll::PartialResult.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id,
|
||||
date: results_params[:date],
|
||||
question_id: question_id,
|
||||
answer: answer)
|
||||
partial_result.officer_assignment_id = @officer_assignment.id
|
||||
partial_result.amount = count.to_i
|
||||
partial_result.author = current_user
|
||||
partial_result.origin = 'booth'
|
||||
@results << partial_result
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -10,8 +10,6 @@ class Polls::QuestionsController < ApplicationController
|
||||
@comment_tree = CommentTree.new(@commentable, params[:page], @current_order)
|
||||
set_comment_flags(@comment_tree.comments)
|
||||
|
||||
@document = Document.new(documentable: @question)
|
||||
|
||||
question_answer = @question.answers.where(author_id: current_user.try(:id)).first
|
||||
@answers_by_question_id = {@question.id => question_answer.try(:answer)}
|
||||
end
|
||||
|
||||
@@ -19,13 +19,11 @@ class ProposalsController < ApplicationController
|
||||
def show
|
||||
super
|
||||
@notifications = @proposal.notifications
|
||||
@document = Document.new(documentable: @proposal)
|
||||
redirect_to proposal_path(@proposal), status: :moved_permanently if request.path != proposal_path(@proposal)
|
||||
end
|
||||
|
||||
def create
|
||||
@proposal = Proposal.new(proposal_params.merge(author: current_user))
|
||||
recover_documents_from_cache(@proposal)
|
||||
|
||||
if @proposal.save
|
||||
redirect_to share_proposal_path(@proposal), notice: I18n.t('flash.actions.create.proposal')
|
||||
@@ -78,7 +76,8 @@ class ProposalsController < ApplicationController
|
||||
def proposal_params
|
||||
params.require(:proposal).permit(:title, :question, :summary, :description, :external_url, :video_url,
|
||||
:responsible_name, :tag_list, :terms_of_service, :geozone_id,
|
||||
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id])
|
||||
image_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy],
|
||||
documents_attributes: [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy] )
|
||||
end
|
||||
|
||||
def retired_params
|
||||
|
||||
11
app/controllers/tags_controller.rb
Normal file
11
app/controllers/tags_controller.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
class TagsController < ApplicationController
|
||||
|
||||
load_and_authorize_resource class: ActsAsTaggableOn::Tag
|
||||
respond_to :json
|
||||
|
||||
def suggest
|
||||
@tags = ActsAsTaggableOn::Tag.search(params[:search]).map(&:name)
|
||||
respond_with @tags
|
||||
end
|
||||
|
||||
end
|
||||
@@ -25,7 +25,7 @@ module AdminHelper
|
||||
end
|
||||
|
||||
def menu_polls?
|
||||
["polls", "questions", "officers", "booths", "officer_assignments", "booth_assignments", "recounts", "results", "shifts"].include? controller_name
|
||||
%w[polls questions officers booths officer_assignments booth_assignments recounts results shifts].include? controller_name
|
||||
end
|
||||
|
||||
def menu_profiles?
|
||||
|
||||
16
app/helpers/direct_uploads_helper.rb
Normal file
16
app/helpers/direct_uploads_helper.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
module DirectUploadsHelper
|
||||
|
||||
def render_destroy_upload_link(direct_upload)
|
||||
label = direct_upload.resource_relation == "image" ? "images" : "documents"
|
||||
link_to t("#{label}.form.delete_button"),
|
||||
direct_upload_destroy_url("direct_upload[resource_type]": direct_upload.resource_type,
|
||||
"direct_upload[resource_id]": direct_upload.resource_id,
|
||||
"direct_upload[resource_relation]": direct_upload.resource_relation,
|
||||
"direct_upload[cached_attachment]": direct_upload.relation.cached_attachment,
|
||||
format: :json),
|
||||
method: :delete,
|
||||
remote: true,
|
||||
class: "delete remove-cached-attachment"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -8,12 +8,12 @@ module DocumentablesHelper
|
||||
documentable.class.max_documents_allowed
|
||||
end
|
||||
|
||||
def max_file_size(documentable)
|
||||
bytes_to_mega(documentable.class.max_file_size)
|
||||
def max_file_size(documentable_class)
|
||||
bytes_to_mega(documentable_class.max_file_size)
|
||||
end
|
||||
|
||||
def accepted_content_types(documentable)
|
||||
documentable.class.accepted_content_types
|
||||
def accepted_content_types(documentable_class)
|
||||
documentable_class.accepted_content_types
|
||||
end
|
||||
|
||||
def accepted_content_types_extensions(documentable_class)
|
||||
@@ -22,16 +22,16 @@ module DocumentablesHelper
|
||||
.join(",")
|
||||
end
|
||||
|
||||
def humanized_accepted_content_types(documentable)
|
||||
documentable.class.accepted_content_types
|
||||
def documentable_humanized_accepted_content_types(documentable_class)
|
||||
documentable_class.accepted_content_types
|
||||
.collect{ |content_type| content_type.split("/").last }
|
||||
.join(", ")
|
||||
end
|
||||
|
||||
def documentables_note(documentable)
|
||||
t "documents.form.note", max_documents_allowed: max_documents_allowed(documentable),
|
||||
accepted_content_types: humanized_accepted_content_types(documentable),
|
||||
max_file_size: max_file_size(documentable)
|
||||
accepted_content_types: documentable_humanized_accepted_content_types(documentable.class),
|
||||
max_file_size: max_file_size(documentable.class)
|
||||
end
|
||||
|
||||
def max_documents_allowed?(documentable)
|
||||
|
||||
@@ -4,7 +4,7 @@ module DocumentsHelper
|
||||
document.attachment_file_name
|
||||
end
|
||||
|
||||
def errors_on_attachment(document)
|
||||
def document_errors_on_attachment(document)
|
||||
document.errors[:attachment].join(', ') if document.errors.key?(:attachment)
|
||||
end
|
||||
|
||||
@@ -12,78 +12,46 @@ module DocumentsHelper
|
||||
bytes / Numeric::MEGABYTE
|
||||
end
|
||||
|
||||
def document_nested_field_name(document, index, field)
|
||||
parent = document.documentable_type.parameterize.underscore
|
||||
"#{parent.parameterize}[documents_attributes][#{index}][#{field}]"
|
||||
end
|
||||
|
||||
def document_nested_field_id(document, index, field)
|
||||
parent = document.documentable_type.parameterize.underscore
|
||||
"#{parent.parameterize}_documents_attributes_#{index}_#{field}"
|
||||
end
|
||||
|
||||
def document_nested_field_wrapper_id(index)
|
||||
"document_#{index}"
|
||||
end
|
||||
|
||||
def render_destroy_document_link(document, index)
|
||||
if document.persisted?
|
||||
def render_destroy_document_link(builder, document)
|
||||
if !document.persisted? && document.cached_attachment.present?
|
||||
link_to t('documents.form.delete_button'),
|
||||
document_path(document, index: index, nested_document: true),
|
||||
method: :delete,
|
||||
remote: true,
|
||||
data: { confirm: t('documents.actions.destroy.confirm') },
|
||||
class: "delete float-right"
|
||||
elsif !document.persisted? && document.cached_attachment.present?
|
||||
link_to t('documents.form.delete_button'),
|
||||
destroy_upload_documents_path(path: document.cached_attachment,
|
||||
nested_document: true,
|
||||
index: index,
|
||||
documentable_type: document.documentable_type,
|
||||
documentable_id: document.documentable_id),
|
||||
method: :delete,
|
||||
remote: true,
|
||||
class: "delete float-right"
|
||||
direct_upload_destroy_url("direct_upload[resource_type]": document.documentable_type,
|
||||
"direct_upload[resource_id]": document.documentable_id,
|
||||
"direct_upload[resource_relation]": "documents",
|
||||
"direct_upload[cached_attachment]": document.cached_attachment),
|
||||
method: :delete,
|
||||
remote: true,
|
||||
class: "delete remove-cached-attachment"
|
||||
else
|
||||
link_to t('documents.form.delete_button'),
|
||||
"#",
|
||||
class: "delete float-right remove-document"
|
||||
link_to_remove_association t('documents.form.delete_button'), builder, class: "delete remove-document"
|
||||
end
|
||||
end
|
||||
|
||||
def render_attachment(document, index)
|
||||
html = file_field_tag :attachment,
|
||||
accept: accepted_content_types_extensions(document.documentable_type.constantize),
|
||||
class: 'document_ajax_attachment',
|
||||
data: {
|
||||
url: document_direct_upload_url(document),
|
||||
cached_attachment_input_field: document_nested_field_id(document, index, :cached_attachment),
|
||||
multiple: false,
|
||||
index: index,
|
||||
nested_document: true
|
||||
},
|
||||
name: document_nested_field_name(document, index, :attachment),
|
||||
id: document_nested_field_id(document, index, :attachment)
|
||||
if document.attachment.blank? && document.cached_attachment.blank?
|
||||
klass = document.errors[:attachment].any? ? "error" : ""
|
||||
html += label_tag document_nested_field_id(document, index, :attachment),
|
||||
t("documents.form.attachment_label"),
|
||||
class: "button hollow #{klass}"
|
||||
if document.errors[:attachment].any?
|
||||
html += content_tag :small, class: "error" do
|
||||
errors_on_attachment(document)
|
||||
end
|
||||
end
|
||||
end
|
||||
def render_attachment(builder, document)
|
||||
klass = document.errors[:attachment].any? ? "error" : ""
|
||||
klass = document.persisted? || document.cached_attachment.present? ? " hide" : ""
|
||||
html = builder.label :attachment,
|
||||
t("documents.form.attachment_label"),
|
||||
class: "button hollow #{klass}"
|
||||
html += builder.file_field :attachment,
|
||||
label: false,
|
||||
accept: accepted_content_types_extensions(document.documentable_type.constantize),
|
||||
class: 'js-document-attachment',
|
||||
data: {
|
||||
url: document_direct_upload_url(document),
|
||||
nested_document: true
|
||||
}
|
||||
html
|
||||
end
|
||||
|
||||
def document_direct_upload_url(document)
|
||||
upload_documents_url(
|
||||
documentable_type: document.documentable_type,
|
||||
documentable_id: document.documentable_id,
|
||||
format: :js
|
||||
)
|
||||
direct_uploads_url("direct_upload[resource_type]": document.documentable_type,
|
||||
"direct_upload[resource_id]": document.documentable_id,
|
||||
"direct_upload[resource_relation]": "documents")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
40
app/helpers/imageables_helper.rb
Normal file
40
app/helpers/imageables_helper.rb
Normal file
@@ -0,0 +1,40 @@
|
||||
module ImageablesHelper
|
||||
|
||||
def can_destroy_image?(imageable)
|
||||
imageable.image.present? && can?(:destroy, imageable.image)
|
||||
end
|
||||
|
||||
def imageable_class(imageable)
|
||||
imageable.class.name.parameterize('_')
|
||||
end
|
||||
|
||||
def imageable_max_file_size
|
||||
bytesToMeg(Image::MAX_IMAGE_SIZE)
|
||||
end
|
||||
|
||||
def bytesToMeg(bytes)
|
||||
bytes / Numeric::MEGABYTE
|
||||
end
|
||||
|
||||
def imageable_accepted_content_types
|
||||
Image::ACCEPTED_CONTENT_TYPE
|
||||
end
|
||||
|
||||
def imageable_accepted_content_types_extensions
|
||||
Image::ACCEPTED_CONTENT_TYPE
|
||||
.collect{ |content_type| ".#{content_type.split("/").last}" }
|
||||
.join(",")
|
||||
end
|
||||
|
||||
def imageable_humanized_accepted_content_types
|
||||
Image::ACCEPTED_CONTENT_TYPE
|
||||
.collect{ |content_type| content_type.split("/").last }
|
||||
.join(", ")
|
||||
end
|
||||
|
||||
def imageables_note(imageable)
|
||||
t "images.form.note", accepted_content_types: imageable_humanized_accepted_content_types,
|
||||
max_file_size: imageable_max_file_size
|
||||
end
|
||||
|
||||
end
|
||||
79
app/helpers/images_helper.rb
Normal file
79
app/helpers/images_helper.rb
Normal file
@@ -0,0 +1,79 @@
|
||||
module ImagesHelper
|
||||
|
||||
def image_absolute_url(image, version)
|
||||
return "" unless image
|
||||
if Paperclip::Attachment.default_options[:storage] == :filesystem
|
||||
URI(request.url) + image.attachment.url(version)
|
||||
else
|
||||
investment.image_url(version)
|
||||
end
|
||||
end
|
||||
|
||||
def image_first_recommendation(image)
|
||||
t "images.#{image.imageable.class.name.parameterize.underscore}.recommendation_one_html",
|
||||
title: image.imageable.title
|
||||
end
|
||||
|
||||
def image_attachment_file_name(image)
|
||||
image.attachment_file_name
|
||||
end
|
||||
|
||||
def image_errors_on_attachment(image)
|
||||
image.errors[:attachment].join(', ') if image.errors.key?(:attachment)
|
||||
end
|
||||
|
||||
def image_bytesToMeg(bytes)
|
||||
bytes / Numeric::MEGABYTE
|
||||
end
|
||||
|
||||
def image_class(image)
|
||||
image.persisted? ? "persisted-image" : "cached-image"
|
||||
end
|
||||
|
||||
def render_destroy_image_link(builder, image)
|
||||
if !image.persisted? && image.cached_attachment.present?
|
||||
link_to t('images.form.delete_button'),
|
||||
direct_upload_destroy_url("direct_upload[resource_type]": image.imageable_type,
|
||||
"direct_upload[resource_id]": image.imageable_id,
|
||||
"direct_upload[resource_relation]": "image",
|
||||
"direct_upload[cached_attachment]": image.cached_attachment),
|
||||
method: :delete,
|
||||
remote: true,
|
||||
class: "delete remove-cached-attachment"
|
||||
else
|
||||
link_to_remove_association t('images.form.delete_button'), builder, class: "delete remove-image"
|
||||
end
|
||||
end
|
||||
|
||||
def render_image_attachment(builder, imageable, image)
|
||||
klass = image.errors[:attachment].any? ? "error" : ""
|
||||
klass = image.persisted? || image.cached_attachment.present? ? " hide" : ""
|
||||
html = builder.label :attachment,
|
||||
t("images.form.attachment_label"),
|
||||
class: "button hollow #{klass}"
|
||||
html += builder.file_field :attachment,
|
||||
label: false,
|
||||
accept: imageable_accepted_content_types_extensions,
|
||||
class: 'js-image-attachment',
|
||||
data: {
|
||||
url: image_direct_upload_url(imageable),
|
||||
nested_image: true
|
||||
}
|
||||
|
||||
html
|
||||
end
|
||||
|
||||
def render_image(image, version, show_caption = true)
|
||||
version = image.persisted? ? version : :original
|
||||
render partial: "images/image", locals: { image: image,
|
||||
version: version,
|
||||
show_caption: show_caption }
|
||||
end
|
||||
|
||||
def image_direct_upload_url(imageable)
|
||||
direct_uploads_url("direct_upload[resource_type]": imageable.class.name,
|
||||
"direct_upload[resource_id]": imageable.id,
|
||||
"direct_upload[resource_relation]": "image")
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,13 +1,5 @@
|
||||
module OfficingHelper
|
||||
|
||||
def officer_assignments_select_options(officer_assignments)
|
||||
options = []
|
||||
officer_assignments.each do |oa|
|
||||
options << ["#{oa.booth_assignment.booth.name}: #{l(oa.date.to_date, format: :long)}", oa.id]
|
||||
end
|
||||
options_for_select(options)
|
||||
end
|
||||
|
||||
def booths_for_officer_select_options(officer_assignments)
|
||||
options = []
|
||||
officer_assignments.each do |oa|
|
||||
@@ -17,10 +9,6 @@ module OfficingHelper
|
||||
options_for_select(options, params[:oa])
|
||||
end
|
||||
|
||||
def system_recount_to_compare_with_final_recount(final_recount)
|
||||
final_recount.booth_assignment.voters.select {|v| v.created_at.to_date == final_recount.date}.size
|
||||
end
|
||||
|
||||
def answer_result_value(question_id, answer_index)
|
||||
return nil if params.blank?
|
||||
return nil if params[:questions].blank?
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
module PollFinalRecountsHelper
|
||||
|
||||
def final_recount_for_date(final_recounts, date)
|
||||
final_recounts.select {|f| f.date == date}.first
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,7 +1,7 @@
|
||||
module PollRecountsHelper
|
||||
|
||||
def booth_assignment_sum_final_recounts(ba)
|
||||
ba.final_recounts.any? ? ba.final_recounts.to_a.sum(&:count) : nil
|
||||
def total_recounts_by_booth(booth_assignment)
|
||||
booth_assignment.total_results.any? ? booth_assignment.total_results.to_a.sum(&:amount) : nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -28,11 +28,6 @@ module PollsHelper
|
||||
options_for_select(options, params[:d])
|
||||
end
|
||||
|
||||
def poll_final_recount_option(poll)
|
||||
final_date = poll.ends_at.to_date + 1.day
|
||||
options_for_select([[I18n.t("polls.final_date"), l(final_date)]])
|
||||
end
|
||||
|
||||
def poll_booths_select_options(poll)
|
||||
options = []
|
||||
poll.booths.each do |booth|
|
||||
|
||||
@@ -12,8 +12,8 @@ module ProposalsHelper
|
||||
percentage = (proposal.total_votes.to_f * 100 / Proposal.votes_needed_for_success)
|
||||
case percentage
|
||||
when 0 then "0%"
|
||||
when 0..(0.1) then "0.1%"
|
||||
when (0.1)..100 then number_to_percentage(percentage, strip_insignificant_zeros: true, precision: 1)
|
||||
when 0..0.1 then "0.1%"
|
||||
when 0.1..100 then number_to_percentage(percentage, strip_insignificant_zeros: true, precision: 1)
|
||||
else "100%"
|
||||
end
|
||||
end
|
||||
@@ -40,11 +40,6 @@ module ProposalsHelper
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def can_create_document?(document, proposal)
|
||||
can?(:create, document) && proposal.documents.size < Proposal.max_documents_allowed
|
||||
end
|
||||
|
||||
def author_of_proposal?(proposal)
|
||||
author_of?(proposal, current_user)
|
||||
end
|
||||
|
||||
@@ -19,14 +19,14 @@ module WelcomeHelper
|
||||
end
|
||||
end
|
||||
|
||||
def render_image(recommended, image_field, image_version, image_default)
|
||||
image_path = calculate_image_path(recommended, image_field, image_version, image_default)
|
||||
def render_recommendation_image(recommended, image_default)
|
||||
image_path = calculate_image_path(recommended, image_default)
|
||||
image_tag(image_path) if image_path.present?
|
||||
end
|
||||
|
||||
def calculate_image_path(recommended, image_field, image_version, image_default)
|
||||
if image_field.present? && image_version.present?
|
||||
recommended.send("#{image_field}", image_version)
|
||||
def calculate_image_path(recommended, image_default)
|
||||
if recommended.try(:image) && recommended.image.present? && recommended.image.attachment.exists?
|
||||
recommended.image.attachment.send("url", :medium)
|
||||
elsif image_default.present?
|
||||
image_default
|
||||
end
|
||||
|
||||
@@ -74,6 +74,8 @@ module Abilities
|
||||
cannot :comment_as_moderator, [::Legislation::Question, Legislation::Annotation]
|
||||
|
||||
can [:create, :destroy], Document
|
||||
can [:destroy], Image
|
||||
can [:create, :destroy], DirectUpload
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -24,6 +24,7 @@ module Abilities
|
||||
|
||||
can :suggest, Debate
|
||||
can :suggest, Proposal
|
||||
can :suggest, ActsAsTaggableOn::Tag
|
||||
|
||||
can [:flag, :unflag], Comment
|
||||
cannot [:flag, :unflag], Comment, user_id: user.id
|
||||
@@ -36,8 +37,11 @@ module Abilities
|
||||
|
||||
can [:create, :destroy], Follow
|
||||
|
||||
can [:create, :destroy, :new], Document, documentable: { author_id: user.id }
|
||||
can [:new_nested, :upload, :destroy_upload], Document
|
||||
can [:destroy], Document, documentable: { author_id: user.id }
|
||||
|
||||
can [:destroy], Image, imageable: { author_id: user.id }
|
||||
|
||||
can [:create, :destroy], DirectUpload
|
||||
|
||||
unless user.organization?
|
||||
can :vote, Debate
|
||||
@@ -54,6 +58,7 @@ module Abilities
|
||||
can :suggest, Budget::Investment, budget: { phase: "accepting" }
|
||||
can :destroy, Budget::Investment, budget: { phase: ["accepting", "reviewing"] }, author_id: user.id
|
||||
can :vote, Budget::Investment, budget: { phase: "selecting" }
|
||||
|
||||
can [:show, :create], Budget::Ballot, budget: { phase: "balloting" }
|
||||
can [:create, :destroy], Budget::Ballot::Line, budget: { phase: "balloting" }
|
||||
|
||||
|
||||
@@ -7,11 +7,11 @@ class Budget
|
||||
include Reclassification
|
||||
include Followable
|
||||
include Communitable
|
||||
include Imageable
|
||||
include Documentable
|
||||
documentable max_documents_allowed: 3,
|
||||
max_file_size: 3.megabytes,
|
||||
accepted_content_types: [ "application/pdf" ]
|
||||
accepts_nested_attributes_for :documents, allow_destroy: true
|
||||
|
||||
acts_as_votable
|
||||
acts_as_paranoid column: :hidden_at
|
||||
|
||||
@@ -3,6 +3,7 @@ module Documentable
|
||||
|
||||
included do
|
||||
has_many :documents, as: :documentable, dependent: :destroy
|
||||
accepts_nested_attributes_for :documents, allow_destroy: true
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
@@ -15,6 +16,7 @@ module Documentable
|
||||
@max_file_size = options[:max_file_size]
|
||||
@accepted_content_types = options[:accepted_content_types]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -24,7 +24,7 @@ module Graphqlable
|
||||
end
|
||||
|
||||
def graphql_type_description
|
||||
(model_name.human).to_s
|
||||
model_name.human.to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
14
app/models/concerns/imageable.rb
Normal file
14
app/models/concerns/imageable.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
# can [:update, :destroy ], Image, :imageable_id => user.id, :imageable_type => 'User'
|
||||
# and add a feature like forbidden/without_role_images_spec.rb to test it
|
||||
module Imageable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
has_one :image, as: :imageable, dependent: :destroy
|
||||
accepts_nested_attributes_for :image, allow_destroy: true, update_only: true
|
||||
|
||||
def image_url(style)
|
||||
image.attachment.url(style) if image && image.attachment.exists?
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -55,10 +55,9 @@ module Verification
|
||||
end
|
||||
|
||||
def user_type
|
||||
case
|
||||
when level_three_verified?
|
||||
if level_three_verified?
|
||||
:level_3_user
|
||||
when level_two_verified?
|
||||
elsif level_two_verified?
|
||||
:level_2_user
|
||||
else
|
||||
:level_1_user
|
||||
|
||||
@@ -95,7 +95,7 @@ class Debate < ActiveRecord::Base
|
||||
|
||||
def register_vote(user, vote_value)
|
||||
if votable_by?(user)
|
||||
Debate.increment_counter(:cached_anonymous_votes_total, id) if (user.unverified? && !user.voted_for?(self))
|
||||
Debate.increment_counter(:cached_anonymous_votes_total, id) if user.unverified? && !user.voted_for?(self)
|
||||
vote_by(voter: user, vote: vote_value)
|
||||
end
|
||||
end
|
||||
|
||||
62
app/models/direct_upload.rb
Normal file
62
app/models/direct_upload.rb
Normal file
@@ -0,0 +1,62 @@
|
||||
class DirectUpload
|
||||
include ActiveModel::Validations
|
||||
include ActiveModel::Conversion
|
||||
extend ActiveModel::Naming
|
||||
|
||||
attr_accessor :resource, :resource_type, :resource_id,
|
||||
:relation, :resource_relation,
|
||||
:attachment, :cached_attachment, :user
|
||||
|
||||
validates_presence_of :attachment, :resource_type, :resource_relation, :user
|
||||
validate :parent_resource_attachment_validations,
|
||||
if: -> { attachment.present? && resource_type.present? && resource_relation.present? && user.present? }
|
||||
|
||||
def initialize(attributes = {})
|
||||
attributes.each do |name, value|
|
||||
send("#{name}=", value)
|
||||
end
|
||||
|
||||
if @resource_type.present? && @resource_relation.present? && (@attachment.present? || @cached_attachment.present?)
|
||||
@resource = @resource_type.constantize.find_or_initialize_by(id: @resource_id)
|
||||
|
||||
if @resource.class.reflections[@resource_relation].macro == :has_one
|
||||
@relation = @resource.send("build_#{resource_relation}", relation_attributtes)
|
||||
else
|
||||
@relation = @resource.send(@resource_relation).build(relation_attributtes)
|
||||
end
|
||||
|
||||
@relation.user = user
|
||||
end
|
||||
end
|
||||
|
||||
def save_attachment
|
||||
@relation.attachment.save
|
||||
end
|
||||
|
||||
def destroy_attachment
|
||||
@relation.attachment.destroy
|
||||
end
|
||||
|
||||
def persisted?
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parent_resource_attachment_validations
|
||||
@relation.valid?
|
||||
|
||||
if @relation.errors.has_key? :attachment
|
||||
errors[:attachment] = @relation.errors[:attachment]
|
||||
end
|
||||
end
|
||||
|
||||
def relation_attributtes
|
||||
{
|
||||
attachment: @attachment,
|
||||
cached_attachment: @cached_attachment,
|
||||
user: @user
|
||||
}
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,14 +1,17 @@
|
||||
class Document < ActiveRecord::Base
|
||||
include DocumentsHelper
|
||||
include DocumentablesHelper
|
||||
has_attached_file :attachment, path: ":rails_root/public/system/:class/:prefix/:style/:filename"
|
||||
has_attached_file :attachment, url: "/system/:class/:prefix/:style/:hash.:extension",
|
||||
hash_data: ":class/:style",
|
||||
use_timestamp: false,
|
||||
hash_secret: Rails.application.secrets.secret_key_base
|
||||
attr_accessor :cached_attachment
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :documentable, polymorphic: true
|
||||
|
||||
# Disable paperclip security validation due to polymorphic configuration
|
||||
# Paperclip do not allow to user Procs on valiations definition
|
||||
# Paperclip do not allow to use Procs on valiations definition
|
||||
do_not_validate_attachment_file_type :attachment
|
||||
validate :attachment_presence
|
||||
validate :validate_attachment_content_type, if: -> { attachment.present? }
|
||||
@@ -18,13 +21,14 @@ class Document < ActiveRecord::Base
|
||||
validates :documentable_id, presence: true, if: -> { persisted? }
|
||||
validates :documentable_type, presence: true, if: -> { persisted? }
|
||||
|
||||
after_save :remove_cached_document, if: -> { valid? && persisted? && cached_attachment.present? }
|
||||
before_save :set_attachment_from_cached_attachment, if: -> { cached_attachment.present? }
|
||||
after_save :remove_cached_attachment, if: -> { cached_attachment.present? }
|
||||
|
||||
def set_cached_attachment_from_attachment(prefix)
|
||||
def set_cached_attachment_from_attachment
|
||||
self.cached_attachment = if Paperclip::Attachment.default_options[:storage] == :filesystem
|
||||
attachment.path
|
||||
else
|
||||
prefix + attachment.url
|
||||
attachment.url
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,7 +44,7 @@ class Document < ActiveRecord::Base
|
||||
attachment.instance.prefix(attachment, style)
|
||||
end
|
||||
|
||||
def prefix(attachment, _style)
|
||||
def prefix(attachment, style)
|
||||
if !attachment.instance.persisted?
|
||||
"cached_attachments/user/#{attachment.instance.user_id}"
|
||||
else
|
||||
@@ -50,21 +54,25 @@ class Document < ActiveRecord::Base
|
||||
|
||||
private
|
||||
|
||||
def documentable_class
|
||||
documentable_type.constantize if documentable_type.present?
|
||||
end
|
||||
|
||||
def validate_attachment_size
|
||||
if documentable.present? &&
|
||||
attachment_file_size > documentable.class.max_file_size
|
||||
if documentable_class.present? &&
|
||||
attachment_file_size > documentable_class.max_file_size
|
||||
errors[:attachment] = I18n.t("documents.errors.messages.in_between",
|
||||
min: "0 Bytes",
|
||||
max: "#{max_file_size(documentable)} MB")
|
||||
max: "#{max_file_size(documentable_class)} MB")
|
||||
end
|
||||
end
|
||||
|
||||
def validate_attachment_content_type
|
||||
if documentable.present? &&
|
||||
!accepted_content_types(documentable).include?(attachment_content_type)
|
||||
if documentable_class &&
|
||||
!accepted_content_types(documentable_class).include?(attachment_content_type)
|
||||
errors[:attachment] = I18n.t("documents.errors.messages.wrong_content_type",
|
||||
content_type: attachment_content_type,
|
||||
accepted_content_types: humanized_accepted_content_types(documentable))
|
||||
accepted_content_types: documentable_humanized_accepted_content_types(documentable_class))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -74,8 +82,12 @@ class Document < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
def remove_cached_document
|
||||
File.delete(cached_attachment) if File.exist?(cached_attachment)
|
||||
def remove_cached_attachment
|
||||
document = Document.new(documentable: documentable,
|
||||
cached_attachment: cached_attachment,
|
||||
user: user)
|
||||
document.set_attachment_from_cached_attachment
|
||||
document.attachment.destroy
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
112
app/models/image.rb
Normal file
112
app/models/image.rb
Normal file
@@ -0,0 +1,112 @@
|
||||
class Image < ActiveRecord::Base
|
||||
include ImagesHelper
|
||||
include ImageablesHelper
|
||||
|
||||
TITLE_LEGHT_RANGE = 4..80
|
||||
MIN_SIZE = 475
|
||||
MAX_IMAGE_SIZE = 1.megabyte
|
||||
ACCEPTED_CONTENT_TYPE = %w(image/jpeg image/jpg)
|
||||
|
||||
has_attached_file :attachment, styles: { large: "x#{MIN_SIZE}", medium: "300x300#", thumb: "140x245#" },
|
||||
url: "/system/:class/:prefix/:style/:hash.:extension",
|
||||
hash_data: ":class/:style",
|
||||
use_timestamp: false,
|
||||
hash_secret: Rails.application.secrets.secret_key_base
|
||||
attr_accessor :cached_attachment
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :imageable, polymorphic: true
|
||||
|
||||
# Disable paperclip security validation due to polymorphic configuration
|
||||
# Paperclip do not allow to use Procs on valiations definition
|
||||
do_not_validate_attachment_file_type :attachment
|
||||
validate :attachment_presence
|
||||
validate :validate_attachment_content_type, if: -> { attachment.present? }
|
||||
validate :validate_attachment_size, if: -> { attachment.present? }
|
||||
validates :title, presence: true, length: { in: TITLE_LEGHT_RANGE }
|
||||
validates :user_id, presence: true
|
||||
validates :imageable_id, presence: true, if: -> { persisted? }
|
||||
validates :imageable_type, presence: true, if: -> { persisted? }
|
||||
validate :validate_image_dimensions, if: -> { attachment.present? && attachment.dirty? }
|
||||
|
||||
before_save :set_attachment_from_cached_attachment, if: -> { cached_attachment.present? }
|
||||
after_save :remove_cached_attachment, if: -> { cached_attachment.present? }
|
||||
|
||||
def set_cached_attachment_from_attachment
|
||||
self.cached_attachment = if Paperclip::Attachment.default_options[:storage] == :filesystem
|
||||
attachment.path
|
||||
else
|
||||
attachment.url
|
||||
end
|
||||
end
|
||||
|
||||
def set_attachment_from_cached_attachment
|
||||
self.attachment = if Paperclip::Attachment.default_options[:storage] == :filesystem
|
||||
File.open(cached_attachment)
|
||||
else
|
||||
URI.parse(cached_attachment)
|
||||
end
|
||||
end
|
||||
|
||||
Paperclip.interpolates :prefix do |attachment, style|
|
||||
attachment.instance.prefix(attachment, style)
|
||||
end
|
||||
|
||||
def prefix(attachment, style)
|
||||
if !attachment.instance.persisted?
|
||||
"cached_attachments/user/#{attachment.instance.user_id}"
|
||||
else
|
||||
":attachment/:id_partition"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def imageable_class
|
||||
imageable_type.constantize if imageable_type.present?
|
||||
end
|
||||
|
||||
def validate_image_dimensions
|
||||
if attachment_of_valid_content_type?
|
||||
dimensions = Paperclip::Geometry.from_file(attachment.queued_for_write[:original].path)
|
||||
errors.add(:attachment, :min_image_width, required_min_width: MIN_SIZE) if dimensions.width < MIN_SIZE
|
||||
errors.add(:attachment, :min_image_height, required_min_height: MIN_SIZE) if dimensions.height < MIN_SIZE
|
||||
end
|
||||
end
|
||||
|
||||
def validate_attachment_size
|
||||
if imageable_class &&
|
||||
attachment_file_size > 1.megabytes
|
||||
errors[:attachment] = I18n.t("images.errors.messages.in_between",
|
||||
min: "0 Bytes",
|
||||
max: "#{imageable_max_file_size} MB")
|
||||
end
|
||||
end
|
||||
|
||||
def validate_attachment_content_type
|
||||
if imageable_class && !attachment_of_valid_content_type?
|
||||
errors[:attachment] = I18n.t("images.errors.messages.wrong_content_type",
|
||||
content_type: attachment_content_type,
|
||||
accepted_content_types: imageable_humanized_accepted_content_types)
|
||||
end
|
||||
end
|
||||
|
||||
def attachment_presence
|
||||
if attachment.blank? && cached_attachment.blank?
|
||||
errors[:attachment] = I18n.t("errors.messages.blank")
|
||||
end
|
||||
end
|
||||
|
||||
def attachment_of_valid_content_type?
|
||||
attachment.present? && imageable_accepted_content_types.include?(attachment_content_type)
|
||||
end
|
||||
|
||||
def remove_cached_attachment
|
||||
image = Image.new(imageable: imageable,
|
||||
cached_attachment: cached_attachment,
|
||||
user: user)
|
||||
image.set_attachment_from_cached_attachment
|
||||
image.attachment.destroy
|
||||
end
|
||||
|
||||
end
|
||||
@@ -4,7 +4,6 @@ class Poll
|
||||
belongs_to :poll
|
||||
|
||||
has_many :officer_assignments, class_name: "Poll::OfficerAssignment", dependent: :destroy
|
||||
has_many :final_recounts, class_name: "Poll::FinalRecount", dependent: :destroy
|
||||
has_many :officers, through: :officer_assignments
|
||||
has_many :voters
|
||||
has_many :partial_results
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
class Poll
|
||||
class FinalRecount < ActiveRecord::Base
|
||||
belongs_to :booth_assignment, class_name: "Poll::BoothAssignment"
|
||||
belongs_to :officer_assignment, class_name: "Poll::OfficerAssignment"
|
||||
|
||||
validates :booth_assignment_id, presence: true
|
||||
validates :date, presence: true, uniqueness: {scope: :booth_assignment_id}
|
||||
validates :count, presence: true, numericality: {only_integer: true}
|
||||
|
||||
before_save :update_logs
|
||||
|
||||
def update_logs
|
||||
if count_changed? && count_was.present?
|
||||
self.count_log += ":#{count_was.to_s}"
|
||||
self.officer_assignment_id_log += ":#{officer_assignment_id_was.to_s}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,8 +2,10 @@ class Poll
|
||||
class OfficerAssignment < ActiveRecord::Base
|
||||
belongs_to :officer
|
||||
belongs_to :booth_assignment
|
||||
has_many :final_recounts
|
||||
has_many :partial_results
|
||||
has_many :white_results
|
||||
has_many :null_results
|
||||
has_many :total_results
|
||||
has_many :voters
|
||||
|
||||
validates :officer_id, presence: true
|
||||
|
||||
@@ -10,11 +10,11 @@ class Proposal < ActiveRecord::Base
|
||||
include Graphqlable
|
||||
include Followable
|
||||
include Communitable
|
||||
include Imageable
|
||||
include Documentable
|
||||
documentable max_documents_allowed: 3,
|
||||
max_file_size: 3.megabytes,
|
||||
accepted_content_types: [ "application/pdf" ]
|
||||
accepts_nested_attributes_for :documents, allow_destroy: true
|
||||
include EmbedVideosHelper
|
||||
|
||||
acts_as_votable
|
||||
@@ -101,7 +101,7 @@ class Proposal < ActiveRecord::Base
|
||||
def self.search_by_code(terms)
|
||||
matched_code = match_code(terms)
|
||||
results = where(id: matched_code[1]) if matched_code
|
||||
return results if (results.present? && results.first.code == terms)
|
||||
return results if results.present? && results.first.code == terms
|
||||
end
|
||||
|
||||
def self.match_code(terms)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="admin-sidebar" data-equalizer-watch>
|
||||
<ul id="admin_menu" data-accordion-menu>
|
||||
<ul id="admin_menu" data-accordion-menu data-multi-open="false">
|
||||
|
||||
<li class="section-title">
|
||||
<a href="#">
|
||||
@@ -60,12 +60,12 @@
|
||||
<span class="icon-checkmark-circle"></span>
|
||||
<strong><%= t("admin.menu.title_polls") %></strong>
|
||||
</a>
|
||||
<ul id="polls_menu" <%= "class=is-active" if menu_polls? && controller.class.parent == Admin::Poll::QuestionsController %>>
|
||||
<ul id="polls_menu" <%= "class=is-active" if menu_polls? && controller.class.parent == Admin::Poll %>>
|
||||
<li <%= "class=active" if ["polls", "officer_assignments", "booth_assignments", "recounts", "results"].include? controller_name %>>
|
||||
<%= link_to t('admin.menu.polls'), admin_polls_path %>
|
||||
</li>
|
||||
|
||||
<li <%= "class=active" if controller_name == "questions" && controller.class.parent == Admin::Poll::QuestionsController %>>
|
||||
<li <%= "class=active" if current_page?(admin_questions_path) %>>
|
||||
<%= link_to t("admin.menu.poll_questions"), admin_questions_path %>
|
||||
</li>
|
||||
|
||||
|
||||
@@ -1,99 +1,9 @@
|
||||
<%= link_to admin_settings_path, class: "button float-right" do %>
|
||||
<span class="icon-settings"></span>
|
||||
<%= t("admin.menu.settings") %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to admin_stats_path, class: "button float-right" do %>
|
||||
<span class="icon-stats"></span>
|
||||
<%= t("admin.menu.stats") %>
|
||||
<% end %>
|
||||
|
||||
<h2 class="inline-block"><%= t("admin.dashboard.index.title") %></h2>
|
||||
|
||||
<p>Desde aquí puedes administrar el sistema, a través de las siguientes acciones:</p>
|
||||
|
||||
<div class="small-12 medium-9">
|
||||
<ul class="accordion" data-accordion data-multi-expand="true" data-allow-all-closed="true">
|
||||
|
||||
<li class="accordion-item" data-accordion-item>
|
||||
<a href="#" class="accordion-title">Temas de debate</a>
|
||||
<div class="accordion-content" data-tab-content>
|
||||
<p>Los temas (también llamadas tags, o etiquetas) de debate son palabras que definen los usuarios al crear debates, para catalogarlos (ej: sanidad, movilidad, arganzuela, ...). Aquí se pueden eliminar temas inapropiados, o <strong>marcarlos para ser propuestos al crear debates</strong> (cada usuario puede definir los que quiera, pero se le sugieren algunos que nos parecen útiles como catalogación por defecto; aquí se puede cambiar cuáles se sugieren)</p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="accordion-item" data-accordion-item>
|
||||
<a href="#" class="accordion-title">Propuestas/Debates/Comentarios ocultos</a>
|
||||
<div class="accordion-content" data-tab-content>
|
||||
<p>Cuando un moderador o un administrador oculta una Propuesta/Debate/Comentario aparecerá en esta lista. De esta forma los administradores pueden revisar que se ha ocultado el elemento adecuado.</p>
|
||||
|
||||
<ul>
|
||||
<li>Al pulsar <strong>Confirmar</strong> se acepta el que se haya ocultado, se considera que se ha hecho correctamente.</li>
|
||||
<li>Al pulsar <strong>Volver a mostrar</strong> se revierte la acción de ocultar y vuelve a ser una Propuesta/Debate/Comentario visible, en el caso de que se considere
|
||||
que ha sido una acción errónea el haberlo ocultado.</li>
|
||||
</ul>
|
||||
|
||||
<p>Para facilitar la gestión, arriba encontramos un <strong>filtro</strong> con las secciones: "pendientes" (los elementos sobre los que todavía no se ha pulsado "confirmar" o "volver a mostrar", que deberían ser revisados todavía), "confirmados" y "todos".</p>
|
||||
|
||||
<p><em>Es recomendable revisar regularmente la sección "pendientes".</em></p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="accordion-item" data-accordion-item>
|
||||
<a href="#" class="accordion-title">Usuarios bloqueados</a>
|
||||
<div class="accordion-content" data-tab-content>
|
||||
<p>Cuando un moderador o un administrador bloquea a un usuario aparecerá en esta lista. Al <strong>bloquear a un usuario, éste deja de poder utilizarlo para ninguna acción de la web</strong>. Los administradores pueden desbloquearlos pulsando el botón al lado del nombre del usuario en la lista.</p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="accordion-item" data-accordion-item>
|
||||
<a href="#" class="accordion-title">Organizaciones</a>
|
||||
<div class="accordion-content" data-tab-content>
|
||||
<p>En la web hay dos tipos de usuarios: individuales y organizaciones. Cualquier persona puede crear usuarios de un tipo o de otro en la propia web. Los usuarios de organizaciones pueden ser verificados por parte de los administradores, confirmando que quien gestiona el usuario efectivamente representa a esa organización. Una vez se haya realizado el proceso de verificación, por el proceso externo a la web que se haya definido para ello, se pulsa el botón <strong>"Verificar"</strong> para confimarlo; lo que hará que al lado del nombre de la organización aparezca una etiqueta señalando que es una organización verificada.</p>
|
||||
|
||||
<p>En caso de que el proceso de verificación haya sido negativo, se pulsa el botón <strong>"Rechazar"</strong>. Para editar alguno de los datos de la organización, se pulsa el botón <strong>"Editar"</strong>.</p>
|
||||
|
||||
<p>En caso de que el proceso de verificación haya sido negativo, se pulsa el botón <strong>"Rechazar"</strong>. Para editar alguno de los datos de la organización, se pulsa el botón <strong>"Editar"</strong>.</p>
|
||||
|
||||
<p>Las organizaciones que no aparecen en la lista pueden ser encontradas para actuar sobre ellas por medio del buscador en la parte superior. Para facilitar la gestión, arriba
|
||||
encontramos un <strong>filtro</strong> con las secciones: "pendientes" (las organizaciones que todavía no han sido verificadas o rechazadas), "verificadas", "rechazadas" y "todas".</p>
|
||||
<p><em>Es recomendable revisar regularmente la sección "pendientes".</em></p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="accordion-item" data-accordion-item>
|
||||
<a href="#" class="accordion-title">Cargos Públicos</a>
|
||||
<div class="accordion-content" data-tab-content>
|
||||
<p>En la web, los usuarios individuales pueden ser usuarios normales, o cargos públicos. Estos últimos se diferencian de los primeros únicamente en que al lado de sus nombres aparece una <strong>etiqueta que les identifica</strong>, y cambia ligeramente el estilo de sus comentarios. Esto permite que los usuarios les identifiquen más fácilmente. Al lado de cada usuario vemos la identificación que aparece en su etiqueta, y <strong>su nivel</strong> (la manera que internamente usa la web para diferenciar entre un tipo de cargos y otros). Pulsando el botón <strong>"Editar"</strong> al lado del usuario, se puede modificar su información. Los cargos públicos que no aparecen en la lista pueden ser encontrados para actuar sobre ellos por medio del buscador en la parte superior.</p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="accordion-item" data-accordion-item>
|
||||
<a href="#" class="accordion-title">Moderadores</a>
|
||||
<div class="accordion-content" data-tab-content>
|
||||
<p>Mediante el buscador de la parte superior se pueden buscar usuarios, para activarlos o desactivarlos como moderadores de la web. Los moderadores al acceder a la web con su usuario ven en la parte superior una nueva sección llamada <strong>"Moderar"</strong></p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="accordion-item" data-accordion-item>
|
||||
<a href="#" class="accordion-title">Actividad de moderadores</a>
|
||||
<div class="accordion-content" data-tab-content>
|
||||
<p>En esta sección se va guardando <strong>todas las acciones que realizan los moderadores o los administradores respecto a la moderación</strong>: ocultar/mostrar Propuestas/Debates/Comentarios y bloquear usuarios. En la columna <strong>"Acción"</strong> comprobamos si la acción corresponde con ocultar o con volver a mostrar (restaurar) elementos o con bloquear usuarios. En las demás columnas tenemos el tipo de elemento, el contenido del elemento y el moderador o administrador que ha realizado la acción. Esta sección permite que los administradores detecten comportamientos irregulares por parte de moderadores específicos y que por lo tanto puedan corregirlos.</p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="accordion-item" data-accordion-item>
|
||||
<a href="#" class="accordion-title">Configuración Global</a>
|
||||
<div class="accordion-content" data-tab-content>
|
||||
<p>Opciones generales de configuración del sistema.</p>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="accordion-item" data-accordion-item>
|
||||
<a href="#" class="accordion-title">Estadísticas</a>
|
||||
<div class="accordion-content" data-tab-content>
|
||||
<p>Estadísticas generales del sistema.</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="float-right">
|
||||
<%= link_to root_path do %>
|
||||
<%= t("admin.dashboard.index.back", org: setting['org_name']) %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<h2 class="title inline-block"><%= t("admin.dashboard.index.title") %></h2>
|
||||
|
||||
<p><%= t("admin.dashboard.index.description", org: setting['org_name']) %></p>
|
||||
|
||||
@@ -45,25 +45,34 @@
|
||||
|
||||
<div class="tabs-panel" id="tab-recounts">
|
||||
<h3><%= t("admin.poll_booth_assignments.show.recounts_list") %></h3>
|
||||
|
||||
<table id="totals">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center"><%= t("admin.poll_booth_assignments.show.count_final") %></th>
|
||||
<th class="text-center"><%= t("admin.poll_booth_assignments.show.total_system") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="text-center" id="total_final"><%= total_recounts_by_booth(@booth_assignment) || '-' %></td>
|
||||
<td class="text-center" id="total_system"><%= @booth_assignment.voters.count %></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table id="recounts_list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.poll_booth_assignments.show.date") %></th>
|
||||
<th class="text-center"><%= t("admin.poll_booth_assignments.show.count_final") %></th>
|
||||
<th class="text-center"><%= t("admin.poll_booth_assignments.show.count_by_system") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% (@poll.starts_at.to_date..@poll.ends_at.to_date).each do |voting_date| %>
|
||||
<% final_recount = final_recount_for_date(@booth_assignment.final_recounts, voting_date) %>
|
||||
<% system_count = @voters_by_date[voting_date].present? ? @voters_by_date[voting_date].size : 0 %>
|
||||
<tr id="recounting_<%= voting_date.strftime('%Y%m%d') %>">
|
||||
<td><%= l voting_date %></td>
|
||||
<% if final_recount.present? %>
|
||||
<td class="text-center <%= 'count-error' if final_recount.count != system_count %>" title="<%= final_recount.officer_assignment.officer.name %>"><%= final_recount.count %></td>
|
||||
<% else %>
|
||||
<td class="text-center" title=""> - </td>
|
||||
<% end %>
|
||||
<td class="text-center"><%= system_count %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
||||
@@ -27,27 +27,24 @@
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
|
||||
<% final_officer_assignments = @officer_assignments.select{|oa| oa.final == true} %>
|
||||
<% if final_officer_assignments.any? %>
|
||||
<h3><%= t("admin.poll_officer_assignments.by_officer.final_recounts") %></h3>
|
||||
<table id="final_recount_list" class="fixed">
|
||||
<h3><%= t("admin.poll_officer_assignments.by_officer.total_recounts") %></h3>
|
||||
<table id="total_recount_list" class="fixed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.poll_officer_assignments.by_officer.date") %></th>
|
||||
<th><%= t("admin.poll_officer_assignments.by_officer.booth") %></th>
|
||||
<th class="text-right"><%= t("admin.poll_officer_assignments.by_officer.final_recount") %></th>
|
||||
<th class="text-right"><%= t("admin.poll_officer_assignments.by_officer.total_recount") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% final_officer_assignments.each do |officer_assignment| %>
|
||||
<tr id="final_recount_<%= officer_assignment.date.to_date.strftime('%Y%m%d') %>">
|
||||
<% @officer_assignments.each do |officer_assignment| %>
|
||||
<tr id="total_recount_<%= officer_assignment.date.to_date.strftime('%Y%m%d') %>">
|
||||
<td><%= l(officer_assignment.date.to_date) %></td>
|
||||
<td><%= booth_name_with_location(officer_assignment.booth_assignment.booth) %></td>
|
||||
<td class="text-right">
|
||||
<% if officer_assignment.final_recounts.any? %>
|
||||
<%= officer_assignment.final_recounts.to_a.sum(&:count) %>
|
||||
<% if officer_assignment.total_results.any? %>
|
||||
<%= officer_assignment.total_results.to_a.sum(&:amount) %>
|
||||
<% else %>
|
||||
<span>-</span>
|
||||
<% end %>
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
ckeditor: { language: I18n.locale } %>
|
||||
</div>
|
||||
|
||||
<div class="documents small-12" data-max-documents="<%= Poll::Question.max_documents_allowed %>">
|
||||
<%= render 'documents/nested_documents', documentable: @question %>
|
||||
<div class="documents small-12">
|
||||
<%= render 'documents/nested_documents', documentable: @question, f: f %>
|
||||
</div>
|
||||
|
||||
<div class="small-12">
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
<table class="fixed margin">
|
||||
<thead>
|
||||
<th><%= t("admin.recounts.index.table_booth_name") %></th>
|
||||
<th class="text-center"><%= t("admin.recounts.index.table_final_recount") %></th>
|
||||
<th class="text-center"><%= t("admin.recounts.index.table_total_recount") %></th>
|
||||
<th class="text-center"><%= t("admin.recounts.index.table_system_count") %></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @booth_assignments.each do |booth_assignment| %>
|
||||
<% final_recount = booth_assignment_sum_final_recounts(booth_assignment) %>
|
||||
<% total_recounts = total_recounts_by_booth(booth_assignment) %>
|
||||
<% system_count = booth_assignment.voters.size %>
|
||||
<tr id="<%= dom_id(booth_assignment) %>_recounts" class="booth_recounts">
|
||||
<td>
|
||||
@@ -25,9 +25,9 @@
|
||||
<%= link_to booth_assignment.booth.name, admin_poll_booth_assignment_path(@poll, booth_assignment, anchor: 'tab-recounts') %>
|
||||
</strong>
|
||||
</td>
|
||||
<td class="text-center <%= 'count-error' if final_recount.to_i != system_count %>">
|
||||
<% if final_recount.present? %>
|
||||
<strong><%= final_recount %></strong>
|
||||
<td class="text-center <%= 'count-error' if total_recounts.to_i != system_count %>">
|
||||
<% if total_recounts.present? %>
|
||||
<strong><%= total_recounts %></strong>
|
||||
<% else %>
|
||||
<span>-</span>
|
||||
<% end %>
|
||||
|
||||
10
app/views/admin/shared/_admin_shortcuts.html.erb
Normal file
10
app/views/admin/shared/_admin_shortcuts.html.erb
Normal file
@@ -0,0 +1,10 @@
|
||||
<li>
|
||||
<%= link_to admin_stats_path, title: t("admin.menu.stats") do %>
|
||||
<span class="icon-stats"></span>
|
||||
<% end %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to admin_settings_path, title: t("admin.menu.settings") do %>
|
||||
<span class="icon-settings"></span>
|
||||
<% end %>
|
||||
</li>
|
||||
@@ -1,4 +1,4 @@
|
||||
<%= form_for(@investment, url: form_url, method: :post) do |f| %>
|
||||
<%= form_for(@investment, url: form_url, method: :post, html: { multipart: true }) do |f| %>
|
||||
<%= render 'shared/errors', resource: @investment %>
|
||||
|
||||
<div class="row">
|
||||
@@ -21,8 +21,12 @@
|
||||
<%= f.text_field :external_url %>
|
||||
</div>
|
||||
|
||||
<div class="documents small-12 column" data-max-documents="<%= Budget::Investment.max_documents_allowed %>">
|
||||
<%= render 'documents/nested_documents', documentable: @investment %>
|
||||
<div class="images small-12 column">
|
||||
<%= render 'images/nested_image', imageable: @investment, f: f %>
|
||||
</div>
|
||||
|
||||
<div class="documents small-12 column">
|
||||
<%= render 'documents/nested_documents', documentable: @investment, f: f %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
@@ -49,10 +53,10 @@
|
||||
label: false,
|
||||
placeholder: t("budgets.investments.form.tags_placeholder"),
|
||||
aria: {describedby: "tags-list-help-text"},
|
||||
class: 'js-tag-list' %>
|
||||
class: 'js-tag-list tag-autocomplete',
|
||||
data: {js_url: suggest_tags_path} %>
|
||||
</div>
|
||||
|
||||
|
||||
<% unless current_user.manager? %>
|
||||
|
||||
<div class="small-12 column">
|
||||
|
||||
@@ -2,13 +2,21 @@
|
||||
<div class="panel">
|
||||
<div class="row">
|
||||
|
||||
<div class="small-12 medium-9 column">
|
||||
<div class="small-12 medium-3 large-2 column">
|
||||
<% if investment.image.present? %>
|
||||
<%= image_tag investment.image_url(:thumb), alt: investment.image.title %>
|
||||
<% else %>
|
||||
<div class="no-image"></div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-6 large-7 column">
|
||||
<div class="budget-investment-content">
|
||||
|
||||
<% cache [locale_and_user_status(investment), 'index', investment, investment.author] do %>
|
||||
<h3><%= link_to investment.title, namespaced_budget_investment_path(investment) %></h3>
|
||||
<p class="investment-project-info">
|
||||
|
||||
<p class="investment-project-info">
|
||||
<%= l investment.created_at.to_date %>
|
||||
|
||||
<% if investment.author.hidden? || investment.author.erased? %>
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
<div class="small-12 medium-9 column">
|
||||
<%= back_link_to budget_investments_path(investment.budget, heading_id: investment.heading) %>
|
||||
|
||||
<% if can?(:create, @document) && investment.documents.size < Budget::Investment.max_documents_allowed %>
|
||||
<%= link_to t("documents.upload_document"),
|
||||
new_document_path(documentable_id:investment, documentable_type: investment.class.name, from: request.url),
|
||||
<% if can_destroy_image?(investment) %>
|
||||
<%= link_to t("images.remove_image"),
|
||||
image_path(investment.image, from: request.url),
|
||||
method: :delete,
|
||||
class: 'button hollow float-right' %>
|
||||
<% end %>
|
||||
|
||||
<h1><%= investment.title %></h1>
|
||||
|
||||
<div class="budget-investment-info">
|
||||
<%= render '/shared/author_info', resource: investment %>
|
||||
|
||||
@@ -20,7 +20,11 @@
|
||||
<span class="bullet"> • </span>
|
||||
<%= investment.heading.name %>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<%= render_image(investment.image, :large, true) if investment.image.present? %>
|
||||
|
||||
<p id="investment_code">
|
||||
<%= t("budgets.investments.show.code_html", code: investment.id) %>
|
||||
</p>
|
||||
@@ -116,6 +120,7 @@
|
||||
<%= render partial: 'shared/social_share', locals: {
|
||||
share_title: t("budgets.investments.show.share"),
|
||||
title: investment.title,
|
||||
image_url: image_absolute_url(investment.image, :thumb),
|
||||
url: budget_investment_url(budget_id: investment.budget_id, id: investment.id)
|
||||
} %>
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
<div class="comment-info">
|
||||
|
||||
<% if comment.as_administrator? %>
|
||||
<span class="user-name"><%= t("comments.comment.admin") %> #<%= comment.administrator_id%></span>
|
||||
<span class="user-name"><%= t("comments.comment.admin") %> #<%= comment.administrator_id %></span>
|
||||
<% elsif comment.as_moderator? %>
|
||||
<span class="user-name"><%= t("comments.comment.moderator") %> #<%= comment.moderator_id%></span>
|
||||
<span class="user-name"><%= t("comments.comment.moderator") %> #<%= comment.moderator_id %></span>
|
||||
<% else %>
|
||||
|
||||
<% if comment.user.hidden? || comment.user.erased? %>
|
||||
@@ -72,7 +72,7 @@
|
||||
</div>
|
||||
|
||||
<% if comment.children.size > 0 %>
|
||||
<%= link_to "#{dom_id(comment)}", class: "js-toggle-children relative", data: {'id': "#{dom_id(comment)}"} do %>
|
||||
<%= link_to "", class: "js-toggle-children relative", data: {'id': "#{dom_id(comment)}"} do %>
|
||||
<span class="show-for-sr js-child-toggle" style="display: none;"><%= t("shared.show") %></span>
|
||||
<span class="show-for-sr js-child-toggle"><%= t("shared.hide") %></span>
|
||||
<span id="<%= dom_id(comment) %>_children_arrow" class="icon-arrow-down"></span> <%= t("comments.comment.responses", count: comment.children.size) %>
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
<%= f.text_field :tag_list, value: @debate.tag_list.to_s,
|
||||
label: false,
|
||||
placeholder: t("debates.form.tags_placeholder"),
|
||||
aria: {describedby: "tag-list-help-text"} %>
|
||||
aria: {describedby: "tag-list-help-text"},
|
||||
data: {js_url: suggest_tags_path},
|
||||
class: 'tag-autocomplete'%>
|
||||
</div>
|
||||
<div class="small-12 column">
|
||||
<% if @debate.new_record? %>
|
||||
|
||||
0
app/views/direct_uploads/_attachment.html.erb
Normal file
0
app/views/direct_uploads/_attachment.html.erb
Normal file
31
app/views/documents/_document_fields.html.erb
Normal file
31
app/views/documents/_document_fields.html.erb
Normal file
@@ -0,0 +1,31 @@
|
||||
<div id="<%= dom_id(f.object) %>" class="document direct-upload document-fields nested-fields">
|
||||
<%= f.hidden_field :id %>
|
||||
<%= f.hidden_field :user_id, value: current_user.id %>
|
||||
<%= f.hidden_field :cached_attachment %>
|
||||
|
||||
<div class="small-12 column title">
|
||||
<%= f.text_field :title, placeholder: t("documents.form.title_placeholder") %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column attachment-actions">
|
||||
<div class="small-9 column action-add attachment-errors document-attachment">
|
||||
<%= render_attachment(f, f.object) %>
|
||||
</div>
|
||||
<div class="small-3 column action-remove text-right">
|
||||
<%= render_destroy_document_link(f, f.object) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="small-6 column">
|
||||
<p class="file-name">
|
||||
<%= document_attachment_file_name(f.object) %>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
</div>
|
||||
@@ -1,6 +1,6 @@
|
||||
<% if documents.any? %>
|
||||
|
||||
<% if documents.size == max_documents_allowed && can?(:create, Document) %>
|
||||
<% if documents.size == max_documents_allowed && can?(:destroy, Document) %>
|
||||
<div class="row documents-list">
|
||||
<div class="small-12 column">
|
||||
<div class="callout warning text-center">
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
<%= form_for @document,
|
||||
url: documents_path(
|
||||
documentable_type: @document.documentable_type,
|
||||
documentable_id: @document.documentable_id,
|
||||
from: params[:from]
|
||||
),
|
||||
html: { multipart: true, class: "documentable"},
|
||||
data: { direct_upload_url: upload_documents_url(documentable_type: @document.documentable_type, documentable_id: @document.documentable_id) } do |f| %>
|
||||
|
||||
<%= render 'shared/errors', resource: @document %>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<%= render 'plain_fields', document: @document %>
|
||||
|
||||
<div class="actions small-12 medium-6 large-4 end column">
|
||||
<%= f.submit(t("documents.form.submit_button"), class: "button expanded") %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -1,22 +1,26 @@
|
||||
<div class="documents-list">
|
||||
<%= label_tag :documents, t("documents.form.title") %>
|
||||
<%= f.label :documents, t("documents.form.title") %>
|
||||
<p class="help-text"><%= documentables_note(documentable) %></p>
|
||||
|
||||
<% documentable.documents.each_with_index do |document, index| %>
|
||||
<%= render 'documents/nested_fields', document: document, index: index, documentable: documentable %>
|
||||
<% end %>
|
||||
<div id="nested-documents" data-max-documents-allowed="<%= documentable.class.max_documents_allowed%>">
|
||||
<%= f.fields_for :documents do |documents_builder| %>
|
||||
<%= render 'documents/document_fields', f: documents_builder %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= link_to_add_association t('documents.form.add_new_document'), f, :documents,
|
||||
partial: "documents/document_fields",
|
||||
id: "new_document_link",
|
||||
class: "button hollow #{"hide" if documentable.documents.count >= documentable.class.max_documents_allowed}",
|
||||
data: {
|
||||
association_insertion_node: "#nested-documents",
|
||||
association_insertion_method: "append"
|
||||
} %>
|
||||
|
||||
<div id="max-documents-notice" class="max-documents-notice callout warning text-center <%= "hide" unless max_documents_allowed?(documentable) %>">
|
||||
<%= t "documents.max_documents_allowed_reached_html" %>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
</div>
|
||||
|
||||
<% unless max_documents_allowed?(documentable) %>
|
||||
<%= link_to t("documents.form.add_new_document"),
|
||||
new_nested_documents_path(documentable_type: documentable.class.name, index: documentable.documents.size),
|
||||
remote: true,
|
||||
id: "new_document_link",
|
||||
class: "button hollow" %>
|
||||
<% end %>
|
||||
|
||||
<div class="max-documents-notice callout warning text-center <%= "hide" unless max_documents_allowed?(documentable) %>">
|
||||
<%= t "documents.max_documents_allowed_reached_html" %>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<div id="<%= document_nested_field_wrapper_id(index) %>" class="document">
|
||||
<%= hidden_field_tag :id,
|
||||
document.id,
|
||||
name: document_nested_field_name(document, index, :id),
|
||||
id: document_nested_field_id(document, index, :id) if document.persisted? %>
|
||||
<%= hidden_field_tag :user_id,
|
||||
current_user.id,
|
||||
name: document_nested_field_name(document, index, :user_id),
|
||||
id: document_nested_field_id(document, index, :user_id) %>
|
||||
<%= hidden_field_tag :cached_attachment,
|
||||
document.cached_attachment,
|
||||
name: document_nested_field_name(document, index, :cached_attachment),
|
||||
id: document_nested_field_id(document, index, :cached_attachment) %>
|
||||
|
||||
<%= label_tag :title, t("activerecord.attributes.document.title") %>
|
||||
<%= text_field_tag :title,
|
||||
document.title,
|
||||
name: document_nested_field_name(document, index, :title),
|
||||
id: document_nested_field_id(document, index, :title),
|
||||
class: "document-title" %>
|
||||
<% if document.errors[:title].any? %>
|
||||
<small class="error"><%= document.errors[:title].join(", ") %></small>
|
||||
<% end %>
|
||||
|
||||
<%= render_attachment(document, index) %>
|
||||
|
||||
<%= render_destroy_document_link(document, index) %>
|
||||
<p class="file-name"><%= document_attachment_file_name(document) %></p>
|
||||
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
|
||||
<hr>
|
||||
</div>
|
||||
@@ -1,50 +0,0 @@
|
||||
<div id="plain_document_fields" class="document">
|
||||
|
||||
<div class="small-12 column">
|
||||
<%= label_tag :document_title, t("activerecord.attributes.document.title") %>
|
||||
<%= text_field_tag :document_title, document.title, name: "document[title]", class: "document-title" %>
|
||||
<% if document.errors.has_key?(:title) %>
|
||||
<small class="error"><%= document.errors[:title].join(", ") %></small>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
<%= hidden_field_tag :cached_attachment, document.cached_attachment, name: "document[cached_attachment]" %>
|
||||
<%= file_field_tag :attachment,
|
||||
accept: accepted_content_types_extensions(document.documentable.class),
|
||||
label: false,
|
||||
class: 'document_ajax_attachment',
|
||||
data: {
|
||||
url: upload_documents_url(documentable_type: document.documentable_type, documentable_id: document.documentable_id),
|
||||
cached_attachment_input_field: "document_cached_attachment",
|
||||
multiple: false,
|
||||
nested_document: false
|
||||
},
|
||||
id: "document_attachment",
|
||||
name: "document[attachment]" %>
|
||||
|
||||
<% if document.cached_attachment.blank? %>
|
||||
<%= label_tag :document_attachment, t("documents.form.attachment_label"), class: 'button hollow' %>
|
||||
<% else %>
|
||||
<%= link_to t('documents.form.delete_button'),
|
||||
destroy_upload_documents_path(path: document.cached_attachment,
|
||||
nested_document: false,
|
||||
documentable_type: document.documentable_type,
|
||||
documentable_id: document.documentable_id),
|
||||
method: :delete,
|
||||
remote: true,
|
||||
class: "delete float-right" %>
|
||||
<% end %>
|
||||
|
||||
<% if document.errors.has_key?(:attachment) %>
|
||||
<div class="small-12 column source-option-file">
|
||||
<div class="attachment-errors">
|
||||
<small class="error"><%= errors_on_attachment(document) %></small>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<p class="file-name"><%= document_attachment_file_name(document) %></p>
|
||||
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -1,17 +1 @@
|
||||
<% if params[:nested_document] == "true" %>
|
||||
|
||||
App.Documentable.destroyNestedDocument("<%= document_nested_field_wrapper_id(params[:index]) %>", "<%= j render('layouts/flash') %>")
|
||||
<% new_document_link = link_to t("documents.form.add_new_document"),
|
||||
new_nested_documents_path(documentable_type: @document.documentable_type, index: params[:index]),
|
||||
remote: true,
|
||||
id: "new_document_link",
|
||||
class: "button hollow" %>
|
||||
App.Documentable.updateNewDocumentButton("<%= j new_document_link %>")
|
||||
|
||||
<% else %>
|
||||
|
||||
App.Documentable.replacePlainDocument("plain_document_fields",
|
||||
"<%= j render('layouts/flash') %>",
|
||||
"<%= j render('plain_fields', document: @document) %>")
|
||||
|
||||
<% end %>
|
||||
App.Documentable.removeDocument("<%= dom_id(@document) %>")
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<div class="document-form <%= documentable_class(@document.documentable) %> row">
|
||||
|
||||
<div class="small-12 medium-9 column">
|
||||
<%= back_link_to params[:from] %>
|
||||
<h1><%= t("documents.new.title") %></h1>
|
||||
<%= render "documents/form", form_url: documents_url %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-3 column">
|
||||
<span class="icon-documents float-right"></span>
|
||||
<h2><%= t("documents.recommendations_title") %></h2>
|
||||
<ul class="recommendations">
|
||||
<li>
|
||||
<%= t "documents.recommendation_one_html",
|
||||
max_documents_allowed: max_documents_allowed(@document.documentable) %>
|
||||
</li>
|
||||
<li>
|
||||
<%= t "documents.recommendation_two_html",
|
||||
accepted_content_types: humanized_accepted_content_types(@document.documentable) %>
|
||||
</li>
|
||||
<li>
|
||||
<%= t "documents.recommendation_three_html",
|
||||
max_file_size: max_file_size(@document.documentable) %>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,9 +0,0 @@
|
||||
<%
|
||||
new_document_link = link_to t("documents.form.add_new_document"),
|
||||
new_nested_documents_path(documentable_type: params[:documentable_type], index: params[:index].to_i + 1),
|
||||
remote: true,
|
||||
id: "new_document_link",
|
||||
class: "button hollow"
|
||||
%>
|
||||
App.Documentable.new("<%= j render('documents/nested_fields', document: @document, index: params[:index]) %>")
|
||||
App.Documentable.updateNewDocumentButton("<%= j new_document_link %>")
|
||||
@@ -1,12 +0,0 @@
|
||||
<% if params[:nested_document] == "true" %>
|
||||
|
||||
App.Documentable.uploadNestedDocument("<%= document_nested_field_wrapper_id(params[:index]) %>",
|
||||
"<%= j render('documents/nested_fields', document: @document, index: params[:index]) %>",
|
||||
<%= @document.cached_attachment.present? %>)
|
||||
<% else %>
|
||||
|
||||
App.Documentable.uploadPlainDocument("plain_document_fields",
|
||||
"<%= j render('documents/plain_fields', document: @document) %>",
|
||||
<%= @document.cached_attachment.present? %>)
|
||||
|
||||
<% end %>
|
||||
18
app/views/images/_image.html.erb
Normal file
18
app/views/images/_image.html.erb
Normal file
@@ -0,0 +1,18 @@
|
||||
<div class="small-12 column text-center image-preview">
|
||||
<figure>
|
||||
<%= image_tag image.attachment.url(version),
|
||||
class: image_class(image),
|
||||
alt: image.title,
|
||||
title: image.title %>
|
||||
<% if show_caption %>
|
||||
<figcaption class="text-right">
|
||||
<em><%= image.title %></em>
|
||||
</figcaption>
|
||||
<% end %>
|
||||
</figure>
|
||||
|
||||
<% if show_caption %>
|
||||
<hr>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
31
app/views/images/_image_fields.html.erb
Normal file
31
app/views/images/_image_fields.html.erb
Normal file
@@ -0,0 +1,31 @@
|
||||
<div id="<%= dom_id(f.object) %>" class="image direct-upload nested-fields">
|
||||
<%= f.hidden_field :id %>
|
||||
<%= f.hidden_field :user_id, value: current_user.id %>
|
||||
<%= f.hidden_field :cached_attachment %>
|
||||
|
||||
<div class="small-12 column title">
|
||||
<%= f.text_field :title, placeholder: t("images.form.title_placeholder") %>
|
||||
</div>
|
||||
|
||||
<%= render_image(f.object, :thumb, false) if f.object.attachment.exists? %>
|
||||
|
||||
<div class="small-12 column attachment-actions">
|
||||
<div class="small-9 column action-add attachment-errors image-attachment">
|
||||
<%= render_image_attachment(f, imageable, f.object) %>
|
||||
</div>
|
||||
<div class="small-3 column action-remove text-right">
|
||||
<%= render_destroy_image_link(f, f.object) %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="small-6 column">
|
||||
<p class="file-name">
|
||||
<%= image_attachment_file_name(f.object) %>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
<div class="progress-bar-placeholder"><div class="loading-bar"></div></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
25
app/views/images/_nested_image.html.erb
Normal file
25
app/views/images/_nested_image.html.erb
Normal file
@@ -0,0 +1,25 @@
|
||||
<div>
|
||||
<%= f.label :image, t("images.form.title") %>
|
||||
<p class="help-text"><%= imageables_note(imageable) %></p>
|
||||
|
||||
<div id="nested-image">
|
||||
<%= f.fields_for :image do |image_builder| %>
|
||||
<%= render 'images/image_fields', f: image_builder, imageable: imageable %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= link_to_add_association t('images.form.add_new_image'), f, :image,
|
||||
force_non_association_create: true,
|
||||
partial: "images/image_fields",
|
||||
id: "new_image_link",
|
||||
class: "button hollow #{"hide" if imageable.image.present?}",
|
||||
render_options: {
|
||||
locals: { imageable: imageable }
|
||||
},
|
||||
data: {
|
||||
association_insertion_node: "#nested-image",
|
||||
association_insertion_method: "append"
|
||||
} %>
|
||||
|
||||
<hr>
|
||||
1
app/views/images/destroy.js.erb
Normal file
1
app/views/images/destroy.js.erb
Normal file
@@ -0,0 +1 @@
|
||||
App.Imageable.removeImage("<%= dom_id(@image) %>")
|
||||
@@ -2,34 +2,31 @@
|
||||
<div class="top-links">
|
||||
<div class="expanded row">
|
||||
<%= render 'shared/locale_switcher' %>
|
||||
<%= link_to t("admin.dashboard.index.back") + " " + setting['org_name'],
|
||||
root_path, class: "float-right back-web" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="expanded row">
|
||||
<div class="top-bar">
|
||||
|
||||
<%= link_to setting['org_name'], namespaced_root_path, class: "logo show-for-small-only" %>
|
||||
|
||||
<span data-responsive-toggle="responsive-menu" data-hide-for="medium" class="float-right">
|
||||
<span class="menu-icon dark" data-toggle></span>
|
||||
<%= t("application.menu")%>
|
||||
</span>
|
||||
|
||||
<div id="responsive-menu">
|
||||
|
||||
<div class="top-bar-title">
|
||||
<h1>
|
||||
<%= link_to namespaced_root_path, class: "hide-for-small-only" do %>
|
||||
<%= image_tag(image_path_for('logo_header.png'), class: 'hide-for-small-only float-left', size: '80x80', alt: t("layouts.header.logo")) %>
|
||||
<%= link_to namespaced_root_path do %>
|
||||
<%= setting['org_name'] %>
|
||||
| <%= namespaced_header_title %>
|
||||
<br><small><%= namespaced_header_title %></small>
|
||||
<% end %>
|
||||
</h1>
|
||||
</div>
|
||||
<div id="responsive-menu">
|
||||
|
||||
<div class="top-bar-right">
|
||||
<ul class="dropdown menu" data-dropdown-menu>
|
||||
<%= render "admin/shared/admin_shortcuts" %>
|
||||
<%= render "shared/admin_login_items" %>
|
||||
<%= render "devise/menu/login_items" %>
|
||||
</ul>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<div class="off-canvas-content" data-off-canvas-content>
|
||||
<%= render 'layouts/admin_header' %>
|
||||
|
||||
<div class="no-margin-top row no-max-width collapse" data-equalizer>
|
||||
<div class="no-margin-top row expanded collapse" data-equalizer>
|
||||
<div class="small-12 medium-3 column" data-equalizer-watch>
|
||||
|
||||
<div class="show-for-small-only">
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="no-margin-top row no-max-width collapse">
|
||||
<main class="no-margin-top row expanded collapse">
|
||||
<div class="small-12 medium-3 column">
|
||||
<%= render "/management/menu" %>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<%= submit_tag t('.select_version_submit'), class: "button" %>
|
||||
<% end %>
|
||||
<% if @draft_version.changelog.present? %>
|
||||
<span><%= link_to t('.see_changes'), legislation_process_draft_version_changes_path(@process, @draft_version) %></span>
|
||||
<span><%= link_to t('.see_changes'), legislation_process_draft_version_changes_path(@process, @draft_version), class: "see-changes" %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
<span><%= t('.updated_at', date: format_date(@draft_version.updated_at)) %></span>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user