Added context menu to media grid
Restructured folderBrowser js class to be less clutered
This commit is contained in:
@@ -350,6 +350,8 @@
|
||||
<Content Include="umbraco\webservices\api\MemberService.asmx" />
|
||||
<Content Include="umbraco\webservices\api\StylesheetService.asmx" />
|
||||
<Content Include="umbraco\webservices\api\TemplateService.asmx" />
|
||||
<Content Include="umbraco_client\ContextMenu\Css\jquery.contextMenu.css" />
|
||||
<Content Include="umbraco_client\ContextMenu\Js\jquery.contextMenu.js" />
|
||||
<Content Include="umbraco_client\FileUploader\js\jquery.fileUploader.js" />
|
||||
<Content Include="umbraco_client\FolderBrowser\Css\folderbrowser.css" />
|
||||
<Content Include="umbraco_client\FolderBrowser\Js\folderbrowser.js" />
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
/*!
|
||||
* jQuery contextMenu - Plugin for simple contextMenu handling
|
||||
*
|
||||
* Version: 1.5.22
|
||||
*
|
||||
* Authors: Rodney Rehm, Addy Osmani (patches for FF)
|
||||
* Web: http://medialize.github.com/jQuery-contextMenu/
|
||||
*
|
||||
* Licensed under
|
||||
* MIT License http://www.opensource.org/licenses/mit-license
|
||||
* GPL v3 http://opensource.org/licenses/GPL-3.0
|
||||
*
|
||||
*/
|
||||
|
||||
.context-menu-list
|
||||
{
|
||||
/*margin:0;
|
||||
padding:0;
|
||||
|
||||
min-width: 120px;
|
||||
max-width: 250px;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
list-style-type: none;
|
||||
|
||||
border: 1px solid #DDD;
|
||||
background: #EEE;
|
||||
|
||||
-webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
|
||||
-moz-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
|
||||
-ms-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
|
||||
-o-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
|
||||
|
||||
font-family: Verdana, Arial, Helvetica, sans-serif;
|
||||
font-size: 11px;*/
|
||||
|
||||
background: #f0f0f0 url(../../Tree/Themes/umbraco/contextMenuBg.gif) repeat-y left;
|
||||
border: 1px solid #979797;
|
||||
padding: 2px 3px;
|
||||
min-width: 130px;
|
||||
max-width: 250px;
|
||||
font-family: Arial,Lucida Grande;
|
||||
font-size: 11px;
|
||||
margin: 0px;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.context-menu-item
|
||||
{
|
||||
border-left: none;
|
||||
background: transparent;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
padding: 0 0 0 35px;
|
||||
margin: 0;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.context-menu-separator {
|
||||
padding-bottom:0;
|
||||
border-bottom: 1px solid #DDD;
|
||||
}
|
||||
|
||||
.context-menu-item > label > input,
|
||||
.context-menu-item > label > textarea {
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.context-menu-item.hover {
|
||||
cursor: pointer;
|
||||
background: #D5EFFC;
|
||||
border:1px solid #99DEFD;
|
||||
}
|
||||
|
||||
.context-menu-item.disabled {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.context-menu-input.hover,
|
||||
.context-menu-item.disabled.hover {
|
||||
cursor: default;
|
||||
background-color: #EEE;
|
||||
}
|
||||
|
||||
.context-menu-submenu:after {
|
||||
content: ">";
|
||||
color: #666;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 3px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* icons
|
||||
#protip:
|
||||
In case you want to use sprites for icons (which I would suggest you do) have a look at
|
||||
http://css-tricks.com/13224-pseudo-spriting/ to get an idea of how to implement
|
||||
.context-menu-item.icon:before {}
|
||||
*/
|
||||
.context-menu-item.icon { min-height: 18px; background-repeat: no-repeat; background-position: 4px 4px; }
|
||||
.context-menu-item.icon-edit { background-image: url(../../../umbraco/images/copy.small.png); }
|
||||
.context-menu-item.icon-cut { background-image: url(images/cut.png); }
|
||||
.context-menu-item.icon-copy { background-image: url(images/page_white_copy.png); }
|
||||
.context-menu-item.icon-paste { background-image: url(images/page_white_paste.png); }
|
||||
.context-menu-item.icon-delete { background-image: url(../../../umbraco/images/delete.small.png); }
|
||||
.context-menu-item.icon-add { background-image: url(images/page_white_add.png); }
|
||||
.context-menu-item.icon-quit { background-image: url(images/door.png); }
|
||||
|
||||
/* vertically align inside labels */
|
||||
.context-menu-input > label > * { vertical-align: top; }
|
||||
|
||||
/* position checkboxes and radios as icons */
|
||||
.context-menu-input > label > input[type="checkbox"],
|
||||
.context-menu-input > label > input[type="radio"] {
|
||||
margin-left: -17px;
|
||||
}
|
||||
.context-menu-input > label > span {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.context-menu-input > label,
|
||||
.context-menu-input > label > input[type="text"],
|
||||
.context-menu-input > label > textarea,
|
||||
.context-menu-input > label > select {
|
||||
display: block;
|
||||
width: 100%;
|
||||
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-ms-box-sizing: border-box;
|
||||
-o-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.context-menu-input > label > textarea {
|
||||
height: 100px;
|
||||
}
|
||||
.context-menu-item > .context-menu-list {
|
||||
display: none;
|
||||
/* re-positioned by js */
|
||||
right: -5px;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
.context-menu-item.hover > .context-menu-list {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.context-menu-accesskey {
|
||||
text-decoration: underline;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
|
||||
Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
|
||||
(function ($, Base) {
|
||||
(function ($, Base, window, document, undefined) {
|
||||
|
||||
Umbraco.Controls.FolderBrowser = Base.extend({
|
||||
|
||||
@@ -12,62 +12,127 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
_opts: null,
|
||||
_viewModel: null,
|
||||
|
||||
_getChildNodes: function () {
|
||||
_this = this;
|
||||
_getChildNodes: function ()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
$.getJSON(_this._opts.basePath + "/FolderBrowserService/GetChildNodes/" + _this._parentId + "/" + _this._viewModel.filterTerm(), function(data) {
|
||||
$.getJSON(self._opts.basePath + "/FolderBrowserService/GetChildNodes/" + self._parentId + "/" + self._viewModel.filterTerm(), function (data) {
|
||||
if (data != undefined && data.length > 0) {
|
||||
ko.mapping.fromJS(data, {}, _this._viewModel.items);
|
||||
ko.mapping.fromJS(data, {}, self._viewModel.items);
|
||||
} else {
|
||||
_this._viewModel.items([]);
|
||||
self._viewModel.items([]);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Constructor
|
||||
constructor: function (el, opts) {
|
||||
_getItemById: function (id)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
var results = ko.utils.arrayFilter(self._viewModel.items(), function (item) {
|
||||
return item.Id() === id;
|
||||
});
|
||||
|
||||
_this = this;
|
||||
return results.length == 1 ? results[0] : null;
|
||||
},
|
||||
|
||||
_deleteItem: function (id)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
// Store el info
|
||||
this._el = el;
|
||||
this._elId = el.id;
|
||||
var item = self._getItemById(id);
|
||||
if (item === null)
|
||||
throw Error("No item found with the id: " + id);
|
||||
|
||||
// Grab parent id from element
|
||||
this._parentId = $(el).data("parentid");
|
||||
if (confirm(window.top.uiKeys['defaultdialogs_confirmdelete'] + ' "' + item.Name() + '"?\n\n'))
|
||||
{
|
||||
$(window.top).trigger("nodeDeleting", []);
|
||||
|
||||
// Merge options with default
|
||||
this._opts = $.extend({
|
||||
// Default options go here
|
||||
}, opts);
|
||||
var safePath = "," + item.Path() + ",";
|
||||
|
||||
if (safePath.indexOf(",-20,") != -1 || safePath.indexOf(",-21,") != -1)
|
||||
{
|
||||
window.top.umbraco.presentation.webservices.legacyAjaxCalls.DeleteContentPermanently(
|
||||
item.Id(),
|
||||
"media",
|
||||
function () {
|
||||
//raise nodeDeleted event
|
||||
$(window.top).trigger("nodeDeleted", []);
|
||||
|
||||
//TODO: Reload current open node in tree
|
||||
|
||||
// Reload nodes
|
||||
self._getChildNodes();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
window.top.umbraco.presentation.webservices.legacyAjaxCalls.Delete(
|
||||
item.Id(), "",
|
||||
"media",
|
||||
function() {
|
||||
//raise nodeDeleted event
|
||||
$(window.top).trigger("nodeDeleted", []);
|
||||
|
||||
//TODO: Reload current open node in tree
|
||||
|
||||
// Reload nodes
|
||||
self._getChildNodes();
|
||||
},
|
||||
function(error) {
|
||||
//raise public error event
|
||||
$(window.top).trigger("publicError", [error]);
|
||||
|
||||
//TODO: Reload current open node in tree
|
||||
|
||||
// Reload nodes
|
||||
self._getChildNodes();
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_initViewModel: function ()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
// Setup the viewmode;
|
||||
this._viewModel = $.extend({}, {
|
||||
parent: this,
|
||||
self._viewModel = $.extend({}, {
|
||||
parent: self,
|
||||
filterTerm: ko.observable(''),
|
||||
items: ko.observableArray([]),
|
||||
queued: ko.observableArray([])
|
||||
});
|
||||
|
||||
this._viewModel.filterTerm.subscribe(function(newValue) {
|
||||
_this._getChildNodes();
|
||||
self._viewModel.filterTerm.subscribe(function (newValue) {
|
||||
self._getChildNodes();
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
_initToolbar: function ()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
// Inject the upload button into the toolbar
|
||||
var button = $("<input id='fbUploadToolbarButton' type='image' src='images/editor/upload.png' titl='Upload...' onmouseover=\"this.className='editorIconOver'\" onmouseout=\"this.className='editorIcon'\" onmouseup=\"this.className='editorIconOver'\" onmousedown=\"this.className='editorIconDown'\" />");
|
||||
button.click(function(e) {
|
||||
button.click(function (e) {
|
||||
e.preventDefault();
|
||||
$(".upload-overlay").show();
|
||||
});
|
||||
|
||||
$(".tabpage:first-child .menubar td[id$='tableContainerButtons'] .sl nobr").after(button);
|
||||
|
||||
$(".tabpage:first-child .menubar td[id$='tableContainerButtons'] .sl nobr").after(button);
|
||||
},
|
||||
|
||||
_initOverlay: function ()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
// Inject the upload overlay
|
||||
var instructions = 'draggable' in document.createElement('span')
|
||||
? "<h1>Drag files here to upload</h1> \
|
||||
<p>Or, click the button below to chose the items to upload</p>"
|
||||
: "<h1>Click the browse button below to chose the items to upload</h1>";
|
||||
|
||||
|
||||
var overlay = $("<div class='upload-overlay'>" +
|
||||
"<div class='upload-panel'>" +
|
||||
instructions +
|
||||
@@ -85,7 +150,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
"</div>");
|
||||
|
||||
$("body").prepend(overlay);
|
||||
|
||||
|
||||
// Create uploader
|
||||
$("#fileupload").fileUploader({
|
||||
dropTarget: ".upload-overlay",
|
||||
@@ -99,43 +164,43 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
size: data.size,
|
||||
progress: ko.observable(data.progress),
|
||||
cancel: function () {
|
||||
if(this.progress() < 100)
|
||||
if (this.progress() < 100)
|
||||
$("#fileupload").fileUploader("cancelItem", this.itemId);
|
||||
else
|
||||
_this._viewModel.queued.remove(this);
|
||||
self._viewModel.queued.remove(this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Store item back in context for easy access later
|
||||
data.context = file;
|
||||
|
||||
data.context = file;
|
||||
|
||||
// Push bindable item into queue
|
||||
_this._viewModel.queued.push(file);
|
||||
self._viewModel.queued.push(file);
|
||||
},
|
||||
onDone: function (data) {
|
||||
switch(data.status) {
|
||||
switch (data.status) {
|
||||
case 'success':
|
||||
//_this._viewModel.queued.remove(data.context);
|
||||
//self._viewModel.queued.remove(data.context);
|
||||
break;
|
||||
case 'error':
|
||||
_this._viewModel.queued.remove(data.context);
|
||||
self._viewModel.queued.remove(data.context);
|
||||
break;
|
||||
case 'canceled':
|
||||
_this._viewModel.queued.remove(data.context);
|
||||
self._viewModel.queued.remove(data.context);
|
||||
break;
|
||||
}
|
||||
},
|
||||
onProgress: function(data) {
|
||||
onProgress: function (data) {
|
||||
data.context.progress(data.progress);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Hook up uploader buttons
|
||||
$(".upload-overlay .upload").click(function(e) {
|
||||
$(".upload-overlay .upload").click(function (e) {
|
||||
e.preventDefault();
|
||||
$("#fileupload").fileUploader("uploadAll");
|
||||
});
|
||||
|
||||
|
||||
$(".upload-overlay .cancel").click(function (e) {
|
||||
e.preventDefault();
|
||||
$("#fileupload").fileUploader("cancelAll");
|
||||
@@ -145,23 +210,69 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
$(".umbFolderBrowser").live('dragenter dragover', function (e) {
|
||||
$(".upload-overlay").show();
|
||||
});
|
||||
|
||||
|
||||
$(".upload-overlay").live('dragleave dragexit', function (e) {
|
||||
$(this).hide();
|
||||
}).click(function() {
|
||||
}).click(function () {
|
||||
$(this).hide();
|
||||
});
|
||||
|
||||
$(".upload-panel").click(function(e) {
|
||||
$(".upload-panel").click(function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
},
|
||||
|
||||
_initContextMenu: function ()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
// Setup context menus
|
||||
$.contextMenu({
|
||||
selector: '.umbFolderBrowser .items li',
|
||||
callback: function (key, options) {
|
||||
var id = options.$trigger.data("id");
|
||||
switch (key) {
|
||||
case "delete":
|
||||
self._deleteItem(id);
|
||||
break;
|
||||
}
|
||||
},
|
||||
items: {
|
||||
"edit": { name: "Edit", icon: "edit" },
|
||||
"delete": { name: "Delete", icon: "delete" }
|
||||
},
|
||||
animation: { show: "fadeIn", hide: "fadeOut" }
|
||||
});
|
||||
},
|
||||
|
||||
// Constructor
|
||||
constructor: function (el, opts)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
// Store el info
|
||||
self._el = el;
|
||||
self._elId = el.id;
|
||||
|
||||
// Grab parent id from element
|
||||
self._parentId = $(el).data("parentid");
|
||||
|
||||
// Merge options with default
|
||||
self._opts = $.extend({
|
||||
// Default options go here
|
||||
}, opts);
|
||||
|
||||
self._initViewModel();
|
||||
self._initToolbar();
|
||||
self._initOverlay();
|
||||
self._initContextMenu();
|
||||
|
||||
// Bind the viewmodel
|
||||
ko.applyBindings(this._viewModel, el);
|
||||
ko.applyBindings(this._viewModel, overlay.get(0));
|
||||
ko.applyBindings(self._viewModel, el);
|
||||
ko.applyBindings(self._viewModel, $(".upload-overlay").get(0));
|
||||
|
||||
// Grab children media items
|
||||
this._getChildNodes();
|
||||
self._getChildNodes();
|
||||
}
|
||||
|
||||
// Public
|
||||
@@ -195,4 +306,4 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
return $(this).data("api");
|
||||
};
|
||||
|
||||
})(jQuery, base2.Base)
|
||||
})(jQuery, base2.Base, window, document)
|
||||
@@ -10,12 +10,14 @@ using umbraco.cms.businesslogic.media;
|
||||
|
||||
namespace Umbraco.Web.UI.Controls
|
||||
{
|
||||
[ClientDependency(ClientDependencyType.Css, "FolderBrowser/css/folderbrowser.css", "UmbracoClient")]
|
||||
[ClientDependency(ClientDependencyType.Css, "ContextMenu/Css/jquery.contextMenu.css", "UmbracoClient")]
|
||||
[ClientDependency(ClientDependencyType.Css, "FolderBrowser/Css/folderbrowser.css", "UmbracoClient")]
|
||||
[ClientDependency(ClientDependencyType.Javascript, "ui/jquery.js", "UmbracoClient", Priority = 1)]
|
||||
[ClientDependency(ClientDependencyType.Javascript, "ui/base2.js", "UmbracoClient", Priority = 1)]
|
||||
[ClientDependency(ClientDependencyType.Javascript, "ui/knockout.js", "UmbracoClient", Priority = 2)]
|
||||
[ClientDependency(ClientDependencyType.Javascript, "ui/knockout.mapping.js", "UmbracoClient", Priority = 3)]
|
||||
[ClientDependency(ClientDependencyType.Javascript, "FileUploader/js/jquery.fileUploader.js", "UmbracoClient", Priority = 3)]
|
||||
[ClientDependency(ClientDependencyType.Javascript, "ContextMenu/Js/jquery.contextMenu.js", "UmbracoClient", Priority = 3)]
|
||||
[ClientDependency(ClientDependencyType.Javascript, "FileUploader/js/jquery.fileUploader.js", "UmbracoClient", Priority = 4)]
|
||||
[ClientDependency(ClientDependencyType.Javascript, "FolderBrowser/js/folderbrowser.js", "UmbracoClient", Priority = 10)]
|
||||
[ToolboxData("<{0}:FolderBrowser runat=server></{0}:FolderBrowser>")]
|
||||
public class FolderBrowser : WebControl
|
||||
@@ -112,7 +114,7 @@ namespace Umbraco.Web.UI.Controls
|
||||
|
||||
// Create thumbnails container
|
||||
sb.Append("<ul class='items' data-bind='foreach: items'>" +
|
||||
"<li><a data-bind='attr: { href: EditUrl }'><span class='img'><img data-bind='attr: { src: ThumbnailUrl }' /></span><span data-bind='text: Name'></span></a></li>" +
|
||||
"<li data-bind=\"attr: { 'data-id': Id }\"><a data-bind='attr: { href: EditUrl }'><span class='img'><img data-bind='attr: { src: ThumbnailUrl }' /></span><span data-bind='text: Name'></span></a></li>" +
|
||||
"</ul>");
|
||||
|
||||
panel.Controls.Add(new LiteralControl(sb.ToString()));
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace Umbraco.Web.WebServices
|
||||
data.Add(new
|
||||
{
|
||||
Id = child.Id,
|
||||
Path = child.Path,
|
||||
Name = child.Text,
|
||||
MediaTypeAlias = child.ContentType.Alias,
|
||||
EditUrl = string.Format("editMedia.aspx?id={0}", child.Id),
|
||||
|
||||
Reference in New Issue
Block a user