houston-core 0.8.4 → 0.9.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +72 -78
- data/app/assets/javascripts/houston/app/models/role.coffee +4 -0
- data/app/assets/javascripts/houston/app/views/nested_resources.coffee +44 -0
- data/app/assets/javascripts/houston/app/views/team_roles_view.coffee +10 -0
- data/app/assets/javascripts/houston/application.js +3 -1
- data/app/assets/javascripts/houston/core/ajax_helpers.coffee +26 -0
- data/app/assets/javascripts/houston/core/app.coffee +0 -45
- data/app/assets/javascripts/houston/core/errors.coffee +1 -12
- data/app/assets/javascripts/houston/core/handlebars_helpers.coffee +8 -70
- data/app/assets/javascripts/houston/core/jquery_extensions.coffee +0 -138
- data/app/assets/javascripts/houston/core/timeline_helpers.coffee +44 -0
- data/app/assets/javascripts/houston/core/uploader_helpers.coffee +99 -0
- data/app/assets/javascripts/houston/vendor.js +26 -9
- data/app/assets/stylesheets/houston/application/actions.scss +22 -0
- data/app/assets/stylesheets/houston/application/navigation.scss +2 -2
- data/app/assets/stylesheets/houston/application/{freight_train.css.scss → nested_resources.scss} +1 -0
- data/app/assets/stylesheets/houston/core/alerts.scss +0 -4
- data/app/assets/stylesheets/houston/core/timeline.scss +204 -0
- data/app/assets/templates/houston/teams/roles/index.hbs +1 -0
- data/app/assets/templates/houston/teams/roles/show.hbs +19 -0
- data/app/channels/events_channel.rb +1 -1
- data/app/concerns/houston/props.rb +3 -2
- data/app/controllers/actions_controller.rb +8 -3
- data/app/controllers/application_controller.rb +9 -12
- data/app/controllers/authorizations_controller.rb +41 -14
- data/app/controllers/errors_controller.rb +3 -3
- data/app/controllers/project_follows_controller.rb +23 -0
- data/app/controllers/project_options_controller.rb +1 -1
- data/app/controllers/user_options_controller.rb +1 -1
- data/app/helpers/actions_helper.rb +12 -0
- data/app/helpers/application_helper.rb +0 -10
- data/app/helpers/layout_helper.rb +20 -0
- data/app/helpers/markdown_helper.rb +2 -10
- data/app/helpers/navigation_helper.rb +5 -5
- data/app/helpers/project_helper.rb +6 -0
- data/app/helpers/url_helper.rb +4 -4
- data/app/helpers/view_extensions_helper.rb +20 -0
- data/app/models/action.rb +61 -44
- data/app/models/authorization.rb +55 -10
- data/app/models/follow.rb +6 -0
- data/app/models/persistent_trigger.rb +11 -1
- data/app/models/project.rb +5 -27
- data/app/models/user.rb +15 -59
- data/app/presenters/project_presenter.rb +2 -2
- data/app/views/actions/_actions.html.erb +8 -5
- data/app/views/actions/index.html.erb +1 -1
- data/app/views/actions/running.html.erb +9 -15
- data/app/views/actions/show.html.erb +6 -3
- data/app/views/actions/unqueued.html.erb +41 -0
- data/app/views/authorizations/_form.html.erb +28 -16
- data/app/views/authorizations/index.html.erb +9 -4
- data/app/views/{oauth/providers/edit.html.erb → authorizations/oauth2_callback.html.erb} +3 -2
- data/app/views/devise/sessions/new.html.erb +0 -8
- data/app/views/errors/index.html.erb +9 -5
- data/app/views/layouts/_navigation.html.erb +9 -0
- data/app/views/layouts/application.html.erb +11 -6
- data/app/views/layouts/dashboard.html.erb +9 -0
- data/app/views/projects/_form.html.erb +7 -18
- data/app/views/projects/_header.html.erb +2 -6
- data/app/views/projects/index.html.erb +4 -4
- data/app/views/teams/_form.html.erb +7 -17
- data/app/views/teams/index.html.erb +1 -1
- data/app/views/users/_form.html.erb +1 -38
- data/config/application.rb +8 -5
- data/config/initializers/devise.rb +0 -14
- data/config/initializers/secret_token.rb +8 -13
- data/config/routes.rb +12 -28
- data/db/migrate/20130706141443_drop_deprecated_project_roles.rb +5 -1
- data/db/migrate/20170118005958_remove_antecedents_from_versions_of_tickets.rb +1 -1
- data/db/migrate/20170130011016_drop_users_environments_subscribed_to.rb +9 -0
- data/db/migrate/20170205004452_drop_settings.rb +12 -0
- data/db/migrate/20170206002030_drop_extension_hstore.rb +9 -0
- data/db/migrate/20170206002732_drop_legacy_columns_from_users.rb +10 -0
- data/db/migrate/20170209022159_rename_projects_color_to_color_name.rb +5 -0
- data/db/migrate/20170213001453_change_providers_from_models_to_extensions.rb +27 -0
- data/db/migrate/20170215012012_add_props_to_authorizations.rb +5 -0
- data/db/migrate/20170216041034_add_user_to_persistent_triggers.rb +5 -0
- data/db/migrate/20170226201504_create_follows.rb +20 -0
- data/db/migrate/20170301014051_drop_name_from_authorizations.rb +9 -0
- data/db/migrate/20170307032041_add_created_at_to_actions.rb +11 -0
- data/db/migrate/20170307035755_allow_actions_started_at_to_be_null.rb +5 -0
- data/db/migrate/20170310024505_replace_authorizations_provider_name_with_type.rb +12 -0
- data/db/migrate/20170329030329_drop_consumer_tokens.rb +9 -0
- data/db/structure.sql +187 -212
- data/houston-core.gemspec +10 -13
- data/lib/houston/boot.rb +1 -4
- data/lib/houston/boot/actions.rb +24 -21
- data/lib/houston/boot/configuration.rb +46 -113
- data/lib/houston/boot/extensions.rb +54 -341
- data/lib/houston/boot/extensions/deprecated.rb +194 -0
- data/lib/houston/boot/extensions/dsl.rb +99 -0
- data/lib/houston/boot/extensions/events.rb +81 -0
- data/lib/houston/boot/extensions/features.rb +42 -0
- data/lib/houston/boot/extensions/layout.rb +70 -0
- data/lib/houston/boot/extensions/navigation.rb +42 -0
- data/lib/houston/boot/extensions/oauth.rb +62 -0
- data/lib/houston/boot/extensions/serializers.rb +29 -0
- data/lib/houston/boot/extensions/view.rb +34 -0
- data/lib/houston/boot/observer.rb +10 -5
- data/{app/models/oauth → lib/houston/boot}/provider.rb +7 -5
- data/lib/houston/boot/running_as.rb +0 -5
- data/lib/houston/boot/serializer.rb +12 -6
- data/lib/houston/boot/{active_record_serializer.rb → serializers/active_record_serializer.rb} +0 -2
- data/lib/houston/boot/{readonly_hash_serializer.rb → serializers/readonly_hash_serializer.rb} +0 -2
- data/lib/houston/boot/timer.rb +10 -0
- data/lib/houston/boot/triggers.rb +27 -8
- data/lib/houston/version.rb +1 -1
- data/templates/new-instance/.gitignore +0 -4
- data/templates/new-instance/config/main.rb +8 -10
- data/templates/new-module/test/dummy/houston.rb +1 -0
- data/test/acceptance/layout_test.rb +58 -0
- data/test/acceptance/updating_props_test.rb +72 -0
- data/test/support/config.rb +1 -0
- data/test/unit/extensions/events_extension_test.rb +33 -0
- data/test/unit/extensions/layout_extension_test.rb +74 -0
- data/test/unit/extensions/navigation_extension_test.rb +62 -0
- data/test/unit/extensions/oauth_extension_test.rb +91 -0
- data/test/unit/extensions/project_features_extension_test.rb +79 -0
- data/test/unit/extensions/serializers_extension_test.rb +47 -0
- data/test/unit/extensions/view_extension_test.rb +98 -0
- data/test/unit/models/actions_test.rb +11 -5
- data/test/unit/models/configuration_test.rb +0 -8
- data/test/unit/models/observer_test.rb +16 -0
- data/test/unit/models/persistent_trigger_test.rb +29 -2
- data/test/unit/models/serializer_test.rb +6 -0
- data/test/unit/models/timer_test.rb +88 -0
- metadata +87 -168
- data/app/assets/font/octicons.eot +0 -0
- data/app/assets/font/octicons.svg +0 -198
- data/app/assets/font/octicons.ttf +0 -0
- data/app/assets/font/octicons.woff +0 -0
- data/app/assets/font/roboto-black-webfont.eot +0 -0
- data/app/assets/font/roboto-black-webfont.svg +0 -675
- data/app/assets/font/roboto-black-webfont.ttf +0 -0
- data/app/assets/font/roboto-black-webfont.woff +0 -0
- data/app/assets/font/roboto-blackitalic-webfont.eot +0 -0
- data/app/assets/font/roboto-blackitalic-webfont.svg +0 -677
- data/app/assets/font/roboto-blackitalic-webfont.ttf +0 -0
- data/app/assets/font/roboto-blackitalic-webfont.woff +0 -0
- data/app/assets/font/roboto-bold-webfont.eot +0 -0
- data/app/assets/font/roboto-bold-webfont.svg +0 -675
- data/app/assets/font/roboto-bold-webfont.ttf +0 -0
- data/app/assets/font/roboto-bold-webfont.woff +0 -0
- data/app/assets/font/roboto-bolditalic-webfont.eot +0 -0
- data/app/assets/font/roboto-bolditalic-webfont.svg +0 -677
- data/app/assets/font/roboto-bolditalic-webfont.ttf +0 -0
- data/app/assets/font/roboto-bolditalic-webfont.woff +0 -0
- data/app/assets/font/roboto-italic-webfont.eot +0 -0
- data/app/assets/font/roboto-italic-webfont.svg +0 -668
- data/app/assets/font/roboto-italic-webfont.ttf +0 -0
- data/app/assets/font/roboto-italic-webfont.woff +0 -0
- data/app/assets/font/roboto-light-webfont.eot +0 -0
- data/app/assets/font/roboto-light-webfont.svg +0 -666
- data/app/assets/font/roboto-light-webfont.ttf +0 -0
- data/app/assets/font/roboto-light-webfont.woff +0 -0
- data/app/assets/font/roboto-lightitalic-webfont.eot +0 -0
- data/app/assets/font/roboto-lightitalic-webfont.svg +0 -668
- data/app/assets/font/roboto-lightitalic-webfont.ttf +0 -0
- data/app/assets/font/roboto-lightitalic-webfont.woff +0 -0
- data/app/assets/font/roboto-medium-webfont.eot +0 -0
- data/app/assets/font/roboto-medium-webfont.svg +0 -675
- data/app/assets/font/roboto-medium-webfont.ttf +0 -0
- data/app/assets/font/roboto-medium-webfont.woff +0 -0
- data/app/assets/font/roboto-mediumitalic-webfont.eot +0 -0
- data/app/assets/font/roboto-mediumitalic-webfont.svg +0 -677
- data/app/assets/font/roboto-mediumitalic-webfont.ttf +0 -0
- data/app/assets/font/roboto-mediumitalic-webfont.woff +0 -0
- data/app/assets/font/roboto-regular-webfont.eot +0 -0
- data/app/assets/font/roboto-regular-webfont.svg +0 -666
- data/app/assets/font/roboto-regular-webfont.ttf +0 -0
- data/app/assets/font/roboto-regular-webfont.woff +0 -0
- data/app/assets/font/roboto-thin-webfont.eot +0 -0
- data/app/assets/font/roboto-thin-webfont.svg +0 -666
- data/app/assets/font/roboto-thin-webfont.ttf +0 -0
- data/app/assets/font/roboto-thin-webfont.woff +0 -0
- data/app/assets/font/roboto-thinitalic-webfont.eot +0 -0
- data/app/assets/font/roboto-thinitalic-webfont.svg +0 -668
- data/app/assets/font/roboto-thinitalic-webfont.ttf +0 -0
- data/app/assets/font/roboto-thinitalic-webfont.woff +0 -0
- data/app/assets/images/bug-fixed-128.png +0 -0
- data/app/assets/images/bug-fixed-32.png +0 -0
- data/app/assets/images/bug-fixed-48.png +0 -0
- data/app/assets/images/bug-new-128.png +0 -0
- data/app/assets/images/bug-new-32.png +0 -0
- data/app/assets/images/bug-new-48.png +0 -0
- data/app/assets/images/bug-open-32.png +0 -0
- data/app/assets/images/bug-zero-128.png +0 -0
- data/app/assets/images/bug-zero-48.png +0 -0
- data/app/assets/images/drag-grip.png +0 -0
- data/app/assets/javascripts/houston/core/burndown_chart.coffee +0 -111
- data/app/assets/javascripts/houston/core/stacked_area_graph.coffee +0 -113
- data/app/assets/javascripts/houston/core/stacked_bar_graph.coffee +0 -108
- data/app/assets/stylesheets/houston/application/project_tiles.scss +0 -26
- data/app/assets/stylesheets/houston/application/tips.scss +0 -5
- data/app/assets/stylesheets/houston/core/octicons-icons.scss +0 -221
- data/app/assets/stylesheets/houston/core/octicons.scss.erb +0 -9
- data/app/assets/stylesheets/houston/core/roboto.scss.erb +0 -131
- data/app/concerns/historical_weekly_stats.rb +0 -15
- data/app/concerns/nosync.rb +0 -21
- data/app/controllers/oauth/providers_controller.rb +0 -45
- data/app/controllers/project_roles_controller.rb +0 -22
- data/app/controllers/settings_controller.rb +0 -14
- data/app/controllers/tester_bar_controller.rb +0 -12
- data/app/controllers/user_credentials_controller.rb +0 -24
- data/app/models/role.rb +0 -33
- data/app/models/setting.rb +0 -10
- data/app/models/settings.rb +0 -38
- data/app/models/slackdown.rb +0 -23
- data/app/models/user_credentials.rb +0 -27
- data/app/views/errors/_actions.html.erb +0 -17
- data/app/views/layouts/_tester_bar.html.erb +0 -6
- data/app/views/layouts/minimal.html.erb +0 -50
- data/app/views/layouts/naked.html.erb +0 -47
- data/app/views/layouts/naked_dashboard.html.erb +0 -50
- data/app/views/oauth/providers/_form.html.erb +0 -54
- data/app/views/oauth/providers/index.html.erb +0 -41
- data/app/views/oauth/providers/new.html.erb +0 -7
- data/config/initializers/add_navigation_renderers.rb +0 -5
- data/config/initializers/vestal_versions.rb +0 -9
- data/db/migrate/20130519163615_create_user_credentials.rb +0 -18
- data/lib/houston/boot/events.rb +0 -10
- data/lib/tasks/keypair.rake +0 -17
- data/vendor/assets/javascripts/jquery.pjax.js +0 -817
@@ -1,18 +1,7 @@
|
|
1
1
|
class window.Errors
|
2
2
|
|
3
3
|
constructor: (response)->
|
4
|
-
|
5
|
-
if response.getResponseHeader('X-Credentials') == 'Missing Credentials'
|
6
|
-
@missingCredentials = true
|
7
|
-
else if response.getResponseHeader('X-Credentials') == 'Invalid Credentials'
|
8
|
-
@invalidCredentials = true
|
9
|
-
else if response.getResponseHeader('X-Credentials') == 'Oauth'
|
10
|
-
@oauthLocation = response.getResponseHeader('Location')
|
11
|
-
else
|
12
|
-
message = response.responseText ? "You are not authorized"
|
13
|
-
@errors = {base: [message]}
|
14
|
-
else
|
15
|
-
@errors = JSON.parse(response.responseText)
|
4
|
+
@errors = JSON.parse(response.responseText)
|
16
5
|
|
17
6
|
renderToAlert: ->
|
18
7
|
sentences = []
|
@@ -42,26 +42,6 @@ Handlebars.registerHelper 'markdown', (markdown)-> App.mdown(markdown)
|
|
42
42
|
|
43
43
|
Handlebars.registerHelper 'emojify', (string)-> App.emojify(string)
|
44
44
|
|
45
|
-
Handlebars.registerHelper 'classForAge', (seconds)->
|
46
|
-
if seconds < (6 * Duration.HOUR)
|
47
|
-
'infant'
|
48
|
-
else if seconds < (2 * Duration.DAY)
|
49
|
-
'child'
|
50
|
-
else if seconds < (7 * Duration.DAY)
|
51
|
-
'adult'
|
52
|
-
else if seconds < (4 * Duration.WEEK)
|
53
|
-
'senior'
|
54
|
-
else if seconds < (26 * Duration.WEEK)
|
55
|
-
'old'
|
56
|
-
else
|
57
|
-
'ancient'
|
58
|
-
|
59
|
-
Handlebars.registerHelper 'radioButton', (object, id, name, value, selectedValue)->
|
60
|
-
id = "#{object}_#{id}_#{name}_#{value}"
|
61
|
-
input = "<input type=\"radio\" id=\"#{id}\" name=\"#{name}\" value=\"#{value}\""
|
62
|
-
input = input + ' checked="checked"' if value == selectedValue
|
63
|
-
"#{input} />"
|
64
|
-
|
65
45
|
Handlebars.registerHelper 'userAvatar', (size)->
|
66
46
|
user = window.user
|
67
47
|
gravatarUrl = "https://www.gravatar.com/avatar/#{MD5(user.get('email').toLowerCase().trim())}?r=g&d=retro&s=#{size * 2}"
|
@@ -83,56 +63,6 @@ Handlebars.registerHelper 'ifEq', (v1, v2, block)->
|
|
83
63
|
|
84
64
|
|
85
65
|
|
86
|
-
Handlebars.registerHelper 'timelineDateRange', (lastDate, date)->
|
87
|
-
return Handlebars.helpers.timelineDate(date) unless lastDate
|
88
|
-
days = (lastDate - date) / Duration.DAY
|
89
|
-
return Handlebars.helpers.timelineDateAfterGap(date) if days >= 3
|
90
|
-
|
91
|
-
_.inject [0...days],
|
92
|
-
((html, i)-> html + Handlebars.helpers.timelineDate((i + 1).days().before(lastDate)))
|
93
|
-
, ''
|
94
|
-
|
95
|
-
Handlebars.registerHelper 'timelineDate', (date)->
|
96
|
-
format = d3.time.format """
|
97
|
-
<div class="timeline-date">
|
98
|
-
<span class="weekday">%a</span>
|
99
|
-
<span class="month">%b</span>
|
100
|
-
<span class="day">%-d</span>
|
101
|
-
<span class="year">%Y</span>
|
102
|
-
</div>
|
103
|
-
"""
|
104
|
-
format toDate(date)
|
105
|
-
|
106
|
-
Handlebars.registerHelper 'timelineTime', (time)->
|
107
|
-
format = d3.time.format('<span class="timeline-event-time">%-I:%M%p</span>')
|
108
|
-
format toDate(time)
|
109
|
-
.replace(/[AP]M/, (str)-> str.toLowerCase()[0])
|
110
|
-
|
111
|
-
Handlebars.registerHelper 'timelineDateAfterGap', (date)->
|
112
|
-
'<div class="timeline-date-gap"></div>' + Handlebars.helpers.timelineDate(date)
|
113
|
-
|
114
|
-
Handlebars.registerHelper 'timeline', (events, options)->
|
115
|
-
lastDate = null
|
116
|
-
events ?= []
|
117
|
-
if events.length > 0
|
118
|
-
html = '<div class="timeline">'
|
119
|
-
for event in events
|
120
|
-
date = App.truncateDate(toDate(event.date || event.time))
|
121
|
-
html += Handlebars.helpers.timelineDateRange(lastDate, date)
|
122
|
-
html += options.fn(event)
|
123
|
-
lastDate = date
|
124
|
-
html += '</div>'
|
125
|
-
html
|
126
|
-
|
127
|
-
Handlebars.registerHelper 'renderTaskWorker', (task)->
|
128
|
-
if task.checkedOutByMe and !task.historical and task.open
|
129
|
-
'<button class="btn btn-danger check-out-button active" data-toggle="button">Check in</button>'
|
130
|
-
else if task.checkedOutBy
|
131
|
-
Handlebars.helpers.avatar(task.checkedOutBy.email, 24, task.checkedOutBy.firstName) +
|
132
|
-
" #{task.checkedOutBy.firstName}"
|
133
|
-
else if task.open
|
134
|
-
'<button class="btn btn-info check-out-button" data-toggle="button">Check out</button>'
|
135
|
-
|
136
66
|
Handlebars.registerHelper 'coalesce', (value, valueIfBlank)->
|
137
67
|
value ? valueIfBlank
|
138
68
|
|
@@ -142,6 +72,14 @@ Handlebars.registerHelper 'ifMe', (user, block)->
|
|
142
72
|
else
|
143
73
|
block.inverse(@)
|
144
74
|
|
75
|
+
Handlebars.registerHelper 'ifEql', (value1, value2, options)->
|
76
|
+
if value1 == value2
|
77
|
+
options.fn(@)
|
78
|
+
|
79
|
+
Handlebars.registerHelper 'ifIn', (value, array, options)->
|
80
|
+
if _.contains(array, value)
|
81
|
+
options.fn(@)
|
82
|
+
|
145
83
|
Handlebars.registerHelper 'renderKeyCombos', (keys)->
|
146
84
|
_.map(keys, Handlebars.helpers.renderKeyCombo).join('<i> or </i>')
|
147
85
|
|
@@ -38,141 +38,3 @@ $.fn.extend
|
|
38
38
|
|
39
39
|
enable: ->
|
40
40
|
$(@).find('input[type="submit"], input[type="reset"], button').removeAttr('disabled').end()
|
41
|
-
|
42
|
-
getCursorPosition: ->
|
43
|
-
input = @get(0)
|
44
|
-
return unless input
|
45
|
-
if input.selectionStart # Standard-compliant browsers
|
46
|
-
input.selectionStart
|
47
|
-
else if document.selection # IE
|
48
|
-
input.focus()
|
49
|
-
sel = document.selection.createRange()
|
50
|
-
selLen = document.selection.createRange().text.length
|
51
|
-
sel.moveStart 'character', -input.value.length
|
52
|
-
sel.text.length - selLen
|
53
|
-
|
54
|
-
appendAsAlert: ->
|
55
|
-
$alerts = $('#body .alert')
|
56
|
-
$newAlert = $(@)
|
57
|
-
if $alerts.length > 0
|
58
|
-
$('#body .alert').fadeOut
|
59
|
-
complete: ->
|
60
|
-
$(@).remove()
|
61
|
-
$newAlert.prependTo($('#body')).alert()
|
62
|
-
else
|
63
|
-
$newAlert.prependTo($('#body')).alert()
|
64
|
-
|
65
|
-
putCursorAtEnd: ->
|
66
|
-
@each ->
|
67
|
-
$(@).focus()
|
68
|
-
|
69
|
-
# If this function exists...
|
70
|
-
if @setSelectionRange
|
71
|
-
# ... then use it (Doesn't work in IE)
|
72
|
-
|
73
|
-
# Double the length because Opera is inconsistent about whether a carriage return is one character or two. Sigh.
|
74
|
-
len = $(@).val().length * 2
|
75
|
-
|
76
|
-
@setSelectionRange(len, len)
|
77
|
-
else
|
78
|
-
|
79
|
-
# ... otherwise replace the contents with itself
|
80
|
-
# (Doesn't work in Google Chrome)
|
81
|
-
|
82
|
-
$(@).val($(@).val())
|
83
|
-
|
84
|
-
insertAtCursor: (text)->
|
85
|
-
textarea = @[0]
|
86
|
-
|
87
|
-
# IE support
|
88
|
-
if document.selection
|
89
|
-
textarea.focus()
|
90
|
-
sel = document.selection.createRange()
|
91
|
-
sel.text = text
|
92
|
-
|
93
|
-
# MOZILLA and others
|
94
|
-
else if textarea.selectionStart || textarea.selectionStart == '0'
|
95
|
-
startPos = textarea.selectionStart
|
96
|
-
endPos = textarea.selectionEnd
|
97
|
-
textarea.value = textarea.value.substring(0, startPos) + text + textarea.value.substring(endPos, textarea.value.length)
|
98
|
-
textarea.selectionStart = startPos + text.length
|
99
|
-
textarea.selectionEnd = startPos + text.length
|
100
|
-
|
101
|
-
else
|
102
|
-
textarea.value += text
|
103
|
-
|
104
|
-
supportImages: ->
|
105
|
-
$el = @
|
106
|
-
|
107
|
-
$el.append '''
|
108
|
-
<div class="drag-and-drop">
|
109
|
-
Attach files or images by dragging & dropping them or <a class="dz-selector">selecting them</a>.
|
110
|
-
</div>
|
111
|
-
<div class="upload-progress"></div>
|
112
|
-
<div class="upload-error"></div>
|
113
|
-
'''
|
114
|
-
|
115
|
-
bucket = App.meta('s3-bucket')
|
116
|
-
$el.dropzone
|
117
|
-
maxFilesize: 13 # MB
|
118
|
-
clickable: '.dz-selector'
|
119
|
-
acceptedFiles: '.pdf,.zip,image/jpeg,image/png,image/gif'
|
120
|
-
url: "//#{bucket}.s3.amazonaws.com"
|
121
|
-
uploadprogress: (file, progress)->
|
122
|
-
$el.find('.upload-progress').html "Uploading #{file.name} (#{progress.toFixed(0)}% complete)"
|
123
|
-
|
124
|
-
complete: ->
|
125
|
-
if @getUploadingFiles().length is 0 and @getQueuedFiles().length is 0
|
126
|
-
$el.removeClass('uploading')
|
127
|
-
|
128
|
-
error: (file, errorMessage)->
|
129
|
-
$el.addClass('error')
|
130
|
-
$el.find('.upload-error').html """
|
131
|
-
<span class="message">#{errorMessage}</span>
|
132
|
-
<a class="dz-selector">Try again</a>"
|
133
|
-
"""
|
134
|
-
|
135
|
-
sending: (file, xhr, formData)=>
|
136
|
-
$el.removeClass('error').addClass('uploading')
|
137
|
-
$el.find('.upload-progress').html "Uploading #{file.name}..."
|
138
|
-
$.ajax
|
139
|
-
url: '/uploads/policies',
|
140
|
-
data: {name: file.name, size: file.size, type: file.type},
|
141
|
-
type: 'POST',
|
142
|
-
async: false, # because we need this response before dropzone can continue
|
143
|
-
success: (params)=>
|
144
|
-
src = "https://s3.amazonaws.com/#{bucket}/#{params.key}"
|
145
|
-
link_markdown = "[#{file.name}](#{src})"
|
146
|
-
link_markdown = "!#{link_markdown}" unless _.contains(["application/pdf", "application/zip"], file.type)
|
147
|
-
@.find('textarea').insertAtCursor link_markdown
|
148
|
-
$.each params, (key, value)->
|
149
|
-
formData.append(key, value)
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
$.extend
|
154
|
-
|
155
|
-
# Extend jQuery with functions for PUT and DELETE requests.
|
156
|
-
put: (url, data, callback, type)->
|
157
|
-
if jQuery.isFunction(data)
|
158
|
-
callback = data
|
159
|
-
data = {}
|
160
|
-
|
161
|
-
data = data || {}
|
162
|
-
data['_method'] = 'put'
|
163
|
-
jQuery.post(url, data, callback, type)
|
164
|
-
|
165
|
-
destroy: (url, data, callback, type)->
|
166
|
-
if jQuery.isFunction(data)
|
167
|
-
callback = data
|
168
|
-
data = {}
|
169
|
-
|
170
|
-
data = data || {}
|
171
|
-
data._method = 'delete'
|
172
|
-
jQuery.post(url, data, callback, type)
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
$(document).ajaxSend (e, jqxhr, settings)->
|
177
|
-
return if settings.type is 'GET'
|
178
|
-
jqxhr.setRequestHeader 'X-CSRF-Token', App.meta('csrf-token')
|
@@ -0,0 +1,44 @@
|
|
1
|
+
toDate = (timestamp)->
|
2
|
+
return timestamp if _.isDate(timestamp)
|
3
|
+
new Date(timestamp)
|
4
|
+
|
5
|
+
Handlebars.registerHelper 'timelineDateRange', (lastDate, date)->
|
6
|
+
return Handlebars.helpers.timelineDate(date) unless lastDate
|
7
|
+
days = (lastDate - date) / Duration.DAY
|
8
|
+
return Handlebars.helpers.timelineDateAfterGap(date) if days >= 3
|
9
|
+
|
10
|
+
_.inject [0...days],
|
11
|
+
((html, i)-> html + Handlebars.helpers.timelineDate((i + 1).days().before(lastDate)))
|
12
|
+
, ''
|
13
|
+
|
14
|
+
Handlebars.registerHelper 'timelineDate', (date)->
|
15
|
+
format = d3.time.format """
|
16
|
+
<div class="timeline-date">
|
17
|
+
<span class="weekday">%a</span>
|
18
|
+
<span class="month">%b</span>
|
19
|
+
<span class="day">%-d</span>
|
20
|
+
<span class="year">%Y</span>
|
21
|
+
</div>
|
22
|
+
"""
|
23
|
+
format toDate(date)
|
24
|
+
|
25
|
+
Handlebars.registerHelper 'timelineTime', (time)->
|
26
|
+
format = d3.time.format('<span class="timeline-event-time">%-I:%M%p</span>')
|
27
|
+
format toDate(time)
|
28
|
+
.replace(/[AP]M/, (str)-> str.toLowerCase()[0])
|
29
|
+
|
30
|
+
Handlebars.registerHelper 'timelineDateAfterGap', (date)->
|
31
|
+
'<div class="timeline-date-gap"></div>' + Handlebars.helpers.timelineDate(date)
|
32
|
+
|
33
|
+
Handlebars.registerHelper 'timeline', (events, options)->
|
34
|
+
lastDate = null
|
35
|
+
events ?= []
|
36
|
+
if events.length > 0
|
37
|
+
html = '<div class="timeline">'
|
38
|
+
for event in events
|
39
|
+
date = App.truncateDate(toDate(event.date || event.time))
|
40
|
+
html += Handlebars.helpers.timelineDateRange(lastDate, date)
|
41
|
+
html += options.fn(event)
|
42
|
+
lastDate = date
|
43
|
+
html += '</div>'
|
44
|
+
html
|
@@ -0,0 +1,99 @@
|
|
1
|
+
$.fn.extend
|
2
|
+
|
3
|
+
getCursorPosition: ->
|
4
|
+
input = @get(0)
|
5
|
+
return unless input
|
6
|
+
if input.selectionStart # Standard-compliant browsers
|
7
|
+
input.selectionStart
|
8
|
+
else if document.selection # IE
|
9
|
+
input.focus()
|
10
|
+
sel = document.selection.createRange()
|
11
|
+
selLen = document.selection.createRange().text.length
|
12
|
+
sel.moveStart 'character', -input.value.length
|
13
|
+
sel.text.length - selLen
|
14
|
+
|
15
|
+
putCursorAtEnd: ->
|
16
|
+
@each ->
|
17
|
+
$(@).focus()
|
18
|
+
|
19
|
+
# If this function exists...
|
20
|
+
if @setSelectionRange
|
21
|
+
# ... then use it (Doesn't work in IE)
|
22
|
+
|
23
|
+
# Double the length because Opera is inconsistent about whether a carriage return is one character or two. Sigh.
|
24
|
+
len = $(@).val().length * 2
|
25
|
+
|
26
|
+
@setSelectionRange(len, len)
|
27
|
+
else
|
28
|
+
|
29
|
+
# ... otherwise replace the contents with itself
|
30
|
+
# (Doesn't work in Google Chrome)
|
31
|
+
|
32
|
+
$(@).val($(@).val())
|
33
|
+
|
34
|
+
insertAtCursor: (text)->
|
35
|
+
textarea = @[0]
|
36
|
+
|
37
|
+
# IE support
|
38
|
+
if document.selection
|
39
|
+
textarea.focus()
|
40
|
+
sel = document.selection.createRange()
|
41
|
+
sel.text = text
|
42
|
+
|
43
|
+
# MOZILLA and others
|
44
|
+
else if textarea.selectionStart || textarea.selectionStart == '0'
|
45
|
+
startPos = textarea.selectionStart
|
46
|
+
endPos = textarea.selectionEnd
|
47
|
+
textarea.value = textarea.value.substring(0, startPos) + text + textarea.value.substring(endPos, textarea.value.length)
|
48
|
+
textarea.selectionStart = startPos + text.length
|
49
|
+
textarea.selectionEnd = startPos + text.length
|
50
|
+
|
51
|
+
else
|
52
|
+
textarea.value += text
|
53
|
+
|
54
|
+
supportImages: ->
|
55
|
+
$el = @
|
56
|
+
|
57
|
+
$el.append '''
|
58
|
+
<div class="drag-and-drop">
|
59
|
+
Attach files or images by dragging & dropping them or <a class="dz-selector">selecting them</a>.
|
60
|
+
</div>
|
61
|
+
<div class="upload-progress"></div>
|
62
|
+
<div class="upload-error"></div>
|
63
|
+
'''
|
64
|
+
|
65
|
+
bucket = App.meta('s3-bucket')
|
66
|
+
$el.dropzone
|
67
|
+
maxFilesize: 13 # MB
|
68
|
+
clickable: '.dz-selector'
|
69
|
+
acceptedFiles: '.pdf,.zip,image/jpeg,image/png,image/gif'
|
70
|
+
url: "//#{bucket}.s3.amazonaws.com"
|
71
|
+
uploadprogress: (file, progress)->
|
72
|
+
$el.find('.upload-progress').html "Uploading #{file.name} (#{progress.toFixed(0)}% complete)"
|
73
|
+
|
74
|
+
complete: ->
|
75
|
+
if @getUploadingFiles().length is 0 and @getQueuedFiles().length is 0
|
76
|
+
$el.removeClass('uploading')
|
77
|
+
|
78
|
+
error: (file, errorMessage)->
|
79
|
+
$el.addClass('error')
|
80
|
+
$el.find('.upload-error').html """
|
81
|
+
<span class="message">#{errorMessage}</span>
|
82
|
+
<a class="dz-selector">Try again</a>"
|
83
|
+
"""
|
84
|
+
|
85
|
+
sending: (file, xhr, formData)=>
|
86
|
+
$el.removeClass('error').addClass('uploading')
|
87
|
+
$el.find('.upload-progress').html "Uploading #{file.name}..."
|
88
|
+
$.ajax
|
89
|
+
url: '/uploads/policies',
|
90
|
+
data: {name: file.name, size: file.size, type: file.type},
|
91
|
+
type: 'POST',
|
92
|
+
async: false, # because we need this response before dropzone can continue
|
93
|
+
success: (params)=>
|
94
|
+
src = "https://s3.amazonaws.com/#{bucket}/#{params.key}"
|
95
|
+
link_markdown = "[#{file.name}](#{src})"
|
96
|
+
link_markdown = "!#{link_markdown}" unless _.contains(["application/pdf", "application/zip"], file.type)
|
97
|
+
@.find('textarea').insertAtCursor link_markdown
|
98
|
+
$.each params, (key, value)->
|
99
|
+
formData.append(key, value)
|
@@ -10,20 +10,37 @@
|
|
10
10
|
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
|
11
11
|
// about supported directives.
|
12
12
|
//
|
13
|
+
//* Houston's client-side stack
|
13
14
|
//= require underscore
|
14
15
|
//= require backbone
|
15
16
|
//= require handlebars
|
16
|
-
//= require
|
17
|
-
//= require jquery-ui
|
17
|
+
//= require neat
|
18
18
|
//= require bootstrap
|
19
|
-
//= require jquery
|
20
|
-
|
21
|
-
|
22
|
-
//= require
|
23
|
-
|
24
|
-
|
19
|
+
//= require jquery-ui
|
20
|
+
//
|
21
|
+
//* for graphics
|
22
|
+
//= require d3
|
23
|
+
//
|
24
|
+
//* for rendering Markdown
|
25
25
|
//= require showdown
|
26
|
-
|
26
|
+
//
|
27
|
+
//* for showing Flash messages
|
27
28
|
//= require alertify
|
29
|
+
//
|
30
|
+
//* for accepting files
|
28
31
|
//= require dropzone
|
32
|
+
//
|
33
|
+
//* for Houston's mobile navigation
|
29
34
|
//= require slideout
|
35
|
+
//
|
36
|
+
//* for rendering simple tables
|
37
|
+
//= require jquery.tablesorter.js
|
38
|
+
//
|
39
|
+
//* for formatting times as elapsed, `formatTimeAgo` helper
|
40
|
+
//= require jquery.timeago.js
|
41
|
+
//
|
42
|
+
//* for defining keyboard shortcuts
|
43
|
+
//= require mousetrap
|
44
|
+
//
|
45
|
+
//* for autogrowing textareas
|
46
|
+
//= require jquery.autosize.js
|