192 lines
7.5 KiB
CoffeeScript
192 lines
7.5 KiB
CoffeeScript
Qstorage = localStorage
|
|
window.day_minutes_to_time = (minutes)->
|
|
return "" unless minutes
|
|
[("0" + Math.floor(minutes/60)).substr(-2,2), ("0" + Math.floor(minutes%60)).substr(-2,2)].join(":")
|
|
|
|
# This is the same as setTimeout but then
|
|
# with switched arguments for coffeescript friendlyness.
|
|
# @a = 3
|
|
# delay =>
|
|
# console.log "The value of a is #{@a}"
|
|
# or to delay not a second but a self defined amount of time in milliseconds:
|
|
# delay 10000, =>
|
|
# console.log "The value of a is #{@a}"
|
|
window.delay = (time = 1000, fn, args...) ->
|
|
setTimeout fn, time, args...
|
|
|
|
# based on http://www.thecodeship.com/web-development/alternative-to-javascript-evil-setinterval/
|
|
# can be used as:
|
|
# to keep scope and execute every second:
|
|
# @a = 3
|
|
# interval =>
|
|
# console.log "Hi there with a is: #{@a}"
|
|
# to log every 200 milliseconds without conservation of this scope:
|
|
# interval 200, -> console.log "Hi there"
|
|
# to execute a maximum number (30) of times:
|
|
# interval 200, 30, -> console.log "Hi there"
|
|
window.interval = (wait = 1000, extra_args..., func)->
|
|
times = extra_args[0]
|
|
interv = do (wait, times)->
|
|
->
|
|
return if times? and times-- <= 0
|
|
setTimeout interv, wait
|
|
try
|
|
func.call null
|
|
catch e
|
|
times = 0
|
|
throw e.toString()
|
|
setTimeout interv, wait
|
|
|
|
window.is_translation_path = (path_or_value) ->
|
|
return true if path_or_value is 'application_name'
|
|
String(path_or_value).match /^[a-z0-9_]+\.[a-z0-9\._]+$/
|
|
|
|
window.ttry = (path, vars={})->
|
|
t(path, $.extend(vars, emptyWhenNotFound: true))
|
|
|
|
# return translation in the form
|
|
# <span data-t="models.table">Tafel</span>
|
|
window.tspan = (path, vars={}) ->
|
|
result = t(path, vars)
|
|
return '' if not result and vars.emptyWhenNotFound
|
|
"<span data-t='#{path}' class='translation' data-t-attributes='#{JSON.stringify(vars)}'>#{result}</span>"
|
|
|
|
window.t = (path, vars={}) ->
|
|
#result = undefined
|
|
#m = undefined
|
|
#translatable = undefined
|
|
#isafety = undefined
|
|
#replacable = undefined
|
|
if vars.scope
|
|
path = "#{vars.scope}.#{path}"
|
|
delete vars.scope unless Object.isFrozen(vars)
|
|
if vars.suffix
|
|
path = "#{path}.#{vars.suffix}"
|
|
delete vars.suffix unless Object.isFrozen(vars)
|
|
locale = Qstorage.getItem('locale') || 'en'
|
|
parts = path.split(".")
|
|
#accessor = "$translations.#{$locale}[\"#{parts.join("\"][\"")}\"]"
|
|
result = $translations[locale]
|
|
try
|
|
result = result[part] for part in parts
|
|
catch err # when nesting gets too deep
|
|
console.log "[TRANSLATION] Cannot find translation: #{path}"
|
|
return vars.default if vars.default? # questionmark is important to allow {default: ''} setting
|
|
result = parts[parts.length - 1].capitalize()
|
|
return if vars.emptyWhenNotFound then "" else result #parts[parts.length - 1].capitalize()
|
|
unless result?
|
|
console.log "[TRANSLATION] Cannot find translation: #{path}"
|
|
return vars.default if vars.default? and not result # questionmark is important to allow {default: ''}. This is however valid for all non truthy result values, so no question mark here
|
|
return "" if result is ""
|
|
return '' if not result? and vars.emptyWhenNotFound # When latest translation part cannot be found and empty result is required
|
|
return parts[parts.length - 1].capitalize() unless result
|
|
|
|
|
|
# allow t('test', {var: 'Benjamin'}) statements
|
|
# with $translations.nl.test = "Hello %{var}"
|
|
for variable, value of vars
|
|
# allow t 'action.select_model' modelPath='models.project'
|
|
if match = String(variable).match(/^(\w+)Path$/)
|
|
value = window.t value
|
|
variable = match[1]
|
|
result = result.replace("%{#{variable}}", value)
|
|
|
|
isafety = 0
|
|
try
|
|
while result.indexOf("${") > -1
|
|
m = result.match(/\${([\w\.]+(\|\w+)?)}/)
|
|
if m[2]
|
|
translatable = m[1].replace(m[2], "")
|
|
operation = $transformation_mappings[m[2].substr(1) or m[2].substr(1)]
|
|
else
|
|
translatable = m[1]
|
|
operation = null
|
|
replacable = t(translatable)
|
|
replacable = replacable[operation]() if operation
|
|
result = result.replace(m[0], replacable)
|
|
break if isafety > 10 # referencing other translations may cause infinite loops
|
|
isafety += 1
|
|
catch err
|
|
console.log "translation #{result} cannot be interpolated"
|
|
result
|
|
|
|
window.setLocale = (locale, options={}) ->
|
|
locale ||= Qstorage.getItem('locale') || options.default || 'en'
|
|
Qstorage.setItem "locale", locale
|
|
window.$locale = locale
|
|
setTranslations()
|
|
|
|
window.setTranslations = (selector) ->
|
|
#list = $("#top-navigation-list")
|
|
locale = Qstorage.getItem('locale') || 'en'
|
|
selector = $( selector || document)
|
|
selector.find(".locale-select").show()
|
|
selector.find(".locale-select-" + locale).hide()
|
|
moment.locale locale
|
|
if selector
|
|
selector.find("[data-t]").each ->
|
|
$(this).html t($(this).data("t"), $(this).data("tAttributes"))
|
|
|
|
selector.find("*[data-time]").each ->
|
|
$(this).text moment($(this).data("time")).format($(this).data("timeFormat") or "dd D MMM HH:mm")
|
|
|
|
else
|
|
$("[data-t]").each ->
|
|
$(this).html t($(this).data("t"), $(this).data("tAttributes"))
|
|
|
|
$("*[data-time]").each ->
|
|
$(this).text moment($(this).data("time")).format($(this).data("timeFormat") or "dd D MMM HH:mm")
|
|
|
|
# jQuery UI datepicker support
|
|
$(".datepicker").datepicker "option", $.datepicker.regional[locale] if $.fn.datepicker
|
|
|
|
# pickadate support
|
|
if $.fn.pickadate
|
|
if selector.hasClass('datepicker')
|
|
datepicker_object = selector
|
|
selector.siblings('.pickadate-display').remove()
|
|
else
|
|
datepicker_object = selector.find('.datepicker')
|
|
selector.find('.pickadate-display').remove()
|
|
datepicker_object.pickadate('stop') if datepicker_object.data('pickadate')
|
|
$.extend( $.fn.pickadate.defaults, $pickadate_translations[locale] ) if $pickadate_translations?[locale]
|
|
window.pickadate_options ||= {}
|
|
datepicker_object.pickadate(window.pickadate_options)
|
|
datepicker_object.change()
|
|
|
|
# use like
|
|
# error_message
|
|
# attribute: t('attributes.section.title')
|
|
# message: 'blank'
|
|
window.error_message = (options = {})->
|
|
locale = options.locale || Qstorage.getItem('locale') || 'en'
|
|
#message = $translations[locale].errors.messages[options.message]
|
|
message = t "errors.messages.#{options.message}", options
|
|
t 'errors.format',
|
|
attribute: options.attribute
|
|
message: message
|
|
|
|
window.setupTranslations = (options = {})->
|
|
locale = options.locale || Qstorage.getItem('locale') || 'en'
|
|
if $.fn.pickadate
|
|
$(document).on 'change', '.datepicker', ->
|
|
input = $(@)
|
|
input.next().remove() if input.next().hasClass('pickadate-display')
|
|
if input.data('pickadate')
|
|
if input.val()
|
|
#display_format = $pickadate_translations[$locale].displayFormat
|
|
#display_date = input.data('pickadate').get('select', display_format)
|
|
display_date = input.data('pickadate').get('select')
|
|
display_date = $('<span></span>').text(" #{display_date}") # add space between the icon and the date
|
|
else
|
|
display_date = $('<span></span>').data('t', 'datepicker.no_date').text(t('datepicker.no_date'))
|
|
display_tag = $('<span></span>').addClass('pickadate-display').append('<span class="fa fa-calendar fa-lg"></span>').append(display_date)
|
|
#display_tag.click (e)->(e.preventDefault();input.click().focus();false )
|
|
display_tag.click (e)->(e.preventDefault();input.pickadate('open');false )
|
|
$(@).after(display_tag)
|
|
setLocale(locale)
|
|
$('.datepicker').change().hide()
|
|
window.$transformation_mappings =
|
|
downcase: "toLowerCase"
|
|
upcase: "toUpperCase"
|