initial github commit
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
# EditorConfig helps developers define and maintain consistent
|
||||||
|
# coding styles between different editors and IDEs
|
||||||
|
# editorconfig.org
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.hbs]
|
||||||
|
insert_final_newline = false
|
||||||
|
|
||||||
|
[*.{diff,md}]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
/**
|
||||||
|
Ember CLI sends analytics information by default. The data is completely
|
||||||
|
anonymous, but there are times when you might want to disable this behavior.
|
||||||
|
|
||||||
|
Setting `disableAnalytics` to true will prevent any data from being sent.
|
||||||
|
*/
|
||||||
|
"disableAnalytics": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 6,
|
||||||
|
sourceType: 'module'
|
||||||
|
},
|
||||||
|
extends: 'eslint:recommended',
|
||||||
|
env: {
|
||||||
|
browser: true
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
}
|
||||||
|
};
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/bower_components
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage/*
|
||||||
|
/libpeerconnection.log
|
||||||
|
/addon/**/*.js
|
||||||
|
npm-debug.log*
|
||||||
|
testem.log
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
/bower_components
|
||||||
|
/config/ember-try.js
|
||||||
|
/dist
|
||||||
|
/tests
|
||||||
|
/tmp
|
||||||
|
**/.gitkeep
|
||||||
|
.bowerrc
|
||||||
|
.editorconfig
|
||||||
|
.ember-cli
|
||||||
|
.gitignore
|
||||||
|
.eslintrc.js
|
||||||
|
.watchmanconfig
|
||||||
|
.travis.yml
|
||||||
|
bower.json
|
||||||
|
ember-cli-build.js
|
||||||
|
testem.js
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "6"
|
||||||
|
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.npm
|
||||||
|
- $HOME/.cache # includes bowers cache
|
||||||
|
|
||||||
|
env:
|
||||||
|
# we recommend testing LTS's and latest stable release (bonus points to beta/canary)
|
||||||
|
- EMBER_TRY_SCENARIO=ember-lts-2.4
|
||||||
|
- EMBER_TRY_SCENARIO=ember-lts-2.8
|
||||||
|
- EMBER_TRY_SCENARIO=ember-release
|
||||||
|
- EMBER_TRY_SCENARIO=ember-beta
|
||||||
|
- EMBER_TRY_SCENARIO=ember-canary
|
||||||
|
- EMBER_TRY_SCENARIO=ember-default
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
allow_failures:
|
||||||
|
- env: EMBER_TRY_SCENARIO=ember-canary
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- npm config set spin false
|
||||||
|
- npm install -g bower phantomjs-prebuilt
|
||||||
|
- bower --version
|
||||||
|
- phantomjs --version
|
||||||
|
|
||||||
|
install:
|
||||||
|
- npm install
|
||||||
|
- bower install
|
||||||
|
|
||||||
|
script:
|
||||||
|
# Usually, it's ok to finish the test scenario without reverting
|
||||||
|
# to the addon's original dependency state, skipping "cleanup".
|
||||||
|
- node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO test --skip-cleanup
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"ignore_dirs": ["tmp", "dist"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2017
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# ember-cli-dunlop
|
||||||
|
|
||||||
|
## Almost expected dependencies
|
||||||
|
One of the awesome powers of this support package is it's strong opinionated approach to
|
||||||
|
buildinng applications. This will result in a system of consistent
|
||||||
|
working applications having a similar experience and layout. This will
|
||||||
|
hugely simplify maintenance and rolling out improvements.
|
||||||
|
|
||||||
|
The downside can be to implement applications that do not fit inside
|
||||||
|
this opinionated model. Consider not to use this package in that case.
|
||||||
|
|
||||||
|
* ember-cli-coffeescript
|
||||||
|
* ember-cli-emblem
|
||||||
|
* ember-changeset-validations
|
||||||
|
* ember-one-way-controls
|
||||||
|
* ember-cpm
|
||||||
|
* ember-simple-auth
|
||||||
|
* ember-truth-helpers
|
||||||
|
* ember-composable-helpers
|
||||||
|
* semantic-ui-ember
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
* `git clone <repository-url>` this repository
|
||||||
|
* `cd ember-cli-dunlop`
|
||||||
|
* `npm install`
|
||||||
|
* `bower install`
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
* `ember serve`
|
||||||
|
* Visit your app at [http://localhost:4200](http://localhost:4200).
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
* `npm test` (Runs `ember try:each` to test your addon against multiple Ember versions)
|
||||||
|
* `ember test`
|
||||||
|
* `ember test --server`
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
* `ember build`
|
||||||
|
|
||||||
|
For more information on using ember-cli, visit [https://ember-cli.com/](https://ember-cli.com/).
|
||||||
@@ -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
|
||||||
@@ -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')
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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}"
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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)
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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'
|
||||||
@@ -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'
|
||||||
@@ -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: -> [])
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
export default Ember.Controller.reopen
|
||||||
|
modal: (name, options={})->
|
||||||
|
@send "openModal", name, options
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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()
|
||||||
@@ -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: ' ]'
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
.page-title
|
||||||
|
&.ui.header
|
||||||
|
margin-top: 12px
|
||||||
|
.between-brackets
|
||||||
|
&:before
|
||||||
|
margin-left: 1rem
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import './freeze-moment'
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
@@ -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')
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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)
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import ApplicationAdapter from './application'
|
||||||
|
import config from 'ember-get-config'
|
||||||
|
|
||||||
|
export default ApplicationAdapter.extend
|
||||||
|
urlForQueryRecord: (query) ->
|
||||||
|
if query.me
|
||||||
|
delete query.me
|
||||||
|
return config.userMeEndpoint || "#{config.apiHost}#{config.rootURL}users/me"
|
||||||
|
@_super arguments...
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import Base from 'ember-simple-auth/authenticators/devise'
|
||||||
|
import config from 'ember-get-config'
|
||||||
|
|
||||||
|
export default Base.extend
|
||||||
|
serverTokenEndpoint: config.serverTokenEndpoint || "#{config.apiHost}/users/sign_in"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import Devise from 'ember-simple-auth/authorizers/devise'
|
||||||
|
|
||||||
|
export default Devise.extend {}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from 'ember-cli-dunlop/components/collapsible-content';
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
classNames: ['section']
|
||||||
|
active: false
|
||||||
|
isFirst: false
|
||||||
|
classNameBindings: ['active']
|
||||||
|
didInsertElement: ->
|
||||||
|
@_super arguments...
|
||||||
|
Ember.run.scheduleOnce 'afterRender', => @get('register')(this)
|
||||||
|
|
||||||
|
willDestroyElement: ->
|
||||||
|
@get('unregister')(this)
|
||||||
|
@_super arguments...
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
css_type: 'semantic'
|
||||||
|
classNameBindings: ['css_type_classes']
|
||||||
|
css_type_classes: Ember.computed 'css_type', ->
|
||||||
|
switch @get('css_type')
|
||||||
|
when 'semantic' then 'dunlop-breadcrumbs ui container bottom attached block header'
|
||||||
|
else 'dunlop-breadcrumbs'
|
||||||
|
|
||||||
|
items: Ember.computed -> Ember.A([]) # emberx-select example
|
||||||
|
|
||||||
|
actions:
|
||||||
|
registerItem: (item) ->
|
||||||
|
item.set('isFirst', true) unless @get('items.length')
|
||||||
|
@get('items').push(item)
|
||||||
|
|
||||||
|
unregisterItem: (item) ->
|
||||||
|
@get('items').removeObject(item)
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from 'ember-cli-dunlop/components/editable-attribute';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from 'ember-cli-dunlop/components/error-handling'
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
#layoutName: 'components/flash-message'
|
||||||
|
classNames: ['flash-message']
|
||||||
|
classNameBindings: ['message:active']
|
||||||
|
message: Ember.computed.alias 'globals.flash_message'
|
||||||
|
click: -> @set 'globals.flash_message', ''
|
||||||
|
inactivator: Ember.observer 'message', ->
|
||||||
|
if @get('message')
|
||||||
|
Ember.run.later((=> @set 'globals.flash_message', ''), 4000)
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
#import config from '../config/environment'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
session: Ember.inject.service('session')
|
||||||
|
identification: ''
|
||||||
|
password: ''
|
||||||
|
actions:
|
||||||
|
submitLogin: ->
|
||||||
|
unless email=@get('identification')
|
||||||
|
return @$('.login-email').focus()
|
||||||
|
unless password=@get('password')
|
||||||
|
return @$('.login-password').focus()
|
||||||
|
|
||||||
|
## STRATEGY 1 HARD TOKEN FROM API
|
||||||
|
#uri = "#{config.apiHost}/#{config.apiNamespace}/users/obtain_token"
|
||||||
|
#Ember.$.post uri, email: email, password: password, (result) =>
|
||||||
|
# result = JSON.parse(result) if typeof result is 'string'
|
||||||
|
# unless result.valid
|
||||||
|
# @set 'globals.flash_message', 'Invalid login'
|
||||||
|
# return false
|
||||||
|
# localStorage.setItem 'authentication_token', result.authentication_token
|
||||||
|
# localStorage.setItem 'user_id', result.user_id
|
||||||
|
# @get('router').transitionTo('index').then (index_route) ->
|
||||||
|
# # do not set on globals of current route, since that one will be 'destroyed' in trasition
|
||||||
|
# index_route.store.findRecord('user', result.user_id).then (current_user) -> index_route.set('router.globals.current_user', current_user)
|
||||||
|
|
||||||
|
## STRATEGY 2 DEVISE SESSION BASED
|
||||||
|
#uri = "#{config.apiHost}/users/sign_in.json"
|
||||||
|
#Ember.$.post uri, email: email, password: password, (result) =>
|
||||||
|
# debugger
|
||||||
|
#.fail (error) =>
|
||||||
|
# # if error.status is 401
|
||||||
|
# @set 'globals.flash_message', 'Invalid login'
|
||||||
|
|
||||||
|
# STRATEGY 2 DEVISE EMBER SIMPLE AUTH BASED
|
||||||
|
@get('session').authenticate('authenticator:devise', email, password).catch (reason) =>
|
||||||
|
message = if typeof(reason) is 'string' then reason else reason.error
|
||||||
|
message ||= reason.message
|
||||||
|
message ||= 'Invalid login'
|
||||||
|
@set 'globals.flash_message', message
|
||||||
|
false
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import BaseModal from 'ember-cli-dunlop/mixins/modal-base'
|
||||||
|
|
||||||
|
export default BaseModal.extend
|
||||||
|
dunlop_base: true
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from 'ember-cli-dunlop/components/number-input';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
import Addon from 'ember-cli-dunlop/components/page-title'
|
||||||
|
export default Addon
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from 'ember-cli-dunlop/components/pagination-progress';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from 'ember-cli-dunlop/components/push-action';
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
#filter_calls: 0
|
||||||
|
tagName: 'tr'
|
||||||
|
classNames: ['table-filters-row', 'ui', 'form']
|
||||||
|
filters: Ember.Object.create()
|
||||||
|
content: null # PagedRemoteArray from ember-cli-pagination
|
||||||
|
key: 'name_eq'
|
||||||
|
apply_filters: null # allow custom apply filters with application logic
|
||||||
|
|
||||||
|
init: ->
|
||||||
|
@_super arguments...
|
||||||
|
Ember.defineProperty @, 'filter_calls', Ember.computed.alias("filters.filter_calls")
|
||||||
|
|
||||||
|
actions:
|
||||||
|
apply_filters: ->
|
||||||
|
query = @get('filters')?.toProperties() || {}
|
||||||
|
if @get('apply_filters')
|
||||||
|
@get('apply_filters')(query)
|
||||||
|
else # use standard implementation
|
||||||
|
filter_calls = @incrementProperty('filter_calls')
|
||||||
|
console.log "QUERY"
|
||||||
|
console.log query
|
||||||
|
@set 'content.page', 1
|
||||||
|
@set 'content.lastPage', null
|
||||||
|
@get('content').setOtherParam?('q', query)
|
||||||
|
clear_filters: ->
|
||||||
|
@set 'filters', Ember.Object.create()
|
||||||
|
@send 'apply_filters'
|
||||||
|
@set 'filter_calls', 0
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
tagName: 'th'
|
||||||
|
classNames: ['actions']
|
||||||
|
apply_filters: ->
|
||||||
|
clear_filters: ->
|
||||||
|
|
||||||
|
actions:
|
||||||
|
apply_filters: ->
|
||||||
|
@get('apply_filters')(@)
|
||||||
|
clear_filters: ->
|
||||||
|
@get('clear_filters')(@)
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
tagName: 'th'
|
||||||
|
classNames: ['filter', 'filter-date-range']
|
||||||
|
classNameBindings: ['has_active_filter_value:active-filter']
|
||||||
|
expandingTime: false
|
||||||
|
weekSelector: false
|
||||||
|
placeholder: '-/-'
|
||||||
|
format: 'll'
|
||||||
|
apply_filters: ->
|
||||||
|
eager_filter: true # filter on enter
|
||||||
|
week_selector_week: ''
|
||||||
|
week_selector_year: String(new Date().getFullYear())
|
||||||
|
has_active_filter_value: Ember.computed.or 'lower_bound', 'upper_bound'
|
||||||
|
target_date_filter_text: Ember.computed '{lower_bound,upper_bound}', ->
|
||||||
|
format = @get('format')
|
||||||
|
if gteq = @get('lower_bound')
|
||||||
|
gteq = gteq.format(format)
|
||||||
|
else
|
||||||
|
gteq = '-'
|
||||||
|
if lteq = @get('upper_bound')
|
||||||
|
lteq = lteq.format(format)
|
||||||
|
else
|
||||||
|
lteq = '-'
|
||||||
|
"#{gteq} / #{lteq}"
|
||||||
|
|
||||||
|
|
||||||
|
has_valid_week_selector_value: Ember.computed '{week_selector_week,week_selector_year}', ->
|
||||||
|
return false unless week = @get('week_selector_week')
|
||||||
|
week = parseInt(week)
|
||||||
|
return false unless Number.isFinite(week)
|
||||||
|
return false unless week < 54
|
||||||
|
return false unless year = String(@get('week_selector_year'))
|
||||||
|
return false unless year.length is 4
|
||||||
|
true
|
||||||
|
|
||||||
|
init: ->
|
||||||
|
@_super()
|
||||||
|
Ember.defineProperty @, 'lower_bound', Ember.computed.alias("filters.#{@get('key')}_gteq")
|
||||||
|
Ember.defineProperty @, 'upper_bound', Ember.computed.alias("filters.#{@get('key')}_lteq")
|
||||||
|
|
||||||
|
actions:
|
||||||
|
set_filter: (key, value) ->
|
||||||
|
@set key, value
|
||||||
|
@$('.dropdown').dropdown('hide') if key is 'upper_bound'
|
||||||
|
@get('apply_filters')(@) if @get('eager_filter')
|
||||||
|
clear_filters: ->
|
||||||
|
@set 'lower_bound', ''
|
||||||
|
@set 'upper_bound', ''
|
||||||
|
@$('.dropdown').dropdown('hide')
|
||||||
|
@get('apply_filters')(@) if @get('eager_filter')
|
||||||
|
|
||||||
|
set_filter_today: ->
|
||||||
|
today = moment()
|
||||||
|
@setProperties
|
||||||
|
lower_bound: today
|
||||||
|
upper_bound: today
|
||||||
|
@get('apply_filters')(@)
|
||||||
|
@$('.dropdown').dropdown('hide')
|
||||||
|
|
||||||
|
set_filter_this_week: ->
|
||||||
|
today = moment()
|
||||||
|
@setProperties
|
||||||
|
lower_bound: today.clone().startOf('isoWeek')
|
||||||
|
upper_bound: today.endOf('isoWeek')
|
||||||
|
@get('apply_filters')(@)
|
||||||
|
@$('.dropdown').dropdown('hide')
|
||||||
|
|
||||||
|
set_filter_this_month: ->
|
||||||
|
today = moment()
|
||||||
|
@setProperties
|
||||||
|
lower_bound: today.clone().startOf('month')
|
||||||
|
upper_bound: today.endOf('month')
|
||||||
|
@get('apply_filters')(@)
|
||||||
|
@$('.dropdown').dropdown('hide')
|
||||||
|
|
||||||
|
week_selector_activate: ->
|
||||||
|
return unless week = @get('week_selector_week')
|
||||||
|
week = parseInt(week)
|
||||||
|
return unless Number.isFinite(week)
|
||||||
|
return unless week < 54
|
||||||
|
return unless year = String(@get('week_selector_year'))
|
||||||
|
return unless year.match /^\d+$/
|
||||||
|
week_start = moment(year).add(week, 'weeks').startOf('isoWeek')
|
||||||
|
@setProperties
|
||||||
|
lower_bound: week_start
|
||||||
|
upper_bound: week_start.clone().endOf('isoWeek')
|
||||||
|
@get('apply_filters')(@)
|
||||||
|
@$('.dropdown').dropdown('hide')
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
placeholder: '-'
|
||||||
|
eager_filter: true # filter on enter
|
||||||
|
has_active_filter_value: Ember.computed.bool 'value'
|
||||||
|
|
||||||
|
init: ->
|
||||||
|
@_super()
|
||||||
|
Ember.defineProperty @, 'value', Ember.computed.alias("filters.#{@get('key')}")
|
||||||
|
|
||||||
|
actions:
|
||||||
|
select_date: (date) ->
|
||||||
|
@set "filters.#{@get('key')}", date?.toISOString()
|
||||||
|
@get('apply_filters')(@) if @get('eager_filter')
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
{get} = Ember
|
||||||
|
export default Ember.Component.extend
|
||||||
|
tagName: 'th'
|
||||||
|
classNames: ['filter', 'filter-dropdown-select-multiple']
|
||||||
|
classNameBindings: ['has_active_filter_value:active-filter', 'key']
|
||||||
|
apply_filters: ->
|
||||||
|
eager_filter: false # filter on single select
|
||||||
|
has_active_filter_value: Ember.computed.bool 'selected.length'
|
||||||
|
search_string: ''
|
||||||
|
search_placeholder: 'Search...' #.htmlSafe()
|
||||||
|
filtered_options: Ember.computed 'options.length', 'search_string', ->
|
||||||
|
return @get('options') unless @get('search_string.length') > 1
|
||||||
|
filtered_options = []
|
||||||
|
tester = new RegExp(@get('search_string'), 'im')
|
||||||
|
@get('options').forEach (option) =>
|
||||||
|
value = if @get('labelPath') then get(option, @get('labelPath')) else option
|
||||||
|
filtered_options.push option if tester.test value
|
||||||
|
filtered_options
|
||||||
|
|
||||||
|
options: []
|
||||||
|
labelPath: '' # if set, indicating an object select
|
||||||
|
valuePath: 'id'
|
||||||
|
selected: []
|
||||||
|
selected_popup_content: Ember.computed 'selected.length', ->
|
||||||
|
return '' unless @get('selected.length')
|
||||||
|
if labelPath = @get('labelPath')
|
||||||
|
result_html = ''
|
||||||
|
@get('options').forEach (option) =>
|
||||||
|
if get(option, @get('valuePath')) in @get('selected')
|
||||||
|
result_html += '<br><hr>' if result_html
|
||||||
|
result_html += get(option, labelPath)
|
||||||
|
result_html
|
||||||
|
else
|
||||||
|
@get('selected').join('<br><hr>')
|
||||||
|
selected_display: Ember.computed 'selected.length', ->
|
||||||
|
if count = @get('selected.length')
|
||||||
|
return '1 item' if count is 1
|
||||||
|
"#{count} items"
|
||||||
|
else
|
||||||
|
'<i class="filter icon"></i>'.htmlSafe()
|
||||||
|
|
||||||
|
init: ->
|
||||||
|
@_super()
|
||||||
|
Ember.defineProperty @, 'selected', Ember.computed.alias("filters.#{@get('key')}")
|
||||||
|
|
||||||
|
actions:
|
||||||
|
apply_filters: ->
|
||||||
|
@$('.dropdown').dropdown('hide')
|
||||||
|
@get('apply_filters')(@)
|
||||||
|
toggle_filter: (option, checked) ->
|
||||||
|
value = if @get('labelPath') then get(option, @get('valuePath')) else option
|
||||||
|
if checked
|
||||||
|
@get('selected').pushObject value
|
||||||
|
else
|
||||||
|
@get('selected').removeObject value
|
||||||
|
@apply_filters() if @get('eager_filter')
|
||||||
|
clear_filter: ->
|
||||||
|
@set 'selected', []
|
||||||
|
@get('apply_filters')(@) # if @get('eager_filter') on clear always reload!
|
||||||
|
@apply_filters()
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
{get} = Ember
|
||||||
|
export default Ember.Component.extend
|
||||||
|
tagName: 'th'
|
||||||
|
classNames: ['filter', 'filter-input']
|
||||||
|
classNameBindings: ['has_active_filter_value:active-filter', 'key']
|
||||||
|
apply_filters: ->
|
||||||
|
eager_filter: true # filter on enter
|
||||||
|
has_active_filter_value: Ember.computed.bool 'selected'
|
||||||
|
options: []
|
||||||
|
labelPath: '' # if set, indicating an object select
|
||||||
|
translationPath: '' # if set indicating a flat select requiring translated values
|
||||||
|
valuePath: 'id'
|
||||||
|
selected: null
|
||||||
|
selected_display: Ember.computed 'selected', ->
|
||||||
|
if selected = @get('selected')
|
||||||
|
if labelPath = @get('labelPath')
|
||||||
|
if obj = @get('options').findBy(@get('valuePath'), selected)
|
||||||
|
get(obj, labelPath)
|
||||||
|
else
|
||||||
|
selected
|
||||||
|
else if translationPath = @get('translationPath')
|
||||||
|
t selected, scope: translationPath, default: selected
|
||||||
|
else
|
||||||
|
selected
|
||||||
|
else
|
||||||
|
'<i class="filter icon"></i>'.htmlSafe()
|
||||||
|
|
||||||
|
init: ->
|
||||||
|
@_super()
|
||||||
|
Ember.defineProperty @, 'selected', Ember.computed.alias("filters.#{@get('key')}")
|
||||||
|
|
||||||
|
actions:
|
||||||
|
set_filter: (value) ->
|
||||||
|
if @get('labelPath')
|
||||||
|
@set 'selected', get(value, @get('valuePath'))
|
||||||
|
else
|
||||||
|
@set 'selected', value
|
||||||
|
@$('.dropdown').dropdown('hide')
|
||||||
|
@get('apply_filters')(@) if @get('eager_filter')
|
||||||
|
clear_filter: ->
|
||||||
|
@set 'selected', ''
|
||||||
|
@get('apply_filters')(@) if @get('eager_filter')
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
tagName: 'th'
|
||||||
|
classNames: ['filter', 'filter-input']
|
||||||
|
classNameBindings: ['has_active_filter_value:active-filter']
|
||||||
|
value: '' # defined on init
|
||||||
|
apply_filters: ->
|
||||||
|
eager_filter: true # filter on enter
|
||||||
|
has_active_filter_value: Ember.computed.bool 'value'
|
||||||
|
key: 'name_eq'
|
||||||
|
placeholder: ''
|
||||||
|
showSearchIcon: false # default false, too crowded ui if all fields have this icon
|
||||||
|
|
||||||
|
smart_placeholder: Ember.computed 'key', 'placeholder', ->
|
||||||
|
return @get('placeholder') if @get('placeholder') # can be set from template
|
||||||
|
return '' unless key = @get('key')
|
||||||
|
switch
|
||||||
|
when /_cont$/.test key then '~'
|
||||||
|
when /_eq$/.test key then '=='
|
||||||
|
when /_gt$/.test key then '>'
|
||||||
|
when /_gteq$/.test key then '>='
|
||||||
|
when /_lt$/.test key then '<'
|
||||||
|
when /_lteq$/.test key then '<='
|
||||||
|
when /_matches$/.test key then '%~%'
|
||||||
|
when /_end$/.test key then '%--'
|
||||||
|
when /_start/.test key then '--%'
|
||||||
|
else ''
|
||||||
|
|
||||||
|
init: ->
|
||||||
|
@_super()
|
||||||
|
Ember.defineProperty @, 'value', Ember.computed.alias("filters.#{@get('key')}")
|
||||||
|
|
||||||
|
actions:
|
||||||
|
enterPressed: ->
|
||||||
|
return unless @get('eager_filter')
|
||||||
|
@get('apply_filters')(@) if @get('eager_filter')
|
||||||
|
clear_query: ->
|
||||||
|
@set 'value', ''
|
||||||
|
@get('apply_filters')(@) if @get('eager_filter')
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
tagName: 'th'
|
||||||
|
classNames: ['filter', 'filter-number-range']
|
||||||
|
classNameBindings: ['has_active_filter_value:active-filter']
|
||||||
|
placeholder: '-/-'
|
||||||
|
display_addition: '' # allow extra display value on cell. Year for example when number-range is weeks
|
||||||
|
apply_filters: ->
|
||||||
|
eager_filter: true # filter on enter
|
||||||
|
has_active_filter_value: Ember.computed.or 'lower_bound', 'upper_bound'
|
||||||
|
lower_bound_candidate: ''
|
||||||
|
upper_bound_candidate: ''
|
||||||
|
filter_text: Ember.computed '{lower_bound,upper_bound,display_addition}', ->
|
||||||
|
gteq = @get('lower_bound') || '-'
|
||||||
|
lteq = @get('upper_bound') || '-'
|
||||||
|
range = "#{gteq} / #{lteq}"
|
||||||
|
range += " #{@get('display_addition')}" if @get('display_addition')
|
||||||
|
range
|
||||||
|
|
||||||
|
|
||||||
|
init: ->
|
||||||
|
@_super()
|
||||||
|
Ember.defineProperty @, 'lower_bound', Ember.computed.alias("filters.#{@get('key')}_gteq")
|
||||||
|
Ember.defineProperty @, 'upper_bound', Ember.computed.alias("filters.#{@get('key')}_lteq")
|
||||||
|
@set 'lower_bound_candidate', @get('lower_bound')
|
||||||
|
@set 'upper_bound_candidate', @get('upper_bound')
|
||||||
|
|
||||||
|
actions:
|
||||||
|
set_filter: (key, value) ->
|
||||||
|
#@set key, value
|
||||||
|
@set 'lower_bound', parseInt(@get('lower_bound_candidate')) || ''
|
||||||
|
@set 'upper_bound', parseInt(@get('upper_bound_candidate')) || ''
|
||||||
|
@$('.dropdown').dropdown('hide')
|
||||||
|
@get('apply_filters')(@) if @get('eager_filter')
|
||||||
|
clear_filters: ->
|
||||||
|
@set 'lower_bound', ''
|
||||||
|
@set 'upper_bound', ''
|
||||||
|
@set 'lower_bound_candidate', ''
|
||||||
|
@set 'upper_bound_candidate', ''
|
||||||
|
@get('apply_filters')(@) if @get('eager_filter')
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
tagName: 'th'
|
||||||
|
classNames: ['filter', 'filter-input']
|
||||||
|
classNameBindings: ['has_active_filter_value:active-filter', 'key']
|
||||||
|
apply_filters: ->
|
||||||
|
eager_filter: true # filter on enter
|
||||||
|
has_active_filter_value: Ember.computed.bool 'selected'
|
||||||
|
options: []
|
||||||
|
selected: null
|
||||||
|
|
||||||
|
init: ->
|
||||||
|
@_super()
|
||||||
|
Ember.defineProperty @, 'selected', Ember.computed.alias("filters.#{@get('key')}")
|
||||||
|
|
||||||
|
actions:
|
||||||
|
set_filter: (value) ->
|
||||||
|
@set 'selected', value
|
||||||
|
@get('apply_filters')(@) if @get('eager_filter')
|
||||||
|
clear_filter: ->
|
||||||
|
@set 'selected', ''
|
||||||
|
@get('apply_filters')(@) if @get('eager_filter')
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
import BaseModal from 'ember-cli-dunlop/components/modals/base'
|
||||||
|
export default BaseModal.extend
|
||||||
|
current_selected: Ember.computed.alias 'modal_options.base.value'
|
||||||
|
options: Ember.computed.alias 'modal_options.base.options'
|
||||||
|
valueKey: Ember.computed.alias 'modal_options.base.valueKey'
|
||||||
|
textKey: Ember.computed.alias 'modal_options.base.textKey'
|
||||||
|
eager_filter: Ember.computed.alias 'modal_options.base.eager_filter'
|
||||||
|
apply_filters: Ember.computed.alias 'modal_options.base.apply_filters'
|
||||||
|
options_map: {}
|
||||||
|
|
||||||
|
willOpenModal: ->
|
||||||
|
options_map = Ember.Object.create()
|
||||||
|
valueKey = @get('valueKey')
|
||||||
|
current_selected = @get('current_selected') || []
|
||||||
|
@get('options').forEach (option) ->
|
||||||
|
value_name = if valueKey then Ember.get(option, valueKey) else option
|
||||||
|
options_map.set value_name, current_selected.includes(value_name)
|
||||||
|
@set 'options_map', options_map
|
||||||
|
|
||||||
|
|
||||||
|
actions:
|
||||||
|
update_selection: ->
|
||||||
|
valueKey = @get('valueKey')
|
||||||
|
selected_options = @get('options').filter (option) =>
|
||||||
|
value_name = if valueKey then Ember.get(option, valueKey) else option
|
||||||
|
@get "options_map.#{value_name}"
|
||||||
|
if valueKey
|
||||||
|
selected_options = selected_options.mapBy valueKey
|
||||||
|
@set 'current_selected', selected_options
|
||||||
|
@get('apply_filters')(@) if @get('eager_filter')
|
||||||
|
@send 'close'
|
||||||
|
|
||||||
|
toggle_selection: (option)->
|
||||||
|
value_name = if @get('valueKey') then Ember.get(option, @get('valueKey')) else option
|
||||||
|
@toggleProperty "options_map.#{value_name}"
|
||||||
|
|
||||||
|
select_all: ->
|
||||||
|
Object.keys(@get('options_map')).forEach (value_name) =>
|
||||||
|
@set "options_map.#{value_name}", true
|
||||||
|
|
||||||
|
select_none: ->
|
||||||
|
Object.keys(@get('options_map')).forEach (value_name) =>
|
||||||
|
@set "options_map.#{value_name}", false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
tagName: 'th'
|
||||||
|
textKey: 'name'
|
||||||
|
classNames: ['filter', 'filter-select-multiple']
|
||||||
|
classNameBindings: ['has_active_filter_values:active-filter']
|
||||||
|
valueKey: null # assumed flat array
|
||||||
|
value: []
|
||||||
|
options: []
|
||||||
|
key: 'name_in' # ransack key
|
||||||
|
eager_filter: true # filter on enter
|
||||||
|
apply_filters: ->
|
||||||
|
has_active_filter_values: Ember.computed.bool 'value.length'
|
||||||
|
|
||||||
|
selectedTitle: Ember.computed 'value.length', ->
|
||||||
|
return '--' unless @get('value.length')
|
||||||
|
@get('value').join(",\n")
|
||||||
|
|
||||||
|
selectedDisplay: Ember.computed 'value.length', ->
|
||||||
|
return '' unless @get('value.length')
|
||||||
|
if @get('value.length') is 1
|
||||||
|
value = @get("value.firstObject")
|
||||||
|
if valueKey = @get('valueKey')
|
||||||
|
option = @get('options').findBy(valueKey, value)
|
||||||
|
Ember.get(option, @get('textKey'))
|
||||||
|
else
|
||||||
|
value
|
||||||
|
else
|
||||||
|
@get('value.length')
|
||||||
|
|
||||||
|
init: ->
|
||||||
|
@_super(arguments...)
|
||||||
|
Ember.defineProperty @, 'value', Ember.computed.alias("filters.#{@get('key')}")
|
||||||
|
|
||||||
|
actions:
|
||||||
|
edit_selection: ->
|
||||||
|
@modal 'table-filters/select-multiple-modal',
|
||||||
|
title: "Select options"
|
||||||
|
base: @
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from 'ember-cli-dunlop/components/ui-calendar-moment';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from 'ember-cli-dunlop/components/ui-markdown-popup';
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import Ember from 'ember'
|
||||||
|
|
||||||
|
export default Ember.Component.extend
|
||||||
|
classNameBindings: ['hasError:error', 'containerClass']
|
||||||
|
classNames: ['field']
|
||||||
|
disabled: false
|
||||||
|
error_text: 'Please set...'
|
||||||
|
|
||||||
|
containerClass: Ember.computed 'attribute', ->
|
||||||
|
return 'validated-attribute' unless record = @get('changeset._content')
|
||||||
|
record_name = record.constructor.modelName || 'record'
|
||||||
|
"validated-attribute-#{record_name}-#{Ember.String.dasherize(@get('attribute'))}".replace(/[\W_]/g, '-')
|
||||||
|
|
||||||
|
init: ->
|
||||||
|
@_super()
|
||||||
|
Ember.defineProperty(@, "hasError", Ember.computed.bool("changeset.error.#{@get("attribute")}"))
|
||||||
|
|
||||||
|
actions:
|
||||||
|
validateAttribute: (changeset, attribute) ->
|
||||||
|
changeset.validate(attribute)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user