Version bump
This commit is contained in:
commit
387bdadbe2
@ -41,11 +41,12 @@
|
||||
"visible":true,
|
||||
"invisible":true,
|
||||
"asyncRender":true,
|
||||
"selectDropdown":true,
|
||||
"selectKit":true,
|
||||
"expandSelectKit":true,
|
||||
"collapseSelectKit":true,
|
||||
"selectKitSelectRow":true,
|
||||
"selectKitSelectRowByValue":true,
|
||||
"selectKitSelectRowByName":true,
|
||||
"selectKitSelectRowByIndex":true,
|
||||
"selectKitSelectNoneRow":true,
|
||||
"selectKitFillInFilter":true,
|
||||
"asyncTestDiscourse":true,
|
||||
|
||||
@ -21,8 +21,11 @@ addons:
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- rvm: 2.5.0
|
||||
|
||||
rvm:
|
||||
- 2.5.0
|
||||
- 2.4.2
|
||||
- 2.3.4
|
||||
|
||||
@ -45,6 +48,7 @@ before_install:
|
||||
- git clone --depth=1 https://github.com/discourse/discourse-canned-replies.git plugins/discourse-canned-replies
|
||||
- git clone --depth=1 https://github.com/discourse/discourse-chat-integration.git plugins/discourse-chat-integration
|
||||
- git clone --depth=1 https://github.com/discourse/discourse-assign.git plugins/discourse-assign
|
||||
- git clone --depth=1 https://github.com/discourse/discourse-patreon.git plugins/discourse-patreon
|
||||
- export PATH=$HOME/.yarn/bin:$PATH
|
||||
|
||||
install:
|
||||
@ -67,7 +71,7 @@ script:
|
||||
bundle exec rake db:create db:migrate
|
||||
|
||||
if [ '$QUNIT_RUN' == '1' ]; then
|
||||
bundle exec rake qunit:test['400000']
|
||||
bundle exec rake qunit:test['400000'] && \
|
||||
bundle exec rake plugin:spec
|
||||
else
|
||||
bundle exec rspec && bundle exec rake plugin:spec
|
||||
|
||||
2
Gemfile
2
Gemfile
@ -36,7 +36,7 @@ gem 'redis-namespace'
|
||||
|
||||
gem 'active_model_serializers', '~> 0.8.3'
|
||||
|
||||
gem 'onebox', '1.8.30'
|
||||
gem 'onebox', '1.8.33'
|
||||
|
||||
gem 'http_accept_language', '~>2.0.5', require: false
|
||||
|
||||
|
||||
@ -232,7 +232,7 @@ GEM
|
||||
omniauth-twitter (1.3.0)
|
||||
omniauth-oauth (~> 1.1)
|
||||
rack
|
||||
onebox (1.8.30)
|
||||
onebox (1.8.33)
|
||||
fast_blank (>= 1.0.0)
|
||||
htmlentities (~> 4.3)
|
||||
moneta (~> 1.0)
|
||||
@ -469,7 +469,7 @@ DEPENDENCIES
|
||||
omniauth-oauth2
|
||||
omniauth-openid
|
||||
omniauth-twitter
|
||||
onebox (= 1.8.30)
|
||||
onebox (= 1.8.33)
|
||||
openid-redis-store
|
||||
pg
|
||||
pry-nav
|
||||
|
||||
@ -16,7 +16,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
||||
|
||||
@computed('name')
|
||||
nameValid(name) {
|
||||
return name && name.match(/\A[a-z_][a-z0-9_-]*\z/i);
|
||||
return name && name.match(/^[a-z_][a-z0-9_-]*$/i);
|
||||
},
|
||||
|
||||
@observes('name')
|
||||
|
||||
@ -68,7 +68,7 @@ export default Discourse.Route.extend({
|
||||
function(confirmed) {
|
||||
if (confirmed) {
|
||||
backup.destroy().then(function() {
|
||||
self.controllerFor("adminBackupsIndex").removeObject(backup);
|
||||
self.controllerFor("adminBackupsIndex").get('model').removeObject(backup);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,9 @@
|
||||
{{#if currentUser.admin}}
|
||||
{{nav-item route='adminCustomize' label='admin.customize.title'}}
|
||||
{{nav-item route='adminApi' label='admin.api.title'}}
|
||||
{{nav-item route='admin.backups' label='admin.backups.title'}}
|
||||
{{#if siteSettings.enable_backups}}
|
||||
{{nav-item route='admin.backups' label='admin.backups.title'}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{nav-item route='adminPlugins' label='admin.plugins.title'}}
|
||||
{{plugin-outlet name="admin-menu" connectorTagName="li"}}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<div class="show-current-style">
|
||||
<h2>
|
||||
<h1>
|
||||
{{#if editingName}}
|
||||
{{text-field value=model.name autofocus="true"}}
|
||||
{{d-button action="finishedEditingName" class="btn-primary btn-small submit-edit" icon="check"}}
|
||||
@ -7,7 +7,7 @@
|
||||
{{else}}
|
||||
{{model.name}} <a {{action "startEditingName"}}>{{d-icon "pencil"}}</a>
|
||||
{{/if}}
|
||||
</h2>
|
||||
</h1>
|
||||
|
||||
{{#if model.remote_theme}}
|
||||
<p>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'span',
|
||||
classNameBindings: [':user-badge', 'badge.badgeTypeClassName'],
|
||||
classNameBindings: [':user-badge', 'badge.badgeTypeClassName', 'badge.enabled::disabled'],
|
||||
title: function(){
|
||||
return $("<div>"+this.get('badge.description')+"</div>").text();
|
||||
}.property('badge.description'),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import userSearch from 'discourse/lib/user-search';
|
||||
import { default as computed, on } from 'ember-addons/ember-computed-decorators';
|
||||
import { default as computed, observes, on } from 'ember-addons/ember-computed-decorators';
|
||||
import { linkSeenMentions, fetchUnseenMentions } from 'discourse/lib/link-mentions';
|
||||
import { linkSeenCategoryHashtags, fetchUnseenCategoryHashtags } from 'discourse/lib/link-category-hashtags';
|
||||
import { linkSeenTagHashtags, fetchUnseenTagHashtags } from 'discourse/lib/link-tag-hashtag';
|
||||
@ -36,6 +36,18 @@ export default Ember.Component.extend({
|
||||
return `[${I18n.t('uploading')}]() `;
|
||||
},
|
||||
|
||||
@observes('composer.uploadCancelled')
|
||||
_cancelUpload() {
|
||||
if (!this.get('composer.uploadCancelled')) { return; }
|
||||
this.set('composer.uploadCancelled', false);
|
||||
|
||||
if (this._xhr) {
|
||||
this._xhr._userCancelled = true;
|
||||
this._xhr.abort();
|
||||
}
|
||||
this._resetUpload(true);
|
||||
},
|
||||
|
||||
@computed
|
||||
markdownOptions() {
|
||||
return {
|
||||
@ -363,7 +375,7 @@ export default Ember.Component.extend({
|
||||
const $e = $(e);
|
||||
var name = $e.data('name');
|
||||
if (found.indexOf(name) === -1){
|
||||
this.sendAction('groupsMentioned', [{name: name, user_count: $e.data('mentionable-user-count')}]);
|
||||
this.sendAction('groupsMentioned', [{name: name, user_count: $e.data('mentionable-user-count'), max_mentions: $e.data('max-mentions')}]);
|
||||
found.push(name);
|
||||
}
|
||||
});
|
||||
@ -401,7 +413,9 @@ export default Ember.Component.extend({
|
||||
},
|
||||
|
||||
_resetUpload(removePlaceholder) {
|
||||
this._validUploads--;
|
||||
if (this._validUploads > 0) {
|
||||
this._validUploads--;
|
||||
}
|
||||
if (this._validUploads === 0) {
|
||||
this.setProperties({ uploadProgress: 0, isUploading: false, isCancellable: false });
|
||||
}
|
||||
@ -493,7 +507,7 @@ export default Ember.Component.extend({
|
||||
this._xhr = null;
|
||||
|
||||
if (!userCancelled) {
|
||||
displayErrorForUpload(data.jqXHR.responseJSON);
|
||||
displayErrorForUpload(data);
|
||||
}
|
||||
});
|
||||
|
||||
@ -624,14 +638,6 @@ export default Ember.Component.extend({
|
||||
this.sendAction('importQuote', toolbarEvent);
|
||||
},
|
||||
|
||||
cancelUpload() {
|
||||
if (this._xhr) {
|
||||
this._xhr._userCancelled = true;
|
||||
this._xhr.abort();
|
||||
}
|
||||
this._resetUpload(true);
|
||||
},
|
||||
|
||||
onExpandPopupMenuOptions(toolbarEvent) {
|
||||
const selected = toolbarEvent.selected;
|
||||
toolbarEvent.selectText(selected.start, selected.end - selected.start);
|
||||
|
||||
@ -279,6 +279,7 @@ export default Ember.Component.extend({
|
||||
const markdownOptions = this.get('markdownOptions') || {};
|
||||
|
||||
cookAsync(value, markdownOptions).then(cooked => {
|
||||
if (this.get('isDestroyed')) { return; }
|
||||
this.set('preview', cooked);
|
||||
Ember.run.scheduleOnce('afterRender', () => {
|
||||
if (this._state !== "inDOM") { return; }
|
||||
@ -632,7 +633,8 @@ export default Ember.Component.extend({
|
||||
|
||||
if (rows.length > 1) {
|
||||
const columns = rows.map(r => r.split("\t").length);
|
||||
const isTable = columns.reduce((a, b) => a && columns[0] === b && b > 1);
|
||||
const isTable = columns.reduce((a, b) => a && columns[0] === b && b > 1) &&
|
||||
!(columns[0] === 2 && rows[0].split("\t")[0].match(/^•$|^\d+.$/)); // to skip tab delimited lists
|
||||
|
||||
if (isTable) {
|
||||
const splitterRow = [...Array(columns[0])].map(() => "---").join("\t");
|
||||
@ -662,8 +664,6 @@ export default Ember.Component.extend({
|
||||
if (table) {
|
||||
this.appEvents.trigger('composer:insert-text', table);
|
||||
handled = true;
|
||||
} else if (html && html.includes("urn:schemas-microsoft-com:office:word")) {
|
||||
html = ""; // use plain text data for microsoft word
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,21 @@
|
||||
import { showEntrance } from "discourse/components/topic-list-item";
|
||||
import { showEntrance, navigateToTopic } from "discourse/components/topic-list-item";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
click: showEntrance,
|
||||
attributeBindings: ['topic.id:data-topic-id'],
|
||||
classNameBindings: [':latest-topic-list-item', 'topic.archived', 'topic.visited']
|
||||
classNameBindings: [':latest-topic-list-item', 'topic.archived', 'topic.visited'],
|
||||
|
||||
showEntrance,
|
||||
navigateToTopic,
|
||||
|
||||
click(e) {
|
||||
// for events undefined has a different meaning than false
|
||||
if (this.showEntrance(e) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.unhandledRowClick(e, this.get('topic'));
|
||||
},
|
||||
|
||||
// Can be overwritten by plugins to handle clicks on other parts of the row
|
||||
unhandledRowClick() { },
|
||||
});
|
||||
|
||||
@ -20,6 +20,12 @@ export function showEntrance(e) {
|
||||
}
|
||||
}
|
||||
|
||||
export function navigateToTopic(topic, href) {
|
||||
this.appEvents.trigger('header:update-topic', topic);
|
||||
DiscourseURL.routeTo(href || topic.get('url'));
|
||||
return false;
|
||||
}
|
||||
|
||||
export default Ember.Component.extend(bufferedRender({
|
||||
rerenderTriggers: ['bulkSelectEnabled', 'topic.pinned'],
|
||||
tagName: 'tr',
|
||||
@ -107,8 +113,10 @@ export default Ember.Component.extend(bufferedRender({
|
||||
return false;
|
||||
}.property(),
|
||||
|
||||
showEntrance,
|
||||
|
||||
click(e) {
|
||||
const result = showEntrance.call(this, e);
|
||||
const result = this.showEntrance(e);
|
||||
if (result === false) { return result; }
|
||||
|
||||
const topic = this.get('topic');
|
||||
@ -124,19 +132,23 @@ export default Ember.Component.extend(bufferedRender({
|
||||
}
|
||||
|
||||
if (target.hasClass('raw-topic-link')) {
|
||||
if (wantsNewWindow(e)) { return true; }
|
||||
|
||||
this.appEvents.trigger('header:update-topic', topic);
|
||||
DiscourseURL.routeTo(target.attr('href'));
|
||||
return false;
|
||||
if (wantsNewWindow(e)) { return true; }
|
||||
return this.navigateToTopic(topic, target.attr('href'));
|
||||
}
|
||||
|
||||
if (target.closest('a.topic-status').length === 1) {
|
||||
this.get('topic').togglePinnedForUser();
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.unhandledRowClick(e, topic);
|
||||
},
|
||||
|
||||
navigateToTopic,
|
||||
|
||||
// Can be overwritten by plugins to handle clicks on other parts of the row
|
||||
unhandledRowClick() { },
|
||||
|
||||
highlight(opts = { isLastViewedTopic: false }) {
|
||||
const $topic = this.$();
|
||||
$topic
|
||||
|
||||
@ -115,8 +115,7 @@ export default Ember.Component.extend(CleansUp, CanCheckEmails, {
|
||||
return false;
|
||||
}
|
||||
|
||||
// XSS protection (should be encapsulated)
|
||||
username = username.toString().replace(/[^A-Za-z0-9_\.\-]/g, "");
|
||||
username = Ember.Handlebars.Utils.escapeExpression(username.toString());
|
||||
|
||||
// Don't show on mobile
|
||||
if (this.site.mobileView) {
|
||||
|
||||
@ -49,6 +49,10 @@ function loadDraft(store, opts) {
|
||||
|
||||
const _popupMenuOptionsCallbacks = [];
|
||||
|
||||
export function clearPopupMenuOptionsCallback() {
|
||||
_popupMenuOptionsCallbacks.length = 0;
|
||||
}
|
||||
|
||||
export function addPopupMenuOptionsCallback(callback) {
|
||||
_popupMenuOptionsCallbacks.push(callback);
|
||||
}
|
||||
@ -220,6 +224,10 @@ export default Ember.Controller.extend({
|
||||
},
|
||||
|
||||
actions: {
|
||||
cancelUpload() {
|
||||
this.set('model.uploadCancelled', true);
|
||||
},
|
||||
|
||||
onPopupMenuAction(action) {
|
||||
this.send(action);
|
||||
},
|
||||
@ -378,11 +386,21 @@ export default Ember.Controller.extend({
|
||||
groupsMentioned(groups) {
|
||||
if (!this.get('model.creatingPrivateMessage') && !this.get('model.topic.isPrivateMessage')) {
|
||||
groups.forEach(group => {
|
||||
const body = I18n.t('composer.group_mentioned', {
|
||||
group: "@" + group.name,
|
||||
count: group.user_count,
|
||||
group_link: Discourse.getURL(`/groups/${group.name}/members`)
|
||||
});
|
||||
let body;
|
||||
|
||||
if (group.max_mentions < group.user_count) {
|
||||
body = I18n.t('composer.group_mentioned_limit', {
|
||||
group: "@" + group.name,
|
||||
max: group.max_mentions,
|
||||
group_link: Discourse.getURL(`/groups/${group.name}/members`)
|
||||
});
|
||||
} else {
|
||||
body = I18n.t('composer.group_mentioned', {
|
||||
group: "@" + group.name,
|
||||
count: group.user_count,
|
||||
group_link: Discourse.getURL(`/groups/${group.name}/members`)
|
||||
});
|
||||
}
|
||||
|
||||
this.appEvents.trigger('composer-messages:create', {
|
||||
extraClass: 'custom-body',
|
||||
|
||||
@ -151,6 +151,12 @@ export default Ember.Controller.extend({
|
||||
this.set("application.showFooter", !this.get("loading"));
|
||||
},
|
||||
|
||||
@computed('resultCount', 'noSortQ')
|
||||
resultCountLabel(count, term) {
|
||||
const plus = (count % 50 === 0 ? "+" : "");
|
||||
return I18n.t('search.result_count', {count, plus, term});
|
||||
},
|
||||
|
||||
@observes('model.posts.length')
|
||||
resultCountChanged() {
|
||||
this.set("resultCount", this.get("model.posts.length"));
|
||||
|
||||
@ -10,6 +10,7 @@ export default Ember.Controller.extend(CanCheckEmails, PreferencesTabController,
|
||||
saveAttrNames: ['name'],
|
||||
|
||||
canEditName: setting('enable_names'),
|
||||
canSaveUser: true,
|
||||
|
||||
newNameInput: null,
|
||||
|
||||
|
||||
@ -272,7 +272,7 @@ export default Ember.Controller.extend(BufferedContent, {
|
||||
const quoteState = this.get('quoteState');
|
||||
const postStream = this.get('model.postStream');
|
||||
|
||||
if (!postStream) return;
|
||||
if (!postStream || !topic || !topic.get('details.can_create_post')) { return; }
|
||||
|
||||
const quotedPost = postStream.findLoadedPost(quoteState.postId);
|
||||
const quotedText = Quote.build(quotedPost, quoteState.buffer);
|
||||
|
||||
@ -55,7 +55,9 @@ export default {
|
||||
node = node[segs[i]];
|
||||
}
|
||||
|
||||
node[segs[segs.length-1]] = v;
|
||||
if (typeof node === "object") {
|
||||
node[segs[segs.length-1]] = v;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ export default {
|
||||
}
|
||||
|
||||
// don't track links in quotes or in elided part
|
||||
if ($link.parents('aside.quote,.elided').length) { return true; }
|
||||
let tracking = $link.parents('aside.quote,.elided').length === 0;
|
||||
|
||||
let href = $link.attr('href') || $link.data('href');
|
||||
|
||||
@ -39,26 +39,31 @@ export default {
|
||||
const userId = $link.data('user-id') || $article.data('user-id');
|
||||
const ownLink = userId && (userId === Discourse.User.currentProp('id'));
|
||||
|
||||
let trackingUrl = Discourse.getURL('/clicks/track?url=' + encodeURIComponent(href));
|
||||
let destUrl = href;
|
||||
|
||||
if (postId && !$link.data('ignore-post-id')) {
|
||||
trackingUrl += "&post_id=" + encodeURI(postId);
|
||||
}
|
||||
if (topicId) {
|
||||
trackingUrl += "&topic_id=" + encodeURI(topicId);
|
||||
}
|
||||
if (tracking) {
|
||||
|
||||
// Update badge clicks unless it's our own
|
||||
if (!ownLink) {
|
||||
const $badge = $('span.badge', $link);
|
||||
if ($badge.length === 1) {
|
||||
// don't update counts in category badge nor in oneboxes (except when we force it)
|
||||
if (isValidLink($link)) {
|
||||
const html = $badge.html();
|
||||
const key = `${new Date().toLocaleDateString()}-${postId}-${href}`;
|
||||
if (/^\d+$/.test(html) && !sessionStorage.getItem(key)) {
|
||||
sessionStorage.setItem(key, true);
|
||||
$badge.html(parseInt(html, 10) + 1);
|
||||
destUrl = Discourse.getURL('/clicks/track?url=' + encodeURIComponent(href));
|
||||
|
||||
if (postId && !$link.data('ignore-post-id')) {
|
||||
destUrl += "&post_id=" + encodeURI(postId);
|
||||
}
|
||||
if (topicId) {
|
||||
destUrl += "&topic_id=" + encodeURI(topicId);
|
||||
}
|
||||
|
||||
// Update badge clicks unless it's our own
|
||||
if (!ownLink) {
|
||||
const $badge = $('span.badge', $link);
|
||||
if ($badge.length === 1) {
|
||||
// don't update counts in category badge nor in oneboxes (except when we force it)
|
||||
if (isValidLink($link)) {
|
||||
const html = $badge.html();
|
||||
const key = `${new Date().toLocaleDateString()}-${postId}-${href}`;
|
||||
if (/^\d+$/.test(html) && !sessionStorage.getItem(key)) {
|
||||
sessionStorage.setItem(key, true);
|
||||
$badge.html(parseInt(html, 10) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -66,12 +71,12 @@ export default {
|
||||
|
||||
// If they right clicked, change the destination href
|
||||
if (e.which === 3) {
|
||||
$link.attr('href', Discourse.SiteSettings.track_external_right_clicks ? trackingUrl : href);
|
||||
$link.attr('href', Discourse.SiteSettings.track_external_right_clicks ? destUrl : href);
|
||||
return true;
|
||||
}
|
||||
|
||||
// if they want to open in a new tab, do an AJAX request
|
||||
if (wantsNewWindow(e)) {
|
||||
if (tracking && wantsNewWindow(e)) {
|
||||
ajax("/clicks/track", {
|
||||
data: {
|
||||
url: href,
|
||||
@ -109,7 +114,7 @@ export default {
|
||||
}
|
||||
|
||||
// If we're on the same site, use the router and track via AJAX
|
||||
if (DiscourseURL.isInternal(href) && !$link.hasClass('attachment')) {
|
||||
if (tracking && DiscourseURL.isInternal(href) && !$link.hasClass('attachment')) {
|
||||
ajax("/clicks/track", {
|
||||
data: {
|
||||
url: href,
|
||||
@ -125,9 +130,9 @@ export default {
|
||||
|
||||
// Otherwise, use a custom URL with a redirect
|
||||
if (Discourse.User.currentProp('external_links_in_new_tab')) {
|
||||
window.open(trackingUrl, '_blank').focus();
|
||||
window.open(destUrl, '_blank').focus();
|
||||
} else {
|
||||
DiscourseURL.redirectTo(trackingUrl);
|
||||
DiscourseURL.redirectTo(destUrl);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@ -310,8 +310,10 @@ export function number(val) {
|
||||
if (val > 999999) {
|
||||
formattedNumber = I18n.toNumber(val / 1000000, {precision: 1});
|
||||
return I18n.t("number.short.millions", {number: formattedNumber});
|
||||
}
|
||||
if (val > 999) {
|
||||
} else if (val > 99999) {
|
||||
formattedNumber = I18n.toNumber(val / 1000, {precision: 0});
|
||||
return I18n.t("number.short.thousands", {number: formattedNumber});
|
||||
} else if (val > 999) {
|
||||
formattedNumber = I18n.toNumber(val / 1000, {precision: 1});
|
||||
return I18n.t("number.short.thousands", {number: formattedNumber});
|
||||
}
|
||||
|
||||
@ -169,7 +169,9 @@ export default {
|
||||
},
|
||||
|
||||
createTopic() {
|
||||
this.container.lookup('controller:composer').open({action: Composer.CREATE_TOPIC, draftKey: Composer.CREATE_TOPIC});
|
||||
if (this.currentUser && this.currentUser.can_create_topic) {
|
||||
this.container.lookup('controller:composer').open({action: Composer.CREATE_TOPIC, draftKey: Composer.CREATE_TOPIC});
|
||||
}
|
||||
},
|
||||
|
||||
pinUnpinTopic() {
|
||||
|
||||
@ -2,13 +2,15 @@ import { ajax } from 'discourse/lib/ajax';
|
||||
import { userPath } from 'discourse/lib/url';
|
||||
import { formatUsername } from 'discourse/lib/utilities';
|
||||
|
||||
let maxGroupMention;
|
||||
|
||||
function replaceSpan($e, username, opts) {
|
||||
let extra = "";
|
||||
let extraClass = "";
|
||||
|
||||
if (opts && opts.group) {
|
||||
if (opts.mentionable) {
|
||||
extra = `data-name='${username}' data-mentionable-user-count='${opts.mentionable.user_count}'`;
|
||||
extra = `data-name='${username}' data-mentionable-user-count='${opts.mentionable.user_count}' data-max-mentions='${maxGroupMention}'`;
|
||||
extraClass = "notify";
|
||||
}
|
||||
$e.replaceWith(`<a href='${Discourse.getURL("/groups/") + username}' class='mention-group ${extraClass}' ${extra}>@${username}</a>`);
|
||||
@ -61,6 +63,7 @@ export function fetchUnseenMentions(usernames, topic_id) {
|
||||
r.valid_groups.forEach(vg => foundGroups[vg] = true);
|
||||
r.mentionable_groups.forEach(mg => mentionableGroups[mg.name] = mg);
|
||||
r.cannot_see.forEach(cs => cannotSee[cs] = true);
|
||||
maxGroupMention = r.max_users_notified_per_group_mention;
|
||||
usernames.forEach(u => checked[u] = true);
|
||||
return r;
|
||||
});
|
||||
|
||||
@ -2,17 +2,23 @@ import parseHTML from 'discourse/helpers/parse-html';
|
||||
|
||||
const trimLeft = text => text.replace(/^\s+/,"");
|
||||
const trimRight = text => text.replace(/\s+$/,"");
|
||||
const countPipes = text => text.replace(/\\\|/,"").match(/\|/g).length;
|
||||
|
||||
class Tag {
|
||||
constructor(name, prefix = "", suffix = "") {
|
||||
constructor(name, prefix = "", suffix = "", inline = false) {
|
||||
this.name = name;
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.inline = inline;
|
||||
}
|
||||
|
||||
decorate(text) {
|
||||
if (this.prefix || this.suffix) {
|
||||
return [this.prefix, text, this.suffix].join("");
|
||||
text = [this.prefix, text, this.suffix].join("");
|
||||
}
|
||||
|
||||
if (this.inline) {
|
||||
text = " " + text + " ";
|
||||
}
|
||||
|
||||
return text;
|
||||
@ -30,7 +36,7 @@ class Tag {
|
||||
|
||||
static blocks() {
|
||||
return ["address", "article", "aside", "dd", "div", "dl", "dt", "fieldset", "figcaption", "figure",
|
||||
"footer", "form", "header", "hgroup", "hr", "main", "nav", "p", "pre", "section", "ul"];
|
||||
"footer", "form", "header", "hgroup", "hr", "main", "nav", "p", "pre", "section"];
|
||||
}
|
||||
|
||||
static headings() {
|
||||
@ -38,25 +44,26 @@ class Tag {
|
||||
}
|
||||
|
||||
static emphases() {
|
||||
return [ ["b", "**"], ["strong", "**"], ["i", "_"], ["em", "_"], ["s", "~~"], ["strike", "~~"] ];
|
||||
return [ ["b", "**"], ["strong", "**"], ["i", "*"], ["em", "*"], ["s", "~~"], ["strike", "~~"] ];
|
||||
}
|
||||
|
||||
static slices() {
|
||||
return ["dt", "dd", "tr", "thead", "tbody", "tfoot"];
|
||||
return ["dt", "dd", "thead", "tbody", "tfoot"];
|
||||
}
|
||||
|
||||
static trimmable() {
|
||||
return [...Tag.blocks(), ...Tag.headings(), ...Tag.slices(), "li", "td", "th", "br", "hr", "blockquote", "table", "ol"];
|
||||
return [...Tag.blocks(), ...Tag.headings(), ...Tag.slices(), "li", "td", "th", "br", "hr", "blockquote", "table", "ol", "tr", "ul"];
|
||||
}
|
||||
|
||||
static block(name, prefix, suffix) {
|
||||
return class extends Tag {
|
||||
constructor() {
|
||||
super(name, prefix, suffix);
|
||||
this.gap = "\n\n";
|
||||
}
|
||||
|
||||
decorate(text) {
|
||||
return `\n\n${this.prefix}${text}${this.suffix}\n\n`;
|
||||
return `${this.gap}${this.prefix}${text}${this.suffix}${this.gap}`;
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -69,18 +76,21 @@ class Tag {
|
||||
static emphasis(name, decorator) {
|
||||
return class extends Tag {
|
||||
constructor() {
|
||||
super(name, decorator, decorator);
|
||||
super(name, decorator, decorator, true);
|
||||
}
|
||||
|
||||
decorate(text) {
|
||||
text = text.trim();
|
||||
|
||||
if (text.includes("\n")) {
|
||||
this.prefix = `<${this.name}>`;
|
||||
this.suffix = `</${this.name}>`;
|
||||
}
|
||||
|
||||
return super.decorate(text);
|
||||
let space = text.match(/^\s/) || [""];
|
||||
this.prefix = space[0] + this.prefix;
|
||||
space = text.match(/\s$/) || [""];
|
||||
this.suffix = this.suffix + space[0];
|
||||
|
||||
return super.decorate(text.trim());
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -109,7 +119,7 @@ class Tag {
|
||||
static link() {
|
||||
return class extends Tag {
|
||||
constructor() {
|
||||
super("a");
|
||||
super("a", "", "", true);
|
||||
}
|
||||
|
||||
decorate(text) {
|
||||
@ -128,7 +138,7 @@ class Tag {
|
||||
static image() {
|
||||
return class extends Tag {
|
||||
constructor() {
|
||||
super("img");
|
||||
super("img", "", "", true);
|
||||
}
|
||||
|
||||
toMarkdown() {
|
||||
@ -143,7 +153,8 @@ class Tag {
|
||||
const height = attr.height || pAttr.height;
|
||||
|
||||
if (width && height) {
|
||||
alt = `${alt}|${width}x${height}`;
|
||||
const pipe = this.element.parentNames.includes("table") ? "\\|" : "|";
|
||||
alt = `${alt}${pipe}${width}x${height}`;
|
||||
}
|
||||
|
||||
return "";
|
||||
@ -178,14 +189,10 @@ class Tag {
|
||||
toMarkdown() {
|
||||
const text = this.element.innerMarkdown().trim();
|
||||
|
||||
if (text.includes("\n") || text.includes("[![")) {
|
||||
if (text.includes("\n")) {
|
||||
throw "Unsupported format inside Markdown table cells";
|
||||
}
|
||||
|
||||
if (!this.element.next) {
|
||||
this.suffix = "|";
|
||||
}
|
||||
|
||||
return this.decorate(text);
|
||||
}
|
||||
};
|
||||
@ -194,7 +201,7 @@ class Tag {
|
||||
static li() {
|
||||
return class extends Tag.slice("li", "\n") {
|
||||
decorate(text) {
|
||||
const indent = this.element.filterParentNames(["ol", "ul"]).slice(1).map(() => " ").join("");
|
||||
const indent = this.element.filterParentNames(["ol", "ul"]).slice(1).map(() => "\t").join("");
|
||||
return super.decorate(`${indent}* ${trimLeft(text)}`);
|
||||
}
|
||||
};
|
||||
@ -210,6 +217,8 @@ class Tag {
|
||||
if (this.element.parentNames.includes("pre")) {
|
||||
this.prefix = '\n\n```\n';
|
||||
this.suffix = '\n```\n\n';
|
||||
} else {
|
||||
this.inline = true;
|
||||
}
|
||||
|
||||
text = $('<textarea />').html(text).text();
|
||||
@ -234,19 +243,45 @@ class Tag {
|
||||
static table() {
|
||||
return class extends Tag.block("table") {
|
||||
decorate(text) {
|
||||
text = super.decorate(text);
|
||||
const splitterRow = text.split("|\n")[0].match(/\|/g).map(() => "| --- ").join("") + "|\n";
|
||||
text = text.replace("|\n", "|\n" + splitterRow).replace(/\|\n{2,}\|/g, "|\n|");
|
||||
text = super.decorate(text).replace(/\|\n{2,}\|/g, "|\n|");
|
||||
const rows = text.trim().split("\n");
|
||||
const pipeCount = countPipes(rows[0]);
|
||||
const isValid = rows.length > 1 &&
|
||||
pipeCount > 2 &&
|
||||
rows.reduce((a, c) => a && countPipes(c) <= pipeCount);
|
||||
|
||||
if (!isValid) {
|
||||
throw "Unsupported table format for Markdown conversion";
|
||||
}
|
||||
|
||||
const splitterRow = [...Array(pipeCount-1)].map(() => "| --- ").join("") + "|\n";
|
||||
text = text.replace("|\n", "|\n" + splitterRow);
|
||||
|
||||
return text;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static list(name) {
|
||||
return class extends Tag.block(name) {
|
||||
decorate(text) {
|
||||
let smallGap = "";
|
||||
|
||||
if (this.element.filterParentNames(["li"]).length) {
|
||||
this.gap = "";
|
||||
smallGap = "\n";
|
||||
}
|
||||
|
||||
return smallGap + super.decorate(trimRight(text));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static ol() {
|
||||
return class extends Tag.block("ol") {
|
||||
return class extends Tag.list("ol") {
|
||||
decorate(text) {
|
||||
text = "\n" + text;
|
||||
const bullet = text.match(/\n *\*/)[0];
|
||||
const bullet = text.match(/\n\t*\*/)[0];
|
||||
|
||||
for (let i = parseInt(this.element.attributes.start || 1); text.includes(bullet); i++) {
|
||||
text = text.replace(bullet, bullet.replace("*", `${i}.`));
|
||||
@ -257,6 +292,17 @@ class Tag {
|
||||
};
|
||||
}
|
||||
|
||||
static tr() {
|
||||
return class extends Tag.slice("tr", "|\n") {
|
||||
decorate(text) {
|
||||
if (!this.element.next) {
|
||||
this.suffix = "|";
|
||||
}
|
||||
return `${text}${this.suffix}`;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const tags = [
|
||||
@ -267,7 +313,7 @@ const tags = [
|
||||
Tag.cell("td"), Tag.cell("th"),
|
||||
Tag.replace("br", "\n"), Tag.replace("hr", "\n---\n"), Tag.replace("head", ""),
|
||||
Tag.keep("ins"), Tag.keep("del"), Tag.keep("small"), Tag.keep("big"),
|
||||
Tag.li(), Tag.link(), Tag.image(), Tag.code(), Tag.blockquote(), Tag.table(),, Tag.ol(),
|
||||
Tag.li(), Tag.link(), Tag.image(), Tag.code(), Tag.blockquote(), Tag.table(), Tag.tr(), Tag.ol(), Tag.list("ul"),
|
||||
];
|
||||
|
||||
class Element {
|
||||
@ -364,6 +410,19 @@ class Element {
|
||||
}
|
||||
}
|
||||
|
||||
function trimUnwantedSpaces(html) {
|
||||
const body = html.match(/<body[^>]*>([\s\S]*?)<\/body>/);
|
||||
html = body ? body[1] : html;
|
||||
html = html.replace(/\r|\n| /g, " ");
|
||||
|
||||
let match;
|
||||
while (match = html.match(/<[^\s>]+[^>]*>\s{2,}<[^\s>]+[^>]*>/)) {
|
||||
html = html.replace(match[0], match[0].replace(/>\s{2,}</, "> <"));
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function putPlaceholders(html) {
|
||||
const codeRegEx = /<code[^>]*>([\s\S]*?)<\/code>/gi;
|
||||
const origHtml = html;
|
||||
@ -379,7 +438,7 @@ function putPlaceholders(html) {
|
||||
match = codeRegEx.exec(origHtml);
|
||||
}
|
||||
|
||||
const elements = parseHTML(html);
|
||||
const elements = parseHTML(trimUnwantedSpaces(html));
|
||||
return { elements, placeholders };
|
||||
}
|
||||
|
||||
@ -395,7 +454,7 @@ export default function toMarkdown(html) {
|
||||
const { elements, placeholders } = putPlaceholders(html);
|
||||
let markdown = Element.parse(elements).trim();
|
||||
markdown = markdown.replace(/^<b>/, "").replace(/<\/b>$/, "").trim(); // fix for google doc copy paste
|
||||
markdown = markdown.replace(/\r/g, "").replace(/\n \n/g, "\n\n").replace(/\n{3,}/g, "\n\n");
|
||||
markdown = markdown.replace(/\n +/g, "\n").replace(/ +\n/g, "\n").replace(/ {2,}/g, " ").replace(/\n{3,}/g, "\n\n").replace(/\t/g, " ");
|
||||
return replacePlaceholders(markdown, placeholders);
|
||||
} catch(err) {
|
||||
return "";
|
||||
|
||||
@ -334,27 +334,27 @@ export function getUploadMarkdown(upload) {
|
||||
}
|
||||
|
||||
export function displayErrorForUpload(data) {
|
||||
// deal with meaningful errors first
|
||||
if (data.jqXHR) {
|
||||
switch (data.jqXHR.status) {
|
||||
// cancelled by the user
|
||||
case 0: return;
|
||||
case 0:
|
||||
return;
|
||||
|
||||
// entity too large, usually returned from the web server
|
||||
// entity too large, usually returned from the web server
|
||||
case 413:
|
||||
var type = uploadTypeFromFileName(data.files[0].name);
|
||||
var maxSizeKB = Discourse.SiteSettings['max_' + type + '_size_kb'];
|
||||
bootbox.alert(I18n.t('post.errors.file_too_large', { max_size_kb: maxSizeKB }));
|
||||
return;
|
||||
const type = uploadTypeFromFileName(data.files[0].name);
|
||||
const max_size_kb = Discourse.SiteSettings[`max_${type}_size_kb`];
|
||||
bootbox.alert(I18n.t('post.errors.file_too_large', { max_size_kb }));
|
||||
return;
|
||||
|
||||
// the error message is provided by the server
|
||||
// the error message is provided by the server
|
||||
case 422:
|
||||
if (data.jqXHR.responseJSON.message) {
|
||||
bootbox.alert(data.jqXHR.responseJSON.message);
|
||||
} else {
|
||||
bootbox.alert(data.jqXHR.responseJSON.join("\n"));
|
||||
}
|
||||
return;
|
||||
if (data.jqXHR.responseJSON.message) {
|
||||
bootbox.alert(data.jqXHR.responseJSON.message);
|
||||
} else {
|
||||
bootbox.alert(data.jqXHR.responseJSON.join("\n"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (data.errors && data.errors.length > 0) {
|
||||
bootbox.alert(data.errors.join("\n"));
|
||||
|
||||
@ -56,7 +56,7 @@ export default Em.Mixin.create({
|
||||
});
|
||||
|
||||
$upload.on("fileuploadfail", (e, data) => {
|
||||
displayErrorForUpload(data.jqXHR.responseJSON);
|
||||
displayErrorForUpload(data);
|
||||
reset();
|
||||
});
|
||||
}.on("didInsertElement"),
|
||||
|
||||
@ -32,7 +32,10 @@ export default (viewName, path) => {
|
||||
},
|
||||
|
||||
deactivate() {
|
||||
this.searchService.set('contextType', 'private_messages');
|
||||
this.searchService.set(
|
||||
'searchContext',
|
||||
this.controllerFor("user").get("model.searchContext")
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@ -20,11 +20,11 @@ const TopicRoute = Discourse.Route.extend({
|
||||
titleToken() {
|
||||
const model = this.modelFor('topic');
|
||||
if (model) {
|
||||
const result = model.get('unicode_title') ? model.get('unicode_title') : model.get('title'),
|
||||
const result = model.get('unicode_title') || model.get('title'),
|
||||
cat = model.get('category');
|
||||
|
||||
// Only display uncategorized in the title tag if it was renamed
|
||||
if (cat && !(cat.get('isUncategorizedCategory') && cat.get('name').toLowerCase() === "uncategorized")) {
|
||||
if (this.siteSettings.topic_page_title_includes_category && cat && !(cat.get('isUncategorizedCategory') && cat.get('name').toLowerCase() === "uncategorized")) {
|
||||
let catName = cat.get('name');
|
||||
|
||||
const parentCategory = cat.get('parentCategory');
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
{{toolbar-popup-menu-options
|
||||
onPopupMenuAction=onPopupMenuAction
|
||||
onExpand=(action b.action b)
|
||||
title="composer.options"
|
||||
title=b.title
|
||||
headerIcon=b.icon
|
||||
class=b.className
|
||||
content=popupMenuOptions}}
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
{{#if category.availableGroups}}
|
||||
{{combo-box class="available-groups"
|
||||
allowInitialValueMutation=true
|
||||
allowsContentReplacement=true
|
||||
allowContentReplacement=true
|
||||
content=category.availableGroups
|
||||
value=selectedGroup}}
|
||||
{{combo-box allowInitialValueMutation=true
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
<div class='search-title clearfix'>
|
||||
<div class='result-count'>
|
||||
<span>
|
||||
{{{i18n "search.result_count" count=resultCount term=noSortQ}}}
|
||||
{{{resultCountLabel}}}
|
||||
</span>
|
||||
</div>
|
||||
<div class='sort-by'>
|
||||
|
||||
@ -3,13 +3,15 @@
|
||||
<div class="controls">
|
||||
<span class='static'>{{model.username}}</span>
|
||||
{{#if model.can_edit_username}}
|
||||
{{#link-to "preferences.username" class="btn btn-small pad-left no-text"}}
|
||||
{{#link-to "preferences.username" class="btn btn-small btn-icon pad-left no-text"}}
|
||||
{{d-icon "pencil"}} {{/link-to}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class='instructions'>
|
||||
{{{i18n 'user.username.short_instructions' username=model.username}}}
|
||||
</div>
|
||||
{{#if siteSettings.enable_mentions}}
|
||||
<div class='instructions'>
|
||||
{{{i18n 'user.username.short_instructions' username=model.username}}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{#if canEditName}}
|
||||
@ -35,7 +37,7 @@
|
||||
<div class="controls">
|
||||
<span class='static'>{{model.email}}</span>
|
||||
{{#if model.can_edit_email}}
|
||||
{{#link-to "preferences.email" class="btn btn-small pad-left no-text"}}{{d-icon "pencil"}}{{/link-to}}
|
||||
{{#link-to "preferences.email" class="btn btn-small btn-icon pad-left no-text"}}{{d-icon "pencil"}}{{/link-to}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class='instructions'>
|
||||
@ -82,22 +84,24 @@
|
||||
<label class="control-label">{{i18n 'user.title.title'}}</label>
|
||||
<div class="controls">
|
||||
<span class="static">{{model.title}}</span>
|
||||
{{#link-to "preferences.badgeTitle" class="btn btn-small pad-left no-text"}}{{d-icon "pencil"}}{{/link-to}}
|
||||
{{#link-to "preferences.badgeTitle" class="btn btn-small btn-icon pad-left no-text"}}{{d-icon "pencil"}}{{/link-to}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{plugin-outlet name="user-preferences-account" args=(hash model=model)}}
|
||||
{{plugin-outlet name="user-preferences-account" args=(hash model=model save=(action "save"))}}
|
||||
|
||||
<br/>
|
||||
|
||||
{{plugin-outlet name="user-custom-controls" args=(hash model=model)}}
|
||||
|
||||
<div class="control-group save-button">
|
||||
<div class="controls">
|
||||
{{partial 'user/preferences/save-button'}}
|
||||
{{#if canSaveUser}}
|
||||
<div class="control-group save-button">
|
||||
<div class="controls">
|
||||
{{partial 'user/preferences/save-button'}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
|
||||
{{#if model.canDeleteAccount}}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<div class="control-group notifications">
|
||||
<div class="controls controls-dropdown">
|
||||
<label>{{i18n 'user.new_topic_duration.label'}}</label>
|
||||
{{combo-box valueAttribute="value" content=considerNewTopicOptions value=model.user_option.new_topic_duration_minutes}}
|
||||
{{combo-box class="duration" valueAttribute="value" content=considerNewTopicOptions value=model.user_option.new_topic_duration_minutes}}
|
||||
</div>
|
||||
|
||||
<div class="controls controls-dropdown">
|
||||
|
||||
@ -191,7 +191,7 @@
|
||||
{{#if showBadges}}
|
||||
<li>{{#link-to 'user.badges'}}{{d-icon "certificate"}}{{i18n 'badges.title'}}{{/link-to}}</li>
|
||||
{{/if}}
|
||||
{{plugin-outlet name="user-main-nav" connectorTagName='li' args=(hash model=model)}}
|
||||
{{plugin-outlet name="user-main-nav" tagName='' connectorTagName='li' args=(hash model=model)}}
|
||||
{{#if model.can_edit}}
|
||||
<li>{{#link-to 'preferences'}}{{d-icon "cog"}}{{i18n 'user.preferences'}}{{/link-to}}</li>
|
||||
{{/if}}
|
||||
|
||||
@ -119,6 +119,23 @@ createWidget('actions-summary-item', {
|
||||
}
|
||||
});
|
||||
|
||||
createWidget('deleted-post', {
|
||||
tagName: 'div.post-action.deleted-post',
|
||||
|
||||
html(attrs) {
|
||||
return [
|
||||
iconNode('trash-o'),
|
||||
' ',
|
||||
avatarFor.call(this, 'small', {
|
||||
template: attrs.deletedByAvatarTemplate,
|
||||
username: attrs.deletedByUsername
|
||||
}),
|
||||
' ',
|
||||
dateNode(attrs.deleted_at)
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
export default createWidget('actions-summary', {
|
||||
tagName: 'section.post-actions',
|
||||
|
||||
@ -131,16 +148,7 @@ export default createWidget('actions-summary', {
|
||||
});
|
||||
|
||||
if (attrs.deleted_at) {
|
||||
body.push(h('div.post-action', [
|
||||
iconNode('trash-o'),
|
||||
' ',
|
||||
avatarFor.call(this, 'small', {
|
||||
template: attrs.deletedByAvatarTemplate,
|
||||
username: attrs.deletedByUsername
|
||||
}),
|
||||
' ',
|
||||
dateNode(attrs.deleted_at)
|
||||
]));
|
||||
body.push(this.attach('deleted-post', attrs));
|
||||
}
|
||||
|
||||
return body;
|
||||
|
||||
@ -3,6 +3,12 @@ import { createWidget } from 'discourse/widgets/widget';
|
||||
import { h } from 'virtual-dom';
|
||||
|
||||
createWidget('menu-links', {
|
||||
buildClasses(attrs) {
|
||||
if (attrs.name && attrs.name.length) {
|
||||
return `menu-container-${attrs.name}`;
|
||||
}
|
||||
},
|
||||
|
||||
html(attrs) {
|
||||
const links = [].concat(attrs.contents());
|
||||
const liOpts = {};
|
||||
|
||||
@ -16,7 +16,7 @@ export function buildManageButtons(attrs, currentUser) {
|
||||
}
|
||||
|
||||
let contents = [];
|
||||
if (attrs.canManage) {
|
||||
if (currentUser.staff) {
|
||||
contents.push({
|
||||
icon: 'list',
|
||||
label: 'admin.flags.moderation_history',
|
||||
|
||||
@ -185,11 +185,13 @@ export default createWidget('topic-admin-menu', {
|
||||
label: isPrivateMessage ? 'actions.make_public' : 'actions.make_private' });
|
||||
}
|
||||
|
||||
buttons.push({
|
||||
action: 'showModerationHistory',
|
||||
icon: 'list',
|
||||
fullLabel: 'admin.flags.moderation_history'
|
||||
});
|
||||
if (this.currentUser.get('staff')) {
|
||||
buttons.push({
|
||||
action: 'showModerationHistory',
|
||||
icon: 'list',
|
||||
fullLabel: 'admin.flags.moderation_history'
|
||||
});
|
||||
}
|
||||
|
||||
const extraButtons = applyDecorators(this, 'adminMenuButtons', this.attrs, this.state);
|
||||
|
||||
|
||||
@ -50,7 +50,9 @@ class Ruler {
|
||||
|
||||
getRuleForTag(tag) {
|
||||
this.ensureCache();
|
||||
return this.cache[tag];
|
||||
if (this.cache.hasOwnProperty(tag)) {
|
||||
return this.cache[tag];
|
||||
}
|
||||
}
|
||||
|
||||
ensureCache() {
|
||||
|
||||
@ -7,10 +7,15 @@ export default MultiSelectComponent.extend({
|
||||
filterable: true,
|
||||
allowAny: false,
|
||||
rowComponent: "category-row",
|
||||
categories: null,
|
||||
blacklist: null,
|
||||
|
||||
init() {
|
||||
this._super();
|
||||
|
||||
if (!this.get("categories")) this.set("categories", []);
|
||||
if (!this.get("blacklist")) this.set("blacklist", []);
|
||||
|
||||
this.get("headerComponentOptions").setProperties({
|
||||
selectedNameComponent: "multi-select/selected-category"
|
||||
});
|
||||
|
||||
@ -4,6 +4,5 @@ export default SelectKitRowComponent.extend({
|
||||
layoutName: "select-kit/templates/components/dropdown-select-box/dropdown-select-box-row",
|
||||
classNames: "dropdown-select-box-row",
|
||||
|
||||
name: Ember.computed.alias("computedContent.name"),
|
||||
description: Ember.computed.alias("computedContent.originalContent.description")
|
||||
});
|
||||
|
||||
@ -116,6 +116,7 @@ export default SelectKitComponent.extend({
|
||||
|
||||
baseHeaderComputedContent() {
|
||||
return {
|
||||
title: this.get("title"),
|
||||
selectedComputedContents: this.get("selectedComputedContents")
|
||||
};
|
||||
},
|
||||
|
||||
@ -3,14 +3,23 @@ import computed from "ember-addons/ember-computed-decorators";
|
||||
import SelectKitHeaderComponent from "select-kit/components/select-kit/select-kit-header";
|
||||
|
||||
export default SelectKitHeaderComponent.extend({
|
||||
attributeBindings: ["names:data-name"],
|
||||
attributeBindings: [
|
||||
"label:title",
|
||||
"label:aria-label",
|
||||
"names:data-name",
|
||||
"values:data-value"
|
||||
],
|
||||
classNames: "multi-select-header",
|
||||
layoutName: "select-kit/templates/components/multi-select/multi-select-header",
|
||||
selectedNameComponent: Ember.computed.alias("options.selectedNameComponent"),
|
||||
|
||||
ariaLabel: Ember.computed.or("computedContent.ariaLabel", "title", "names"),
|
||||
|
||||
title: Ember.computed.or("computedContent.title", "names"),
|
||||
|
||||
@on("didRender")
|
||||
_positionFilter() {
|
||||
if (this.get("shouldDisplayFilter") === false) { return; }
|
||||
if (!this.get("shouldDisplayFilter")) return;
|
||||
|
||||
const $filter = this.$(".filter");
|
||||
$filter.width(0);
|
||||
@ -26,7 +35,12 @@ export default SelectKitHeaderComponent.extend({
|
||||
},
|
||||
|
||||
@computed("computedContent.selectedComputedContents.[]")
|
||||
names(selectedComputedContents) {
|
||||
return Ember.makeArray(selectedComputedContents).map(sc => sc.name).join(",");
|
||||
names(selection) {
|
||||
return Ember.makeArray(selection).map(s => s.name).join(",");
|
||||
},
|
||||
|
||||
@computed("computedContent.selectedComputedContents.[]")
|
||||
values(selection) {
|
||||
return Ember.makeArray(selection).map(s => s.value).join(",");
|
||||
}
|
||||
});
|
||||
|
||||
@ -6,8 +6,9 @@ export default SelectedNameComponent.extend({
|
||||
classNames: "selected-category",
|
||||
layoutName: "select-kit/templates/components/multi-select/selected-category",
|
||||
|
||||
@computed("content.originalContent")
|
||||
@computed("computedContent.originalContent")
|
||||
badge(category) {
|
||||
return categoryBadgeHTML(category, {allowUncategorized: true, link: false}).htmlSafe();
|
||||
return categoryBadgeHTML(category, { allowUncategorized: true, link: false })
|
||||
.htmlSafe();
|
||||
}
|
||||
});
|
||||
|
||||
@ -5,7 +5,7 @@ export default SelectedNameComponent.extend({
|
||||
layoutName: "select-kit/templates/components/multi-select/selected-color",
|
||||
|
||||
didRender() {
|
||||
const name = this.get("content.name");
|
||||
const name = this.get("name");
|
||||
this.$(".color-preview").css("background", `#${name}`.htmlSafe());
|
||||
}
|
||||
});
|
||||
|
||||
@ -3,8 +3,10 @@ import computed from "ember-addons/ember-computed-decorators";
|
||||
export default Ember.Component.extend({
|
||||
attributeBindings: [
|
||||
"tabindex",
|
||||
"content.name:data-name",
|
||||
"content.value:data-value",
|
||||
"ariaLabel:aria-label",
|
||||
"title",
|
||||
"name:data-name",
|
||||
"value:data-value",
|
||||
"guid:data-guid"
|
||||
],
|
||||
classNames: ["selected-name", "choice"],
|
||||
@ -13,11 +15,27 @@ export default Ember.Component.extend({
|
||||
tagName: "span",
|
||||
tabindex: -1,
|
||||
|
||||
@computed("content")
|
||||
guid(content) { return Ember.guidFor(content); },
|
||||
@computed("computedContent")
|
||||
guid(computedContent) { return Ember.guidFor(computedContent); },
|
||||
|
||||
isLocked: Ember.computed("content.locked", function() {
|
||||
return this.getWithDefault("content.locked", false);
|
||||
ariaLabel: Ember.computed.or("computedContent.ariaLabel", "title"),
|
||||
|
||||
@computed("computedContent.title", "name")
|
||||
title(computedContentTitle, name) {
|
||||
if (computedContentTitle) return computedContentTitle;
|
||||
if (name) return name;
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
label: Ember.computed.or("computedContent.label", "title", "name"),
|
||||
|
||||
name: Ember.computed.alias("computedContent.name"),
|
||||
|
||||
value: Ember.computed.alias("computedContent.value"),
|
||||
|
||||
isLocked: Ember.computed("computedContent.locked", function() {
|
||||
return this.getWithDefault("computedContent.locked", false);
|
||||
}),
|
||||
|
||||
click() {
|
||||
|
||||
@ -17,8 +17,9 @@ export default DropdownSelectBoxComponent.extend({
|
||||
const state = pinned ? `pinned${globally}` : "unpinned";
|
||||
const title = I18n.t(`topic_statuses.${state}.title`);
|
||||
|
||||
content.name = `${title}${iconHTML("caret-down")}`.htmlSafe();
|
||||
content.dataName = title;
|
||||
content.label = `${title}${iconHTML("caret-down")}`.htmlSafe();
|
||||
content.title = title;
|
||||
content.name = state;
|
||||
content.icon = `thumb-tack${state === "unpinned" ? " unpinned" : ''}`;
|
||||
return content;
|
||||
},
|
||||
|
||||
@ -29,7 +29,6 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi
|
||||
renderedBodyOnce: false,
|
||||
renderedFilterOnce: false,
|
||||
tabindex: 0,
|
||||
scrollableParentSelector: ".modal-body",
|
||||
none: null,
|
||||
highlightedValue: null,
|
||||
noContentLabel: "select_kit.no_content",
|
||||
@ -61,15 +60,13 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi
|
||||
computedContent: null,
|
||||
limitMatches: 100,
|
||||
nameChanges: false,
|
||||
allowsContentReplacement: false,
|
||||
allowContentReplacement: false,
|
||||
collectionHeader: null,
|
||||
|
||||
init() {
|
||||
this._super();
|
||||
|
||||
this.noneValue = "__none__";
|
||||
this._previousScrollParentOverflow = "auto";
|
||||
this._previousCSSContext = {};
|
||||
this.set("headerComponentOptions", Ember.Object.create());
|
||||
this.set("rowComponentOptions", Ember.Object.create());
|
||||
this.set("computedContent", []);
|
||||
@ -82,7 +79,7 @@ export default Ember.Component.extend(UtilsMixin, PluginApiMixin, DomHelpersMixi
|
||||
this.addObserver(`content.@each.${this.get("nameProperty")}`, this, this._compute);
|
||||
}
|
||||
|
||||
if (this.get("allowsContentReplacement")) {
|
||||
if (this.get("allowContentReplacement")) {
|
||||
this.addObserver(`content.[]`, this, this._compute);
|
||||
}
|
||||
},
|
||||
|
||||
@ -5,32 +5,37 @@ export default Ember.Component.extend({
|
||||
classNames: ["select-kit-header", "select-box-kit-header"],
|
||||
classNameBindings: ["isFocused"],
|
||||
attributeBindings: [
|
||||
"dataName:data-name",
|
||||
"tabindex",
|
||||
"ariaLabel:aria-label",
|
||||
"ariaHasPopup:aria-haspopup",
|
||||
"title"
|
||||
"title",
|
||||
"value:data-value",
|
||||
"name:data-name",
|
||||
],
|
||||
|
||||
ariaHasPopup: true,
|
||||
|
||||
ariaLabel: Ember.computed.alias("title"),
|
||||
ariaLabel: Ember.computed.or("computedContent.ariaLabel", "title"),
|
||||
|
||||
@computed("computedContent.title", "name")
|
||||
title(computedContentTitle, name) {
|
||||
if (computedContentTitle) return computedContentTitle;
|
||||
if (name) return name;
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
label: Ember.computed.or("computedContent.label", "title", "name"),
|
||||
|
||||
name: Ember.computed.alias("computedContent.name"),
|
||||
|
||||
value: Ember.computed.alias("computedContent.value"),
|
||||
|
||||
@computed("computedContent.icon", "computedContent.icons")
|
||||
icons(icon, icons) {
|
||||
return Ember.makeArray(icon).concat(icons).filter(i => !Ember.isEmpty(i));
|
||||
},
|
||||
|
||||
@computed("computedContent.dataName", "name")
|
||||
dataName(dataName, name) { return dataName || name; },
|
||||
|
||||
@computed("title", "computedContent.title", "name")
|
||||
title(title, computedContentTitle, name) {
|
||||
return title || computedContentTitle || name;
|
||||
},
|
||||
|
||||
click() {
|
||||
this.sendAction("onToggle");
|
||||
}
|
||||
|
||||
@ -11,23 +11,35 @@ export default Ember.Component.extend(UtilsMixin, {
|
||||
attributeBindings: [
|
||||
"tabIndex",
|
||||
"title",
|
||||
"computedContent.value:data-value",
|
||||
"computedContent.name:data-name"
|
||||
"value:data-value",
|
||||
"name:data-name",
|
||||
"ariaLabel:aria-label"
|
||||
],
|
||||
classNameBindings: ["isHighlighted", "isSelected"],
|
||||
|
||||
@computed("computedContent.title", "computedContent.name")
|
||||
title(title, name) { return title || name; },
|
||||
ariaLabel: Ember.computed.or("computedContent.ariaLabel", "title"),
|
||||
|
||||
@computed("computedContent.title", "name")
|
||||
title(computedContentTitle, name) {
|
||||
if (computedContentTitle) return computedContentTitle;
|
||||
if (name) return name;
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
label: Ember.computed.or("computedContent.label", "title", "name"),
|
||||
|
||||
name: Ember.computed.alias("computedContent.name"),
|
||||
|
||||
value: Ember.computed.alias("computedContent.value"),
|
||||
|
||||
@computed("templateForRow")
|
||||
template(templateForRow) { return templateForRow(this); },
|
||||
|
||||
@on("didReceiveAttrs")
|
||||
_setSelectionState() {
|
||||
const contentValue = this.get("computedContent.value");
|
||||
|
||||
this.set("isSelected", this.get("computedValue") === contentValue);
|
||||
this.set("isHighlighted", this.get("highlightedValue") === contentValue);
|
||||
this.set("isSelected", this.get("computedValue") === this.get("value"));
|
||||
this.set("isHighlighted", this.get("highlightedValue") === this.get("value"));
|
||||
},
|
||||
|
||||
@on("willDestroyElement")
|
||||
|
||||
@ -78,7 +78,9 @@ export default SelectKitComponent.extend({
|
||||
|
||||
baseHeaderComputedContent() {
|
||||
return {
|
||||
title: this.get("title"),
|
||||
icons: Ember.makeArray(this.getWithDefault("headerIcon", [])),
|
||||
value: this.get("selectedComputedContent.value"),
|
||||
name: this.get("selectedComputedContent.name") || this.get("noneRowComputedContent.name")
|
||||
};
|
||||
},
|
||||
|
||||
@ -10,7 +10,7 @@ export default DropdownSelectBoxComponent.extend({
|
||||
|
||||
@computed("title")
|
||||
collectionHeader(title) {
|
||||
return `<h3>${I18n.t(title)}</h3>`;
|
||||
return `<h3>${title}</h3>`;
|
||||
},
|
||||
|
||||
mutateValue(value) {
|
||||
|
||||
@ -4,12 +4,16 @@ export default Ember.Mixin.create({
|
||||
init() {
|
||||
this._super();
|
||||
|
||||
this._previousScrollParentOverflow = null;
|
||||
this._previousCSSContext = null;
|
||||
this.filterInputSelector = ".filter-input";
|
||||
this.rowSelector = ".select-kit-row";
|
||||
this.collectionSelector = ".select-kit-collection";
|
||||
this.headerSelector = ".select-kit-header";
|
||||
this.bodySelector = ".select-kit-body";
|
||||
this.wrapperSelector = ".select-kit-wrapper";
|
||||
this.scrollableParentSelector = ".modal-body";
|
||||
this.fixedPlaceholderSelector = `.select-kit-fixed-placeholder-${this.elementId}`;
|
||||
},
|
||||
|
||||
$findRowByValue(value) { return this.$(`${this.rowSelector}[data-value='${value}']`); },
|
||||
@ -18,15 +22,16 @@ export default Ember.Mixin.create({
|
||||
|
||||
$body() { return this.$(this.bodySelector); },
|
||||
|
||||
$wrapper() { return this.$(this.wrapperSelector); },
|
||||
|
||||
$collection() { return this.$(this.collectionSelector); },
|
||||
|
||||
$rows(withHidden) {
|
||||
$scrollableParent() { return $(this.scrollableParentSelector); },
|
||||
|
||||
if (withHidden === true) {
|
||||
return this.$(`${this.rowSelector}:not(.no-content)`);
|
||||
} else {
|
||||
return this.$(`${this.rowSelector}:not(.no-content):not(.is-hidden)`);
|
||||
}
|
||||
$fixedPlaceholder() { return $(this.fixedPlaceholderSelector); },
|
||||
|
||||
$rows() {
|
||||
return this.$(`${this.rowSelector}:not(.no-content):not(.is-hidden)`);
|
||||
},
|
||||
|
||||
$highlightedRow() { return this.$rows().filter(".is-highlighted"); },
|
||||
@ -36,8 +41,7 @@ export default Ember.Mixin.create({
|
||||
$filterInput() { return this.$(this.filterInputSelector); },
|
||||
|
||||
@on("didRender")
|
||||
_ajustPosition() {
|
||||
$(`.select-kit-fixed-placeholder-${this.elementId}`).remove();
|
||||
_adjustPosition() {
|
||||
this.$collection().css("max-height", this.get("collectionHeight"));
|
||||
this._applyFixedPosition();
|
||||
this._applyDirection();
|
||||
@ -46,7 +50,7 @@ export default Ember.Mixin.create({
|
||||
|
||||
@on("willDestroyElement")
|
||||
_clearState() {
|
||||
$(`.select-kit-fixed-placeholder-${this.elementId}`).remove();
|
||||
this.$fixedPlaceholder().remove();
|
||||
},
|
||||
|
||||
// use to collapse and remove focus
|
||||
@ -102,17 +106,14 @@ export default Ember.Mixin.create({
|
||||
_applyDirection() {
|
||||
let options = { left: "auto", bottom: "auto", top: "auto" };
|
||||
|
||||
const dHeader = $(".d-header")[0];
|
||||
const dHeaderBounds = dHeader ? dHeader.getBoundingClientRect() : {top: 0, height: 0};
|
||||
const dHeaderHeight = dHeaderBounds.top + dHeaderBounds.height;
|
||||
const bodyHeight = this.$body()[0].getBoundingClientRect().height;
|
||||
const discourseHeader = $(".d-header")[0];
|
||||
const discourseHeaderHeight = discourseHeader ? (discourseHeader.getBoundingClientRect().top + this._computedStyle(discourseHeader, "height")) : 0;
|
||||
const bodyHeight = this._computedStyle(this.$body()[0], "height");
|
||||
const windowWidth = $(window).width();
|
||||
const windowHeight = $(window).height();
|
||||
const boundingRect = this.get("element").getBoundingClientRect();
|
||||
const componentHeight = boundingRect.height;
|
||||
const componentWidth = boundingRect.width;
|
||||
const offsetTop = boundingRect.top;
|
||||
const offsetBottom = boundingRect.bottom;
|
||||
const componentHeight = this._computedStyle(this.get("element"), "height");
|
||||
const componentWidth = this._computedStyle(this.get("element"), "width");
|
||||
const offsetTop = this.get("element").getBoundingClientRect().top;
|
||||
const offsetBottom = this.get("element").getBoundingClientRect().bottom;
|
||||
|
||||
if (this.get("fullWidthOnMobile") && (this.site && this.site.isMobileDevice)) {
|
||||
const margin = 10;
|
||||
@ -121,10 +122,10 @@ export default Ember.Mixin.create({
|
||||
options.width = windowWidth - margin * 2;
|
||||
options.maxWidth = options.minWidth = "unset";
|
||||
} else {
|
||||
const bodyWidth = this.$body()[0].getBoundingClientRect().width;
|
||||
const bodyWidth = this._computedStyle(this.$body()[0], "width");
|
||||
|
||||
if ($("html").css("direction") === "rtl") {
|
||||
const horizontalSpacing = boundingRect.right;
|
||||
if (this._isRTL()) {
|
||||
const horizontalSpacing = this.get("element").getBoundingClientRect().right;
|
||||
const hasHorizontalSpace = horizontalSpacing - (this.get("horizontalOffset") + bodyWidth) > 0;
|
||||
if (hasHorizontalSpace) {
|
||||
this.setProperties({ isLeftAligned: true, isRightAligned: false });
|
||||
@ -134,7 +135,7 @@ export default Ember.Mixin.create({
|
||||
options.right = - (bodyWidth - componentWidth + this.get("horizontalOffset"));
|
||||
}
|
||||
} else {
|
||||
const horizontalSpacing = boundingRect.left;
|
||||
const horizontalSpacing = this.get("element").getBoundingClientRect().left;
|
||||
const hasHorizontalSpace = (windowWidth - (this.get("horizontalOffset") + horizontalSpacing + bodyWidth) > 0);
|
||||
if (hasHorizontalSpace) {
|
||||
this.setProperties({ isLeftAligned: true, isRightAligned: false });
|
||||
@ -147,87 +148,109 @@ export default Ember.Mixin.create({
|
||||
}
|
||||
|
||||
const fullHeight = this.get("verticalOffset") + bodyHeight + componentHeight;
|
||||
const hasBelowSpace = windowHeight - offsetBottom - fullHeight > 0;
|
||||
const hasAboveSpace = offsetTop - fullHeight - dHeaderHeight > 0;
|
||||
const hasBelowSpace = $(window).height() - offsetBottom - fullHeight > 0;
|
||||
const hasAboveSpace = offsetTop - fullHeight - discourseHeaderHeight > 0;
|
||||
const headerHeight = this._computedStyle(this.$header()[0], "height");
|
||||
if (hasBelowSpace || (!hasBelowSpace && !hasAboveSpace)) {
|
||||
this.setProperties({ isBelow: true, isAbove: false });
|
||||
options.top = this.$header()[0].getBoundingClientRect().height + this.get("verticalOffset");
|
||||
options.top = headerHeight + this.get("verticalOffset");
|
||||
} else {
|
||||
this.setProperties({ isBelow: false, isAbove: true });
|
||||
options.bottom = this.$header()[0].getBoundingClientRect().height + this.get("verticalOffset");
|
||||
options.bottom = headerHeight + this.get("verticalOffset");
|
||||
}
|
||||
|
||||
this.$body().css(options);
|
||||
},
|
||||
|
||||
_applyFixedPosition() {
|
||||
if (this.get("isExpanded") !== true) { return; }
|
||||
if (this.get("isExpanded") !== true) return;
|
||||
if (this.$fixedPlaceholder().length === 1) return;
|
||||
if (this.$scrollableParent().length === 0) return;
|
||||
|
||||
const scrollableParent = this.$().parents(this.get("scrollableParentSelector"));
|
||||
if (scrollableParent.length === 0) { return; }
|
||||
const width = this._computedStyle(this.get("element"), "width");
|
||||
const height = this._computedStyle(this.get("element"), "height");
|
||||
|
||||
const boundingRect = this.get("element").getBoundingClientRect();
|
||||
const width = boundingRect.width;
|
||||
const height = boundingRect.height;
|
||||
const $placeholder = $(`<div class='select-kit-fixed-placeholder-${this.elementId}'></div>`);
|
||||
this._previousScrollParentOverflow = this._previousScrollParentOverflow ||
|
||||
this.$scrollableParent().css("overflow");
|
||||
|
||||
this._previousScrollParentOverflow = this._previousScrollParentOverflow || scrollableParent.css("overflow");
|
||||
scrollableParent.css({ overflow: "hidden" });
|
||||
|
||||
this._previousCSSContext = {
|
||||
this._previousCSSContext = this._previousCSSContext || {
|
||||
width,
|
||||
minWidth: this.$().css("min-width"),
|
||||
maxWidth: this.$().css("max-width")
|
||||
maxWidth: this.$().css("max-width"),
|
||||
top: this.$().css("top"),
|
||||
left: this.$().css("left"),
|
||||
marginLeft: this.$().css("margin-left"),
|
||||
marginRight: this.$().css("margin-right"),
|
||||
position: this.$().css("position")
|
||||
};
|
||||
|
||||
const componentStyles = {
|
||||
position: "fixed",
|
||||
"margin-top": -scrollableParent.scrollTop(),
|
||||
top: this.get("element").getBoundingClientRect().top,
|
||||
width,
|
||||
left: this.get("element").getBoundingClientRect().left,
|
||||
marginLeft: 0,
|
||||
marginRight: 0,
|
||||
minWidth: "unset",
|
||||
maxWidth: "unset"
|
||||
maxWidth: "unset",
|
||||
position: "fixed"
|
||||
};
|
||||
|
||||
if ($("html").css("direction") === "rtl") {
|
||||
componentStyles.marginRight = -width;
|
||||
} else {
|
||||
componentStyles.marginLeft = -width;
|
||||
}
|
||||
const $placeholderTemplate = $(`<div class='select-kit-fixed-placeholder-${this.elementId}'></div>`);
|
||||
$placeholderTemplate.css({
|
||||
display: "inline-block",
|
||||
width,
|
||||
height,
|
||||
"vertical-align": "middle"
|
||||
});
|
||||
|
||||
$placeholder.css({ display: "inline-block", width, height, "vertical-align": "middle" });
|
||||
this.$()
|
||||
.before($placeholderTemplate)
|
||||
.css(componentStyles);
|
||||
|
||||
this.$().before($placeholder).css(componentStyles);
|
||||
this.$scrollableParent().css({ overflow: "hidden" });
|
||||
},
|
||||
|
||||
_removeFixedPosition() {
|
||||
$(`.select-kit-fixed-placeholder-${this.elementId}`).remove();
|
||||
this.$fixedPlaceholder().remove();
|
||||
|
||||
if (!this.element || this.isDestroying || this.isDestroyed) { return; }
|
||||
if (!this.element || this.isDestroying || this.isDestroyed) return;
|
||||
if (this.$scrollableParent().length === 0) return;
|
||||
|
||||
const scrollableParent = this.$().parents(this.get("scrollableParentSelector"));
|
||||
if (scrollableParent.length === 0) { return; }
|
||||
|
||||
const css = jQuery.extend(
|
||||
this._previousCSSContext,
|
||||
{
|
||||
top: "auto",
|
||||
left: "auto",
|
||||
"margin-left": "auto",
|
||||
"margin-right": "auto",
|
||||
"margin-top": "auto",
|
||||
position: "relative"
|
||||
}
|
||||
);
|
||||
this.$().css(css);
|
||||
|
||||
scrollableParent.css("overflow", this._previousScrollParentOverflow);
|
||||
this.$().css(this._previousCSSContext || {});
|
||||
this.$scrollableParent().css("overflow", this._previousScrollParentOverflow || {});
|
||||
},
|
||||
|
||||
_positionWrapper() {
|
||||
const headerBoundingRect = this.$header()[0].getBoundingClientRect();
|
||||
const elementWidth = this._computedStyle(this.get("element"), "width");
|
||||
const headerHeight = this._computedStyle(this.$header()[0], "height");
|
||||
const bodyHeight = this._computedStyle(this.$body()[0], "height");
|
||||
|
||||
this.$(this.wrapperSelector).css({
|
||||
width: this.get("element").getBoundingClientRect().width,
|
||||
height: headerBoundingRect.height + this.$body()[0].getBoundingClientRect().height
|
||||
this.$wrapper().css({
|
||||
width: elementWidth,
|
||||
height: headerHeight + bodyHeight
|
||||
});
|
||||
},
|
||||
|
||||
_isRTL() {
|
||||
return $("html").css("direction") === "rtl";
|
||||
},
|
||||
|
||||
_computedStyle(element, style) {
|
||||
if (!element) return 0;
|
||||
|
||||
let value;
|
||||
|
||||
if (window.getComputedStyle) {
|
||||
value = window.getComputedStyle(element, null)[style];
|
||||
} else {
|
||||
value = $(element).css(style);
|
||||
}
|
||||
|
||||
return this._getFloat(value);
|
||||
},
|
||||
|
||||
_getFloat(value) {
|
||||
value = parseFloat(value);
|
||||
return $.isNumeric(value) ? value : 0;
|
||||
}
|
||||
});
|
||||
|
||||
@ -38,8 +38,12 @@ export default Ember.Mixin.create({
|
||||
|
||||
$(document)
|
||||
.on("mousedown.select-kit", event => {
|
||||
event.stopPropagation();
|
||||
|
||||
if (!this.get("renderedBodyOnce")) return;
|
||||
if (!this.get("isFocused")) return;
|
||||
if (Ember.isNone(this.get("element"))) return;
|
||||
if (this.get("element").contains(event.target)) return;
|
||||
if (Ember.$.contains(this.get("element"), event.target)) return;
|
||||
|
||||
this.didClickOutside(event);
|
||||
});
|
||||
|
||||
@ -15,5 +15,5 @@
|
||||
<div class="category-desc">{{{description}}}</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{computedContent.name}}
|
||||
{{{label}}}
|
||||
{{/if}}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{{#each icons as |icon|}} {{d-icon icon}} {{/each}}
|
||||
|
||||
<span class="selected-name" title={{title}}>
|
||||
{{{name}}}
|
||||
<span class="selected-name">
|
||||
{{{label}}}
|
||||
</span>
|
||||
|
||||
{{#if shouldDisplayClearableButton}}
|
||||
|
||||
@ -2,6 +2,6 @@
|
||||
|
||||
{{#if options.showFullTitle}}
|
||||
<span class="d-button-label selected-name">
|
||||
{{name}}
|
||||
{{label}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
{{/if}}
|
||||
|
||||
<div class="texts">
|
||||
<span class="name">{{{name}}}</span>
|
||||
<span class="name">{{{label}}}</span>
|
||||
<span class="desc">{{{description}}}</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
{{/if}}
|
||||
|
||||
<span class="selected-name" title={{title}}>
|
||||
{{{name}}}
|
||||
{{{label}}}
|
||||
</span>
|
||||
|
||||
{{#if computedContent.datetime}}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<span class="name">{{computedContent.name}}</span>
|
||||
<span class="name">{{label}}</span>
|
||||
|
||||
{{#if computedContent.datetime}}
|
||||
<span class="future-date-input-selector-datetime">
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div class="choices">
|
||||
{{#each computedContent.selectedComputedContents as |selectedComputedContent|}}
|
||||
{{component selectedNameComponent onDeselect=onDeselect content=selectedComputedContent}}
|
||||
{{component selectedNameComponent onDeselect=onDeselect computedContent=selectedComputedContent}}
|
||||
{{/each}}
|
||||
<span class="filter choice" tabindex="-1">
|
||||
{{component "select-kit/select-kit-filter"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<span class="name">
|
||||
<span class="delete-icon" {{action onDeselect content bubbles=false}}>
|
||||
<span class="delete-icon" {{action onDeselect computedContent bubbles=false}}>
|
||||
{{d-icon "times"}}
|
||||
</span>
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
<div class="selected-color-wrapper">
|
||||
<span class="name">
|
||||
{{#unless isLocked}}
|
||||
<span class="delete-icon" {{action onDeselect content bubbles=false}}>
|
||||
<span class="delete-icon" {{action onDeselect computedContent bubbles=false}}>
|
||||
{{d-icon "times"}}
|
||||
</span>
|
||||
{{/unless}}
|
||||
|
||||
#{{content.name}}
|
||||
#{{{label}}}
|
||||
</span>
|
||||
|
||||
<span class="color-preview"></span>
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
{{d-icon "lock"}}
|
||||
</span>
|
||||
{{else}}
|
||||
<span class="locked-icon" {{action onDeselect content bubbles=false}}>
|
||||
<span class="locked-icon" {{action onDeselect computedContent bubbles=false}}>
|
||||
{{d-icon "times"}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
<span class="name">
|
||||
{{content.name}}
|
||||
{{{label}}}
|
||||
</span>
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
onClear=(action "onClear")
|
||||
options=headerComponentOptions
|
||||
shouldDisplayFilter=shouldDisplayFilter
|
||||
title=(i18n title)
|
||||
}}
|
||||
|
||||
<div class="select-kit-body">
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
highlightedValue=highlightedValue
|
||||
onClear=onClear
|
||||
onHighlight=onHighlight
|
||||
value=computedValue
|
||||
computedValue=computedValue
|
||||
options=rowComponentOptions
|
||||
}}
|
||||
{{/if}}
|
||||
@ -25,7 +25,7 @@
|
||||
highlightedValue=highlightedValue
|
||||
onHighlight=onHighlight
|
||||
onCreate=onCreate
|
||||
value=computedValue
|
||||
computedValue=computedValue
|
||||
options=rowComponentOptions
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{{#each icons as |icon|}} {{d-icon icon}} {{/each}}
|
||||
|
||||
<span class="selected-name" title={{name}}>
|
||||
{{{name}}}
|
||||
<span class="selected-name">
|
||||
{{{label}}}
|
||||
</span>
|
||||
|
||||
@ -2,5 +2,5 @@
|
||||
{{{template}}}
|
||||
{{else}}
|
||||
{{#each icons as |icon|}} {{d-icon icon}} {{/each}}
|
||||
<span class="name">{{computedContent.name}}</span>
|
||||
<span class="name">{{{label}}}</span>
|
||||
{{/if}}
|
||||
|
||||
@ -363,12 +363,15 @@ $mobile-breakpoint: 700px;
|
||||
|
||||
.groups, .badges, .web-hook-container {
|
||||
.form-horizontal {
|
||||
label {
|
||||
font-weight: bold;
|
||||
& > div {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
& > div {
|
||||
margin-top: 10px;
|
||||
.d-editor-textarea-wrapper {
|
||||
max-width: 60%;
|
||||
.d-editor-button-bar {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
input, textarea, select, .select-box {
|
||||
|
||||
@ -4,6 +4,10 @@
|
||||
margin-bottom: 10px;
|
||||
input {
|
||||
margin-bottom: 0;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.btn-small {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -174,7 +174,7 @@
|
||||
}
|
||||
td.stats {
|
||||
.unit {
|
||||
font-size: .8em;
|
||||
font-size: .857em;
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,7 +217,7 @@
|
||||
padding: 0;
|
||||
border: 0;
|
||||
color: $danger-medium;
|
||||
font-size: 0.929em;
|
||||
font-size: 1em;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
@ -267,7 +267,7 @@ ol.category-breadcrumb {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
a.badge-category, .dropdown-header {
|
||||
font-size: 0.929em;
|
||||
font-size: 0.857em;
|
||||
font-weight: bold;
|
||||
float: none;
|
||||
text-transform: none;
|
||||
@ -296,7 +296,7 @@ ol.category-breadcrumb {
|
||||
float: left;
|
||||
margin: 5px 0 10px;
|
||||
.top-date-string {
|
||||
font-size: 0.7em;
|
||||
font-size: 0.857em;
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,7 +318,7 @@ ol.category-breadcrumb {
|
||||
|
||||
@include unselectable;
|
||||
|
||||
font-size: 1.2em;
|
||||
font-size: 1.143em;
|
||||
border: 1px solid $primary-low;
|
||||
padding: 5px;
|
||||
background: $secondary;
|
||||
@ -342,7 +342,7 @@ ol.category-breadcrumb {
|
||||
}
|
||||
.top-date-string {
|
||||
font-weight: normal;
|
||||
font-size: 0.8em;
|
||||
font-size: 0.857em;
|
||||
}
|
||||
&:hover {
|
||||
background-color: $highlight-medium;
|
||||
|
||||
@ -75,7 +75,7 @@
|
||||
.description {
|
||||
padding: 0 1em 1em 1em;
|
||||
text-align: center;
|
||||
font-size: 1.05em;
|
||||
font-size: 1em;
|
||||
color: dark-light-choose($primary-medium, $secondary-high);
|
||||
.overflow {
|
||||
max-height: 6em;
|
||||
@ -85,7 +85,7 @@
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2em;
|
||||
font-size: 1.286em;
|
||||
margin-bottom: 0.5em;
|
||||
margin-top: 0.25em;
|
||||
line-height: 1.1em;
|
||||
@ -102,7 +102,7 @@
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2em;
|
||||
font-size: 1.286em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
z-index: 999;
|
||||
transition: height 250ms ease, background 250ms ease, transform 250ms ease, max-width 250ms ease;
|
||||
background-color: $secondary;
|
||||
box-shadow: 0 -2px 40px rgba($primary, .12);
|
||||
box-shadow: 0 -1px 40px rgba(0,0,0, .12);
|
||||
|
||||
.reply-area {
|
||||
display: flex;
|
||||
@ -300,7 +300,7 @@
|
||||
color: $primary;
|
||||
}
|
||||
span.name {
|
||||
font-size: .8em;
|
||||
font-size: .857em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
&.selected {
|
||||
@ -326,7 +326,7 @@ div.ac-wrap.disabled {
|
||||
|
||||
div.ac-wrap div.item a.remove, .remove-link {
|
||||
margin-left: 4px;
|
||||
font-size: .8em;
|
||||
font-size: .857em;
|
||||
line-height: 10px;
|
||||
padding: 1.5px 1.5px 1.5px 2.5px;
|
||||
border-radius: 12px;
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
border-bottom: 1px solid $primary-low;
|
||||
|
||||
.number, .time-read {
|
||||
font-size: 1.4em;
|
||||
font-size: 1.429em;
|
||||
color: $primary-medium;
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,11 +47,11 @@ body {
|
||||
}
|
||||
|
||||
big {
|
||||
font-size: 2em;
|
||||
font-size: 2.286em;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: .643em;
|
||||
font-size: .786em;
|
||||
}
|
||||
|
||||
//setting a static limit on big and small prevents nesting abuse
|
||||
@ -423,7 +423,7 @@ select {
|
||||
.content-list {
|
||||
h3 {
|
||||
color: $primary-medium;
|
||||
font-size: 1.071em;
|
||||
font-size: 1.143em;
|
||||
padding-left: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
@ -474,7 +474,7 @@ select {
|
||||
|
||||
.control-label {
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
font-size: 1.286em;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
@ -517,7 +517,7 @@ select {
|
||||
|
||||
#loading-message {
|
||||
position: absolute;
|
||||
font-size: 2.143em;
|
||||
font-size: 2.286em;
|
||||
text-align: center;
|
||||
top: 120px;
|
||||
left: 500px;
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
|
||||
h3 {
|
||||
font-weight: normal;
|
||||
font-size: 1.071em;
|
||||
font-size: 1.143em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,12 +7,12 @@
|
||||
height: 60px;
|
||||
}
|
||||
.reason {
|
||||
font-size: 1.714em;
|
||||
font-size: 1.857em;
|
||||
height: 24px;
|
||||
}
|
||||
.url {
|
||||
font-style: italic;
|
||||
font-size: .786em;
|
||||
font-size: .857em;
|
||||
}
|
||||
.desc {
|
||||
margin-top: 16px;
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
.time,
|
||||
.delete-info {
|
||||
color: lighten($primary, 40%);
|
||||
font-size: 0.8em;
|
||||
font-size: 0.857em;
|
||||
}
|
||||
|
||||
.group-member-info {
|
||||
@ -28,11 +28,13 @@
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
.group-post-title {
|
||||
font-size: 1.143em;
|
||||
}
|
||||
}
|
||||
|
||||
.group-post-excerpt {
|
||||
margin: 1em 0;
|
||||
font-size: 0.929em;
|
||||
word-wrap: break-word;
|
||||
color: $primary;
|
||||
}
|
||||
@ -45,13 +47,13 @@
|
||||
width: 100%;
|
||||
|
||||
.group-info-name {
|
||||
font-size: 1.4em;
|
||||
font-size: 1.429em;
|
||||
font-weight: bold;
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
.group-info-full-name {
|
||||
font-size: 1.2em;
|
||||
font-size: 1.286em;
|
||||
color: dark-light-choose($primary-high, $secondary-low);
|
||||
}
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
}
|
||||
|
||||
td.groups-user-count {
|
||||
font-size: 1.2em;
|
||||
font-size: 1.286em;
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
}
|
||||
|
||||
.groups-info-title {
|
||||
font-size: 0.9em;
|
||||
font-size: 0.857em;
|
||||
color: dark-light-choose($primary-medium, $secondary-medium);
|
||||
}
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ $input-width: 220px;
|
||||
}
|
||||
|
||||
.disclaimer {
|
||||
font-size: 0.9em;
|
||||
font-size: 0.857em;
|
||||
color: dark-light-choose($primary-medium, $secondary-medium);
|
||||
clear: both;
|
||||
}
|
||||
@ -58,7 +58,7 @@ $input-width: 220px;
|
||||
.instructions {
|
||||
color: dark-light-choose($primary-medium, $secondary-medium);
|
||||
margin: 0;
|
||||
font-size: 0.929em;
|
||||
font-size: 0.857em;
|
||||
font-weight: normal;
|
||||
line-height: 18px;
|
||||
}
|
||||
@ -100,7 +100,7 @@ $input-width: 220px;
|
||||
.instructions {
|
||||
color: dark-light-choose($primary-medium, $secondary-medium);
|
||||
margin: 0;
|
||||
font-size: 0.929em;
|
||||
font-size: 0.857em;
|
||||
font-weight: normal;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
@ -285,7 +285,6 @@ button {
|
||||
}
|
||||
padding: 0 0 18px 10px;
|
||||
color: $controls-color;
|
||||
|
||||
font-style: normal;
|
||||
font-size: 2em;
|
||||
font-family: Arial, Baskerville, monospace;
|
||||
|
||||
@ -65,7 +65,7 @@
|
||||
}
|
||||
|
||||
.new {
|
||||
font-size: 0.8em;
|
||||
font-size: 0.857em;
|
||||
margin-left: 0.5em;
|
||||
color: dark-light-choose($primary-medium, $secondary-medium);
|
||||
}
|
||||
@ -174,7 +174,7 @@
|
||||
}
|
||||
|
||||
li:not(.category):not(.heading) {
|
||||
font-size: 0.929em;
|
||||
font-size: 1em;
|
||||
line-height: 16px;
|
||||
|
||||
.fa {
|
||||
@ -327,9 +327,6 @@ div.menu-links-header {
|
||||
color: dark-light-choose($primary-medium, $secondary-medium);
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: 1.1em;
|
||||
}
|
||||
.d-icon-user {
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
|
||||
@ -153,7 +153,7 @@
|
||||
}
|
||||
p {
|
||||
color: darken($primary, 40%);
|
||||
font-size: 0.929em;
|
||||
font-size: 1em;
|
||||
}
|
||||
.archetype-option {
|
||||
margin-bottom: 20px;
|
||||
@ -247,7 +247,7 @@
|
||||
margin-left: 0 !important; // override needed
|
||||
font-weight: bold;
|
||||
.topic-title {
|
||||
font-size: 0.929em;
|
||||
font-size: 1em;
|
||||
font-weight: normal;
|
||||
}
|
||||
&.btn-reply-here {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Page not found styles
|
||||
|
||||
h1.page-not-found {
|
||||
font-size: 2.25em;
|
||||
font-size: 2.286em;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
|
||||
@ -118,7 +118,7 @@ aside.onebox {
|
||||
clear: both;
|
||||
|
||||
h3, h4 {
|
||||
font-size: 1.17em;
|
||||
font-size: 1.143em;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
@ -395,7 +395,7 @@ aside.onebox.twitterstatus .onebox-body {
|
||||
|
||||
.album-title {
|
||||
width: 100%;
|
||||
font-size: 1.083em;
|
||||
font-size: 1.143em;
|
||||
line-height: 30px;
|
||||
color: #ccc;
|
||||
text-decoration: none;
|
||||
|
||||
@ -4,10 +4,10 @@
|
||||
input[type=text] {
|
||||
width: 320px;
|
||||
height: 30px;
|
||||
font-size: 1.571em;
|
||||
font-size: 1.429em;
|
||||
}
|
||||
input[type=submit] {
|
||||
font-size: 1.571em;
|
||||
font-size: 1.429em;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
}
|
||||
.search-link {
|
||||
.topic-statuses, .topic-title {
|
||||
font-size: 1.3em;
|
||||
font-size: 1.286em;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@
|
||||
}
|
||||
|
||||
.discourse-tag {
|
||||
font-size: 0.8em;
|
||||
font-size: 0.857em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
margin: 14px 0;
|
||||
}
|
||||
h3 {
|
||||
font-size: 0.929em;
|
||||
font-size: 1em;
|
||||
}
|
||||
.copy-text {
|
||||
display: inline-block;
|
||||
@ -31,7 +31,7 @@
|
||||
color: $success;
|
||||
opacity: 1;
|
||||
transition: opacity 0.25s;
|
||||
font-size: .929em;
|
||||
font-size: 1em;
|
||||
&:not(.success) {
|
||||
opacity: 0;
|
||||
}
|
||||
@ -40,7 +40,7 @@
|
||||
margin-left: 2px;
|
||||
margin-right: 8px;
|
||||
float: left;
|
||||
font-size: 1.571em;
|
||||
font-size: 1.857em;
|
||||
}
|
||||
.reply-as-new-topic {
|
||||
float: left;
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
}
|
||||
|
||||
.tag-count {
|
||||
font-size: 0.9em;
|
||||
font-size: 0.857em;
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@
|
||||
$tag-color: $primary-medium;
|
||||
|
||||
.discourse-tag-count {
|
||||
font-size: 0.8em;
|
||||
font-size: 0.857em;
|
||||
color: $tag-color;
|
||||
}
|
||||
|
||||
@ -153,7 +153,7 @@ $tag-color: $primary-medium;
|
||||
|
||||
.topic-list-item .discourse-tags {
|
||||
display: block;
|
||||
font-size: 0.75em;
|
||||
font-size: 0.786em;
|
||||
font-weight: normal;
|
||||
clear: both;
|
||||
margin-top: 5px;
|
||||
@ -170,7 +170,7 @@ $tag-color: $primary-medium;
|
||||
|
||||
.mobile-view .topic-list-item .discourse-tags {
|
||||
display: inline-block;
|
||||
font-size: 0.9em;
|
||||
font-size: 0.857em;
|
||||
margin-top: 0;
|
||||
.discourse-tag.box {
|
||||
position:relative;
|
||||
@ -185,7 +185,7 @@ $tag-color: $primary-medium;
|
||||
font-family: FontAwesome;
|
||||
color: $primary-low-mid;
|
||||
margin-right: 5px;
|
||||
font-size: 0.7em;
|
||||
font-size: 0.786em;
|
||||
position:relative;
|
||||
top: -0.1em;
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@
|
||||
|
||||
// add staff color
|
||||
.moderator {
|
||||
.cooked {
|
||||
.regular > .cooked {
|
||||
background-color: dark-light-choose($highlight-low, $highlight-medium);
|
||||
padding: 10px;
|
||||
img:not(.thumbnail) {
|
||||
@ -75,7 +75,7 @@
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.names {
|
||||
.clearfix > .topic-meta-data > .names {
|
||||
span.user-title {
|
||||
background-color: dark-light-choose($highlight-low, $highlight-medium);
|
||||
color: dark-light-choose($primary-high, $secondary-low);
|
||||
@ -371,14 +371,14 @@ blockquote > *:last-child {
|
||||
margin-top: 6px;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
font-size: 0.9em;
|
||||
font-size: 0.857em;
|
||||
color: dark-light-choose($primary-low-mid, $secondary-high);
|
||||
|
||||
.custom-message {
|
||||
text-transform: none;
|
||||
margin: 15px 0px 5px;
|
||||
font-weight: normal;
|
||||
font-size: 1.11em;
|
||||
font-size: 1.143em;
|
||||
p {
|
||||
margin: 5px 0;
|
||||
}
|
||||
@ -464,7 +464,7 @@ a.mention, a.mention-group {
|
||||
> span.help {
|
||||
display: inline-block;
|
||||
color: dark-light-choose($primary-medium, $secondary-medium);
|
||||
font-size: 0.929em;
|
||||
font-size: 0.857em;
|
||||
font-style: italic;
|
||||
line-height: $base-line-height;
|
||||
margin-bottom: 1px;
|
||||
|
||||
@ -30,6 +30,14 @@
|
||||
&.badge-type-bronze .fa {
|
||||
color: #cd7f32 !important;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: $primary-medium;
|
||||
background-color: $primary-very-low;
|
||||
.fa {
|
||||
opacity: 0.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-width: 750px) {
|
||||
@ -60,7 +68,7 @@
|
||||
|
||||
.show-badge .badge-user-info {
|
||||
.earned {
|
||||
font-size: 1.3em;
|
||||
font-size: 1.286em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
@ -71,7 +79,7 @@
|
||||
.load-more {
|
||||
padding-top: 30px;
|
||||
display: block;
|
||||
font-size: 1.2em;
|
||||
font-size: 1.286em;
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,11 +94,11 @@
|
||||
}
|
||||
.date {
|
||||
display: inline-block;
|
||||
font-size: 1.1em;
|
||||
font-size: 1.143em;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.post-link {
|
||||
font-size: 1.3em;
|
||||
font-size: 1.286em;
|
||||
width: 500px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@ -130,7 +138,7 @@
|
||||
top: 5px;
|
||||
font-weight: bold;
|
||||
color: $primary-medium;
|
||||
font-size: 1.2em;
|
||||
font-size: 1.286em;
|
||||
}
|
||||
|
||||
.badge-contents {
|
||||
|
||||
@ -19,7 +19,6 @@
|
||||
width: 100%;
|
||||
|
||||
.secondary {
|
||||
font-size: 0.929em;
|
||||
|
||||
.btn {
|
||||
padding: 3px 12px;
|
||||
@ -61,13 +60,13 @@
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.143em;
|
||||
font-size: 2.286em;
|
||||
font-weight: normal;
|
||||
i {font-size: .8em;}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.214em;
|
||||
font-size: 1.286em;
|
||||
font-weight: normal;
|
||||
margin-top: 10px;
|
||||
max-width: 100%;
|
||||
@ -168,7 +167,7 @@
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.071em;
|
||||
font-size: 1.143em;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
@ -256,7 +255,7 @@
|
||||
color: dark-light-choose($primary-medium, $secondary-medium);
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 80%;
|
||||
font-size: .857em;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
}
|
||||
@ -268,7 +267,7 @@
|
||||
text-align: top;
|
||||
color: $danger;
|
||||
font-weight: bold;
|
||||
font-size: 1.3em;
|
||||
font-size: 1.286em;
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,7 +402,7 @@
|
||||
|
||||
.value {
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
font-size: 1.286em;
|
||||
}
|
||||
|
||||
.label {
|
||||
@ -450,7 +449,7 @@
|
||||
|
||||
.links-section {
|
||||
.domain {
|
||||
font-size: 0.714em;
|
||||
font-size: 0.786em;
|
||||
color: dark-light-choose($primary-medium, $secondary-high);
|
||||
}
|
||||
}
|
||||
@ -480,7 +479,7 @@
|
||||
.instructions {
|
||||
color: dark-light-choose($primary-medium, $secondary-medium);
|
||||
margin-bottom: 10px;
|
||||
font-size: 80%;
|
||||
font-size: .857em;
|
||||
line-height: 1.4em;
|
||||
|
||||
a[href] {
|
||||
|
||||
@ -24,9 +24,11 @@
|
||||
.main-link {
|
||||
@extend .topic-list-main-link;
|
||||
flex: 15;
|
||||
font-size: 1em;
|
||||
|
||||
.top-row {
|
||||
margin-bottom: 0.1em;
|
||||
font-size: 1.143em;
|
||||
}
|
||||
}
|
||||
.topic-stats {
|
||||
|
||||
@ -33,6 +33,7 @@ span.badge-posts {
|
||||
}
|
||||
button {
|
||||
border: none;
|
||||
font-size: 1.286em;
|
||||
padding: 8px 10px;
|
||||
vertical-align: top;
|
||||
background: transparent;
|
||||
|
||||
7
app/assets/stylesheets/vendor/normalize.scss
vendored
7
app/assets/stylesheets/vendor/normalize.scss
vendored
@ -101,11 +101,12 @@ a:hover {
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
|
||||
* Address styling not present in IE 8/9/10/11 & Edge
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
abbr[title], acronym[title] {
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dotted;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -2,6 +2,7 @@ require "backup_restore/backup_restore"
|
||||
|
||||
class Admin::BackupsController < Admin::AdminController
|
||||
|
||||
before_action :ensure_backups_enabled
|
||||
skip_before_action :check_xhr, only: [:index, :show, :logs, :check_backup_chunk, :upload_backup_chunk]
|
||||
|
||||
def index
|
||||
@ -178,4 +179,8 @@ class Admin::BackupsController < Admin::AdminController
|
||||
`df -Pk #{Rails.root}/public/backups | awk 'NR==2 {print $4 * 1024;}'`.to_i > size
|
||||
end
|
||||
|
||||
def ensure_backups_enabled
|
||||
raise Discourse::InvalidAccess.new unless SiteSetting.enable_backups?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -5,6 +5,7 @@ class StaticController < ApplicationController
|
||||
|
||||
skip_before_action :check_xhr, :redirect_to_login_if_required
|
||||
skip_before_action :verify_authenticity_token, only: [:brotli_asset, :cdn_asset, :enter, :favicon, :service_worker_asset]
|
||||
skip_before_action :preload_json, only: [:brotli_asset, :cdn_asset, :enter, :favicon, :service_worker_asset]
|
||||
|
||||
PAGES_WITH_EMAIL_PARAM = ['login', 'password_reset', 'signup']
|
||||
|
||||
@ -146,6 +147,10 @@ class StaticController < ApplicationController
|
||||
def service_worker_asset
|
||||
respond_to do |format|
|
||||
format.js do
|
||||
|
||||
# we take 1 hour to give a new service worker to all users
|
||||
immutable_for 1.hour
|
||||
|
||||
render(
|
||||
plain: Rails.application.assets_manifest.find_sources('service-worker.js').first,
|
||||
content_type: 'application/javascript'
|
||||
|
||||
@ -26,17 +26,22 @@ class UploadsController < ApplicationController
|
||||
# note, atm hijack is processed in its own context and has not access to controller
|
||||
# longer term we may change this
|
||||
hijack do
|
||||
info = UploadsController.create_upload(
|
||||
current_user: me,
|
||||
file: file,
|
||||
url: url,
|
||||
type: type,
|
||||
for_private_message: for_private_message,
|
||||
pasted: pasted,
|
||||
is_api: is_api,
|
||||
retain_hours: retain_hours
|
||||
)
|
||||
render json: UploadsController.serialize_upload(info), status: Upload === info ? 200 : 422
|
||||
begin
|
||||
info = UploadsController.create_upload(
|
||||
current_user: me,
|
||||
file: file,
|
||||
url: url,
|
||||
type: type,
|
||||
for_private_message: for_private_message,
|
||||
pasted: pasted,
|
||||
is_api: is_api,
|
||||
retain_hours: retain_hours
|
||||
)
|
||||
rescue => e
|
||||
render json: failed_json.merge(message: e.message&.split("\n")&.first), status: 422
|
||||
else
|
||||
render json: UploadsController.serialize_upload(info), status: Upload === info ? 200 : 422
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -248,7 +248,12 @@ class UsersController < ApplicationController
|
||||
Group.mentionable(current_user)
|
||||
.where(name: usernames)
|
||||
.pluck(:name, :user_count)
|
||||
.map { |name, user_count| { name: name, user_count: user_count } }
|
||||
.map do |name, user_count|
|
||||
{
|
||||
name: name,
|
||||
user_count: user_count
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
usernames -= groups
|
||||
@ -267,7 +272,13 @@ class UsersController < ApplicationController
|
||||
.where(username_lower: usernames)
|
||||
.pluck(:username_lower)
|
||||
|
||||
render json: { valid: result, valid_groups: groups, mentionable_groups: mentionable_groups, cannot_see: cannot_see }
|
||||
render json: {
|
||||
valid: result,
|
||||
valid_groups: groups,
|
||||
mentionable_groups: mentionable_groups,
|
||||
cannot_see: cannot_see,
|
||||
max_users_notified_per_group_mention: SiteSetting.max_users_notified_per_group_mention
|
||||
}
|
||||
end
|
||||
|
||||
def render_available_true
|
||||
|
||||
@ -38,7 +38,7 @@ module Jobs
|
||||
end
|
||||
end
|
||||
|
||||
if !post.user.staff? && !post.user.staged
|
||||
if !post.user&.staff? && !post.user&.staged?
|
||||
s = post.cooked
|
||||
s << " #{post.topic.title}" if post.post_number == 1
|
||||
if !args[:bypass_bump] && WordWatcher.new(s).should_flag?
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user