uComponents: MNTP - Resolved various ClientDependency concerns.
Removed the Extension class, as wasn't needed. Included MNTP's CSS/JS as embedded resources. Added icons (for delete & info) to '/umbraco/images' and 'jquery.tooltip' script to 'umbraco_client/ui'
This commit is contained in:
@@ -14,17 +14,16 @@ using umbraco.IO;
|
||||
|
||||
namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The user interface to display to the content editor
|
||||
/// </summary>
|
||||
[ClientDependency( ClientDependencyType.Javascript, "ui/jqueryui.js", "UmbracoClient")]
|
||||
/// <summary>
|
||||
/// The user interface to display to the content editor
|
||||
/// </summary>
|
||||
[ClientDependency(ClientDependencyType.Javascript, "ui/jqueryui.js", "UmbracoClient")]
|
||||
[ClientDependency(ClientDependencyType.Javascript, "ui/jquery.tooltip.min.js", "UmbracoClient")]
|
||||
[ClientDependency(ClientDependencyType.Javascript, "controls/Images/ImageViewer.js", "UmbracoRoot")]
|
||||
public class MNTP_DataEditor : Control, INamingContainer
|
||||
{
|
||||
|
||||
#region Static Constructor
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This adds our filtered tree definition to the TreeDefinitionCollection at runtime
|
||||
/// instead of having to declare it in the database
|
||||
@@ -79,13 +78,13 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MNTP_DataEditor"/> class.
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MNTP_DataEditor"/> class.
|
||||
/// </summary>
|
||||
public MNTP_DataEditor()
|
||||
{
|
||||
this.MediaTypesWithThumbnails = new string[] { "image" };
|
||||
@@ -93,7 +92,7 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
TreeToRender = "content";
|
||||
MaxNodeCount = -1;
|
||||
MinNodeCount = 0;
|
||||
StartNodeId = uQuery.RootNodeId;
|
||||
StartNodeId = uQuery.RootNodeId;
|
||||
ShowToolTips = true;
|
||||
ControlHeight = 200;
|
||||
}
|
||||
@@ -102,35 +101,35 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
/// <summary>
|
||||
/// Used for locking code blocks
|
||||
/// </summary>
|
||||
private static readonly object m_Locker = new object();
|
||||
private static readonly object m_Locker = new object();
|
||||
#endregion
|
||||
|
||||
#region Protected members
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected CustomValidator MinItemsValidator;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected CustomTreeControl TreePickerControl;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected Repeater SelectedValues;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected Repeater SelectedValues;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected HiddenField PickedValue;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected HiddenField PickedValue;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected HtmlGenericControl RightColumn;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected HtmlGenericControl RightColumn;
|
||||
#endregion
|
||||
|
||||
#region public Properties
|
||||
@@ -191,7 +190,7 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
var nodes = value.Descendants("nodeId");
|
||||
SelectedValues.DataSource = nodes;
|
||||
PickedValue.Value = string.Join(",", nodes.Select(x => x.Value).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,11 +239,11 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
/// </summary>
|
||||
public string StartNodeXPathExpression { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [show tool tips].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [show tool tips]; otherwise, <c>false</c>.</value>
|
||||
/// <remarks>Shows/Hides the tooltip info bubble.</remarks>
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [show tool tips].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [show tool tips]; otherwise, <c>false</c>.</value>
|
||||
/// <remarks>Shows/Hides the tooltip info bubble.</remarks>
|
||||
public bool ShowToolTips { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -252,13 +251,13 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
/// </summary>
|
||||
public XPathFilterType XPathFilterMatchType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [show thumbnails for media].
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if [show thumbnails for media]; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
/// <remarks>Whether or not to show thumbnails for media</remarks>
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [show thumbnails for media].
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if [show thumbnails for media]; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
/// <remarks>Whether or not to show thumbnails for media</remarks>
|
||||
public bool ShowThumbnailsForMedia { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -279,10 +278,10 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the control, make sure children are created
|
||||
/// </summary>
|
||||
/// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
|
||||
/// <summary>
|
||||
/// Initialize the control, make sure children are created
|
||||
/// </summary>
|
||||
/// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
|
||||
protected override void OnInit(EventArgs e)
|
||||
{
|
||||
base.OnInit(e);
|
||||
@@ -299,7 +298,8 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
base.OnLoad(e);
|
||||
|
||||
//add the js/css required
|
||||
this.AddAllMNTPClientDependencies();
|
||||
this.RegisterEmbeddedClientResource("umbraco.editorControls.MultiNodeTreePicker.MultiNodePickerStyles.css", umbraco.cms.businesslogic.datatype.ClientDependencyType.Css);
|
||||
this.RegisterEmbeddedClientResource("umbraco.editorControls.MultiNodeTreePicker.MultiNodePickerScripts.js", umbraco.cms.businesslogic.datatype.ClientDependencyType.Javascript);
|
||||
|
||||
//update the tree type (we need to do this each time because i don't think view state works with these controls)
|
||||
switch (TreeToRender)
|
||||
@@ -320,13 +320,13 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
//since it is a post back, bind the data source to the view state values
|
||||
XmlValue = ConvertToXDocument(SelectedIds);
|
||||
}
|
||||
|
||||
|
||||
//bind the repeater if theres a data source, or if there's no datasource but this is a postback (i.e. nodes deleted)
|
||||
if (SelectedValues.DataSource != null || Page.IsPostBack)
|
||||
{
|
||||
SelectedValues.DataBind();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -355,7 +355,7 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
//create the right column
|
||||
RightColumn = new HtmlGenericControl("div") { ID = "RightColumn" };
|
||||
RightColumn.Attributes.Add("class", "right propertypane");
|
||||
|
||||
|
||||
//create the repeater
|
||||
SelectedValues = new Repeater
|
||||
{
|
||||
@@ -384,13 +384,13 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
this.Controls.Add(RightColumn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Ensure the repeater is data bound
|
||||
/// </summary>
|
||||
public override void DataBind()
|
||||
{
|
||||
{
|
||||
base.DataBind();
|
||||
SelectedValues.DataBind();
|
||||
}
|
||||
@@ -428,7 +428,7 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
if (int.TryParse(thisNode.Value, out thisNodeId))
|
||||
{
|
||||
umbraco.cms.businesslogic.Content loadedNode;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
loadedNode = new umbraco.cms.businesslogic.Content(thisNodeId);
|
||||
@@ -465,7 +465,7 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
var imgPreview = (ImageViewer)e.Item.FindControl("ImgPreview");
|
||||
//show the thubmnail controls
|
||||
imgPreview.Visible = true;
|
||||
|
||||
|
||||
//add the item class
|
||||
var item = (HtmlGenericControl)e.Item.FindControl("Item");
|
||||
item.Attributes["class"] += " thumb-item";
|
||||
@@ -482,7 +482,7 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
imgPreview.MediaId = thisNodeId;
|
||||
imgPreview.DataBind();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -490,8 +490,8 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
{
|
||||
//the node no longer exists, so we display a msg
|
||||
litSelectNodeName.Text = "<i>NODE NO LONGER EXISTS</i>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -511,13 +511,13 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
SavePersistentValuesForTree(XPathFilter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override render to control the exact output of what is rendered this includes instantiating the jquery plugin
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> object that receives the server control content.</param>
|
||||
/// <remarks>
|
||||
/// Generally i don't like to do this but there's a few div's, etc... to render so this makes more sense.
|
||||
/// </remarks>
|
||||
/// <summary>
|
||||
/// Override render to control the exact output of what is rendered this includes instantiating the jquery plugin
|
||||
/// </summary>
|
||||
/// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> object that receives the server control content.</param>
|
||||
/// <remarks>
|
||||
/// Generally i don't like to do this but there's a few div's, etc... to render so this makes more sense.
|
||||
/// </remarks>
|
||||
protected override void Render(HtmlTextWriter writer)
|
||||
{
|
||||
//<div class="multiTreePicker">
|
||||
@@ -536,7 +536,7 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
|
||||
RenderTooltip(writer);
|
||||
|
||||
writer.AddAttribute("class", (!MinItemsValidator.IsValid ? "error " : "") + "multiNodePicker clearfix");
|
||||
writer.AddAttribute("class", (!MinItemsValidator.IsValid ? "error " : "") + "multiNodePicker clearfix");
|
||||
writer.AddAttribute("id", this.ClientID);
|
||||
writer.RenderBeginTag(HtmlTextWriterTag.Div);
|
||||
|
||||
@@ -548,20 +548,20 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
writer.RenderEndTag();
|
||||
|
||||
writer.AddAttribute("class", "left propertypane");
|
||||
writer.AddStyleAttribute( HtmlTextWriterStyle.Height, ((ControlHeight + 10).ToString() + "px"));
|
||||
writer.AddStyleAttribute(HtmlTextWriterStyle.Height, ((ControlHeight + 10).ToString() + "px"));
|
||||
writer.RenderBeginTag(HtmlTextWriterTag.Div);
|
||||
//add the tree control here
|
||||
TreePickerControl.RenderControl(writer);
|
||||
writer.RenderEndTag();
|
||||
|
||||
RightColumn.RenderControl(writer);
|
||||
RightColumn.RenderControl(writer);
|
||||
|
||||
//render the hidden field
|
||||
PickedValue.RenderControl(writer);
|
||||
|
||||
writer.RenderEndTag(); //end multiNodePicker div
|
||||
|
||||
var tooltipAjaxUrl = IOHelper.ResolveUrl(SystemDirectories.Umbraco) + @"/plugins/MultiNodePicker/CustomTreeService.asmx/GetNodeInfo";
|
||||
var tooltipAjaxUrl = IOHelper.ResolveUrl(SystemDirectories.Umbraco) + @"/plugins/MultiNodePicker/CustomTreeService.asmx/GetNodeInfo";
|
||||
|
||||
//add jquery window load event to create the js tree picker
|
||||
var jsMethod = string.Format("jQuery('#{0}').MultiNodeTreePicker('{1}', {2}, '{3}', {4}, {5}, '{6}', '{7}');",
|
||||
@@ -574,23 +574,23 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
IOHelper.ResolveUrl(SystemDirectories.Umbraco),
|
||||
TreeToRender);
|
||||
var js = "jQuery(window).load(function() { " + jsMethod + " });";
|
||||
|
||||
|
||||
writer.WriteLine("<script type='text/javascript'>" + js + "</script>");
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// converts a list of Ids to the XDocument structure
|
||||
/// </summary>
|
||||
/// <param name="val">The value.</param>
|
||||
/// <returns></returns>
|
||||
/// <summary>
|
||||
/// converts a list of Ids to the XDocument structure
|
||||
/// </summary>
|
||||
/// <param name="val">The value.</param>
|
||||
/// <returns></returns>
|
||||
private XDocument ConvertToXDocument(IEnumerable<string> val)
|
||||
{
|
||||
if (val.Count() > 0)
|
||||
{
|
||||
return new XDocument(new XElement("MultiNodePicker",
|
||||
new XAttribute("type", TreeToRender),
|
||||
val.Select(x => new XElement("nodeId", x.ToString()))));
|
||||
val.Select(x => new XElement("nodeId", x.ToString()))));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -633,18 +633,18 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
this.Page.Items.Add("MNTPTooltip", true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will update the multi-node tree picker data which is used to store
|
||||
/// the xpath data and xpath match type for this control id.
|
||||
/// </summary>
|
||||
/// <param name="xpath">The xpath.</param>
|
||||
/// <remarks>
|
||||
/// This will save the data into a cookie and also into the request cookie. It must save
|
||||
/// it to both locations in case the request cookie has been changed and the request cookie
|
||||
/// is different than the response cookie.
|
||||
/// </remarks>
|
||||
/// <summary>
|
||||
/// This will update the multi-node tree picker data which is used to store
|
||||
/// the xpath data and xpath match type for this control id.
|
||||
/// </summary>
|
||||
/// <param name="xpath">The xpath.</param>
|
||||
/// <remarks>
|
||||
/// This will save the data into a cookie and also into the request cookie. It must save
|
||||
/// it to both locations in case the request cookie has been changed and the request cookie
|
||||
/// is different than the response cookie.
|
||||
/// </remarks>
|
||||
private void SavePersistentValuesForTree(string xpath)
|
||||
{
|
||||
{
|
||||
|
||||
//create the output cookie with all of the values of the request cookie
|
||||
|
||||
@@ -668,7 +668,7 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
var id = 0;
|
||||
if (int.TryParse(HttpContext.Current.Request["id"], out id))
|
||||
{
|
||||
newCookie.MntpAddCurrentEditingNode(this.DataTypeDefinitionId, id);
|
||||
newCookie.MntpAddCurrentEditingNode(this.DataTypeDefinitionId, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,7 +681,7 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
HttpContext.Current.Request.Cookies.Remove(MNTP_DataType.PersistenceCookieName);
|
||||
}
|
||||
HttpContext.Current.Request.Cookies.Add(newCookie);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -316,7 +316,7 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
base.OnInit(e);
|
||||
this.EnsureChildControls();
|
||||
|
||||
this.AddResourceToClientDependency("uComponents.DataTypes.Shared.Resources.Styles.PrevalueEditor.css", ClientDependency.Core.ClientDependencyType.Css);
|
||||
this.RegisterEmbeddedClientResource("umbraco.editorControls.PrevalueEditor.css", ClientDependencyType.Css);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -329,7 +329,7 @@ namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
base.OnLoad(e);
|
||||
|
||||
//add the css required
|
||||
this.AddCssMNTPClientDependencies();
|
||||
//// this.AddCssMNTPClientDependencies();
|
||||
|
||||
//let view state handle the rest
|
||||
if (!Page.IsPostBack)
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
(function ($) {
|
||||
|
||||
//jquery plugin for our tree picker
|
||||
$.fn.MultiNodeTreePicker = function (ctlId, maxItems, tooltipAjaxUrl, showTooltip, showThumbnail, umbPath, treeType) {
|
||||
|
||||
/* internal properties */
|
||||
var $tree = $(this);
|
||||
var ctl = $("#" + ctlId);
|
||||
var hiddenField = ctl.find("input[type='hidden']");
|
||||
var rightCol = ctl.find(".right");
|
||||
var tooltip = null; //the tooltip object (will be defined when it is shown)
|
||||
var throbber = null;
|
||||
var collapseNode = null; //this is used to track collapsing of tree nodes due to the issue of the nodeClicked event being fired on tree collapse
|
||||
|
||||
//store a reference to the hidden field in the right columns data collection
|
||||
rightCol.data("hiddenField", hiddenField);
|
||||
|
||||
function getPosition(trigger, tip, conf) {
|
||||
// get origin top/left position
|
||||
var top = trigger.offset().top,
|
||||
left = trigger.offset().left,
|
||||
pos = conf.position[0];
|
||||
|
||||
top -= tip.outerHeight() - conf.offset[0];
|
||||
left += trigger.outerWidth() + conf.offset[1];
|
||||
|
||||
// adjust Y
|
||||
var height = tip.outerHeight() + trigger.outerHeight();
|
||||
if (pos == 'center') { top += height / 2; }
|
||||
if (pos == 'bottom') { top += height; }
|
||||
|
||||
|
||||
// adjust X
|
||||
pos = conf.position[1];
|
||||
var width = tip.outerWidth() + trigger.outerWidth();
|
||||
if (pos == 'center') { left -= width / 2; }
|
||||
if (pos == 'left') { left -= width; }
|
||||
|
||||
return { top: top, left: left };
|
||||
}
|
||||
|
||||
//used to create the tooltip
|
||||
var tooltipOptions = {
|
||||
tip: "#MNTPTooltip",
|
||||
effect: "fade",
|
||||
predelay: 0,
|
||||
position: 'center left',
|
||||
relative: true,
|
||||
offset: [30, 0],
|
||||
onShow: function () {
|
||||
//get the id of the item being queried
|
||||
var id = this.getTrigger().next().find("li").attr("rel");
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
data: "{\"id\": " + id + "}",
|
||||
dataType: "json",
|
||||
url: tooltipAjaxUrl,
|
||||
contentType: "application/json; charset=UTF-8",
|
||||
success: function (data) {
|
||||
var newLocation = (treeType == "content" ? umbPath + "/editContent.aspx?id=" : umbPath + "/editMedia.aspx?id=") + data.d.Id;
|
||||
var h = $("<a href='" + newLocation + "'>[edit]</a><h5>ID: " + data.d.Id + "</h5><p><b>Path:</b> " + data.d.Path + "</p><p><i>" + data.d.PathAsNames + "</i></p>");
|
||||
h.click(function () {
|
||||
|
||||
if (!confirm("Are you sure you want to navigate away from this page?\n\nYou may have unsaved changes.\n\nPress OK to continue or Cancel to stay on the current page.")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//this is a VERY dodgy work around for deep linking between sections and pages
|
||||
var iframe = UmbClientMgr.mainWindow().jQuery("#deepLinkScriptFrame");
|
||||
if (iframe.length == 0) {
|
||||
var html = "<html><head><script type='text/javascript'>"
|
||||
+ "this.window.top.delayedNavigate = function(url, app) { "
|
||||
+ " if (UmbClientMgr.historyManager().getCurrent() == app) {"
|
||||
+ " UmbClientMgr.contentFrame(url);"
|
||||
+ " }"
|
||||
+ " else {"
|
||||
+ " var origContentFrameFunc = UmbClientMgr.contentFrame;"
|
||||
+ " var newContentFrameFunc = function (location) {"
|
||||
+ " UmbClientMgr.contentFrame = origContentFrameFunc;"
|
||||
+ " origContentFrameFunc.call(this, url);"
|
||||
+ " };"
|
||||
+ " UmbClientMgr.contentFrame = newContentFrameFunc;"
|
||||
+ " UmbClientMgr.mainTree()._loadedApps['tree_' + app] = null;"
|
||||
+ " UmbClientMgr.mainTree().setActiveTreeType(app);"
|
||||
+ " UmbClientMgr.mainWindow().location.hash = '#' + app ; "
|
||||
+ " }"
|
||||
+ "};"
|
||||
+ "</script></head><body></body></html>";
|
||||
iframe = UmbClientMgr.mainWindow().jQuery("<iframe id='deepLinkScriptFrame'>")
|
||||
.append(html)
|
||||
.hide()
|
||||
.css("width", "0px")
|
||||
.css("height", "0px");
|
||||
UmbClientMgr.mainWindow().jQuery("body").append(iframe);
|
||||
}
|
||||
|
||||
UmbClientMgr.mainWindow().delayedNavigate(newLocation, treeType);
|
||||
|
||||
return false;
|
||||
});
|
||||
throbber.hide().next().html("").append(h).show();
|
||||
},
|
||||
error: function (data) {
|
||||
alert("Error!" + data.d.Message);
|
||||
}
|
||||
});
|
||||
},
|
||||
onBeforeShow: function (ev, pos) {
|
||||
tooltip = this.getTip();
|
||||
//move the tooltip just before the trigger so that it's relatively placed
|
||||
this.getTrigger().before(tooltip);
|
||||
throbber = tooltip.find(".throbber");
|
||||
throbber.show().next().hide();
|
||||
},
|
||||
events: {
|
||||
def: 'click, mouseleave'
|
||||
}
|
||||
};
|
||||
|
||||
function StorePickedNodes(hiddenField, rightCol) {
|
||||
if (!hiddenField || !rightCol)
|
||||
return;
|
||||
|
||||
var val = "";
|
||||
rightCol.find(".item ul.rightNode li").each(function () {
|
||||
val += $(this).attr("rel") + ",";
|
||||
});
|
||||
if (val != "") val = val.substr(0, val.length - 1);
|
||||
hiddenField.val(val);
|
||||
};
|
||||
|
||||
function doHighlight(node) {
|
||||
var div = node.find('a').find("div:first");
|
||||
var origBorder = div.css("border");
|
||||
div.css("border", "1px solid #FBC2C4").css("background-color", "#FBE3E4").css("color", "#8a1f11");
|
||||
setTimeout(function () { div.attr("style", ""); }, 500);
|
||||
}
|
||||
|
||||
//handler for the node clicking event
|
||||
function nodeClickHandler(e, node) {
|
||||
//this is a dodgy hack due to a bug in the umb tree that fires the click event
|
||||
//twice: http://umbraco.codeplex.com/workitem/29194
|
||||
if ($(node).is(":hidden")) {
|
||||
collapseNode = node;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
//if the collapseNode flag is null, then we're ok
|
||||
if (!collapseNode) {
|
||||
if (!$(node).hasClass("uc-treenode-noclick")) {
|
||||
AddToRight(node);
|
||||
}
|
||||
else {
|
||||
doHighlight($(node));
|
||||
}
|
||||
}
|
||||
else {
|
||||
//reset the flag but still do nothing
|
||||
collapseNode = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//handler for when the tree is synced
|
||||
function treeSyncEventHandler() {
|
||||
//re-add a handler to the tree's nodeClicked event
|
||||
$tree.UmbracoTreeAPI().addEventHandler("nodeClicked", nodeClickHandler);
|
||||
}
|
||||
|
||||
//syncs the tree with the item selected on the right
|
||||
function SyncItems(node) {
|
||||
//first remove the nodeClick event handler as this will fire when the tree is synced
|
||||
$tree.UmbracoTreeAPI().removeEventHandler("nodeClicked", nodeClickHandler);
|
||||
|
||||
//for some reason node syncing doesn't work until a node is selected, so lets just
|
||||
//select the root node, then continue to sync the tree.
|
||||
$tree.UmbracoTreeAPI().selectNode($tree.find("li:first"));
|
||||
|
||||
//the path will be available to nodes rendered when the page is rendered so we can do a full sync tree.
|
||||
//only the node id will be available for nodes that have been newly selected but this is ok since the
|
||||
//nodes are already loaded so the system will be able to sync them.
|
||||
var nodeId = node.attr("rel");
|
||||
var path = node.attr("umb:nodedata");
|
||||
if (!path) path = nodeId;
|
||||
|
||||
$tree.UmbracoTreeAPI()
|
||||
.syncTree(path.toString());
|
||||
}
|
||||
|
||||
//does the adding of a node to the right hand column
|
||||
//If "test" is true the node is not added. Instead true is returned if it could have been added
|
||||
function AddToRight(node, test) {
|
||||
|
||||
var $node = $(node);
|
||||
|
||||
if ($node.hasClass("uc-treenode-noclick")) {
|
||||
doHighlight($node);
|
||||
return "Item not allowed here";
|
||||
}
|
||||
|
||||
//get the node id of the node selected
|
||||
var nodeId = $node.attr("id");
|
||||
|
||||
//first, check if we've reached the max
|
||||
if (maxItems >= 0 && rightCol.find("li").length >= maxItems) {
|
||||
doHighlight($node);
|
||||
return "No more items can be added";
|
||||
}
|
||||
|
||||
//check if node id already exists in the right panel, also check if it the root node
|
||||
//since this should not be selectable
|
||||
if (nodeId <= 0 || $tree.find("li:first").attr("id") == nodeId || (rightCol.find("li[rel='" + nodeId + "']").length > 0)) {
|
||||
doHighlight($node);
|
||||
return nodeId < 0 ? "Item not allowed here" : "Item already added";
|
||||
}
|
||||
|
||||
if (test) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//create a copy of the node clicked on the tree
|
||||
var jNode = $node.clone().find("a:first")
|
||||
//remove un-needed attributes
|
||||
jNode.removeAttr("href")
|
||||
.removeAttr("umb:nodedata")
|
||||
.attr("href", "#")
|
||||
.attr("title", "Sync tree");
|
||||
|
||||
//build a DOM object to put in the right panel
|
||||
var inserted = $("<div class='item'><a href='javascript:void(0);' class='info'></a>" +
|
||||
"<div class='inner'><ul class='rightNode'>" +
|
||||
"<li rel='" + nodeId + "' class='closed'>" +
|
||||
"</li></ul><a class='close' title='Remove' href='javascript:void(0);'></a></div></div>")
|
||||
.hide()
|
||||
.appendTo(rightCol) //add the full div to the right col
|
||||
.find(".closed") //get the li element
|
||||
.append(jNode) //append the anchor link
|
||||
.closest(".item"); //get the item div
|
||||
|
||||
if (showTooltip) {
|
||||
inserted.find(".info").tooltip(tooltipOptions) //add the tooltop
|
||||
}
|
||||
else {
|
||||
//remove the tooltip
|
||||
inserted.find(".info").remove();
|
||||
}
|
||||
|
||||
//add the image preview if we need to
|
||||
if (showThumbnail) {
|
||||
//set the item height to 50px and the width of the inner to 224px
|
||||
inserted.css("height", "50px").find(".inner").css("width", "224px");
|
||||
var imgViewer = $("<div class='imageViewer'></div>").prependTo(inserted);
|
||||
//create the image viewer object, get the API of it and update the image
|
||||
imgViewer.UmbracoImageViewer({
|
||||
umbPath: umbPath,
|
||||
style: "Basic",
|
||||
linkTarget: "_blank"
|
||||
})
|
||||
.UmbracoImageViewerAPI()
|
||||
.updateImage(nodeId, function (args) {
|
||||
if (imgViewer.find("a").attr("href") == "#") {
|
||||
imgViewer.find("img").attr("src", umbPath + "/images/blank.png");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
inserted.show();
|
||||
|
||||
//now update the hidden field with the
|
||||
//node selection
|
||||
StorePickedNodes(hiddenField, rightCol);
|
||||
}
|
||||
|
||||
//remove all trashed nodes
|
||||
rightCol.find("li[rel='trashed']").closest(".item").remove();
|
||||
|
||||
//live click handlers for the removal of items
|
||||
$(".item a.close", rightCol).live("click", function () {
|
||||
$(this).closest(".item").remove();
|
||||
StorePickedNodes(hiddenField, rightCol);
|
||||
});
|
||||
//create live click handlers to the right hand items
|
||||
$(".item ul li a", rightCol).live("click", function () {
|
||||
SyncItems($(this).parent());
|
||||
});
|
||||
|
||||
//add a handler to the tree's nodeClicked event
|
||||
$tree.UmbracoTreeAPI().addEventHandler("nodeClicked", nodeClickHandler);
|
||||
$tree.UmbracoTreeAPI().addEventHandler("syncNotFound", treeSyncEventHandler);
|
||||
$tree.UmbracoTreeAPI().addEventHandler("syncFound", treeSyncEventHandler);
|
||||
|
||||
//create a sortable, drag/drop list and
|
||||
//initialize the right panel with previously
|
||||
//saved data.
|
||||
rightCol.sortable({
|
||||
stop: function (event, ui) { StorePickedNodes($(this).data("hiddenField"), $(this)); },
|
||||
start: function (event, ui) { if (tooltip) tooltip.hide(); }, //hide the tooltip when sorting
|
||||
handle: '.inner'
|
||||
});
|
||||
|
||||
//add the tooltips
|
||||
rightCol.find("a.info").tooltip(tooltipOptions);
|
||||
|
||||
//Register drag and drop action
|
||||
//PROOF OF CONCEPT: The user can probably also drop stuff that shouldn't be dropped (e.g., StartNodeID is not considered). The filter function can take care of that
|
||||
if (typeof (UmbDragDrop) != "undefined") {
|
||||
UmbDragDrop.register(
|
||||
//Container to highlight
|
||||
rightCol,
|
||||
//Drop action
|
||||
function (info) {
|
||||
AddToRight(info.drag_node);
|
||||
},
|
||||
//Filter
|
||||
function (info) {
|
||||
var dropMessage = AddToRight(info.drag_node, true);
|
||||
return { canDrop: dropMessage === true, message: dropMessage === true ? "" : dropMessage };
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1,210 @@
|
||||
/* Standard clearfix */
|
||||
.clearfix:after
|
||||
{
|
||||
content: ".";
|
||||
display: block;
|
||||
clear: both;
|
||||
visibility: hidden;
|
||||
line-height: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.clearfix
|
||||
{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.multiNodePicker .item ul.rightNode
|
||||
{
|
||||
float: left;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: inherit !important;
|
||||
}
|
||||
.multiNodePicker .item ul.rightNode li
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
font: icon;
|
||||
font-family: Arial,Lucida Grande;
|
||||
font-size: 12px;
|
||||
min-height: 20px;
|
||||
}
|
||||
.multiNodePicker .item ul.rightNode li a
|
||||
{
|
||||
background-repeat: no-repeat !important;
|
||||
border: 0 none;
|
||||
color: #2F2F2F;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
padding: 0 0 0 18px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.multiNodePicker .item ul.rightNode li a div
|
||||
{
|
||||
cursor: move;
|
||||
overflow: hidden;
|
||||
height: 20px;
|
||||
width: 240px;
|
||||
}
|
||||
.multiNodePicker .item.thumb-item ul.rightNode li a div
|
||||
{
|
||||
height: 40px;
|
||||
width: 190px;
|
||||
}
|
||||
.multiNodePicker .item a
|
||||
{
|
||||
float: left;
|
||||
}
|
||||
.multiNodePicker .item a.close
|
||||
{
|
||||
color: red;
|
||||
margin: 0;
|
||||
padding: 0px;
|
||||
background: transparent url('/umbraco/images/delete.gif') no-repeat 0px 3px;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 2px;
|
||||
z-index: 200;
|
||||
}
|
||||
.multiNodePicker .item
|
||||
{
|
||||
width: 298px;
|
||||
height: 21px;
|
||||
border: 1px dotted #DCD;
|
||||
overflow: hidden;
|
||||
background-color: #FFF;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
.multiNodePicker .item.thumb-item
|
||||
{
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.multiNodePicker .item:hover
|
||||
{
|
||||
background-color: #F6F6FA;
|
||||
}
|
||||
|
||||
.multiNodePicker .item .inner
|
||||
{
|
||||
float: left;
|
||||
padding: 2px 0px 0px 2px;
|
||||
width: 278px;
|
||||
cursor: move;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.multiNodePicker .item.thumb-item .inner
|
||||
{
|
||||
width: 224px;
|
||||
}
|
||||
|
||||
.multiNodePicker a.info
|
||||
{
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: transparent url('/umbraco/images/information.png') no-repeat 1px 2px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* tooltip */
|
||||
#MNTPTooltip, .tooltip
|
||||
{
|
||||
background: url('/umbraco_client/propertypane/images/propertyBackground.gif') repeat-x scroll center top #FFFFFF;
|
||||
display: none;
|
||||
border: 2px solid #999;
|
||||
width: 200px;
|
||||
height: 70px;
|
||||
padding: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
position: absolute;
|
||||
z-index: 5000;
|
||||
-moz-box-shadow: 2px 2px 11px #999;
|
||||
-webkit-box-shadow: 2px 2px 11px #999;
|
||||
}
|
||||
#MNTPTooltip div.throbber, .tooltip div.throbber
|
||||
{
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: transparent url('/umbraco/images/throbber.gif') no-repeat top left;
|
||||
display: none;
|
||||
}
|
||||
#MNTPTooltip div.tooltipInfo, .tooltip div.tooltipInfo
|
||||
{
|
||||
font-family: Trebuchet MS,Lucida Grande,verdana,arial;
|
||||
font-size: 11px;
|
||||
overflow: hidden;
|
||||
}
|
||||
#MNTPTooltip div.tooltipInfo p, .tooltip div.tooltipInfo p
|
||||
{
|
||||
margin: 3px 0px 3px 0px;
|
||||
}
|
||||
#MNTPTooltip div.tooltipInfo h5, .tooltip div.tooltipInfo h5
|
||||
{
|
||||
font-size: 16px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#MNTPTooltip div.tooltipInfo a, .tooltip div.tooltipInfo a
|
||||
{
|
||||
float: right;
|
||||
font-size: 10px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.multiNodePicker .left.propertypane
|
||||
{
|
||||
width: 300px;
|
||||
float: left;
|
||||
clear: none;
|
||||
margin-right: 10px;
|
||||
height: 210px;
|
||||
}
|
||||
.multiNodePicker .right.propertypane
|
||||
{
|
||||
width: 300px;
|
||||
float: left;
|
||||
clear: right;
|
||||
padding: 3px;
|
||||
}
|
||||
.multiNodePicker .header
|
||||
{
|
||||
width: 622px;
|
||||
}
|
||||
|
||||
.uc-treenode-noclick > a > div
|
||||
{
|
||||
color: #CC8888;
|
||||
}
|
||||
.tree.tree-umbraco li.uc-treenode-noclick > a:hover
|
||||
{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.multiNodePicker .treeContainer
|
||||
{
|
||||
overflow: auto;
|
||||
height: 200px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.multiNodePicker .imageViewer
|
||||
{
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-right: 1px dotted #DCD;
|
||||
margin-right: 2px;
|
||||
float: left;
|
||||
}
|
||||
.multiNodePicker .imageViewer img
|
||||
{
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using System.Web.UI;
|
||||
using umbraco.cms.businesslogic.datatype;
|
||||
|
||||
[assembly: WebResource("umbraco.editorControls.MultiNodeTreePicker.jquery.tooltip.min.js", "application/x-javascript")]
|
||||
[assembly: WebResource("umbraco.editorControls.MultiNodeTreePicker.MultiNodePickerScripts.js", "application/x-javascript")]
|
||||
[assembly: WebResource("umbraco.editorControls.MultiNodeTreePicker.MultiNodePickerStyles.css", "text/css", PerformSubstitution = true)]
|
||||
|
||||
namespace umbraco.editorControls.MultiNodeTreePicker
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for this namespace
|
||||
/// </summary>
|
||||
public static class MultiNodeTreePickerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds the JS/CSS required for the MultiNodeTreePicker
|
||||
/// </summary>
|
||||
/// <param name="ctl"></param>
|
||||
public static void AddAllMNTPClientDependencies(this Control ctl)
|
||||
{
|
||||
//get the urls for the embedded resources
|
||||
AddCssMNTPClientDependencies(ctl);
|
||||
AddJsMNTPClientDependencies(ctl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the CSS required for the MultiNodeTreePicker
|
||||
/// </summary>
|
||||
/// <param name="ctl"></param>
|
||||
public static void AddCssMNTPClientDependencies(this Control ctl)
|
||||
{
|
||||
ctl.AddResourceToClientDependency("umbraco.editorControls.MultiNodeTreePicker.MultiNodePickerStyles.css", ClientDependencyType.Css);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the JS required for the MultiNodeTreePicker
|
||||
/// </summary>
|
||||
/// <param name="ctl"></param>
|
||||
public static void AddJsMNTPClientDependencies(this Control ctl)
|
||||
{
|
||||
ctl.AddResourceToClientDependency("umbraco.editorControls.MultiNodeTreePicker.MultiNodePickerScripts.js", ClientDependencyType.Javascript);
|
||||
ctl.AddResourceToClientDependency("umbraco.editorControls.MultiNodeTreePicker.jquery.tooltip.min.js", ClientDependencyType.Javascript);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user