mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
lots of missing files
This commit is contained in:
parent
40e22b14f3
commit
2ed7b6e459
|
@ -0,0 +1,75 @@
|
|||
(function($) {
|
||||
$.fn.applyLocalDates = function(repeat) {
|
||||
function _formatTimezone(timezone) {
|
||||
return timezone.replace("_", " ").split("/");
|
||||
}
|
||||
|
||||
function processElement($element, options) {
|
||||
repeat = repeat || true;
|
||||
|
||||
if (this.timeout) {
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
|
||||
var relativeTime = moment.utc(options.date + " " + options.time, "YYYY-MM-DD HH:mm");
|
||||
|
||||
if (options.recurring && relativeTime < moment().utc()) {
|
||||
var parts = options.recurring.split(".");
|
||||
var count = parseInt(parts[0], 10);
|
||||
var type = parts[1];
|
||||
var diff = moment().diff(relativeTime, type);
|
||||
var add = Math.ceil(diff + count);
|
||||
|
||||
relativeTime = relativeTime.add(add, type);
|
||||
}
|
||||
|
||||
var previews = options.timezones.split("|").map(function(timezone) {
|
||||
var dateTime = relativeTime.tz(timezone).format(options.format);
|
||||
var timezoneParts = _formatTimezone(timezone);
|
||||
|
||||
if (dateTime.match(/TZ/)) {
|
||||
return dateTime.replace("TZ", timezoneParts.join(": "));
|
||||
} else {
|
||||
var output = timezoneParts[0];
|
||||
if (timezoneParts[1]) {
|
||||
output += " (" + timezoneParts[1] + ")";
|
||||
}
|
||||
output += " " + dateTime;
|
||||
return output;
|
||||
}
|
||||
});
|
||||
|
||||
relativeTime = relativeTime.tz(moment.tz.guess()).format(options.format);
|
||||
|
||||
var html = "<span>";
|
||||
html += "<i class='fa fa-globe d-icon d-icon-globe'></i>";
|
||||
html += relativeTime.replace("TZ", _formatTimezone(moment.tz.guess()).join(": "));
|
||||
html += "</span>";
|
||||
|
||||
$element
|
||||
.html(html)
|
||||
.attr("title", previews.join("\n"))
|
||||
.attr("onclick", "alert('" + previews.join("\\n") + "');return false;")
|
||||
.addClass("cooked");
|
||||
|
||||
if (repeat) {
|
||||
this.timeout = setTimeout(function() {
|
||||
processElement($element, options);
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
return this.each(function() {
|
||||
var $this = $(this);
|
||||
|
||||
var options = {};
|
||||
options.format = $this.attr("data-format");
|
||||
options.date = $this.attr("data-date");
|
||||
options.time = $this.attr("data-time");
|
||||
options.recurring = $this.attr("data-recurring");
|
||||
options.timezones = $this.attr("data-timezones") || "Etc/UTC";
|
||||
|
||||
processElement($this, options);
|
||||
});
|
||||
};
|
||||
})(jQuery);
|
|
@ -0,0 +1,116 @@
|
|||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { observes } from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
timeFormat: "HH:mm",
|
||||
dateFormat: "YYYY-MM-DD",
|
||||
dateTimeFormat: "YYYY-MM-DD HH:mm",
|
||||
config: null,
|
||||
date: null,
|
||||
time: null,
|
||||
format: null,
|
||||
formats: null,
|
||||
recurring: null,
|
||||
advancedMode: false,
|
||||
|
||||
init() {
|
||||
this._super();
|
||||
|
||||
this.set("date", moment().format(this.dateFormat));
|
||||
this.set("time", moment().format(this.timeFormat));
|
||||
this.set("format", `LLL`);
|
||||
this.set("timezones", (this.siteSettings.discourse_local_dates_default_timezones || "").split("|").filter(f => f));
|
||||
this.set("formats", (this.siteSettings.discourse_local_dates_default_formats || "").split("|"));
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super();
|
||||
|
||||
this._setConfig();
|
||||
},
|
||||
|
||||
@computed
|
||||
currentUserTimezone() {
|
||||
return moment.tz.guess();
|
||||
},
|
||||
|
||||
@computed
|
||||
recurringOptions() {
|
||||
return [
|
||||
{ name: "Every day", id: "1.days" },
|
||||
{ name: "Every week", id: "1.weeks" },
|
||||
{ name: "Every two weeks", id: "2.weeks" },
|
||||
{ name: "Every month", id: "1.months" },
|
||||
{ name: "Every two months", id: "2.months" },
|
||||
{ name: "Every three months", id: "3.months" },
|
||||
{ name: "Every six months", id: "6.months" },
|
||||
{ name: "Every year", id: "1.years" },
|
||||
];
|
||||
},
|
||||
|
||||
@computed()
|
||||
allTimezones() {
|
||||
return _.map(moment.tz.names(), (z) => z);
|
||||
},
|
||||
|
||||
@observes("date", "time", "recurring", "format", "timezones")
|
||||
_setConfig() {
|
||||
const date = this.get("date");
|
||||
const time = this.get("time");
|
||||
const recurring = this.get("recurring");
|
||||
const format = this.get("format");
|
||||
const timezones = this.get("timezones");
|
||||
const dateTime = moment(`${date} ${time}`, this.dateTimeFormat).utc();
|
||||
|
||||
this.set("config", {
|
||||
date: dateTime.format(this.dateFormat),
|
||||
time: dateTime.format(this.timeFormat),
|
||||
dateTime,
|
||||
recurring,
|
||||
format,
|
||||
timezones,
|
||||
});
|
||||
},
|
||||
|
||||
getTextConfig(config) {
|
||||
let text = `[date=${config.date} `;
|
||||
if (config.recurring) text += `recurring=${config.recurring} `;
|
||||
text += `time=${config.time} `;
|
||||
text += `format=${config.format} `;
|
||||
text += `timezones="${config.timezones.join("|")}"`;
|
||||
text += `]`;
|
||||
return text;
|
||||
},
|
||||
|
||||
@computed("config.dateTime")
|
||||
validDate(dateTime) {
|
||||
if (!dateTime) return false;
|
||||
return dateTime.isValid();
|
||||
},
|
||||
|
||||
actions: {
|
||||
advancedMode() {
|
||||
this.toggleProperty("advancedMode");
|
||||
},
|
||||
|
||||
save() {
|
||||
this._closeModal();
|
||||
|
||||
const textConfig = this.getTextConfig(this.get("config"));
|
||||
this.get("toolbarEvent").addText(textConfig);
|
||||
},
|
||||
|
||||
fillFormat(format) {
|
||||
this.set("format", format);
|
||||
},
|
||||
|
||||
cancel() {
|
||||
this._closeModal();
|
||||
}
|
||||
},
|
||||
|
||||
_closeModal() {
|
||||
const composer = Discourse.__container__.lookup("controller:composer");
|
||||
composer.send("closeModal");
|
||||
}
|
||||
});
|
|
@ -0,0 +1,77 @@
|
|||
{{#d-modal-body
|
||||
title="discourse_local_dates.create.modal_title"
|
||||
class="discourse-local-dates-create-modal"
|
||||
style="overflow: auto"}}
|
||||
|
||||
<div class="form">
|
||||
<div class="control-group">
|
||||
<div class="controls date-time">
|
||||
{{date-picker-future class="date" value=date defaultDate="DD-MM-YYYY"}}
|
||||
{{input type="time" value=time class="time"}}
|
||||
<span>{{currentUserTimezone}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>{{i18n "discourse_local_dates.create.form.recurring_title"}}</h3>
|
||||
<div class="control-group">
|
||||
{{#if advancedMode}}
|
||||
<label>{{{i18n "discourse_local_dates.create.form.recurring_description"}}}</label>
|
||||
{{/if}}
|
||||
<div class="controls">
|
||||
{{combo-box content=recurringOptions value=recurring none="discourse_local_dates.create.form.recurring_none"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{d-button
|
||||
class="advanced-mode-btn"
|
||||
action=(action "advancedMode")
|
||||
icon="cog"
|
||||
label="discourse_local_dates.create.form.advanced_mode"}}
|
||||
|
||||
{{#if advancedMode}}
|
||||
<div class="advanced-options">
|
||||
<div class="control-group">
|
||||
<label>
|
||||
{{i18n "discourse_local_dates.create.form.format_description"}}
|
||||
(<a target="_blank" rel="noopener" href="https://momentjs.com/docs/#/parsing/string-format/">?</a>)
|
||||
</label>
|
||||
<div class="controls">
|
||||
{{text-field value=format}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<ul class="formats">
|
||||
{{#each formats as |format|}}
|
||||
<li class="format">
|
||||
<a href {{action "fillFormat" format}}>{{format}}</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h3>{{i18n "discourse_local_dates.create.form.timezones_title"}}</h3>
|
||||
<div class="control-group">
|
||||
<label>{{i18n "discourse_local_dates.create.form.timezones_description"}}</label>
|
||||
<div class="controls">
|
||||
{{multi-select allowAny=false maximum=5 content=allTimezones values=timezones}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/d-modal-body}}
|
||||
|
||||
<div class="modal-footer discourse-local-dates-create-modal-footer">
|
||||
|
||||
{{#if validDate}}
|
||||
{{d-button class="btn"
|
||||
action="save"
|
||||
label="discourse_local_dates.create.form.insert"}}
|
||||
{{else}}
|
||||
<span class="validation-error">{{i18n "discourse_local_dates.create.form.invalid_date"}}</span>
|
||||
{{/if}}
|
||||
|
||||
<a href {{action "cancel"}}>
|
||||
{{i18n 'cancel'}}
|
||||
</a>
|
||||
</div>
|
|
@ -0,0 +1 @@
|
|||
{{discourse-local-dates-create-form config=config toolbarEvent=toolbarEvent}}
|
|
@ -0,0 +1,37 @@
|
|||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
function initializeDiscourseLocalDates(api) {
|
||||
api.decorateCooked($elem => {
|
||||
$(".discourse-local-date", $elem).applyLocalDates();
|
||||
});
|
||||
|
||||
api.addToolbarPopupMenuOptionsCallback(() => {
|
||||
return {
|
||||
action: "insertDiscourseLocalDate",
|
||||
icon: "globe",
|
||||
label: "discourse_local_dates.title"
|
||||
};
|
||||
});
|
||||
|
||||
api.modifyClass('controller:composer', {
|
||||
actions: {
|
||||
insertDiscourseLocalDate() {
|
||||
showModal("discourse-local-dates-create-modal").setProperties({
|
||||
toolbarEvent: this.get("toolbarEvent")
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "discourse-local-dates",
|
||||
|
||||
initialize(container) {
|
||||
const siteSettings = container.lookup("site-settings:main");
|
||||
if (siteSettings.discourse_local_dates_enabled) {
|
||||
withPluginApi("0.8.8", initializeDiscourseLocalDates);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,73 @@
|
|||
import { parseBBCodeTag } from 'pretty-text/engines/discourse-markdown/bbcode-block';
|
||||
|
||||
function addLocalDate(buffer, matches, state) {
|
||||
let token;
|
||||
|
||||
let config = {
|
||||
date: null,
|
||||
time: null,
|
||||
format: "YYYY-MM-DD HH:mm",
|
||||
timezones: ""
|
||||
};
|
||||
|
||||
let parsed = parseBBCodeTag("[date date" + matches[1] + "]", 0, matches[1].length + 11);
|
||||
|
||||
config.date = parsed.attrs.date;
|
||||
config.time = parsed.attrs.time;
|
||||
config.format = parsed.attrs.format || config.format;
|
||||
config.timezones = parsed.attrs.timezones || config.timezones;
|
||||
|
||||
token = new state.Token('a_open', 'a', 1);
|
||||
token.attrs = [
|
||||
['class', 'discourse-local-date'],
|
||||
['data-date', config.date],
|
||||
['data-time', config.time],
|
||||
['data-recurring', config.recurring],
|
||||
['data-format', config.format],
|
||||
['data-timezones', config.timezones],
|
||||
];
|
||||
buffer.push(token);
|
||||
|
||||
const previews = config.timezones.split("|").filter(t => t).map(timezone => {
|
||||
const dateTime = moment
|
||||
.utc(`${config.date} ${config.time}`, "YYYY-MM-DD HH:mm")
|
||||
.tz(timezone)
|
||||
.format(config.format);
|
||||
|
||||
const formattedTimezone = timezone.replace("/", ": ").replace("_", " ");
|
||||
|
||||
if (dateTime.match(/TZ/)) {
|
||||
return dateTime.replace("TZ", formattedTimezone);
|
||||
} else {
|
||||
return `${dateTime} (${formattedTimezone})`;
|
||||
}
|
||||
});
|
||||
|
||||
token = new state.Token('text', '', 0);
|
||||
token.content = previews.join(", ");
|
||||
buffer.push(token);
|
||||
|
||||
token = new state.Token('a_close', 'a', -1);
|
||||
buffer.push(token);
|
||||
}
|
||||
|
||||
export function setup(helper) {
|
||||
helper.whiteList([
|
||||
'a.discourse-local-date',
|
||||
'a[data-*]',
|
||||
'a[title]'
|
||||
]);
|
||||
|
||||
helper.registerOptions((opts, siteSettings) => {
|
||||
opts.features['discourse-local-dates'] = !!siteSettings.discourse_local_dates_enabled;
|
||||
});
|
||||
|
||||
helper.registerPlugin(md => {
|
||||
const rule = {
|
||||
matcher: /\[date(.*?)\]/,
|
||||
onMatch: addLocalDate
|
||||
};
|
||||
|
||||
md.core.textPostProcess.ruler.push('discourse-local-dates', rule);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
.discourse-local-date {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
|
||||
&.cooked {
|
||||
color: $primary;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
|
||||
.d-icon-globe {
|
||||
margin-right: .25em;
|
||||
color: $primary-medium;
|
||||
|
||||
&:hover {
|
||||
color: $primary-high;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .d-icon-globe {
|
||||
color: $primary-high;
|
||||
}
|
||||
}
|
||||
|
||||
+ .discourse-local-date {
|
||||
margin-left: .5em;
|
||||
}
|
||||
}
|
||||
|
||||
.discourse-local-dates-create-modal-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.validation-error {
|
||||
color: $danger;
|
||||
}
|
||||
|
||||
&:before, &:after {
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
|
||||
.discourse-local-dates-create-modal {
|
||||
min-height: 300px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.form {
|
||||
flex: 1;
|
||||
.controls {
|
||||
&.date-time {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin-bottom: 1em;
|
||||
|
||||
.date {
|
||||
margin: 0 0.5em 0 0;
|
||||
}
|
||||
|
||||
.date-picker {
|
||||
padding-top: 5px;
|
||||
bottom: 5px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.time {
|
||||
margin: 0 0.5em 0 0;
|
||||
max-width: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.advanced-mode-btn {
|
||||
margin-top: 2em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.select-kit.multi-select {
|
||||
width: 90%;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user