در گیت هاب میتونید تعداد زیادی پروژه پیدا کنید که لیستی از منابع و لینکهای مفید رو برای یه زبون با یک فریم ورک خاص جمع کرده. مثلا awesome-javascript رو مشاهده کنید: https://github.com/sorrycc/awesome-javascript
حالا یک پروژه به نام awesome درست شده که لیستی از تمام این awesomeها رو تو خودش جمع کرده! و این واقعا عالیه
// Pure JavaScript errors handler window.addEventListener('error', function (err) { var lineAndColumnInfo = err.colno ? ' line:' + err.lineno +', column:'+ err.colno : ' line:' + e.lineno; _gaq.push([ '_trackEvent', 'JavaScript Error', err.message, err.filename + lineAndColumnInfo + ' -> ' + navigator.userAgent, 0, true ]); });
معرفی جیسان، JSON
موتور شبیه سازی فیزیک در محیط 2 بعدی
ASP.NET MVC #5
اگر بخواهیم از داخل کنترلرمون مقادیریمون را در قالب alert تو view نمایش بدیم باید چکار کرد؟
من خودم به این شکل عمل کردم
<script language="javascript" type="text/javascript"> alert(' @ViewData["ErrorMessage"]'); </script>
اصلا بهتر نیست از partialview استفاده کنم که یه view برای alert کلا داشته باشم؟
مرسی
var unicorn = { legs: 4, color: 'brown', horn: true };
var proxyUnicorn = new Proxy(unicorn, { get: function(target, property) { if(property === 'color') { return 'awesome ' + target[property]; } else { return target[property]; } } });
شیء Proxy در ES 6 دو پارامتر را دریافت میکند. پارامتر اول آن، شیء اصلی است که باید محصور شود و پارامتر دوم آن مشخص میکند که چه عملیاتی باید تحت کنترل و سفارشی سازی قرار گیرد. در این مثال عملیات get تحت نظر قرار گرفتهاست و برای اینکار متدی که تعریف شده (به آن handler نیز میگویند)، پارامتر اول آن target یا همان unicorn در این مثال است و property نام خاصیتی است که هم اکنون قرار است مقدار آن بازگشت داده شود. در مثال فوق دو حالت دسترسی به خاصیتی به نام color و همچنین سایر خواصی که این نام را ندارند، پیاده سازی شدهاست.
پس از این عملیات، اگر به خواص ارائه شدهی توسط شیء پروکسی دسترسی پیدا کنیم، یک چنین خروجی را دریافت خواهیم کرد:
console.log(proxyUnicorn.legs); //4 console.log(proxyUnicorn.color); //'awesome brown'
مثالی دیگر در این زمینه میتواند کنترل عملیات دسترسی به حالت set باشد (هر دوی این حالتها را با یک شیء پروکسی نیز میتوان مدیریت کرد):
var proxyUnicorn = new Proxy(unicorn, { set: function(target, property, value) { if(property === 'horn' && value === false) { console.log('unicorn cannot ever lose its horn!'); } else { target[property] = value; } } });
ردگیری فراخوانیهای توابع توسط پروکسیهای ES 6
در ادامه همان شیء unicorn را مشاهده میکنید که متد hornAttack نیز به آن اضافه شدهاست.
var unicorn = { legs: 4, color: 'brown', horn: true, hornAttack: function(target) { return target.name + ' was obliterated!'; } };
var thief = { name: 'Rupert'} thief.attack = unicorn.hornAttack; thief.attack();
unicorn.hornAttack = new Proxy(unicorn.hornAttack, { apply: function(target, context, args) { if(context !== unicorn) { return 'nobody can use unicorn horn but unicorn!'; } else { return target.apply(context, args); } } });
در ادامه اگر متد thief.attack فراخوانی شود، این فراخوانی عمل نکرده (چون حالت context !== unicorn برقرار است) و پیام «nobody can use unicorn horn but unicorn» نمایش داده میشود.
در این متد handler (پارامتر دوم شیء پروکسی) مواردی مانند افزودن یا حذف خواص را نیز میتوان تحت کنترل قرار داد:
function NOPE() { throw new Error("can't modify read-only view"); } var handler = { // Override all five mutating methods. set: NOPE, defineProperty: NOPE, deleteProperty: NOPE, preventExtensions: NOPE, setPrototypeOf: NOPE };
قابلیت چند زبانه و Localization در AngularJs- بخش چهارم و نهایی: Best Practiceهای angular-translate
ex7_load_static_files
<script src="Scripts/angular.js"></script> <script src="Scripts/angular-cookies.js"></script> <script src="Scripts/angular-translate.js"></script> <script src="Scripts/angular-translate-storage-cookie.js"></script> <!-- for override loader methods in angular translate --> <script src="/src/service/loader-static-files.js"></script>
// Register a loader for the static files // So, the module will search missing translation tables under the specified urls. // Those urls are [prefix][langKey][suffix]. $translateProvider.useStaticFilesLoader({ prefix: '/l10n/', suffix: '.json' });
حال ببینیم که این فرآیند در loader-static-files چگونه پیاده سازی شده است. در این فایل یک متد load نوشته شده است که فایلهای static را طبق یک الگوی مشتمل بر prefix و suffix از سرور میخواند. لزومی ندارد که شما فایلها را حتما به صورت JSON و با این پسوند ذخیره کنید. اما چیزی که قطعی است این است که فایلها حتما باید به صورت key value ذخیره شده باشند.
تکه کد زیر اطلاعات فایل loader-static-files را نمایش میدهد.
angular.module('pascalprecht.translate') .factory('$translateStaticFilesLoader', $translateStaticFilesLoader); function $translateStaticFilesLoader($q, $http) { 'use strict'; return function (options) { if (!options || (!angular.isArray(options.files) && (!angular.isString(options.prefix) || !angular.isString(options.suffix)))) { throw new Error('Couldn\'t load static files, no files and prefix or suffix specified!'); } if (!options.files) { options.files = [{ prefix: options.prefix, suffix: options.suffix }]; } var load = function (file) { if (!file || (!angular.isString(file.prefix) || !angular.isString(file.suffix))) { throw new Error('Couldn\'t load static file, no prefix or suffix specified!'); } var deferred = $q.defer(); $http(angular.extend({ url: [ file.prefix, options.key, file.suffix ].join(''), method: 'GET', params: '' }, options.$http)).success(function (data) { deferred.resolve(data); }).error(function () { deferred.reject(options.key); }); return deferred.promise; }; var deferred = $q.defer(), promises = [], length = options.files.length; for (var i = 0; i < length; i++) { promises.push(load({ prefix: options.files[i].prefix, key: options.key, suffix: options.files[i].suffix })); } $q.all(promises).then(function (data) { var length = data.length, mergedData = {}; for (var i = 0; i < length; i++) { for (var key in data[i]) { mergedData[key] = data[i][key]; } } deferred.resolve(mergedData); }, function (data) { deferred.reject(data); }); return deferred.promise; }; } $translateStaticFilesLoader.displayName = '$translateStaticFilesLoader';
همانطور که ملاحظه میکنید، کد فوق یک سرویس با نام $translateStaticFilesLoader را تعریف نموده است. در صورتیکه ما در کنترلر فایل ex7، اصلا نامی از آن نبردیم و تنها از $translateProvider.useStaticFilesLoader استفاده نمودیم! جواب در نحوهی نگارش کد angular-translate نهفته است. در خط 866 فایل angular-translate تکه کد زیر مربوط به تعریف translateStaticFileLoader میباشد. همانطور که ملاحظه میکنید سرویس translateStaticFilesLoader درون فضای نام سرویس translateTable قرار گرفته است. بنابراین ما تنها با تعریف سرویس translateStaticFilesLoader، در حقیقت آن را override نمودهایم. در کد نمونهای که در بخشهای قبلی قرار دادهام یک فایل translate.js نیز قرار دارد که در فولدر src/services قرار گرفته است. این فایل نیز برخی از امکانات و سرویسهای built-in درون angular-translate را سفارشی نموده است.
/** * @ngdoc function * @name pascalprecht.translate.$translateProvider#useStaticFilesLoader * @methodOf pascalprecht.translate.$translateProvider * * @description * Tells angular-translate to use `$translateStaticFilesLoader` extension service as loader. * * @param {Object=} options Optional configuration object */ this.useStaticFilesLoader = function (options) { return this.useLoader('$translateStaticFilesLoader', options); };
در این 4 مجموعه سعی کردم تمامی آنچه را که برای ایجاد قابلیت چند زبانه و localization نیاز است و حیاتی بود، تشریح کنم. بنابراین تا کنون دانش خوبی دربارهی این کتابخانه کسب نمودهاید. باقی تمرینها را میتوانید بر حسب نیاز با استفاده از مستندات موجود در angular-translate مطالعه و استفاده نمایید.
using System; namespace TestUsing { public class MyResource : IDisposable { public void DoWork() { throw new ArgumentException("A"); } public void Dispose() { throw new ArgumentException("B"); } } public static class TestClass { public static void Test() { using (MyResource r = new MyResource()) { throw new ArgumentException("C"); r.DoWork(); } } } }
try { TestClass.Test(); } catch (Exception ex) { Console.WriteLine(ex.Message); }
پاسخ: برخلاف تصور (که احتمالا C است؛ چون قبل از فراخوانی متد DoWork سبب بروز استثناء شده است)، فقط B را در خروجی مشاهده خواهیم کرد!
و این دقیقا مشکلی است که در حین کار با کتابخانه iTextSharp برای اولین بار با آن مواجه شدم. روش استفاده متداول از iTextSharp به نحو زیر است:
using (var pdfDoc = new Document(PageSize.A4)) { //todo: ... }
و خلاصه نتایج هم این است:
اگر به ثبت جزئیات خطاهای سیستم اهمیت میدهید (یکی از مهمترین مزیتهای دات نت نسبت به بسیاری از فریم ورکهای مشابه که حداکثر خطای 0xABC12EF را نمایش میدهند)، از using استفاده نکنید! using در پشت صحنه به try/finally ترجمه میشود و بهتر است این مورد را دستی نوشت تا اینکه کامپایلر اینکار را به صورت خودکار انجام دهد.
در اینجا باز هم به یک سری کد تکراری try/finally خواهیم رسید و همانطور که در مباحث کاربردهای Action و Func در این سایت ذکر شد، میتوان آنرا تبدیل به کدهایی با قابلیت استفاده مجدد کرد. یک نمونه از پیاده سازی آنرا در این سایت «C# Using Blocks can Swallow Exceptions » میتوانید مشاهده کنید که خلاصه آن کلاس زیر است:
using System; namespace Guard { public static class SafeUsing { public static void SafeUsingBlock<TDisposable>(this TDisposable disposable, Action<TDisposable> action) where TDisposable : IDisposable { disposable.SafeUsingBlock(action, d => d); } internal static void SafeUsingBlock<TDisposable, T>(this TDisposable disposable, Action<T> action, Func<TDisposable, T> unwrapper) where TDisposable : IDisposable { try { action(unwrapper(disposable)); } catch (Exception actionException) { try { disposable.Dispose(); } catch (Exception disposeException) { throw new AggregateException(actionException, disposeException); } throw; } disposable.Dispose(); } } }
new Document(PageSize.A4).SafeUsingBlock(pdfDoc => { //todo: ... });
بهبود SEO در ASP.NET MVC
به گزارشهای گوگل در مورد سایت جاری که نگاه میکردم، تمام لینکهای به صفحات جستجوی سایت را مثلا https://www.dntips.ir/search?term=seo تکراری گزارش کرده بود (تعداد زیادی بودند). چون عنوان قبلی صفحه جستجو، فقط «جستجو» بود (یک عنوان همیشه ثابت). بعد از اینکه عنوان را تبدیل کردم به «جستجو + عبارت وارد شده»، گزارش موارد تکراری آن برطرف شد.