a color picker based on AngularJS Demo
پیشنیازها
برای این مطلب از دو کتابخانهی moment-jalaali، برای تبدیل تاریخ، از میلادی به شمسی و برعکس، استفاده خواهیم کرد. همچنین کنترل انتخاب تاریخ نیز از کتابخانهی MD.BootstrapPersianDateTimePicker تامین میشود.
moment-jalaali را میتوانید به صورت ذیل از طریق npm نصب کنید:
npm install moment-jalaali --save
node_modules/moment/min/moment.min.js node_modules/moment-jalaali/build/moment-jalaali.js
MD.BootstrapPersianDateTimePicker را یا از طریق نیوگت نصب کنید و یا مخزن کد آنرا به صورت کامل دریافت کنید:
Install-Package MD.BootstrapPersianDateTimePicker
همچنین فایلهای jalaali.js و jquery.Bootstrap-PersianDateTimePicker.js آنرا نیز به مداخل اسکریپتهای صفحهی خود اضافه نمائید.
در کل اگر از ASP.NET Core استفاده میکنید، فایل bundleconfig.json یک چنین شکلی را پیدا خواهد کرد. در این حالت فایل layout برنامه تنها این دو مدخل نهایی را نیاز خواهد داشت:
<link href="~/css/site.min.css" rel="stylesheet" asp-append-version="true" /> <script src="~/js/site.min.js" type="text/javascript" asp-append-version="true"></script>
فعالسازی کنترل انتخاب تاریخ شمسی بجای کامپوننت پیش فرض انتخاب تاریخ Kendo UI
پس از افزودن ارجاعات مورد نیاز، اکنون فرض ما بر این است که ستون تاریخ، دقیقا با فرمت میلادی از سمت سرور دریافت میشود و addDate نام دارد.
پس از آن، مرحلهی اول کار، نمایش این تاریخ میلادی به صورت شمسی است:
{ field: "addDate", title: "تاریخ ثبت", template: "#=moment(addDate).format('jYYYY/jMM/jDD')#",
در ادامهی تکمیل خواص ستون جاری، خاصیت editor را اضافه خواهیم کرد:
editor: function(container, options) { }
در ادامه نیاز است یک input field سفارشی را در اینجا درج کنیم تا کار نمایش کنترل انتخاب تاریخ شمسی را انجام دهد:
// دریافت تاریخ میلادی و تبدیل آن به شمسی جهت نمایش در تکست باکس var persianAddDate = moment(options.model.addDate).format('jYYYY/jMM/jDD'); // ایجاد کنترل انتخاب تاریخ سفارشی با مقدار تاریخ شمسی دریف جاری var input = $('<div dir="ltr" class="input-group">'+ '<div class="input-group-addon" data-name="datepicker1" data-mddatetimepicker="true" data-trigger="click" data-targetselector="#' + options.field + '" data-fromdate="false" data-enabletimepicker="false" data-englishnumber="true" data-placement="left">'+ '<span class="glyphicon glyphicon-calendar"></span>'+ '</div>'+ '<input type="text" value="'+ persianAddDate +'" class="form-control" id="' + options.field + '" placeholder="از تاریخ" data-mddatetimepicker="true" data-trigger="click" data-targetselector="#' + options.field + '" data-englishnumber="true" data-fromdate="true" data-enabletimepicker="false" data-placement="right" />'+ '</div>'); // افزودن کنترل جدید به صفحه input.appendTo(container);
متد input.appendTo، کار افزودن این input جدید را به container یا همان محل نمایش ستون جاری، انجام میدهد.
در این حالت اگر برنامه را اجرا کنید، هرچند ظاهر Input جدید تغییر کردهاست، اما سبب نمایش کنترل انتخاب تاریخ نمیشود؛ چون این فیلد ویرایشی، پس از رندر صفحه، به صفحه اضافه شدهاست. به همین جهت نیاز است متد EnableMdDateTimePickers نیز فراخوانی شود. این متد کار فعالسازی input جدید را انجام خواهد داد:
// با خبر سازی کتابخانه انتخاب تاریخ از تکست باکس جدید EnableMdDateTimePickers();
تا اینجا موفق شدیم بجای کنترل انتخاب تاریخ میلادی، کنترل انتخاب تاریخ شمسی را نمایش دهیم. اما تاریخی که انتخاب میشود نیز شمسی است و تاریخی که به سمت سرور ارسال خواهد شد، میلادی میباشد. به همین جهت تغییرات این کنترل را تحت نظر قرار داده و هر زمانیکه کاربر تاریخی را انتخاب کرد، آنرا به میلادی تبدیل کرده و بجای فیلد addDate اصلی تنظیم میکنیم:
// هر زمانیکه کاربر تاریخ جدیدی را وارد کرد، آنرا به میلادی تبدیل کرده و در مدل ردیف جاری ثبت میکنیم // در نهایت این مقدار میلادی است که به سمت سرور ارسال خواهد شد $('#' + options.field).change(function(){ var selectedPersianDate = $(this)[0].value; var gregorianAddDate = moment(selectedPersianDate, 'jYYYY/jMM/jDD').format('YYYY-MM-DD'); options.model.set('addDate', gregorianAddDate); });
تنها مرحلهی باقیمانده، مخفی کردن این کنترل نمایش تاریخ، با از دست رفتن فوکوس است:
// با از دست رفتن فوکوس نیاز است این کنترل مخفی شود $('#' + options.field).blur(function(){ $('[data-name="datepicker1"]').MdPersianDateTimePicker('hide'); });
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید: با این کنترلر و این View
وارد کردن کتابخانه ها
این کتابخانه شامل دو فایل css و JS میباشد که بسته به محیطی که در آن کار میکنید متفاوت هستند. در این صفحه شما میتوانید برای 4 محیط Jquery ,JqueryUI , Bootstrap2 و Bootsrap3 بستهی مخصوصش را یا به صورت دانلود فایلها یا از طریق CDN دریافت نمایید. در اینجا هم یک دمو از قابلیتهای آن قابل مشاهده است.
برای شروع، کتابخانهی مورد نظر خود را دریافت و آنها را به صفحهی خود اضافه نمایید. در صورتیکه از Bootstrap استفاده میکنید، ابتدا فایلهای زیر را اضافه کنید:
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"> <script src="http://code.jquery.com/jquery-2.0.3.min.js"></script> <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
اولین حالتیکه میتوانید با این کتابخانه کار کنید، استفاده از خاصیت *-data است. نمونه زیر را در نظر بگیرید:
<a href="#" id="favsite" data-type="text" data-pk="1" data-url="@Url.Action(MVC.Categories.EditCategory())" data-title="Enter your favorite site">dotnettips.info</a>
$(document).ready(function () { $('#favsite').editable(); });
$(document).ready(function () { $.fn.editable.defaults.mode = 'inline'; $('#favsite').editable(); });
حالت بعدی که میتوان استفاده کرد به شکل زیر است:
<a href="#" id="favsite" >dotnettips.info</a>
$.fn.editable.defaults.mode = 'inline'; $(document).ready(function () { $('#favsite').editable({ type: 'text', pk: 1, url: '@Url.Action(MVC.Categories.EditCategory())', title: 'Enter your favorite site' }); });
خوبی این روش این است که میتوان اطلاعات بیشتری چون رویدادها را به آن پاس داد. تا الان با نحوهی انتساب آن به اشیاء آشنا شدیم. اجازه دهید تا با خصوصیات آن آشنا شویم.
AjaxOptions | همانطور
که متوجه شدید به طور خودکار اطلاعات ویرایش شده، به سمت آدرس داده شده،
به شیوه Post ارسال میگردند. در صورتیکه قصد دست بردن
در نوع درخواست را دارید، میتوانید از این ویژگی استفاده کنید: ajaxOptions: { type: 'put', dataType: 'json' } |
Anim | این
ویژگی که تنها در حالت inline پاسخ میدهد، میتواند زمان بسته شدن
x-editable را تغییر دهد که به طور پیش فرض با false مقداردهی شده است. جهت
تغییر زمان بسته شدن، کد زیر را وارد نمایید: anim:'false' //or anim: { duration: 2000 } |
autotext | در انتهای جدول آمده است. |
defaultValue | در
صورتیکه عنصر مورد نظر محتوایی نداشته باشد و این خصوصیت را
مقداردهی کنید، موقع ویرایش، این عبارت تعیین شده نمایش مییابد. در مثال
بالا باید متن تگ a را حذف کرده تا نتیجه را ببینید: (البته فیلد value نباید مقداری داشته باشد) defaultValue: 'default val' //or defaultValue: undefined //or defaultValue: null |
disabled | false کردن این ویژگی باعث غیرفعال شدن x-editable بر روی کنترل جاری میگردد. |
display | خاصیت
display یا مقدار بولین false را دریافت میکند، یا نال، یا یک تابع
callback را میتوان به آن پاس داد. این خصوصت زمانی صدا زده میشود که
اطلاعات به سمت آدرس سرور رفته و با موفقیت بازگشت داده میشوند (در صورتی
که این ویژگی غیرفعال باشد، بلافاصه بعد از تایید کاربر، از اطلاعات وارد شده
صدا زده میشود) و سپس متن جدید عنصر تغییر مییابد. حال اگر این خاصیت نال
که مقدار پیش فرض آن است باشد، متن تغییر مییابد. ولی اگر false باشد، متن سابق
باقی خواهد ماند و در صورتیکه تابعی به آن پاس داده باشید، طبق تابع شما
عمل خواهد کرد. پارامترهایی که تابع شما میتواند داشته باشد به شرح زیر است: value : مقدار جدید response : پاسخ سرور ( در صورتی که ارسال از طریق Ajax صورت گرفته باشد) و در صورتیکه عنصر شما checlklist یا select باشد که حاوی منبعی از مقادیر هست، مقادیرشان در قالب یک آرایه با نام sourceData بازگشت خواهد خورد. برای دسترسی به آیتمهای انتخابی هم از کد زیر استفاده میکنیم: $.fn.editableutils.itemsByValue(value, sourceData) |
emptyclass | معرفی یک کلاس css برای موقعیکه عنصر خالی است. |
emptytext | در صورتی خالی بودن عنصر، این متن را برای عنصر نمایش بده. |
highlight | بعد از به روز رسانی متن عنصر، آن را با این رنگ highlight خواهد کرد و کد رنگی باید در مبنای هگز باشد. مقدار پیش فرض آن false است. |
mode | دو
حالت نمایشی دارد که پیش فرض آن popup است و با باز کردن یک پنجره، مقدار
جدید را دریافت میکند. مورد بعدی inline است که به جای باز کردن پنجره،
متن عنصر را به حالت ویرایش تغییر میدهد. |
name | نام فیلدی که مقدارش تغییر میکند. |
onblur | زمانی که کاربر فوکوس را از ویرایشگر میگیرد، ویرایشگر چه پاسخی باید به آن بدهد، باز بماند؟ ignore ، بسته شود؟ cancel و یا مقدار داده شده را تایید کند؟submit |
params | پارامترهای درخواست ایجکسی که کنترل در حالت پیش فرض ارسال میکند؛ شامل Pk که آن را با id
رکورد پر میکنیم. name نام فیلدی که تغییر یافته است و value که مقدار جدید
است. در صورتیکه دوست دارید اطلاعات اضافیتری نیز ارسال شوند،
میتوانید از این خاصیت استفاده کنید و پارامترها را در قالب Object به آن
پاس کنید. ولی اگر بخواهید در کل همهی پارامترها را رونویسی کنید باید یک
تابع را به آن پاس کنید: params: function(params) { //در این حالت پارامترهای پیش فرض ارسال نشده و تنها پارامترهای معرفی شده در این تابع ارسال میشوند params.a = 1; return params; } |
pk | کلید
اصلی رکورد شما در دیتابیس یا هان id است. در صورتی که از کلیدهای ترکیبی
استفاده میکنید، نگران نباشید فکر آن را هم کرده اند.//کلید عدد pk:1, //کلید رشته ای pk:'dp123' //کلید ترکیبی pk:{id: 1, lang: 'en'} //معرفی یک تابع به آن و بازگشت |
Placement | این ویژگی فقط به درد حالت Popup میخورد که پنجره را کجای عنصر نمایش دهد و شامل چهار مقدار left,right,top,bottom میشود. |
saveonchange | زمانی
که مقدار جدید، برابر مقدار فعلی باشد و این خاصیت false باشد، هیچ تغییری رخ
نخواهد داد. ولی اگر برابر true باشد ،مقدار جدید اسال و جایگزین مقدار فعلی
خواهد شد. مقدار پیش فرض آن false است. |
selector |
با استفاده از این خصوصیت در عنصر انتخابی به دنبال عناصری که در selector
تعیین شده میگردد و حالت ویرایش را روی آنها فعال میکند. در این حالت استفاده از خصوصیات emptytext و autotext در ابتدای امر ممکن نیست و بعد از اولین کلیک قابل استفاده هستند. نکته بعدی اینکه شما باید کلاسهای زیر را دستی اضافه کنید. کلاس editable-click برای همه کنترلها وکلاس editable-empty به کنترلهای بدون مقدار و برای مقداردهی کنترلهای بدون مقدار میتوان از خاصیت ''=data-value استفاده کرد. <div id="user"> <!-- empty --> <a href="#" data-name="username" data-type="text" data-value="" title="Username">Empty</a> <!-- non-empty --> <a href="#" data-name="group" data-type="select" data-source="/groups" data-value="1" title="Group">Operator</a> </div> <script> $('#user').editable({ selector: 'a', url: '/post', pk: 1 }); </script> |
send | سه
مقدار auto,always و never را دریافت میکند. موقعی که شما آن را روی auto
تنظیم کنید؛ در صورتی مقادیر به سمت سرور ارسال میشوند که دو خاصیت url و
pk تعریف شده باشند. در غیر این صورت ویرایش فقط در حالت محلی و روی سیستم
کاربر رخ خواهد داد. |
showbuttons | در
صورتیکه با false مقداردهی شود، تایید فرم به طور خودکار انجام میگیرد و
اگر با یکی از مقادیر left یا Bottom پر شود، دکمهها را در آن قسمت نشان
میدهد. |
success | اطلاعات به سمت سرور
رفته و با موفقیت با کد 200 بازگشت داده شدهاند. در مستندات نوشته است، هر
کد وضعیتی غیر از 200 بازگشت داده شود، به سمت خاصیت error هدایت میشو.د ولی
آن طور که من با httpresponsemessage
تست کردم، چنین چیزی را مشاهده نکردم و مجددا success صدا زده شد. پس بهتر
هست دادهای را که به سمت کنترل برگشت میدهید، خودتان کنترل کنید. به خصوص
اگر انتقال اطلاعات صحیح باشد. ولی اگر در دیتابیس، تغییر با خطا روبرو گردد
بهتر است نتیجهی آن ارسال شده و از تغییر مقدار فعلی ممانعت به عمل آورید. success: function(response, newValue) { if(!response.success) return response.msg; } |
toggle | اگر قصد دارید که باز و بسته کردن ویرایشگر را بر عهدهی مثلا یک دکمهی روی صفحه بگذارید، این خصوصیت به شما کمک میکند:$('#edit-button').click(function(e) { e.stopPropagation(); $('#favsite').editable('toggle'); }); |
type | نوع
ویرایشی را که قرار است انجام گیرد، مشخص میکند. text برای متن، date برای
تاریخ، textarea جهت متون طولانیتر نسبت به text و بسیاری از موارد دیگر |
unsavedclass | این
کلاس موقعی اعمال میگردد که اطلاعاتی را ویرایش کردهاید، ولی اطلاعاتی
به سمت سرور ارسال نشده است. مثلا pk مقداردهی نشده یا send=never قرار
داید و یا اینکه به صورت محلی ذخیره میکنید و میخواهید در آخر همهی اطلاعات را
ارسال کنید. این خاصیت به طور پیش فرض با کلاس editable-unsaved مقداردهی شده که میتوانید با نال کردن، از شرش خلاص شوید. |
url | این
خاصیت با آدرس سمت سرور پر میشود. ولی میتوان به آن یک تابع هم پاس کرد که
این تابع جایگزین درخواست ایجکسی خودش خواهد شد و برای بازگشت دادن نتیجهی این درخواست به سمت تابعهای callback خودش میتوانید یک deferred object را برگشت دهید: url: function(params) { var d = new $.Deferred; if(params.value === 'abc') { //returning error via deferred object return d.reject('error message'); } else { //async saving data in js model someModel.asyncSaveMethod({ ..., success: function(){ d.resolve(); } }); return d.promise(); } } |
validate | مقدار
پیش فرض آن نال است و میتوان به آن یک تابع را جهت اعتبارسنجی سمت کلاینت پاس
داد. به عنوان آرگومان، مقدار جدیدی را ارسال کرده و در آن به اعتبارسنجی
میپردازید. در صورتی که مقدار، نامعتبر باشد، میتوانید یک پیام خطا از نوع
رشتهای را برگردانید. در صورتی که از نسخهی 1.5.1 به بعد استفاده میکنید، دریافت یک object با مقادیر زیر نیز ممکن شده است: newValue: مقدار جدید و جایگزین مقدار غیر معتبر. msg : پیام خطا. به کدهای زیر در سه حالت نگاه کنید: validate: function (value) { if ($.trim(value) == '') { //در تمامی نسخههای یک پیام متنی باز میگردد return 'This field is required'; //1.5.1 //یک مقدار جدید برگشت میدهد که بلافاصله آن را // تایید میکند و متن عنصر به روز میشود return { newValue: 'validated' }; //متن جدید ار ارسال کرده و پیام هشدار را نشان میدهد //ولی تایید نمیکند و منتظر تایید کاربر است return { newValue: 'validated', |
value | مقدار پیش فرضی که در ویرایشگر نشان میدهد و اگر مقداردهی نشود، از متن عنصر استفاده میکند. |
autotext | سه مقدار دارد auto (پیش فرض)،always و never. موقعیکه عنصر شما متنی نداشته باشد و روی auto تنظیم شده باشد، مقدار value را به عنوان متن عنصر نمایش میدهد. always کاری ندارد که عنصر شما متن دارد یا خالی است؛ مقدار value به آن انتساب داده خواهد شد. never هیچگاه. |
در قسمت بعدی که قسمت پایانی است مطالب را ادامه میدهیم.
<script src="cordova.js"></script>
مثال برای اندروید
(function () { "use strict"; document.addEventListener( 'deviceready', onDeviceReady.bind( this ), false ); function onDeviceReady() { // Handle the Cordova pause and resume events document.addEventListener( 'pause', onPause.bind( this ), false ); document.addEventListener('resume', onResume.bind(this), false); document.addEventListener('menubutton', onMenuButton.bind(this), false); document.addEventListener('backbutton', onBackButton.bind(this), false); //document.addEventListener('searchbutton', onResume.bind(this), false); //document.addEventListener('endcallbutton', onResume.bind(this), false); //document.addEventListener('offline', onResume.bind(this), false); //document.addEventListener('online', onResume.bind(this), false); //document.addEventListener('startcallbutton', onResume.bind(this), false); //document.addEventListener('volumedownbutton', onResume.bind(this), false); //document.addEventListener('volumeupbutton', onResume.bind(this), false); // TODO: Cordova has been loaded. Perform any initialization that requires Cordova here. }; function onPause() { // TODO: This application has been suspended. Save application state here. alert("paused"); }; function onResume() { alert("resume"); }; function onMenuButton() { alert("menu"); }; function onBackButton() { alert("back button"); }; } )();
.در مقالات آینده از افزونههای موجود، برای مدیریت رخدادهای باتری سیستم استفاده خواهیم کرد
jQuery Mobile
Phones/Tablets
Android 1.6+
BlackBerry 5+
iOS 3+
Windows Phone 7
WebOS 1.4+
Symbian (Nokia S60)
Firefox Mobile Opera Mobile 11+
Opera Mini 5+
Desktop browsers
Chrome 11+
Firefox 3.6+
Internet Explorer 7+
Safari
برای نصب jQuery Mobile کافی است دستورات زیر را در package manager console ویژوال استودیو استفاده کنید:
PM>install-package jquery
PM>install-package jquery.mobile.rtl
بعد از دانلود فایلهای مورد نظر خود، فولدری بنام jquery.mobile.rtl در ریشه پروژه ایجاد خواهد شد. به ترتیب فایل های rtl.jquery.mobile-1.4.0.css و rtl.jquery.mobile-1.4.0.js موجود در زیر شاخههای فلدر مذکور را به head و آخر body فایل index.html اضافه کنید.
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>CordovaApp01</title> <!-- CordovaApp01 references --> <link href="css/index.css" rel="stylesheet" /> <link href="jquery.mobile.rtl/css/themes/default/rtl.jquery.mobile-1.4.0.css" rel="stylesheet" /> </head> <body> <div data-role="page" id="page1"> <div data-role="header"> <h1>اولین برنامه</h1> </div> <div data-role="content"> <p>سلام من محتوای اولین برنامه هستم</p> </div> <div data-role="footer"> <h1>من فوتر هستم</h1> </div> </div> <!-- Cordova reference, this is added to your app when it's built. --> <script src="scripts/jquery-2.1.3.min.js"></script> <script src="cordova.js"></script> <script src="scripts/platformOverrides.js"></script> <script src="scripts/index.js"></script> <script src="jquery.mobile.rtl/js/rtl.jquery.mobile-1.4.0.js"></script> </body> </html>
نتیجهی نهایی به شکل زیر خواهد بود:
در مقالهی بعد به استفاده از pluginها خواهیم پرداخت.
ادامه دارد...
ViewEngine.ViewLocationFormats= "~/Views/{controller}/{action}.cshtml"
"~/Themes/{ThemeName}/Views/{controller}/{action}.cshtml"
public static void Themeable(this VirtualPathProviderViewEngine engine) { var ThemePath = "~/Themes"; var ThemeName = WebConfigurationManager.AppSettings["MvcTheme"]; if (string.IsNullOrEmpty(ThemeName)) return; var themeFolder = HttpContext.Current.Server.MapPath(string.Format("{0}/{1}/", ThemePath, ThemeName)); if (!Directory.Exists(themeFolder)) throw new DirectoryNotFoundException(string.Format("Theme folder not exists: {0}/{1}}", ThemePath, ThemeName)); var newViewLocations = new[] { string.Format("{0}/{1}/Views/{2}/{3}.cshtml", ThemePath, ThemeName, "{1}", "{0}"), string.Format("{0}/{1}/Views/Shared/{2}.cshtml", ThemePath, ThemeName, "{0}"), // vb.net : // string.Format("{0}/{1}/Views/{2}/{3}.vbhtml", ThemePath, ThemeName, "{1}", "{0}"), // string.Format("{0}/{1}/Views/Shared/{2}.vbhtml", ThemePath, ThemeName, "{0}"), }; engine.ViewLocationFormats = newViewLocations; engine.PartialViewLocationFormats = newViewLocations; }
<appSettings> ... <add key="MvcTheme" value="Test1" /> </appSettings>
ViewEngines.Engines.OfType<RazorViewEngine>().Single().Themeable();
@{ // Layout = "~/Views/Shared/_Layout.cshtml"; Layout = "~/themes/test1/Views/Shared/_Layout.cshtml"; }
public class ThemeBundle { public BundleType BundleType { get; set; } public string VirtualPath { get; set; } public string[] Urls { get; set; } } public enum BundleType { Style, Script }
public static void RegisterThemeBundels(BundleCollection bundles) { var ThemePath = "~/Themes"; var ThemeName = WebConfigurationManager.AppSettings["MvcTheme"]; var ThemeBundleFileName = "ThemeBundle.json"; List<ThemeBundle> list; try { JavaScriptSerializer jss = new JavaScriptSerializer(); var jsonaddress = System.Web.HttpContext.Current.Server.MapPath(string.Format("{0}/{1}/{2}", ThemePath, ThemeName, ThemeBundleFileName)); var json = System.IO.File.ReadAllText(jsonaddress); list = jss.Deserialize<List<ThemeBundle>>(json); } catch (Exception ex) { throw new Exception(string.Format("Cannot read {0}. see more error in inner exception.", ThemeBundleFileName), ex); } foreach (var themeBundle in list) { switch (themeBundle.BundleType) { case BundleType.Script: bundles.Add(new ScriptBundle(themeBundle.VirtualPath).Include( themeBundle.Urls)); break; case BundleType.Style: bundles.Add(new StyleBundle(themeBundle.VirtualPath).Include( themeBundle.Urls)); break; default: throw new ArgumentOutOfRangeException(nameof(themeBundle.BundleType)); } } }
public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { if (MvcTheme.ThemeName != null) { MvcTheme.RegisterThemeBundels(bundles); return; } bundles.Add(new ScriptBundle("~/bundles/jquery").Include( "~/Scripts/jquery-{version}.js")); bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include( "~/Scripts/jquery.validate*")); ... } }
[ { "BundleType": "Script", "VirtualPath": "~/themes/test1/js/jquery", "Urls": [ "~/themes/test1/js/jquery-1.10.2.js" ] }, { "BundleType": "Script", "VirtualPath": "~/themes/test1/js/jqueryval", "Urls": [ "~/themes/test1/js/jquery.validate.js", "~/themes/test1/js/jquery.validate.unobtrusive.js" ] }, { "BundleType": "Script", "VirtualPath": "~/themes/test1/js/modernizr", "Urls": [ "~/themes/test1/js/modernizr-2.6.2.js" ] }, { "BundleType": "Script", "VirtualPath": "~/themes/test1/js/bootstrap", "Urls": [ "~/themes/test1/js/bootstrap.js", "~/themes/test1/js/respond.js" ] }, { "BundleType": "Style", "VirtualPath": "~/themes/test1/css/css", "Urls": [ "~/themes/test1/css/bootstrap.css", "~/themes/test1/css/site.css" ] } ]
Themes ├───Test1 │ │ThemeBundle.json │ ├───Css │ ├───Fonts │ ├───Images │ ├───Js │ └───Views ├───Test2 │ │ThemeBundle.json │ ├───Css │ ├───Fonts │ ├───Images │ ├───Js │ └───Views
public static class MvcTheme { public static string ThemeName { get; } public static string ThemePath { get; set; } private const string AppSettingName = "MvcTheme"; private const string ThemeBundleFileName = "ThemeBundle.json"; static MvcTheme() { ThemePath = "~/Themes"; ThemeName = WebConfigurationManager.AppSettings[AppSettingName]; } public static void Themeable(this VirtualPathProviderViewEngine engine) { if (string.IsNullOrEmpty(ThemeName)) return; var themeFolder = HttpContext.Current.Server.MapPath(string.Format("{0}/{1}/", ThemePath, ThemeName)); if (!Directory.Exists(themeFolder)) throw new DirectoryNotFoundException(string.Format("Theme folder not exists: {0}/{1}}", ThemePath, ThemeName)); var newViewLocations = new[] { string.Format("{0}/{1}/Views/{2}/{3}.cshtml", ThemePath, ThemeName, "{1}", "{0}"), string.Format("{0}/{1}/Views/Shared/{2}.cshtml", ThemePath, ThemeName, "{0}"), // vb.net : // string.Format("{0}/{1}/Views/{2}/{3}.vbhtml", ThemePath, ThemeName, "{1}", "{0}"), // string.Format("{0}/{1}/Views/Shared/{2}.vbhtml", ThemePath, ThemeName, "{0}"), }; engine.ViewLocationFormats = newViewLocations; engine.PartialViewLocationFormats = newViewLocations; } public static void RegisterThemeBundels(BundleCollection bundles) { if(ThemeName == null) return; var list = ReadThemeBundles(); foreach (var themeBundle in list) { switch (themeBundle.BundleType) { case BundleType.Script: bundles.Add(new ScriptBundle(themeBundle.VirtualPath).Include( themeBundle.Urls)); break; case BundleType.Style: bundles.Add(new StyleBundle(themeBundle.VirtualPath).Include( themeBundle.Urls)); break; default: throw new ArgumentOutOfRangeException(nameof(themeBundle.BundleType)); } } } public static List<ThemeBundle> ReadThemeBundles() { try { JavaScriptSerializer jss = new JavaScriptSerializer(); var jsonaddress = System.Web.HttpContext.Current.Server.MapPath(string.Format("{0}/{1}/{2}", ThemePath, ThemeName, ThemeBundleFileName)); var json = System.IO.File.ReadAllText(jsonaddress); var list = jss.Deserialize<List<ThemeBundle>>(json); return list; } catch (Exception ex) { throw new Exception(string.Format("Cannot read {0}. see more error in inner exception.", ThemeBundleFileName), ex); } } } public class ThemeBundle { public BundleType BundleType { get; set; } public string VirtualPath { get; set; } public string[] Urls { get; set; } } public enum BundleType { Style, Script }
قابلیتهای نسخههای مختلف Sql Server Express 2008
نسخه / قابلیت | Database Engine | Management Studio Basic | Full-Text Search | Reporting Services |
Management Studio Basic | X | |||
Runtime Only | X | |||
with Tools | X | X | ||
with Advanced Services | X | X | X | X |
(SQL Server 2008 Express (Runtime Only
SQL Server 2008 Express with Tools
SQL Server 2008 Express with Advanced Services
دو حالت برای نصب SQL Server وجود دارد:
نصب SQL Server Express 2008 از طریق Command Prompt
Setup.exe /q /Action=Install /Hideconsole /Features=SQL,Tools /InstanceName=SQLExpress /SQLSYSADMINACCOUNTS="Builtin\Administrators" /SQLSVCACCOUNT="<DomainName\UserName>" /SQLSVCPASSWORD="<StrongPassword>
باتوجه به سیاستها نصب میتوانید از پارامترها دیگری نیز استفاده کنید. بعنوان مثال پارامترهای زیر برای نصب روی سیستمی که نام کاربری و پسورد انرا نداریم مناسب است:
setup.exe /q /Action=Install /Features=SQL /InstanceName=SQLExpress /SECURITYMODE=SQL /SAPWD="1234567" /SQLSYSADMINACCOUNTS="Builtin\Administrators" /SQLSVCACCOUNT="NT AUTHORITY\SYSTEM" /SQLSVCSTARTUPTYPE="Automatic" /TCPENABLED=1
Setup.exe /q /Hideconsole /ACTION=upgrade /INSTANCENAME=SQLExpress
برای مشاهده دیگر پارامترها به مستندات MSDN مراجعه کنید. همچنین میتوان نصب از طریق فایل Configuration را نیز انجام داد.
یک Profiler رایگان
یک سینتکس جدید برای توابع
var myFunction = function(arg) { return arg.toUpperCase(); };
var myFunction = (arg) => arg.toUpperCase();
var digits = [1,2,3,4,5,6]; var even = digits.filter( x => x%2 === 0); // فیلتر بر اساس یک شرط var evenSquares = even.map( x => x*x ); console.log(even, evenSquares); //[2,4,6] [4,16,36]
- توابع arrow زمانیکه داخل بدنهی آنها بیش از یک عبارت قرار گیرد لازم است که به طور صریح از کلید واژه return استفاده شود.
- برای برگشت یک شیء خالی باید از سینتکس زیر استفاده کنیم:
const emptyObject = () => {}; emptyObject(); // ? در این حالت یک باگ به حساب میآید //باید دقت شود که اکولادها را در بین پرانتزها قرار دهیم تا تابع به درستی کار کند const emptyObject = () => ({}); emptyObject(); // {}
- تمامی ویژگیهایی را که برای پارمترها گفته شد، میتوان برای توابع arrow بکار برد.
function () { return arguments[0]; } (...args) => args[0]
let NotGood = () => {}; let wontWork = new NotGood();
this لکسیکال (lexical) یا نحوی
$('.current-time').each(function () { setInterval(function () { $(this).text(Date.now()); }, 1000); });
$('.current-time').each(function () { var self = this; setInterval(function () { $(self).text(Date.now()); }, 1000); });
$('.current-time').each(function () { setInterval(function () { $(this).text(Date.now()); }.bind(this), 1000); });
$('.current-time').each(function () { setInterval(() => $(this).text(Date.now()), 1000); });