Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
angusmcleod committed Aug 24, 2017
0 parents commit 5ac6b9e
Show file tree
Hide file tree
Showing 23 changed files with 1,099 additions and 0 deletions.
339 changes: 339 additions & 0 deletions LICENSE.txt

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions assets/javascripts/discourse/components/add-event-controls.js.es6
@@ -0,0 +1,26 @@
import showModal from 'discourse/lib/show-modal';
import { eventLabel } from '../lib/date-utilities';
import { default as computed } from 'ember-addons/ember-computed-decorators';

export default Ember.Component.extend({
classNames: ['event-label'],

actions: {
showAddEvent() {
let controller = showModal('set-event', {
model: {
event: this.get('event'),
update: (event) => {
this.set('event', event)
}
}
});

controller.send('setup');
},

removeEvent() {
this.set('event', null);
}
}
})
20 changes: 20 additions & 0 deletions assets/javascripts/discourse/components/composer-add-event.js.es6
@@ -0,0 +1,20 @@
import { observes } from 'ember-addons/ember-computed-decorators';

export default Ember.Component.extend({
classNames: ['composer-add-event'],

didInsertElement() {
this.sendAction('updateTip', 'composer.tip.add_event', 'top');
},

@observes('event', 'location')
checkIfReady() {
const event = this.get('event');
const location = this.get('location');
if (event && location) {
this.sendAction('addComposerProperty', 'event', event);
this.sendAction('addComposerProperty', 'location', location);
this.sendAction('ready');
}
}
})
@@ -0,0 +1,6 @@
<section class='field'>
<label>
{{input type="checkbox" checked=category.custom_fields.events_enabled}}
{{i18n 'category.enable_events'}}
</label>
</section>
@@ -0,0 +1,3 @@
{{#if model.showEventControls}}
{{add-event-controls event=model.event}}
{{/if}}
@@ -0,0 +1,3 @@
{{#if model.showEventControls}}
{{add-event-controls event=buffered.event}}
{{/if}}
@@ -0,0 +1,7 @@
{{#if context.topic.event}}
<div class="date-time-container">
<a href="{{context.topic.lastUnreadUrl}}" class="{{context.topic.topicListItemClasses}}">
{{event-label context.topic.event short="true" includeIcon="true"}}
</a>
</div>
{{/if}}
@@ -0,0 +1,8 @@
{{#unless model.editingTopic}}
{{#if model.event}}
<div class="event-label">
{{d-icon 'calendar'}}
{{event-label model.event}}
</div>
{{/if}}
{{/unless}}
64 changes: 64 additions & 0 deletions assets/javascripts/discourse/controllers/set-event.js.es6
@@ -0,0 +1,64 @@
import { default as computed, observes } from 'ember-addons/ember-computed-decorators';

export default Ember.Controller.extend({
title: 'add_event.modal_title',

setup() {
const event = this.get('model.event');

let start = event && event.start ? event.start : moment();
let end = event && event.end ? event.end : moment().add(1, 'hours');

this.setProperties({
startDate: moment(start).format('YYYY-MM-DD'),
startTime: moment(start).format('HH:MM'),
endDate: moment(end).format('YYYY-MM-DD'),
endTime: moment(end).format('HH:MM')
})
},

dateTime: function(date, time) {
return moment(date + 'T' + time).format();
},

@computed('startDate', 'startTime')
eventStart(date, time) {
return date && time ? this.dateTime(date, time) : '';
},

@computed('endDate', 'endTime')
eventEnd(date, time) {
return date && time ? this.dateTime(date, time) : '';
},

@computed('eventStart','eventEnd')
notReady(eventStart, eventEnd) {
return !eventStart || !eventEnd || eventStart > eventEnd;
},

resetProperties() {
this.setProperties({
startDate: null,
startTime: null,
endDate: null,
endTime: null
})
},

actions: {
setup() {
this.setup();
},

addEvent() {
const event = {
start: this.get('eventStart'),
end: this.get('eventEnd')
}

this.get('model.update')(event);
this.resetProperties();
this.send("closeModal");
}
}
});
6 changes: 6 additions & 0 deletions assets/javascripts/discourse/helpers/event-label.js.es6
@@ -0,0 +1,6 @@
import { registerUnbound } from 'discourse-common/lib/helpers';
import { eventLabel } from '../lib/date-utilities';

export default registerUnbound('event-label', function(event, args) {
return new Handlebars.SafeString(eventLabel(event, args));
});
82 changes: 82 additions & 0 deletions assets/javascripts/discourse/initializers/event-edits.js.es6
@@ -0,0 +1,82 @@
import Composer from 'discourse/models/composer';
import ComposerBody from 'discourse/components/composer-body';
import Topic from 'discourse/models/topic';
import TopicController from 'discourse/controllers/topic';
import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
import NavItem from 'discourse/models/nav-item';
import EditCategorySettings from 'discourse/components/edit-category-settings';

export default {
name: 'events-edits',
initialize(){
Composer.serializeOnCreate('event');

Composer.reopen({
@computed('currentType', 'category.events_enabled', 'topicFirstPost')
showEventControls(type, categoryEnabled, topicFirstPost) {
return topicFirstPost && (type === 'event' || categoryEnabled);
}
})

ComposerBody.reopen({
@observes('composer.event')
resizeWhenEventAdded: function() {
this.resize();
}
})

Topic.reopen({
@computed('subtype', 'category.events_enabled')
showEventControls(subtype, categoryEnabled) {
return subtype === 'event' || categoryEnabled;
},

@computed('last_read_post_number', 'highest_post_number')
topicListItemClasses(lastRead, highest) {
let classes = "date-time title raw-link raw-topic-link";
if (lastRead === this.get('highest_post_number')) {
classes += ' visited';
}
return classes;
}
})

// necessary because topic-title plugin outlet only recieves model
TopicController.reopen({
@observes('editingTopic')
setEditingTopicOnModel() {
this.set('model.editingTopic', this.get('editingTopic'));
}
})

NavItem.reopenClass({
buildList(category, args) {
let items = this._super(category, args);

if (category && category.events_enabled) {
items.push(Discourse.NavItem.fromText('agenda', args));
}

return items;
}
})

EditCategorySettings.reopen({
@computed('category')
availableViews(category) {
let views = [
{name: I18n.t('filters.latest.title'), value: 'latest'},
{name: I18n.t('filters.top.title'), value: 'top'},
]

if (category.get('events_enabled')) {
views.push(
{name: I18n.t('filters.agenda.title'), value: 'agenda'}
)
}

return views;
},
})
}
}
20 changes: 20 additions & 0 deletions assets/javascripts/discourse/lib/date-utilities.js.es6
@@ -0,0 +1,20 @@
function eventLabel(event, args = {}) {
let label = '';

if (args['includeIcon']) {
label += "<i class='fa fa-calendar'></i>"
}

let startFormat = args.short ? 'M-D, h:mm' : 'MMMM Do, h:mm';
let diffDay = moment(event['start']).date() !== moment(event['end']).date();
let endFormat = diffDay ? startFormat : 'h:mm';

let dateString = moment(event['start']).format(startFormat) + ' - '
+ moment(event['end']).format(endFormat);

label += `<span>${dateString}</span>`;

return label;
}

export { eventLabel };
@@ -0,0 +1,6 @@
{{#if event}}
{{d-button class="btn current-event" action="showAddEvent" translatedLabel=(event-label event) icon='calendar'}}
{{d-button icon="times" action="removeEvent"}}
{{else}}
{{d-button label="add_event.btn_label" action="showAddEvent" icon='calendar'}}
{{/if}}
@@ -0,0 +1,2 @@
{{add-event-controls topic=topic}}
{{add-location-controls location=location categoryId=category.id}}
@@ -0,0 +1 @@
<input type="text" value={{value}} class="date-picker">
48 changes: 48 additions & 0 deletions assets/javascripts/discourse/templates/modal/set-event.hbs
@@ -0,0 +1,48 @@
{{#d-modal-body class="set-event-modal" id="event-modal" title=title}}
<div class="start-card">
<span class="modal-sub-title">
{{i18n "add_event.event_start"}}
</span>
{{input-tip validation=startDateTimeValidation}}
<div class="modal-date-time-set">
<div class="modal-date-area">
<label class="input-group-label">
{{i18n "add_event.event_date"}}
</label>
{{date-picker value=startDate containerId="date-container-start"}}
</div>
<div class="modal-time-area">
<label class="input-group-label">
{{i18n "add_event.event_time"}}
</label>
{{input type="time" class="modal-time" value=startTime disabled=allDay}}
</div>
</div>
<div id="date-container-start"/>
</div>
<div class="end-card">
<span class="modal-sub-title">
{{i18n "add_event.event_end"}}
</span>
{{input-tip validation=scheduleDateTimeValidation}}
<div class="modal-date-time-set">
<div class="modal-date-area">
<label class="input-group-label">
{{i18n "add_event.event_date"}}
</label>
{{date-picker value=endDate containerId="date-container-end"}}
</div>
<div class="modal-time-area">
<label class="input-group-label">
{{i18n "add_event.event_time"}}
</label>
{{input type="time" class="modal-time" value=endTime disabled=allDay}}
</div>
</div>
<div id="date-container-end"/>
</div>
{{/d-modal-body}}

<div class="modal-footer">
{{d-button action="addEvent" icon="calendar" class="btn-primary" label="add_event.event_add" disabled=notReady}}
</div>
42 changes: 42 additions & 0 deletions assets/javascripts/discourse/widgets/event-list-controls.js.es6
@@ -0,0 +1,42 @@
import { createWidget } from 'discourse/widgets/widget';
import showModal from 'discourse/lib/show-modal';
import { getOwner } from 'discourse-common/lib/get-owner';

export default createWidget('event-list-controls', {
tagName: 'div.event-list-controls',

html(attrs) {
const user = this.currentUser;
let links = [];

if (user && user.staff) {
links.push(this.attach('link', {
icon: 'plus',
label: 'event_list.create',
action: 'createEvent',
}));
}

return links;
},

createEvent() {
const category = this.attrs.category;
const controller = getOwner(this).lookup('controller:composer');

let attrs = {
action: 'createTopic',
draftKey: 'new_topic',
draftSequence: 0,
addProperties: {
currentType: 'event'
}
};

if (category) {
attrs['categoryId'] = category.id;
}

controller.open(attrs);
}
})

0 comments on commit 5ac6b9e

Please sign in to comment.