function ReadFlagsOnXml(divControlName, XMLFile) { var div = $("#" + divControlName); console.log($(div).text()); $.ajax({ type: "GET", url: XMLFile, dataType: "xml", success: function(xml) { var xmlDoc = $.parseXML(xml), $xml = $(xmlDoc); console.log(xml); var countries = $(xml).find('Countries'); $(countries).find('Country').each(function() { var countryName = $(this).find('Name').text(); var flagImage = $(this).find('Image').text(); $("<img>", { src: flagImage, title: countryName }).appendTo($(div)); }); } }); }
تهیه خروجی RSS در برنامههای ASP.NET MVC
برای نمونه این خروجی رو میتونید در سورس نهایی فید سایت مشاهده کنید.
پلاگین Data Table مبتنی بر AngularJs
JQuery Datatables برای برنامه نویسان وب یک پلاگین کاربردی و معروف محسوب میشود. Angular Datatables نسخه همگام شده با AngularJs است. کار با این پلاگین خیلی ساده است و کسانی که با کارکرد Datatables آشنایی دارند هیچ مشکلی با نسخه AngularJs نخواهند داشت. از امکانات ویژه این پلاگین میتوان به Binding ساده و خودکار و امکان تغییر Optionها در سمت کنترلر و مدیریت promise اشاره کرد.
<div class="alert"> نمایش اعلانات </div>
تعدادی کلاس دیگر نیز جهت استفاده از رنگهای مختلف نیز توسط بوت استرپ ارائه شده است:
همچنین اگر مایل بودید میتوانید با افزودن یک دکمه با کلاس close و ویژگی data-dismiss مساوی alert، امکان بستن پیام را در اختیار کاربر قرار دهید:
<div class="alert alert-warning alert-dismissable"> <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> نمایش اعلان </div>
در ادامه قصد داریم این پیام را بعد از ثبت اطلاعات، به کاربر نمایش دهیم. یعنی در داخل کد، امکان صدا زدن این نوع پیامها را داشته باشیم.
ابتدا کلاسهای زیر را تعریف میکنیم:
کلاس Alert
public class Alert { public const string TempDataKey = "TempDataAlerts"; public string AlertStyle { get; set; } public string Message { get; set; } public bool Dismissable { get; set; } }
در کلاس فوق خصوصیت یک alert را تعریف کردهایم (از خاصیت TempDataKey جهت پاس دادن alertها به view استفاده میکنیم).
public class AlertStyles { public const string Success = "success"; public const string Information = "info"; public const string Warning = "warning"; public const string Danger = "danger"; }
public class BaseController : Controller { public void Success(string message, bool dismissable = false) { AddAlert(AlertStyles.Success, message, dismissable); } public void Information(string message, bool dismissable = false) { AddAlert(AlertStyles.Information, message, dismissable); } public void Warning(string message, bool dismissable = false) { AddAlert(AlertStyles.Warning, message, dismissable); } public void Danger(string message, bool dismissable = false) { AddAlert(AlertStyles.Danger, message, dismissable); } private void AddAlert(string alertStyle, string message, bool dismissable) { var alerts = TempData.ContainsKey(Alert.TempDataKey) ? (List<Alert>)TempData[Alert.TempDataKey] : new List<Alert>(); alerts.Add(new Alert { AlertStyle = alertStyle, Message = message, Dismissable = dismissable }); TempData[Alert.TempDataKey] = alerts; } }
public ActionResult Index() { var userInfo = new { Name = "Sirwan", LastName = "Afifi", }; ViewData["User"] = userInfo; ViewBag.User = userInfo; TempData["User"] = userInfo; return RedirectToAction("About"); }
@{ ViewBag.Title = "About"; } <h1>Tempdata</h1><p>@TempData["User"]</p> <h1>ViewData</h1><p>@ViewData["User"]</p> <h1>ViewBag</h1><p>@ViewBag.User</p>
public class NewsController : BaseController { readonly INewsService _newsService; readonly IUnitOfWork _uow; public NewsController(INewsService newsService, IUnitOfWork uow) { _newsService = newsService; _uow = uow; } [HttpPost] [ValidateAntiForgeryToken] [ValidateInput(false)] public ActionResult Create(News news) { if (ModelState.IsValid) { _newsService.AddNews(news); _uow.SaveChanges(); Success(string.Format("خبر با عنوان <b>{0}</b> با موفقیت ذخیره گردید!", news.Title), true); return RedirectToAction("Index"); } Danger("خطا در هنگام ثبت اطلاعات "); return View(news); } [HttpPost] public ActionResult Delete(int id) { _newsService.DeleteNewsById(id); _uow.SaveChanges(); Danger("اطلاعات مورد نظر با موفقیت حذف گردید!", true); return RedirectToAction("Index"); } }
@{ var alerts = TempData.ContainsKey(Alert.TempDataKey) ? (List<Alert>)TempData[Alert.TempDataKey] : new List<Alert>(); if (alerts.Any()) { <hr /> } foreach (var alert in alerts) { var dismissableClass = alert.Dismissable ? "alert-dismissable" : null; <div class="alert alert-@alert.AlertStyle @dismissableClass"> @if (alert.Dismissable) { <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> } @Html.Raw(alert.Message) </div> } }
<div> @{ Html.RenderPartial("_Alerts"); } @RenderBody() </div>
الف) اگر از jQuery Ajax استفاده میکنید، حتما باید استفاده از Url.Action را لحاظ کنید
برای نمونه اگر قسمتی از عملیات Ajaxایی برنامه شما به نحو زیر تعریف شده است :
$.ajax({ type: "POST", url: "/Home/EmployeeInfo", ...
در این حالت برنامه شما تنها در زمانیکه در ریشه یک دومین قرار گرفته باشد کار خواهد کرد. اگر برنامه شما در مسیری مانند http://www.site.com/myNewApp نصب شود، کلیه فراخوانیهای Ajax ایی آن دیگر کار نخواهند کرد چون مسیر url فوق به ریشه سایت اشاره میکند و نه مسیر جاری برنامه شما (در یک sub domain جدید).
به همین جهت در یک چنین حالتی حتما باید به کمک Url.Action مسیر یک اکشن متد را معرفی کرد تا به صورت خودکار بر اساس محل قرارگیری برنامه و تعاریف مسیریابی آن، Url صحیحی تولید شود.
@Url.Action("EmployeeInfo", "Home")
ب) دریافت Url مطلق از یک Url.Action
Urlهای تولید شده توسط Url.Action به صورت پیش فرض نسبی هستند (نسبت به محل نصب و قرارگیری برنامه تعریف میشوند). اگر نیاز به دریافت یک مسیر مطلق که با http برای مثال شروع میشود دارید، باید به نحو زیر عمل کرد:
@Url.Action("About", "Home", null, "http")
ج) استفاده از Url.Action در یک کنترلر
فرض کنید قصد تولید یک فید RSS را در کنترلری دارید. یکی از آیتمهایی که باید ارائه دهید، لینک به مطلب مورد نظر است. این لینک باید مطلق باشد همچنین در یک View هم قرار نداریم که به کمک @ بلافاصله به متد کمکی Url.Action دسترسی پیدا کنیم.
در کنترلرها، وهله جاری کلاس به شیء Url و متد Action آن به نحو زیر دسترسی دارد و خروجی نهایی آن یک رشته است:
var url = this.Url.Action(actionName: "Index", controllerName: "Post", protocol: "http", routeValues: new { id = item.Id });
د) استفاده از Url.Action در کلاسهای کمکی برنامه خارج از یک کنترلر
فرض کنید قصد تهیه یک Html Helper سفارشی را به کمک کدنویسی در یک کلاس مجزا دارید. در اینجا نیز نباید Urlها را دستی تولید کرد. در Html Helperهای سفارشی نیز میتوان به کمک متد UrlHelper.GenerateUrl، به همان امکانات Url.Action دسترسی یافت:
public static class Extensions { public static string MyLink(this HtmlHelper html, ...) { string url = UrlHelper.GenerateUrl(null, "actionName", "controllerName", null, html.RouteCollection, html.ViewContext.RequestContext, includeImplicitMvcValues: true); //...
تولید اعداد تصادفی در جاوا اسکریپت
$(function () { $(window).scroll(function () { var aTop = $(document).height() - $(window).scrollTop() - $(window).height(); if (aTop == 0) { alert("ok"); } }); });
اگر به گوگل ریدر دقت کرده باشید، دو گزینهی به اشتراک گذاری دارد: share و share with note .
اگر گزینهی share with note را انتخاب کرده و توضیحی را ارسال یا اضافه کنیم، این توضیحات، به فید از نوع Atom اشتراکها هم اضافه میشود. مثلا:
<?xml version="1.0"?>
<feed xmlns:media="http://search.yahoo.com/mrss/"
xmlns:gr="http://www.google.com/schemas/reader/atom/"
xmlns:idx="urn:atom-extension:indexing"
xmlns="http://www.w3.org/2005/Atom"
idx:index="no"
gr:dir="ltr">
...
<entry gr:crawl-timestamp-msec="1316627782108">
...
<gr:annotation>
<content type="html">text-text-text</content>
<author>
<name>Vahid</name>
</author>
</gr:annotation>
...
</entry>
...
</feed>
این افزونه استاندارد نیست و همانطور که در قسمت xmlns:gr اطلاعات فوق مشخص است، در فضای نام http://www.google.com/schemas/reader/atom/ معنا پیدا میکند. از دات نت سه و نیم به بعد هم کلاسی جهت خواندن فیدهای استاندارد وجود دارد (تعریف شده در فضای نام System.ServiceModel.Syndication). اما چگونه میتوان این افزونهی غیر استاندارد را با کمک امکانات توکار دات نت خواند؟
روش کار با استفاده از ElementExtensions هر آیتم یک فید است؛ به صورت زیر :
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Syndication;
using System.Xml;
using System.Xml.Linq;
namespace Linq2Rss
{
public class RssEntry
{
public string Title { set; get; }
public string Description { set; get; }
public string Link { set; get; }
public DateTime PublicationDate { set; get; }
public string Author { set; get; }
public string BlogName { set; get; }
public string BlogAddress { set; get; }
public string Annotation { set; get; }
}
public static class AtomReader
{
private static string getAtomAnnotation(this SyndicationElementExtensionCollection items)
{
if (!items.Any()) return string.Empty;
var item = items.Where(x => x.OuterName.ToLowerInvariant() == "annotation").FirstOrDefault();
if (item == null) return string.Empty;
var element = item.GetObject<XElement>();
var content = element.Element("{http://www.w3.org/2005/Atom}content");
return content == null ? string.Empty : content.Value;
}
public static IList<RssEntry> GetEntries(string feedUrl)
{
using (var reader = XmlReader.Create(feedUrl))
{
var feed = SyndicationFeed.Load(reader);
if (feed == null) return null;
return feed.Items.Select(x =>
new RssEntry
{
Title = x.Title.Text,
Author = x.Authors.Any() ? x.Authors.First().Name : string.Empty,
Description = x.Content == null ? string.Empty : ((TextSyndicationContent)x.Content).Text,
Link = x.Links.Any() ? x.Links.First().Uri.AbsoluteUri : string.Empty,
PublicationDate = x.PublishDate.UtcDateTime,
BlogName = x.SourceFeed.Title.Text,
BlogAddress = x.SourceFeed.Links.Any() ? x.SourceFeed.Links.First().Uri.AbsoluteUri : string.Empty,
Annotation = x.ElementExtensions.getAtomAnnotation()
}).ToList();
}
}
}
}
در این مثال به کمک متد الحاقی getAtomAnnotation، مجموعهی SyndicationElementExtensionCollection هر آیتم یک فید بررسی شده، در بین اینها، موردی که از نوع annotation باشد انتخاب و سپس content آن استخراج میگردد.
نکتهای دیگر:
اکثر کلاسهای موجود در فضاهای نام مرتبط با XML در دات نت امکان خواندن اطلاعات را از یک Uri هم دارند؛ مانند مثال فوق و متد XmlReader.Create بکارگرفته شده در آن. اما اگر بخواهیم حین خواندن اطلاعات، یک پروکسی را نیز به پروسه جاری اضافه کنیم، به نظر خاصیت یا متدی جهت انجام اینکار وجود ندارد. برای رفع این مشکل میتوان یک پروکسی سراسری را تعریف کرد. تنها کافی است خاصیت System.Net.WebRequest.DefaultWebProxy مقدار دهی شود. پس از آن به صورت خودکار بر روی کل برنامه تاثیر خواهد گذاشت.
در این مثال برای نمایش پیام به صورت notification، از کتابخانه toastr استفاده میکنیم که از طریق nuget میتوانید آن را به پروژه اضافه کنید:
PM> Install-Package toastr
toastr.info("نمایش یک پیام - info"); toastr.success("نمایش یک پیام - success"); toastr.error("نمایش یک پیام - error"); toastr.warning("نمایش یک پیام - warning");
toastr.success("نمایش یک پیام - success", "عنوان");
toastr.options = { tapToDismiss: true, toastClass: 'toast', containerId: 'toast-container', debug: false, showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery showDuration: 300, showEasing: 'swing', //swing and linear are built into jQuery onShown: undefined, hideMethod: 'fadeOut', hideDuration: 1000, hideEasing: 'swing', onHidden: undefined, extendedTimeOut: 1000, iconClasses: { error: 'toast-error', info: 'toast-info', success: 'toast-success', warning: 'toast-warning' }, iconClass: 'toast-info', positionClass: 'toast-top-right', timeOut: 5000, // Set timeOut and extendedTimeOut to 0 to make it sticky titleClass: 'toast-title', messageClass: 'toast-message', target: 'body', closeHtml: '<button>×</button>', newestOnTop: true, preventDuplicates: false, progressBar: false };
public class NotificationHub : Hub { private readonly IProductService _productService; public NotificationHub(IProductService productService) { _productService = productService; } public void SendNotification() { Clients.Others.ShowNotification(_productService.GetLastProduct()); } }
var notify = $.connection.notificationHub; notify.client.showNotification = function (data) { toastr.info("رکورد جدیدی ثبت گردید جهت نمایش اینجا کلیک کنید"); }; $.connection.hub.start().done(function () { @{ if (ViewBag.NotifyUsers) { <text>notify.server.sendNotification();</text> } } });
var positionClasses = { topRight: 'toast-top-right', bottomRight: 'toast-bottom-right', bottomLeft: 'toast-bottom-left', topLeft: 'toast-top-left', topCenter: 'toast-top-center', bottomCenter: 'toast-bottom-center' }; var notify = $.connection.notificationHub; notify.client.showNotification = function (data) { toastr.options = { showDuration: 300, positionClass: positionClasses.bottomRight, onclick: function () { $('#table tr:last').after("<tr>" + "<td>" + data.Title + "</td>" + "<td>" + data.Description + "</td>" + "<td>" + data.Price + "</td>" + "<td>" + data.Category + "</td>" + "<td> </td>" + "</tr>"); } }; toastr.info("رکورد جدیدی ثبت گردید جهت نمایش اینجا کلیک کنید"); }; $.connection.hub.start().done(function () { @{ if (ViewBag.NotifyUsers) { <text>notify.server.sendNotification();</text> } } });
onclick: function () { $('#table tr:last').after("<tr>" + "<td>" + data.Title + "</td>" + "<td>" + data.Description + "</td>" + "<td>" + data.Price + "</td>" + "<td>" + data.Category + "</td>" + "<td> </td>" + "</tr>"); }
data {Id: 12, Title: "Item1", Description: "Des", Price: 100000, Category: 0}
var d = new Date(); $.jCookies({ name: 'dotnettips.info', value: { Title: 'ساخت کوکی با jcookie', Author: 'علی یگانه مقدم', Seen: d.getDate(), Favorite: true } });
$.jCookies ({ name : 'User', value : { username : 'Bob' , level : 5 }, minutes : 60 });
$.jCookies.defaults = { name : '', value : '', days : 27 }
var values = $.jCookies ({ get: 'dotnettips.info' });
var values = $.jCookies({ get: 'Rutabaga', error: true });
Error : { arguments : undefined, message : "Invalid base64 data", stack : "—", type : undefined }
var values = $.jCookies({ get: '*' }); alert(values["dotnettips.info"].Title); alert(values["data2"].Title);
var value = $.jCookies({ erase: 'dotnettips.info' });
- برگشت دادهها از حالت رمزگذاری base64
- دادهها در فرمت json هستند و باید به حالتی قابل استفاده در محیط شی گرا تبدیل شوند.
Title | ایجاد کوکی با jcookie |
Author | علی یگانه مقدم |
Seen | 2015/1/14 |
Favorite | true |
byte[] from64 = Convert.FromBase64String(Page.Request.Cookies["dotnettips.info"].Value); string json = Encoding.UTF8.GetString(from64); Dictionary<string, object> article =new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json); Page.Response.Write("Title: "+ (string)article["Title"]);
byte[] from64 = Convert.FromBase64String(Page.Request.Cookies["dotnettips.info"].Value); string json = Encoding.Unicode.GetString(from64); Dictionary<string, object> article =new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json); Page.Response.Write("Title: "+ (string)article["Title"]);