mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-04-05 21:01:35 +08:00
Feature/tinymce contentlinks plugin (#8679)
* Adds the ability to create links based on orchard contents, calculating href during the display process using tokens # Conflicts: # src/Orchard.Web/Modules/TinyMce/Scripts/orchard-tinymce.js * Adds Contentmanager.Get Tokens Adds Content Links plugin to TinyMCE * Adds settings for TextField and BodyPart in order to specify which content types or part to show in the list * Settings for Html editors built on BodyParts, TextFields, LayoutParts * Adds minified version of the plugin.js * Tests if dependencies are enabled before activating the content links settings * new .png for TinyMce * Renamed the token as suggested during last meeting
This commit is contained in:
parent
12e9f06689
commit
05e3c196aa
@ -7,7 +7,7 @@
|
|||||||
@Html.ValidationMessageFor(m => m.Text)
|
@Html.ValidationMessageFor(m => m.Text)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@Display.Body_Editor(Text: Model.Text, EditorFlavor: Model.Settings.Flavor, Required: Model.Settings.Required, ContentItem: Model.ContentItem)
|
@Display.Body_Editor(Text: Model.Text, EditorFlavor: Model.Settings.Flavor, Required: Model.Settings.Required, ContentItem: Model.ContentItem, Field: Model.Field)
|
||||||
}
|
}
|
||||||
@if (HasText(Model.Settings.Hint)) {
|
@if (HasText(Model.Settings.Hint)) {
|
||||||
<span class="hint">@Model.Settings.Hint</span>
|
<span class="hint">@Model.Settings.Hint</span>
|
||||||
|
@ -2,6 +2,6 @@
|
|||||||
@using Orchard.Core.Common.ViewModels;
|
@using Orchard.Core.Common.ViewModels;
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label>@T("Body")</label>
|
<label>@T("Body")</label>
|
||||||
@Display.Body_Editor(Text: Model.Text, EditorFlavor: Model.EditorFlavor, Required: false, AutoFocus: false, ContentItem: Model.BodyPart.ContentItem)
|
@Display.Body_Editor(Text: Model.Text, EditorFlavor: Model.EditorFlavor, Required: false, AutoFocus: false, ContentItem: Model.BodyPart.ContentItem, Part: Model.BodyPart)
|
||||||
@Html.ValidationMessageFor(m => m.Text)
|
@Html.ValidationMessageFor(m => m.Text)
|
||||||
</fieldset>
|
</fieldset>
|
@ -15,7 +15,8 @@ namespace Orchard.Layouts.Drivers {
|
|||||||
|
|
||||||
protected override EditorResult OnBuildEditor(Html element, ElementEditorContext context) {
|
protected override EditorResult OnBuildEditor(Html element, ElementEditorContext context) {
|
||||||
var viewModel = new HtmlEditorViewModel {
|
var viewModel = new HtmlEditorViewModel {
|
||||||
Text = element.Content
|
Text = element.Content,
|
||||||
|
Part = ((dynamic)context.Content.ContentItem).LayoutPart
|
||||||
};
|
};
|
||||||
var editor = context.ShapeFactory.EditorTemplate(TemplateName: "Elements.Html", Model: viewModel);
|
var editor = context.ShapeFactory.EditorTemplate(TemplateName: "Elements.Html", Model: viewModel);
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
namespace Orchard.Layouts.ViewModels {
|
using Orchard.ContentManagement;
|
||||||
|
|
||||||
|
namespace Orchard.Layouts.ViewModels {
|
||||||
public class HtmlEditorViewModel {
|
public class HtmlEditorViewModel {
|
||||||
public string Text { get; set; }
|
public string Text { get; set; }
|
||||||
|
public ContentPart Part { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
@model Orchard.Layouts.ViewModels.HtmlEditorViewModel
|
@model Orchard.Layouts.ViewModels.HtmlEditorViewModel
|
||||||
<fieldset>
|
<fieldset>
|
||||||
@Html.LabelFor(m => m.Text, T("HTML"))
|
@Html.LabelFor(m => m.Text, T("HTML"))
|
||||||
@Display.Body_Editor(EditorFlavor: "html", Text: Model.Text, AutoFocus: true)
|
@Display.Body_Editor(EditorFlavor: "html", Text: Model.Text, AutoFocus: true, Part: Model.Part)
|
||||||
</fieldset>
|
</fieldset>
|
@ -26,6 +26,9 @@ namespace Orchard.Tokens.Providers {
|
|||||||
public Localizer T { get; set; }
|
public Localizer T { get; set; }
|
||||||
|
|
||||||
public void Describe(DescribeContext context) {
|
public void Describe(DescribeContext context) {
|
||||||
|
context.For("ContentItem", T("Content Items"), T("The context to access specific content items."))
|
||||||
|
.Token("Id:*", T("Content Item by Id"), T("The content item with the specified id."));
|
||||||
|
|
||||||
context.For("Content", T("Content Items"), T("Content Items"))
|
context.For("Content", T("Content Items"), T("Content Items"))
|
||||||
.Token("Id", T("Content Id"), T("Numeric primary key value of content."))
|
.Token("Id", T("Content Id"), T("Numeric primary key value of content."))
|
||||||
.Token("Author", T("Content Author"), T("Person in charge of the content."), "User")
|
.Token("Author", T("Content Author"), T("Person in charge of the content."), "User")
|
||||||
@ -36,8 +39,7 @@ namespace Orchard.Tokens.Providers {
|
|||||||
.Token("DisplayUrl", T("Display Url"), T("Url to display the content."), "Url")
|
.Token("DisplayUrl", T("Display Url"), T("Url to display the content."), "Url")
|
||||||
.Token("EditUrl", T("Edit Url"), T("Url to edit the content."), "Url")
|
.Token("EditUrl", T("Edit Url"), T("Url to edit the content."), "Url")
|
||||||
.Token("Container", T("Container"), T("The container Content Item."), "Content")
|
.Token("Container", T("Container"), T("The container Content Item."), "Content")
|
||||||
.Token("Body", T("Body"), T("The body text of the content item."), "Text")
|
.Token("Body", T("Body"), T("The body text of the content item."), "Text");
|
||||||
;
|
|
||||||
|
|
||||||
// Token descriptors for fields
|
// Token descriptors for fields
|
||||||
foreach (var typeDefinition in _contentManager.GetContentTypeDefinitions()) {
|
foreach (var typeDefinition in _contentManager.GetContentTypeDefinitions()) {
|
||||||
@ -72,26 +74,57 @@ namespace Orchard.Tokens.Providers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Evaluate(EvaluateContext context) {
|
public void Evaluate(EvaluateContext context) {
|
||||||
|
context.For<IContentManager>("ContentItem", _contentManager)
|
||||||
|
.Token(
|
||||||
|
token => token.StartsWith("Id:", StringComparison.OrdinalIgnoreCase) ? ContentManagerGetToken(token) : "",
|
||||||
|
(token, cm) => {
|
||||||
|
// token is Id:*
|
||||||
|
if (token != "") {
|
||||||
|
var id = token.Substring("Id:".Length);
|
||||||
|
return cm.Get(Convert.ToInt32(id));
|
||||||
|
}
|
||||||
|
else { return null; }
|
||||||
|
})
|
||||||
|
.Chain(
|
||||||
|
token => {
|
||||||
|
var cleanToken = ContentManagerGetToken(token); // is Id:*
|
||||||
|
if (string.IsNullOrWhiteSpace(cleanToken)) return null;
|
||||||
|
int cleanTokenLength = cleanToken.Length;
|
||||||
|
var subTokens = token.Length > cleanTokenLength ? token.Substring(cleanToken.Length + 1) : "";
|
||||||
|
return new Tuple<string, string>(
|
||||||
|
cleanToken, //The specific Token Id:*, it is the key
|
||||||
|
subTokens //The subsequent Tokens (i.e Fields.PartName.FieldName)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
"Content",
|
||||||
|
(token, cm) => {
|
||||||
|
// token is Id:*
|
||||||
|
|
||||||
|
if (token != "") {
|
||||||
|
var id = token.Substring("Id:".Length);
|
||||||
|
return cm.Get(Convert.ToInt32(id));
|
||||||
|
}
|
||||||
|
else { return null; }
|
||||||
|
});
|
||||||
context.For<IContent>("Content")
|
context.For<IContent>("Content")
|
||||||
.Token("Id", content => content != null ? content.Id : 0)
|
.Token("Id", content => content != null ? content.Id : 0)
|
||||||
.Token("Author", AuthorName)
|
.Token("Author", AuthorName)
|
||||||
.Chain("Author", "User", content => content != null ? content.As<ICommonPart>().Owner : null)
|
.Chain("Author", "User", content => content != null ? content.As<ICommonPart>().Owner : null)
|
||||||
.Token("Date", Date)
|
.Token("Date", Date)
|
||||||
.Chain("Date", "Date", Date)
|
.Chain("Date", "Date", Date)
|
||||||
.Token("Identity", content => content != null ? _contentManager.GetItemMetadata(content).Identity.ToString() : String.Empty)
|
.Token("Identity", content => content != null ? _contentManager.GetItemMetadata(content).Identity.ToString() : String.Empty)
|
||||||
.Token("ContentType", content => content != null ? content.ContentItem.TypeDefinition.DisplayName : String.Empty)
|
.Token("ContentType", content => content != null ? content.ContentItem.TypeDefinition.DisplayName : String.Empty)
|
||||||
.Chain("ContentType", "TypeDefinition", content => content != null ? content.ContentItem.TypeDefinition : null)
|
.Chain("ContentType", "TypeDefinition", content => content != null ? content.ContentItem.TypeDefinition : null)
|
||||||
.Token("DisplayText", DisplayText)
|
.Token("DisplayText", DisplayText)
|
||||||
.Chain("DisplayText", "Text", DisplayText)
|
.Chain("DisplayText", "Text", DisplayText)
|
||||||
.Token("DisplayUrl", DisplayUrl)
|
.Token("DisplayUrl", DisplayUrl)
|
||||||
.Chain("DisplayUrl", "Url", DisplayUrl)
|
.Chain("DisplayUrl", "Url", DisplayUrl)
|
||||||
.Token("EditUrl", EditUrl)
|
.Token("EditUrl", EditUrl)
|
||||||
.Chain("EditUrl", "Url", EditUrl)
|
.Chain("EditUrl", "Url", EditUrl)
|
||||||
.Token("Container", content => DisplayText(Container(content)))
|
.Token("Container", content => DisplayText(Container(content)))
|
||||||
.Chain("Container", "Content", Container)
|
.Chain("Container", "Content", Container)
|
||||||
.Token("Body", Body)
|
.Token("Body", Body)
|
||||||
.Chain("Body", "Text", Body)
|
.Chain("Body", "Text", Body);
|
||||||
;
|
|
||||||
|
|
||||||
if (context.Target == "Content") {
|
if (context.Target == "Content") {
|
||||||
var forContent = context.For<IContent>("Content");
|
var forContent = context.For<IContent>("Content");
|
||||||
@ -201,5 +234,36 @@ namespace Orchard.Tokens.Providers {
|
|||||||
|
|
||||||
return bodyPart.Text;
|
return bodyPart.Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//returns Id:* Token
|
||||||
|
private static string ContentManagerGetToken(string token) {
|
||||||
|
string tokenPrefix, result;
|
||||||
|
int chainIndex, tokenLength;
|
||||||
|
|
||||||
|
if (token.IndexOf(":") == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
tokenPrefix = token.Substring(0, token.IndexOf(":"));
|
||||||
|
|
||||||
|
chainIndex = token.IndexOf(".");
|
||||||
|
tokenLength = (tokenPrefix + ":").Length;
|
||||||
|
if (!token.StartsWith((tokenPrefix + ":"), StringComparison.OrdinalIgnoreCase) || chainIndex <= tokenLength) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if (chainIndex == 0) {// "." has not be found
|
||||||
|
result = token.Substring(tokenLength);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = token.Substring(0, chainIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the resulting id if it is a number, otherwise an empty string
|
||||||
|
if (int.TryParse(result.Substring(tokenPrefix.Length + 1), out var contentid)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,6 @@
|
|||||||
var mediaPlugins = "";
|
var mediaPlugins = "";
|
||||||
|
var contentPickerPlugins = "";
|
||||||
|
var contentPickerButtons = "";
|
||||||
|
|
||||||
if (mediaPickerEnabled) {
|
if (mediaPickerEnabled) {
|
||||||
mediaPlugins += " mediapicker";
|
mediaPlugins += " mediapicker";
|
||||||
@ -8,14 +10,19 @@ if (mediaLibraryEnabled) {
|
|||||||
mediaPlugins += " medialibrary";
|
mediaPlugins += " medialibrary";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (contenPickerEnabled && tokensHtmlFilterEnabled) {
|
||||||
|
contentPickerPlugins += " orchardcontentlinks"
|
||||||
|
contentPickerButtons += "orchardlink"
|
||||||
|
}
|
||||||
|
|
||||||
tinyMCE.init({
|
tinyMCE.init({
|
||||||
selector: "textarea.tinymce",
|
selector: "textarea.tinymce",
|
||||||
theme: "modern",
|
theme: "modern",
|
||||||
schema: "html5",
|
schema: "html5",
|
||||||
plugins: [
|
plugins: [
|
||||||
"advlist, anchor, autolink, autoresize, charmap, code, colorpicker, contextmenu, directionality, emoticons, fullscreen, hr, image, insertdatetime, link, lists, media, nonbreaking, pagebreak, paste, preview, print, searchreplace, table, template, textcolor, textpattern, visualblocks, visualchars, wordcount, htmlsnippets" + mediaPlugins
|
"advlist, anchor, autolink, autoresize, charmap, code, colorpicker, contextmenu, directionality, emoticons, fullscreen, hr, image, insertdatetime, link, lists, media, nonbreaking, pagebreak, paste, preview, print, searchreplace, table, template, textcolor, textpattern, visualblocks, visualchars, wordcount, htmlsnippets" + (contentPickerPlugins != "" ? ", " + contentPickerPlugins : "") + (mediaPlugins != "" ? ", " + mediaPlugins : "")
|
||||||
],
|
],
|
||||||
toolbar: "undo redo cut copy paste | bold italic | bullist numlist outdent indent formatselect | alignleft aligncenter alignright alignjustify ltr rtl | " + mediaPlugins + " link unlink charmap | code htmlsnippetsbutton fullscreen",
|
toolbar: "undo redo cut copy paste | bold italic | bullist numlist outdent indent formatselect | alignleft aligncenter alignright alignjustify ltr rtl | " + mediaPlugins + " link " + contentPickerButtons + " unlink charmap | code htmlsnippetsbutton fullscreen",
|
||||||
convert_urls: false,
|
convert_urls: false,
|
||||||
valid_elements: "*[*]",
|
valid_elements: "*[*]",
|
||||||
// Shouldn't be needed due to the valid_elements setting, but TinyMCE would strip script.src without it.
|
// Shouldn't be needed due to the valid_elements setting, but TinyMCE would strip script.src without it.
|
||||||
@ -27,7 +34,7 @@ tinyMCE.init({
|
|||||||
auto_focus: autofocus,
|
auto_focus: autofocus,
|
||||||
directionality: directionality,
|
directionality: directionality,
|
||||||
setup: function (editor) {
|
setup: function (editor) {
|
||||||
$(document).bind("localization.ui.directionalitychanged", function(event, directionality) {
|
$(document).bind("localization.ui.directionalitychanged", function (event, directionality) {
|
||||||
editor.getBody().dir = directionality;
|
editor.getBody().dir = directionality;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
tinymce.PluginManager.add('orchardcontentlinks', function (editor, url) {
|
||||||
|
var contentPickerAction = function () {
|
||||||
|
var data = {};
|
||||||
|
var callbackName = "_contentpicker_" + new Date().getTime();
|
||||||
|
data.callbackName = callbackName;
|
||||||
|
$[callbackName] = function (returnData) {
|
||||||
|
delete $[callbackName];
|
||||||
|
//the code to wrap text with link
|
||||||
|
var textLink = editor.selection.getContent();
|
||||||
|
if (!textLink || textLink == "") {
|
||||||
|
textLink = returnData.displayText;
|
||||||
|
}
|
||||||
|
editor.insertContent("<a href=\"#{ContentItem.Id:" + returnData.id.toString() + ".DisplayUrl}\">" + textLink + "</a>");
|
||||||
|
|
||||||
|
};
|
||||||
|
$[callbackName].data = data;
|
||||||
|
|
||||||
|
// Open content picker window
|
||||||
|
var baseUrl = baseOrchardPath;
|
||||||
|
|
||||||
|
// remove trailing slash if any
|
||||||
|
if (baseUrl.slice(-1) == '/')
|
||||||
|
baseUrl = baseUrl.substr(0, baseUrl.length - 1);
|
||||||
|
var url = baseUrl + "/Admin/Orchard.ContentPicker?";
|
||||||
|
url += "callback=" + callbackName + "&" + (new Date() - 0);
|
||||||
|
if ($("#" + editor.id).data("content-types")) {
|
||||||
|
url += "&types=" + $("#" + editor.id).data("content-types");
|
||||||
|
}
|
||||||
|
var w = window.open(url, "_blank", data.windowFeatures || "width=685,height=700,status=no,toolbar=no,location=no,menubar=no,resizable=no,scrollbars=yes");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a button that opens a window
|
||||||
|
editor.addButton('orchardlink', {
|
||||||
|
image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsSAAALEgHS3X78AAABb0lEQVRIibWW223CQBBFDxEFUAIdJNHsf6CCkApiKgBXAFSAUgFJBdCB4X9HogSX4A6Sjx0rK8cGY5P7sw9Z93h3HvYAk4jbAk/cpgLYqPpz0wODCJDZ9NTSfBVBpk2QKuCk6tdt3EXcN5BGoFrIQ8u3bdIZeAZyIBNxf664LwBVnwPTJkhvgEGKJsiwp/dCxE2i9RFYAlsD9gIcgRHwUtkv4kVngKqf1u2LuHUMvUsMLunfAVevSMQtCUf+UvWHWwEXTyDidoSMGAF7EZfcDWDmCTC3gM6BnYgb9wZYoSSEXlP2l3LsDCiAQzTPgXd+KzMDzqr+2Amg6t+AmXXViUHGBs0MWJv7rQB25yszWpn5xsYjoR0XVYNrGkbmCSGQr4SsyYG8qWLbqjxBAqSq/hP4MNDYQL1UFloBPEbzPeEENxdWEyAl5PiIEOCcjndeVfxNngELM08NdOtfBlgnLWM3qHvC8n7bwbzUWdWnAD+rk38HDdeC5gAAAABJRU5ErkJggg==',
|
||||||
|
tooltip: 'Content link',
|
||||||
|
onclick: contentPickerAction
|
||||||
|
});
|
||||||
|
|
||||||
|
// Adds a menu item to the tools menu
|
||||||
|
editor.addMenuItem('orchardlink ', {
|
||||||
|
text: 'content link',
|
||||||
|
image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsSAAALEgHS3X78AAABb0lEQVRIibWW223CQBBFDxEFUAIdJNHsf6CCkApiKgBXAFSAUgFJBdCB4X9HogSX4A6Sjx0rK8cGY5P7sw9Z93h3HvYAk4jbAk/cpgLYqPpz0wODCJDZ9NTSfBVBpk2QKuCk6tdt3EXcN5BGoFrIQ8u3bdIZeAZyIBNxf664LwBVnwPTJkhvgEGKJsiwp/dCxE2i9RFYAlsD9gIcgRHwUtkv4kVngKqf1u2LuHUMvUsMLunfAVevSMQtCUf+UvWHWwEXTyDidoSMGAF7EZfcDWDmCTC3gM6BnYgb9wZYoSSEXlP2l3LsDCiAQzTPgXd+KzMDzqr+2Amg6t+AmXXViUHGBs0MWJv7rQB25yszWpn5xsYjoR0XVYNrGkbmCSGQr4SsyYG8qWLbqjxBAqSq/hP4MNDYQL1UFloBPEbzPeEENxdWEyAl5PiIEOCcjndeVfxNngELM08NdOtfBlgnLWM3qHvC8n7bwbzUWdWnAD+rk38HDdeC5gAAAABJRU5ErkJggg==',
|
||||||
|
context: 'insert',
|
||||||
|
onclick: contentPickerAction
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
getMetadata: function () {
|
||||||
|
return {
|
||||||
|
name: "Orchard content link plugin"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
1
src/Orchard.Web/Modules/TinyMce/Scripts/plugins/orchardcontentlinks/plugin.min.js
vendored
Normal file
1
src/Orchard.Web/Modules/TinyMce/Scripts/plugins/orchardcontentlinks/plugin.min.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
tinymce.PluginManager.add("orchardcontentlinks", function (A, n) { var t = function () { var n = {}, t = "_contentpicker_" + new Date().getTime(); n.callbackName = t, $[t] = function (n) { delete $[t]; var e = A.selection.getContent(); e && "" != e || (e = n.displayText), A.insertContent('<a href="#{ContentItem.Id:' + n.id.toString() + '.DisplayUrl}">' + e + "</a>") }, $[t].data = n; var e = baseOrchardPath; "/" == e.slice(-1) && (e = e.substr(0, e.length - 1)); var g = e + "/Admin/Orchard.ContentPicker?"; g += "callback=" + t + "&" + (new Date - 0), $("#" + A.id).data("content-types") && (g += "&types=" + $("#" + A.id).data("content-types")), window.open(g, "_blank", n.windowFeatures || "width=685,height=700,status=no,toolbar=no,location=no,menubar=no,resizable=no,scrollbars=yes") }; return A.addButton("orchardlink", { image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsSAAALEgHS3X78AAABb0lEQVRIibWW223CQBBFDxEFUAIdJNHsf6CCkApiKgBXAFSAUgFJBdCB4X9HogSX4A6Sjx0rK8cGY5P7sw9Z93h3HvYAk4jbAk/cpgLYqPpz0wODCJDZ9NTSfBVBpk2QKuCk6tdt3EXcN5BGoFrIQ8u3bdIZeAZyIBNxf664LwBVnwPTJkhvgEGKJsiwp/dCxE2i9RFYAlsD9gIcgRHwUtkv4kVngKqf1u2LuHUMvUsMLunfAVevSMQtCUf+UvWHWwEXTyDidoSMGAF7EZfcDWDmCTC3gM6BnYgb9wZYoSSEXlP2l3LsDCiAQzTPgXd+KzMDzqr+2Amg6t+AmXXViUHGBs0MWJv7rQB25yszWpn5xsYjoR0XVYNrGkbmCSGQr4SsyYG8qWLbqjxBAqSq/hP4MNDYQL1UFloBPEbzPeEENxdWEyAl5PiIEOCcjndeVfxNngELM08NdOtfBlgnLWM3qHvC8n7bwbzUWdWnAD+rk38HDdeC5gAAAABJRU5ErkJggg==", tooltip: "Content link", onclick: t }), A.addMenuItem("orchardlink ", { text: "content link", image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsSAAALEgHS3X78AAABb0lEQVRIibWW223CQBBFDxEFUAIdJNHsf6CCkApiKgBXAFSAUgFJBdCB4X9HogSX4A6Sjx0rK8cGY5P7sw9Z93h3HvYAk4jbAk/cpgLYqPpz0wODCJDZ9NTSfBVBpk2QKuCk6tdt3EXcN5BGoFrIQ8u3bdIZeAZyIBNxf664LwBVnwPTJkhvgEGKJsiwp/dCxE2i9RFYAlsD9gIcgRHwUtkv4kVngKqf1u2LuHUMvUsMLunfAVevSMQtCUf+UvWHWwEXTyDidoSMGAF7EZfcDWDmCTC3gM6BnYgb9wZYoSSEXlP2l3LsDCiAQzTPgXd+KzMDzqr+2Amg6t+AmXXViUHGBs0MWJv7rQB25yszWpn5xsYjoR0XVYNrGkbmCSGQr4SsyYG8qWLbqjxBAqSq/hP4MNDYQL1UFloBPEbzPeEENxdWEyAl5PiIEOCcjndeVfxNngELM08NdOtfBlgnLWM3qHvC8n7bwbzUWdWnAD+rk38HDdeC5gAAAABJRU5ErkJggg==", context: "insert", onclick: t }), { getMetadata: function () { return { name: "Orchard content link plugin" } } } });
|
@ -0,0 +1,5 @@
|
|||||||
|
namespace TinyMce.Settings {
|
||||||
|
public class ContentLinksSettings {
|
||||||
|
public string DisplayedContentTypes { get; set; }
|
||||||
|
}
|
||||||
|
}
|
59
src/Orchard.Web/Modules/TinyMce/Settings/EditorEvents.cs
Normal file
59
src/Orchard.Web/Modules/TinyMce/Settings/EditorEvents.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Orchard.ContentManagement;
|
||||||
|
using Orchard.ContentManagement.MetaData;
|
||||||
|
using Orchard.ContentManagement.MetaData.Builders;
|
||||||
|
using Orchard.ContentManagement.MetaData.Models;
|
||||||
|
using Orchard.ContentManagement.ViewModels;
|
||||||
|
using Orchard.Environment.Descriptor.Models;
|
||||||
|
|
||||||
|
namespace TinyMce.Settings {
|
||||||
|
public class EditorEvents : ContentDefinitionEditorEventsBase {
|
||||||
|
|
||||||
|
private string[] _htmlParts = new string[] { "BodyPart", "LayoutPart" };
|
||||||
|
private string[] _htmlFields = new string[] { "TextField" };
|
||||||
|
private bool _contentLinksDependenciesEnabled = false;
|
||||||
|
|
||||||
|
public EditorEvents(ShellDescriptor shellDescriptor) {
|
||||||
|
var contenPickerEnabled = shellDescriptor.Features.Any(x => x.Name == "Orchard.ContentPicker") ? true : false;
|
||||||
|
var tokensHtmlFilterEnabled = shellDescriptor.Features.Any(x => x.Name == "Orchard.Tokens.HtmlFilter") ? true : false;
|
||||||
|
_contentLinksDependenciesEnabled = contenPickerEnabled && tokensHtmlFilterEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<TemplateViewModel> PartFieldEditor(ContentPartFieldDefinition definition) {
|
||||||
|
if (!_contentLinksDependenciesEnabled || !_htmlFields.Any(x => x.Equals(definition.FieldDefinition.Name, StringComparison.InvariantCultureIgnoreCase)))
|
||||||
|
yield break;
|
||||||
|
var model = definition.Settings.GetModel<ContentLinksSettings>();
|
||||||
|
yield return DefinitionTemplate(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<TemplateViewModel> PartFieldEditorUpdate(ContentPartFieldDefinitionBuilder builder, IUpdateModel updateModel) {
|
||||||
|
if (!_contentLinksDependenciesEnabled || !_htmlFields.Any(x => x.Equals(builder.Name, StringComparison.InvariantCultureIgnoreCase)))
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
var model = new ContentLinksSettings();
|
||||||
|
updateModel.TryUpdateModel(model, "ContentLinksSettings", null, null);
|
||||||
|
builder.WithSetting("ContentLinksSettings.DisplayedContentTypes", model.DisplayedContentTypes);
|
||||||
|
|
||||||
|
yield return DefinitionTemplate(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<TemplateViewModel> TypePartEditor(ContentTypePartDefinition definition) {
|
||||||
|
if (!_contentLinksDependenciesEnabled || !_htmlParts.Any(x => x.Equals(definition.PartDefinition.Name, StringComparison.InvariantCultureIgnoreCase)))
|
||||||
|
yield break;
|
||||||
|
var model = definition.Settings.GetModel<ContentLinksSettings>();
|
||||||
|
yield return DefinitionTemplate(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override IEnumerable<TemplateViewModel> TypePartEditorUpdate(ContentTypePartDefinitionBuilder builder, IUpdateModel updateModel) {
|
||||||
|
if (!_contentLinksDependenciesEnabled || !_htmlParts.Any(x => x.Equals(builder.Name, StringComparison.InvariantCultureIgnoreCase)))
|
||||||
|
yield break;
|
||||||
|
var model = new ContentLinksSettings();
|
||||||
|
updateModel.TryUpdateModel(model, "ContentLinksSettings", null, null);
|
||||||
|
builder.WithSetting("ContentLinksSettings.DisplayedContentTypes", model.DisplayedContentTypes);
|
||||||
|
yield return DefinitionTemplate(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -250,6 +250,8 @@
|
|||||||
<Content Include="Scripts\plugins\nonbreaking\plugin.min.js" />
|
<Content Include="Scripts\plugins\nonbreaking\plugin.min.js" />
|
||||||
<Content Include="Scripts\plugins\noneditable\plugin.js" />
|
<Content Include="Scripts\plugins\noneditable\plugin.js" />
|
||||||
<Content Include="Scripts\plugins\noneditable\plugin.min.js" />
|
<Content Include="Scripts\plugins\noneditable\plugin.min.js" />
|
||||||
|
<Content Include="Scripts\plugins\orchardcontentlinks\plugin.js" />
|
||||||
|
<Content Include="Scripts\plugins\orchardcontentlinks\plugin.min.js" />
|
||||||
<Content Include="Scripts\plugins\pagebreak\plugin.js" />
|
<Content Include="Scripts\plugins\pagebreak\plugin.js" />
|
||||||
<Content Include="Scripts\plugins\pagebreak\plugin.min.js" />
|
<Content Include="Scripts\plugins\pagebreak\plugin.min.js" />
|
||||||
<Content Include="Scripts\plugins\paste\plugin.js" />
|
<Content Include="Scripts\plugins\paste\plugin.js" />
|
||||||
@ -317,6 +319,8 @@
|
|||||||
<Compile Include="ResourceManifest.cs" />
|
<Compile Include="ResourceManifest.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Services\TinyMceShapeDisplayEvent.cs" />
|
<Compile Include="Services\TinyMceShapeDisplayEvent.cs" />
|
||||||
|
<Compile Include="Settings\ContentLinksSettings.cs" />
|
||||||
|
<Compile Include="Settings\EditorEvents.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Styles\orchard-tinymce.css" />
|
<Content Include="Styles\orchard-tinymce.css" />
|
||||||
@ -379,7 +383,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
|
<Content Include="Views\DefinitionTemplates\ContentLinksSettings.cshtml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
@ -3,17 +3,35 @@
|
|||||||
@using Orchard.Environment.Descriptor.Models
|
@using Orchard.Environment.Descriptor.Models
|
||||||
@using Orchard.Localization
|
@using Orchard.Localization
|
||||||
@using Orchard.Mvc.Extensions
|
@using Orchard.Mvc.Extensions
|
||||||
|
@using TinyMce.Settings;
|
||||||
@{
|
@{
|
||||||
var shellDescriptor = WorkContext.Resolve<ShellDescriptor>();
|
var shellDescriptor = WorkContext.Resolve<ShellDescriptor>();
|
||||||
var urlPrefix = WorkContext.Resolve<ShellSettings>().RequestUrlPrefix;
|
var urlPrefix = WorkContext.Resolve<ShellSettings>().RequestUrlPrefix;
|
||||||
if (!string.IsNullOrWhiteSpace(urlPrefix)) {
|
if (!string.IsNullOrWhiteSpace(urlPrefix)) {
|
||||||
urlPrefix += "/";
|
urlPrefix += "/";
|
||||||
}
|
}
|
||||||
|
var contentTypes = "";
|
||||||
|
if (Model.Field != null) {
|
||||||
|
var settings = Model.Field.PartFieldDefinition.Settings.GetModel<ContentLinksSettings>();
|
||||||
|
if (settings != null) {
|
||||||
|
contentTypes = settings.DisplayedContentTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Model.Part != null) {
|
||||||
|
var settings = Model.Part.TypePartDefinition.Settings.GetModel<ContentLinksSettings>();
|
||||||
|
if (settings != null) {
|
||||||
|
contentTypes = settings.DisplayedContentTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var mediaPickerEnabled = @(shellDescriptor.Features.Any(x => x.Name == "Orchard.MediaPicker") ? "true" : "false");
|
var mediaPickerEnabled = @(shellDescriptor.Features.Any(x => x.Name == "Orchard.MediaPicker") ? "true" : "false");
|
||||||
var mediaLibraryEnabled = @(shellDescriptor.Features.Any(x => x.Name == "Orchard.MediaLibrary") ? "true" : "false");
|
var mediaLibraryEnabled = @(shellDescriptor.Features.Any(x => x.Name == "Orchard.MediaLibrary") ? "true" : "false");
|
||||||
|
var contenPickerEnabled= @(shellDescriptor.Features.Any(x => x.Name == "Orchard.ContentPicker") ? "true" : "false");
|
||||||
|
var tokensHtmlFilterEnabled= @(shellDescriptor.Features.Any(x => x.Name == "Orchard.Tokens.HtmlFilter") ? "true" : "false");
|
||||||
var directionality = "@WorkContext.GetTextDirection((IContent)Model.ContentItem)";
|
var directionality = "@WorkContext.GetTextDirection((IContent)Model.ContentItem)";
|
||||||
var language = "@Model.Language";
|
var language = "@Model.Language";
|
||||||
var autofocus = "@(Model.AutoFocus == true ? ViewData.TemplateInfo.GetFullHtmlFieldId("Text") : null)";
|
var autofocus = "@(Model.AutoFocus == true ? ViewData.TemplateInfo.GetFullHtmlFieldId("Text") : null)";
|
||||||
@ -32,5 +50,6 @@
|
|||||||
{ "class", "html tinymce" },
|
{ "class", "html tinymce" },
|
||||||
{ "data-mediapicker-uploadpath", Model.AddMediaPath },
|
{ "data-mediapicker-uploadpath", Model.AddMediaPath },
|
||||||
{ "data-mediapicker-title", T("Insert/Update Media") },
|
{ "data-mediapicker-title", T("Insert/Update Media") },
|
||||||
|
{ "data-content-types", contentTypes },
|
||||||
{ "style", "width:100%" }
|
{ "style", "width:100%" }
|
||||||
})
|
})
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
@model TinyMce.Settings.ContentLinksSettings
|
||||||
|
<fieldset>
|
||||||
|
<div>
|
||||||
|
<label for="@Html.FieldIdFor(m => m.DisplayedContentTypes)">@T("Html editor - Content Types and Parts")</label>
|
||||||
|
@Html.TextBoxFor(m => m.DisplayedContentTypes)
|
||||||
|
<span class="hint">@T("A comma separated value of all the content types or content parts to be linkable contents.")</span>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
Loading…
Reference in New Issue
Block a user