Smoothing over some MediaPicker rough edges.

- Can now upload images to a specific folder
- Can now create folders in gallery tab
- Images are scaled before drawn
- Added throbber on image uploads
- Clicking image ensures Chrome displays the image instead of downloads it
- After uploading image the image is selected

--HG--
branch : dev
This commit is contained in:
Dave Reed
2011-02-15 16:02:02 -08:00
parent 62ee211557
commit a2e177de76
6 changed files with 131 additions and 19 deletions

View File

@@ -1,13 +1,17 @@
using System;
using System.Web;
using System.Web.Mvc;
using Orchard.Localization;
using Orchard;
using System.Collections.Generic;
using Orchard.Media;
using Orchard.Media.Models;
using Orchard.Media.ViewModels;
using Orchard.Media.Services;
using Orchard.Security;
using Orchard.UI.Admin;
using Orchard.Themes;
using Orchard.UI.Notify;
namespace Orchard.MediaPicker.Controllers {
[Themed(false)]
@@ -42,5 +46,23 @@ namespace Orchard.MediaPicker.Controllers {
ViewData["Service"] = _mediaService;
return View(model);
}
[HttpPost]
public JsonResult CreateFolder(string path, string folderName) {
if (!_authorizer.Authorize(StandardPermissions.AccessAdminPanel)) {
return Json(T("Can't access the admin").ToString());
}
if (!Services.Authorizer.Authorize(Permissions.ManageMedia)) {
return Json(T("Couldn't create media folder").ToString());
}
try {
_mediaService.CreateFolder(HttpUtility.UrlDecode(path), folderName);
return Json(true);
}
catch (Exception exception) {
return Json(T("Creating Folder failed: {0}", exception.Message).ToString());
}
}
}
}

View File

@@ -58,6 +58,7 @@
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<Content Include="Content\synchronizing.gif" />
<Content Include="Scripts\MediaBrowser.js" />
<Content Include="Scripts\MediaPicker.js" />
<Content Include="Styles\mediapicker.css" />
@@ -97,6 +98,9 @@
<ItemGroup>
<Content Include="Views\Tab_Gallery.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="Content\Web.config" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -44,13 +44,52 @@
publishInsertEvent(this);
});
$(".media-filename").live("click", function (ev) {
// when clicking on a filename in the gallery view,
// we interrupt the normal operation and write a <img>
// tag into a new window to ensure the image displays in
// a new window instead of being 'downloaded' like in Chrome
ev.preventDefault();
var self = $(this),
src = attributeEncode(self.attr("href")),
w = window.open("", self.attr("target"));
w.document.write("<!DOCTYPE html><html><head><title>" + src + "</title></head><body><img src=\"" + src + "\" alt=\"\" /></body></html>");
});
$("#createFolder").live("click", function () {
$.post("MediaPicker/Home/CreateFolder", { path: query("mediaPath"), folderName: $("#folderName").val(), __RequestVerificationToken: $("#__requesttoken").val() },
function (response) {
if (typeof response === "string") {
alert(response);
}
else {
location.reload(true);
}
});
});
$(function () {
$("#tabs").tabs({ selected: parseInt(location.hash.replace("#", "")) || 0 });
$("#tabs").tabs({ selected: parseInt(query("tab", location.hash)) || 0 });
// populate width and height when image loads
// note: load event does not bubble so cannot be used with .live
$("#img-loader, #lib-loader").bind("load", syncImage);
$("#lib-uploadform").bind("uploadComplete", function (ev, url) {
// from the libary view, uploading should cause a reload
var href = location.href,
hashindex = location.href.indexOf("#");
if (hashindex !== -1) {
href = href.substr(0, hashindex);
}
location.href = href + "&rl=" + (new Date() - 0) + "#tab=1&select=" + url.substr(url.lastIndexOf("/") + 1);
});
var preselect = query("select", location.hash);
if (preselect) {
$("img[data-filename=" + preselect + "]").closest(".media-item").trigger("click");
}
// edit mode has slightly different wording
// elements advertise this with data-edittext attributes,
// the edit text is the element's new val() unless -content is specified.
@@ -76,7 +115,13 @@
});
function selectImage(prefix, src) {
$(prefix + "preview").width("").height("").attr("src", src);
$(prefix + "preview")
.css({
display: "none",
width: "",
height: ""
})
.attr("src", src);
$(prefix + "loader").attr("src", src);
$(prefix + "src").val(src);
@@ -150,7 +195,12 @@
height = maxHeight;
width = Math.round(width * aspect);
}
self.width(width).height(height);
self.css({
width: width,
height: height,
display: "inline"
});
}
function syncImage() {
@@ -170,11 +220,15 @@
suppressResize = false;
}
function attributeEncode(value) {
return !value ? "" : value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\//g, "&#47;");
}
function getAttr(name, value) {
// get an attribute value, escaping any necessary characters to html entities.
// not an exhastive list, but should cover all the necessary characters for this UI (e.g. you can't really put in newlines).
if (!value && name !== "alt") return "";
return ' ' + name + '="' + value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;") + '"';
return ' ' + name + '="' + attributeEncode(value) + '"';
}
function getImageHtml(data) {
@@ -188,21 +242,24 @@
}
function uploadMedia(form) {
var name = "addmedia__" + (new Date()).getTime();
var name = "addmedia__" + (new Date()).getTime(),
prefix = getIdPrefix(form);
$("<iframe/>", {
id: prefix.substr(1) + "iframe",
name: name,
src: "about:blank",
css: { display: "none" },
load: iframeLoadHandler
}).appendTo(document.body);
}).appendTo(form);
form.target = name;
$(prefix + "indicator").show();
}
// get a querystring value
function query(name) {
function query(name, querystring) {
name = name.toLowerCase();
var search = location.search;
var parts = search.replace("?", "").split("&");
var search = querystring || location.search;
var parts = search.replace("?", "").replace("#", "").split("&");
for (var i = 0, l = parts.length; i < l; i++) {
var part = parts[i];
var eqIndex = part.indexOf("=");
@@ -216,16 +273,15 @@
function iframeLoadHandler() {
try {
var self = $(this),
form = self.closest("form"),
frame = window.frames[this.name];
if (!frame.document || frame.document.URL == "about:blank") {
return true;
}
var result = frame.result;
if (result && result.url) {
// successfully uploaded image, response by setting the url
// to the new image. The change event will respond just as if
// the user typed the url.
$("#img-src").val(result.url).trigger("change");
selectImage(getIdPrefix(this), result.url);
form.trigger("uploadComplete", [result.url]);
}
else if (result && result.error) {
alert(result.error);
@@ -241,7 +297,7 @@
alert(somethingPotentiallyHorrible);
}
}
$(getIdPrefix(form.get(0)) + "indicator").hide();
//cleanup
window.setTimeout(function () {
self.remove();

View File

@@ -18,8 +18,14 @@ input[type="file"] {
{
text-align: center;
vertical-align: middle;
display: none; /*revealed by javascript after scaling*/
}
.selected
{
background-color: Yellow;
}
.throbber
{
display: none
}

View File

@@ -7,7 +7,7 @@
@helper FolderLink(string folderName, string mediaPath) {
// querystring values need to persist after a new GET when clicking on the media browser's
// folders for navigation.
@Html.ActionLink(folderName, "Index", null, null, null, "1", new {
@Html.ActionLink(folderName, "Index", null, null, null, "tab=1", new {
upload = Request["upload"],
uploadpath = Request["uploadpath"],
editmode = Request["editmode"],
@@ -15,6 +15,13 @@
editorId = Request["editorId"],
name = folderName,
mediaPath = mediaPath }, null);
}
@{
// only allow uploading to a local url
var uploadAction = Request["upload"];
if (!Url.IsLocalUrl(uploadAction)) {
uploadAction = "";
}
}
<div style="float:left">
@@ -24,9 +31,14 @@
<text>&#62;</text> @FolderLink(navigation.FolderName, navigation.FolderPath)
}
</p>
<fieldset>
<input id="__requesttoken" type="hidden" value="@Html.AntiForgeryTokenValueOrchard()" />
<input id="folderName" type="text" />
<input type="button" id="createFolder" value="@T("Create Folder")" />
</fieldset>
</div>
<fieldset>
<table class="items" summary="@T("This is a table of the pages currently available for use in your application.")">
<table class="items" summary="@T("This is a table of the images currently available for use in your application.")">
@foreach (var mediaFolder in Model.MediaFolders) {
<tr>
<td>
@@ -42,12 +54,12 @@
<tr data-imgsrc="@src" class="media-item">
<td>
<div class="media-thumbnail">
<img alt="" src="@src" onload="jQuery.mediaPicker.scalePreview(this)" />
<img data-filename="@src.Substring(src.LastIndexOf("/") + 1)" alt="" src="@src" onload="jQuery.mediaPicker.scalePreview(this)" />
</div>
</td>
<td>
<ul class="media-summary">
<li><a href="@src" target="_blank">@mediaFile.Name</a></li>
<li><a class="media-filename" href="@src" target="_blank">@mediaFile.Name</a></li>
<li>@T("Added on"): @mediaFile.LastUpdated</li>
<li>@T("Size"): @mediaFile.Size.ToFriendlySizeString()</li>
</ul>
@@ -55,6 +67,17 @@
</tr>
}
</table>
@if (!String.IsNullOrWhiteSpace(Model.MediaPath)) {
using (Html.BeginFormAntiForgeryPost(uploadAction, FormMethod.Post, new { id="lib-uploadform", enctype = "multipart/form-data", onsubmit = "jQuery.mediaPicker.uploadMedia(this)" })) {
<input type="hidden" name="MediaPath" value="@Model.MediaPath" />
<label for="fileUpload">@T("Upload an image from your computer")</label>
<input type="file" name="fileUpload" id="fileUpload" />
<input type="submit" id="upload" value="Upload" />
}
}
<img id="lib-indicator" src="@Url.Content("~/modules/orchard.mediapicker/content/synchronizing.gif")" alt="" class="throbber" />
</fieldset>
</div>

View File

@@ -25,12 +25,13 @@
<input type="text" id="img-src" />
</div>
<div>
@using(Html.BeginFormAntiForgeryPost(uploadAction, FormMethod.Post, new { enctype = "multipart/form-data", onsubmit="jQuery.mediaPicker.uploadMedia(this)"})) {
@using(Html.BeginFormAntiForgeryPost(uploadAction, FormMethod.Post, new { id = "img-uploadform", enctype = "multipart/form-data", onsubmit="jQuery.mediaPicker.uploadMedia(this)"})) {
<input type="hidden" name="MediaPath" value="@mediaPath" />
<label for="fileUpload">@T("Upload an image from your computer")</label>
<input type="file" name="fileUpload" id="fileUpload" />
<input type="submit" id="upload" value="Upload" />
}
<img id="img-indicator" src="@Url.Content("~/modules/orchard.mediapicker/content/synchronizing.gif")" alt="" class="throbber" />
</div>
</div>