First things first, we're going to want to declare all our variables. We'll begin with caching some selectors so we can put them to good use later (we're going to use these guys a lot so we should keep them around here - beats parsing the DOM every time)
$head = $(".page-header")
$auth = $("#targeted_authority")
$focus = $("#targeted_focus")
I'd like to cache this one too if possible, but not sure I can due to its dynamic nature. Must experiment later. Not a huge deal as it's not used as frequently as the three above.
# $sub = $("#targeted_sub")
We're using Ladda for the buttons on this site, at least for the look and feel. On some of the pages (mostly those with forms) we're actually using the Ladda functionality too, so if those buttons exist on the page that's been loaded we need to initialize them.
d = Ladda.create document.querySelector("#btn-archive") unless $("#btn-archive").length < 1
l = Ladda.create document.querySelector("[type=submit]") unless $("[type=submit]").length < 1
And let's drop our reusable functions at the top too (since JavaScript's weird function scoping will try to do this anyway).
This first function grabs a list of locations that are below the authority in hierarchy (LSS area, SLT area, whatever, it depends on the second parameter) and, if there are any returned from the server, spawns and populates a new drop down. It's not actually asynchronous, because we need this dropdown to be either spawned and fully populated or not at all, and being stuck in callback hell is dull.
focusAuthority = (authority, focus) ->
$.ajax
type : "GET"
url : "/areas/#{authority}/#{focus}"
dataType : "json"
async : false
success : (data) ->
if data isnt false
$("#targeted_sub").html("<option value='' disabled selected>Please select…</option>").show()
for dt in data
dt = dt.toLowerCase()
$("#targeted_sub").append "<option value='#{dt}'>#{dt}</option>"
So here's probably the trickiest bit. This function has to select (possibly multiple) schools / whatevers in the #targeted_sub
list. To accomplish this we're going to need an array of everything that should be selected in there, then we'll need to iterate through its values and match them up.
selectFocus = ->
$.ajax
type : "GET"
url : "/areas/14" # this should be article id
dataType : "json"
success : (data) ->
if data.multiple is false
$("#targeted_sub").val data.value.slice(0, -1)
else
values = data.value.split ";"
$("#targeted_sub").val values
So, now for the stuff that happens on load. This script is loaded asynchronously, so no $ ->
required - this stuff happens after ready anyway. We're using Bootstrap Datepicker plugin so let's kick that one off first.
$(".date").datepicker
format : "yyyy-mm-dd" # Could make this friendlier at a later date
We're also using Redactor as our WYSIWYG editor.
$('.redactor').redactor
imageUpload : '/news/image/'
convertDivs : true
buttons : ['bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', '|', 'image', 'video', 'file', 'table', 'link', '|', 'fontcolor', '|', 'horizontalrule', '|', 'readmore']
buttonsCustom :
readmore :
title : 'Read More'
callback : (obj) ->
obj.execCommand 'inserthtml', '<!--readmore--> Read More<!--endreadmore-->';
In the interests of clarity we're going to actually declare an event here, amidst the onload stuff. There are some checkboxes on the form that flip open a panel when they're ticked.
$(".toggle").on "click", ->
$(@).closest("div").children("div").slideToggle()
We're going to want to see if they're checked on load too so that they're flipped open then too. This'll prevent all sorts of weirdness.
$(".toggle").each ->
$(@).closest("div").children("div").show() if $(@).attr "checked"
Finally let's pick the right values on page load, too, if this article is targeted.
if !!$auth.val()
$focus.show()
focusAuthority $auth.val(), $focus.val()
if $focus.val() isnt ""
selectFocus()
Right, now for the events (bar the teeny one that snuck in above!)
These little guys make addional selects appear so you can narrow down your article targeting. Also, we make them disappear if applicable, too.
$auth.on "change", ->
if $auth.val().length > 0
$focus.show()
$focus.val ""
$("#targeted_sub").html("").hide()
$focus.on "change", ->
v = $focus.val()
if v.length > 0
focusAuthority $auth.val(), v
else
$("#targeted_sub").html("").hide()
So on the pages this script is loaded on there are two ways of archiving articles. One is an archive button (or, more precisely, a load of archive buttons) with no going back from it - that makes life easy as we just have to send a DELETE
request to the right URL ;)
$(".glyphicon-inbox").on "click", (e) ->
e.preventDefault()
$icon = $(@) # Hooray for function scoping
$.ajax
type : "DELETE"
url : "/news/" + $icon.attr "data-archive"
dataType : "json"
success : (data) ->
$icon.replaceWith "<span class='label label-archived'>Archived</span>"
There's also a more complex means of archiving, where the button changes to essentially 'unarchive' if the article is archived. Simple enough, we can use the same URL (thanks to REST) but just change the request type depending on what button is displaying. These buttons are Ladda ones, by the way, so we need to deal with the spinniness too.
$("#btn-archive").on "click", (e) ->
e.preventDefault()
return if d.isLoading()
d.start() # Start Ladda spinning
$(".alert-activation").remove()
color = $(@).attr "data-color"
if color is "red"
type = "DELETE"
else
type = "PUT"
$.ajax
type : type
url : window.location.pathname
dataType : "json"
success : (data) ->
name = $(".page-header small").text()
### Could and totally should get this into its own function... there's reuse here ###
window.setTimeout -> # Flip this guy on to let Ladda actually spin a bit ;)
d.stop()
if data.success is false
$head.before "<div class='alert alert-danger'><strong>Error changing user status:</strong> An unexpected error occurred</div>"
else if data.date is null
$head.before "<div class='alert alert-activation'><strong>#{name}</strong> reactivated successfully!</div>"
$('.label-archived').fadeOut()
$('#btn-archive .ladda-label').text 'Archive'
$('#btn-archive').attr 'data-color', 'red'
else
$head.before "<div class='alert alert-activation'><strong>#{name}</strong> archived successfully</div>"
$('#btn-archive .ladda-label').text 'Restore'
$('#btn-archive').attr 'data-color', 'green'
$('.label-archived').fadeIn()
, 1000
Finally we need to deal with what happens when someone hits save on an article. Easy peasy - again just firing a request of the right type to the right URL.
$(".news-article-form").on "submit", (e) ->
e.preventDefault()
return if l.isLoading()
return if not $(@).parsley "validate"
$(".alert").remove()
l.start()
$.ajax
type : "POST"
url : window.location.pathname
data : $(@).serialize()
dataType : "json"
success : (data) ->
if not data.success
message = "An error occurred when saving"
type = "danger"
else
message = "Changes saved successfully!"
type = "success"
window.setTimeout ->
l.stop()
$head.after "<div class='alert alert-#{type}'>#{message}</div>"
h1 = $(".page-header h1").text().trim().toLowerCase().substring 0, 3
if h1 is "new"
$("input, textarea, select, [type=submit]").attr "disabled", "disabled"
$("[type=submit]").hide().after "<a class='btn ladda-button' data-color='green' href='/news/'>View Article List</a>"
, 1000