Version bump
This commit is contained in:
commit
ccbfacbfb0
6255 changed files with 9396 additions and 1949 deletions
app/assets/javascripts
admin
adapters
components
controllers
helpers
models
routes
admin-api-index.js.es6admin-api-keys.js.es6admin-route-map.js.es6admin-web-hooks-show-events.js.es6admin-web-hooks-show.js.es6
templates
discourse-common
discourse-objects.jsdiscourse.js.es6discourse
components
categories-admin-dropdown.js.es6category-chooser.js.es6category-logo-link.js.es6category-title-link.js.es6create-topics-notice.js.es6d-button.js.es6d-link.js.es6directory-toggle.js.es6global-notice.js.es6input-tip.js.es6notifications-button.js.es6popup-input-tip.js.es6tags-admin-dropdown.js.es6topic-footer-mobile-dropdown.js.es6topic-status.js.es6
controllers
ember
helpers
application.js.es6border-color.js.es6bound-avatar-template.js.es6bound-avatar.js.es6bound-category-link.js.es6bound-date.js.es6capitalize-string.js.es6category-badge.js.es6category-link.js.es6cold-age-class.js.es6cook-text.js.es6custom-html.js.es6dash-if-empty.js.es6discouse-tag.js.es6fa-icon-node.js.es6format-age.js.es6format-date.js.es6icon-or-image.js.es6loading-spinner.es6max-usernames.js.es6period-title.js.es6plugin-outlet.js.es6raw.js.es6replace-emoji.js.es6shorten-url.js.es6topic-link.js.es6user-avatar.js.es6user-status.js.es6
initializers
lib
autocomplete.js.es6create-view.js.es6mobile.js.es6plugin-api.js.es6transform-post.js.es6url.js.es6utilities.js.es6
mapping-router.js.es6models
pre-initializers
templates
views
|
@ -0,0 +1,7 @@
|
|||
import RESTAdapter from 'discourse/adapters/rest';
|
||||
|
||||
export default RESTAdapter.extend({
|
||||
basePath() {
|
||||
return '/admin/api/';
|
||||
}
|
||||
});
|
7
app/assets/javascripts/admin/adapters/web-hook.js.es6
Normal file
7
app/assets/javascripts/admin/adapters/web-hook.js.es6
Normal file
|
@ -0,0 +1,7 @@
|
|||
import RESTAdapter from 'discourse/adapters/rest';
|
||||
|
||||
export default RESTAdapter.extend({
|
||||
basePath() {
|
||||
return '/admin/api/';
|
||||
}
|
||||
});
|
|
@ -26,14 +26,14 @@ export default Ember.Component.extend({
|
|||
@computed('model.duration')
|
||||
completion(duration) {
|
||||
const seconds = Math.floor(duration / 10.0) / 100.0;
|
||||
return I18n.t('admin.web_hooks.events.completion', { seconds });
|
||||
return I18n.t('admin.web_hooks.events.completed_in', { count: seconds });
|
||||
},
|
||||
|
||||
actions: {
|
||||
redeliver() {
|
||||
return bootbox.confirm(I18n.t('admin.web_hooks.events.redeliver_confirm'), I18n.t('no_value'), I18n.t('yes_value'), result => {
|
||||
if (result) {
|
||||
ajax(`/admin/web_hooks/${this.get('model.web_hook_id')}/events/${this.get('model.id')}/redeliver`, { type: 'POST' }).then(json => {
|
||||
ajax(`/admin/api/web_hooks/${this.get('model.web_hook_id')}/events/${this.get('model.id')}/redeliver`, { type: 'POST' }).then(json => {
|
||||
this.set('model', json.web_hook_event);
|
||||
}).catch(popupAjaxError);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,65 @@
|
|||
import { ajax } from 'discourse/lib/ajax';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
pingDisabled: false,
|
||||
incomingEventIds: [],
|
||||
incomingCount: Ember.computed.alias("incomingEventIds.length"),
|
||||
|
||||
@computed('incomingCount')
|
||||
hasIncoming(incomingCount) {
|
||||
return incomingCount > 0;
|
||||
},
|
||||
|
||||
subscribe() {
|
||||
this.messageBus.subscribe(`/web_hook_events/${this.get('model.extras.web_hook_id')}`, data => {
|
||||
if (data.event_type === 'ping') {
|
||||
this.set('pingDisabled', false);
|
||||
}
|
||||
this._addIncoming(data.web_hook_event_id);
|
||||
});
|
||||
},
|
||||
|
||||
unsubscribe() {
|
||||
this.messageBus.unsubscribe('/web_hook_events/*');
|
||||
},
|
||||
|
||||
_addIncoming(eventId) {
|
||||
const incomingEventIds = this.get("incomingEventIds");
|
||||
|
||||
if (incomingEventIds.indexOf(eventId) === -1) {
|
||||
incomingEventIds.pushObject(eventId);
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
loadMore() {
|
||||
this.get('model').loadMore();
|
||||
},
|
||||
|
||||
ping() {
|
||||
ajax(`/admin/web_hooks/${this.get('model.extras.web_hook_id')}/ping`, {type: 'POST'}).catch(popupAjaxError);
|
||||
this.set('pingDisabled', true);
|
||||
|
||||
ajax(`/admin/api/web_hooks/${this.get('model.extras.web_hook_id')}/ping`, {
|
||||
type: 'POST'
|
||||
}).catch(error => {
|
||||
this.set('pingDisabled', false);
|
||||
popupAjaxError(error);
|
||||
});
|
||||
},
|
||||
|
||||
showInserted() {
|
||||
const webHookId = this.get('model.extras.web_hook_id');
|
||||
|
||||
ajax(`/admin/api/web_hooks/${webHookId}/events/bulk`, {
|
||||
type: 'GET',
|
||||
data: { ids: this.get('incomingEventIds') }
|
||||
}).then(data => {
|
||||
const objects = data.map(event => this.store.createRecord('web-hook-event', event));
|
||||
this.get("model").unshiftObjects(objects);
|
||||
this.set("incomingEventIds", []);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
|
||||
export default htmlHelper(size => I18n.toHumanSize(size));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
import { escapeExpression } from 'discourse/lib/utilities';
|
||||
|
||||
export default htmlHelper(str => escapeExpression(str).replace(/\n/g, "<br>"));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
|
||||
registerUnbound('value-at-tl', function(data, params) {
|
||||
var tl = parseInt(params.level, 10);
|
||||
|
|
|
@ -52,7 +52,7 @@ ApiKey.reopenClass({
|
|||
@returns {Promise} a promise that resolves to the array of `ApiKey` instances
|
||||
**/
|
||||
find: function() {
|
||||
return ajax("/admin/api").then(function(keys) {
|
||||
return ajax("/admin/api/keys").then(function(keys) {
|
||||
return keys.map(function (key) {
|
||||
return ApiKey.create(key);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export default Ember.Route.extend({
|
||||
beforeModel() {
|
||||
this.transitionTo('adminApiKeys');
|
||||
}
|
||||
});
|
|
@ -35,10 +35,14 @@ export default {
|
|||
this.route('edit', { path: '/:id' });
|
||||
});
|
||||
});
|
||||
this.route('api');
|
||||
this.resource('adminWebHooks', { path: '/web_hooks' }, function() {
|
||||
this.route('show', { path: '/:web_hook_id' });
|
||||
this.route('showEvents', { path: '/:web_hook_id/events' });
|
||||
|
||||
this.resource('adminApi', { path: '/api' }, function() {
|
||||
this.resource('adminApiKeys', { path: '/keys' });
|
||||
|
||||
this.resource('adminWebHooks', { path: '/web_hooks' }, function() {
|
||||
this.route('show', { path: '/:web_hook_id' });
|
||||
this.route('showEvents', { path: '/:web_hook_id/events' });
|
||||
});
|
||||
});
|
||||
|
||||
this.resource('admin.backups', { path: '/backups' }, function() {
|
||||
|
|
|
@ -5,9 +5,14 @@ export default Discourse.Route.extend({
|
|||
|
||||
setupController(controller, model) {
|
||||
controller.set('model', model);
|
||||
controller.subscribe();
|
||||
},
|
||||
|
||||
deactivate() {
|
||||
this.controllerFor('adminWebHooks.showEvents').unsubscribe();
|
||||
},
|
||||
|
||||
renderTemplate() {
|
||||
this.render('admin/templates/web-hooks-show-events', { into: 'admin' });
|
||||
this.render('admin/templates/web-hooks-show-events', { into: 'adminApi' });
|
||||
}
|
||||
});
|
||||
|
|
|
@ -21,6 +21,6 @@ export default Discourse.Route.extend({
|
|||
},
|
||||
|
||||
renderTemplate() {
|
||||
this.render('admin/templates/web-hooks-show', { into: 'admin' });
|
||||
this.render('admin/templates/web-hooks-show', { into: 'adminApi' });
|
||||
}
|
||||
});
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
{{nav-item route='adminLogs' label='admin.logs.title'}}
|
||||
{{#if currentUser.admin}}
|
||||
{{nav-item route='adminCustomize' label='admin.customize.title'}}
|
||||
{{nav-item route='admin.api' label='admin.api.title'}}
|
||||
{{nav-item route='adminWebHooks' label='admin.web_hooks.title'}}
|
||||
{{nav-item route='adminApi' label='admin.api.title'}}
|
||||
{{nav-item route='admin.backups' label='admin.backups.title'}}
|
||||
{{/if}}
|
||||
{{nav-item route='adminPlugins' label='admin.plugins.title'}}
|
||||
|
|
34
app/assets/javascripts/admin/templates/api-keys.hbs
Normal file
34
app/assets/javascripts/admin/templates/api-keys.hbs
Normal file
|
@ -0,0 +1,34 @@
|
|||
{{#if model}}
|
||||
<table class='api-keys'>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.api.key'}}</th>
|
||||
<th>{{i18n 'admin.api.user'}}</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{{#each model as |k|}}
|
||||
<tr>
|
||||
<td class='key'>{{k.key}}</td>
|
||||
<td>
|
||||
{{#if k.user}}
|
||||
{{#link-to 'adminUser' k.user}}
|
||||
{{avatar k.user imageSize="small"}}
|
||||
{{/link-to}}
|
||||
{{else}}
|
||||
{{i18n 'admin.api.all_users'}}
|
||||
{{/if}}
|
||||
</td>
|
||||
<td>
|
||||
{{d-button action="regenerateKey" actionParam=k icon="undo" label='admin.api.regenerate'}}
|
||||
{{d-button action="revokeKey" actionParam=k icon="times" label='admin.api.revoke'}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
{{else}}
|
||||
<p>{{i18n 'admin.api.none'}}</p>
|
||||
{{/if}}
|
||||
|
||||
{{#unless hasMasterKey}}
|
||||
<button class='btn' {{action "generateMasterKey"}}><i class="fa fa-key"></i>{{i18n 'admin.api.generate_master'}}</button>
|
||||
{{/unless }}
|
||||
|
|
@ -1,33 +1,10 @@
|
|||
{{#if model}}
|
||||
<table class='api-keys'>
|
||||
<tr>
|
||||
<th>{{i18n 'admin.api.key'}}</th>
|
||||
<th>{{i18n 'admin.api.user'}}</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{{#each model as |k|}}
|
||||
<tr>
|
||||
<td class='key'>{{k.key}}</td>
|
||||
<td>
|
||||
{{#if k.user}}
|
||||
{{#link-to 'adminUser' k.user}}
|
||||
{{avatar k.user imageSize="small"}}
|
||||
{{/link-to}}
|
||||
{{else}}
|
||||
{{i18n 'admin.api.all_users'}}
|
||||
{{/if}}
|
||||
</td>
|
||||
<td>
|
||||
<button class='btn' {{action "regenerateKey" k}}><i class="fa fa-undo"></i>{{i18n 'admin.api.regenerate'}}</button>
|
||||
<button class='btn' {{action "revokeKey" k}}><i class="fa fa-times"></i>{{i18n 'admin.api.revoke'}}</button>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
{{else}}
|
||||
<p>{{i18n 'admin.api.none'}}</p>
|
||||
{{/if}}
|
||||
<div class="api">
|
||||
{{#admin-nav}}
|
||||
{{nav-item route='adminApiKeys' label='admin.api.title'}}
|
||||
{{nav-item route='adminWebHooks' label='admin.web_hooks.title'}}
|
||||
{{/admin-nav}}
|
||||
|
||||
{{#unless hasMasterKey}}
|
||||
<button class='btn' {{action "generateMasterKey"}}><i class="fa fa-key"></i>{{i18n 'admin.api.generate_master'}}</button>
|
||||
{{/unless }}
|
||||
<div class="admin-container">
|
||||
{{outlet}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="col first">
|
||||
<div class="col first status">
|
||||
<span class="{{statusColorClasses}}">{{model.status}}</span>
|
||||
</div>
|
||||
<div class="col event-id">{{model.id}}</div>
|
||||
|
|
|
@ -119,6 +119,11 @@
|
|||
{{text-field name="flair_color" class="flair_color" value=model.flair_color placeholderKey="admin.groups.flair_color_placeholder"}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<br/>
|
||||
<div>
|
||||
<strong>{{i18n 'admin.groups.flair_note'}}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if flairPreviewIcon}}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{{#link-to 'adminWebHooks' tagName='button' classNames='btn'}}
|
||||
{{fa-icon 'list'}} {{i18n 'admin.web_hooks.events.go_list'}}
|
||||
{{/link-to}}
|
||||
{{d-button icon="send" label="admin.web_hooks.events.ping" action="ping"}}
|
||||
{{d-button icon="send" label="admin.web_hooks.events.ping" action="ping" disabled=pingDisabled}}
|
||||
{{#link-to 'adminWebHooks.show' model.extras.web_hook_id tagName='button' classNames='btn'}}
|
||||
{{fa-icon 'edit'}} {{i18n 'admin.web_hooks.events.go_details'}}
|
||||
{{/link-to}}
|
||||
|
@ -12,6 +12,20 @@
|
|||
{{#if model}}
|
||||
{{#load-more selector=".web-hook-events li" action="loadMore"}}
|
||||
<div class='web-hook-events content-list'>
|
||||
<div class='heading-container'>
|
||||
<div class='col heading first status'>{{i18n 'admin.web_hooks.events.status'}}</div>
|
||||
<div class='col heading event-id'>{{i18n 'admin.web_hooks.events.event_id'}}</div>
|
||||
<div class='col heading timestamp'>{{i18n 'admin.web_hooks.events.timestamp'}}</div>
|
||||
<div class='col heading completion'>{{i18n 'admin.web_hooks.events.completion'}}</div>
|
||||
<div class='col heading actions'>{{i18n 'admin.web_hooks.events.actions'}}</div>
|
||||
<div class='clearfix'></div>
|
||||
</div>
|
||||
{{#if hasIncoming}}
|
||||
<div class='alert alert-info clickable' {{action "showInserted"}}>
|
||||
{{count-i18n key="admin.web_hooks.events.incoming" count=incomingCount}}
|
||||
{{i18n 'click_to_show'}}
|
||||
</div>
|
||||
{{/if}}
|
||||
<ul>
|
||||
{{#each model as |webHookEvent|}}
|
||||
{{admin-web-hook-event model=webHookEvent}}
|
||||
|
|
|
@ -64,10 +64,11 @@ export default Ember.Component.extend({
|
|||
}
|
||||
|
||||
const $elem = this.$();
|
||||
const minimumResultsForSearch = this.capabilities.isIOS ? -1 : 5;
|
||||
const caps = this.capabilities;
|
||||
const minimumResultsForSearch = (caps && caps.isIOS) ? -1 : 5;
|
||||
$elem.select2({
|
||||
formatResult: this.comboTemplate, minimumResultsForSearch,
|
||||
width: 'resolve',
|
||||
width: this.get('width') || 'resolve',
|
||||
allowClear: true
|
||||
});
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
|
||||
export default htmlHelper((key, params) => I18n.t(key, params.hash));
|
|
@ -1,8 +1,7 @@
|
|||
import { h } from 'virtual-dom';
|
||||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
|
||||
function iconClasses(icon, params) {
|
||||
var classes = "fa fa-" + icon;
|
||||
export function iconClasses(icon, params) {
|
||||
let classes = "fa fa-" + icon;
|
||||
if (params.modifier) { classes += " fa-" + params.modifier; }
|
||||
if (params['class']) { classes += ' ' + params['class']; }
|
||||
return classes;
|
||||
|
@ -21,23 +20,6 @@ export function iconHTML(icon, params) {
|
|||
return html;
|
||||
}
|
||||
|
||||
export function iconNode(icon, params) {
|
||||
params = params || {};
|
||||
|
||||
const properties = {
|
||||
className: iconClasses(icon, params),
|
||||
attributes: { "aria-hidden": true }
|
||||
};
|
||||
|
||||
if (params.title) { properties.attributes.title = params.title; }
|
||||
|
||||
if (params.label) {
|
||||
return h('i', properties, h('span.sr-only', I18n.t(params.label)));
|
||||
} else {
|
||||
return h('i', properties);
|
||||
}
|
||||
}
|
||||
|
||||
registerUnbound('fa-icon', function(icon, params) {
|
||||
return new Handlebars.SafeString(iconHTML(icon, params));
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
|
||||
registerUnbound('i18n', (key, params) => I18n.t(key, params));
|
|
@ -1,4 +1,4 @@
|
|||
import { get } from 'discourse/lib/raw-handlebars';
|
||||
import { get } from 'discourse-common/lib/raw-handlebars';
|
||||
|
||||
// `Ember.Helper` is only available in versions after 1.12
|
||||
export function htmlHelper(fn) {
|
218
app/assets/javascripts/discourse-common/resolver.js.es6
Normal file
218
app/assets/javascripts/discourse-common/resolver.js.es6
Normal file
|
@ -0,0 +1,218 @@
|
|||
/* global requirejs, require */
|
||||
|
||||
var classify = Ember.String.classify;
|
||||
var get = Ember.get;
|
||||
|
||||
var LOADING_WHITELIST = ['badges', 'userActivity', 'userPrivateMessages', 'admin', 'adminFlags',
|
||||
'user', 'preferences', 'adminEmail', 'adminUsersList'];
|
||||
var _dummyRoute;
|
||||
var _loadingView;
|
||||
|
||||
function loadingResolver(cb) {
|
||||
return function(parsedName) {
|
||||
var fullNameWithoutType = parsedName.fullNameWithoutType;
|
||||
|
||||
if (fullNameWithoutType.indexOf('Loading') >= 0) {
|
||||
fullNameWithoutType = fullNameWithoutType.replace('Loading', '');
|
||||
if (LOADING_WHITELIST.indexOf(fullNameWithoutType) !== -1) {
|
||||
return cb(fullNameWithoutType);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function parseName(fullName) {
|
||||
const nameParts = fullName.split(":"),
|
||||
type = nameParts[0], fullNameWithoutType = nameParts[1],
|
||||
name = fullNameWithoutType,
|
||||
namespace = get(this, 'namespace'),
|
||||
root = namespace;
|
||||
|
||||
return {
|
||||
fullName: fullName,
|
||||
type: type,
|
||||
fullNameWithoutType: fullNameWithoutType,
|
||||
name: name,
|
||||
root: root,
|
||||
resolveMethodName: "resolve" + classify(type)
|
||||
};
|
||||
}
|
||||
|
||||
export function buildResolver(baseName) {
|
||||
return Ember.DefaultResolver.extend({
|
||||
parseName,
|
||||
|
||||
resolveRouter(parsedName) {
|
||||
const routerPath = `${baseName}/router`;
|
||||
if (requirejs.entries[routerPath]) {
|
||||
const module = require(routerPath, null, null, true);
|
||||
return module.default;
|
||||
}
|
||||
return this._super(parsedName);
|
||||
},
|
||||
|
||||
normalize(fullName) {
|
||||
const split = fullName.split(':');
|
||||
if (split.length > 1) {
|
||||
const appBase = `${baseName}/${split[0]}s/`;
|
||||
const adminBase = 'admin/' + split[0] + 's/';
|
||||
|
||||
// Allow render 'admin/templates/xyz' too
|
||||
split[1] = split[1].replace('.templates', '').replace('/templates', '');
|
||||
|
||||
// Try slashes
|
||||
let dashed = Ember.String.dasherize(split[1].replace(/\./g, '/'));
|
||||
if (requirejs.entries[appBase + dashed] || requirejs.entries[adminBase + dashed]) {
|
||||
return split[0] + ":" + dashed;
|
||||
}
|
||||
|
||||
// Try with dashes instead of slashes
|
||||
dashed = Ember.String.dasherize(split[1].replace(/\./g, '-'));
|
||||
if (requirejs.entries[appBase + dashed] || requirejs.entries[adminBase + dashed]) {
|
||||
return split[0] + ":" + dashed;
|
||||
}
|
||||
}
|
||||
return this._super(fullName);
|
||||
},
|
||||
|
||||
customResolve(parsedName) {
|
||||
// If we end with the name we want, use it. This allows us to define components within plugins.
|
||||
const suffix = parsedName.type + 's/' + parsedName.fullNameWithoutType,
|
||||
dashed = Ember.String.dasherize(suffix),
|
||||
moduleName = Object.keys(requirejs.entries).find(function(e) {
|
||||
return (e.indexOf(suffix, e.length - suffix.length) !== -1) ||
|
||||
(e.indexOf(dashed, e.length - dashed.length) !== -1);
|
||||
});
|
||||
|
||||
var module;
|
||||
if (moduleName) {
|
||||
module = require(moduleName, null, null, true /* force sync */);
|
||||
if (module && module['default']) { module = module['default']; }
|
||||
}
|
||||
return module;
|
||||
},
|
||||
|
||||
resolveWidget(parsedName) {
|
||||
return this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveAdapter(parsedName) {
|
||||
return this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveModel(parsedName) {
|
||||
return this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveView(parsedName) {
|
||||
return this.findLoadingView(parsedName) || this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveHelper(parsedName) {
|
||||
return this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveController(parsedName) {
|
||||
return this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveComponent(parsedName) {
|
||||
return this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveRoute(parsedName) {
|
||||
return this.findLoadingRoute(parsedName) || this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveTemplate(parsedName) {
|
||||
return this.findPluginMobileTemplate(parsedName) ||
|
||||
this.findPluginTemplate(parsedName) ||
|
||||
this.findMobileTemplate(parsedName) ||
|
||||
this.findTemplate(parsedName) ||
|
||||
Ember.TEMPLATES.not_found;
|
||||
},
|
||||
|
||||
findLoadingRoute: loadingResolver(function() {
|
||||
_dummyRoute = _dummyRoute || Ember.Route.extend();
|
||||
return _dummyRoute;
|
||||
}),
|
||||
|
||||
findLoadingView: loadingResolver(function() {
|
||||
if (!_loadingView) {
|
||||
_loadingView = require('discourse/views/loading', null, null, true /* force sync */);
|
||||
if (_loadingView && _loadingView['default']) { _loadingView = _loadingView['default']; }
|
||||
}
|
||||
return _loadingView;
|
||||
}),
|
||||
|
||||
findPluginTemplate(parsedName) {
|
||||
var pluginParsedName = this.parseName(parsedName.fullName.replace("template:", "template:javascripts/"));
|
||||
return this.findTemplate(pluginParsedName);
|
||||
},
|
||||
|
||||
findPluginMobileTemplate(parsedName) {
|
||||
if (this.mobileView) {
|
||||
var pluginParsedName = this.parseName(parsedName.fullName.replace("template:", "template:javascripts/mobile/"));
|
||||
return this.findTemplate(pluginParsedName);
|
||||
}
|
||||
},
|
||||
|
||||
findMobileTemplate(parsedName) {
|
||||
if (this.mobileView) {
|
||||
var mobileParsedName = this.parseName(parsedName.fullName.replace("template:", "template:mobile/"));
|
||||
return this.findTemplate(mobileParsedName);
|
||||
}
|
||||
},
|
||||
|
||||
findTemplate(parsedName) {
|
||||
const withoutType = parsedName.fullNameWithoutType,
|
||||
slashedType = withoutType.replace(/\./g, '/'),
|
||||
decamelized = withoutType.decamelize(),
|
||||
dashed = decamelized.replace(/\./g, '-').replace(/\_/g, '-'),
|
||||
templates = Ember.TEMPLATES;
|
||||
|
||||
return this._super(parsedName) ||
|
||||
templates[slashedType] ||
|
||||
templates[withoutType] ||
|
||||
templates[dashed] ||
|
||||
templates[decamelized.replace(/\./, '/')] ||
|
||||
templates[decamelized.replace(/\_/, '/')] ||
|
||||
templates[`${baseName}/templates/${withoutType}`] ||
|
||||
this.findAdminTemplate(parsedName) ||
|
||||
this.findUnderscoredTemplate(parsedName);
|
||||
},
|
||||
|
||||
findUnderscoredTemplate(parsedName) {
|
||||
var decamelized = parsedName.fullNameWithoutType.decamelize();
|
||||
var underscored = decamelized.replace(/\-/g, "_");
|
||||
return Ember.TEMPLATES[underscored];
|
||||
},
|
||||
|
||||
// Try to find a template within a special admin namespace, e.g. adminEmail => admin/templates/email
|
||||
// (similar to how discourse lays out templates)
|
||||
findAdminTemplate(parsedName) {
|
||||
var decamelized = parsedName.fullNameWithoutType.decamelize();
|
||||
|
||||
if (decamelized.indexOf('components') === 0) {
|
||||
const compTemplate = Ember.TEMPLATES['admin/templates/' + decamelized];
|
||||
if (compTemplate) { return compTemplate; }
|
||||
}
|
||||
|
||||
if (decamelized === "javascripts/admin") {
|
||||
return Ember.TEMPLATES['admin/templates/admin'];
|
||||
}
|
||||
|
||||
if (decamelized.indexOf('admin') === 0 || decamelized.indexOf('javascripts/admin') === 0) {
|
||||
decamelized = decamelized.replace(/^admin\_/, 'admin/templates/');
|
||||
decamelized = decamelized.replace(/^admin\./, 'admin/templates/');
|
||||
decamelized = decamelized.replace(/\./g, '_');
|
||||
|
||||
const dashed = decamelized.replace(/_/g, '-');
|
||||
return Ember.TEMPLATES[decamelized] ||
|
||||
Ember.TEMPLATES[dashed] ||
|
||||
Ember.TEMPLATES[dashed.replace('admin-', 'admin/')];
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
2
app/assets/javascripts/discourse-objects.js
Normal file
2
app/assets/javascripts/discourse-objects.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
window.Discourse = {};
|
||||
Discourse.SiteSettings = {};
|
|
@ -1,4 +1,4 @@
|
|||
import DiscourseResolver from 'discourse/ember/resolver';
|
||||
import { buildResolver } from 'discourse-common/resolver';
|
||||
import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
const _pluginCallbacks = [];
|
||||
|
@ -31,7 +31,7 @@ const Discourse = Ember.Application.extend({
|
|||
return url;
|
||||
},
|
||||
|
||||
Resolver: DiscourseResolver,
|
||||
Resolver: buildResolver('discourse'),
|
||||
|
||||
@observes('_docTitle', 'hasFocus', 'notifyCount')
|
||||
_titleChanged() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
import DropdownButton from 'discourse/components/dropdown-button';
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import ComboboxView from 'discourse/components/combo-box';
|
||||
import ComboboxView from 'discourse-common/components/combo-box';
|
||||
import { categoryBadgeHTML } from 'discourse/helpers/category-link';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import { observes, on } from 'ember-addons/ember-computed-decorators';
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
export default Em.Component.extend({
|
||||
tagName: 'a',
|
||||
attributeBindings: ['href'],
|
||||
href: function() {
|
||||
return Discourse.getURL('/c/') + Discourse.Category.slugFor(this.get('category'));
|
||||
}.property(),
|
||||
|
||||
render(buffer) {
|
||||
const categoryLogo = this.get('category.logo_url');
|
||||
buffer.push(`<img class="category-logo" src='${categoryLogo}'/>`);
|
||||
}
|
||||
});
|
|
@ -1,17 +1,10 @@
|
|||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Em.Component.extend({
|
||||
tagName: 'h3',
|
||||
|
||||
render(buffer) {
|
||||
const category = this.get('category');
|
||||
const categoryUrl = Discourse.getURL('/c/') + Discourse.Category.slugFor(category);
|
||||
const categoryName = Handlebars.Utils.escapeExpression(category.get('name'));
|
||||
|
||||
if (category.get('read_restricted')) { buffer.push(iconHTML('lock')); }
|
||||
|
||||
buffer.push(`<a href='${categoryUrl}'>`);
|
||||
buffer.push(`<span class='category-name'>${categoryName}</span>`);
|
||||
buffer.push(`</a>`);
|
||||
@computed("category.name")
|
||||
categoryName(name) {
|
||||
return Handlebars.Utils.escapeExpression(name);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -36,7 +36,10 @@ export default Ember.Component.extend({
|
|||
|
||||
@computed()
|
||||
shouldSee() {
|
||||
return Discourse.User.currentProp('admin') && this.siteSettings.show_create_topics_notice;
|
||||
const user = this.currentUser;
|
||||
return user && user.get('admin') &&
|
||||
this.siteSettings.show_create_topics_notice &&
|
||||
!this.site.get('wizard_required');
|
||||
},
|
||||
|
||||
@computed('enabled', 'shouldSee', 'publicTopicCount', 'publicPostCount')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
import interceptClick from 'discourse/lib/intercept-click';
|
||||
|
||||
export default Ember.Component.extend({
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
|
||||
export default Ember.Component.extend(StringBuffer, {
|
||||
tagName: 'th',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { on } from 'ember-addons/ember-computed-decorators';
|
||||
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
import LogsNotice from 'discourse/services/logs-notice';
|
||||
|
||||
export default Ember.Component.extend(StringBuffer, {
|
||||
|
@ -17,6 +17,10 @@ export default Ember.Component.extend(StringBuffer, {
|
|||
notices.push([I18n.t("emails_are_disabled"), 'alert-emails-disabled']);
|
||||
}
|
||||
|
||||
if (this.site.get('wizard_required')) {
|
||||
notices.push([I18n.t('wizard_required'), 'alert-wizard']);
|
||||
}
|
||||
|
||||
if (this.currentUser && this.currentUser.get('staff') && this.siteSettings.bootstrap_mode_enabled) {
|
||||
if (this.siteSettings.bootstrap_mode_min_users > 0) {
|
||||
notices.push([I18n.t("bootstrap_mode_enabled", {min_users: this.siteSettings.bootstrap_mode_min_users}), 'alert-bootstrap-mode']);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
|
||||
export default Ember.Component.extend(StringBuffer, {
|
||||
classNameBindings: [':tip', 'good', 'bad'],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import DropdownButton from 'discourse/components/dropdown-button';
|
||||
import { allLevels, buttonDetails } from 'discourse/lib/notification-levels';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
import computed from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default DropdownButton.extend({
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Ember.Component.extend(StringBuffer, {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
import DropdownButton from 'discourse/components/dropdown-button';
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import Combobox from 'discourse/components/combo-box';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
import Combobox from 'discourse-common/components/combo-box';
|
||||
import { on, observes } from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export default Combobox.extend({
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
import StringBuffer from 'discourse/mixins/string-buffer';
|
||||
import { escapeExpression } from 'discourse/lib/utilities';
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
|||
if(customLogin){
|
||||
customLogin();
|
||||
} else {
|
||||
const authUrl = loginMethod.get('customUrl') || Discourse.getURL("/auth/" + name);
|
||||
let authUrl = loginMethod.get('customUrl') || Discourse.getURL("/auth/" + name);
|
||||
if (loginMethod.get("fullScreenLogin")) {
|
||||
document.cookie = "fsl=true";
|
||||
window.location = authUrl;
|
||||
|
@ -141,6 +141,11 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
|||
|
||||
const height = loginMethod.get("frameHeight") || 400;
|
||||
const width = loginMethod.get("frameWidth") || 800;
|
||||
|
||||
if (loginMethod.get("displayPopup")) {
|
||||
authUrl = authUrl + "?display=popup";
|
||||
}
|
||||
|
||||
const w = window.open(authUrl, "_blank",
|
||||
"menubar=no,status=no,height=" + height + ",width=" + width + ",left=" + left + ",top=" + top);
|
||||
const self = this;
|
||||
|
|
|
@ -1,206 +0,0 @@
|
|||
/* global requirejs, require */
|
||||
|
||||
var classify = Ember.String.classify;
|
||||
var get = Ember.get;
|
||||
|
||||
var LOADING_WHITELIST = ['badges', 'userActivity', 'userPrivateMessages', 'admin', 'adminFlags',
|
||||
'user', 'preferences', 'adminEmail', 'adminUsersList'];
|
||||
var _dummyRoute;
|
||||
var _loadingView;
|
||||
|
||||
function loadingResolver(cb) {
|
||||
return function(parsedName) {
|
||||
var fullNameWithoutType = parsedName.fullNameWithoutType;
|
||||
|
||||
if (fullNameWithoutType.indexOf('Loading') >= 0) {
|
||||
fullNameWithoutType = fullNameWithoutType.replace('Loading', '');
|
||||
if (LOADING_WHITELIST.indexOf(fullNameWithoutType) !== -1) {
|
||||
return cb(fullNameWithoutType);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function parseName(fullName) {
|
||||
const nameParts = fullName.split(":"),
|
||||
type = nameParts[0], fullNameWithoutType = nameParts[1],
|
||||
name = fullNameWithoutType,
|
||||
namespace = get(this, 'namespace'),
|
||||
root = namespace;
|
||||
|
||||
return {
|
||||
fullName: fullName,
|
||||
type: type,
|
||||
fullNameWithoutType: fullNameWithoutType,
|
||||
name: name,
|
||||
root: root,
|
||||
resolveMethodName: "resolve" + classify(type)
|
||||
};
|
||||
}
|
||||
|
||||
export default Ember.DefaultResolver.extend({
|
||||
parseName: parseName,
|
||||
|
||||
normalize(fullName) {
|
||||
var split = fullName.split(':');
|
||||
if (split.length > 1) {
|
||||
var discourseBase = 'discourse/' + split[0] + 's/';
|
||||
var adminBase = 'admin/' + split[0] + 's/';
|
||||
|
||||
// Allow render 'admin/templates/xyz' too
|
||||
split[1] = split[1].replace('.templates', '').replace('/templates', '');
|
||||
|
||||
// Try slashes
|
||||
var dashed = Ember.String.dasherize(split[1].replace(/\./g, '/'));
|
||||
if (requirejs.entries[discourseBase + dashed] || requirejs.entries[adminBase + dashed]) {
|
||||
return split[0] + ":" + dashed;
|
||||
}
|
||||
|
||||
// Try with dashes instead of slashes
|
||||
dashed = Ember.String.dasherize(split[1].replace(/\./g, '-'));
|
||||
if (requirejs.entries[discourseBase + dashed] || requirejs.entries[adminBase + dashed]) {
|
||||
return split[0] + ":" + dashed;
|
||||
}
|
||||
}
|
||||
return this._super(fullName);
|
||||
},
|
||||
|
||||
customResolve(parsedName) {
|
||||
// If we end with the name we want, use it. This allows us to define components within plugins.
|
||||
const suffix = parsedName.type + 's/' + parsedName.fullNameWithoutType,
|
||||
dashed = Ember.String.dasherize(suffix),
|
||||
moduleName = Object.keys(requirejs.entries).find(function(e) {
|
||||
return (e.indexOf(suffix, e.length - suffix.length) !== -1) ||
|
||||
(e.indexOf(dashed, e.length - dashed.length) !== -1);
|
||||
});
|
||||
|
||||
var module;
|
||||
if (moduleName) {
|
||||
module = require(moduleName, null, null, true /* force sync */);
|
||||
if (module && module['default']) { module = module['default']; }
|
||||
}
|
||||
return module;
|
||||
},
|
||||
|
||||
resolveWidget(parsedName) {
|
||||
return this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveAdapter(parsedName) {
|
||||
return this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveModel(parsedName) {
|
||||
return this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveView(parsedName) {
|
||||
return this.findLoadingView(parsedName) || this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveHelper(parsedName) {
|
||||
return this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveController(parsedName) {
|
||||
return this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveComponent(parsedName) {
|
||||
return this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveRoute(parsedName) {
|
||||
return this.findLoadingRoute(parsedName) || this.customResolve(parsedName) || this._super(parsedName);
|
||||
},
|
||||
|
||||
resolveTemplate(parsedName) {
|
||||
return this.findPluginMobileTemplate(parsedName) ||
|
||||
this.findPluginTemplate(parsedName) ||
|
||||
this.findMobileTemplate(parsedName) ||
|
||||
this.findTemplate(parsedName) ||
|
||||
Ember.TEMPLATES.not_found;
|
||||
},
|
||||
|
||||
findLoadingRoute: loadingResolver(function() {
|
||||
_dummyRoute = _dummyRoute || Ember.Route.extend();
|
||||
return _dummyRoute;
|
||||
}),
|
||||
|
||||
findLoadingView: loadingResolver(function() {
|
||||
if (!_loadingView) {
|
||||
_loadingView = require('discourse/views/loading', null, null, true /* force sync */);
|
||||
if (_loadingView && _loadingView['default']) { _loadingView = _loadingView['default']; }
|
||||
}
|
||||
return _loadingView;
|
||||
}),
|
||||
|
||||
findPluginTemplate(parsedName) {
|
||||
var pluginParsedName = this.parseName(parsedName.fullName.replace("template:", "template:javascripts/"));
|
||||
return this.findTemplate(pluginParsedName);
|
||||
},
|
||||
|
||||
findPluginMobileTemplate(parsedName) {
|
||||
if (this.mobileView) {
|
||||
var pluginParsedName = this.parseName(parsedName.fullName.replace("template:", "template:javascripts/mobile/"));
|
||||
return this.findTemplate(pluginParsedName);
|
||||
}
|
||||
},
|
||||
|
||||
findMobileTemplate(parsedName) {
|
||||
if (this.mobileView) {
|
||||
var mobileParsedName = this.parseName(parsedName.fullName.replace("template:", "template:mobile/"));
|
||||
return this.findTemplate(mobileParsedName);
|
||||
}
|
||||
},
|
||||
|
||||
findTemplate(parsedName) {
|
||||
const withoutType = parsedName.fullNameWithoutType,
|
||||
slashedType = withoutType.replace(/\./g, '/'),
|
||||
decamelized = withoutType.decamelize(),
|
||||
dashed = decamelized.replace(/\./g, '-').replace(/\_/g, '-'),
|
||||
templates = Ember.TEMPLATES;
|
||||
|
||||
return this._super(parsedName) ||
|
||||
templates[slashedType] ||
|
||||
templates[withoutType] ||
|
||||
templates[dashed] ||
|
||||
templates[decamelized.replace(/\./, '/')] ||
|
||||
templates[decamelized.replace(/\_/, '/')] ||
|
||||
this.findAdminTemplate(parsedName) ||
|
||||
this.findUnderscoredTemplate(parsedName);
|
||||
},
|
||||
|
||||
findUnderscoredTemplate(parsedName) {
|
||||
var decamelized = parsedName.fullNameWithoutType.decamelize();
|
||||
var underscored = decamelized.replace(/\-/g, "_");
|
||||
return Ember.TEMPLATES[underscored];
|
||||
},
|
||||
|
||||
// Try to find a template within a special admin namespace, e.g. adminEmail => admin/templates/email
|
||||
// (similar to how discourse lays out templates)
|
||||
findAdminTemplate(parsedName) {
|
||||
var decamelized = parsedName.fullNameWithoutType.decamelize();
|
||||
|
||||
if (decamelized.indexOf('components') === 0) {
|
||||
const compTemplate = Ember.TEMPLATES['admin/templates/' + decamelized];
|
||||
if (compTemplate) { return compTemplate; }
|
||||
}
|
||||
|
||||
if (decamelized === "javascripts/admin") {
|
||||
return Ember.TEMPLATES['admin/templates/admin'];
|
||||
}
|
||||
|
||||
if (decamelized.indexOf('admin') === 0 || decamelized.indexOf('javascripts/admin') === 0) {
|
||||
decamelized = decamelized.replace(/^admin\_/, 'admin/templates/');
|
||||
decamelized = decamelized.replace(/^admin\./, 'admin/templates/');
|
||||
decamelized = decamelized.replace(/\./g, '_');
|
||||
|
||||
const dashed = decamelized.replace(/_/g, '-');
|
||||
return Ember.TEMPLATES[decamelized] ||
|
||||
Ember.TEMPLATES[dashed] ||
|
||||
Ember.TEMPLATES[dashed.replace('admin-', 'admin/')];
|
||||
}
|
||||
}
|
||||
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
import { longDate, autoUpdatingRelativeAge, number } from 'discourse/lib/formatter';
|
||||
|
||||
const safe = Handlebars.SafeString;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
|
||||
export default htmlHelper(color => `border-color: #${color}`);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
import { avatarImg } from 'discourse/lib/utilities';
|
||||
|
||||
export default htmlHelper((avatarTemplate, size) => avatarImg({ size, avatarTemplate }));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
import { avatarImg } from 'discourse/lib/utilities';
|
||||
|
||||
export default htmlHelper((user, size) => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
import { categoryLinkHTML } from 'discourse/helpers/category-link';
|
||||
|
||||
export default htmlHelper(categoryLinkHTML);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { autoUpdatingRelativeAge } from 'discourse/lib/formatter';
|
||||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
|
||||
export default htmlHelper(dt => autoUpdatingRelativeAge(new Date(dt), {format: 'medium', title: true }));
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
|
||||
export default htmlHelper(str => str[0].toUpperCase() + str.slice(1));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { categoryLinkHTML } from 'discourse/helpers/category-link';
|
||||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
|
||||
registerUnbound('category-badge', function(cat, options) {
|
||||
options.link = false;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
|
||||
var get = Em.get,
|
||||
escapeExpression = Handlebars.Utils.escapeExpression;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
|
||||
function daysSinceEpoch(dt) {
|
||||
// 1000 * 60 * 60 * 24 = days since epoch
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { cook } from 'discourse/lib/text';
|
||||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
|
||||
registerUnbound('cook-text', cook);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { registerHelper } from 'discourse/lib/helpers';
|
||||
import { registerHelper } from 'discourse-common/lib/helpers';
|
||||
import PreloadStore from 'preload-store';
|
||||
|
||||
const _customizations = {};
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
|
||||
export default htmlHelper(str => Ember.isEmpty(str) ? '—' : str);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
import renderTag from 'discourse/lib/render-tag';
|
||||
|
||||
export default registerUnbound('discourse-tag', function(name, params) {
|
||||
|
|
20
app/assets/javascripts/discourse/helpers/fa-icon-node.js.es6
Normal file
20
app/assets/javascripts/discourse/helpers/fa-icon-node.js.es6
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { h } from 'virtual-dom';
|
||||
import { iconClasses } from 'discourse-common/helpers/fa-icon';
|
||||
|
||||
export function iconNode(icon, params) {
|
||||
params = params || {};
|
||||
|
||||
const properties = {
|
||||
className: iconClasses(icon, params),
|
||||
attributes: { "aria-hidden": true }
|
||||
};
|
||||
|
||||
if (params.title) { properties.attributes.title = params.title; }
|
||||
|
||||
if (params.label) {
|
||||
return h('i', properties, h('span.sr-only', I18n.t(params.label)));
|
||||
} else {
|
||||
return h('i', properties);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { autoUpdatingRelativeAge } from 'discourse/lib/formatter';
|
||||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
|
||||
registerUnbound('format-age', function(dt) {
|
||||
dt = new Date(dt);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
import { autoUpdatingRelativeAge } from 'discourse/lib/formatter';
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
|
||||
export default htmlHelper(function(str) {
|
||||
if (Ember.isEmpty(str)) { return ""; }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
|
||||
function renderSpinner(cssClass) {
|
||||
var html = "<div class='spinner";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
|
||||
registerUnbound('max-usernames', function(usernames, params) {
|
||||
var maxLength = parseInt(params.max) || 3;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
|
||||
const TITLE_SUBS = {
|
||||
all: 'all_time',
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
The list of disabled plugins is returned via the `Site` singleton.
|
||||
|
||||
**/
|
||||
import { registerHelper } from 'discourse/lib/helpers';
|
||||
import { registerHelper } from 'discourse-common/lib/helpers';
|
||||
|
||||
let _connectorCache, _rawCache;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
|
||||
// see: https://github.com/emberjs/ember.js/issues/12634
|
||||
var missingViews = {};
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
import { emojiUnescape } from 'discourse/lib/text';
|
||||
|
||||
registerUnbound('i18n', (key, params) => I18n.t(key, params));
|
||||
registerUnbound('replace-emoji', text => new Handlebars.SafeString(emojiUnescape(text)));
|
|
@ -1,4 +1,4 @@
|
|||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
|
||||
registerUnbound('shorten-url', function(url) {
|
||||
var matches = url.match(/\//g);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
|
||||
registerUnbound('topic-link', function(topic) {
|
||||
var title = topic.get('fancyTitle');
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { registerUnbound } from 'discourse/lib/helpers';
|
||||
import { registerUnbound } from 'discourse-common/lib/helpers';
|
||||
import { avatarImg } from 'discourse/lib/utilities';
|
||||
|
||||
function renderAvatar(user, options) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { htmlHelper } from 'discourse/lib/helpers';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
import { htmlHelper } from 'discourse-common/lib/helpers';
|
||||
import { escapeExpression } from 'discourse/lib/utilities';
|
||||
|
||||
export default htmlHelper((user, args) => {
|
||||
|
|
|
@ -12,13 +12,13 @@ export default {
|
|||
Discourse.set("assetVersion", version);
|
||||
|
||||
if (!timeoutIsSet && Discourse.get("requiresRefresh")) {
|
||||
// since we can do this transparently for people browsing the forum
|
||||
// hold back the message a couple of hours
|
||||
// Since we can do this transparently for people browsing the forum
|
||||
// hold back the message 24 hours.
|
||||
setTimeout(function () {
|
||||
bootbox.confirm(I18n.lookup("assets_changed_confirm"), function (result) {
|
||||
if (result) { document.location.reload(); }
|
||||
});
|
||||
}, 1000 * 60 * 120);
|
||||
}, 1000 * 60 * 24 * 60);
|
||||
timeoutIsSet = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -237,15 +237,19 @@ export default function(options) {
|
|||
|
||||
me.parent().append(div);
|
||||
|
||||
if(!isInput){
|
||||
if (!isInput) {
|
||||
vOffset = div.height();
|
||||
}
|
||||
|
||||
if (Discourse.Site.currentProp('mobileView') && !isInput) {
|
||||
div.css('width', 'auto');
|
||||
if ((window.innerHeight - me.outerHeight() - $("header.d-header").innerHeight()) < vOffset) {
|
||||
vOffset = -23;
|
||||
}
|
||||
|
||||
if ((me.height() / 2) >= pos.top) { vOffset = -23; }
|
||||
if ((me.width() / 2) <= pos.left) { hOffset = -div.width(); }
|
||||
if (Discourse.Site.currentProp('mobileView')) {
|
||||
div.css('width', 'auto');
|
||||
|
||||
if ((me.height() / 2) >= pos.top) { vOffset = -23; }
|
||||
if ((me.width() / 2) <= pos.left) { hOffset = -div.width(); }
|
||||
}
|
||||
}
|
||||
|
||||
var mePos = me.position();
|
||||
|
|
15
app/assets/javascripts/discourse/lib/create-view.js.es6
Normal file
15
app/assets/javascripts/discourse/lib/create-view.js.es6
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { on } from 'ember-addons/ember-computed-decorators';
|
||||
|
||||
export function createViewWithBodyClass(body_class) {
|
||||
return Ember.View.extend({
|
||||
@on("didInsertElement")
|
||||
addBodyClass() {
|
||||
$('body').addClass(body_class);
|
||||
},
|
||||
|
||||
@on("willDestroyElement")
|
||||
removeBodyClass() {
|
||||
$('body').removeClass(body_class);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -29,6 +29,18 @@ const Mobile = {
|
|||
// localStorage may be disabled, just skip this
|
||||
// you get security errors if it is disabled
|
||||
}
|
||||
|
||||
// Sam: I tried this to disable zooming on iOS 10 but it is not consistent
|
||||
// you can still sometimes trigger zoom and be stuck in a horrible state
|
||||
//
|
||||
// let iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform);
|
||||
// if (iOS) {
|
||||
// document.documentElement.addEventListener('touchstart', function (event) {
|
||||
// if (event.touches.length > 1) {
|
||||
// event.preventDefault();
|
||||
// }
|
||||
// }, false);
|
||||
// }
|
||||
},
|
||||
|
||||
toggleMobileView() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { iconNode } from 'discourse/helpers/fa-icon';
|
||||
import { iconNode } from 'discourse/helpers/fa-icon-node';
|
||||
import { addDecorator } from 'discourse/widgets/post-cooked';
|
||||
import ComposerEditor from 'discourse/components/composer-editor';
|
||||
import { addButton } from 'discourse/widgets/post-menu';
|
||||
|
|
|
@ -28,10 +28,10 @@ export function transformBasicPost(post) {
|
|||
isDeleted: post.deleted_at || post.user_deleted,
|
||||
deletedByAvatarTemplate: null,
|
||||
deletedByUsername: null,
|
||||
primaryGroupName: post.primary_group_name,
|
||||
primaryGroupFlairUrl: post.primary_group_flair_url,
|
||||
primaryGroupFlairBgColor: post.primary_group_flair_bg_color,
|
||||
primaryGroupFlairColor: post.primary_group_flair_color,
|
||||
primary_group_name: post.primary_group_name,
|
||||
primary_group_flair_url: post.primary_group_flair_url,
|
||||
primary_group_flair_bg_color: post.primary_group_flair_bg_color,
|
||||
primary_group_flair_color: post.primary_group_flair_color,
|
||||
wiki: post.wiki,
|
||||
firstPost: post.post_number === 1,
|
||||
post_number: post.post_number,
|
||||
|
|
|
@ -121,7 +121,7 @@ const DiscourseURL = Ember.Object.extend({
|
|||
}
|
||||
|
||||
// Scroll to the same page, different anchor
|
||||
const m = /#(.+)$/.exec(path);
|
||||
const m = /^#(.+)$/.exec(path);
|
||||
if (m) {
|
||||
jumpToElement(m[1]);
|
||||
return this.replaceState(path);
|
||||
|
|
|
@ -111,7 +111,7 @@ export function selectedText() {
|
|||
const $div = $(div);
|
||||
|
||||
// Find all emojis and replace with its title attribute.
|
||||
$div.find('img.emoji').replaceWith(() => this.title);
|
||||
$div.find('img.emoji').replaceWith(function() { return this.title; });
|
||||
$('.clicks', $div).remove();
|
||||
const text = div.textContent || div.innerText || "";
|
||||
|
||||
|
|
|
@ -34,7 +34,9 @@ export function findAll(siteSettings, capabilities, isMobileDevice) {
|
|||
params.frameWidth = 850;
|
||||
params.frameHeight = 500;
|
||||
} else if (name === "facebook") {
|
||||
params.frameHeight = 450;
|
||||
params.frameWidth= 580;
|
||||
params.frameHeight = 400;
|
||||
params.displayPopup = true;
|
||||
}
|
||||
|
||||
params.siteSettings = siteSettings;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { mapRoutes } from 'discourse/router';
|
||||
import { mapRoutes } from 'discourse/mapping-router';
|
||||
|
||||
export default {
|
||||
name: "map-routes",
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
expandExcerpts=expandExcerpts
|
||||
bulkSelectEnabled=bulkSelectEnabled
|
||||
canBulkSelect=canBulkSelect
|
||||
selected=selected}}
|
||||
selected=selected
|
||||
skipHeader=skipHeader}}
|
||||
{{else}}
|
||||
{{#unless loadingMore}}
|
||||
<div class='alert alert-info'>
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
<td class="category" style={{border-color c.color}}>
|
||||
<div>
|
||||
{{category-title-link category=c}}
|
||||
{{#if c.logo_url}}
|
||||
{{category-logo-link category=c}}
|
||||
{{/if}}
|
||||
<div class="category-description">
|
||||
{{{c.description_excerpt}}}
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<a href={{category.url}}>
|
||||
{{#if category.read_restricted}}
|
||||
{{fa-icon 'lock'}}
|
||||
{{/if}}
|
||||
|
||||
<span class="category-name">{{categoryName}}</span>
|
||||
|
||||
{{#if category.logo_url}}
|
||||
<div>{{cdn-img src=category.logo_url class="category-logo"}}</div>
|
||||
{{/if}}
|
||||
</a>
|
|
@ -1,7 +1,12 @@
|
|||
{{#if visible}}
|
||||
<div class="card-content">
|
||||
|
||||
<a href={{user.path}} {{action "showUser"}} class="card-huge-avatar">{{bound-avatar avatar "huge"}}</a>
|
||||
<div class="user-card-avatar">
|
||||
<a href={{user.path}} {{action "showUser"}} class="card-huge-avatar">{{bound-avatar avatar "huge"}}</a>
|
||||
{{#if user.primary_group_name}}
|
||||
{{mount-widget widget="avatar-flair" args=user}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="names">
|
||||
<span>
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
canBulkSelect=canBulkSelect
|
||||
bulkSelectEnabled=bulkSelectEnabled
|
||||
selected=selected
|
||||
postsAction="showTopicEntrance"}}
|
||||
postsAction="showTopicEntrance"
|
||||
skipHeader=true}}
|
||||
|
||||
{{conditional-loading-spinner condition=model.loadingMore}}
|
||||
{{/load-more}}
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
{{#if model.title}}
|
||||
<h3>{{model.title}}</h3>
|
||||
{{/if}}
|
||||
{{plugin-outlet "user-post-names"}}
|
||||
<h3>
|
||||
{{#if model.location}}{{fa-icon "map-marker"}} {{model.location}}{{/if}}
|
||||
{{#if model.website_name}}
|
||||
|
|
3
app/assets/javascripts/discourse/views/about.js.es6
Normal file
3
app/assets/javascripts/discourse/views/about.js.es6
Normal file
|
@ -0,0 +1,3 @@
|
|||
import { createViewWithBodyClass } from 'discourse/lib/create-view';
|
||||
|
||||
export default createViewWithBodyClass('about-page');
|
|
@ -1,3 +1,4 @@
|
|||
import ScrollTop from 'discourse/mixins/scroll-top';
|
||||
import { createViewWithBodyClass } from 'discourse/lib/create-view';
|
||||
|
||||
export default Ember.View.extend(ScrollTop);
|
||||
export default createViewWithBodyClass('badges-page').extend(ScrollTop);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import ButtonView from 'discourse/views/button';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
|
||||
export default ButtonView.extend({
|
||||
classNames: ['bookmark'],
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import ButtonView from 'discourse/views/button';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
|
||||
export default ButtonView.extend({
|
||||
classNames: ['flag-topic'],
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
export default Ember.View.extend();
|
||||
import { createViewWithBodyClass } from 'discourse/lib/create-view';
|
||||
|
||||
export default createViewWithBodyClass('search-page').extend({
|
||||
classNames: ['search-container']
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import ButtonView from 'discourse/views/button';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
|
||||
export default ButtonView.extend({
|
||||
classNames: ['invite-topic'],
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
export default Ember.View.extend({
|
||||
import { createViewWithBodyClass } from 'discourse/lib/create-view';
|
||||
|
||||
export default createViewWithBodyClass('user-preferences-page').extend({
|
||||
templateName: 'user/preferences',
|
||||
classNames: ['user-preferences']
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import ButtonView from 'discourse/views/button';
|
||||
import { iconHTML } from 'discourse/helpers/fa-icon';
|
||||
import { iconHTML } from 'discourse-common/helpers/fa-icon';
|
||||
|
||||
export default ButtonView.extend({
|
||||
classNames: ['share'],
|
||||
|
|
3
app/assets/javascripts/discourse/views/tags.js.es6
Normal file
3
app/assets/javascripts/discourse/views/tags.js.es6
Normal file
|
@ -0,0 +1,3 @@
|
|||
import { createViewWithBodyClass } from 'discourse/lib/create-view';
|
||||
|
||||
export default createViewWithBodyClass('tags-page');
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue