Version bump
This commit is contained in:
commit
b2660b7d12
1
.gitignore
vendored
1
.gitignore
vendored
@ -54,6 +54,7 @@ bootsnap-compile-cache/
|
||||
!/plugins/discourse-details/
|
||||
!/plugins/discourse-nginx-performance-report
|
||||
!/plugins/discourse-narrative-bot
|
||||
!/plugins/discourse-presence
|
||||
/plugins/*/auto_generated/
|
||||
|
||||
/spec/fixtures/plugins/my_plugin/auto_generated
|
||||
|
||||
@ -43,6 +43,7 @@ before_install:
|
||||
- git clone --depth=1 https://github.com/discourse/discourse-cakeday.git plugins/discourse-cakeday
|
||||
- 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-slack-official.git plugins/discourse-slack-official
|
||||
- git clone --depth=1 https://github.com/discourse/discourse-chat-integration.git plugins/discourse-chat-integration
|
||||
|
||||
install:
|
||||
- bash -c "if [ '$RAILS_MASTER' == '1' ]; then bundle update --retry=3 --jobs=3 arel rails seed-fu; fi"
|
||||
|
||||
12
.tx/config
12
.tx/config
@ -38,6 +38,18 @@ source_file = plugins/discourse-narrative-bot/config/locales/server.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.presenceclientenyml]
|
||||
file_filter = plugins/discourse-presence/config/locales/client.<lang>.yml
|
||||
source_file = plugins/discourse-presence/config/locales/client.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.presenceserverenyml]
|
||||
file_filter = plugins/discourse-presence/config/locales/server.<lang>.yml
|
||||
source_file = plugins/discourse-presence/config/locales/server.en.yml
|
||||
source_lang = en
|
||||
type = YML
|
||||
|
||||
[discourse-org.403html]
|
||||
file_filter = public/403.<lang>.html
|
||||
source_file = public/403.html
|
||||
|
||||
@ -122,7 +122,7 @@
|
||||
|
||||
<div>
|
||||
<label>{{i18n 'groups.notification_level'}}</label>
|
||||
{{notifications-button i18nPrefix='groups.notifications' notificationLevel=model.default_notification_level}}
|
||||
{{notifications-button i18nPrefix='groups.notifications' value=model.default_notification_level}}
|
||||
<div class='clearfix'></div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -174,6 +174,8 @@
|
||||
</section>
|
||||
{{/if}}
|
||||
|
||||
{{plugin-outlet name="admin-user-details" args=(hash model=model)}}
|
||||
|
||||
<section class='details'>
|
||||
<h1>{{i18n 'admin.user.permissions'}}</h1>
|
||||
|
||||
@ -466,7 +468,7 @@
|
||||
{{/if}}
|
||||
|
||||
<section>
|
||||
<hr/>
|
||||
<hr>
|
||||
<div class="pull-right">
|
||||
{{#unless model.anonymizeForbidden}}
|
||||
{{d-button label="admin.user.anonymize"
|
||||
@ -487,7 +489,7 @@
|
||||
|
||||
{{#if model.deleteExplanation}}
|
||||
<div class="clearfix"></div>
|
||||
<br/>
|
||||
<br>
|
||||
<div class="pull-right">
|
||||
{{d-icon "exclamation-triangle"}} {{model.deleteExplanation}}
|
||||
</div>
|
||||
|
||||
@ -66,7 +66,6 @@
|
||||
//= require ./discourse/controllers/navigation/default
|
||||
//= require ./discourse/components/edit-category-panel
|
||||
//= require ./discourse/components/dropdown-button
|
||||
//= require ./discourse/components/notifications-button
|
||||
//= require ./discourse/lib/link-mentions
|
||||
//= require ./discourse/components/site-header
|
||||
//= require ./discourse/components/d-editor
|
||||
|
||||
@ -1,6 +1,16 @@
|
||||
import { h } from 'virtual-dom';
|
||||
let _renderers = [];
|
||||
|
||||
const REPLACEMENTS = {
|
||||
'd-tracking': 'circle',
|
||||
'd-muted': 'times-circle',
|
||||
'd-regular': 'circle-o',
|
||||
'd-watching': 'exclamation-circle',
|
||||
'd-watching-first': 'dot-circle-o',
|
||||
'd-drop-expanded': 'caret-down',
|
||||
'd-drop-collapsed': 'caret-right',
|
||||
};
|
||||
|
||||
export function renderIcon(renderType, id, params) {
|
||||
for (let i=0; i<_renderers.length; i++) {
|
||||
let renderer = _renderers[i];
|
||||
@ -23,6 +33,11 @@ export function iconNode(id, params) {
|
||||
return renderIcon('node', id, params);
|
||||
}
|
||||
|
||||
// TODO: Improve how helpers are registered for vdom compliation
|
||||
if (typeof Discourse !== "undefined") {
|
||||
Discourse.__widget_helpers.iconNode = iconNode;
|
||||
}
|
||||
|
||||
export function registerIconRenderer(renderer) {
|
||||
_renderers.unshift(renderer);
|
||||
}
|
||||
@ -42,6 +57,8 @@ registerIconRenderer({
|
||||
name: 'font-awesome',
|
||||
|
||||
string(id, params) {
|
||||
id = REPLACEMENTS[id] || id;
|
||||
|
||||
let tagName = params.tagName || 'i';
|
||||
let html = `<${tagName} class='${faClasses(id, params)}'`;
|
||||
if (params.title) { html += ` title='${I18n.t(params.title)}'`; }
|
||||
@ -54,6 +71,8 @@ registerIconRenderer({
|
||||
},
|
||||
|
||||
node(id, params) {
|
||||
id = REPLACEMENTS[id] || id;
|
||||
|
||||
let tagName = params.tagName || 'i';
|
||||
|
||||
const properties = {
|
||||
|
||||
@ -7,6 +7,8 @@ const Discourse = Ember.Application.extend({
|
||||
rootElement: '#main',
|
||||
_docTitle: document.title,
|
||||
RAW_TEMPLATES: {},
|
||||
__widget_helpers: {},
|
||||
showingSignup: false,
|
||||
|
||||
getURL(url) {
|
||||
if (!url) return url;
|
||||
|
||||
@ -1,39 +1,49 @@
|
||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
||||
import DropdownButton from 'discourse/components/dropdown-button';
|
||||
import DropdownSelectBoxComponent from "discourse/components/dropdown-select-box";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default DropdownButton.extend({
|
||||
buttonExtraClasses: 'no-text',
|
||||
title: '',
|
||||
text: iconHTML('bars') + ' ' + iconHTML('caret-down'),
|
||||
classNames: ['category-notification-menu', 'category-admin-menu'],
|
||||
export default DropdownSelectBoxComponent.extend({
|
||||
classNames: ["categories-admin-dropdown"],
|
||||
|
||||
@computed()
|
||||
dropDownContent() {
|
||||
const includeReorder = this.get('siteSettings.fixed_category_positions');
|
||||
icon: `${iconHTML('bars')}${iconHTML('caret-down')}`.htmlSafe(),
|
||||
|
||||
generatedHeadertext: null,
|
||||
|
||||
@computed
|
||||
content() {
|
||||
const items = [
|
||||
{ id: 'create',
|
||||
title: I18n.t('category.create'),
|
||||
description: I18n.t('category.create_long'),
|
||||
icon: 'plus' }
|
||||
{
|
||||
id: "create",
|
||||
text: I18n.t("category.create"),
|
||||
description: I18n.t("category.create_long"),
|
||||
icon: "plus"
|
||||
}
|
||||
];
|
||||
|
||||
const includeReorder = this.get("siteSettings.fixed_category_positions");
|
||||
if (includeReorder) {
|
||||
items.push({
|
||||
id: 'reorder',
|
||||
title: I18n.t('categories.reorder.title'),
|
||||
description: I18n.t('categories.reorder.title_long'),
|
||||
icon: 'random'
|
||||
id: "reorder",
|
||||
text: I18n.t("categories.reorder.title"),
|
||||
description: I18n.t("categories.reorder.title_long"),
|
||||
icon: "random"
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
},
|
||||
|
||||
actionNames: {
|
||||
create: 'createCategory',
|
||||
reorder: 'reorderCategories'
|
||||
create: "createCategory",
|
||||
reorder: "reorderCategories"
|
||||
},
|
||||
|
||||
clicked(id) {
|
||||
this.sendAction('actionNames.' + id);
|
||||
actions: {
|
||||
onSelectRow(content) {
|
||||
this._super(content);
|
||||
|
||||
this.sendAction(`actionNames.${this.get("value")}`);
|
||||
this.set("value", null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -12,7 +12,7 @@ export default Ember.Component.extend({
|
||||
|
||||
@computed('expanded')
|
||||
expandIcon(expanded) {
|
||||
return expanded ? 'caret-down' : 'caret-right';
|
||||
return expanded ? 'd-drop-expanded' : 'd-drop-collapsed';
|
||||
},
|
||||
|
||||
allCategoriesUrl: function() {
|
||||
|
||||
@ -1,13 +1,28 @@
|
||||
import NotificationsButton from 'discourse/components/notifications-button';
|
||||
import NotificationOptionsComponent from "discourse/components/notifications-button";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
|
||||
export default NotificationsButton.extend({
|
||||
classNames: ['notification-options', 'category-notification-menu'],
|
||||
buttonIncludesText: false,
|
||||
hidden: Em.computed.alias('category.deleted'),
|
||||
notificationLevel: Em.computed.alias('category.notification_level'),
|
||||
i18nPrefix: 'category.notifications',
|
||||
export default NotificationOptionsComponent.extend({
|
||||
classNames: ["category-notifications-button"],
|
||||
|
||||
clicked(id) {
|
||||
this.get('category').setNotification(id);
|
||||
hidden: Ember.computed.or("category.deleted", "site.isMobileDevice"),
|
||||
|
||||
i18nPrefix: "category.notifications",
|
||||
|
||||
value: Em.computed.alias("category.notification_level"),
|
||||
|
||||
@computed("value")
|
||||
icon() {
|
||||
return `${this._super()}${iconHTML("caret-down")}`.htmlSafe();
|
||||
},
|
||||
|
||||
generatedHeadertext: null,
|
||||
|
||||
actions: {
|
||||
onSelectRow(content) {
|
||||
this._super(content);
|
||||
|
||||
this.get("category").setNotification(this.get("value"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -26,6 +26,12 @@ export default SelectBoxComponent.extend({
|
||||
this.set("content", this.get("categories"));
|
||||
this._scopeCategories();
|
||||
}
|
||||
|
||||
if (Ember.isNone(this.get("value"))) {
|
||||
if (this.siteSettings.allow_uncategorized_topics && this.get("allowUncategorized") !== false) {
|
||||
this.set("value", Category.findUncategorized().id);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
filterFunction: function(content) {
|
||||
|
||||
@ -376,7 +376,7 @@ export default Ember.Component.extend({
|
||||
return resolve([translations[full]]);
|
||||
}
|
||||
|
||||
const match = term.match(/^:?(.*?):t(\d)?$/);
|
||||
const match = term.match(/^:?(.*?):t([2-6])?$/);
|
||||
if (match) {
|
||||
let name = match[1];
|
||||
let scale = match[2];
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import SelectBoxComponent from "discourse/components/select-box";
|
||||
|
||||
export default SelectBoxComponent.extend({
|
||||
classNames: ["dropdown-select-box"],
|
||||
wrapper: false,
|
||||
verticalOffset: 3,
|
||||
collectionHeight: "auto",
|
||||
fullWidthOnMobile: true,
|
||||
selectBoxHeaderComponent: "dropdown-select-box/dropdown-header",
|
||||
|
||||
@computed
|
||||
templateForRow: function() {
|
||||
return (rowComponent) => {
|
||||
let template = "";
|
||||
const content = rowComponent.get("content");
|
||||
|
||||
const icon = rowComponent.icon();
|
||||
if (icon) {
|
||||
template += `<div class="icons">${icon}</div>`;
|
||||
}
|
||||
|
||||
template += `
|
||||
<div class="texts">
|
||||
<span class="title">${Handlebars.escapeExpression(Ember.get(content, this.get("textKey")))}</span>
|
||||
<span class="desc">${Handlebars.escapeExpression(content.description)}</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
return template;
|
||||
};
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,7 @@
|
||||
import SelectBoxHeaderComponent from "discourse/components/select-box/select-box-header";
|
||||
|
||||
export default SelectBoxHeaderComponent.extend({
|
||||
layoutName: "components/dropdown-select-box/dropdown-header",
|
||||
|
||||
classNames: ["dropdown-header"]
|
||||
});
|
||||
@ -1,11 +1,17 @@
|
||||
import NotificationsButton from 'discourse/components/notifications-button';
|
||||
import NotificationOptionsComponent from "discourse/components/notifications-button";
|
||||
|
||||
export default NotificationsButton.extend({
|
||||
classNames: ['notification-options', 'group-notification-menu'],
|
||||
notificationLevel: Em.computed.alias('group.group_user.notification_level'),
|
||||
i18nPrefix: 'groups.notifications',
|
||||
export default NotificationOptionsComponent.extend({
|
||||
classNames: ["group-notifications-button"],
|
||||
|
||||
clicked(id) {
|
||||
this.get('group').setNotification(id, this.get('user.id'));
|
||||
value: Em.computed.alias("group.group_user.notification_level"),
|
||||
|
||||
i18nPrefix: "groups.notifications",
|
||||
|
||||
actions: {
|
||||
onSelectRow(content) {
|
||||
this._super(content);
|
||||
|
||||
this.get("group").setNotification(this.get("value"), this.get("user.id"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -3,5 +3,5 @@ import { showEntrance } 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']
|
||||
classNameBindings: [':latest-topic-list-item', 'topic.archived', 'topic.visited']
|
||||
});
|
||||
|
||||
@ -2,6 +2,6 @@ import { showEntrance } from 'discourse/components/topic-list-item';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'tr',
|
||||
classNameBindings: [':category-topic-link', 'topic.archived'],
|
||||
classNameBindings: [':category-topic-link', 'topic.archived', 'topic.visited'],
|
||||
click: showEntrance
|
||||
});
|
||||
|
||||
@ -1,50 +1,68 @@
|
||||
import DropdownButton from 'discourse/components/dropdown-button';
|
||||
import { allLevels, buttonDetails } from 'discourse/lib/notification-levels';
|
||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import DropdownSelectBoxComponent from "discourse/components/dropdown-select-box";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { buttonDetails } from "discourse/lib/notification-levels";
|
||||
import { allLevels } from "discourse/lib/notification-levels";
|
||||
|
||||
export default DropdownButton.extend({
|
||||
classNames: ['notification-options'],
|
||||
title: '',
|
||||
buttonIncludesText: true,
|
||||
activeItem: Em.computed.alias('notificationLevel'),
|
||||
i18nPrefix: '',
|
||||
i18nPostfix: '',
|
||||
export default DropdownSelectBoxComponent.extend({
|
||||
classNames: ["notifications-button"],
|
||||
|
||||
i18nPrefix: "",
|
||||
i18nPostfix: "",
|
||||
textKey: "key",
|
||||
showFullTitle: true,
|
||||
fullWidthOnMobile: true,
|
||||
content: allLevels,
|
||||
|
||||
value: Em.computed.alias("notificationLevel"),
|
||||
|
||||
@computed("selectedDetails")
|
||||
icon(details) {
|
||||
return iconHTML(details.icon, {class: details.key}).htmlSafe();
|
||||
},
|
||||
|
||||
@computed("selectedDetails.key", "i18nPrefix")
|
||||
selectedTitle(key, prefix) {
|
||||
return I18n.t(`${prefix}.${key}.title`);
|
||||
},
|
||||
|
||||
@computed("value")
|
||||
selectedDetails(value) {
|
||||
return buttonDetails(value);
|
||||
},
|
||||
|
||||
@computed("selectedTitle", "showFullTitle")
|
||||
generatedHeadertext(selectedTitle, showFullTitle) {
|
||||
return showFullTitle ? selectedTitle : null;
|
||||
},
|
||||
|
||||
@computed
|
||||
dropDownContent() {
|
||||
const prefix = this.get('i18nPrefix');
|
||||
const postfix = this.get('i18nPostfix');
|
||||
|
||||
return allLevels.map(l => {
|
||||
const start = `${prefix}.${l.key}${postfix}`;
|
||||
return {
|
||||
id: l.id,
|
||||
title: I18n.t(`${start}.title`),
|
||||
description: I18n.t(`${start}.description`),
|
||||
icon: l.icon,
|
||||
iconClass: l.key.dasherize(),
|
||||
};
|
||||
});
|
||||
titleForRow: function() {
|
||||
return (rowComponent) => {
|
||||
const notificationLevel = rowComponent.get(`content.${this.get("idKey")}`);
|
||||
const details = buttonDetails(notificationLevel);
|
||||
return I18n.t(`${this.get("i18nPrefix")}.${details.key}.title`);
|
||||
};
|
||||
},
|
||||
|
||||
@computed('notificationLevel')
|
||||
text(notificationLevel) {
|
||||
const details = buttonDetails(notificationLevel);
|
||||
const { key } = details;
|
||||
const icon = iconHTML(details.icon, { class: key.dasherize() });
|
||||
@computed
|
||||
templateForRow: function() {
|
||||
return (rowComponent) => {
|
||||
const content = rowComponent.get("content");
|
||||
const start = `${this.get("i18nPrefix")}.${content.key}${this.get("i18nPostfix")}`;
|
||||
const title = I18n.t(`${start}.title`);
|
||||
const description = I18n.t(`${start}.description`);
|
||||
|
||||
if (this.get('buttonIncludesText')) {
|
||||
const prefix = this.get('i18nPrefix');
|
||||
const postfix = this.get('i18nPostfix');
|
||||
const text = I18n.t(`${prefix}.${key}${postfix}.title`);
|
||||
return `${icon} ${text}<span class='caret'></span>`;
|
||||
} else {
|
||||
return `${icon} <span class='caret'></span>`;
|
||||
}
|
||||
},
|
||||
|
||||
clicked(id) {
|
||||
this.set("notificationLevel", id);
|
||||
return `
|
||||
<div class="icons">
|
||||
<span class="selection-indicator"></span>
|
||||
${iconHTML(content.icon, { class: content.key.dasherize() })}
|
||||
</div>
|
||||
<div class="texts">
|
||||
<span class="title">${Handlebars.escapeExpression(title)}</span>
|
||||
<span class="desc">${Handlebars.escapeExpression(description)}</span>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@ -1,67 +1,22 @@
|
||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import DropdownButton from 'discourse/components/dropdown-button';
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default DropdownButton.extend({
|
||||
descriptionKey: 'help',
|
||||
classNames: ['pinned-options'],
|
||||
title: '',
|
||||
buttonExtraClasses: 'btn-icon-text',
|
||||
export default Ember.Component.extend({
|
||||
descriptionKey: "help",
|
||||
|
||||
longDescription: function(){
|
||||
const topic = this.get('topic');
|
||||
const globally = topic.get('pinned_globally') ? '_globally' : '';
|
||||
const key = 'topic_statuses.' + (topic.get('pinned') ? 'pinned' + globally : 'unpinned') + '.help';
|
||||
classNames: ["pinned-button"],
|
||||
|
||||
classNameBindings: ["hidden:is-hidden"],
|
||||
|
||||
@computed("topic.pinned_globally", "topic.pinned")
|
||||
reasonText(pinnedGlobally, pinned) {
|
||||
const globally = pinnedGlobally ? "_globally" : "";
|
||||
const pinnedKey = pinned ? `pinned${globally}` : "unpinned";
|
||||
const key = `topic_statuses.${pinnedKey}.help`;
|
||||
return I18n.t(key);
|
||||
}.property('topic.pinned'),
|
||||
|
||||
target: Em.computed.alias('topic'),
|
||||
|
||||
hidden: function(){
|
||||
const topic = this.get('topic');
|
||||
return topic.get('deleted') || (!topic.get('pinned') && !topic.get('unpinned'));
|
||||
}.property('topic.pinned', 'topic.deleted', 'topic.unpinned'),
|
||||
|
||||
activeItem: function(){
|
||||
return this.get('topic.pinned') ? 'pinned' : 'unpinned';
|
||||
}.property('topic.pinned'),
|
||||
|
||||
dropDownContent: function() {
|
||||
const globally = this.get('topic.pinned_globally') ? '_globally' : '';
|
||||
return [
|
||||
{id: 'pinned',
|
||||
title: I18n.t('topic_statuses.pinned' + globally + '.title'),
|
||||
description: I18n.t('topic_statuses.pinned' + globally + '.help'),
|
||||
icon: 'thumb-tack' },
|
||||
{id: 'unpinned',
|
||||
title: I18n.t('topic_statuses.unpinned.title'),
|
||||
description: I18n.t('topic_statuses.unpinned.help'),
|
||||
icon: 'thumb-tack',
|
||||
iconClass: 'unpinned' }
|
||||
];
|
||||
}.property(),
|
||||
|
||||
@computed('topic.pinned', 'topic.pinned_globally')
|
||||
text(pinned, pinnedGlobally) {
|
||||
const globally = pinnedGlobally ? '_globally' : '';
|
||||
const state = pinned ? 'pinned' + globally : 'unpinned';
|
||||
|
||||
const icon = iconHTML(
|
||||
'thumb-tack',
|
||||
{ tagName: 'span', class: (state === 'unpinned' ? 'unpinned' : null) }
|
||||
);
|
||||
|
||||
return icon +
|
||||
I18n.t('topic_statuses.' + state + '.title') + "<span class='caret'></span>";
|
||||
},
|
||||
|
||||
clicked(id) {
|
||||
const topic = this.get('topic');
|
||||
if(id==='unpinned'){
|
||||
topic.clearPin();
|
||||
} else {
|
||||
topic.rePin();
|
||||
}
|
||||
@computed("topic.pinned", "topic.deleted", "topic.unpinned")
|
||||
hidden(pinned, deleted, unpinned) {
|
||||
return deleted || (!pinned && !unpinned);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
import DropdownSelectBoxComponent from "discourse/components/dropdown-select-box";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { observes } from "ember-addons/ember-computed-decorators";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
|
||||
export default DropdownSelectBoxComponent.extend({
|
||||
classNames: ["pinned-options"],
|
||||
|
||||
@computed("topic.pinned")
|
||||
value(pinned) {
|
||||
return pinned ? "pinned" : "unpinned";
|
||||
},
|
||||
|
||||
@observes("topic.pinned")
|
||||
_pinnedChanged() {
|
||||
this.set("value", this.get("topic.pinned") ? "pinned" : "unpinned");
|
||||
},
|
||||
|
||||
@computed("topic.pinned_globally")
|
||||
content(pinnedGlobally) {
|
||||
const globally = pinnedGlobally ? "_globally" : "";
|
||||
|
||||
return [
|
||||
{
|
||||
id: "pinned",
|
||||
text: I18n.t("topic_statuses.pinned" + globally + ".title"),
|
||||
description: I18n.t('topic_statuses.pinned' + globally + '.help'),
|
||||
icon: "thumb-tack"
|
||||
},
|
||||
{
|
||||
id: "unpinned",
|
||||
text: I18n.t("topic_statuses.unpinned.title"),
|
||||
icon: "thumb-tack",
|
||||
description: I18n.t('topic_statuses.unpinned.help'),
|
||||
iconClass: "unpinned"
|
||||
}
|
||||
];
|
||||
},
|
||||
|
||||
@computed("topic.pinned", "topic.pinned_globally")
|
||||
icon(pinned, pinnedGlobally) {
|
||||
const globally = pinnedGlobally ? "_globally" : "";
|
||||
const state = pinned ? `pinned${globally}` : "unpinned";
|
||||
|
||||
return iconHTML(
|
||||
"thumb-tack",
|
||||
{ class: (state === "unpinned" ? "unpinned" : null) }
|
||||
);
|
||||
},
|
||||
|
||||
@computed("topic.pinned", "topic.pinned_globally")
|
||||
generatedHeadertext(pinned, pinnedGlobally) {
|
||||
const globally = pinnedGlobally ? "_globally" : "";
|
||||
const state = pinned ? `pinned${globally}` : "unpinned";
|
||||
const title = I18n.t(`topic_statuses.${state}.title`);
|
||||
|
||||
return `${title}${iconHTML("caret-down")}`.htmlSafe();
|
||||
},
|
||||
|
||||
actions: {
|
||||
onSelectRow(content) {
|
||||
this._super(content);
|
||||
|
||||
const topic = this.get("topic");
|
||||
|
||||
if (this.get("value") === "unpinned") {
|
||||
topic.clearPin();
|
||||
} else {
|
||||
topic.rePin();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,18 +1,17 @@
|
||||
import { on, observes } from "ember-addons/ember-computed-decorators";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
layoutName: "components/select-box",
|
||||
|
||||
classNames: "select-box",
|
||||
classNameBindings: ["expanded:is-expanded"],
|
||||
classNameBindings: ["expanded:is-expanded", "hidden:is-hidden"],
|
||||
|
||||
expanded: false,
|
||||
focused: false,
|
||||
filterFocused: false,
|
||||
renderBody: false,
|
||||
wrapper: true,
|
||||
hidden: false,
|
||||
tabindex: 0,
|
||||
scrollableParentSelector: ".modal-body",
|
||||
|
||||
@ -24,9 +23,9 @@ export default Ember.Component.extend({
|
||||
clearable: false,
|
||||
|
||||
value: null,
|
||||
highlightedValue: null,
|
||||
selectedContent: null,
|
||||
noContentLabel: I18n.t("select_box.no_content"),
|
||||
lastHovered: null,
|
||||
clearSelectionLabel: null,
|
||||
|
||||
idKey: "id",
|
||||
@ -43,13 +42,17 @@ export default Ember.Component.extend({
|
||||
selectBoxHeaderComponent: "select-box/select-box-header",
|
||||
selectBoxCollectionComponent: "select-box/select-box-collection",
|
||||
|
||||
minWidth: 220,
|
||||
maxCollectionHeight: 200,
|
||||
collectionHeight: 200,
|
||||
verticalOffset: 0,
|
||||
horizontalOffset: 0,
|
||||
fullWidthOnMobile: false,
|
||||
|
||||
castInteger: false,
|
||||
|
||||
click(event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
|
||||
filterFunction: function(content) {
|
||||
return (selectBox) => {
|
||||
const filter = selectBox.get("filter").toLowerCase();
|
||||
@ -59,33 +62,37 @@ export default Ember.Component.extend({
|
||||
};
|
||||
},
|
||||
|
||||
@computed
|
||||
titleForRow: function() {
|
||||
return (rowComponent) => {
|
||||
return rowComponent.get(`content.${this.get("textKey")}`);
|
||||
};
|
||||
}.property(),
|
||||
},
|
||||
|
||||
@computed
|
||||
shouldHighlightRow: function() {
|
||||
return (rowComponent) => {
|
||||
if (Ember.isNone(this.get("value")) && Ember.isNone(this.get("lastHovered"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const id = this._castInteger(rowComponent.get(`content.${this.get("idKey")}`));
|
||||
if (Ember.isNone(this.get("lastHovered"))) {
|
||||
return id === this.get("value");
|
||||
} else {
|
||||
return id === this.get("lastHovered");
|
||||
}
|
||||
return id === this.get("highlightedValue");
|
||||
};
|
||||
}.property(),
|
||||
},
|
||||
|
||||
@computed("value", "idKey")
|
||||
shouldSelectRow(value, idKey) {
|
||||
return (rowComponent) => {
|
||||
const id = this._castInteger(rowComponent.get(`content.${idKey}`));
|
||||
return id === value;
|
||||
};
|
||||
},
|
||||
|
||||
@computed
|
||||
templateForRow: function() {
|
||||
return (rowComponent) => {
|
||||
let template = "";
|
||||
|
||||
if (rowComponent.get("content.icon")) {
|
||||
template += iconHTML(Handlebars.escapeExpression(rowComponent.get("content.icon")));
|
||||
const icon = rowComponent.icon();
|
||||
if (icon) {
|
||||
template += icon;
|
||||
}
|
||||
|
||||
const text = rowComponent.get(`content.${this.get("textKey")}`);
|
||||
@ -93,29 +100,50 @@ export default Ember.Component.extend({
|
||||
|
||||
return template;
|
||||
};
|
||||
}.property(),
|
||||
},
|
||||
|
||||
applyDirection() {
|
||||
const offsetTop = this.$()[0].getBoundingClientRect().top;
|
||||
const windowHeight = $(window).height();
|
||||
this.$().removeClass("is-above is-below is-left-aligned is-right-aligned");
|
||||
let options = { left: "auto", bottom: "auto", left: "auto", top: "auto" };
|
||||
const headerHeight = this.$(".select-box-header").outerHeight(false);
|
||||
const filterHeight = this.$(".select-box-filter").outerHeight(false);
|
||||
const bodyHeight = this.$(".select-box-body").outerHeight(false);
|
||||
const windowWidth = $(window).width();
|
||||
const windowHeight = $(window).height();
|
||||
const boundingRect = this.$()[0].getBoundingClientRect();
|
||||
const offsetTop = boundingRect.top;
|
||||
|
||||
if (windowHeight - (offsetTop + this.get("maxCollectionHeight") + filterHeight + headerHeight) < 0) {
|
||||
this.$().addClass("is-reversed");
|
||||
this.$(".select-box-body").css({
|
||||
left: this.get("horizontalOffset"),
|
||||
top: "auto",
|
||||
bottom: headerHeight + this.get("verticalOffset")
|
||||
});
|
||||
if (this.get("fullWidthOnMobile") && this.site.isMobileDevice) {
|
||||
const margin = 10;
|
||||
const relativeLeft = this.$().offset().left - $(window).scrollLeft();
|
||||
options.left = margin - relativeLeft;
|
||||
options.width = windowWidth - margin * 2;
|
||||
options.maxWidth = options.minWidth = "unset";
|
||||
} else {
|
||||
this.$().removeClass("is-reversed");
|
||||
this.$(".select-box-body").css({
|
||||
left: this.get("horizontalOffset"),
|
||||
top: headerHeight + this.get("verticalOffset"),
|
||||
bottom: "auto"
|
||||
});
|
||||
const offsetLeft = boundingRect.left;
|
||||
const bodyWidth = this.$(".select-box-body").outerWidth(false);
|
||||
const hasRightSpace = (windowWidth - (this.get("horizontalOffset") + offsetLeft + filterHeight + bodyWidth) > 0);
|
||||
|
||||
if (hasRightSpace) {
|
||||
this.$().addClass("is-left-aligned");
|
||||
options.left = this.get("horizontalOffset");
|
||||
} else {
|
||||
this.$().addClass("is-right-aligned");
|
||||
options.right = this.get("horizontalOffset");
|
||||
}
|
||||
}
|
||||
|
||||
const componentHeight = this.get("verticalOffset") + bodyHeight + headerHeight;
|
||||
const hasBelowSpace = windowHeight - offsetTop - componentHeight > 0;
|
||||
if (hasBelowSpace) {
|
||||
this.$().addClass("is-below");
|
||||
options.top = headerHeight + this.get("verticalOffset");
|
||||
} else {
|
||||
this.$().addClass("is-above");
|
||||
options.bottom = headerHeight + this.get("verticalOffset");
|
||||
}
|
||||
|
||||
this.$(".select-box-body").css(options);
|
||||
},
|
||||
|
||||
init() {
|
||||
@ -136,7 +164,7 @@ export default Ember.Component.extend({
|
||||
|
||||
@on("willDestroyElement")
|
||||
_removeDocumentListeners: function() {
|
||||
$(document).off("click.select-box", "keydown.select-box");
|
||||
$(document).off("click.select-box");
|
||||
$(window).off("resize.select-box");
|
||||
},
|
||||
|
||||
@ -156,12 +184,9 @@ export default Ember.Component.extend({
|
||||
this._removeFixedPosition();
|
||||
}
|
||||
|
||||
this.$().css("min-width", this.get("minWidth"));
|
||||
|
||||
const computedWidth = this.$().outerWidth(false);
|
||||
const computedHeight = this.$().outerHeight(false);
|
||||
|
||||
this.$(".select-box-header").css("height", computedHeight);
|
||||
this.$(".select-box-filter").css("height", computedHeight);
|
||||
|
||||
if (this.get("expanded")) {
|
||||
@ -169,14 +194,14 @@ export default Ember.Component.extend({
|
||||
this._applyFixedPosition(computedWidth, computedHeight);
|
||||
}
|
||||
|
||||
this.$(".select-box-body").css("width", computedWidth);
|
||||
this.$(".select-box-collection").css("max-height", this.get("maxCollectionHeight"));
|
||||
this.$(".select-box-collection").css("max-height", this.get("collectionHeight"));
|
||||
|
||||
this.applyDirection();
|
||||
|
||||
if (this.get("wrapper")) {
|
||||
this._positionSelectBoxWrapper();
|
||||
}
|
||||
Ember.run.schedule("afterRender", () => {
|
||||
this.applyDirection();
|
||||
if (this.get("wrapper")) {
|
||||
this._positionSelectBoxWrapper();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (this.get("wrapper")) {
|
||||
this.$(".select-box-wrapper").hide();
|
||||
@ -184,8 +209,42 @@ export default Ember.Component.extend({
|
||||
}
|
||||
},
|
||||
|
||||
keyDown(event) {
|
||||
const keyCode = event.keyCode || event.which;
|
||||
|
||||
if (this.get("expanded")) {
|
||||
if ((keyCode === 13 || keyCode === 9) && Ember.isPresent(this.get("highlightedValue"))) {
|
||||
event.preventDefault();
|
||||
this.send("onSelectRow", this.get("highlightedContent"));
|
||||
}
|
||||
|
||||
if (keyCode === 9) {
|
||||
this.set("expanded", false);
|
||||
}
|
||||
|
||||
if (keyCode === 27) {
|
||||
this.set("expanded", false);
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
if (keyCode === 38) {
|
||||
event.preventDefault();
|
||||
const self = this;
|
||||
Ember.run.throttle(self, this._handleUpArrow, 50);
|
||||
}
|
||||
|
||||
if (keyCode === 40) {
|
||||
event.preventDefault();
|
||||
const self = this;
|
||||
Ember.run.throttle(self, this._handleDownArrow, 50);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@on("didRender")
|
||||
_setupDocumentListeners: function() {
|
||||
$(document).off("click.select-box");
|
||||
|
||||
$(document)
|
||||
.on("click.select-box", (event) => {
|
||||
if (this.isDestroying || this.isDestroyed) { return; }
|
||||
@ -196,13 +255,6 @@ export default Ember.Component.extend({
|
||||
if (!$target.closest($element).length) {
|
||||
this.set("expanded", false);
|
||||
}
|
||||
})
|
||||
.on("keydown.select-box", (event) => {
|
||||
const keyCode = event.keyCode || event.which;
|
||||
|
||||
if (this.get("expanded") && keyCode === 9) {
|
||||
this.set("expanded", false);
|
||||
}
|
||||
});
|
||||
|
||||
$(window).on("resize.select-box", () => this.set("expanded", false) );
|
||||
@ -222,17 +274,12 @@ export default Ember.Component.extend({
|
||||
const keyCode = event.keyCode || event.which;
|
||||
|
||||
if (keyCode === 13 || keyCode === 40) {
|
||||
this.setProperties({expanded: true, focused: false});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (keyCode === 27) {
|
||||
this.$(".select-box-offscreen").blur();
|
||||
return false;
|
||||
this.setProperties({ expanded: true, focused: false });
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
if (keyCode >= 65 && keyCode <= 90) {
|
||||
this.setProperties({expanded: true, focused: false});
|
||||
this.setProperties({ expanded: true, focused: false });
|
||||
Ember.run.schedule("afterRender", () => {
|
||||
this.$(".filter-query").focus().val(String.fromCharCode(keyCode));
|
||||
});
|
||||
@ -243,7 +290,7 @@ export default Ember.Component.extend({
|
||||
@observes("expanded")
|
||||
_expandedChanged: function() {
|
||||
if (this.get("expanded")) {
|
||||
this.setProperties({ focused: false, renderBody: true });
|
||||
this.setProperties({ highlightedValue: null, renderBody: true, focused: false });
|
||||
|
||||
if (this.get("filterable")) {
|
||||
Ember.run.schedule("afterRender", () => this.$(".filter-query").focus());
|
||||
@ -251,17 +298,37 @@ export default Ember.Component.extend({
|
||||
};
|
||||
},
|
||||
|
||||
@computed("value", "content.[]")
|
||||
selectedContent(value, content) {
|
||||
@computed("value", "content.[]", "idKey")
|
||||
selectedContent(value, content, idKey) {
|
||||
if (Ember.isNone(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return content.find((c) => {
|
||||
return this._castInteger(c[this.get("idKey")]) === value;
|
||||
return this._castInteger(Ember.get(c, idKey)) === value;
|
||||
});
|
||||
},
|
||||
|
||||
@computed("highlightedValue", "content.[]", "idKey")
|
||||
highlightedContent(highlightedValue, content, idKey) {
|
||||
if (Ember.isNone(highlightedValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return content.find((c) => {
|
||||
return this._castInteger(Ember.get(c, idKey)) === highlightedValue;
|
||||
});
|
||||
},
|
||||
|
||||
@computed("headerText", "selectedContent", "textKey")
|
||||
selectedTitle(headerText, selectedContent, textKey) {
|
||||
if (Ember.isNone(selectedContent)) {
|
||||
return headerText;
|
||||
}
|
||||
|
||||
return selectedContent[textKey];
|
||||
},
|
||||
|
||||
@computed("headerText", "dynamicHeaderText", "selectedContent", "textKey", "clearSelectionLabel")
|
||||
generatedHeadertext(headerText, dynamic, selectedContent, textKey, clearSelectionLabel) {
|
||||
if (dynamic && !Ember.isNone(selectedContent)) {
|
||||
@ -275,14 +342,18 @@ export default Ember.Component.extend({
|
||||
return headerText;
|
||||
},
|
||||
|
||||
@computed("content.[]", "filter")
|
||||
filteredContent(content, filter) {
|
||||
@computed("content.[]", "filter", "idKey")
|
||||
filteredContent(content, filter, idKey) {
|
||||
let filteredContent;
|
||||
|
||||
if (Ember.isEmpty(filter)) {
|
||||
filteredContent = content;
|
||||
} else {
|
||||
filteredContent = this.filterFunction(content)(this);
|
||||
|
||||
if (!Ember.isEmpty(filteredContent)) {
|
||||
this.set("highlightedValue", filteredContent[0][idKey]);
|
||||
}
|
||||
}
|
||||
|
||||
return filteredContent;
|
||||
@ -302,19 +373,20 @@ export default Ember.Component.extend({
|
||||
this.set("filter", filter);
|
||||
},
|
||||
|
||||
onHoverRow(content) {
|
||||
const id = this._castInteger(Ember.get(content, this.get("idKey")));
|
||||
this.set("highlightedValue", id);
|
||||
},
|
||||
|
||||
onSelectRow(content) {
|
||||
this.setProperties({
|
||||
value: this._castInteger(content[this.get("idKey")]),
|
||||
value: this._castInteger(Ember.get(content, this.get("idKey"))),
|
||||
expanded: false
|
||||
});
|
||||
},
|
||||
|
||||
onClearSelection() {
|
||||
this.setProperties({ value: null, expanded: false });
|
||||
},
|
||||
|
||||
onHoverRow(content) {
|
||||
this.set("lastHovered", this._castInteger(content[this.get("idKey")]));
|
||||
}
|
||||
},
|
||||
|
||||
@ -362,5 +434,45 @@ export default Ember.Component.extend({
|
||||
});
|
||||
|
||||
this.get("scrollableParent").off("scroll.select-box");
|
||||
},
|
||||
|
||||
_handleDownArrow() {
|
||||
this._handleArrow("down");
|
||||
},
|
||||
|
||||
_handleUpArrow() {
|
||||
this._handleArrow("up");
|
||||
},
|
||||
|
||||
_handleArrow(direction) {
|
||||
const content = this.get("filteredContent");
|
||||
const idKey = this.get("idKey");
|
||||
const selectedContent = content.findBy(idKey, this.get("highlightedValue"));
|
||||
const currentIndex = content.indexOf(selectedContent);
|
||||
|
||||
if (direction === "down") {
|
||||
if (currentIndex < 0) {
|
||||
this.set("highlightedValue", this._castInteger(Ember.get(content[0], idKey)));
|
||||
} else if(currentIndex + 1 < content.length) {
|
||||
this.set("highlightedValue", this._castInteger(Ember.get(content[currentIndex + 1], idKey)));
|
||||
}
|
||||
} else {
|
||||
if (currentIndex <= 0) {
|
||||
this.set("highlightedValue", this._castInteger(Ember.get(content[0], idKey)));
|
||||
} else if(currentIndex - 1 < content.length) {
|
||||
this.set("highlightedValue", this._castInteger(Ember.get(content[currentIndex - 1], idKey)));
|
||||
}
|
||||
}
|
||||
|
||||
Ember.run.schedule("afterRender", () => {
|
||||
const $highlightedRow = this.$(".select-box-row.is-highlighted");
|
||||
|
||||
if ($highlightedRow.length === 0) { return; }
|
||||
|
||||
const $collection = this.$(".select-box-collection");
|
||||
const rowOffset = $highlightedRow.offset();
|
||||
const bodyOffset = $collection.offset();
|
||||
$collection.scrollTop(rowOffset.top - bodyOffset.top);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -9,8 +9,9 @@ export default Ember.Component.extend({
|
||||
this._setCaretIcon();
|
||||
},
|
||||
|
||||
click() {
|
||||
click(event) {
|
||||
this.sendAction("onToggle");
|
||||
event.stopPropagation();
|
||||
},
|
||||
|
||||
_setCaretIcon() {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
layoutName: "components/select-box/select-box-row",
|
||||
@ -9,7 +10,7 @@ export default Ember.Component.extend({
|
||||
|
||||
attributeBindings: ["title"],
|
||||
|
||||
classNameBindings: ["isHighlighted:is-highlighted"],
|
||||
classNameBindings: ["isHighlighted:is-highlighted", "isSelected:is-selected"],
|
||||
|
||||
@computed("titleForRow")
|
||||
title(titleForRow) {
|
||||
@ -21,11 +22,26 @@ export default Ember.Component.extend({
|
||||
return templateForRow(this);
|
||||
},
|
||||
|
||||
@computed("shouldHighlightRow", "lastHovered", "value")
|
||||
@computed("shouldHighlightRow", "highlightedValue")
|
||||
isHighlighted(shouldHighlightRow) {
|
||||
return shouldHighlightRow(this);
|
||||
},
|
||||
|
||||
@computed("shouldSelectRow", "value")
|
||||
isSelected(shouldSelectRow) {
|
||||
return shouldSelectRow(this);
|
||||
},
|
||||
|
||||
icon() {
|
||||
if (this.get("content.icon")) {
|
||||
const iconName = this.get("content.icon");
|
||||
const iconClass = this.get("content.iconClass");
|
||||
return iconHTML(iconName, { class: iconClass });
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
mouseEnter() {
|
||||
this.sendAction("onHover", this.get("content"));
|
||||
},
|
||||
|
||||
@ -62,6 +62,7 @@ const SiteHeaderComponent = MountWidget.extend(Docking, {
|
||||
|
||||
this.dispatch('notifications:changed', 'user-notifications');
|
||||
this.dispatch('header:keyboard-trigger', 'header');
|
||||
this.dispatch('search-autocomplete:after-complete', 'search-term');
|
||||
|
||||
this.appEvents.on('dom:clean', () => {
|
||||
// For performance, only trigger a re-render if any menu panels are visible
|
||||
|
||||
@ -22,7 +22,7 @@ export default Ember.Component.extend({
|
||||
|
||||
@computed('expanded')
|
||||
expandedIcon(expanded) {
|
||||
return expanded ? 'caret-down' : 'caret-right';
|
||||
return expanded ? 'd-drop-expanded' : 'd-drop-collapsed';
|
||||
},
|
||||
|
||||
@computed('tagId')
|
||||
|
||||
@ -1,11 +1,24 @@
|
||||
import NotificationsButton from 'discourse/components/notifications-button';
|
||||
import NotificationOptionsComponent from "discourse/components/notifications-button";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { iconHTML } from "discourse-common/lib/icon-library";
|
||||
|
||||
export default NotificationsButton.extend({
|
||||
classNames: ['notification-options', 'tag-notification-menu'],
|
||||
buttonIncludesText: false,
|
||||
i18nPrefix: 'tagging.notifications',
|
||||
export default NotificationOptionsComponent.extend({
|
||||
classNames: ["tag-notifications-button"],
|
||||
|
||||
clicked(id) {
|
||||
this.sendAction('action', id);
|
||||
i18nPrefix: "tagging.notifications",
|
||||
|
||||
@computed("value")
|
||||
icon() {
|
||||
return `${this._super()}${iconHTML("caret-down")}`.htmlSafe();
|
||||
},
|
||||
|
||||
generatedHeadertext: null,
|
||||
|
||||
actions: {
|
||||
onSelectRow(content) {
|
||||
this._super(content);
|
||||
|
||||
this.sendAction("action", this.get("value"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -15,7 +15,7 @@ export default Ember.Component.extend({
|
||||
|
||||
@computed
|
||||
showAdminButton() {
|
||||
return !this.site.mobileView && this.currentUser.get('canManageTopic');
|
||||
return !this.site.mobileView && this.currentUser && this.currentUser.get('canManageTopic');
|
||||
},
|
||||
|
||||
@computed('topic.message_archived')
|
||||
|
||||
@ -8,7 +8,7 @@ export default SelectBoxComponent.extend({
|
||||
|
||||
dynamicHeaderText: false,
|
||||
|
||||
maxCollectionHeight: 300,
|
||||
collectionHeight: 300,
|
||||
|
||||
init() {
|
||||
this._super();
|
||||
|
||||
@ -23,7 +23,7 @@ export function showEntrance(e) {
|
||||
export default Ember.Component.extend(bufferedRender({
|
||||
rerenderTriggers: ['bulkSelectEnabled', 'topic.pinned'],
|
||||
tagName: 'tr',
|
||||
classNameBindings: [':topic-list-item', 'unboundClassNames'],
|
||||
classNameBindings: [':topic-list-item', 'unboundClassNames', 'topic.visited'],
|
||||
attributeBindings: ['data-topic-id'],
|
||||
'data-topic-id': Em.computed.alias('topic.id'),
|
||||
|
||||
|
||||
@ -1,21 +1,9 @@
|
||||
import MountWidget from 'discourse/components/mount-widget';
|
||||
import { observes } from 'ember-addons/ember-computed-decorators';
|
||||
export default Ember.Component.extend({
|
||||
layoutName: "components/topic-notifications-button",
|
||||
|
||||
export default MountWidget.extend({
|
||||
classNames: ['topic-notifications-container'],
|
||||
widget: 'topic-notifications-button',
|
||||
classNames: ["topic-notifications-button"],
|
||||
|
||||
buildArgs() {
|
||||
return { topic: this.get('topic'), appendReason: true, showFullTitle: true };
|
||||
},
|
||||
showFullTitle: true,
|
||||
|
||||
@observes('topic.details.notification_level')
|
||||
_queueRerender() {
|
||||
this.queueRerender();
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super();
|
||||
this.dispatch('topic-notifications-button:changed', 'topic-notifications-button');
|
||||
}
|
||||
appendReason: true,
|
||||
});
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
import NotificationOptionsComponent from "discourse/components/notifications-button";
|
||||
import { on } from "ember-addons/ember-computed-decorators";
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { topicLevels, buttonDetails } from "discourse/lib/notification-levels";
|
||||
|
||||
export default NotificationOptionsComponent.extend({
|
||||
classNames: ["topic-notifications-options"],
|
||||
|
||||
content: topicLevels,
|
||||
|
||||
i18nPrefix: "topic.notifications",
|
||||
|
||||
value: Ember.computed.alias("topic.details.notification_level"),
|
||||
|
||||
@on("didInsertElement")
|
||||
_bindGlobalLevelChanged() {
|
||||
this.appEvents.on("topic-notifications-button:changed", (msg) => {
|
||||
if (msg.type === "notification") {
|
||||
if (this.get("value") !== msg.id) {
|
||||
this.get("topic.details").updateNotifications(msg.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@on("willDestroyElement")
|
||||
_unbindGlobalLevelChanged() {
|
||||
this.appEvents.off("topic-notifications-button:changed");
|
||||
},
|
||||
|
||||
@computed("value", "showFullTitle")
|
||||
generatedHeadertext(value, showFullTitle) {
|
||||
if (showFullTitle) {
|
||||
const details = buttonDetails(value);
|
||||
return I18n.t(`topic.notifications.${details.key}.title`);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
onSelectRow(content) {
|
||||
const notificationLevelId = Ember.get(content, this.get("idKey"));
|
||||
|
||||
if (notificationLevelId !== this.get("value")) {
|
||||
this.get("topic.details").updateNotifications(notificationLevelId);
|
||||
}
|
||||
|
||||
this._super(content);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -84,6 +84,5 @@ export default MountWidget.extend(Docking, {
|
||||
}
|
||||
|
||||
this.dispatch('topic:current-post-scrolled', 'timeline-scrollarea');
|
||||
this.dispatch('topic-notifications-button:changed', 'topic-notifications-button');
|
||||
}
|
||||
});
|
||||
|
||||
@ -4,7 +4,7 @@ import Category from 'discourse/models/category';
|
||||
|
||||
export default Ember.Component.extend(bufferedRender({
|
||||
classNames: ['topic-status-info'],
|
||||
delayedRerender: null,
|
||||
_delayedRerender: null,
|
||||
|
||||
rerenderTriggers: [
|
||||
'statusType',
|
||||
@ -58,12 +58,14 @@ export default Ember.Component.extend(bufferedRender({
|
||||
buffer.push('</h3>');
|
||||
|
||||
// TODO Sam: concerned this can cause a heavy rerender loop
|
||||
this.set('delayedRerender', Em.run.later(this, this.rerender, rerenderDelay));
|
||||
if (!Ember.testing) {
|
||||
this._delayedRerender = Ember.run.later(this, this.rerender, rerenderDelay);
|
||||
}
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
if( this.delayedRerender ) {
|
||||
Em.run.cancel(this.get('delayedRerender'));
|
||||
if (this._delayedRerender) {
|
||||
Em.run.cancel(this._delayedRerender);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ function addBulkButton(action, key, opts) {
|
||||
addBulkButton('showChangeCategory', 'change_category', {icon: 'pencil'});
|
||||
addBulkButton('closeTopics', 'close_topics', {icon: 'lock'});
|
||||
addBulkButton('archiveTopics', 'archive_topics', {icon: 'folder'});
|
||||
addBulkButton('showNotificationLevel', 'notification_level', {icon: 'circle-o'});
|
||||
addBulkButton('showNotificationLevel', 'notification_level', {icon: 'd-regular'});
|
||||
addBulkButton('resetRead', 'reset_read', {icon: 'backward'});
|
||||
addBulkButton('unlistTopics', 'unlist_topics', {
|
||||
icon: 'eye-slash',
|
||||
|
||||
@ -827,7 +827,7 @@ export default Ember.Controller.extend(SelectedPostsCount, BufferedContent, {
|
||||
this.messageBus.subscribe(`/topic/${this.get('model.id')}`, data => {
|
||||
const topic = this.get('model');
|
||||
|
||||
if (data.notification_level_change) {
|
||||
if (Ember.isPresent(data.notification_level_change)) {
|
||||
topic.set('details.notification_level', data.notification_level_change);
|
||||
topic.set('details.notifications_reason_id', data.notifications_reason_id);
|
||||
return;
|
||||
|
||||
@ -7,10 +7,6 @@ registerUnbound('topic-link', (topic, args) => {
|
||||
topic.get('lastUnreadUrl');
|
||||
|
||||
const classes = ['title'];
|
||||
if (topic.get('last_read_post_number') === topic.get('highest_post_number')) {
|
||||
classes.push('visited');
|
||||
}
|
||||
|
||||
if (args.class) {
|
||||
args.class.split(" ").forEach(c => classes.push(c));
|
||||
}
|
||||
|
||||
@ -9,15 +9,15 @@ export const NotificationLevels = { WATCHING_FIRST_POST, WATCHING, TRACKING, REG
|
||||
export function buttonDetails(level) {
|
||||
switch(level) {
|
||||
case WATCHING_FIRST_POST:
|
||||
return { id: WATCHING_FIRST_POST, key: 'watching_first_post', icon: 'dot-circle-o' };
|
||||
return { id: WATCHING_FIRST_POST, key: 'watching_first_post', icon: 'd-watching-first' };
|
||||
case WATCHING:
|
||||
return { id: WATCHING, key: 'watching', icon: 'exclamation-circle' };
|
||||
return { id: WATCHING, key: 'watching', icon: 'd-watching' };
|
||||
case TRACKING:
|
||||
return { id: TRACKING, key: 'tracking', icon: 'circle' };
|
||||
return { id: TRACKING, key: 'tracking', icon: 'd-tracking' };
|
||||
case MUTED:
|
||||
return { id: MUTED, key: 'muted', icon: 'times-circle' };
|
||||
return { id: MUTED, key: 'muted', icon: 'd-muted' };
|
||||
default:
|
||||
return { id: REGULAR, key: 'regular', icon: 'circle-o' };
|
||||
return { id: REGULAR, key: 'regular', icon: 'd-regular' };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -35,6 +35,7 @@ export function transformBasicPost(post) {
|
||||
primary_group_flair_bg_color: post.primary_group_flair_bg_color,
|
||||
primary_group_flair_color: post.primary_group_flair_color,
|
||||
wiki: post.wiki,
|
||||
lastWikiEdit: post.last_wiki_edit,
|
||||
firstPost: post.post_number === 1,
|
||||
post_number: post.post_number,
|
||||
cooked: post.cooked,
|
||||
|
||||
@ -2,6 +2,9 @@ import { ajax } from 'discourse/lib/ajax';
|
||||
import { default as computed, observes } from "ember-addons/ember-computed-decorators";
|
||||
import GroupHistory from 'discourse/models/group-history';
|
||||
import RestModel from 'discourse/models/rest';
|
||||
import Category from "discourse/models/category";
|
||||
import User from "discourse/models/user";
|
||||
import Topic from "discourse/models/topic";
|
||||
|
||||
const Group = RestModel.extend({
|
||||
limit: 50,
|
||||
@ -44,9 +47,9 @@ const Group = RestModel.extend({
|
||||
if (ownerIds[member.id]) {
|
||||
member.owner = true;
|
||||
}
|
||||
return Discourse.User.create(member);
|
||||
return User.create(member);
|
||||
}),
|
||||
owners: result.owners.map(owner => Discourse.User.create(owner)),
|
||||
owners: result.owners.map(owner => User.create(owner)),
|
||||
});
|
||||
});
|
||||
},
|
||||
@ -207,8 +210,9 @@ const Group = RestModel.extend({
|
||||
|
||||
return ajax(`/groups/${this.get('name')}/${type}.json`, { data: data }).then(posts => {
|
||||
return posts.map(p => {
|
||||
p.user = Discourse.User.create(p.user);
|
||||
p.topic = Discourse.Topic.create(p.topic);
|
||||
p.user = User.create(p.user);
|
||||
p.topic = Topic.create(p.topic);
|
||||
p.category = Category.findById(p.category_id);
|
||||
return Em.Object.create(p);
|
||||
});
|
||||
});
|
||||
|
||||
@ -33,6 +33,11 @@ const Topic = RestModel.extend({
|
||||
message: null,
|
||||
errorLoading: false,
|
||||
|
||||
@computed('last_read_post_number', 'highest_post_number')
|
||||
visited(lastReadPostNumber, highestPostNumber) {
|
||||
return lastReadPostNumber === highestPostNumber;
|
||||
},
|
||||
|
||||
@computed('posters.firstObject')
|
||||
creator(poster){
|
||||
return poster && poster.user;
|
||||
@ -407,6 +412,10 @@ const Topic = RestModel.extend({
|
||||
});
|
||||
},
|
||||
|
||||
@computed('excerpt')
|
||||
escapedExcerpt(excerpt) {
|
||||
return emojiUnescape(excerpt);
|
||||
},
|
||||
|
||||
hasExcerpt: Em.computed.notEmpty('excerpt'),
|
||||
|
||||
|
||||
@ -34,7 +34,11 @@ export default Discourse.Route.extend({
|
||||
});
|
||||
} else {
|
||||
$.cookie('destination_url', window.location.href);
|
||||
this.replaceWith('login');
|
||||
if (Discourse.showingSignup) {
|
||||
Discourse.showingSignup = false;
|
||||
} else {
|
||||
self.replaceWith('login');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,12 @@ export default Discourse.Route.extend({
|
||||
} else {
|
||||
// User is not logged in
|
||||
$.cookie('destination_url', window.location.href);
|
||||
self.replaceWith('login');
|
||||
if (Discourse.showingSignup) {
|
||||
// We're showing the sign up modal
|
||||
Discourse.showingSignup = false;
|
||||
} else {
|
||||
self.replaceWith('login');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
{{#if category.read_restricted}}
|
||||
{{d-icon "lock"}}
|
||||
{{/if}}
|
||||
{{category.name}}
|
||||
<span class='d-label'>{{category.name}}</span>
|
||||
</a>
|
||||
{{else}}
|
||||
{{#if noSubcategories}}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
<button
|
||||
class="btn {{if text 'btn-icon-text' 'no-text btn-icon'}}"
|
||||
aria-label="{{selectedTitle}}"
|
||||
type="button"
|
||||
title="{{selectedTitle}}">
|
||||
|
||||
{{{icon}}}
|
||||
|
||||
{{#if text}}
|
||||
<span class="d-button-label">{{{text}}}</span>
|
||||
{{/if}}
|
||||
</button>
|
||||
@ -0,0 +1,5 @@
|
||||
{{pinned-options topic=topic}}
|
||||
|
||||
<p class="reason">
|
||||
{{{reasonText}}}
|
||||
</p>
|
||||
@ -9,6 +9,7 @@
|
||||
|
||||
{{component selectBoxHeaderComponent
|
||||
text=generatedHeadertext
|
||||
selectedTitle=selectedTitle
|
||||
focused=focused
|
||||
caretUpIcon=caretUpIcon
|
||||
caretDownIcon=caretDownIcon
|
||||
@ -26,6 +27,7 @@
|
||||
icon=filterIcon
|
||||
focused=filterFocused
|
||||
placeholder=filterPlaceholder
|
||||
tabindex=tabindex
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
@ -35,12 +37,13 @@
|
||||
selectBoxRowComponent=selectBoxRowComponent
|
||||
templateForRow=templateForRow
|
||||
shouldHighlightRow=shouldHighlightRow
|
||||
shouldSelectRow=shouldSelectRow
|
||||
titleForRow=titleForRow
|
||||
lastHovered=lastHovered
|
||||
onSelectRow=(action "onSelectRow")
|
||||
onHoverRow=(action "onHoverRow")
|
||||
onClearSelection=(action "onClearSelection")
|
||||
noContentLabel=noContentLabel
|
||||
highlightedValue=highlightedValue
|
||||
value=value
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
@ -11,7 +11,8 @@
|
||||
templateForRow=templateForRow
|
||||
titleForRow=titleForRow
|
||||
shouldHighlightRow=shouldHighlightRow
|
||||
lastHovered=lastHovered
|
||||
shouldSelectRow=shouldSelectRow
|
||||
highlightedValue=highlightedValue
|
||||
onSelect=onSelectRow
|
||||
onHover=onHoverRow
|
||||
value=value
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{{input
|
||||
tabindex="-1"
|
||||
tabindex=tabindex
|
||||
class="filter-query"
|
||||
placeholder=placeholder
|
||||
key-up=onFilterChange
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
{{d-icon icon class="icon"}}
|
||||
{{/if}}
|
||||
|
||||
<span class="current-selection">
|
||||
<span class="current-selection" title={{selectedTitle}}>
|
||||
{{text}}
|
||||
</span>
|
||||
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
{{topic-notifications-options topic=topic showFullTitle=showFullTitle}}
|
||||
|
||||
{{#if appendReason}}
|
||||
<p class="reason">
|
||||
{{{topic.details.notificationReasonText}}}
|
||||
</p>
|
||||
{{/if}}
|
||||
@ -1,6 +1,6 @@
|
||||
{{#if topic.hasExcerpt}}
|
||||
<div class="topic-excerpt">
|
||||
{{{topic.excerpt}}}
|
||||
{{{topic.escapedExcerpt}}}
|
||||
{{#if topic.excerptTruncated}}
|
||||
<a href="{{topic.url}}">{{i18n 'read_more'}}</a>
|
||||
{{/if}}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<table class="topic-list">
|
||||
<tbody>
|
||||
{{#each topics as |t|}}
|
||||
<tr class="{{if t.archived 'archived'}}" data-topic-id={{t.id}}>
|
||||
<tr class="{{if t.archived 'archived'}} {{if t.visited 'visited'}}" data-topic-id={{t.id}}>
|
||||
<td>
|
||||
<div class='main-link'>
|
||||
{{topic-status topic=t}}
|
||||
|
||||
@ -33,4 +33,3 @@
|
||||
{{plugin-outlet name="category-navigation" args=(hash category=category)}}
|
||||
</div>
|
||||
{{/d-section}}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<label class="control-label">{{i18n 'user.categories_settings'}}</label>
|
||||
|
||||
<div class="controls category-controls">
|
||||
<label>{{d-icon "exclamation-circle" class="icon watching"}} {{i18n 'user.watched_categories'}}</label>
|
||||
<label>{{d-icon "d-watching" class="icon watching"}} {{i18n 'user.watched_categories'}}</label>
|
||||
{{category-selector categories=model.watchedCategories blacklist=selectedCategories}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n 'user.watched_categories_instructions'}}</div>
|
||||
@ -12,7 +12,7 @@
|
||||
</div>
|
||||
|
||||
<div class="controls category-controls">
|
||||
<label>{{d-icon "circle" class="icon tracking"}} {{i18n 'user.tracked_categories'}}</label>
|
||||
<label>{{d-icon "d-tracking" class="icon tracking"}} {{i18n 'user.tracked_categories'}}</label>
|
||||
{{category-selector categories=model.trackedCategories blacklist=selectedCategories}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n 'user.tracked_categories_instructions'}}</div>
|
||||
@ -21,13 +21,13 @@
|
||||
</div>
|
||||
|
||||
<div class="controls category-controls">
|
||||
<label>{{d-icon "dot-circle-o" class="icon watching-first-post"}} {{i18n 'user.watched_first_post_categories'}}</label>
|
||||
<label>{{d-icon "d-watching-first" class="icon watching-first-post"}} {{i18n 'user.watched_first_post_categories'}}</label>
|
||||
{{category-selector categories=model.watchedFirstPostCategories}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n 'user.watched_first_post_categories_instructions'}}</div>
|
||||
|
||||
<div class="controls category-controls">
|
||||
<label>{{d-icon "times-circle" class="icon muted"}} {{i18n 'user.muted_categories'}}</label>
|
||||
<label>{{d-icon "d-muted" class="icon muted"}} {{i18n 'user.muted_categories'}}</label>
|
||||
{{category-selector categories=model.mutedCategories blacklist=selectedCategories}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n 'user.muted_categories_instructions'}}</div>
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
<div class="control-group muting">
|
||||
<label class="control-label">{{i18n 'user.users'}}</label>
|
||||
<div class="controls category-controls">
|
||||
<label>{{d-icon "times-circle" class="muted icon"}} {{i18n 'user.muted_users'}}</label>
|
||||
<label>{{d-icon "d-muted" class="muted icon"}} {{i18n 'user.muted_users'}}</label>
|
||||
{{user-selector excludeCurrentUser=true usernames=model.muted_usernames class="user-selector"}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n 'user.muted_users_instructions'}}</div>
|
||||
|
||||
@ -4,25 +4,25 @@
|
||||
<label class="control-label">{{i18n 'user.tag_settings'}}</label>
|
||||
|
||||
<div class="controls tag-controls">
|
||||
<label>{{d-icon "exclamation-circle" class="icon watching"}} {{i18n 'user.watched_tags'}}</label>
|
||||
<label>{{d-icon "d-watching" class="icon watching"}} {{i18n 'user.watched_tags'}}</label>
|
||||
{{tag-chooser tags=model.watched_tags blacklist=selectedTags allowCreate=false placeholder="" everyTag="true" unlimitedTagCount="true"}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n 'user.watched_tags_instructions'}}</div>
|
||||
|
||||
<div class="controls tag-controls">
|
||||
<label>{{d-icon "circle" class="icon tracking"}} {{i18n 'user.tracked_tags'}}</label>
|
||||
<label>{{d-icon "d-regular" class="icon tracking"}} {{i18n 'user.tracked_tags'}}</label>
|
||||
{{tag-chooser tags=model.tracked_tags blacklist=selectedTags allowCreate=false placeholder="" everyTag="true" unlimitedTagCount="true"}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n 'user.tracked_tags_instructions'}}</div>
|
||||
|
||||
<div class="controls tag-controls">
|
||||
<label>{{d-icon "dot-circle-o" class="icon watching-first-post"}} {{i18n 'user.watched_first_post_tags'}}</label>
|
||||
<label>{{d-icon "d-watching-first" class="icon watching-first-post"}} {{i18n 'user.watched_first_post_tags'}}</label>
|
||||
{{tag-chooser tags=model.watching_first_post_tags blacklist=selectedTags allowCreate=false placeholder="" everyTag="true" unlimitedTagCount="true"}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n 'user.watched_first_post_tags_instructions'}}</div>
|
||||
|
||||
<div class="controls tag-controls">
|
||||
<label>{{d-icon "times-circle" class="icon muted"}} {{i18n 'user.muted_tags'}}</label>
|
||||
<label>{{d-icon "d-muted" class="icon muted"}} {{i18n 'user.muted_tags'}}</label>
|
||||
{{tag-chooser tags=model.muted_tags blacklist=selectedTags allowCreate=false placeholder="" everyTag="true" unlimitedTagCount="true"}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n 'user.muted_tags_instructions'}}</div>
|
||||
|
||||
@ -3,8 +3,11 @@
|
||||
<p>
|
||||
{{{stopNotificiationsText}}}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
{{i18n "topic.unsubscribe.change_notification_state"}} {{topic-notifications-button topic=model}}
|
||||
{{i18n "topic.unsubscribe.change_notification_state"}}
|
||||
</p>
|
||||
|
||||
{{topic-notifications-button topic=model}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -116,7 +116,6 @@
|
||||
<div style='clear: both'></div>
|
||||
</div>
|
||||
|
||||
|
||||
{{#unless collapsedInfo}}
|
||||
<div class='secondary'>
|
||||
<dl>
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
export default class ComponentConnector {
|
||||
constructor(widget, componentName, opts) {
|
||||
this.widget = widget;
|
||||
this.opts = opts;
|
||||
this.componentName = componentName;
|
||||
}
|
||||
|
||||
init() {
|
||||
const $elem = $('<div style="display: inline-block;" class="widget-component-connector"></div>');
|
||||
const elem = $elem[0];
|
||||
const { opts, widget, componentName } = this;
|
||||
|
||||
Ember.run.next(() => {
|
||||
const mounted = widget._findView();
|
||||
|
||||
const view = widget
|
||||
.register
|
||||
.lookupFactory(`component:${componentName}`)
|
||||
.create(opts);
|
||||
|
||||
if (Ember.setOwner) {
|
||||
Ember.setOwner(view, Ember.getOwner(mounted));
|
||||
}
|
||||
|
||||
mounted._connected.push(view);
|
||||
view.renderer.appendTo(view, $elem[0]);
|
||||
});
|
||||
|
||||
return elem;
|
||||
}
|
||||
|
||||
update() { }
|
||||
}
|
||||
|
||||
ComponentConnector.prototype.type = 'Widget';
|
||||
@ -2,21 +2,21 @@ import PostCooked from 'discourse/widgets/post-cooked';
|
||||
import DecoratorHelper from 'discourse/widgets/decorator-helper';
|
||||
import { createWidget } from 'discourse/widgets/widget';
|
||||
import { h } from 'virtual-dom';
|
||||
import { iconNode } from 'discourse-common/lib/icon-library';
|
||||
import DiscourseURL from 'discourse/lib/url';
|
||||
import hbs from 'discourse/widgets/hbs-compiler';
|
||||
|
||||
createWidget('post-link-arrow', {
|
||||
html(attrs) {
|
||||
if (attrs.above) {
|
||||
return h('a.post-info.arrow', {
|
||||
attributes: { title: I18n.t('topic.jump_reply_up') }
|
||||
}, iconNode('arrow-up'));
|
||||
} else {
|
||||
return h('a.post-info.arrow', {
|
||||
attributes: { title: I18n.t('topic.jump_reply_down') }
|
||||
}, iconNode('arrow-down'));
|
||||
}
|
||||
},
|
||||
template: hbs`
|
||||
{{#if attrs.above}}
|
||||
<a class="post-info arrow" title={{i18n "topic.jump_reply_up"}}>
|
||||
{{fa-icon "arrow-up"}}
|
||||
</a>
|
||||
{{else}}
|
||||
<a class="post-info arrow" title={{i18n "topic.jump_reply_down"}}>
|
||||
{{fa-icon "arrow-down"}}
|
||||
</a>
|
||||
{{/if}}
|
||||
`,
|
||||
|
||||
click() {
|
||||
DiscourseURL.routeTo(this.attrs.shareUrl);
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
export default function hbs() {
|
||||
console.log('Templates should be precompiled server side');
|
||||
}
|
||||
@ -28,23 +28,26 @@ createWidget('header-notifications', {
|
||||
},
|
||||
|
||||
html(attrs) {
|
||||
const { currentUser } = this;
|
||||
const { user } = attrs;
|
||||
|
||||
const contents = [ avatarImg(this.settings.avatarSize, {
|
||||
template: currentUser.get('avatar_template'),
|
||||
username: currentUser.get('username')
|
||||
template: user.get('avatar_template'),
|
||||
username: user.get('username')
|
||||
}) ];
|
||||
|
||||
const unreadNotifications = currentUser.get('unread_notifications');
|
||||
const unreadNotifications = user.get('unread_notifications');
|
||||
if (!!unreadNotifications) {
|
||||
contents.push(this.attach('link', { action: attrs.action,
|
||||
className: 'badge-notification unread-notifications',
|
||||
rawLabel: unreadNotifications }));
|
||||
contents.push(this.attach('link', {
|
||||
action: attrs.action,
|
||||
className: 'badge-notification unread-notifications',
|
||||
rawLabel: unreadNotifications,
|
||||
omitSpan: true
|
||||
}));
|
||||
}
|
||||
|
||||
const unreadPMs = currentUser.get('unread_private_messages');
|
||||
const unreadPMs = user.get('unread_private_messages');
|
||||
if (!!unreadPMs) {
|
||||
if (!currentUser.get('read_first_notification')) {
|
||||
if (!user.get('read_first_notification')) {
|
||||
contents.push(h('span.ring'));
|
||||
if (!attrs.active && attrs.ringBackdrop) {
|
||||
contents.push(h('span.ring-backdrop-spotlight'));
|
||||
@ -55,9 +58,12 @@ createWidget('header-notifications', {
|
||||
}
|
||||
};
|
||||
|
||||
contents.push(this.attach('link', { action: attrs.action,
|
||||
className: 'badge-notification unread-private-messages',
|
||||
rawLabel: unreadPMs }));
|
||||
contents.push(this.attach('link', {
|
||||
action: attrs.action,
|
||||
className: 'badge-notification unread-private-messages',
|
||||
rawLabel: unreadPMs,
|
||||
omitSpan: true
|
||||
}));
|
||||
}
|
||||
|
||||
return contents;
|
||||
@ -72,9 +78,7 @@ createWidget('user-dropdown', jQuery.extend({
|
||||
},
|
||||
|
||||
html(attrs) {
|
||||
const { currentUser } = this;
|
||||
|
||||
return h('a.icon', { attributes: { href: currentUser.get('path'), 'data-auto-route': true } },
|
||||
return h('a.icon', { attributes: { href: attrs.user.get('path'), 'data-auto-route': true } },
|
||||
this.attach('header-notifications', attrs));
|
||||
}
|
||||
}, dropdown));
|
||||
@ -106,7 +110,7 @@ createWidget('header-dropdown', jQuery.extend({
|
||||
}, dropdown));
|
||||
|
||||
createWidget('header-icons', {
|
||||
tagName: 'ul.icons.clearfix',
|
||||
tagName: 'ul.icons.d-header-icons.clearfix',
|
||||
|
||||
buildAttributes() {
|
||||
return { role: 'navigation' };
|
||||
@ -139,10 +143,13 @@ createWidget('header-icons', {
|
||||
});
|
||||
|
||||
const icons = [search, hamburger];
|
||||
if (this.currentUser) {
|
||||
icons.push(this.attach('user-dropdown', { active: attrs.userVisible,
|
||||
action: 'toggleUserMenu',
|
||||
ringBackdrop: attrs.ringBackdrop }));
|
||||
if (attrs.user) {
|
||||
icons.push(this.attach('user-dropdown', {
|
||||
active: attrs.userVisible,
|
||||
action: 'toggleUserMenu',
|
||||
ringBackdrop: attrs.ringBackdrop,
|
||||
user: attrs.user
|
||||
}));
|
||||
}
|
||||
|
||||
return icons;
|
||||
@ -204,7 +211,8 @@ export default createWidget('header', {
|
||||
userVisible: state.userVisible,
|
||||
searchVisible: state.searchVisible,
|
||||
ringBackdrop: state.ringBackdrop,
|
||||
flagCount: attrs.flagCount })];
|
||||
flagCount: attrs.flagCount,
|
||||
user: this.currentUser })];
|
||||
|
||||
if (state.searchVisible) {
|
||||
const contextType = this.searchContextType();
|
||||
|
||||
@ -54,7 +54,13 @@ export default createWidget('link', {
|
||||
}
|
||||
|
||||
if (!attrs.hideLabel) {
|
||||
result.push(this.label(attrs));
|
||||
let label = this.label(attrs);
|
||||
|
||||
if (attrs.omitSpan) {
|
||||
result.push(label);
|
||||
} else {
|
||||
result.push(h('span.d-label', label));
|
||||
}
|
||||
}
|
||||
|
||||
const currentUser = this.currentUser;
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import hbs from 'discourse/widgets/hbs-compiler';
|
||||
import { createWidget } from 'discourse/widgets/widget';
|
||||
import { h } from 'virtual-dom';
|
||||
|
||||
@ -23,14 +24,17 @@ createWidget('menu-links', {
|
||||
|
||||
createWidget('menu-panel', {
|
||||
tagName: 'div.menu-panel',
|
||||
template: hbs`
|
||||
<div class='panel-body'>
|
||||
<div class='panel-body-contents clearfix'>
|
||||
{{yield}}
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
|
||||
buildAttributes(attrs) {
|
||||
if (attrs.maxWidth) {
|
||||
return { 'data-max-width': attrs.maxWidth };
|
||||
}
|
||||
},
|
||||
|
||||
html(attrs) {
|
||||
return h('div.panel-body', h('div.panel-body-contents.clearfix', attrs.contents()));
|
||||
}
|
||||
});
|
||||
|
||||
@ -173,20 +173,18 @@ registerButton('reply', attrs => {
|
||||
registerButton('bookmark', attrs => {
|
||||
if (!attrs.canBookmark) { return; }
|
||||
|
||||
let iconClass = 'read-icon';
|
||||
let buttonClass = 'bookmark';
|
||||
let tooltip = 'bookmarks.not_bookmarked';
|
||||
let className = 'bookmark';
|
||||
|
||||
if (attrs.bookmarked) {
|
||||
iconClass += ' bookmarked';
|
||||
buttonClass += ' bookmarked';
|
||||
tooltip = 'bookmarks.created';
|
||||
className += ' bookmarked';
|
||||
}
|
||||
|
||||
return { action: 'toggleBookmark',
|
||||
title: tooltip,
|
||||
className: buttonClass,
|
||||
contents: h('div', { className: iconClass }) };
|
||||
return {
|
||||
action: 'toggleBookmark',
|
||||
title: attrs.bookmarked ? "bookmarks.created" : "bookmarks.not_bookmarked",
|
||||
className,
|
||||
icon: 'bookmark'
|
||||
};
|
||||
});
|
||||
|
||||
registerButton('admin', attrs => {
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
import { createWidget } from 'discourse/widgets/widget';
|
||||
import { h } from 'virtual-dom';
|
||||
import hbs from 'discourse/widgets/hbs-compiler';
|
||||
|
||||
export default createWidget('post-placeholder', {
|
||||
tagName: 'article.placeholder',
|
||||
|
||||
html() {
|
||||
return h('div.row', [
|
||||
h('div.topic-avatar', h('div.placeholder-avatar')),
|
||||
h('div.topic-body', [
|
||||
h('div.placeholder-text'),
|
||||
h('div.placeholder-text'),
|
||||
h('div.placeholder-text')
|
||||
])
|
||||
]);
|
||||
}
|
||||
template: hbs`
|
||||
<div class='row'>
|
||||
<div class='topic-avatar'>
|
||||
<div class='placeholder-avatar'></div>
|
||||
</div>
|
||||
<div class='topic-body'>
|
||||
<div class='placeholder-text'></div>
|
||||
<div class='placeholder-text'></div>
|
||||
<div class='placeholder-text'></div>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
});
|
||||
|
||||
@ -171,19 +171,22 @@ createWidget('post-meta-data', {
|
||||
}, iconNode('eye-slash')));
|
||||
}
|
||||
|
||||
const lastWikiEdit = attrs.wiki && attrs.lastWikiEdit && new Date(attrs.lastWikiEdit);
|
||||
const createdAt = new Date(attrs.created_at);
|
||||
if (createdAt) {
|
||||
result.push(h('div.post-info',
|
||||
h('a.post-date', {
|
||||
attributes: {
|
||||
href: attrs.shareUrl,
|
||||
'data-share-url': attrs.shareUrl,
|
||||
'data-post-number': attrs.post_number,
|
||||
}
|
||||
}, dateNode(createdAt))
|
||||
));
|
||||
const date = lastWikiEdit ? dateNode(lastWikiEdit) : dateNode(createdAt);
|
||||
const attributes = {
|
||||
class: "post-date",
|
||||
href: attrs.shareUrl,
|
||||
'data-share-url': attrs.shareUrl,
|
||||
'data-post-number': attrs.post_number
|
||||
};
|
||||
|
||||
if (lastWikiEdit) {
|
||||
attributes["class"] += " last-wiki-edit";
|
||||
}
|
||||
|
||||
result.push(h('div.post-info', h('a', { attributes }, date)));
|
||||
|
||||
if (attrs.via_email) {
|
||||
result.push(this.attach('post-email-indicator', attrs));
|
||||
}
|
||||
|
||||
@ -2,13 +2,11 @@ import { iconNode } from 'discourse-common/lib/icon-library';
|
||||
import { createWidget } from 'discourse/widgets/widget';
|
||||
import { h } from 'virtual-dom';
|
||||
import { avatarFor } from 'discourse/widgets/post';
|
||||
import hbs from 'discourse/widgets/hbs-compiler';
|
||||
|
||||
createWidget('pm-remove-group-link', {
|
||||
tagName: 'a.remove-invited',
|
||||
|
||||
html() {
|
||||
return iconNode('times');
|
||||
},
|
||||
template: hbs`{{fa-icon "times"}}`,
|
||||
|
||||
click() {
|
||||
bootbox.confirm(I18n.t("private_message_info.remove_allowed_group", {name: this.attrs.name}), (confirmed) => {
|
||||
@ -35,10 +33,7 @@ createWidget('pm-map-user-group', {
|
||||
|
||||
createWidget('pm-remove-link', {
|
||||
tagName: 'a.remove-invited',
|
||||
|
||||
html() {
|
||||
return iconNode('times');
|
||||
},
|
||||
template: hbs`{{fa-icon "times"}}`,
|
||||
|
||||
click() {
|
||||
bootbox.confirm(I18n.t("private_message_info.remove_allowed_user", {name: this.attrs.username}), (confirmed) => {
|
||||
|
||||
@ -5,16 +5,16 @@ import { createWidget } from 'discourse/widgets/widget';
|
||||
createWidget('search-term', {
|
||||
tagName: 'input',
|
||||
buildId: () => 'search-term',
|
||||
buildKey: (attrs) => `search-term-${attrs.id}`,
|
||||
buildKey: () => `search-term`,
|
||||
|
||||
defaultState() {
|
||||
this.appEvents.on("search-autocomplete:after-complete", () => {
|
||||
this.state.afterAutocomplete = true;
|
||||
});
|
||||
|
||||
return { afterAutocomplete: false };
|
||||
},
|
||||
|
||||
searchAutocompleteAfterComplete() {
|
||||
this.state.afterAutocomplete = true;
|
||||
},
|
||||
|
||||
buildAttributes(attrs) {
|
||||
return { type: 'text',
|
||||
value: attrs.value || '',
|
||||
|
||||
@ -130,15 +130,19 @@ createWidget('search-menu-results', {
|
||||
className: "filter filter-type"})));
|
||||
}
|
||||
|
||||
return [
|
||||
let resultNode = [
|
||||
h('ul', this.attach(rt.componentName, {
|
||||
searchContextEnabled: attrs.searchContextEnabled,
|
||||
searchLogId: attrs.results.grouped_search_result.search_log_id,
|
||||
results: rt.results,
|
||||
term: attrs.term
|
||||
})),
|
||||
h('div.no-results', more)
|
||||
];
|
||||
if (more.length) {
|
||||
resultNode.push(h('div.no-results', more));
|
||||
}
|
||||
|
||||
return resultNode;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -115,26 +115,29 @@ export default createWidget('search-menu', {
|
||||
panelContents() {
|
||||
const contextEnabled = searchData.contextEnabled;
|
||||
|
||||
const results = [
|
||||
let searchInput = [
|
||||
this.attach('search-term', { value: searchData.term, contextEnabled }),
|
||||
];
|
||||
if (searchData.term && searchData.loading) {
|
||||
searchInput.push(h('div.searching', h('div.spinner')));
|
||||
}
|
||||
|
||||
const results = [
|
||||
h('div.search-input', searchInput),
|
||||
this.attach('search-context', {
|
||||
contextEnabled,
|
||||
url: this.fullSearchUrl({ expanded: true })
|
||||
})
|
||||
];
|
||||
|
||||
if (searchData.term) {
|
||||
if (searchData.loading) {
|
||||
results.push(h('div.searching', h('div.spinner')));
|
||||
} else {
|
||||
results.push(this.attach('search-menu-results', {
|
||||
term: searchData.term,
|
||||
noResults: searchData.noResults,
|
||||
results: searchData.results,
|
||||
invalidTerm: searchData.invalidTerm,
|
||||
searchContextEnabled: searchData.contextEnabled,
|
||||
}));
|
||||
}
|
||||
if (searchData.term && !searchData.loading) {
|
||||
results.push(this.attach('search-menu-results', {
|
||||
term: searchData.term,
|
||||
noResults: searchData.noResults,
|
||||
results: searchData.results,
|
||||
invalidTerm: searchData.invalidTerm,
|
||||
searchContextEnabled: searchData.contextEnabled,
|
||||
}));
|
||||
}
|
||||
|
||||
return results;
|
||||
|
||||
@ -136,7 +136,8 @@ createWidget('topic-map-link', {
|
||||
target: "_blank",
|
||||
'data-user-id': attrs.user_id,
|
||||
'data-ignore-post-id': 'true',
|
||||
title: attrs.url };
|
||||
title: attrs.url,
|
||||
rel: 'nofollow noopener' };
|
||||
},
|
||||
|
||||
html(attrs) {
|
||||
|
||||
@ -1,101 +0,0 @@
|
||||
import { createWidget } from 'discourse/widgets/widget';
|
||||
import { topicLevels, buttonDetails } from 'discourse/lib/notification-levels';
|
||||
import { h } from 'virtual-dom';
|
||||
import RawHTML from 'discourse/widgets/raw-html';
|
||||
import { iconNode } from 'discourse-common/lib/icon-library';
|
||||
|
||||
createWidget('notification-option', {
|
||||
buildKey: attrs => `topic-notifications-button-${attrs.id}`,
|
||||
tagName: 'li',
|
||||
|
||||
html(attrs) {
|
||||
return h('a', [
|
||||
iconNode(attrs.icon, { class: `icon ${attrs.key}`, tagName: 'span' }),
|
||||
h('div', [
|
||||
h('span.title', I18n.t(`topic.notifications.${attrs.key}.title`)),
|
||||
h('span.desc', I18n.t(`topic.notifications.${attrs.key}.description`)),
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
click() {
|
||||
this.sendWidgetAction('notificationLevelChanged', this.attrs.id);
|
||||
}
|
||||
});
|
||||
|
||||
export default createWidget('topic-notifications-button', {
|
||||
tagName: 'span.btn-group.notification-options',
|
||||
buildKey: () => `topic-notifications-button`,
|
||||
|
||||
defaultState() {
|
||||
return { expanded: false };
|
||||
},
|
||||
|
||||
buildClasses(attrs, state) {
|
||||
if (state.expanded) { return "open"; }
|
||||
},
|
||||
|
||||
buildAttributes() {
|
||||
return { title: I18n.t('topic.notifications.title') };
|
||||
},
|
||||
|
||||
buttonFor(level) {
|
||||
const details = buttonDetails(level);
|
||||
|
||||
const button = {
|
||||
className: `toggle-notification-options`,
|
||||
label: null,
|
||||
icon: details.icon,
|
||||
action: 'toggleDropdown',
|
||||
iconClass: details.key
|
||||
};
|
||||
|
||||
if (this.attrs.showFullTitle) {
|
||||
button.label = `topic.notifications.${details.key}.title`;
|
||||
} else {
|
||||
button.className = 'btn toggle-notifications-options notifications-dropdown';
|
||||
}
|
||||
|
||||
return this.attach('button', button);
|
||||
},
|
||||
|
||||
html(attrs, state) {
|
||||
const details = attrs.topic.get('details');
|
||||
const result = [ this.buttonFor(details.get('notification_level')) ];
|
||||
|
||||
if (state.expanded) {
|
||||
result.push(h('ul.dropdown-menu', topicLevels.map(l => this.attach('notification-option', l))));
|
||||
}
|
||||
|
||||
if (attrs.appendReason) {
|
||||
result.push(new RawHTML({ html: `<p>${details.get('notificationReasonText')}</p>` }));
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
toggleDropdown() {
|
||||
this.state.expanded = !this.state.expanded;
|
||||
},
|
||||
|
||||
clickOutside() {
|
||||
if (this.state.expanded) {
|
||||
this.sendWidgetAction('toggleDropdown');
|
||||
}
|
||||
},
|
||||
|
||||
notificationLevelChanged(id) {
|
||||
this.state.expanded = false;
|
||||
return this.attrs.topic.get('details').updateNotifications(id);
|
||||
},
|
||||
|
||||
topicNotificationsButtonChanged(msg) {
|
||||
switch(msg.type) {
|
||||
case 'notification':
|
||||
if (this.attrs.topic.get('details.notification_level') !== msg.id) {
|
||||
this.notificationLevelChanged(msg.id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1,4 +1,5 @@
|
||||
import { createWidget } from 'discourse/widgets/widget';
|
||||
import ComponentConnector from 'discourse/widgets/component_connector';
|
||||
import { h } from 'virtual-dom';
|
||||
import { relativeAge } from 'discourse/lib/formatter';
|
||||
import { iconNode } from 'discourse-common/lib/icon-library';
|
||||
@ -313,7 +314,14 @@ createWidget('timeline-footer-controls', {
|
||||
}
|
||||
|
||||
if (currentUser) {
|
||||
controls.push(this.attach('topic-notifications-button', { topic }));
|
||||
controls.push(new ComponentConnector(this,
|
||||
'topic-notifications-button',
|
||||
{
|
||||
topic,
|
||||
appendReason: false,
|
||||
showFullTitle: false
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
return controls;
|
||||
|
||||
@ -112,6 +112,10 @@ export function createWidget(name, opts) {
|
||||
opts.html = opts.html || emptyContent;
|
||||
opts.draw = drawWidget;
|
||||
|
||||
if (opts.template) {
|
||||
opts.html = opts.template;
|
||||
}
|
||||
|
||||
Object.keys(opts).forEach(k => result.prototype[k] = opts[k]);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -176,9 +176,10 @@ function findInlineCloseTag(state, openTag, start, max) {
|
||||
closeTag = parseBBCodeTag(state.src, j, max);
|
||||
if (!closeTag || closeTag.tag !== openTag.tag || !closeTag.closing) {
|
||||
closeTag = null;
|
||||
} else {
|
||||
closeTag.start = j;
|
||||
break;
|
||||
}
|
||||
closeTag.start = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,6 +62,7 @@ export function buildOptions(state) {
|
||||
lookupImageUrls,
|
||||
censoredWords,
|
||||
allowedHrefSchemes: siteSettings.allowed_href_schemes ? siteSettings.allowed_href_schemes.split('|') : null,
|
||||
allowedIframes: siteSettings.allowed_iframes ? siteSettings.allowed_iframes.split('|') : [],
|
||||
markdownIt: true,
|
||||
previewing
|
||||
};
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import xss from 'pretty-text/xss';
|
||||
|
||||
const _validIframes = [];
|
||||
|
||||
function attr(name, value) {
|
||||
if (value) {
|
||||
return `${name}="${xss.escapeAttrValue(value)}"`;
|
||||
@ -69,7 +67,8 @@ export function sanitize(text, whiteLister) {
|
||||
text = text.replace(/<([^A-Za-z\/\!]|$)/g, "<$1");
|
||||
|
||||
const whiteList = whiteLister.getWhiteList(),
|
||||
allowedHrefSchemes = whiteLister.getAllowedHrefSchemes();
|
||||
allowedHrefSchemes = whiteLister.getAllowedHrefSchemes(),
|
||||
allowedIframes = whiteLister.getAllowedIframes();
|
||||
let extraHrefMatchers = null;
|
||||
|
||||
if (allowedHrefSchemes && allowedHrefSchemes.length > 0) {
|
||||
@ -85,11 +84,13 @@ export function sanitize(text, whiteLister) {
|
||||
const forTag = whiteList.attrList[tag];
|
||||
if (forTag) {
|
||||
const forAttr = forTag[name];
|
||||
if ((forAttr && (forAttr.indexOf('*') !== -1 || forAttr.indexOf(value) !== -1)) ||
|
||||
if (
|
||||
(forAttr && (forAttr.indexOf('*') !== -1 || forAttr.indexOf(value) !== -1)) ||
|
||||
(name.indexOf('data-') === 0 && forTag['data-*']) ||
|
||||
((tag === 'a' && name === 'href') && hrefAllowed(value, extraHrefMatchers)) ||
|
||||
(tag === 'img' && name === 'src' && (/^data:image.*$/i.test(value) || hrefAllowed(value, extraHrefMatchers))) ||
|
||||
(tag === 'iframe' && name === 'src' && _validIframes.some(i => i.test(value)))) {
|
||||
(tag === 'iframe' && name === 'src' && allowedIframes.some(i => { return value.toLowerCase().indexOf((i || '').toLowerCase()) === 0;}))
|
||||
) {
|
||||
return attr(name, value);
|
||||
}
|
||||
|
||||
@ -114,10 +115,3 @@ export function sanitize(text, whiteLister) {
|
||||
.replace(/'/g, "'")
|
||||
.replace(/ \/>/g, '>');
|
||||
};
|
||||
|
||||
export function whiteListIframe(regexp) {
|
||||
_validIframes.push(regexp);
|
||||
}
|
||||
|
||||
whiteListIframe(/^(https?:)?\/\/www\.google\.com\/maps\/embed\?.+/i);
|
||||
whiteListIframe(/^(https?:)?\/\/www\.openstreetmap\.org\/export\/embed.html\?.+/i);
|
||||
|
||||
@ -9,6 +9,7 @@ export default class WhiteLister {
|
||||
|
||||
this._enabled = { "default": true };
|
||||
this._allowedHrefSchemes = (options && options.allowedHrefSchemes) || [];
|
||||
this._allowedIframes = (options && options.allowedIframes) || [];
|
||||
this._rawFeatures = [["default", DEFAULT_LIST]];
|
||||
|
||||
this._cache = null;
|
||||
@ -102,6 +103,10 @@ export default class WhiteLister {
|
||||
getAllowedHrefSchemes() {
|
||||
return this._allowedHrefSchemes;
|
||||
}
|
||||
|
||||
getAllowedIframes() {
|
||||
return this._allowedIframes;
|
||||
}
|
||||
}
|
||||
|
||||
// Only add to `default` when you always want your whitelist to occur. In other words,
|
||||
|
||||
@ -14,10 +14,24 @@
|
||||
font: 1.071em/0.9 "FontAwesome";
|
||||
}
|
||||
}
|
||||
|
||||
.select-box {
|
||||
align-self: center;
|
||||
|
||||
&.categories-admin-dropdown, &.category-notifications-button, &.tag-notifications-button {
|
||||
float: right;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html.anon .topic-list a.title:visited:not(.badge-notification) {color: $primary-medium; }
|
||||
.topic-list a.title.visited:not(.badge-notification) {color: $primary-medium; }
|
||||
html.anon .topic-list,
|
||||
.topic-list-item.visited,
|
||||
.latest-topic-list-item.visited,
|
||||
.category-topic-link.visited,
|
||||
#suggested-topics .topic-list tr.visited {
|
||||
a.title:not(.badge-notification) { color: $primary-medium; }
|
||||
}
|
||||
|
||||
.topic-list-main-link {
|
||||
font-size: 1.143em;
|
||||
@ -47,7 +61,7 @@ html.anon .topic-list a.title:visited:not(.badge-notification) {color: $primary-
|
||||
vertical-align: top;
|
||||
margin-top: 2px;
|
||||
}
|
||||
border-bottom: 1px solid $primary-low;
|
||||
border-bottom: 1px solid $primary-low;
|
||||
|
||||
&.last-visit {
|
||||
border-bottom: none;
|
||||
@ -253,7 +267,7 @@ ol.category-breadcrumb {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
position: absolute;
|
||||
border: 1px solid $primary-low;
|
||||
border: 1px solid $primary-low;
|
||||
background-color: $secondary;
|
||||
z-index: 100;
|
||||
|
||||
@ -315,7 +329,7 @@ ol.category-breadcrumb {
|
||||
@include unselectable;
|
||||
|
||||
font-size: 1.2em;
|
||||
border: 1px solid $primary-low;
|
||||
border: 1px solid $primary-low;
|
||||
padding: 5px;
|
||||
background: $secondary;
|
||||
position: absolute;
|
||||
@ -369,4 +383,3 @@ div.education {
|
||||
@extend .list-cell;
|
||||
border-bottom: 2px solid $primary-low;
|
||||
}
|
||||
|
||||
|
||||
@ -1,45 +1,39 @@
|
||||
img.avatar {
|
||||
border-radius: 50%;
|
||||
}
|
||||
// Common
|
||||
// global styles that apply to the Discourse application specifically
|
||||
// BEWARE: changing these styles implies they take effect anywhere they are seen
|
||||
// throughout the Discourse application
|
||||
|
||||
.container {
|
||||
@extend .clearfix;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
@extend .clearfix;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
padding: 0 8px;
|
||||
.contents {
|
||||
position: relative;
|
||||
// Animation Keyframes
|
||||
@keyframes ping {
|
||||
from {
|
||||
transform: scale(0.25);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: scale(2);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.full-width {
|
||||
margin-left: 12px;
|
||||
@keyframes rotate-forever {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
big {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
//setting a static limit on big and small prevents nesting abuse
|
||||
|
||||
|
||||
blockquote {
|
||||
@include post-aside;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
a.no-href {
|
||||
cursor: pointer;
|
||||
@keyframes background-fade-highlight {
|
||||
0% {
|
||||
background-color: $tertiary-low;
|
||||
}
|
||||
100% {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
// Base Elements
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
@ -52,56 +46,170 @@ body {
|
||||
@include clearfix;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
big {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
//setting a static limit on big and small prevents nesting abuse
|
||||
blockquote {
|
||||
@include post-aside;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
button.ok {
|
||||
background: $success;
|
||||
color: $secondary;
|
||||
@include hover {
|
||||
background: lighten($success, 10%);
|
||||
button {
|
||||
&.ok {
|
||||
background: $success;
|
||||
color: $secondary;
|
||||
|
||||
@include hover {
|
||||
background: lighten($success, 10%);
|
||||
color: $secondary;
|
||||
}
|
||||
}
|
||||
|
||||
&.cancel {
|
||||
background: $danger;
|
||||
color: $secondary;
|
||||
|
||||
@include hover {
|
||||
background: lighten($danger, 10%);
|
||||
color: $secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button.cancel {
|
||||
background: $danger;
|
||||
color: $secondary;
|
||||
@include hover {
|
||||
background: lighten($danger, 10%);
|
||||
color: $secondary;
|
||||
ul.breadcrumb {
|
||||
margin: 0 10px 0 10px;
|
||||
}
|
||||
|
||||
a.no-href {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img.avatar {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
// don't wrap relative dates; we want Jul 26, '15, not: Jul
|
||||
// 26,
|
||||
// '15
|
||||
span.relative-date {
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
input {
|
||||
&[type="radio"],
|
||||
&[type="checkbox"] {
|
||||
margin: 3px 0;
|
||||
line-height: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
&[type="submit"],
|
||||
&[type="reset"],
|
||||
&[type="button"],
|
||||
&[type="radio"],
|
||||
&[type="checkbox"] {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
&.invalid {
|
||||
background-color: dark-light-choose(scale-color($danger, $lightness: 80%), scale-color($danger, $lightness: -60%));
|
||||
}
|
||||
|
||||
.radio &[type="radio"],
|
||||
.checkbox &[type="checkbox"] {
|
||||
float: left;
|
||||
margin-left: -18px;
|
||||
}
|
||||
}
|
||||
|
||||
// Common Classes
|
||||
.radio,
|
||||
.checkbox {
|
||||
min-height: 18px;
|
||||
padding-left: 18px;
|
||||
|
||||
.controls > &:first-child {
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
&.inline {
|
||||
display: inline-block;
|
||||
padding-top: 5px;
|
||||
margin-bottom: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.radio.inline .radio.inline,
|
||||
.checkbox.inline .checkbox.inline {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.container {
|
||||
@extend .clearfix;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
@extend .clearfix;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
padding: 0 8px;
|
||||
|
||||
.contents {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.boxed {
|
||||
&.white {
|
||||
background-color: $secondary;
|
||||
}
|
||||
}
|
||||
|
||||
.full-width {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
// the default for table cells in topic list
|
||||
// is scale-color($primary, $lightness: 50%)
|
||||
// numbers get dimmer as they get colder
|
||||
.coldmap-high {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 70%), scale-color($secondary, $lightness: 30%)) !important;
|
||||
}
|
||||
.coldmap-med {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 60%), scale-color($secondary, $lightness: 40%)) !important;
|
||||
}
|
||||
.coldmap-low {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)) !important;
|
||||
.coldmap {
|
||||
&-high {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 70%), scale-color($secondary, $lightness: 30%)) !important;
|
||||
}
|
||||
|
||||
&-med {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 60%), scale-color($secondary, $lightness: 40%)) !important;
|
||||
}
|
||||
|
||||
&-low {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
#loading-message {
|
||||
position: absolute;
|
||||
font-size: 2.143em;
|
||||
text-align: center;
|
||||
top: 120px;
|
||||
left: 500px;
|
||||
color: $primary;
|
||||
}
|
||||
.top-space {
|
||||
.top-space {
|
||||
margin-top: 10px;
|
||||
}
|
||||
ul.breadcrumb {
|
||||
margin: 0 10px 0 10px;
|
||||
}
|
||||
|
||||
.message {
|
||||
@include border-radius-all(8px);
|
||||
@ -113,18 +221,6 @@ ul.breadcrumb {
|
||||
}
|
||||
}
|
||||
|
||||
#footer {
|
||||
.container {
|
||||
height: 50px;
|
||||
.contents {
|
||||
padding-top: 10px;
|
||||
a[href] {
|
||||
color: $secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.clear-transitions {
|
||||
transition:none !important;
|
||||
}
|
||||
@ -139,10 +235,6 @@ ul.breadcrumb {
|
||||
}
|
||||
}
|
||||
|
||||
input[type].invalid {
|
||||
background-color: dark-light-choose(scale-color($danger, $lightness: 80%), scale-color($danger, $lightness: -60%));
|
||||
}
|
||||
|
||||
.d-editor-input {
|
||||
resize: none;
|
||||
}
|
||||
@ -157,43 +249,6 @@ input[type].invalid {
|
||||
top: 60px !important;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
input {
|
||||
&[type="radio"], &[type="checkbox"] {
|
||||
margin: 3px 0;
|
||||
line-height: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
&[type="submit"], &[type="reset"], &[type="button"], &[type="radio"], &[type="checkbox"] {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
.radio, .checkbox {
|
||||
min-height: 18px;
|
||||
padding-left: 18px;
|
||||
}
|
||||
.radio input[type="radio"], .checkbox input[type="checkbox"] {
|
||||
float: left;
|
||||
margin-left: -18px;
|
||||
}
|
||||
.controls > {
|
||||
.radio:first-child, .checkbox:first-child {
|
||||
padding-top: 5px;
|
||||
}
|
||||
}
|
||||
.radio.inline, .checkbox.inline {
|
||||
display: inline-block;
|
||||
padding-top: 5px;
|
||||
margin-bottom: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.radio.inline .radio.inline, .checkbox.inline .checkbox.inline {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.flex-center-align {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -202,7 +257,10 @@ input {
|
||||
.unread-private-messages {
|
||||
color: $secondary;
|
||||
background: $success;
|
||||
&.badge-notification[href] {color: $secondary;}
|
||||
|
||||
&.badge-notification[href] {
|
||||
color: $secondary;
|
||||
}
|
||||
}
|
||||
|
||||
.ring-backdrop-spotlight {
|
||||
@ -256,50 +314,12 @@ input {
|
||||
-webkit-animation-name: ping;
|
||||
}
|
||||
|
||||
@-webkit-keyframes ping {
|
||||
from {
|
||||
$scale: 0.25;
|
||||
transform: scale($scale);
|
||||
-ms-transform: scale($scale);
|
||||
-webkit-transform: scale($scale);
|
||||
-o-transform: scale($scale);
|
||||
-moz-transform: scale($scale);
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
$scale: 2;
|
||||
transform: scale($scale);
|
||||
-ms-transform: scale($scale);
|
||||
-webkit-transform: scale($scale);
|
||||
-o-transform: scale($scale);
|
||||
-moz-transform: scale($scale);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.fade {
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s linear;
|
||||
}
|
||||
|
||||
.fade.in {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@-webkit-keyframes rotate-forever {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes rotate-forever {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
&.in {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,7 +348,6 @@ input {
|
||||
}
|
||||
|
||||
.content-list {
|
||||
|
||||
h3 {
|
||||
color: $primary-medium;
|
||||
font-size: 1.071em;
|
||||
@ -340,50 +359,106 @@ input {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
|
||||
li:first-of-type {
|
||||
border-top: 1px solid $primary-low;
|
||||
}
|
||||
li {
|
||||
border-bottom: 1px solid $primary-low;
|
||||
}
|
||||
|
||||
li a {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
color: $primary;
|
||||
|
||||
&:hover {
|
||||
background-color: $primary-low;
|
||||
color: $primary;
|
||||
&:first-of-type {
|
||||
border-top: 1px solid $primary-low;
|
||||
}
|
||||
|
||||
&.active {
|
||||
font-weight: bold;
|
||||
a {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
color: $primary;
|
||||
|
||||
&:hover {
|
||||
background-color: $primary-low;
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
&.active {
|
||||
font-weight: bold;
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// don't wrap relative dates, we want
|
||||
//
|
||||
// Jul 26, '15
|
||||
//
|
||||
// not
|
||||
//
|
||||
// Jul
|
||||
// 26,
|
||||
// '15
|
||||
//
|
||||
span.relative-date {
|
||||
white-space:nowrap;
|
||||
.form-vertical {
|
||||
input,
|
||||
textarea,
|
||||
select,
|
||||
.input-prepend,
|
||||
.input-append {
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.control-group {
|
||||
@include clearfix;
|
||||
}
|
||||
|
||||
.control-label {
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.controls {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes background-fade-highlight {
|
||||
0% {
|
||||
background-color: $tertiary-low;
|
||||
// Special elements
|
||||
// Special elements
|
||||
#main {
|
||||
img.avatar {
|
||||
&.header {
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
&.medium {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
&.small {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
|
||||
&.tiny {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
100% {
|
||||
background-color: transparent;
|
||||
|
||||
.user-list {
|
||||
.user {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#loading-message {
|
||||
position: absolute;
|
||||
font-size: 2.143em;
|
||||
text-align: center;
|
||||
top: 120px;
|
||||
left: 500px;
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
#footer {
|
||||
.container {
|
||||
height: 50px;
|
||||
.contents {
|
||||
padding-top: 10px;
|
||||
a[href] {
|
||||
color: $secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,151 +1,163 @@
|
||||
.d-header {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
z-index: 1001;
|
||||
background-color: $header_background;
|
||||
box-shadow: 0 2px 4px -1px rgba(0,0,0, .25);
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
z-index: 1001;
|
||||
background-color: $header_background;
|
||||
box-shadow: 0 2px 4px -1px rgba(0,0,0, .25);
|
||||
|
||||
.docked & {
|
||||
position: fixed;
|
||||
backface-visibility: hidden; /** do magic for scrolling performance **/
|
||||
.docked & {
|
||||
position: fixed;
|
||||
backface-visibility: hidden; /** do magic for scrolling performance **/
|
||||
}
|
||||
|
||||
.contents {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.title {
|
||||
float: left;
|
||||
a, a:visited {
|
||||
color: $header_primary;
|
||||
}
|
||||
}
|
||||
|
||||
.contents {
|
||||
margin: 8px 0;
|
||||
}
|
||||
#site-logo {
|
||||
max-height: 40px;
|
||||
}
|
||||
|
||||
.title {
|
||||
float: left;
|
||||
a, a:visited {
|
||||
color: $header_primary;
|
||||
}
|
||||
}
|
||||
.d-icon-home {
|
||||
font-size: 1.643em;
|
||||
}
|
||||
|
||||
#site-logo {
|
||||
max-height: 40px;
|
||||
}
|
||||
.panel {
|
||||
float: right;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.d-icon-home {
|
||||
font-size: 1.643em;
|
||||
}
|
||||
.login-button, button.sign-up-button {
|
||||
float: left;
|
||||
margin-top: 7px;
|
||||
padding: 6px 10px;
|
||||
.fa { margin-right: 3px; }
|
||||
}
|
||||
|
||||
.panel {
|
||||
float: right;
|
||||
position: relative;
|
||||
}
|
||||
button.login-button {
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
.login-button, button.sign-up-button {
|
||||
float: left;
|
||||
margin-top: 7px;
|
||||
padding: 6px 10px;
|
||||
.fa { margin-right: 3px; }
|
||||
}
|
||||
|
||||
button.login-button {
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
.icons {
|
||||
float: right;
|
||||
text-align: center;
|
||||
margin: 0 0 0 5px;
|
||||
list-style: none;
|
||||
|
||||
> li {
|
||||
float: left;
|
||||
}
|
||||
.icon {
|
||||
display: block;
|
||||
padding: 3px;
|
||||
color: dark-light-choose(scale-color($header_primary, $lightness: 50%), $header_primary);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
border-top: 1px solid transparent;
|
||||
border-left: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
transition: all linear .15s;
|
||||
|
||||
|
||||
&:hover {
|
||||
color: $primary;
|
||||
background-color: $primary-low;
|
||||
border-top: 1px solid transparent;
|
||||
border-left: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
}
|
||||
&:active {
|
||||
color: $primary;
|
||||
background-color: $primary-low;
|
||||
}
|
||||
}
|
||||
.drop-down-visible & {
|
||||
.active .icon {
|
||||
position: relative;
|
||||
color: #7b7b7b;
|
||||
background-color: $secondary;
|
||||
cursor: default;
|
||||
border-top: 1px solid $primary-low;
|
||||
border-left: 1px solid $primary-low;
|
||||
border-right: 1px solid $primary-low;
|
||||
|
||||
.badge-notification {
|
||||
top: -10px;
|
||||
}
|
||||
|
||||
.flagged-posts {
|
||||
right: 24px;
|
||||
}
|
||||
|
||||
&:after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
z-index: 1101;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
content: "";
|
||||
border-top: 1px solid $secondary;
|
||||
}
|
||||
&:hover {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.d-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 1.714em;
|
||||
line-height: 32px;
|
||||
display: inline-block;
|
||||
}
|
||||
.notifications {
|
||||
position: relative;
|
||||
}
|
||||
.badge-notification, .ring {
|
||||
position: absolute;
|
||||
top: -9px;
|
||||
z-index: 1;
|
||||
margin-left: 0;
|
||||
}
|
||||
.unread-notifications {
|
||||
right: 0;
|
||||
background-color: scale-color($tertiary, $lightness: 50%);
|
||||
}
|
||||
.unread-private-messages, .ring {
|
||||
right: 25px;
|
||||
}
|
||||
.flagged-posts {
|
||||
right: 65px;
|
||||
}
|
||||
}
|
||||
.flagged-posts, .queued-posts {
|
||||
background: $danger;
|
||||
}
|
||||
.d-header-icons {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.header-dropdown-toggle, .drop-down {
|
||||
.flagged-posts, .queued-posts {
|
||||
background: $danger;
|
||||
}
|
||||
}
|
||||
|
||||
.d-header-icons {
|
||||
text-align: center;
|
||||
margin: 0 0 0 5px;
|
||||
list-style: none;
|
||||
|
||||
|
||||
> li {
|
||||
float: left;
|
||||
}
|
||||
.icon {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 3px;
|
||||
color: dark-light-choose(scale-color($header_primary, $lightness: 50%), $header_primary);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
border-top: 1px solid transparent;
|
||||
border-left: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
transition: all linear .15s;
|
||||
|
||||
|
||||
&:hover {
|
||||
color: $primary;
|
||||
background-color: $primary-low;
|
||||
border-top: 1px solid transparent;
|
||||
border-left: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
}
|
||||
&:active {
|
||||
color: $primary;
|
||||
background-color: $primary-low;
|
||||
}
|
||||
}
|
||||
.drop-down-visible & {
|
||||
.active .icon {
|
||||
position: relative;
|
||||
color: #7b7b7b;
|
||||
background-color: $secondary;
|
||||
cursor: default;
|
||||
border-top: 1px solid $primary-low;
|
||||
border-left: 1px solid $primary-low;
|
||||
border-right: 1px solid $primary-low;
|
||||
|
||||
.flagged-posts {
|
||||
right: 24px;
|
||||
}
|
||||
|
||||
&:after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
z-index: 1101;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
content: "";
|
||||
border-top: 1px solid $secondary;
|
||||
}
|
||||
&:hover {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.d-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
font-size: 1.714em;
|
||||
line-height: 32px;
|
||||
display: inline-block;
|
||||
}
|
||||
.notifications {
|
||||
position: relative;
|
||||
}
|
||||
.ring {
|
||||
position: absolute;
|
||||
top: -9px;
|
||||
z-index: 1;
|
||||
margin-left: 0;
|
||||
}
|
||||
.header-dropdown-toggle {
|
||||
position: relative;
|
||||
}
|
||||
.badge-notification {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
top: -9px;
|
||||
min-width: 6px;
|
||||
}
|
||||
.unread-notifications {
|
||||
left: auto;
|
||||
right: 0;
|
||||
background-color: scale-color($tertiary, $lightness: 50%);
|
||||
}
|
||||
.unread-private-messages, .ring {
|
||||
left: auto;
|
||||
right: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.highlight-strong {
|
||||
background-color: $highlight-medium;
|
||||
|
||||
@ -129,13 +129,9 @@
|
||||
|
||||
.searching {
|
||||
position: absolute;
|
||||
top: 0.25em;
|
||||
right: 1.5em;
|
||||
|
||||
top: -3px;
|
||||
right: 0.75em;
|
||||
.drop-down-visible & {
|
||||
top: 0.2em;
|
||||
right: 1.2em;
|
||||
}
|
||||
.spinner {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
.fa.muted, .fa.watching-first-post {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%));
|
||||
}
|
||||
.fa.tracking, .fa.watching {
|
||||
color: $tertiary;
|
||||
font-weight: normal;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
.notifications-button.notifications-button.notifications-button {
|
||||
.d-icon.regular, .d-icon.muted, .d-icon.watching-first-post {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%));
|
||||
}
|
||||
.d-icon.tracking, .d-icon.watching {
|
||||
color: $tertiary;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
@ -49,6 +49,36 @@
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.topic-category {
|
||||
margin-top: 5px;
|
||||
|
||||
.topic-header-extra {
|
||||
display: inline;
|
||||
vertical-align: baseline;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.badge-wrapper {
|
||||
display: inline-block;
|
||||
vertical-align: baseline;
|
||||
margin-top: 0;
|
||||
|
||||
&.bullet .badge-category {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&.box, &.bullet {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&.box + .topic-header-extra,
|
||||
&.bullet + .topic-header-extra,
|
||||
&.bar + .topic-header-extra {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-tags .select2 {
|
||||
margin: 0;
|
||||
}
|
||||
@ -187,18 +217,6 @@ header .discourse-tag {color: $tag-color }
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.notification-options.tag-notification-menu {
|
||||
float: right;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.tag-notification-menu .dropdown-menu {
|
||||
right: 0;
|
||||
top: 30px;
|
||||
bottom: auto;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
.tag-sort-options {
|
||||
margin-bottom: 20px;
|
||||
a {
|
||||
|
||||
@ -247,7 +247,8 @@ aside.quote {
|
||||
}
|
||||
}
|
||||
|
||||
.wiki {
|
||||
.wiki,
|
||||
.last-wiki-edit {
|
||||
color: green !important;
|
||||
}
|
||||
|
||||
@ -420,3 +421,10 @@ a.mention, a.mention-group {
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.broken-image, .large-image {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 70%), scale-color($secondary, $lightness: 30%));
|
||||
border: 1px solid $primary-low;
|
||||
font-size: 32px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
@ -123,7 +123,7 @@
|
||||
}
|
||||
|
||||
.topic-unsubscribe {
|
||||
.notification-options {
|
||||
.notifications-button {
|
||||
display: inline-block;
|
||||
float: none;
|
||||
line-height: 2em;
|
||||
|
||||
@ -58,19 +58,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.user-info.medium.badge-info {
|
||||
min-height: 80px;
|
||||
|
||||
.granted-on {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
||||
}
|
||||
|
||||
.post-link {
|
||||
display: block;
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.show-badge .badge-user-info {
|
||||
.earned {
|
||||
font-size: 1.3em;
|
||||
|
||||
@ -1,8 +1,266 @@
|
||||
// Common styles for "/user" section
|
||||
.user-right {
|
||||
.list-actions {
|
||||
margin-bottom: 10px;
|
||||
|
||||
.btn {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-main {
|
||||
.d-icon-heart {
|
||||
color: $love !important;
|
||||
}
|
||||
|
||||
.about {
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
|
||||
.secondary {
|
||||
font-size: 0.929em;
|
||||
|
||||
.btn {
|
||||
padding: 3px 12px;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
dd {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: $primary;
|
||||
|
||||
&.groups {
|
||||
span:after {
|
||||
content: ','
|
||||
}
|
||||
span:last-of-type:after {
|
||||
content:''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dt {
|
||||
color: $secondary-medium;
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
background: rgba($secondary, .85);
|
||||
|
||||
blockquote {
|
||||
background-color: $secondary-low;
|
||||
border-left-color: $secondary-low;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.143em;
|
||||
font-weight: normal;
|
||||
i {font-size: .8em;}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.214em;
|
||||
font-weight: normal;
|
||||
margin-top: 10px;
|
||||
max-width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: normal;
|
||||
font-size: 1em;
|
||||
margin: 5px 0;
|
||||
|
||||
.d-icon:not(:first-of-type) {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.groups {
|
||||
margin-left: 10px;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
img.avatar {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.suspended {
|
||||
color: $danger;
|
||||
}
|
||||
|
||||
.primary {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
float: left;
|
||||
|
||||
h1 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.bio {
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
|
||||
a[href] {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.controls {
|
||||
ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
a {
|
||||
padding: 5px 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&.collapsed-info {
|
||||
.controls {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.profile-image {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.details {
|
||||
margin-top: 0;
|
||||
background: rgba($secondary, .85);
|
||||
|
||||
.bio {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.primary {
|
||||
text-align: left;
|
||||
margin-top: 0;
|
||||
width: 100%;
|
||||
|
||||
.avatar {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
width: 45px;
|
||||
height: 45px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.429em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.071em;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.staff-counters {
|
||||
text-align: left;
|
||||
background: $primary;
|
||||
|
||||
> div {
|
||||
margin: 0 10px 0 0;
|
||||
display: inline-block;
|
||||
padding: 5px 0;
|
||||
&:first-of-type {
|
||||
padding-left: 10px;
|
||||
}
|
||||
span {
|
||||
padding: 1px 5px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: $secondary;
|
||||
}
|
||||
|
||||
.active {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.pill {
|
||||
border-radius: 15px;
|
||||
display: inline-block;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
.helpful-flags {
|
||||
background-color: green;
|
||||
}
|
||||
|
||||
.flagged-posts {
|
||||
background-color: #E49735;
|
||||
}
|
||||
|
||||
.warnings-received {
|
||||
background-color: #EC441B;
|
||||
}
|
||||
|
||||
.deleted-posts {
|
||||
background-color: #EC441B;
|
||||
}
|
||||
|
||||
.suspensions {
|
||||
background-color: #c22020;
|
||||
}
|
||||
|
||||
.user-field {
|
||||
clear: both;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&.text {
|
||||
padding-top: 18px;
|
||||
}
|
||||
|
||||
.controls {
|
||||
label {
|
||||
width: auto;
|
||||
text-align: left;
|
||||
font-weight: normal;
|
||||
float: auto;
|
||||
}
|
||||
|
||||
.instructions {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 80%;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-field {
|
||||
@ -17,24 +275,26 @@
|
||||
.public-user-fields {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.user-field-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.collapsed-info .public-user-fields {
|
||||
display: none;
|
||||
.collapsed-info & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.user-navigation {
|
||||
|
||||
.map {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
float: left;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
nav.buttons {
|
||||
width: 180px;
|
||||
padding: 0;
|
||||
@ -44,6 +304,7 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
a {
|
||||
font-size: 1em;
|
||||
@ -51,7 +312,6 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.user-table {
|
||||
@ -78,69 +338,6 @@
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: inline-block;
|
||||
clear: both;
|
||||
margin-bottom: 1em;
|
||||
|
||||
.user-image {
|
||||
float: left;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.user-detail {
|
||||
float: left;
|
||||
width: 70%;
|
||||
padding-left: 5px;
|
||||
font-size: 13px;
|
||||
|
||||
.name-line {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.username a {
|
||||
font-weight: bold;
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 30%), scale-color($secondary, $lightness: 70%));
|
||||
}
|
||||
|
||||
.name {
|
||||
margin-left: 5px;
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 30%), scale-color($secondary, $lightness: 70%));
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-top: 3px;
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-info.small {
|
||||
width: 333px;
|
||||
}
|
||||
|
||||
.user-info.medium {
|
||||
width: 480px;
|
||||
min-height: 60px;
|
||||
|
||||
.user-image {
|
||||
width: 55px;
|
||||
}
|
||||
.user-detail {
|
||||
width: 380px;
|
||||
}
|
||||
|
||||
.username, .name {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.name {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.user-nav {
|
||||
margin: 5px 0px;
|
||||
padding-top: 10px;
|
||||
@ -150,15 +347,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.user-right {
|
||||
.list-actions {
|
||||
margin-bottom: 10px;
|
||||
.btn {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.top-section {
|
||||
@include clearfix();
|
||||
ul {
|
||||
@ -229,6 +417,11 @@
|
||||
.topic-info {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 40%));
|
||||
}
|
||||
|
||||
@media all and (max-width : 600px) {
|
||||
float: none;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.replies-section,
|
||||
@ -252,19 +445,62 @@
|
||||
}
|
||||
}
|
||||
|
||||
@media all
|
||||
and (max-width : 600px) {
|
||||
.top-sub-section {
|
||||
float: none;
|
||||
width: 100%;
|
||||
.groups {
|
||||
.group-link {
|
||||
color: $tertiary;
|
||||
}
|
||||
}
|
||||
|
||||
.user-preferences .tags .select2-container-multi {
|
||||
border: 1px solid $primary-low;
|
||||
width: 540px;
|
||||
border-radius: 0;
|
||||
.select2-choices {
|
||||
border: none;
|
||||
.user-preferences {
|
||||
textarea {
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.static {
|
||||
color: $primary;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.instructions {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
||||
margin-bottom: 10px;
|
||||
font-size: 80%;
|
||||
line-height: 1.4em;
|
||||
|
||||
a[href] {
|
||||
color: $tertiary;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: scale-color($danger, $lightness: 30%);
|
||||
padding: 5px 8px;
|
||||
color: $secondary;
|
||||
width: 520px;
|
||||
}
|
||||
|
||||
.category-notifications .category-controls,
|
||||
.tag-notifications .tag-controls {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.tags .select2-container-multi {
|
||||
border: 1px solid $primary-low;
|
||||
width: 540px;
|
||||
border-radius: 0;
|
||||
.select2-choices {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.paginated-topics-list {
|
||||
.user-content {
|
||||
width: 100%;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,18 +153,19 @@
|
||||
|
||||
|
||||
.list-controls {
|
||||
.category-breadcrumb {
|
||||
a.badge-category, .dropdown-header {
|
||||
.category-breadcrumb {
|
||||
a.badge-category, .dropdown-header {
|
||||
display: inline-block;
|
||||
padding: 5px 8px;
|
||||
line-height: 20px;
|
||||
&.category-dropdown-button {
|
||||
margin-left: -4px;
|
||||
padding: 5px;
|
||||
width: 13px;
|
||||
|
||||
.d-icon-caret-right {
|
||||
margin-left: 2px;
|
||||
&.category-dropdown-button {
|
||||
margin-left: -4px;
|
||||
padding: 5px;
|
||||
width: 13px;
|
||||
|
||||
.d-icon-caret-right {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,8 +191,6 @@
|
||||
margin: 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.category-dropdown-menu {
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
.categories-admin-dropdown.categories-admin-dropdown.categories-admin-dropdown {
|
||||
.select-box-body {
|
||||
min-width: auto;
|
||||
width: 250px;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
.select-box.category-select-box {
|
||||
.category-select-box.category-select-box {
|
||||
.select-box-row {
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
@ -23,6 +23,7 @@
|
||||
}
|
||||
|
||||
.category-status {
|
||||
color: $primary;
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 1 1 auto;
|
||||
flex: 1 1 auto;
|
||||
@ -32,7 +33,7 @@
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 1 1 auto;
|
||||
flex: 1 1 auto;
|
||||
color: $primary;
|
||||
color: #919191;
|
||||
font-size: 0.857em;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
@ -0,0 +1,103 @@
|
||||
.dropdown-select-box.dropdown-select-box {
|
||||
display: inline-flex;
|
||||
height: 30px;
|
||||
min-width: auto;
|
||||
|
||||
&.is-expanded {
|
||||
.collection,
|
||||
.select-box-collection,
|
||||
.select-box-body {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box-body {
|
||||
border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
|
||||
background-clip: padding-box;
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
max-width: 300px;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.select-box-row {
|
||||
margin: 0;
|
||||
padding: 10px 5px;
|
||||
|
||||
.icons {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
align-self: flex-start;
|
||||
margin-right: 10px;
|
||||
margin-top: 2px;
|
||||
width: 30px;
|
||||
|
||||
.d-icon {
|
||||
font-size: 1.286em;
|
||||
align-self: center;
|
||||
margin-right: 0;
|
||||
opacity: 1;
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 60%));
|
||||
}
|
||||
}
|
||||
|
||||
.texts {
|
||||
line-height: 18px;
|
||||
flex: 1;
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: column;
|
||||
|
||||
.title {
|
||||
flex: 1;
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
font-size: 1em;
|
||||
color: $primary;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.desc {
|
||||
flex: 1;
|
||||
font-size: 0.857em;
|
||||
font-weight: normal;
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 40%));;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-highlighted {
|
||||
background: $tertiary-low;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $highlight-medium;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box-collection {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.dropdown-header {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
justify-content: flex-start;
|
||||
background: none;
|
||||
|
||||
.d-icon + .d-icon {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
flex-direction: row;
|
||||
display: inline-flex;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
.notifications-button.notifications-button.notifications-button {
|
||||
.select-box-body {
|
||||
min-width: 550px;
|
||||
max-width: 550px;
|
||||
}
|
||||
|
||||
.select-box-row {
|
||||
.icons {
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
app/assets/stylesheets/common/components/pinned-button.scss
Normal file
39
app/assets/stylesheets/common/components/pinned-button.scss
Normal file
@ -0,0 +1,39 @@
|
||||
#topic-footer-buttons {
|
||||
.pinned-button {
|
||||
min-width: auto;
|
||||
margin: 10px 0 5px 0;
|
||||
|
||||
&.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.reason {
|
||||
line-height: 16px;
|
||||
margin: 0 0 0 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pinned-button {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
min-width: auto;
|
||||
|
||||
.pinned-options {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.pinned-options.pinned-options.pinned-options {
|
||||
.select-box-body {
|
||||
min-width: unset;
|
||||
max-width: unset;
|
||||
width: 550px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,13 +9,18 @@
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
height: 34px;
|
||||
min-width: 220px;
|
||||
|
||||
&.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.small {
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
&.is-expanded {
|
||||
z-index: 9999;
|
||||
z-index: 999;
|
||||
|
||||
.select-box-wrapper {
|
||||
border: 1px solid $tertiary;
|
||||
@ -39,14 +44,14 @@
|
||||
}
|
||||
|
||||
.collection, {
|
||||
border-radius: 0 0 3px 3px;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
.select-box-header {
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
&.is-reversed {
|
||||
&.is-above {
|
||||
.select-box-header {
|
||||
border-radius: 0 0 3px 3px;
|
||||
}
|
||||
@ -61,7 +66,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.is-reversed {
|
||||
&.is-above {
|
||||
.select-box-body {
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
@ -90,6 +95,16 @@
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
height: inherit;
|
||||
|
||||
&.is-focused {
|
||||
border: 1px solid $tertiary;
|
||||
@ -97,10 +112,43 @@
|
||||
-webkit-box-shadow: $tertiary 0px 0px 6px 0px;
|
||||
box-shadow: $tertiary 0px 0px 6px 0px;
|
||||
}
|
||||
|
||||
.current-selection {
|
||||
text-align: left;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.caret-icon {
|
||||
margin-left: 5px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.d-button-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
.d-icon {
|
||||
margin-left: 5px;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select-box-body {
|
||||
display: none;
|
||||
width: 100%;
|
||||
background: $secondary;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
@ -119,6 +167,26 @@
|
||||
-webkit-box-pack: start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
|
||||
.text {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.d-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&.is-highlighted {
|
||||
background: $tertiary-low;
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
background: $highlight-medium;
|
||||
}
|
||||
|
||||
&.is-selected.is-highlighted {
|
||||
background: $tertiary-low;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box-collection {
|
||||
@ -127,9 +195,9 @@
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 1 auto;
|
||||
flex: 0 1 auto;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: column;
|
||||
@ -137,15 +205,64 @@
|
||||
background: $secondary;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
border-radius: 0 0 3px 3px;
|
||||
border-radius: inherit;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
.collection {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
&:hover .select-box-row.is-highlighted:hover {
|
||||
background: $tertiary-low;
|
||||
}
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
-webkit-appearance: none;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
background: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box-filter {
|
||||
border-bottom: 1px solid $primary-low;
|
||||
background: $secondary;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
|
||||
.filter-query, .filter-query:focus, .filter-query:active {
|
||||
background: none;
|
||||
margin: 0;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
outline: none;
|
||||
border: 0;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
width: 100%;
|
||||
padding: 5px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box-wrapper {
|
||||
@ -159,132 +276,18 @@
|
||||
pointer-events: none;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box .select-box-header {
|
||||
height: inherit;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-direction: normal;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
|
||||
.current-selection {
|
||||
text-align: left;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.caret-icon {
|
||||
margin-left: 5px;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box .select-box-collection {
|
||||
-webkit-box-flex: 0;
|
||||
-ms-flex: 0 1 auto;
|
||||
flex: 0 1 auto;
|
||||
|
||||
.collection {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
-webkit-appearance: none;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
background: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box .select-box-row {
|
||||
.text {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.d-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&.is-highlighted {
|
||||
background: $highlight-medium;
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
a {
|
||||
background: $highlight-medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select-box .select-box-filter {
|
||||
background: $secondary;
|
||||
display: -webkit-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-align: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-box-pack: justify;
|
||||
-ms-flex-pack: justify;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
|
||||
.filter-query, .filter-query:focus, .filter-query:active {
|
||||
background: none;
|
||||
margin: 0;
|
||||
-webkit-box-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
outline: none;
|
||||
.select-box-offscreen, .select-box .select-box-offscreen:focus {
|
||||
clip: rect(0 0 0 0);
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
width: 100%;
|
||||
padding: 5px 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
outline: 0;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box .select-box-offscreen, .select-box .select-box-offscreen:focus {
|
||||
clip: rect(0 0 0 0);
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
outline: 0;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
#topic-footer-buttons {
|
||||
.topic-notifications-button {
|
||||
min-width: auto;
|
||||
margin: 10px 0 15px 0;
|
||||
|
||||
.btn {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.reason {
|
||||
line-height: 16px;
|
||||
margin: 0 0 0 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.topic-notifications-button .topic-notifications-options {
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.topic-notifications-button {
|
||||
display: inline-flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
|
||||
.topic-notifications-options {
|
||||
display: inline-flex;
|
||||
}
|
||||
}
|
||||
68
app/assets/stylesheets/common/components/user-info.scss
Normal file
68
app/assets/stylesheets/common/components/user-info.scss
Normal file
@ -0,0 +1,68 @@
|
||||
// Common styles for "user-info" component
|
||||
.user-info {
|
||||
display: inline-block;
|
||||
clear: both;
|
||||
margin-bottom: 1em;
|
||||
|
||||
.user-image {
|
||||
float: left;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.user-detail {
|
||||
float: left;
|
||||
width: 70%;
|
||||
padding-left: 5px;
|
||||
font-size: 13px;
|
||||
|
||||
.name-line {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.username a {
|
||||
font-weight: bold;
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 30%), scale-color($secondary, $lightness: 70%));
|
||||
}
|
||||
|
||||
.name {
|
||||
margin-left: 5px;
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 30%), scale-color($secondary, $lightness: 70%));
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-top: 3px;
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
||||
}
|
||||
}
|
||||
|
||||
&.small {
|
||||
width: 333px;
|
||||
}
|
||||
|
||||
&.medium {
|
||||
min-height: 60px;
|
||||
|
||||
.username, .name {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.name {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&.badge-info {
|
||||
min-height: 80px;
|
||||
|
||||
.granted-on {
|
||||
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
||||
}
|
||||
|
||||
.post-link {
|
||||
display: block;
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user