initial github commit

This commit is contained in:
2017-12-21 11:42:41 +01:00
commit a57548c7da
209 changed files with 3841 additions and 0 deletions
View File
+56
View File
@@ -0,0 +1,56 @@
import Ember from 'ember'
import DS from 'ember-data'
import config from 'ember-get-config'
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin'
export default DS.JSONAPIAdapter.extend DataAdapterMixin,
namespace: config.apiNamespace
host: config.apiHost
authorizer: 'authorizer:devise'
#pathForType: (type)->
# type.underscore().pluralize()
# Code for createRecord and updateRecord taken from ember data v2.0.0 restadapter
createRecord: (store, type, snapshot) ->
data = {}
#var serializer = store.serializerFor(type.modelName);
serializer = Ember.get(snapshot.record, 'store').serializerFor('create-and-update')
url = @buildURL(type.modelName, null, snapshot, 'createRecord')
serializer.serializeIntoHash data, type, snapshot, includeId: true
@ajax url, 'POST', data: data
# return pluralized underscored version
pathForType: (modelName) ->
base = Ember.String.underscore(modelName)
base = base.replace(/\./g, '/')
#base.split(/\//).map( (str) -> Ember.String.pluralize(str) ).join('/') # all parts pluralized
Ember.String.pluralize(base)
updateRecord: (store, type, snapshot) ->
data = {}
#var serializer = store.serializerFor(type.modelName);
serializer = Ember.get(snapshot.record, 'store').serializerFor('create-and-update')
id = snapshot.id
url = @buildURL(type.modelName, id, snapshot, 'updateRecord')
serializer.serializeIntoHash data, type, snapshot, includeId: true
@ajax url, 'PUT', data: data
handleResponse: (status, headers, payload) ->
switch status
when 401, 403
application_route = Ember.getOwner(@).lookup('route:application')
application_route.set 'router.globals.flash_message', "Unauthorized action"
#@get('session')?.invalidate()
#application_route.set 'router.globals.current_user', null
#application_route.transitionTo('login')
else
@_super arguments...
#buildURL: (modelName, id, snapshot, requestType, query)->
# response = @_super arguments...
# debugger
# response
@@ -0,0 +1,28 @@
import Ember from 'ember'
import layout from '../templates/components/collapsible-content'
Component = Ember.Component.extend
layout: layout
collapsed: true
classNames: ['collapsible-content-container']
title: Ember.computed 'titleSpec', ->
title = "#{@get('titleSpec')}"
options = {}
# allow modelPath as argument, useful for page-title 'action.new_model' modelPath='models.projects.site' etc
if modelPath = @get('modelPath')
options.model = t(modelPath)
# interpret the given argument as a translation string if it matches the characteristics
title = tspan(title, options) if is_translation_path(title)
title.htmlSafe()
actions:
toggleCollapsed: -> @toggleProperty('collapsed')
Component.reopenClass
positionalParams: ['titleSpec']
export default Component
@@ -0,0 +1,33 @@
import Ember from 'ember'
import layout from '../templates/components/editable-attribute'
export default Ember.Component.extend
layout: layout
attributeName: 'name'
can_make_editable: true
isEditing: false
validation_message: ''
make_editable: (-> @set 'isEditing', true ).on 'doubleClick'
init: ->
@_super arguments...
@set 'isEditing', true if @get('model.isNew')
actions:
destroyRecord: ->
@set 'validation_message', ''
model = @get('model')
model.rollbackAttributes()
model.destroyRecord()
editRecord: -> @set('isEditing', true)
saveRecord: ->
model = @get('model')
@set 'validation_message', ''
if validate = @get('validate')
@set 'validation_message', 'Must be given' if validate is 'presence' and not @get('model.name')
unless @get 'validation_message'
@set 'isEditing', false
model.save()
rollbackRecord: ->
@set 'validation_message', ''
model = @get('model')
model.rollbackAttributes()
@set 'isEditing', false
+28
View File
@@ -0,0 +1,28 @@
import Ember from 'ember'
#import layout from '../templates/components/error-handling'
export default Ember.Component.extend
#classNames: ['dunlop-global-error', 'ui', 'negative', 'message']
#classNameBindings: ['show_error:active:hidden']
#layout: layout
error: {}
show_error: true
show_as_list: Ember.computed.gt 'error.errors.length', 1
error_header: Ember.computed 'error.message', ->
@get('error.message') || 'Oops'
error_body: Ember.computed 'show_as_list', ->
''
single_error: Ember.computed 'error.message', ->
Ember.Object.create
title: @get('error.message')
status: @get('error.status')
detail: @get('error.backtrace')
actions:
reload_page: -> window.location.reload()
clear_error: -> @set 'show_error', false
clear_error_and_go_home: ->
@set 'show_error', false
Ember.getOwner(this).lookup('route:application').transitionTo('index')
+18
View File
@@ -0,0 +1,18 @@
import Ember from 'ember'
# = number-input numericValue=path.to.numeric_value, taken from mozo
export default Ember.TextField.extend
type: 'number'
attributeBindings: ['min', 'max', 'step']
classNames: ['number-input']
focusIn: -> @$().select()
init: ->
@_super arguments...
value = @get 'numericValue'
# value? returns true on 0
@set 'value', if value? then String(value) else ''
handle_value_change: Ember.observer 'value', ->
string_value = @get('value')
setValue = parseFloat(string_value)
@set "numericValue", if Number.isFinite(setValue) then setValue else null
+24
View File
@@ -0,0 +1,24 @@
import Ember from 'ember'
Component = Ember.Component.extend
tagName: 'h2'
classNames: ['page-title', 'ui', 'header']
back: null
title: Ember.computed 'titleSpec', ->
title = "#{@get('titleSpec')}"
options = {}
# allow modelPath as argument, useful for page-title 'action.new_model' modelPath='models.projects.site' etc
if modelPath = @get('modelPath')
options.model = t(modelPath)
# interpret the given argument as a translation string if it matches the characteristics
title = tspan(title, options) if is_translation_path(title)
title.htmlSafe()
Component.reopenClass
positionalParams: ['titleSpec']
export default Component
@@ -0,0 +1,16 @@
import Ember from 'ember'
import layout from '../templates/components/pagination-progress'
export default Ember.Component.extend
tagName: 'span'
layout: layout
progressText: Ember.computed 'content.page', 'content.content.length', 'content.perPage', 'content.total_count', ->
per_page = @get('content.perPage') || 10
current_page = @get('content.page') || 1
records_displayed = @get('content.content.length') || 0
total_count = @get('content.meta.total_count') || 0
from_item = (current_page - 1) * per_page + 1
to_item = Math.min(from_item + records_displayed - 1, total_count)
from_item = 0 unless total_count
"#{from_item} - #{to_item} / #{total_count}"
+39
View File
@@ -0,0 +1,39 @@
import Ember from 'ember'
import layout from '../templates/components/push-action'
export default Ember.Component.extend
layout: layout
tagName: 'button'
type: ''
size: ''
model: null
classNames: ['push-action', 'ui', 'icon', 'button']
classNameBindings: ['type', 'size', 'colorClass']
click: ->
@sendAction 'action', @get('model')
colorClass: Ember.computed 'type', ->
return unless type = @get('type')
switch type
when 'save' then 'primary'
when 'destroy' then 'negative'
when 'new' then 'grey'
else ''
iconClass: Ember.computed 'type', ->
return unless type = @get('type')
switch type
when 'edit' then 'pencil'
when 'new' then 'plus'
when 'show' then 'eye'
when 'sort' then 'sort'
when 'rollback' then 'undo'
when 'save' then 'save'
when 'destroy' then 'trash'
when 'authorization' then 'users' # 'unlock alternate'
when 'constraints' then 'connectdevelop'
when 'position' then 'random'
when 'contract' then 'file text'
when 'raster' then 'grid layout'
else type
@@ -0,0 +1,24 @@
import Ember from 'ember'
import UiCalendarComponent from 'ember-semantic-ui-calendar/components/ui-calendar'
{ computed, inject, merge } = Ember
export default UiCalendarComponent.extend
momentValue: null
firstDayOfWeek: null
is_date: false
# Provide the Date object that is used by ui-calendar
date: computed('momentValue', ->
if momentValue = @get('momentValue') then momentValue.toDate() else null
).readOnly()
willInitSemantic: (settings) ->
settings.firstDayOfWeek = if Number.isFinite(@get('firstDayOfWeek')) then @get('firstDayOfWeek') else (if Number.isFinite(@get('globals.first_day_of_week')) then @get('globals.first_day_of_week') else 1)
@_super arguments...
@set('is_date', true) if @get('momentValue._f') is 'YYYY-MM-DD' or @get('momentValue._ambigTime') or @get('type') is 'date'
merge settings,
onChange: (date) ->
# Wraps the Date in a moment object an triggers the onChange action
momentDate = if date then moment(date) else null
momentDate._ambigTime = true if momentDate and @get('is_date')
@sendAction 'onChange', momentDate
+14
View File
@@ -0,0 +1,14 @@
import Ember from 'ember'
import layout from '../templates/components/ui-markdown-popup'
import UiPopup from 'semantic-ui-ember/components/ui-popup'
import showdown from 'showdown'
export default UiPopup.extend
extensions: []
init: ->
markdown = @get('markdown')
converter = new showdown.Converter(@get('extensions'))
html = converter.makeHtml(markdown)
@attrs.html = html
@_super arguments...
layout: layout
@@ -0,0 +1,191 @@
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
if vars.suffix
path = "#{path}.#{vars.suffix}"
delete vars.suffix
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"
@@ -0,0 +1,16 @@
import Ember from 'ember'
## This function receives the params `params, hash`
#export anyPermissionStartsWith = (params) ->
# return params
#export default Ember.Helper.helper anyPermissionStartsWith
export default Ember.Helper.extend
globals: Ember.inject.service('globals')
compute: ([expression], options) ->
return false unless @get('globals.current_user')
return true if @get('globals.current_user.admin')
regexp = new RegExp("^\\w+-\\w+-#{expression}")
roles = @get('globals.current_user.role_names')
roles.some (role) ->
regexp.test role
+13
View File
@@ -0,0 +1,13 @@
import Ember from 'ember'
export default Ember.Helper.extend
globals: Ember.inject.service('globals')
custom_compute: (authorization, type, target, roles) ->
false
compute: ([authorization, type, target], options) ->
return false unless @get('globals.current_user')
return true if @get('globals.current_user.admin')
roles = @get('globals.current_user.role_names') || []
return true if "manage-#{type}-#{target}" in roles
return true if "#{authorization}-#{type}-#{target}" in roles
@custom_compute.call(@, authorization, type, target, roles)
+9
View File
@@ -0,0 +1,9 @@
import Ember from 'ember'
export formatDate = ([date], options={}) ->
return '' unless date
return date if typeof date is 'string'
date = moment(date) unless date._isAMomentObject
date.format(options.format || 'll')
export default Ember.Helper.helper formatDate
@@ -0,0 +1,17 @@
import Ember from 'ember'
## This function receives the params `params, hash`
#export hasPermissionOfType = (params) ->
# return params
#export default Ember.Helper.helper hasPermissionOfType
export default Ember.Helper.extend
globals: Ember.inject.service('globals')
compute: ([permission_type], options) ->
return false unless permission_type
return false unless @get('globals.current_user')
return true if @get('globals.current_user.admin')
regexp = new RegExp("^\\w+-#{permission_type}-")
roles = @get('globals.current_user.role_names')
roles.some (role) ->
regexp.test role
+13
View File
@@ -0,0 +1,13 @@
import Ember from 'ember'
# This function receives the params `params, hash`
export minuteOfDay = ([number]) ->
return '-' unless number?
hour = Math.floor(number / 60)
minute = number % 60
hour_string = "0#{hour}".slice(-2)
minute_string = "0#{minute}".slice(-2)
"#{hour_string}:#{minute_string}"
export default Ember.Helper.helper minuteOfDay
+41
View File
@@ -0,0 +1,41 @@
import Ember from 'ember'
headers = [
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ", "AK", "AL", "AM", "AN", "AO", "AP", "AQ", "AR", "AS", "AT", "AU", "AV",
"AW", "AX", "AY", "AZ", "BA", "BB", "BC", "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BK", "BL", "BM", "BN", "BO", "BP", "BQ", "BR",
"BS", "BT", "BU", "BV", "BW", "BX", "BY", "BZ", "CA", "CB", "CC", "CD", "CE", "CF", "CG", "CH", "CI", "CJ", "CK", "CL", "CM", "CN",
"CO", "CP", "CQ", "CR", "CS", "CT", "CU", "CV", "CW", "CX", "CY", "CZ", "DA", "DB", "DC", "DD", "DE", "DF", "DG", "DH", "DI", "DJ",
"DK", "DL", "DM", "DN", "DO", "DP", "DQ", "DR", "DS", "DT", "DU", "DV", "DW", "DX", "DY", "DZ", "EA", "EB", "EC", "ED", "EE", "EF",
"EG", "EH", "EI", "EJ", "EK", "EL", "EM", "EN", "EO", "EP", "EQ", "ER", "ES", "ET", "EU", "EV", "EW", "EX", "EY", "EZ", "FA", "FB",
"FC", "FD", "FE", "FF", "FG", "FH", "FI", "FJ", "FK", "FL", "FM", "FN", "FO", "FP", "FQ", "FR", "FS", "FT", "FU", "FV", "FW", "FX",
"FY", "FZ", "GA", "GB", "GC", "GD", "GE", "GF", "GG", "GH", "GI", "GJ", "GK", "GL", "GM", "GN", "GO", "GP", "GQ", "GR", "GS", "GT",
"GU", "GV", "GW", "GX", "GY", "GZ", "HA", "HB", "HC", "HD", "HE", "HF", "HG", "HH", "HI", "HJ", "HK", "HL", "HM", "HN", "HO", "HP",
"HQ", "HR", "HS", "HT", "HU", "HV", "HW", "HX", "HY", "HZ", "IA", "IB", "IC", "ID", "IE", "IF", "IG", "IH", "II", "IJ", "IK", "IL",
"IM", "IN", "IO", "IP", "IQ", "IR", "IS", "IT", "IU", "IV", "IW", "IX", "IY", "IZ", "JA", "JB", "JC", "JD", "JE", "JF", "JG", "JH",
"JI", "JJ", "JK", "JL", "JM", "JN", "JO", "JP", "JQ", "JR", "JS", "JT", "JU", "JV", "JW", "JX", "JY", "JZ", "KA", "KB", "KC", "KD",
"KE", "KF", "KG", "KH", "KI", "KJ", "KK", "KL", "KM", "KN", "KO", "KP", "KQ", "KR", "KS", "KT", "KU", "KV", "KW", "KX", "KY", "KZ",
"LA", "LB", "LC", "LD", "LE", "LF", "LG", "LH", "LI", "LJ", "LK", "LL", "LM", "LN", "LO", "LP", "LQ", "LR", "LS", "LT", "LU", "LV",
"LW", "LX", "LY", "LZ", "MA", "MB", "MC", "MD", "ME", "MF", "MG", "MH", "MI", "MJ", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR",
"MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NB", "NC", "ND", "NE", "NF", "NG", "NH", "NI", "NJ", "NK", "NL", "NM", "NN",
"NO", "NP", "NQ", "NR", "NS", "NT", "NU", "NV", "NW", "NX", "NY", "NZ", "OA", "OB", "OC", "OD", "OE", "OF", "OG", "OH", "OI", "OJ",
"OK", "OL", "OM", "ON", "OO", "OP", "OQ", "OR", "OS", "OT", "OU", "OV", "OW", "OX", "OY", "OZ", "PA", "PB", "PC", "PD", "PE", "PF",
"PG", "PH", "PI", "PJ", "PK", "PL", "PM", "PN", "PO", "PP", "PQ", "PR", "PS", "PT", "PU", "PV", "PW", "PX", "PY", "PZ", "QA", "QB",
"QC", "QD", "QE", "QF", "QG", "QH", "QI", "QJ", "QK", "QL", "QM", "QN", "QO", "QP", "QQ", "QR", "QS", "QT", "QU", "QV", "QW", "QX",
"QY", "QZ", "RA", "RB", "RC", "RD", "RE", "RF", "RG", "RH", "RI", "RJ", "RK", "RL", "RM", "RN", "RO", "RP", "RQ", "RR", "RS", "RT",
"RU", "RV", "RW", "RX", "RY", "RZ", "SA", "SB", "SC", "SD", "SE", "SF", "SG", "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SP",
"SQ", "SR", "SS", "ST", "SU", "SV", "SW", "SX", "SY", "SZ", "TA", "TB", "TC", "TD", "TE", "TF", "TG", "TH", "TI", "TJ", "TK", "TL",
"TM", "TN", "TO", "TP", "TQ", "TR", "TS", "TT", "TU", "TV", "TW", "TX", "TY", "TZ", "UA", "UB", "UC", "UD", "UE", "UF", "UG", "UH",
"UI", "UJ", "UK", "UL", "UM", "UN", "UO", "UP", "UQ", "UR", "US", "UT", "UU", "UV", "UW", "UX", "UY", "UZ", "VA", "VB", "VC", "VD",
"VE", "VF", "VG", "VH", "VI", "VJ", "VK", "VL", "VM", "VN", "VO", "VP", "VQ", "VR", "VS", "VT", "VU", "VV", "VW", "VX", "VY", "VZ",
"WA", "WB", "WC", "WD", "WE", "WF", "WG", "WH", "WI", "WJ", "WK", "WL", "WM", "WN", "WO", "WP", "WQ", "WR", "WS", "WT", "WU", "WV",
"WW", "WX", "WY", "WZ", "XA", "XB", "XC", "XD", "XE", "XF", "XG", "XH", "XI", "XJ", "XK", "XL", "XM", "XN", "XO", "XP", "XQ", "XR",
"XS", "XT", "XU", "XV", "XW", "XX", "XY", "XZ", "YA", "YB", "YC", "YD", "YE", "YF", "YG", "YH", "YI", "YJ", "YK", "YL", "YM", "YN",
"YO", "YP", "YQ", "YR", "YS", "YT", "YU", "YV", "YW", "YX", "YY", "YZ", "ZA", "ZB", "ZC", "ZD", "ZE", "ZF", "ZG", "ZH", "ZI", "ZJ",
"ZK", "ZL", "ZM", "ZN", "ZO", "ZP", "ZQ", "ZR", "ZS", "ZT", "ZU", "ZV", "ZW", "ZX", "ZY", "ZZ"
]
# This function receives the params `params, hash`
export numberToXlsHeader = ([index], options) ->
headers[index]
export default Ember.Helper.helper numberToXlsHeader
+13
View File
@@ -0,0 +1,13 @@
import Ember from 'ember'
# This function receives the params `params, hash`
export translate = (params, options) ->
path = params[0]
toptions = options
if params.length > 1 and typeof(params[1].toJSON) is 'function'
$.extend toptions, params[1].toJSON()
text = t(path, toptions)
tag = if options.bare then text else "<span data-t='#{path}' class='translation' data-t-attributes='#{JSON.stringify(toptions)}'>#{text}</span>"
tag.htmlSafe()
export default Ember.Helper.helper translate
@@ -0,0 +1,18 @@
import ComponentOverrides from 'ember-cli-dunlop/overrides/component'
import ControllerOverrides from 'ember-cli-dunlop/overrides/controller'
import ObjectOverrides from 'ember-cli-dunlop/overrides/object'
import RouteOverrides from 'ember-cli-dunlop/overrides/route'
import DunlopTranslationFunctions from 'ember-cli-dunlop/dunlop-translations/global-functions'
#included: function(app) {
# this._super.included(app);
# app.import('ember-cli-dunlop/overrides/component');
# app.import('ember-cli-dunlop/overrides/controller');
#}
# Takes two parameters: container and application
export initialize = () ->
# application.register 'route', 'foo', 'service:foo'
export default {
name: 'ember-cli-dunlop-overrides'
initialize: initialize
}
+165
View File
@@ -0,0 +1,165 @@
import Ember from 'ember'
import config from 'ember-get-config'
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin'
export default Ember.Mixin.create ApplicationRouteMixin,
current_user_loaded: (user) ->
beforeModel: (transition) ->
@_loadCurrentUser arguments... unless transition?.targetName is 'login'
sessionAuthenticated: ->
@_super arguments...
@_loadCurrentUser()
_loadCurrentUser: (transition) ->
#if userId = @get('session.data.authenticated.user_id')
return if transition?.targetName is 'login'
@get('store').queryRecord('user', me: true).then (user) =>
@set 'router.globals.current_user', user
@current_user_loaded user # overloadable
, =>
@set 'router.globals.current_user', null
#@transitionTo('login').then (loginRoute) -> loginRoute.set('router.globals.flash.notice', 'Please login')
@transitionTo('login')
actions:
error: (error) ->
return unless @connections?.length # cannot use outlet at this moment
console.log error
container = Ember.getOwner(@)
if status = error.status || error?.errors?[0].status
switch parseInt(status)
when 401, 403
@set 'router.globals.current_user', null
@transitionTo 'login'
return
controller = container.lookup "component:error-handling"
return unless controller?.set
controller.set 'error', error
@render 'global/error-messages',
into: 'application'
outlet: 'error-handling'
controller: controller
#@set "router.globals.flash_message", "Oops! Something went wrong!<br>#{error.message}".htmlSafe()
clear_error: ->
#@disconnectOutlet # https://github.com/emberjs/ember-inspector/issues/625
# outlet: 'error-handling'
# parentView: 'application'
@render 'modals/nothing',
outlet: 'error-handling'
into: 'application'
controller: 'application'
@set 'router.globals.modal_active', false
clear_error_and_go_home: ->
@send 'clear_error'
@transitionTo 'index'
didTransition: ->
@_super arguments...
Ember.run.next =>
return unless path = @get('controller.currentPath')
@set 'router.globals.current_route', Ember.Object.create
path: path # a.b.c
node: path.replace(/.*\./, '') # c
primary: '.' in path
openModal: (modalName, options={}) ->
if typeof options is 'function'
console.warn "Modal #{modalName} call has function as argument in stead of options!"
return
else if options.promise? and options.content
options = {model: options.content}
else if typeof options isnt 'object'
options = {model: options}
options.model = options.model.content if options.model?.promise? and options.model.content
container = Ember.getOwner(@)
modalNameParts = modalName.split('/')
partialName = modalNameParts.pop()
controller = container.lookup "component:modals/#{modalName}"
if not controller and modalNameParts.length
controller = container.lookup "component:#{modalNameParts.join('/')}/modals/#{partialName}"
controller ||= container.lookup "component:#{modalName}"
controller ||= container.lookup('component:modals/base')
#try
# controller = @controllerFor("modals/#{modalName}")
#catch error
# controller = @controllerFor("modals/base")
#controller ||= @controllerFor("modals/base")
controller.set 'model', options.model
defaultModalOptions =
closeOnOverlay: true
closeOnModalClick: false
modal_options = Ember.Object.create($.extend(defaultModalOptions, options))
controller.set 'modal_options', modal_options
# use root level partials for wizards and elementary use case
# Try to resolve the modalName traversing up the hierarchy so a modalName
# of wizard/create-distribution-point/copper/edit-distribution-point will look for partials:
#
# wizard/create-distribution-point/copper/-edit-distribution-point
# wizard/create-distribution-point/copper/modals/-edit-distribution-point
# modals/wizard/create-distribution-point/copper/-edit-distribution-point
#
# wizard/create-distribution-point/-edit-distribution-point
# wizard/create-distribution-point/modals/-edit-distribution-point
# modals/wizard/create-distribution-point/-edit-distribution-point
#
# wizard/-edit-distribution-point
# wizard/modals/-edit-distribution-point
# modals/wizard/-edit-distribution-point
#
# -edit-distribution-point
# modals/-edit-distribution-point
#
partialPath = null
while not partialPath and modalNameParts.length
if container.lookup "template:#{modalNameParts.join('/')}/-#{partialName}"
partialPath = "#{modalNameParts.join('/')}/#{partialName}" # without the dash
else if container.lookup "template:#{modalNameParts.join('/')}/modals/-#{partialName}"
partialPath = "#{modalNameParts.join('/')}/modals/#{partialName}" # without the dash
else if container.lookup "template:modals/#{modalNameParts.join('/')}/modals/-#{partialName}"
partialPath = "modals/#{modalNameParts.join('/')}/modals/#{partialName}" # without the dash
else if container.lookup "template:components/#{modalNameParts.join('/')}/-#{partialName}"
partialPath = "components/#{modalNameParts.join('/')}/#{partialName}" # without the dash
modalNameParts.pop()
partialPath ||= partialName if container.lookup("template:-#{partialName}") # can be root template
partialPath ||= "modals/#{partialName}" if container.lookup("template:modals/-#{partialName}") # can be root template
unless partialPath
message = "Cannot find template for modal '#{modalName}'"
console.log message
@set "router.globals.flash_message", message
return
@incrementProperty 'router.globals.modals_counter'
controller.set 'partialName', partialPath
controller.willOpenModal() # can be implemented to setup stuff before rendering and hooks
@render 'modals/layout',
into: 'application'
outlet: 'modal'
controller: controller
@set 'router.globals.modal_active', true
false # return false since this result will in most cases the the last statement of an action. So prevent bubbling
closeModal: ->
#@disconnectOutlet # https://github.com/emberjs/ember-inspector/issues/625
# outlet: 'modal'
# parentView: 'application'
@render 'modals/nothing',
outlet: 'modal'
into: 'application'
controller: 'application'
@set 'router.globals.modal_active', false
signOut: ->
@set 'router.globals.current_user', null
@get('session').invalidate() if @get('session.isAuthenticated')
@transitionTo 'login'
try
$.ajax
url: "#{config.apiHost}/users/sign_out"
type: 'DELETE'
dataType: 'json'
+121
View File
@@ -0,0 +1,121 @@
import Ember from 'ember'
export default Ember.Component.extend
alert_message: ""
modal_options: {}
layoutName: 'modals/layout'
willOpenModal: -> # can be implemented, is fired after loading attributes, before rendering
title: (->
# return title if directly set by options
return @get('modal_options.title') if @get('modal_options.title')
# return translated title_path if directly set by controller
translation_params = {}
if title_params = @get('modal_options.title_params')
translation_params = title_params
else if model = @get('model')
if model.toJSON
translation_params = model.toJSON()
else if model.__changeset__ and model._content?.toJSON
translation_params = model._content.toJSON()
# return translated title_path if directly set by options
# return translated title_path if directly set by controller
if title_path = @get('modal_options.title_path') || @get('title_path')
return tspan(title_path, translation_params).htmlSafe()
translation_params.emptyWhenNotFound = true # allow for fallbacks
partial_title_path = "#{@get('partialName').replace(/-/g, '_').replace(/\W/g, '.')}.title"
return partialNameTranslation.htmlSafe() if partialNameTranslation = tspan(partial_title_path, translation_params)
# @toString() => <frontend@component:workflow-action-definition/modals/edit-workflow-action-definition::ember873>
underscored = @toString().replace(/.*(controller|component):/, '').replace(/::ember.*$/, '').replace(/\W+$/, '').underscore().replace(/\//g, '.')
return convention_translation.htmlSafe() if convention_translation = tspan("#{underscored}.title", translation_params)
# Return a kind of humanized version of the title
underscored.replace(/.*\./,'').capitalize().replace(/_/, ' ')
).property('model.id', 'modal_options.title_path')
body: (->
@get('modal_options.body')
).property('modal_options.body')
save_error: (error)->
if typeof error is 'string'
@set 'alert_message', error
else if error?.status is 403 or error?.status is 401
@set 'alert_message', 'Unauthorized action'
else
@set 'alert_message', 'Something went wrong'
save_success: ->
@set 'alert_message', ''
pre_hook_modals_count = @get('globals.modals_counter')
if save_callback = @get('modal_options.save')
save_callback.apply(@, arguments)
after_hook_modals_count = @get('globals.modals_counter')
@send 'closeModal' unless after_hook_modals_count > pre_hook_modals_count # when modals count changed, another modal is opened by the hook. Do not close
actions:
close: ->
pre_hook_modals_count = @get('globals.modals_counter')
if close = @get('modal_options.close')
close.apply(@)
after_hook_modals_count = @get('globals.modals_counter')
unless @preventClose or after_hook_modals_count > pre_hook_modals_count # when modals count changed, another modal is opened by the hook. Do not close
@set 'alert_message', ''
@send 'closeModal'
closeOnOverlay: ->
@send('rollback_and_close') if @get('modal_options.closeOnOverlay')
false
modalClick: ->
@send('close') if @get('modal_options.closeOnModalClick')
false
ok: ->
if ok = @get('modal_options.ok')
ok.call(@)
@set 'alert_message', ''
@send 'closeModal' unless @preventClose
confirm: -> @send('ok')
saveRecord: ->
model = @get("model")
if typeof model.validate is 'function'
model.validate() # validate if method exists
if changeset = model.get('changeset')
changeset.validate()
if changeset.get('isValid')
changeset.save().then @save_success.bind(@), @save_error.bind(@)
else
if model.get('isValid')
model.save().then @save_success.bind(@), @save_error.bind(@)
#@send 'closeModal' unless @preventClose
else
console.log "[VALIDATION ERRORS]"
console.log model.get("errors")
rollback_and_close: ->
if model = @get("model")
if model.__changeset__
model.rollback()
if model.get("_content.isNew") # delete new records on modal rollback
model.get("_content").deleteRecord() #NOTE: maybe this should be unloadRecord --force=true (state/dirty tracking issues)
else
model.rollbackAttributes() if typeof model.rollbackAttributes is 'function'
@send 'close'
destroyRecord: ->
my_scope = @
destroy_callback = @get('modal_options.destroy_callback') || ->
# transition to top level route if current is nested inside a model.show route
if modelName = my_scope.get('model.constructor.modelName')
flat_model_name = modelName.replace(/^\w+\//, '').replace('/', '.') # panda/projec => project
if my_scope.get('router.globals.current_route.path')?.match("^#{flat_model_name}.show")
my_scope.get('router').transitionTo flat_model_name
@modal 'confirm',
title_path: @get('modal_options.destroy_text_path') || 'general.destroy.are_you_sure'
model: @get('model')
ok: ->
model = @get("model")
model = model.get("_content") if model.__changeset__
model.destroyRecord().then -> destroy_callback.call(my_scope, model)
@send 'closeModal' unless @preventClose
closeModal: ->
container = Ember.getOwner(@)
ar = container.lookup('route:application')
ar.send 'closeModal'
+8
View File
@@ -0,0 +1,8 @@
import DS from 'ember-data'
export default DS.Model.extend
nickname: DS.attr('string')
email: DS.attr('string')
admin: DS.attr('boolean', defaultValue: false)
role_names: DS.attr(defaultValue: -> [])
+5
View File
@@ -0,0 +1,5 @@
import Ember from 'ember'
export default Ember.Component.reopen
modal: (name, options={}) ->
target = Ember.getOwner(@).lookup('route:application')
target.send "openModal", name, options
+4
View File
@@ -0,0 +1,4 @@
import Ember from 'ember'
export default Ember.Controller.reopen
modal: (name, options={})->
@send "openModal", name, options
+20
View File
@@ -0,0 +1,20 @@
import Ember from 'ember'
export default Ember.Object.reopen
getPropertyValues: (names...) ->
result = Ember.A()
for name in names
result.push @get(name)
result
toProperties: ->
result = {}
for key, value of @
continue unless @hasOwnProperty(key)
continue if key is 'changeset'
if typeof(value?.format) is 'function'
value = value.format()
else if typeof(value?.toISOString) is 'function'
value = value.toISOString()
result[key] = value
result
+5
View File
@@ -0,0 +1,5 @@
import Ember from 'ember'
Ember.Route.reopen
modal: (name, options = {})->
@send "openModal", name, options
@@ -0,0 +1,27 @@
import { ActiveModelSerializer } from 'active-model-adapter'
export default ActiveModelSerializer.extend #DS.EmbeddedRecordsMixin,
#serializeIntoHash: ->
# debugger
# @_super arguments...
# debugger
# 3
#payloadKeyFromModelName: (modelName) ->
# key = @_super(modelName)
# key.replace(/\//g, '.')
serializeBelongsTo: (snapshot, json, relationship)->
payloadKey = @keyForRelationship(relationship.key, 'belongsTo', 'serialize')
belongsToId = snapshot.record.get("#{relationship.key}.id")
belongsToId?= null
json[payloadKey] = belongsToId
# the super method looks up the inverse (workflow_step_definition) in stead of the constraint_workflow_step_definition id
#debugger
#@_super(arguments...)
# If a relationship has configuration serialize: 'ids' then add the association's ids
# comments: DS.hasMany('comment', serialize: 'ids')
serializeHasMany: (snapshot, json, relationship)->
if relationship.options.serialize is 'ids'
json["#{relationship.key.singularize()}_ids"] = Ember.get(snapshot.record, relationship.key).mapBy('id').toArray()
+69
View File
@@ -0,0 +1,69 @@
.pointable
cursor: pointer
.comma-separated-items
> *
&:after
content: ", "
&:last-child
&:after
content: ""
.pull-right
float: right
.unpadded
padding: 0 !important
.ui.table
td
&.compact
padding: 0.5em 0.7em
input:disabled
background-color: #ccc !important
// .ui.grid might end up with columns having a negative bottom margin that captures the click event of the svg below it
.without-bottom-margin
margin-bottom: 0 !important
.between-brackets
&:before
content: '('
&:after
content: ')'
&.curly
&:before
content: '{'
&:after
content: '}'
&.angle
&:before
content: '<'
&:after
content: '>'
&.square
&:before
content: '['
&:after
content: ']'
&.spaced
&:before
content: '( '
&:after
content: ' )'
&.curly
&:before
content: '{ '
&:after
content: ' }'
&.angle
&:before
content: '< '
&:after
content: ' >'
&.square
&:before
content: '[ '
&:after
content: ' ]'
+17
View File
@@ -0,0 +1,17 @@
$non-default-attention-color: #f2711c;
@import "./mixins/animations";
@import './convenience-helpers';
@import "./components/collapsible-content";
@import "./components/error-handling";
@import "./components/modal";
@import "./components/flash-message";
@import "./components/forms";
@import "./components/page-title";
@import "./components/pagination";
@import "./components/table-filtering";
@import "./components/title-box";
@import "./components/ui-calendar-additions";
@import "./components/ui-markdown-popup";
@@ -0,0 +1,3 @@
.collapsible-content-container
.header
cursor: pointer
@@ -0,0 +1,3 @@
.dunlop-global-error
&.hidden
display: none
@@ -0,0 +1,26 @@
.flash-message
position: fixed
top: 60px
right: -440px
background-color: rgba(200,200,200,0.8)
padding: 20px
width: 400px
border-radius: 9999px
font-weight: bold
font-size: 1.4
z-index: 8976
+animation(flashMessageInactive 0.5s)
&.active
+animation(flashMessageActive 0.5s)
right: 20px
+keyframes(flashMessageActive)
from
right: -440px
to
right: 20px
+keyframes(flashMessageInactive)
from
right: 20px
to
right: -440px
+19
View File
@@ -0,0 +1,19 @@
.ui.form
.form-label
display: inline-block
vertical-align: top
width: 35%
.form-field
display: inline-block
width: 64%
@media screen and (max-width: 723px)
.form-label
width: 99%
.form-field
width: 99%
.form-actions
clear: both
margin-top: 12px
padding-top: 8px
border-top: 1px solid #ddd
+74
View File
@@ -0,0 +1,74 @@
.modal
margin: 10px auto
width: 1122px
max-width: 100%
background-color: #fff
padding: 1em
padding-bottom: 0
max-height: calc(100% - 20px)
overflow-y: scroll
z-index: 6524
.modal-body
// Add space for modal-actions
padding-bottom: 86px
position: relative
min-height: 392px
.modal-rollback
//+button($bg: $secondary-color)
//@extend .ui, .button
.modal-close
//+button($bg: #ddd)
//@extend .ui, .button
.modal-confirm, .modal-ok, .modal-save, .modal-add
//+button
//@extend .primary
.modal-destroy
//+button($bg: $alert-color)
//@extend .negative
margin-right: 8px
.modal-edit
//+button($bg: $warning-color)
margin-right: 8px
.done
text-decoration: line-through
.modal-actions
border-top: 1px solid #999
padding-top: 7px
padding-bottom: 7px
margin-bottom: -86px
> a
margin-bottom: 0
&.sticky
position: absolute
margin-bottom: 0
box-shadow: 0 -3px 9px -2px rgba(0, 0, 0, 0.8)
background-color: #eee
padding-left: 1em
padding-right: 1em
bottom: 0
width: calc(100% + 2em)
//Width: 100%
margin-left: -1em
//margin-right: -1em
border-top: 1px solid #999
.pull-right
.ui.action.input
margin-right: 122px
.ui.message
margin: 0
.modal-alert
//@extend .alert-box
//@extend .alert
//color: $alert-color
.overlay
height: 100%
width: 100%
position: fixed
top: 0
left: 0
background-color: rgba(0, 0, 0, 0.5)
z-index: 6522
.flush--top
margin-top: 0
+6
View File
@@ -0,0 +1,6 @@
.page-title
&.ui.header
margin-top: 12px
.between-brackets
&:before
margin-left: 1rem
+33
View File
@@ -0,0 +1,33 @@
ul.pagination
padding: 0
list-style: none
a
cursor: pointer
&.disabled
cursor: default
li
display: inline
&.arrow
a
padding: 0 6px
&.next
padding-left: 3px // subtract margin-right from li
&.page-number
margin-right: 3px
a
background-color: #ccc
padding: 4px
color: #666
border-radius: 3px
&.active
a
color: white
background-color: black
font-weight: bold
.ui.top-right.pagination.menu
float: right
border-bottom-left-radius: 0
border-bottom-right-radius: 0
margin-top: 8px
border-bottom-width: 0
@@ -0,0 +1,81 @@
// ransack componennt integration
table thead tr.table-filters-row, table.ui.table thead tr.table-filters-row
input
margin: 0
margin-top: 3px
padding: 3px
button
margin: 0
margin-top: 3px
th
padding: 0 4px
&.active-filter
background-color: rgba(242, 112, 28, 0.15)
color: $non-default-attention-color
.active-button
background-color: $non-default-attention-color
color: white
font-weight: bold
i, i.ui.icon
cursor: pointer
pointer-events: auto
// Allow force by means of extra class
&.action
cursor: pointer !important
pointer-events: auto !important
&.filter-date-range
.menu
.divider + .item
padding-top: 0 !important
.item + .divider
margin-top: 0
.select-week
input
width: 72px
.select-year
input
width: 92px
.ui.horizontal.divider
// Without this css it renders a double border if text is used
border-top: 0
// semantic-ui implementation
table
td, th
&.actions
// semantic-ui .collapsing
width: 1px
white-space: nowrap
text-align: right
.ui.icon.button
padding: 0.4rem
table.ui.table
thead
// custom
tr.filters
th
padding: 0
i.close.icon
cursor: pointer
margin-left: 6px
.active-filter
.active-button
background-color: $non-default-attention-color
color: white
font-weight: bold
tr.table-filters-row
.filter-dropdown-select-multiple
.ui.action.input
margin-right: 49px // space for action button
input
margin-top: 0
.ui.icon.button
i
// This one is somehow needed for the right filter icon fit
padding-top: 0
.ui.header
&.active-filter
color: $non-default-attention-color
+71
View File
@@ -0,0 +1,71 @@
/* Based on the bootstrap 3+ panel, of course under a different name.
The conversion is done based on:
http://stackoverflow.com/questions/19220027/can-you-use-panels-in-bootstrap-2-3
.title-box
padding: 15px
margin-bottom: 20px
background-color: #ffffff
border: 1px solid #dddddd
border-radius: 4px
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05)
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05)
.title-box-heading
padding: 10px 15px
margin: -15px -15px 15px
font-size: 17.5px
font-weight: 500
background-color: #f5f5f5
border-bottom: 1px solid #dddddd
border-top-right-radius: 3px
border-top-left-radius: 3px
.title-box-footer
padding: 10px 15px
margin: 15px -15px -15px
background-color: #f5f5f5
border-top: 1px solid #dddddd
border-bottom-right-radius: 3px
border-bottom-left-radius: 3px
.title-box-primary
border-color: #428bca
.title-box-heading
color: #ffffff
background-color: #428bca
border-color: #428bca
.title-box-success
border-color: #d6e9c6
.title-box-heading
color: #468847
background-color: #dff0d8
border-color: #d6e9c6
.title-box-warning
border-color: #fbeed5
.title-box-heading
color: #c09853
background-color: #fcf8e3
border-color: #fbeed5
.title-box-danger
border-color: #eed3d7
.title-box-heading
color: #b94a48
background-color: #f2dede
border-color: #eed3d7
.title-box-info
border-color: #bce8f1
.title-box-heading
color: #3a87ad
background-color: #d9edf7
border-color: #bce8f1
//State specific additions
@@ -0,0 +1,24 @@
// This fixes the issue of ember-semantic-ui-calendar not functioning inside a definition table
.ui.definition.table .ui.calendar
padding: 0
table
//border: 1px solid rgba(34,36,38,.15)
border-radius: .28571429rem
box-shadow: none
color: rgba(0,0,0,.87)
tr
th
pointer-events: all
font-weight: bold
color: rgba(0,0,0,.87)
background-color: #F9FAFB
&:nth-child(2)
border-left: 0
td
pointer-events: all
&:first-child:not(.ignored)
background-color: white
font-weight: normal
&.disabled
color: rgba(40, 40, 40, 0.3)
@@ -0,0 +1,8 @@
body .ui.popup
z-index: 9021
>
ul, ol
margin-top: 4px
margin-bottom: 4px
padding-left: 1em
+27
View File
@@ -0,0 +1,27 @@
=animation($animate...)
$max: length($animate)
$animations: ""
@for $i from 1 through $max
$animations: #{$animations + nth($animate, $i)}
@if $i < $max
$animations: #{$animations + ", "}
-webkit-animation: $animations
-moz-animation: $animations
-o-animation: $animations
animation: $animations
=keyframes($animationName)
@-webkit-keyframes #{$animationName}
@content
@-moz-keyframes #{$animationName}
@content
@-o-keyframes #{$animationName}
@content
@keyframes #{$animationName}
@content
@@ -0,0 +1,9 @@
if collapsed
.ui.header{action 'toggleCollapsed'}
i.arrow.right.icon
.content= title
else
.ui.header{action 'toggleCollapsed'}
i.arrow.down.icon
.content= title
= yield
@@ -0,0 +1,26 @@
/.ui.form
.ui.right.floated.icon.buttons
if isEditing
= push-action type='rollback' action='rollbackRecord'
= push-action type='destroy' action='destroyRecord'
= push-action type='save' action='saveRecord'
else
if can_make_editable
/= push-action type='edit' action='editRecord'
if isEditing
= input value=model.name enter='saveRecord'
else
span= model.name
if isEditing
.ui.action.input
= input value=model.name enter='saveRecord'
= push-action type='rollback' action='rollbackRecord'
= push-action type='destroy' action='destroyRecord'
= push-action type='save' action='saveRecord'
if validation_message
br
.ui.pointing.red.basic.label= validation_message
else
span= model.name
= yield
@@ -0,0 +1,3 @@
i.close.icon
.header= error_header
= yield
@@ -0,0 +1,3 @@
= progressText
= yield
@@ -0,0 +1,3 @@
i.icon class=iconClass
if hasBlock
span.push-action-content= yield
@@ -0,0 +1 @@
= yield
+1
View File
@@ -0,0 +1 @@
import './freeze-moment'
+11
View File
@@ -0,0 +1,11 @@
window.freezeMoment = (time, callback) ->
#time = "#{time}Z" if typeof time is 'string' and time.slice(-1) isnt 'Z' # work with UTC dates?
time = moment(time) unless time._isAMomentObject
originalMomentNow = moment.now
date = time.toDate()
moment.now = -> date
callback.call null, time
moment.now = originalMomentNow
time
+16
View File
@@ -0,0 +1,16 @@
import DS from 'ember-data'
import moment from 'moment'
# mozo magick, better than ember-cli-moment-transform, since it preserves dates through time zones!!!!
export default DS.Transform.extend
deserialize: (serialized)->
return serialized unless serialized
m = moment(serialized)
m.type = 'date'
m
serialize: (deserialized, options = {})->
return deserialized unless deserialized
deserialized = moment(deserialized) unless moment.isMoment(deserialized)
deserialized.format(options.format || 'YYYY-MM-DD')
+16
View File
@@ -0,0 +1,16 @@
import DS from 'ember-data'
import moment from 'moment'
# mozo magick, better than ember-cli-moment-transform, since it preserves dates through time zones!!!!
export default DS.Transform.extend
deserialize: (serialized)->
return serialized unless serialized
m = moment(serialized)
m.type = 'datetime'
m
serialize: (deserialized, options = {})->
return deserialized unless deserialized
deserialized = moment(deserialized) unless moment.isMoment(deserialized)
deserialized.format(options.format)
+17
View File
@@ -0,0 +1,17 @@
dateSort = (date_a, date_b) ->
if date_a
a = if date_a.toISOString then date_a.toISOString() else date_a
else
a = null
if date_b
b = if date_b.toISOString then date_b.toISOString() else date_b
else
b = null
Ember.compare a, b
create_date_sort = (attribute) ->
(object_a, object_b) ->
dateSort object_a.get(attribute), object_b.get(attribute)
export { create_date_sort }
export default dateSort
+10
View File
@@ -0,0 +1,10 @@
getMaxSuffix = (array) ->
max = 0
return 0 unless array
array.forEach (element)->
return unless element
max = Math.max(match[0], max) if match = String(element).match /\d+$/
max
window.get_max_suffix = getMaxSuffix # make globally available
export default getMaxSuffix
+11
View File
@@ -0,0 +1,11 @@
# based on https://github.com/alisdair/horses-and-chickens
import Ember from 'ember'
export default (attribute) ->
Ember.computed attribute,
get: ->
@get(attribute).toString()
set: (key, value) ->
@set(attribute, parseInt(value, 10))
return value
+46
View File
@@ -0,0 +1,46 @@
mapSum = (target, property) ->
Ember.computed "#{target}.@each.#{property}", ->
return 0 unless ary_result = @get(target).mapBy(property)
return 0 unless ary_result.length
ary_result.reduce( ((sum, item) -> sum + item), 0)
mapFilter = (target, property, filter_by_key) ->
Ember.computed "#{target}.@each.#{property}", filter_by_key, ->
@get(target).filterBy(property, @get(filter_by_key))
mapHasMany = (target, has_many_relation) ->
Ember.computed "#{target}.@each.#{has_many_relation}", ->
result = Ember.A()
Ember.RSVP.all(@get(target).mapBy(has_many_relation)).then (targets_has_many_associations) ->
Ember.run ->
targets_has_many_associations.forEach (target_has_many_records) ->
result.pushObjects target_has_many_records.toArray()
result
mapMany = (target, many_attribute) ->
Ember.computed "#{target}.@each.#{many_attribute}", ->
result = Ember.A()
Ember.run =>
targets = @get(target)
if Ember.isArray(targets)
targets.forEach (record) ->
result.pushObjects record.get(many_attribute)
else
targets.then (records) ->
records.forEach (record) ->
result.pushObjects record.get(many_attribute)
result
mapMax = (target, property, options={}) ->
Ember.computed "#{target}.@each.#{property}", ->
return 0 unless ary_result = @get(target).mapBy(property)
return 0 unless ary_result.length
ary_result.reduce (max, item) ->
Math.max(max, item)
, -Infinity
export { mapSum, mapFilter, mapHasMany, mapMany, mapMax }
export default Ember.Object.create
mapSum: mapSum
mapFilter: mapFilter
mapHasMany: mapHasMany
+12
View File
@@ -0,0 +1,12 @@
# This is an objects merge helper but in stead of
# mergin into the first object, it merges into the last object.
# This is a lot safer and better in coffeescript environments, since the
# last argument is the indented subject(focus) of configuration.
# Since the attributes of these have prevalence, this merger comes last
# in the used Ember.assign
mergeObjects = (objects..., target) ->
result = {}
Ember.assign result, objects..., target
result
window.merge_objects = mergeObjects
export default mergeObjects
+17
View File
@@ -0,0 +1,17 @@
export default Ember.Object.create
# go from string:
# 19, 21-27, 98-101
# to
# [19,21,22,23,24,25,26,27,98,99,100,101]
parse: (identifier) ->
ids = []
return ids unless identifier
String(identifier).replace(/\s/g, '').split(',').forEach (id_spec) ->
[id_start, id_end] = id_spec.split('-')
id_start = parseInt(id_start)
if id_end
range_result = [id_start..id_end]
ids = ids.concat range_result
else
ids.push id_start
ids
+12
View File
@@ -0,0 +1,12 @@
sortNumeric = (target, keys...) ->
Ember.computed.sort target, (a, b) ->
[int_a, int_b] = [parseInt(a.get(keys[0])), parseInt(b.get(keys[0]))]
if int_a > int_b
1
else if int_a < int_b
-1
else
0
export { sortNumeric }
export default sortNumeric
@@ -0,0 +1,34 @@
import Ember from 'ember'
import buildMessage from 'ember-changeset-validations/utils/validation-errors'
_isPresent = (value) ->
if (value instanceof Ember.ObjectProxy || value instanceof Ember.ArrayProxy)
return Ember._isPresent(Ember.get(value, 'content'))
Ember.isPresent(value)
_testPresence = (key, value, presence, context = {}) ->
if presence
return Ember._isPresent(value) || buildMessage(key, 'present', value, context)
else
return Ember.isBlank(value) || buildMessage(key, 'blank', value, context)
export default (opts)->
(key, value, oldValue, changes, content) =>
if typeof opts is "function"
presence = true
condition = opts
else
presence = if "presence" in opts then opts.presence else true
condition = opts.condition
# since contentn is the model we have to emulate the changes for now
condition_object = Ember.assign(content.toJSON(), changes)
if condition.call(condition_object) # perform validation when condition returns true
if presence
_isPresent(value) || buildMessage(key, 'present', value, opts)
else
isBlank(value) || buildMessage(key, 'blank', value, opts)
else
true
#return _testPresence(key, value, opts)