Merge pull request #1620 from consul/medialab-legislation

Adds Collaborative Legislation
This commit is contained in:
Juanjo Bazán
2017-06-07 18:06:15 +02:00
committed by GitHub
181 changed files with 10913 additions and 142 deletions

View File

@@ -50,6 +50,15 @@
//= require banners
//= require social_share
//= require checkbox_toggle
//= require markdown-it
//= require markdown_editor
//= require cocoon
//= require legislation_admin
//= require legislation
//= require legislation_allegations
//= require legislation_annotatable
//= require watch_form_changes
//= require tree_navigator
//= require custom
var initialize_modules = function() {
@@ -76,6 +85,14 @@ var initialize_modules = function() {
App.Banners.initialize();
App.SocialShare.initialize();
App.CheckboxToggle.initialize();
App.MarkdownEditor.initialize();
App.LegislationAdmin.initialize();
App.LegislationAllegations.initialize();
App.Legislation.initialize();
if ( $(".legislation-annotatable").length )
App.LegislationAnnotatable.initialize();
App.WatchFormChanges.initialize();
App.TreeNavigator.initialize();
};
$(function(){

View File

@@ -0,0 +1,25 @@
App.Legislation =
initialize: ->
$('#js-toggle-debate').on
click: ->
$('#debate-show').toggle()
$('#js-toggle-small-debate').on
click: ->
$('#debate-show').toggle()
$('span').toggleClass('icon-angle-up')
$('form#new_legislation_answer input.button').hide()
$('form#new_legislation_answer input[type=radio]').on
click: ->
$('form#new_legislation_answer').submit()
$('form#draft_version_go_to_version input.button').hide()
$('form#draft_version_go_to_version select').on
change: ->
$('form#draft_version_go_to_version').submit()
$('#js-toggle-legislation-process-header').on
click: ->
$('[data-target="legislation-header-full"]').toggle()

View File

@@ -0,0 +1,14 @@
App.LegislationAdmin =
initialize: ->
$("input[type='checkbox'][data-disable-date]").on
change: ->
checkbox = $(this)
parent = $(this).parents('.row:eq(0)')
date_selector = $(this).data('disable-date')
parent.find("input[type='text'][id^='"+date_selector+"']").each ->
if checkbox.is(':checked')
$(this).removeAttr("disabled")
else
$(this).val("")

View File

@@ -0,0 +1,25 @@
App.LegislationAllegations =
toggle_comments: ->
if !App.LegislationAnnotatable.isMobile()
$('.draft-allegation').toggleClass('comments-on')
$('#comments-box').html('').hide()
show_comments: ->
if !App.LegislationAnnotatable.isMobile()
$('.draft-allegation').addClass('comments-on')
initialize: ->
$('.js-toggle-allegations .draft-panel').on
click: (e) ->
e.preventDefault()
e.stopPropagation()
if !App.LegislationAnnotatable.isMobile()
App.LegislationAllegations.toggle_comments()
$('.js-toggle-allegations').on
click: (e) ->
# Toggle comments when the section title is visible
if !App.LegislationAnnotatable.isMobile()
if $(this).find('.draft-panel .panel-title:visible').length == 0
App.LegislationAllegations.toggle_comments()

View File

@@ -0,0 +1,215 @@
_t = (key) -> new Gettext().gettext(key)
App.LegislationAnnotatable =
makeEditableAndHighlight: (colour) ->
sel = window.getSelection()
if sel.rangeCount and sel.getRangeAt
range = sel.getRangeAt(0)
document.designMode = 'on'
if range
sel.removeAllRanges()
sel.addRange range
# Use HiliteColor since some browsers apply BackColor to the whole block
if !document.execCommand('HiliteColor', false, colour)
document.execCommand 'BackColor', false, colour
document.designMode = 'off'
return
highlight: (colour) ->
if window.getSelection
# IE9 and non-IE
try
if !document.execCommand('BackColor', false, colour)
App.LegislationAnnotatable.makeEditableAndHighlight colour
catch ex
App.LegislationAnnotatable.makeEditableAndHighlight colour
else if document.selection and document.selection.createRange
# IE <= 8 case
range = document.selection.createRange()
range.execCommand 'BackColor', false, colour
return
remove_highlight: ->
$('[data-legislation-draft-version-id] span[style]').replaceWith(->
return $(this).contents()
)
return
renderAnnotationComments: (event) ->
if event.offset
$("#comments-box").css({top: event.offset - $('.calc-comments').offset().top})
if App.LegislationAnnotatable.isMobile()
return
$.ajax
method: "GET"
url: event.annotation_url + "/annotations/" + event.annotation_id + "/comments"
dataType: 'script'
onClick: (event) ->
event.preventDefault()
event.stopPropagation()
if App.LegislationAnnotatable.isMobile()
annotation_url = $(event.target).closest(".legislation-annotatable").data("legislation-annotatable-base-url")
window.location.href = annotation_url + "/annotations/" + $(this).data('annotation-id')
return
$('[data-annotation-id]').removeClass('current-annotation')
target = $(this)
parents = target.parents('.annotator-hl')
parents_ids = parents.map (_, elem) ->
$(elem).data("annotation-id")
annotation_id = target.data('annotation-id')
$('[data-annotation-id="'+annotation_id+'"]').addClass('current-annotation')
$('#comments-box').html('')
App.LegislationAllegations.show_comments()
$("#comments-box").show()
$.event.trigger
type: "renderLegislationAnnotation"
annotation_id: target.data("annotation-id")
annotation_url: target.closest(".legislation-annotatable").data("legislation-annotatable-base-url")
offset: target.offset()["top"]
parents_ids.each (i, pid) ->
$.event.trigger
type: "renderLegislationAnnotation"
annotation_id: pid
annotation_url: target.closest(".legislation-annotatable").data("legislation-annotatable-base-url")
isMobile: () ->
return window.innerWidth <= 652
viewerExtension: (viewer) ->
viewer._onHighlightMouseover = (event) ->
return
customShow: (position) ->
$(@element).html ''
# Clean comments section and open it
$('#comments-box').html ''
App.LegislationAllegations.show_comments()
$('#comments-box').show()
annotation_url = $('[data-legislation-annotatable-base-url]').data('legislation-annotatable-base-url')
$.ajax(
method: 'GET'
url: annotation_url + '/annotations/new'
dataType: 'script').done (->
$('#new_legislation_annotation #legislation_annotation_quote').val(@annotation.quote)
$('#new_legislation_annotation #legislation_annotation_ranges').val(JSON.stringify(@annotation.ranges))
$('#comments-box').css({top: position.top - $('.calc-comments').offset().top})
unless $('[data-legislation-open-phase]').data('legislation-open-phase') == false
App.LegislationAnnotatable.highlight('#7fff9a')
$('#comments-box textarea').focus()
$("#new_legislation_annotation").on("ajax:complete", (e, data, status, xhr) ->
App.LegislationAnnotatable.app.destroy()
if data.status == 200
App.LegislationAnnotatable.remove_highlight()
$("#comments-box").html("").hide()
$.ajax
method: "GET"
url: annotation_url + "/annotations/" + data.responseJSON.id + "/comments"
dataType: 'script'
else
$(e.target).find('label').addClass('error')
$('<small class="error">' + data.responseJSON[0] + '</small>').insertAfter($(e.target).find('textarea'))
return true
)
return
).bind(this)
editorExtension: (editor) ->
editor.show = App.LegislationAnnotatable.customShow
scrollToAnchor: ->
annotationsLoaded: (annotations) ->
anchor = $(location).attr('hash')
if anchor && anchor.startsWith('#annotation')
ann_id = anchor.split("-")[-1..]
checkExist = setInterval((->
if $("span[data-annotation-id='" + ann_id + "']").length
el = $("span[data-annotation-id='" + ann_id + "']")
el.addClass('current-annotation')
$('#comments-box').html('')
App.LegislationAllegations.show_comments()
$('html,body').animate({scrollTop: el.offset().top})
$.event.trigger
type: "renderLegislationAnnotation"
annotation_id: ann_id
annotation_url: el.closest(".legislation-annotatable").data("legislation-annotatable-base-url")
offset: el.offset()["top"]
clearInterval checkExist
return
), 100)
propotionalWeight: (v, max) ->
Math.floor(v*5/(max+1)) + 1
addWeightClasses: ->
annotationsLoaded: (annotations) ->
return if annotations.length == 0
weights = annotations.map (ann) -> ann.weight
max_weight = Math.max.apply(null, weights)
last_annotation = annotations[annotations.length - 1]
checkExist = setInterval((->
if $("span[data-annotation-id='" + last_annotation.id + "']").length
for annotation in annotations
ann_weight = App.LegislationAnnotatable.propotionalWeight(annotation.weight, max_weight)
el = $("span[data-annotation-id='" + annotation.id + "']")
el.addClass('weight-' + ann_weight)
clearInterval checkExist
return
), 100)
initialize: ->
$(document).off("renderLegislationAnnotation").on("renderLegislationAnnotation", App.LegislationAnnotatable.renderAnnotationComments)
$(document).off('click', '[data-annotation-id]').on('click', '[data-annotation-id]', App.LegislationAnnotatable.onClick)
$(document).off('click', '[data-cancel-annotation]').on('click', '[data-cancel-annotation]', (e) ->
e.preventDefault()
$('#comments-box').html('')
$('#comments-box').hide()
App.LegislationAnnotatable.remove_highlight()
return
)
current_user_id = $('html').data('current-user-id')
$(".legislation-annotatable").each ->
$this = $(this)
ann_type = "legislation_draft_version"
ann_id = $this.data("legislation-draft-version-id")
base_url = $this.data("legislation-annotatable-base-url")
App.LegislationAnnotatable.app = new annotator.App()
.include ->
beforeAnnotationCreated: (ann) ->
ann["legislation_draft_version_id"] = ann_id
ann.permissions = ann.permissions || {}
ann.permissions.admin = []
.include(annotator.ui.main, {
element: this,
viewerExtensions: [App.LegislationAnnotatable.viewerExtension],
editorExtensions: [App.LegislationAnnotatable.editorExtension]
})
.include(App.LegislationAnnotatable.scrollToAnchor)
.include(App.LegislationAnnotatable.addWeightClasses)
.include(annotator.storage.http, { prefix: base_url, urls: { search: "/annotations/search" } })
App.LegislationAnnotatable.app.start().then ->
App.LegislationAnnotatable.app.ident.identity = current_user_id
options = {}
options["legislation_draft_version_id"] = ann_id
App.LegislationAnnotatable.app.annotations.load(options)

View File

@@ -0,0 +1,39 @@
App.MarkdownEditor =
refresh_preview: (element, md) ->
textarea_content = element.find('textarea').val()
result = md.render(textarea_content)
element.find('#markdown-preview').html(result)
initialize: ->
$('.markdown-editor').each ->
md = window.markdownit({
html: true,
breaks: true,
typographer: true,
})
App.MarkdownEditor.refresh_preview($(this), md)
$(this).on 'change input paste keyup', ->
App.MarkdownEditor.refresh_preview($(this), md)
$('.legislation-draft-versions-edit .warning').show()
return
$(this).find('textarea').on 'scroll', ->
$('#markdown-preview').scrollTop($(this).scrollTop())
$(this).find('.fullscreen-toggle').on 'click', ->
$('.markdown-editor').toggleClass('fullscreen')
$('.fullscreen-container').toggleClass('medium-8', 'medium-12')
span = $(this).find('span')
current_html = span.html()
if(current_html == span.data('open-text'))
span.html(span.data('closed-text'))
else
span.html(span.data('open-text'))
if $('.markdown-editor').hasClass('fullscreen')
$('.markdown-editor textarea').height($(window).height() - 100)
else
$('.markdown-editor textarea').height("10em")

View File

@@ -0,0 +1,37 @@
App.TreeNavigator =
setNodes: (nodes) ->
children = nodes.children('ul')
if(children.length == 0)
return
children.each ->
link = $(this).prev('a')
$('<span class="open"></span>').insertBefore(link)
App.TreeNavigator.setNodes($(this).children())
initialize: ->
elem = $('[data-tree-navigator]')
if(elem.length == 0)
return
ul = elem.find('ul:eq(0)')
if(ul.length && ul.children().length)
App.TreeNavigator.setNodes(ul.children())
$('[data-tree-navigator] span').on
click: (e) ->
elem = $(this)
if(elem.hasClass('open'))
elem.removeClass('open').addClass('closed')
elem.siblings('ul').hide()
else if(elem.hasClass('closed'))
elem.removeClass('closed').addClass('open')
elem.siblings('ul').show()
if anchor = $(location).attr('hash')
if link = elem.find('a[href="'+anchor+'"]')
link.parents('ul').each ->
$(this).show()
$(this).siblings('span').removeClass('closed').addClass('open')

View File

@@ -13,4 +13,6 @@ App.Votes =
initialize: ->
App.Votes.hoverize "div.votes"
App.Votes.hoverize "div.supports"
App.Votes.hoverize "div.debate-questions"
App.Votes.hoverize "div.comment-footer"
false

View File

@@ -0,0 +1,30 @@
App.WatchFormChanges =
forms: ->
return $('form[data-watch-changes]')
msg: ->
if($('[data-watch-form-message]').length)
return $('[data-watch-form-message]').data('watch-form-message')
checkChanges: (event) ->
changes = false
App.WatchFormChanges.forms().each ->
form = $(this)
if form.serialize() != form.data('watchChanges')
changes = true
if changes
return confirm(App.WatchFormChanges.msg())
else
return true
initialize: ->
if App.WatchFormChanges.forms().length == 0 || App.WatchFormChanges.msg() == undefined
return
$(document).off('page:before-change').on('page:before-change', (e) -> App.WatchFormChanges.checkChanges(e))
App.WatchFormChanges.forms().each ->
form = $(this)
form.data('watchChanges', form.serialize())
false

View File

@@ -164,6 +164,7 @@ $header-font-family: $body-font-family;
$header-font-weight: $global-weight-normal;
$header-font-style: normal;
$font-family-monospace: Consolas, 'Liberation Mono', Courier, monospace;
$font-family-serif: Georgia, 'Times New Roman', Times, serif;
$header-sizes: (
small: (
'h1': 34,

View File

@@ -6,6 +6,8 @@
// 04. Stats
// 05. Management
// 06. Polls
// 07. Legislation
// 08. CMS
//
// 01. Global styles
@@ -542,7 +544,75 @@ table {
}
}
// 07. CMS
// 07. Legislation
// --------------
// Markdown Editor
// ---------------
.markdown-editor {
background-color: white;
.markdown-area,
#markdown-preview {
display: none;
}
}
.markdown-editor #markdown-preview {
overflow-y: auto;
height: 15em;
}
.markdown-editor textarea {
height: 15em;
}
.markdown-editor.fullscreen {
z-index: 9999;
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
}
.markdown-editor.fullscreen #markdown-preview {
height: 99%;
}
.edit_legislation_draft_version .row {
margin-bottom: 2rem;
}
.legislation-admin {
.menu .active > a {
background: none;
}
}
.legislation-process-save {
@include breakpoint(medium) {
float: right;
}
}
.legislation-question-delete {
@include breakpoint(medium) {
text-align: right;
}
}
.legislation-process-index {
.legislation-process-new {
@include breakpoint(medium) {
text-align: right;
}
}
}
// 08. CMS
// --------------
.cms_page_list {
@@ -551,3 +621,290 @@ table {
vertical-align: middle;
}
}
.legislation-process-edit {
.edit_legislation_process {
small {
color: $text-medium;
}
input[type]:not([type="submit"]):not([type="file"]):not([type="checkbox"]):not([type="radio"]) {
background: $white;
}
.legislation-process-start, .legislation-process-end {
@include breakpoint(medium) {
line-height: 3rem;
}
}
.legislation-process-end {
@include breakpoint(medium) {
text-align: right;
}
}
}
}
.legislation-draft-versions-index {
.legislation-process-question,
.legislation-process-version {
@include breakpoint(medium) {
text-align: right;
}
}
table tr td {
padding: 0.25rem 0.375rem;
}
}
.legislation-questions-form {
input[type]:not([type="submit"]):not([type="file"]):not([type="checkbox"]):not([type="radio"]) {
background: $white;
margin-bottom: 0;
@include breakpoint(medium) {
margin-bottom: 1rem;
}
}
input::-webkit-input-placeholder {
font-style: italic;
}
input:-moz-placeholder { /* Firefox 18- */
font-style: italic;
}
input::-moz-placeholder { /* Firefox 19+ */
font-style: italic;
}
input:-ms-input-placeholder {
font-style: italic;
}
.legislation-questions-answers {
margin-bottom: 1rem;
}
.field {
margin-bottom: 1rem;
@include breakpoint(medium) {
margin-bottom: 0;
}
a {
line-height: 3rem;
color: $delete;
span {
text-decoration: underline;
}
.icon-x {
vertical-align: sub;
text-decoration: none;
line-height: 0;
}
&:active,
&:focus,
&:hover {
text-decoration: none;
}
}
}
}
.legislation-draft-versions-form {
.legislation-process-version {
@include breakpoint(medium) {
text-align: right;
}
}
input[type]:not([type="submit"]):not([type="file"]):not([type="checkbox"]):not([type="radio"]) {
background: $white;
}
.control {
cursor: pointer;
margin-bottom: 1rem;
small {
display: block;
margin-top: -1rem;
color: $text-medium;
@include breakpoint(medium) {
margin-left: 0.25rem;
display: inline-block;
margin-top: 0;
}
}
}
.fullscreen-container {
text-align: center;
background: #ccdbe6;
.markdown-editor-header,
.markdown-editor-buttons {
display: none;
}
a {
line-height: 8rem;
span {
text-decoration: none;
font-size: $small-font-size;
}
.icon-expand {
margin-left: 0.25rem;
vertical-align: sub;
text-decoration: none;
line-height: 0;
}
&:active,
&:focus,
&:hover {
text-decoration: none;
}
}
}
#legislation_draft_version_body {
font-family: $font-family-serif;
background: #f5f5f5;
height: 16em;
&:focus {
border: 1px solid #cacaca;
box-shadow: inset 0 1px 2px rgba(34, 34, 34, 0.1);
}
}
#markdown-preview {
font-family: $font-family-serif;
border: 1px solid #cacaca;
margin-bottom: 2rem;
h1, h2, h3, h4, h5, h6 {
font-family: $font-family-serif !important;
font-size: 1rem;
line-height: 1.625rem;
margin-bottom: 0;
}
p {
font-size: 1rem;
line-height: 1.625rem;
}
}
.fullscreen {
.markdown-area,
#markdown-preview {
display: block;
}
.column {
padding: 0;
}
.fullscreen-container {
text-align: left;
background: $admin-color;
padding: 0.5rem 1rem;
margin-bottom: 0;
a {
line-height: 3rem;
@include breakpoint(medium) {
float: right;
}
}
.markdown-editor-header {
vertical-align: top;
display: inline-block;
color: $white;
@include breakpoint(medium) {
line-height: 3rem;
}
}
.truncate {
@include breakpoint(medium) {
width: 40vw;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.markdown-editor-buttons {
display: block;
@include breakpoint(medium) {
display: inline-block;
float: right;
padding-left: 1rem;
}
input {
font-size: $small-font-size;
padding: 0.5em 1em;
margin-left: 0;
margin-bottom: 0;
margin-top: 1rem;
@include breakpoint(medium) {
margin: 0.5rem;
}
}
}
a {
color: $white;
}
}
#legislation_draft_version_body {
border-radius: 0;
padding: 1rem;
border: none;
@include breakpoint(medium) {
padding: 1rem 2rem;
}
&:focus {
border: none;
}
}
#markdown-preview {
padding: 1rem;
border: none;
@include breakpoint(medium) {
padding: 1rem 2rem;
}
}
}
}

View File

@@ -97,3 +97,28 @@
}
}
}
.annotator-hl {
cursor: pointer;
background: rgba(255, 255, 10, 0.2);
}
.annotator-hl.weight-1 {
background: #FFF9DA;
}
.annotator-hl.weight-2 {
background: #FFF5BC;
}
.annotator-hl.weight-3 {
background: #FFF1A2;
}
.annotator-hl.weight-4 {
background: #FFEF8C;
}
.annotator-hl.weight-5 {
background: #FFE95F;
}
.current-annotation {
text-decoration: underline;
}

View File

@@ -7,6 +7,8 @@
@import "layout";
@import "participation";
@import "pages";
@import "legislation";
@import "legislation_process";
@import "custom";
@import "c3";
@import "annotator.min";

View File

@@ -1,5 +1,4 @@
@charset "UTF-8";
@font-face {
font-family: 'icons';
src: font-url('icons.eot');
@@ -10,7 +9,6 @@
font-weight: normal;
font-style: normal;
}
[data-icon]:before {
font-family: "icons" !important;
content: attr(data-icon);
@@ -23,7 +21,6 @@
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
[class^="icon-"]:before,
[class*=" icon-"]:before {
font-family: "icons" !important;
@@ -36,7 +33,6 @@
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-angle-down:before {
content: "\61";
}
@@ -184,12 +180,18 @@
.icon-arrow-top:before {
content: "\57";
}
.icon-help-1:before {
content: "\58";
}
.icon-checkmark-circle:before {
content: "\59";
}
.icon-minus-square:before {
content: "\58";
}
.icon-plus-square:before {
content: "\5a";
}
.icon-expand:before {
content: "\30";
}
.icon-telegram:before {
content: "\31";
}

View File

@@ -455,7 +455,7 @@ header {
li {
@include breakpoint(medium) {
display: inline-block;
margin-right: rem-calc(36);
margin-right: rem-calc(20);
}
a {

View File

@@ -0,0 +1,107 @@
// Table of Contents
//
// 01. Hero
// 02. Sidebar menu
// 03. Legislation cards
//
// 01. Hero
// -----------------
.brand-heading {
background: $brand;
margin-bottom: 5rem;
.column {
padding-top: 10rem;
padding-bottom: 10rem;
h4 {
font-weight: 400;
text-align: center;
color: white;
}
}
}
// 02. Sidebar menu
// -----------------
.legislation-categories {
.menu.simple {
border-bottom: none;
list-style: none;
padding-left: 0;
margin-left: 0;
margin-top: 0;
@include breakpoint(medium) {
margin: 1.5rem 0;
}
li {
display: block;
cursor: pointer;
margin-bottom: 1rem;
@include breakpoint(medium) {
margin-bottom: 2rem;
max-width: 80%;
}
}
li.active {
font-weight: 700;
}
}
}
// 03. Legislation cards
// -----------------
.legislation {
margin: 0 0 $line-height 0;
background: white;
border: 1px solid;
border-color: #e5e6e9 #dfe0e4 #d0d1d5;
border-radius: 0;
box-shadow: 0px 1px 3px 0 #DEE0E3;
min-height: 12rem;
padding: 2rem 0 0 0;
}
.legislation-text {
margin-bottom: 1rem;
h3 a {
color: $black;
}
}
.legislation-calendar-info p {
font-size: $small-font-size;
color: $text-medium;
margin-bottom: 0;
}
.legislation-calendar {
background: #E5ECF2;
padding-top: 1rem;
h5 {
margin-left: 0.25rem;
margin-bottom: 0;
color: #61686E;
@include breakpoint(medium) {
margin-left: 0;
}
}
p {
margin-left: 0.25rem;
font-size: $small-font-size;
@include breakpoint(medium) {
margin-left: 0;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -299,7 +299,10 @@
.proposal-show,
.investment-project-show,
.budget-investment-show,
.polls-show {
.polls-show,
.debate-quiz,
.budget-investment-show,
.draft-panels {
p {
word-wrap: break-word;
@@ -493,7 +496,7 @@
}
}
.debate, .proposal, .investment-project, .budget-investment {
.debate, .proposal, .investment-project, .budget-investment, .legislation {
margin: $line-height/4 0;
.panel {