mirror of
https://github.com/discourse/discourse.git
synced 2025-03-29 14:55:52 +08:00
fix my git foo
This commit is contained in:
parent
12919f72fa
commit
9b9bd9c0a1
@ -1,11 +1,39 @@
|
|||||||
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
import ModalFunctionality from 'discourse/mixins/modal-functionality';
|
||||||
|
|
||||||
|
const _buttons = [];
|
||||||
|
|
||||||
|
function addBulkButton(action, key) {
|
||||||
|
_buttons.push({ action: action, label: "topics.bulk." + key });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default buttons
|
||||||
|
addBulkButton('showChangeCategory', 'change_category');
|
||||||
|
addBulkButton('deleteTopics', 'delete');
|
||||||
|
addBulkButton('closeTopics', 'close_topics');
|
||||||
|
addBulkButton('archiveTopics', 'archive_topics');
|
||||||
|
addBulkButton('showNotificationLevel', 'notification_level');
|
||||||
|
addBulkButton('resetRead', 'reset_read');
|
||||||
|
|
||||||
// Modal for performing bulk actions on topics
|
// Modal for performing bulk actions on topics
|
||||||
export default Ember.ArrayController.extend(ModalFunctionality, {
|
export default Ember.ArrayController.extend(ModalFunctionality, {
|
||||||
needs: ['discovery/topics'],
|
needs: ['discovery/topics'],
|
||||||
|
buttonRows: null,
|
||||||
|
|
||||||
onShow: function() {
|
onShow: function() {
|
||||||
this.set('controllers.modal.modalClass', 'topic-bulk-actions-modal small');
|
this.set('controllers.modal.modalClass', 'topic-bulk-actions-modal small');
|
||||||
|
|
||||||
|
const buttonRows = [];
|
||||||
|
let row = [];
|
||||||
|
_buttons.forEach(function(b) {
|
||||||
|
row.push(b);
|
||||||
|
if (row.length === 4) {
|
||||||
|
buttonRows.push(row);
|
||||||
|
row = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (row.length) { buttonRows.push(row); }
|
||||||
|
|
||||||
|
this.set('buttonRows', buttonRows);
|
||||||
},
|
},
|
||||||
|
|
||||||
perform: function(operation) {
|
perform: function(operation) {
|
||||||
@ -89,3 +117,5 @@ export default Ember.ArrayController.extend(ModalFunctionality, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export { addBulkButton };
|
||||||
|
@ -10,7 +10,7 @@ var acceptableCodeClasses =
|
|||||||
"perl", "php", "profile", "python", "r", "rib", "rsl", "ruby", "rust", "scala", "smalltalk", "sql",
|
"perl", "php", "profile", "python", "r", "rib", "rsl", "ruby", "rust", "scala", "smalltalk", "sql",
|
||||||
"tex", "text", "vala", "vbscript", "vhdl"];
|
"tex", "text", "vala", "vbscript", "vhdl"];
|
||||||
|
|
||||||
var textCodeClasses = ["text", "pre", "plain"];
|
var textCodeClasses = ["text", "pre"];
|
||||||
|
|
||||||
function flattenBlocks(blocks) {
|
function flattenBlocks(blocks) {
|
||||||
var result = "";
|
var result = "";
|
||||||
@ -39,17 +39,6 @@ Discourse.Dialect.replaceBlock({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Discourse.Dialect.replaceBlock({
|
|
||||||
start: /(<pre[^\>]*\>)([\s\S]*)/igm,
|
|
||||||
stop: /<\/pre>/igm,
|
|
||||||
rawContents: true,
|
|
||||||
skipIfTradtionalLinebreaks: true,
|
|
||||||
|
|
||||||
emitter: function(blockContents) {
|
|
||||||
return ['p', ['pre', flattenBlocks(blockContents)]];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ensure that content in a code block is fully escaped. This way it's not white listed
|
// Ensure that content in a code block is fully escaped. This way it's not white listed
|
||||||
// and we can use HTML and Javascript examples.
|
// and we can use HTML and Javascript examples.
|
||||||
Discourse.Dialect.on('parseNode', function (event) {
|
Discourse.Dialect.on('parseNode', function (event) {
|
||||||
@ -62,6 +51,7 @@ Discourse.Dialect.on('parseNode', function (event) {
|
|||||||
|
|
||||||
if (path && path[path.length-1] && path[path.length-1][0] && path[path.length-1][0] === "pre") {
|
if (path && path[path.length-1] && path[path.length-1][0] && path[path.length-1][0] === "pre") {
|
||||||
regexp = / +$/g;
|
regexp = / +$/g;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
regexp = /^ +| +$/g;
|
regexp = /^ +| +$/g;
|
||||||
}
|
}
|
||||||
@ -69,6 +59,17 @@ Discourse.Dialect.on('parseNode', function (event) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Discourse.Dialect.replaceBlock({
|
||||||
|
start: /(<pre[^\>]*\>)([\s\S]*)/igm,
|
||||||
|
stop: /<\/pre>/igm,
|
||||||
|
rawContents: true,
|
||||||
|
skipIfTradtionalLinebreaks: true,
|
||||||
|
|
||||||
|
emitter: function(blockContents) {
|
||||||
|
return ['p', ['pre', flattenBlocks(blockContents)]];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Whitelist the language classes
|
// Whitelist the language classes
|
||||||
var regexpSource = "^lang-(" + acceptableCodeClasses.join('|') + ")$";
|
var regexpSource = "^lang-(" + acceptableCodeClasses.join('|') + ")$";
|
||||||
Discourse.Markdown.whiteListTag('code', 'class', new RegExp(regexpSource, "i"));
|
Discourse.Markdown.whiteListTag('code', 'class', new RegExp(regexpSource, "i"));
|
||||||
|
@ -12,8 +12,7 @@ var parser = window.BetterMarkdown,
|
|||||||
initialized = false,
|
initialized = false,
|
||||||
emitters = [],
|
emitters = [],
|
||||||
hoisted,
|
hoisted,
|
||||||
preProcessors = [],
|
preProcessors = [];
|
||||||
escape = Handlebars.Utils.escapeExpression;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Initialize our dialects for processing.
|
Initialize our dialects for processing.
|
||||||
@ -163,10 +162,6 @@ function hoister(t, target, replacement) {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
function outdent(t) {
|
|
||||||
return t.replace(/^[ ]{4}/gm, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
An object used for rendering our dialects.
|
An object used for rendering our dialects.
|
||||||
@ -188,46 +183,14 @@ Discourse.Dialect = {
|
|||||||
cook: function(text, opts) {
|
cook: function(text, opts) {
|
||||||
if (!initialized) { initializeDialects(); }
|
if (!initialized) { initializeDialects(); }
|
||||||
|
|
||||||
dialect.options = opts;
|
|
||||||
|
|
||||||
// Helps us hoist out HTML
|
// Helps us hoist out HTML
|
||||||
hoisted = {};
|
hoisted = {};
|
||||||
|
|
||||||
// pre-hoist all code-blocks
|
|
||||||
|
|
||||||
// <pre>...</pre> blocks
|
|
||||||
text = text.replace(/(\n*)<pre>([\s\S]*?)<\/pre>/ig, function(_, before, m) {
|
|
||||||
var hash = md5(m);
|
|
||||||
hoisted[hash] = escape(m.trim());
|
|
||||||
return before + "<pre>" + hash + "</pre>";
|
|
||||||
});
|
|
||||||
|
|
||||||
// fenced blocks
|
|
||||||
text = text.replace(/(\n*)```([a-z0-9\-]*)\n([\s\S]*?)\n```/g, function(_, before, language, m) {
|
|
||||||
var hash = md5(m);
|
|
||||||
hoisted[hash] = escape(m.trim());
|
|
||||||
return before + "```" + language + "\n" + hash + "\n```";
|
|
||||||
});
|
|
||||||
|
|
||||||
// inline
|
|
||||||
text = text.replace(/(^|[^`])`([^`]*?)`([^`]|$)/g, function(_, before, m, after) {
|
|
||||||
var hash = md5(m);
|
|
||||||
hoisted[hash] = escape(m);
|
|
||||||
return before + "`" + hash + "`" + after;
|
|
||||||
});
|
|
||||||
|
|
||||||
// markdown blocks
|
|
||||||
text = text.replace(/(\n*)((?:(?:[ ]{4}).*\n+)+)/g, function(_, before, m) {
|
|
||||||
var hash = md5(m);
|
|
||||||
hoisted[hash] = escape(outdent(m).trim());
|
|
||||||
return before + " " + hash + "\n";
|
|
||||||
});
|
|
||||||
|
|
||||||
// pre-processors
|
|
||||||
preProcessors.forEach(function(p) {
|
preProcessors.forEach(function(p) {
|
||||||
text = p(text, hoister);
|
text = p(text, hoister);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dialect.options = opts;
|
||||||
var tree = parser.toHTMLTree(text, 'Discourse'),
|
var tree = parser.toHTMLTree(text, 'Discourse'),
|
||||||
result = parser.renderJsonML(parseTree(tree));
|
result = parser.renderJsonML(parseTree(tree));
|
||||||
|
|
||||||
@ -240,11 +203,12 @@ Discourse.Dialect = {
|
|||||||
// If we hoisted out anything, put it back
|
// If we hoisted out anything, put it back
|
||||||
var keys = Object.keys(hoisted);
|
var keys = Object.keys(hoisted);
|
||||||
if (keys.length) {
|
if (keys.length) {
|
||||||
keys.forEach(function(key) {
|
keys.forEach(function(k) {
|
||||||
result = result.replace(new RegExp(key, "g"), hoisted[key]);
|
result = result.replace(new RegExp(k,"g"), hoisted[k]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hoisted = {};
|
||||||
return result.trim();
|
return result.trim();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
<p>
|
{{#each row in buttonRows}}
|
||||||
<button class='btn' {{action "showChangeCategory"}}>{{i18n 'topics.bulk.change_category'}}</button>
|
<p>
|
||||||
<button class='btn' {{action "deleteTopics"}}>{{i18n 'topics.bulk.delete'}}</button>
|
{{#each button in row}}
|
||||||
<button class='btn' {{action "closeTopics"}}>{{i18n 'topics.bulk.close_topics'}}</button>
|
{{d-button action=button.action label=button.label}}
|
||||||
<button class='btn' {{action "archiveTopics"}}>{{i18n 'topics.bulk.archive_topics'}}</button>
|
{{/each}}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
{{/each}}
|
||||||
<button class='btn' {{action "showNotificationLevel"}}>{{i18n 'topics.bulk.notification_level'}}</button>
|
|
||||||
<button class='btn' {{action "resetRead"}}>{{i18n 'topics.bulk.reset_read'}}</button>
|
|
||||||
</p>
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
<p>Choose the new category for the topics:</p>
|
<p>{{i18n "topics.bulk.choose_new_category"}}</p>
|
||||||
|
|
||||||
<p>{{category-chooser value=newCategoryId}}</p>
|
<p>{{category-chooser value=newCategoryId}}</p>
|
||||||
|
|
||||||
{{#if loading}}
|
{{#loading-spinner condition=loading}}
|
||||||
<div class='loading'>{{i18n 'loading'}}</div>
|
{{d-button action="changeCategory" label="topics.bulk.change_category"}}
|
||||||
{{else}}
|
{{/loading-spinner}}
|
||||||
<button class='btn' {{action "changeCategory"}}>Change Category</button>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
export default Discourse.ModalBodyView.extend({
|
||||||
|
templateName: 'modal/topic-bulk-actions',
|
||||||
|
title: I18n.t('topics.bulk.actions')
|
||||||
|
});
|
@ -1,12 +0,0 @@
|
|||||||
/**
|
|
||||||
Handles the view for the topic bulk actions modal
|
|
||||||
|
|
||||||
@class TopicBulkActionsView
|
|
||||||
@extends Discourse.ModalBodyView
|
|
||||||
@namespace Discourse
|
|
||||||
@module Discourse
|
|
||||||
**/
|
|
||||||
Discourse.TopicBulkActionsView = Discourse.ModalBodyView.extend({
|
|
||||||
templateName: 'modal/topic_bulk_actions',
|
|
||||||
title: I18n.t('topics.bulk.actions')
|
|
||||||
});
|
|
@ -814,6 +814,7 @@ en:
|
|||||||
close_topics: "Close Topics"
|
close_topics: "Close Topics"
|
||||||
archive_topics: "Archive Topics"
|
archive_topics: "Archive Topics"
|
||||||
notification_level: "Change Notification Level"
|
notification_level: "Change Notification Level"
|
||||||
|
choose_new_category: "Choose the new category for the topics:"
|
||||||
selected:
|
selected:
|
||||||
one: "You have selected <b>1</b> topic."
|
one: "You have selected <b>1</b> topic."
|
||||||
other: "You have selected <b>{{count}}</b> topics."
|
other: "You have selected <b>{{count}}</b> topics."
|
||||||
|
@ -8,7 +8,12 @@ class TopicsBulkAction
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.operations
|
def self.operations
|
||||||
%w(change_category close archive change_notification_level reset_read dismiss_posts delete)
|
@operations ||= %w(change_category close archive change_notification_level reset_read dismiss_posts delete)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.register_operation(name, &block)
|
||||||
|
operations << name
|
||||||
|
define_method(name, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform!
|
def perform!
|
||||||
|
@ -345,12 +345,12 @@ test("Code Blocks", function() {
|
|||||||
"<p><pre><code class=\"lang-json\">{hello: 'world'}</code></pre></p>\n\n<p>trailing</p>",
|
"<p><pre><code class=\"lang-json\">{hello: 'world'}</code></pre></p>\n\n<p>trailing</p>",
|
||||||
"It does not truncate text after a code block.");
|
"It does not truncate text after a code block.");
|
||||||
|
|
||||||
cooked("```json\nline 1\n\nline 2\n\n\nline 3\n```",
|
cooked("```json\nline 1\n\nline 2\n\n\nline3\n```",
|
||||||
"<p><pre><code class=\"lang-json\">line 1\n\nline 2\n\n\nline 3</code></pre></p>",
|
"<p><pre><code class=\"lang-json\">line 1\n\nline 2\n\n\nline3</code></pre></p>",
|
||||||
"it maintains new lines inside a code block.");
|
"it maintains new lines inside a code block.");
|
||||||
|
|
||||||
cooked("hello\nworld\n```json\nline 1\n\nline 2\n\n\nline 3\n```",
|
cooked("hello\nworld\n```json\nline 1\n\nline 2\n\n\nline3\n```",
|
||||||
"<p>hello<br/>world<br/></p>\n\n<p><pre><code class=\"lang-json\">line 1\n\nline 2\n\n\nline 3</code></pre></p>",
|
"<p>hello<br/>world<br/></p>\n\n<p><pre><code class=\"lang-json\">line 1\n\nline 2\n\n\nline3</code></pre></p>",
|
||||||
"it maintains new lines inside a code block with leading content.");
|
"it maintains new lines inside a code block with leading content.");
|
||||||
|
|
||||||
cooked("```ruby\n<header>hello</header>\n```",
|
cooked("```ruby\n<header>hello</header>\n```",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user