مطالب
آشنایی با ساختار IIS قسمت هفتم

در این قسمت بیشتر یک سری از ماژول‌ها را به شما در قالب جداول گروه بندی شده معرفی خواهیم کرد :

   همانطور که در قسمت‌های قبلی گفتیم سرور IIS آماده خصوصی سازی و کار بر اساس علائق شماست؛ ولی توجه داشته باشید حذف تمامی ماژول‌ها ممکن است اثرات جانبی هم داشته باشد. در اینجا ما ماژول هایی را به شما معرفی می‌کنیم که بدانید کار هر ماژول چیست تا مثلا با حذف ماژولی، امنیت وب سایت خود را به خطر نیندازید :

ماژول‌های سودمند یا utility

نام ماژول:

UriCacheModule

توضیح:

این ماژول نوعی کش برای URLها به شمار می‌رود. موقعی که url درخواست می‌شود، اطلاعات در اولین درخواست خوانده شده و کش می‌شود و اگر دوباره همان url درخواست شود، بدون خواندن تنظیمات و بر اساس تنظیمات قبلی، کار url مربوطه را انجام میدهد تا اطلاعات پیکربندی تغییر کند و بر اساس اطلاعات جدید، خود را به روز کند.

تگ قابل پیکربندی:

لازم ندارد

وابستگی:

ندارد

اثرات حذف آن:

کارایی سیستم کاهش می‌یابد و سیستم مجبور است برای هر درخواست فایل پیکربندی را بخواند.

نام ماژول :

FileCacheModule

توضیح :

فایل هندلِ فایل‌هایی که قبلا در سرور باز شده‌اند را کش می‌کند تا در صورت نیاز در دفعات بعدی سریعتر عمل کند.

تگ قابل پیکربندی :

لازم ندارد .

وابستگی :

ندارد.

اثرات حذف آن :

کارایی سیستم کاهش می‌یابد. سیستم در هر اجرای دستور مربوط به فایل‌ها باید فایل هندل را به دست آورد.

نام ماژول :

TokenCacheModule

توضیح :

توکن‌های امنیتی ویندوز که پسوردهایی بر اساس authentication schemes هستند را کش می‌کند (anonymous authentication, basic authentication, IIS client certificate authentication )

تگ قابل پیکربندی :

لازم ندارد

وابستگی :

ندارد

اثرات حذف آن :

کارایی سیستم به شدت پایین می‌آید. کاربر باید با هر درخواستی لاگین کند. یکی از اصلی‌ترین ضربه‌ها با حذف این ماژول این است که اگر مثلا یک پسورد از یک فایل html محافظت می‌کند و این صفحه به 50 تصویر ارجاع دارد، 51 بار باید درخواست لاگین اجرا گردد یا شاید هم بدتر

MANAGED ENGINE: ASP.NET INTEGRATION

نام ماژول :

ManagedEngine

توضیح :

مدیریت ماژول‌های native و مدیریت شده

تگ قابل پیکربندی :


وابستگی :

ندارد

اثرات حذف آن :

مشخصا غیرفعال شدن asp.net integrated و غیر فعال شدن تمامی ماژول‌ها و هندلر‌های تگ وب کانفیگ یا داخل فایل کانفیگ IIS که در مقالات قبلی به تفصیل بیان کرده‌ایم.

IIS 7 NATIVE MODULES

نام ماژول :

HttpCacheModule

توضیح :

مدیریت کش خروجی در htttp.sys بر اساس پیکربندی مثل تعریف سایز کش و ...

تگ قابل پیکربندی :

System.webServer/caching

وابستگی :

ندارد.

اثرات حذف آن :

محتوا دیگر به صورت کرنل مد، کش نمی‌شود و کش پروفایل هم ندید گرفته می‌شود و احتمالا بر کارآیی و استفاده از منابع هم اثر می‌گذارد.

نام ماژول :

DynamicCompressionModule

توضیح :

پیاده سازی in-memory compression در محتوای پویا

تگ قابل پیکربندی :

system.webServer/httpCompression and system.webServer/urlCompression.

وابستگی :

وابستگی ندارد چرا که به طور پیش فرض غیرفعال است.

نام ماژول :

StaticCompressionModule

توضیح :

پیادسازی فشرده سازی در محتوای ایستا و برای فایل‌های سیستمی از نوع in memory

تگ قابل پیکربندی :

system.webServer/httpCompression and system.webServer/urlCompression

وابستگی :

ندارد.

اثرات حذف آن :

در صورت عدم فشرده سازی بر مصرف ترافیک تاثیر گذار است.

نام ماژول :

DefaultDocumentModule

توضیح :

پیاده سازی یک لیست سند پیش فرض. درخواست‌ها مدام پشت سر هم می‌آیند و این درخواست‌های پشت سرهم، به سند پیش فرض هدایت می‌شوند. همان پنجره ای که شما به ترتیب فایل‌های index.htm,index.asp,default.aspx و... را تعیین می‌کنید.

تگ قابل پیکربندی :

system.webServer/defaultDocument

وابستگی :

ندارد.

اثرات حذف آن :

درخواست را به ریشه هدایت می‌کند. مثلا برای localhost صفحه 404 باز میگرداند و اگر directoryBrowsing فعال باشد لیستی از دایرکتوری ریشه را باز میگرداند.

نام ماژول :

DirectoryListingModule

توضیح :

پیادی سازی لیستی از محتویات یک دایرکتوری

تگ قابل پیکربندی :

system.webServer/directoryBrowse

وابستگی :

ندارد.

اثرات حذف آن :

اگر این ماژول و ماژول قبلی غیرفعال باشند response نهایی خالی است.

نام ماژول :

ProtocolSupportModule

توضیح :

پیاده سازی اختصاصی از response header

پیاده سازی تنظیمات trace و HTTP verbs.

پیاده سازی تنظیمات مربوطه به keep-alive بر اساس پیکربندی

تگ قابل پیکربندی :

system.webServer/httpProtocol

وابستگی :

ندارد.

اثرات حذف آن :

بازگرداندن پیام خطای "405 Method not allowed".

نام ماژول :

HttpRedirectionModule

توضیح :

پیاده سازی عملیات انتقال یا redirect

تگ قابل پیکربندی :

system.webServer/httpRedirect

وابستگی :

ندارد.

اثرات حذف آن :

خطر امنیتی: اگر منابعی با redirect کردن محافظت می‌شوند، از این پس در دسترسند.

نام ماژول :

ServerSideIncludeModule

توضیح :

حمایت از فایل shtm یا shtml و ...

تگ قابل پیکربندی :

system.webServer/serverSideInclude

وابستگی :

ندارد.

اثرات حذف آن :

این فایل‌ها به صورت متنی نمایش داده می‌شوند

نام ماژول :

StaticFileModule

توضیح :

فایل‌های ایستا را به همراه پسوند ارسال می‌کند. مثل jpg,html و نوع محتوا را بر اساس staticContent/mimeMap پیکربندی می‌کند.

تگ قابل پیکربندی :

system.webServer/staticContent

وابستگی :

ندارد.

اثرات حذف آن :

فایل‌های ایستا دیگر ارائه نشده و به جای آن خطای 404 بازگشت داده می‌شود.

نام ماژول :

AnonymousAuthenticationModule

توضیح :

پیاده سازی سیستم شناسایی افراد ناشناس. همانطور که میدانید در یک وب سایت حداقل محتوایی برای افرادی بدون داشتن اکانت هم وجود دارد. برای اینکار یک شیء httpuser ایجاد می‌کند.

تگ قابل پیکربندی :

system.webServer/security/authentication/anonymousAuthentication

وابستگی :

ندارد.

اثرات حذف آن :

حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS می‌باشد و در صورت نبودن هیچ سیستم شناسایی وجود نداشته و در نبود شیء httpuser سیستم خطای 401.2 را تولید می‌کند.

نام ماژول :

CertificateMappingAuthenticationModule

توضیح :

مجوز SSL را به Active Directory نگاشت می‌کند.

تگ قابل پیکربندی :

system.webServer/security/authentication/clientCertificateMappingAuthentication

وابستگی :

برای اینکه این ماژول وظیفه خود را انجام دهد باید تنظیمات SSL انجام شود و همچنین سیستم IIS جزئی از دامنه Active directory باشد

اثرات حذف آن :

درخواست‌ها، نرمال رسیدگی میشوند انگار SSL وجود ندارد.

نام ماژول :

BasicAuthenticationModule

توضیح :

پیاده سازی پایه‌ای و روتین شناسایی کاربران بر اساس آن چیزی که در استانداد زیر آمده است

RFC 2617.

تگ قابل پیکربندی :

system.webServer/security/authentication/basicAuthentication

وابستگی :

None.

اثرات حذف آن :

حداقل باید یک سیستم امنیتی برای شناساسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده‌ای در IIS می‌باشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء  httpuser در سیستم، خطای 401.2 را تولید می‌کند.

نام ماژول :

WindowsAuthenticationModule

توضیح :

((windows Authentication (NTLM or Negotiate (Kerberos

تگ قابل پیکربندی :

system.webServer/security/authentication/windowsAuthentication

وابستگی :

ندارد.

اثرات حذف آن :

حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS می‌باشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید می‌کند.

نام ماژول :

DigestAuthenticationModule

توضیح :

پیاده سازی سیستم شناسایی دیاجست بر اساس

RFC 2617 .

تگ قابل پیکربندی :

system.webServer/security/authentication/digestAuthentication

وابستگی :

IIS باید بخشی از دامنه Active Directory باشد.

اثرات حذف آن :

حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS می‌باشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید می‌کند.

نام ماژول :

IISCertificateMappingAuthenticationModule

توضیح :

پیاده سازی نگاشت مجوزهای IIS، نگهداری و ذخیره اطلاعات همه نگاشت‌ها و مجوزهای کاربری چون SSL client certificates  

تگ قابل پیکربندی :

system.webServer/iisClientCertificateMappingAuthentication

وابستگی :

اطلاعات SSL به همراه دریافت client certificates جهت پیکربندی این ماژول

اثرات حذف آن :

حداقل باید یک سیستم امنیتی برای شناسایی یا authenticate وجود داشته باشد. httpuser یک ساختار داده ای در IIS می‌باشد و در صورت نبود، هیچ سیستم شناسایی یافت نشده و نبود شیء httpuser در سیستم، خطای 401.2 را تولید می‌کند.

نام ماژول :

UrlAuthorizationModule

توضیح :

پیاده سازی authorization بر اساس قوانین پیکربندی شده

تگ قابل پیکربندی :

system.webServer/security/authorization

وابستگی :

ندارد.

اثرات حذف آن :

محتواهای محافظت شده توسط authorization دیگر محافظت نمی‌شوند.

نام ماژول :

IsapiModule

توضیح :

پیاده سازی ISAPI Extension 

تگ قابل پیکربندی :

system.webServer/isapiCgiRestriction

وابستگی :

ندارد.

اثرات حذف آن :

هندلر‌های معرفی شده در بخش IsapiModule و تگ handlers دیگر اجرا نمی‌شوند

نام ماژول :

IsapiFilterModule

توضیح :

پیاده سازی ISAPI filter 

تگ قابل پیکربندی :

system.webServer/isapiFilters

وابستگی :

ندارد.

اثرات حذف آن :

اگر برنامه ای از ISAPI filter استفاده می‌کند، در اجرا دچار مشکل خواهد شد.

نام ماژول :

IpRestrictionModule

توضیح :

یک سیستم تشخیص دسترسی  بر اساس آی پی‌های ورژن4

تگ قابل پیکربندی :

system.webServer/security/ipSecurity

وابستگی :

IPv4 stack باید نصب شود.

اثرات حذف آن :

کلاینت هایی که IP هایشان در IPsecurity لیست شده‌اند ندید گرفته میشوند

نام ماژول :

RequestFilteringModule

توضیح :

پیاده سازی یک مجموعه قدرتمند از قوانین امنیتی که درخواست‌های مشکوک را پس می‌زند.

تگ قابل پیکربندی :

system.webServer/security/requestFiltering

وابستگی :

ندارد.

اثرات حذف آن :

دیگر قوانین امنیتی اجرا نخواهند شد و سبب وجود مشکلات امنیتی میشود.

نام ماژول :

CustomLoggingModule

توضیح :

پیاده سازی اینترفیس ILogPlugin در سمت IIS، به مشتریان اجازه میدهد تا لاگ‌های خود را توسعه دهند. هر چند این روش توصیه نمی‌شود و توصیه کارشناس مایکروسافت استفاده از یک ماژول دست نویس از نوع RQ_LOG_REQUEST می باشد.

Implements the ILogPlugin interface on top of IIS. ILogPlugin is a previous COM implementation that allowed customers to extend IIS logging. We do not not recommend extending IIS using this interface. Instead, customers should write a module and subscribe to the RQ_LOG_REQUEST notification.

تگ قابل پیکربندی :

system.webServer/httpLogging and system.applicationhost/sites/site/logFile/customLogPluginClsid

وابستگی :

ندارد.

اثرات حذف آن :

مسلما پلاگین‌های‌های این اینترفیس از کار می‌‌افتند که سیستم ODBC Logging هم جز آن است.

نام ماژول :

CustomErrorModule

توضیح :

پیاده سازی مدیریت خطاهای ویژه

تگ قابل پیکبرندی :

system.webServer/httpErrors

وابستگی :

None.

اثرات حذف آن :

در صورتی که خطایی از هسته باشد، نتیجه یک صفحه، با توضیح مختصری از خطا خواهد بود. در غیر این صورت اگر خطا از برنامه یا کامپوننتی باشد جزئیات خطا فاش خواهد شد

نام ماژول :

HttpLoggingModule

توضیح :

پیاده سازی سیستم logging استاندارد http.sys

تگ قابل پیکربندی :

system.applicationHost/log and system.webServer/httpLogging

وابستگی :

ندارد.

اثرات حذف آن :

از کار افتادن سیستم لاگ

نام ماژول :

FailedRequestsTracingModule

توضیح :

پیاده سازی سیستم ردیابی درخواست‌های ناموفق و اجرای قوانین، طبق پیکربندی

تگ قابل پیکربندی :

system.webServer/tracing and system.webServer/httpTracing

وابستگی :

ندارد.

اثرات حذف آن :

Tracing http requests will no longer work.

نام ماژول :

RequestMonitorModule

توضیح :

پیاده سازی IIS Run-time State and Control Interface یا به اختصار RSCA . به کاربران اجازه می‌دهد از اطلاعات، حین اجرا، کوئری بگیرند. مثل درخواست درحال اجرای جاری، آغاز به کار یا توقف وب سایت و دامنه‌های اپلیکیشن در حال اجرای جاری

تگ قابل پیکربندی :

ندارد.

وابستگی :

ندارد.

اثرات حذف آن :

ابزارهای مرتبط با این موضوع از کار می‌افتند

نام ماژول :

CgiModule

توضیح :

پیاده سازی CGI در سمت IIS

تگ قابل پیکبرندی :

system.webServer/cgi and system.webServer/isapiCgiRestriction

وابستگی :

ندارد.

اثرات حذف آن :

برنامه‌های CGI متوقف می‌شوند

نام ماژول :

TracingModule

توضیح :

پیاده سازی سیستم ردیابی ETW

تگ قابل پیکربندی :

system.webServer/httpTracing

وابستگی :

ندارد.

اثرات حذف آن :

باعث از کار افتادن سیستم مربوطه می‌شود

نام ماژول :

ConfigurationValidationModule

توضیح :

اعتبارسنجی تنظیمات برنامه ASP.Net که به حالت integrate انتقال یافته است

تگ قابل پیکربندی :

system.webServer/Validation

وابستگی :

ندارد.

اثرات حذف آن :

عدم اعتبارسنجی و در نتیجه عدم نمایش خطاها

MANAGED MODULES:

نام ماژول :

OutputCache

توضیح :

پیاده سازی output caching

تگ قابل پیکربندی :

system.web/caching/outputCache

وابستگی :

نیاز به ManagedEngine .

اثرات حذف آن :

عدم اجرای output cache

نام ماژول :

Session

توضیح :

مدیریت سشن ها

تگ قابل پیکربندی :

system.web/sessionState

وابستگی :

نیاز به ManagedEngine . 

اثرات حذف آن :

سشن‌ها از دسترس خارج می‌شوند.

نام ماژول :

WindowsAuthentication

توضیح :

اینجا 

تگ قابل پیکربندی :

system.web/authentication

وابستگی :

نیاز به ManagedEngine .

اثرات حذف آن :

این حالت قابل اجرا نخواهد بود

نام ماژول :

FormsAuthentication

توضیح :

اینجا 

تگ قابل پیکربندی :

system.web/authentication

وابستگی :

نیاز به ManagedEngine .

اثرات حذف آن :

این حالت قابل اجرا نیست و کاربران مجوز دار هم نمی‌توانند به منابع محافظت شده دسترسی داشته باشند.

نام ماژول :

DefaultAuthentication

توضیح :

اطمینان از وجود شی Authentication در context مربوطه 

تگ قابل پیکربندی :

system.web/authentication

وابستگی :

نیاز به ManagedEngine .  

اثرات حذف آن :

اگر مد Forms authentication انتخاب شده باشد بر روی بعضی از کاربران ناشناس کار نخواهد کرد و رویداد DefaultAuthentication.OnAuthenticate اجرا نخواهد شد.

نام ماژول :

RoleManager

توضیح :

اینجا 

تگ قابل پیکربندی :


وابستگی :

نیاز به ManagedEngine .

اثرات حذف آن :

این قابلیت در دسترس نمی‌باشد

نام ماژول :

UrlAuthorization

توضیح :

اینجا 

تگ قابل پیکربندی :

system.web/authorization.

وابستگی :

نیاز به ManagedEngine .  

اثرات حذف آن :

باعث از کار افتادن asp.net authorization و فاش شدن بعضی اطلاعات و همچنین دیگر تهدیدات امنیتی

نام ماژول :

AnonymousIdentification

توضیح :

اینجا 

تگ قابل پیکربندی :


وابستگی :

نیاز به ManagedEngine . 

اثرات حذف آن :

The anonymous identification feature used by the ASP.NET Profile will not work.

نام ماژول :

Profile

توضیح :

اینجا 

تگ قابل پیکربندی :


وابستگی :

ManagedEngine module must be installed.

اثرات حذف آن :

ASP.Net Profile از کار خواهد افتاد

نام ماژول :

UrlMappingsModule

توضیح :

 تبدیل یک Url واقعی به یک Url کاربرپسند 

تگ قابل پیکبرندی :


وابستگی :

نیاز به ManagedEngine .

اثرات حذف آن :

نگاشت Url‌ها صورت نمی‌گیرد

مطالب
نوشتن افزونه برای مرورگرها: قسمت دوم : کروم
در مقاله پیشین ما ظاهر افزونه را طراحی و یک سری از قابلیت‌های افزونه را معرفی کردیم. در این قسمت قصد داریم پردازش پس زمینه افزونه یعنی خواندن RSS و اعلام به روز آوری سایت را مورد بررسی قرار دهیم و یک سری قابلیت هایی که گوگل در اختیار ما قرار داده است.

خواندن RSS توسط APIهای گوگل
گوگل در تعدادی از زمینه‌ها و سرویس‌های خودش apiهایی را ارائه کرده است که یکی از آن ها خواندن فید است و ما از آن برای خواندن RSS یا اتم وب سایت کمک می‌گیریم. روند کار بدین صورت است که ابتدا ما بررسی می‌کنیم کاربر چه مقادیری را ثبت کرده است و افزونه قرار است چه بخش هایی از وب سایت را بررسی نماید. در این حین، صفحه پس زمینه شروع به کار کرده و در هر سیکل زمانی مشخص شده بررسی می‌کند که آخرین بار چه زمانی RSS به روز شده است. اگر از تاریخ قبلی بزرگتر باشد، پس سایت به روز شده است و تاریخ جدید را برای دفعات آینده جایگزین تاریخ قبلی کرده و یک پیام را به صورت نوتیفیکیشن جهت اعلام به روز رسانی جدید در آن بخش به کاربر نشان می‌دهد.
 اجازه دهید کدها را کمی شکیل‌تر کنیم. من از فایل زیر که یک فایل جاوااسکریپتی است برای نگه داشتن مقادیر بهره می‌برم تا اگر روزی خواستم یکی از آن‌ها را تغییر دهم راحت باشم و در همه جا نیاز به تغییر مجدد نداشته نباشم. نام فایل را (const.js) به خاطر ثابت بودن آن‌ها انتخاب کرده‌ام.
  //برای ذخیره مقادیر از ساختار نام و مقدار استفاده می‌کنیم که نام‌ها را اینجا ثبت کرده ام
var Variables={
 posts:"posts",
 postsComments:"postsComments",
 shares:"shares",
 sharesComments:"sharesComments",
}

//برای ذخیره زمان آخرین تغییر سایت برای هر یک از مطالب به صورت جداگانه نیاز به یک ساختار نام و مقدار است که نام‌ها را در اینجا ذخیره کرده ام
var DateContainer={
 posts:"dtposts",
 postsComments:"dtpostsComments",
 shares:"dtshares",
 sharesComments:"dtsharesComments",
 interval:"interval"
}
 
//برای نمایش پیام‌ها به کاربر
var Messages={
SettingsSaved:"تنظیمات ذخیره شد",
SiteUpdated:"سایت به روز شد",
PostsUpdated:"مطلب ارسالی جدید به سایت اضافه شد",
CommentsUpdated:"نظری جدیدی در مورد مطالب سایت ارسال شد",
SharesUpdated:"اشتراک جدید به سایت ارسال شد",
SharesCommentsUpdated:"نظری برای اشتراک‌های سایت اضافه شد"
}
//لینک‌های فید سایت
var Links={
 postUrl:"https://www.dntips.ir/feeds/posts",
 posts_commentsUrl:"https://www.dntips.ir/feeds/comments",
 sharesUrl:"https://www.dntips.ir/feed/news",
 shares_CommentsUrl:"https://www.dntips.ir/feed/newscomments"
}
//لینک صفحات سایت
var WebLinks={
Home:"https://www.dntips.ir",
 postUrl:"https://www.dntips.ir/postsarchive",
 posts_commentsUrl:"https://www.dntips.ir/commentsarchive",
 sharesUrl:"https://www.dntips.ir/newsarchive",
 shares_CommentsUrl:"https://www.dntips.ir/newsarchive/comments"
}
موقعی که اولین بار افزونه نصب می‌شود، باید مقادیر پیش فرضی وجود داشته باشند که یکی از آن‌ها مربوط به مقدار سیکل زمانی است (هر چند وقت یکبار فید را چک کند) و دیگری ذخیره مقادیر پیش فرض رابط کاربری که قسمت پیشین درست کردیم؛ پروسه پس زمینه برای کار خود به آن‌ها نیاز دارد و بعدی هم تاریخ نصب افزونه است برای اینکه تاریخ آخرین تغییر سایت را با آن مقایسه کند که البته با اولین به روزرسانی تاریخ فید جای آن را می‌گیرد. جهت انجام اینکار یک فایل init.js ایجاد کرده‌ام که قرار است بعد از نصب افزونه، مقادیر پیش فرض بالا را ذخیره کنیم.
chrome.runtime.onInstalled.addListener(function(details) {
var now=String(new Date());

var params={};
params[Variables.posts]=true;
params[Variables.postsComments]=false;
params[Variables.shares]=false;
params[Variables.sharesComments]=false;

params[DateContainer.interval]=1;

params[DateContainer.posts]=now;
params[DateContainer.postsComments]=now;
params[DateContainer.shares]=now;
params[DateContainer.sharesComments]=now;

 chrome.storage.local.set(params, function() {
  if(chrome.runtime.lastError)
   {
       /* error */
       console.log(chrome.runtime.lastError.message);
       return;
   }
        });
});
chrome.runtime شامل رویدادهایی چون onInstalled ، onStartup ، onSuspend و ... است که مربوطه به وضعیت اجرایی افزونه میشود. آنچه ما اضافه کردیم یک listener برای زمانی است که افزونه نصب شده است و در آن مقادیر پیش فرض ذخیره می‌شوند. اگر خوب دقت کنید می‌بینید که روش دخیره سازی ما در اینجا کمی متفاوت از مقاله پیشین هست و شاید پیش خودتان بگویید که احتمالا به دلیل زیباتر شدن کد اینگونه نوشته شده است ولی مهمترین دلیل این نوع نوشتار این است که متغیرهای بین {} آنچنان فرقی با خود string نمی‌کنند یعنی کد زیر:
chrome.storage.local.set('mykey':myvalue,....
با کد زیر برابر است:
chrome.storage.local.set(mykey:myvalue,...
پس اگر مقداری را داخل متغیر بگذاریم آن مقدار حساب نمی‌شود؛ بلکه کلید نام متغیر خواهد شد.
 برای معرفی این دو فایل const.js و init.js به manifest.json می‌توانید به صورت زیر عمل کنید:
"background": {
    "scripts": ["const.js","init.js"]
}
در این حالت خود اکستنشن در زمان نصب یک فایل html درست کرده و این دو فایل js را در آن صدا میزند که البته خود ما هم می‌توانیم اینکار را مستقیما انجام دهیم. مزیت اینکه ما خودمان مسقیما این کار را انجام دهیم این است که در صورتی که فایل‌های js ما زیاد شوند، فایل manifest.jason زیادی شلوغ شده و شکل زشتی پیدا می‌کند و بهتر است این فایل را تا آنجا که می‌توانیم خلاصه نگه داریم. البته روش بالا برای دو یا سه تا فایل js بسیار خوب است ولی اگر به فرض بشود 10 تا یا بیشتر بهتر است یک فایل جداگانه شود و من به همین علت فایل background.htm را درست کرده و به صورت زیر تعریف کرده‌ام:
نکته:نمی توان در تعریف بک گراند هم فایل اسکریپت معرفی کرد و هم فایل html
"background": {
    "page": "background.htm"
}
background.htm
<html>
  <head>
  <script type="text/javascript" src="const.js"></script>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript" src="init.js"></script>
<script type="text/javascript" src="omnibox.js"></script>
<script type="text/javascript" src="rssreader.js"></script>
<script type="text/javascript" src="contextmenus.js"></script>
  </head>
  <body>
  </body>
</html>
لینک‌های بالا به ترتیب معرفی ثابت‌ها، لینک api گوگل که بعدا بررسی می‌شود، فایل init.js برای ذخیره مقادیر پیش فرض، فایل ominibox که در مقاله پیشین در مورد آن صحبت کردیم و فایل rssreader.js که جهت خواندن rss در پایینتر در موردش بحث می‌کنیم و فایل contextmenus که این را هم در مطلب پیشین توضیح دادیم.
جهت خواندن فید سایت ما از Google API استفاده می‌کنیم؛ اینکار دو دلیل دارد:
  1. کدنویسی راحت‌تر و خلاصه‌تر برای خواندن RSS
  2. استفاده اجباری از یک پروکسی به خاطر Content Security Policy و حتی CORS
قبل از اینکه manifst به ورژن 2 برسد ما اجازه داشتیم کدهای جاوااسکریپت به صورت inline در فایل‌های html بنویسیم و یا اینکه از منابع و آدرس‌های خارجی استفاده کنیم برای مثال یک فایل jquery بر روی وب سایت jquery ؛ ولی از ورژن 2 به بعد، گوگل سیاست امنیت محتوا Content Security Policy را که سورس و سند اصلی آن در اینجا قرار دارد، به سیستم Extension خود افزود تا از حملاتی قبیل XSS و یا تغییر منبع راه دور به عنوان یک malware جلوگیری کند. پس ما از این به بعد نه اجازه داشتیم inline بنویسیم و نه اجازه داشتیم فایل jquery را از روی سرورهای سایت سازنده صدا بزنیم. پس برای حل این مشکل، ابتدا مثل همیشه یک فایل js را در فایل html معرفی می‌کردیم و برای حل مشکل دوم باید منابع را به صورت محلی استفاده می‌کردیم؛ یعنی فایل jquery را داخل دایرکتوری extension قرار می‌دادیم.
برای حل مشکل مشکل صدا زدن فایل‌های راه دور ما از Relaxing the Default Policy  استفاده می‌کنیم که به ما یک لیست سفید ارائه می‌کند و در این لیست سفید دو نکته‌ی مهم به چشم میخورد که یکی از آن این است که استفاده از آدرس هایی با پروتکل Https و آدرس لوکال local host/127.0.0.1 بلا مانع است و از آنجا که api گوگل یک آدرس Https است، می‌توانیم به راحتی از API آن استفاده کنیم. فقط نیاز است تا خط زیر را به manifest.json اضافه کنیم تا این استثناء را برای ما در نظر بگیرد.
"content_security_policy": "script-src 'self' https://*.google.com; object-src 'self'"
در اینجا استفاده از هر نوع subdomain در سایت گوگل بلامانع اعلام می‌شود.
بنابراین آدرس زیر به background.htm اضافه می‌شود:
 <script type="text/javascript" src="https://www.google.com/jsapi"></script>

استفاده از این Api در rssreader.js
فایل rssreader.js را به background.htm اضافه می‌کنیم و در آن کد زیر را می‌نویسیم:
google.load("feeds", "1");
google.setOnLoadCallback(alarmManager);
آدرسی که ما از گوگل درخواست کردیم فقط مختص خواندن فید نیست؛ تمامی apiهای جاوااسکریپتی در آن قرار دارند و ما تنها نیاز داریم قسمتی از آن لود شود. پس اولین خط از دستور بالا بارگذاری بخش مورد نیاز ما را به عهده دارد. در مورد این دستور این صفحه را مشاهده کنید.
در خط دوم ما تابع خودمان را به آن معرفی می‌کنیم تا وقتی که گوگل لودش تمام شد این تابع را اجرا کند تا قبل از لود ما از توابع آن استفاده نکنیم و خطای undefined دریافت نکنیم. تابعی که ما از آن خواستیم اجرا کند alarmManager نام دارد و قرار است یک آلارم و یک سیکل زمانی را ایجاد کرده و در هر دوره، فید را بخواند. کد تابع مدنظر به شرح زیر است:
function alarmManager()
{
chrome.storage.local.get(DateContainer.interval,function ( items) {
period_time==items[DateContainer.interval];
chrome.alarms.create('RssInterval', {periodInMinutes: period_time});
});


chrome.alarms.onAlarm.addListener(function (alarm) {
console.log(alarm);
    if (alarm.name == 'RssInterval') {

var boolposts,boolpostsComments,boolshares,boolsharesComments;
chrome.storage.local.get([Variables.posts,Variables.postsComments,Variables.shares,Variables.sharesComments],function ( items) {
boolposts=items[Variables.posts];
boolpostsComments=items[Variables.postsComments];
boolshares=items[Variables.shares];
boolsharesComments=items[Variables.sharesComments];


chrome.storage.local.get([DateContainer.posts,DateContainer.postsComments,DateContainer.shares,DateContainer.sharesComments],function ( items) {

var Vposts=new Date(items[DateContainer.posts]);
var VpostsComments=new Date(items[DateContainer.postsComments]);
var Vshares=new Date(items[DateContainer.shares]);
var VsharesComments=new Date(items[DateContainer.sharesComments]);

if(boolposts){var result=RssReader(Links.postUrl,Vposts,DateContainer.posts,Messages.PostsUpdated);}
if(boolpostsComments){var result=RssReader(Links.posts_commentsUrl,VpostsComments,DateContainer.postsComments,Messages.CommentsUpdated); }
if(boolshares){var result=RssReader(Links.sharesUrl,Vshares,DateContainer.shares,Messages.SharesUpdated);}
if(boolsharesComments){var result=RssReader(Links.shares_CommentsUrl,VsharesComments,DateContainer.sharesComments,Messages.SharesCommentsUpdated);}

});
});
    }
});
}
خطوط اول تابع alarmManager وظیفه‌ی خواندن مقدار interval را که در init.js ذخیره کرده‌ایم، دارند که به طور پیش فرض 10 ذخیره شده است تا تایمر یا آلارم خود را بر اساس آن بسازیم. در خط chrome.alarms.create یک آلارم با نام rssinterval می‌سازد و قرار است هر 10 دقیقه وظایفی که بر دوشش گذاشته می‌شود را اجرا کند (استفاده از api جهت دسترسی به آلارم نیاز به مجوز "alarms" دارد). وظایفش از طریق یک listener که بر روی رویداد chrome.alarms.onAlarm  گذاشته شده است مشخص می‌شود. در خط بعدی مشخص می‌شود که این رویداد به خاطر چه آلارمی صدا زده شده است. البته از آنجا که ما یک آلارم داریم، نیاز چندانی به این کد نیست. ولی اگر پروژه شما حداقل دو آلارم داشته باشد نیاز است مشخص شود که کدام آلارم باعث صدا زدن این رویداد شده است. در مرحله بعد مشخص می‌کنیم که کاربر قصد بررسی چه قسمت‌هایی از سایت را داشته است و در تابع callback آن هم تاریخ آخرین تغییرات هر بخش را می‌خوانیم و در متغیری نگه داری می‌کنیم. هر کدام را جداگانه چک کرده و تابع RssReader را برای هر کدام صدا می‌زنیم. این تابع 4 پارامتر دارد:
  1. آدرس فیدی که قرار است از روی آن بخواند
  2. آخرین به روزسانی که از سایت داشته متعلق به چه تاریخی است.
  3. نام کلید ذخیره سازی تاریخ آخرین تغییر سایت که اگر بررسی شد و مشخص شد سایت به روز شده است، تاریخ جدید را روی آن ذخیره کنیم.
  4. در صورتی که سایت به روز شده باشد نیاز است پیامی را برای کاربر نمایش دهیم که این پیام را در اینجا قرار می‌دهیم.
کد تابع rssreader
function RssReader(URL,lastupdate,datecontainer,Message) {
            var feed = new google.feeds.Feed(URL);
            feed.setResultFormat(google.feeds.Feed.XML_FORMAT);
                    feed.load(function (result) {
if(result!=null)
{
var strRssUpdate = result.xmlDocument.firstChild.firstChild.childNodes[5].textContent;
var RssUpdate=new Date(strRssUpdate);

if(RssUpdate>lastupdate)
{
SaveDateAndShowMessage(datecontainer,strRssUpdate,Message)
}
}
});
}
در خط اول فید توسط گوگل خوانده میشود، در خط بعدی ما به گوگل میگوییم که فید خوانده شده را چگونه به ما تحویل دهد که ما قالب xml را خواسته ایم و در خط بعدی اطلاعات را در متغیری به اسم result قرار میدهد که در یک تابع برگشتی آن را در اختیار ما میگذارد. از آن جا که ما قرار است تگ lastBuildDate را بخوانیم که پنجمین تگ اولین گره در اولین گره به حساب می‌آید، خط زیر این دسترسی را برای ما فراهم می‌کند و چون تگ ما در یک مکان ثابت است با همین تکه کد، دسترسی مستقیمی به آن داریم:
var strRssUpdate = result.xmlDocument.firstChild.firstChild.childNodes[5].textContent;
مرحله بعد تاریخ را که در قالب رشته‌ای است، تبدیل به تاریخ کرده و با lastupdate یعنی آخرین تغییر قبلی مقایسه می‌کنیم و اگر تاریخ برگرفته از فید بزرگتر بود، یعنی سایت به روز شده است و تابع SaveDateAndShowMessage را صدا می‌زنیم که وظیفه ذخیره سازی تاریخ جدید و ایجاد notification را به عهده دارد و سه پارامتر کلید ذخیره سازی و مقدار آن و پیام را به آن پاس می‌کنیم.

کد تابع SaveDateAndShowMesage
function SaveDateAndShowMessage(DateField,DateValue,Message)
{
var params={
}
params[DateField]=DateValue;

chrome.storage.local.set( params,function(){

var options={
  type: "basic",
   title: Messages.SiteUpdated,
   message: Message,
   iconUrl: "icon.png"
}
chrome.notifications.create("",options,function(){
chrome.notifications.onClicked.addListener(function(){
chrome.tabs.create({'url': WebLinks.Home}, function(tab) {
});
});
});
});
}
خطوط اول مربوط به ذخیره تاریخ است و دومین نکته نحوه‌ی ساخت نوتیفکیشن است. اجرای یک notification  نیاز به مجوز "notifications " دارد که مجوز آن در manifest به شرح زیر است:
"permissions": [
    "storage",
     "tabs",
 "alarms",
 "notifications"
  ]
در خطوط بالا سایر مجوزهایی که در طول این دوره به کار اضافه شده است را هم می‌بینید.
برای ساخت نوتیفکیشن از کد chrome.notifications.create استفاده می‌کنیم که پارامتر اول آن کد یکتا یا همان ID جهت ساخت نوتیفیکیشن هست که میتوان خالی گذاشت و دومی تنظیمات ساخت آن است؛ از قبیل عنوان و آیکن و ... که در بالا به اسم options معرفی کرده ایم و در آگومان دوم آن را معرفی کرده ایم و آرگومان سوم هم یک تابع callback است که نوشتن آن اجباری است. options شامل عنوان، پیام، آیکن و نوع notification می‌باشد که در اینجا basic انتخاب کرده‌ایم. برای دسترسی به دیگر خصوصیت‌های options به اینجا و برای داشتن notification‌های زیباتر به عنوان rich notification به اینجا مراجعه کنید. برای اینکه این امکان باشد که کاربر با کلیک روی notification به سایت هدایت شود باید در تابع callback مربوط به notifications.create این کد اضافه گردد که در صورت کلیک یک تب جدید با آدرس سایت ساخته شود:
chrome.notifications.create("",options,function(){
chrome.notifications.onClicked.addListener(function(){
chrome.tabs.create({'url': WebLinks.Home}, function(tab) {
});});
});

نکته مهم:  پیشتر معرفی آیکن به صورت بالا کفایت میکرد ولی بعد از این باگ  کد زیر هم باید جداگانه به manifest اضافه شود:
"web_accessible_resources": [
    "icon.png"
  ]


خوب؛ کار افزونه تمام شده است ولی اجازه دهید این بار امکانات افزونه را بسط دهیم:
من می‌خواهم برای افزونه نیز قسمت تنظیمات داشته باشم. برای دسترسی به options میتوان از قسمت مدیریت افزونه‌ها در مرورگر یا حتی با راست کلیک روی آیکن browser action عمل کرد. در اصل این قسمت برای تنظیمات افزونه است ولی ما به خاطر آموزش و هم اینکه افزونه ما UI خاصی نداشت تنظیمات را از طریق browser action پیاده سازی کردیم و گرنه در صورتی که افزونه شما شامل UI خاصی مثلا نمایش فید مطالب باشد، بهترین مکان تنظیمات، options است. برای تعریف options در manifest.json به روش زیر اقدام کنید:
"options_page": "popup.html"
همان صفحه popup را در این بخش نشان میدهم و اینبار یک کار اضافه‌تر دیگر که نیاز به آموزش ندارد اضافه کردن input  با Type=number است که برای تغییر interval به کار می‌رود و نحوه ذخیره و بازیابی آن را در طول دوره یاد گرفته اید.

جایزگزینی صفحات یا 
 Override Pages
بعضی صفحات مانند بوک مارک و تاریخچه فعالیت‌ها History و همینطور newtab را می‌توانید جایگزین کنید. البته یک اکستنشن میتواند فقط یکی از صفحات را جایگزین کند. برای تعیین جایگزین در manifest اینگونه عمل می‌کنیم:
"chrome_url_overrides": {
    "newtab": "newtab.htm"
  }

ایجاد یک تب اختصاصی در Developer Tools
تکه کدی که باید manifest اضافه شود:
"devtools_page": "devtools.htm"
شاید فکر کنید کد بالا الان شامل مباحث ui و ... می‌شود و بعد به مرورگر اعمال خواهد شد؛ در صورتی که اینگونه نیست و نیاز دارد چند خط کدی نوشته شود. ولی مسئله اینست که کد بالا تنها صفحات html را پشتیبانی می‌کند و مستقیما نمی‌تواند فایل js را بخواند. پس صفحه بالا را ساخته و کد زیر را داخلش می‌گذاریم:
<script src="devtools.js"></script>
فایل devtools.js هم شامل کد زیر می‌شود:
chrome.devtools.panels.create(
    "Dotnettips Updater Tools", 
    "icon.png", 
    "devtoolsui.htm",
    function(panel) {
    }
);
خط chrome.devtools.panels.create یک پنل یا همان تب را ساخته و در پارامترهای بالا به ترتیب عنوان، آیکن و صفحه‌ای که باید در آن رندر شود را دریافت می‌کند و پس از ایجاد یک callback اجرا می‌شود. اطلاعات بیشتر

APIها
برای دیدن لیست کاملی از API‌ها می‌توانید به مستندات آن رجوع کنید و این مورد را به یاد داشته باشید که ممکن است بعضی api‌ها در بعضی موارد پاسخ ندهند. به عنوان مثال در content scripts نمی‌توانید به chrome.devtools.panels دسترسی داشته باشید یا اینکه در DeveloperTools  دسترسی به DOM میسر نیست. پس این مورد را به خاطر داشته باشید. همچنین بعضی api‌ها از نسخه‌ی خاصی به بعد اضافه شده‌اند مثلا همین مثال قبلی devtools از نسخه 18 به بعد اضافه شده است و به این معنی است با خیال راحت می‌توانید از آن استفاده کنید. یا آلارم‌ها از نسخه 22 به بعد اضافه شده‌اند. البته خوشبختانه امروزه با دسترسی آسانتر به اینترنت و آپدیت خودکار مرورگرها این مشکلات دیگر آن چنان رخ نمی‌دهند.

Messaging
همانطور که در بالا اشاره شد شما نمی‌توانید بعضی از apiها را در بعضی جاها استفاده کنید. برای حل این مشکل می‌توان از messaging استفاده کرد که دو نوع تبادلات پیغامی داریم:
  1. One-Time Requests یا درخواست‌های تک مرتبه‌ای
  2. Long-Lived Connections یا اتصالات بلند مدت یا مصر

درخواست‌های تک مرتبه ای
  این درخواست‌ها همانطور که از نامش پیداست تنها یک مرتبه رخ می‌دهد؛ درخواست را ارسال کرده و منتظر پاسخ می‌ماند. به عنوان مثال به کد زیر که در content script است دقت کنید:
window.addEventListener("load", function() {
    chrome.extension.sendMessage({
        type: "dom-loaded", 
        data: {
            myProperty   : "value" 
        }
    });
}, true);
کد بالا یک ارسال کننده پیام است. موقعی که سایتی باز می‌شود، یک کلید با مقدارش را ارسال می‌کند و کد زیر در background گوش می‌ایستد تا اگر درخواستی آمد آن را دریافت کند:
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
    switch(request.type) {
        case "dom-loaded":
            alert(request.data.myProperty   ); 
        break;
    }
    return true;
});

اتصالات بلند مدت یا مصر
اگر نیاز به یک کانال ارتباطی مصر و همیشگی دارید کد‌ها را به شکل زیر تغییر دهید
contentscripts
var port = chrome.runtime.connect({name: "my-channel"});
port.postMessage({myProperty: "value"});
port.onMessage.addListener(function(msg) {
    // do some stuff here
});

background
chrome.runtime.onConnect.addListener(function(port) {
    if(port.name == "my-channel"){
        port.onMessage.addListener(function(msg) {
            // do some stuff here
        });
    }
});

نمونه کد
نمونه کدهایی که در سایت گوگل موجود هست می‌توانند کمک بسیاری خوبی باشند ولی اینگونه که پیداست اکثر مثال‌ها مربوط به نسخه‌ی یک manifest است که دیگر توسط مرورگرها پشتیبانی نمی‌شوند و مشکلاتی چون اسکریپت inline و CSP که در بالا اشاره کردیم را دارند و گوگل کدها را به روز نکرده است.

دیباگ کردن و پک کردن فایل‌ها برای تبدیل به فایل افزونه Debugging and packing
برای دیباگ کردن کد‌ها می‌توان از دو نمونه console.log و alert برای گرفتن خروجی استفاده کرد و همچنین ابزار  Chrome Apps & Extensions Developer Tool هم نسبتا امکانات خوبی دارد که البته میتوان از آن برای پک کردن اکستنشن نهایی هم استفاده کرد. برای پک کردن روی گزینه pack کلیک کرده و در کادر باز شده گزینه‌ی pack را بزنید. برای شما دو نوع فایل را در مسیر والد دایرکتوری extension نوشته شده درست خواهد کرد که یکی پسوند crx دارد که می‌شود همان فایل نهایی افزونه و دیگری هم پسوند pem دارد که یک کلید اختصاصی است و باید برای آپدیت‌های آینده افزونه آن را نگاه دارید. در صورتی که افزونه را تغییر دادید و خواستید آن را به روز رسانی کنید موقعی که اولین گزینه pack را می‌زنید و صفحه باز می‌شود قبل از اینکه دومین گزینه pack را بزنید، از شما می‌خواهد اگر دارید عملیات به روز رسانی را انجام می‌دهید، کلید اختصاصی آن را وارد نمایید و بعد از آن گزینه pack را بزنید:


آپلود نهایی کار در Google web store

برای آپلود نهایی کار به google web store که در آن تمامی برنامه‌ها و افزونه‌های کروم قرار دارند بروید. سمت راست آیکن تنظیمات را بزنید و گزینه developer dashboard را انتخاب کنید تا صفحه‌ی آپلود کار برای شما باز شود. دایرکتوری محتویات اکستنشن را zip کرده و آپلود نمایید. توجه داشته باشید که محتویات و سورس خود را باید آپلود کنید نه فایل crx را. بعد از آپلود موفقیت آمیز، صفحه‌ای ظاهر می‌شود که از شما آیکن افزونه را در اندازه 128 پیکسل میخواهد بعلاوه توضیحاتی در مورد افزونه، قیمت گذاری که به طور پیش فرض به صورت رایگان تنظیم شده است، لینک وب سایت مرتبط، لینک محل پرسش و پاسخ برای افزونه، اگر لینک یوتیوبی در مورد افزونه دارید، یک شات تصویری از افزونه و همینطور چند تصویر برای اسلایدشو سازی که در همان صفحه استاندارد آن‌ها را توضیح می‌دهد و در نهایت گزینه‌ی جالب‌تر هم اینکه اکستنشن شما برای چه مناطقی تهیه شده است که متاسفانه ایران را ندیدم که می‌توان همه موارد را انتخاب کرد. به خصوص در مورد ایران که آی پی‌ها هم صحیح نیست، انتخاب ایران چنان تاثیری ندارد و در نهایت گزینه‌ی publish را می‌زنید که متاسفانه بعد از این صفحه درخواست می‌کند برای اولین بار باید 5 دلار آمریکا پرداخت شود که برای بسیاری از ما این گزینه ممکن نیست.

سورس پروژه را می‌توانید از اینجا ببینید و خود افزونه را از اینجا دریافت کنید.

 
مطالب
آموزش فایرباگ - #3 - JavaScript Development
توابع توسعه جاوا اسکریپت در فایرباگ به دو بخش تقسیم می‌شوند :
  • توابع خط فرمان - Command Line API
  • توابع کنسول - Console API
توابع خط فرمان توابعی هستند که فقط در خط فرمان قابل استفاده هستند و توابع کنسول هم توابعی هستند که خارج از محیط خط فرمان ( ، در بین کدهای جاوا اسکریپت برنامه ) هم قابل استفاده هستند .
در این قسمت توابع خط فرمان را بررسی خواهیم کرد و در قسمت بعدی با توابع کنسول آشنا خواهیم شد .

توابع خط فرمان - Command Line API :

این توابع حدود 14 تا هستند که بوسیله آنها می‌توانیم در حین اجرای برنامه تست‌های مختلفی انجام داده یا اطلاعاتی از قسمت‌های مختلف بدست آوریم .
توجه : برای همراه شدن با تست‌های انجام شده در این مقاله می‌توانید کد صفحه‌ی زیر را ذخیره کنید و برای اجرای کدها ، آن‌ها را در قسمت خط فرمان ( در تب کنسول ) قرار بدهید و دکمه‌ی Run ( یا Ctrl + Enter ) را بزنید .
<div id="first" class="content">Content1 with css class and id</div>
<div class="content">
    Content2 with css class
    <a class="links" href="#">Link1</a>
    <a href="#">Link2</a>
</div>
<div>
    Content3 without css class and id
</div>
<input type="button" onclick="myFunc()" value="Run myFunc" />
<input type="text" id="myInput" />

<script type="text/javascript">
    function myFunc() {
        loop(1000);
        loop(50000);
    }
    function loop(number) {
        for (var i = 0; i < number; i++) { }
    }
</script>
قبل از توضیح این توابع ، یک مثال ساده می‌زنیم :
فرض کنید می‌خواهید همه‌ی المنت هایی که با یک selector مطابقت دارند را مشاهده کنید . ( آرایه ای از المنت‌ها دریافت کنید )
$$("div.content");
نتیجه :

می خواهید یکی از توابع جاوا اسکریپت برنامه را اجرا و آن را از لحاظ سرعت ، تعداد فراخوانی شدن و ... بررسی کنید .
profile("myFunc Testing");
myFunc();
profileEnd();
نتیجه :

اکنون با همه‌ی توابع خط فرمان آشنا می‌شویم :

  • $(id)

    معادل دستور document.getElementById است که یک المنت با id داده شده بر می‌گرداند .
    $("first");
    نتیجه :

  • $$(selector)


    آرایه ای از المنت‌های مطابق با selector داده شده بر می‌گرداند .
    $$("div.content")
    نتیجه :

    به تفاوت دو دستور توجه کنید . خروجی دستور اول ، یک المنت است و خروجی دستور دوم یک آرایه از المنت که بین [ و ] قرار گرفته اند .

    برای آشنایی بیشتر با CSS Seletor‌ها به این لینک مراجعه کنید : http://www.w3.org/TR/css3-selectors

  • $x(xPathExpression)

    آرایه ای از المنت هایی را بر می‌گرداند که با xPath داده شده مطابقت داشته باشند .
    var objects = $x("html/body/div[2]/a")
    
    for(var i = 0; i < objects.length; i++) {
       console.log(objects[i]);
    }
    نتیجه :

    برای آشنایی بیشتر با عبارات xPath به این لینک مراجعه کنید : http://www.w3schools.com/xpath

  • dir(object)

    تمام خصوصیات شیء ارسال شده را لیست می‌کند .
    var objects = $x("html/body/div[2]/a")
    
    dir(objects);
    نتیجه :

  • dirxml(node)

    سورس یک المنت را بصورت درختواره ( tree ) پرینت می‌کند . همچنین با کلیک بروی هر node ، فایرباگ آن node را در تب html نمایش می‌دهد .
    var node = $("first");
    dirxml(node);
    نتیجه :

    توجه کنید که این دستور فقط یک node دریافت می‌کند . برای همین اگر از دستور $$("#first") استفاده می‌کنید ، چون این دستور یک آرایه بر می‌گرداند ، باید اولین عضو آرایه را دریافت و ارسال کنید .
    یعنی :
    var node = $$("#first")[0];
    dirxml(node);
  • clear()

    این دستور محیط console را خالی می‌کند . عملکرد این دستور معادل کلیک دکمه‌ی Clear ( در بالا - چپ تب کنسول ) است .

  • inspect(object[,tabName])

    توسط این دستور می‌توانید یک شیء را در مناسب‌ترین تب فایرباگ یا یکی از تب‌های مورد نظر خود ، Inspect کنید .
    var node = $("first");
    
    inspect(node); // inspect in html tab
    inspect(node,'dom'); // inspect in dom tab
  • keys(object)

    آرایه ای از "نام" تمام خصوصیات شیء ارسال شده بر می‌گرداند .
    var obj = $("first");
    keys(obj)
  • values(object)

    آرایه ای از "مقدار" تمام خصوصیات شیء ارسال شده بر می‌گرداند .
    var obj = $("first");
    values(obj)
  • debug(fn) and undebug(fn)

    این متدها یک BreakPoint در ابتدای تابع مشخص شده اضافه/حذف می‌کنند . ( در تب Script ) . به همین ترتیب هنگامی که تابع مورد نظر فراخوانی شود ، در نقطه ای که BreakPoint قرار داده شده توقف خواهد کرد .
    البته می‌شود BreakPoint را دستی هم قرار داد . در اصل این تابع ، این عملیات را ساده‌تر می‌کند .
    debug(myFunc);
    myFunc();
    undebug(myFunc);
  • monitor(fn) and unmonitor(fn)

    این متدها برای فعال/غیرفعال کردن Logging فراخوانی‌های یک تابع استفاده می‌شوند .
    در حالت عادی برای پی بردن به اینکه یک تابع اجرا می‌شود یا نه ، در تابع مورد نظر یک alert قرار می‌دهیم و تست می‌کنیم . که این روش در برنامه برنامه‌های بزرگ صحیح نیست . زیرا در این حالت باید بین حجم زیادی کد به دنبال تابع مورد نظر بگردیم  و سپس alert را قرار بدهیم و بعد اطمینان از صحت عملکرد تابع مجدد آن را حذف کرد ، که با اتلاف زمان و به خطر انداختن کدها همراه است .
    اما با استفاده از این متدها ، تنها نیاز به داشتن اسم تابع داریم ( و نه مکان تابع در کدهای برنامه ) .
    تست monitor :
    monitor(myFunc);
    // now click on "Run myFunc" button
    تست unmonitor :
    unmonitor(myFunc);
    // now click on "Run myFunc" button
  • monitorEvents(object[, types]) and unmonitorEvents(object[, types])

    این متدها عملیات Event Logging برای یک شیء را فعال/غیرفعال می‌کنند . در کنار شیء مورد نظر ، می‌توان نوع رویداد را هم به متد ارسال کرد . در این صورت عملیات Logging فقط برای همان گروه رویداد/رویداد ، فعال/غیرفعال می‌شود .
    منظور از گروه رویداد ، مجموعه رویداد‌های یک شیء است . مثلا mousemove , moseover , mousedown , ... در گروه mouse قرار می‌گیرند . یعنی می‌توانید با ارسال کلمه‌ی mouse فقط رویدادهای mouse را تحت نظر بگیرید یا اینکه فقط یک رویداد را مشخص کنید ، مثل mousedown .
    راه ساده‌تر فعال کردن Event Logging ، رفتن به تب Html ، راست کلیک کردن بروی المنت مورد نظر و فعال کردن گزینه‌ی Log Events می‌باشد .
    var obj = $("myInput");
    monitorEvents(obj,'keypress');

    نتیجه پس از فشردن چند دکمه‌ی کیبورد در myInput :

    توضیحات بیشتر : http://getfirebug.com/wiki/index.php/MonitorEvents

  • profile([title]) and profileEnd()

    این متدها ، JavaScript Profiler را فعال/غیرفعال می‌کنند . هنگام فعال کردن می‌توانید یک عنوان هم برای پروفایل مشخص کنید . در قسمت قبلی مقاله در مورد این قابلیت توضیحاتی ارائه شد .
    سه را برای اجرای Profiler وجود دارد :
    1 - کلیک بروی دکمه‌ی Profiler در بالای تب کنسول .
    2 - استفاده از کد console.profile("ProfileTitle") در کدهای جاوا اسکریپت .
    3 - استفاده از متد profile("Profile Title") در خط فرمان .

    profile("myFunc Testing");
    myFunc();
    profileEnd();
    نتیجه :



    ستون‌های Profiler :

    Function : نام تابع اجرا شده .
    Calls : تعداد دفعات فراخوانی تابع .
    Percent : زمان اجرای تابع در زمان کل ، به درصد .
    Own Time : زمان اجرای تابع به تنهایی . برای مثال در کد ما ، زمان اجرای تابع myFunc به تنهایی تقریبا صفر است زیرا عمیاتی در خود انجام نمی‌دهد و زمان صرف شده در این تابع ، برای اجرای 2 با تابع loop است . این زمان ( Own Time ) زمان اجرای تابع ، منهای زمان صرف شده برای فراخوانی توابع دیگر است .
    Time : زمان اجرای تابع از نقطه‌ی آغاز تا پایان . مجموع زمان اجرای خود تابع به همراه زمان اجرای توابع فراخوانی شده . در کد ما ، این زمان ، مجموع زمان اجرای خود تابع به همراه دو بار فراخوانی تابع loop است .
    Avg : میانگین زمان اجرای هربار تابع . فرمول : Avg = Time / Calls
    Min & Max : حداقل و حداکثر زمان اجرای تابع .
    File : نام فایل و شماره خطی که تابع در آن قرار دارد .

در قسمت بعد با توابع کنسول آشنا خواهیم شد .

منابع :
Packtpub.Firebug.1.5.Editing.Debugging.and.Monitoring.Web.Pages.Apr.2010
مطالب
شروع کار با Dart - قسمت 1

Dart کتابخانه ای است که توسط شرکت گوگل ارائه شده است و گفته می‌شود، قرار است جایگزین جاوا اسکریپت گردد و از آدرس https://www.dartlang.org قابل دسترسی می‌باشد. این کتابخانه، دارای انعطاف پذیری فوق العاده بالایی است و کد نویسی Java Script را راحت‌تر می‌کند. در حال حاضر هیچ مرورگری به غیر از Chromium از این تکنولوژی پشتیبانی نمی‌کند و جهت تسهیل در کدنویسی، باید از ویرایشگر Dart Editor استفاده کنید. این ویرایشگر کدهای نوشته شده را به دو صورت Native و JavaScript Compiled در اختیار مرورگر قرار می‌دهد. در ادامه با نحوه‌ی کار و راه اندازی Dart آشنا خواهید شد.

ابتدا Dart و ویرایشگر مربوط به آن را توسط لینک‌های زیر دانلود کنید:

دانلود نسخه 64 بیتی دارت + ویرایشگر

دانلود نسخه 32 بیتی دارت + ویرایشگر

بعد از اینکه فایلهای فوق را از حالت فشرده خارج کردید، پوشه ای با نام dart ایجاد می‌نماید. وارد پوشه dart شده و DartEditor را اجرا کنید.

توجه: جهت اجرای dart به JDK 6.0 یا بالاتر نیاز دارید

در مرحله بعد نمونه کدهای Dart را از لینک زیر دانلود نمایید و از حالت فشرده خارج کنید. پوشه ای با نام one-hour-codelab ایجاد می‌گردد.

دانلود نمونه کدهای دارت

از منوی File > Open Existing Folder… پوشه one-hour-codelab را باز کنید .

توضیحات

- پوشه packages و همچنین فایلهای pubspec.yaml و pubspec.lock شامل پیش نیازها و Package هایی هستند که جهت اجرای برنامه‌های تحت Dart مورد نیاز هستند. Dart Editor این نیازمندی‌ها را به صورت خودکار نصب و تنظیم می‌کند.

توجه: اگر پوشه Packages را مشاهده نکردید و یا در سمت چپ فایلها علامت X قرمز رنگ وجود داشت، بدین معنی است که package ‌ها به درستی نصب نشده اند. برای این منظور بر روی pubspec.yaml کلیک راست نموده و گزینه Get Pub را انتخاب کنید. توجه داشته باید که بدلیل تحریم ایران توسط گوگل باید از ابزارهای عبور از تحریم استفاده کنید.

- 6 پوشه را نیز در تصویر فوق مشاهده می‌کنید که نمونه کد piratebadge را بصورت مرحله به مرحله انجام داده و به پایان می‌رساند.

- Dart SDK شامل سورس کد مربوط به تمامی توابع، متغیرها و کلاس هایی است که توسط کیت توسعه نرم افزاری Dart ارائه شده است.

- Installed Packages شامل سورس کد مربوط به تمامی توابع، متغیرها و کلاس‌های کتابخانه‌های اضافه‌تری است که Application به آنها وابسته است.


گام اول: اجرای یک برنامه کوچک

در این مرحله سورس کدهای آماده را مشاهده می‌کنید و با ساختار کدهای Dart و HTML آشنا می‌شوید و برنامه کوچکی را اجرا می‌نمایید.

در Dart Editor پوشه 1-blankbadge را باز کنید و فایلهای piratebadge.html و piratebadge.dart را مشاهده نمایید.

کد موجود در فایل piratebadge.html

<html>
  <head>
    <meta charset="utf-8">
    <title>Pirate badge</title>
    <meta name="viewport"
          content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="piratebadge.css">
  </head>
  <body>
    <h1>Pirate badge</h1>
    
    <div>
      TO DO: Put the UI widgets here.
    </div>
    <div>
      <div>
        Arrr! Me name is
      </div>
      <div>
        <span id="badgeName"> </span>
      </div>
    </div>

    <script type="application/dart" src="piratebadge.dart"></script>
    <script src="packages/browser/dart.js"></script>
  </body>
</html>

توضیحات

- در کد HTML ، اولین تگ <script> ، فایل piratebadge.dart را جهت پیاده سازی دستورات dart به صفحه ضمیمه می‌نماید

- Dart Virtual Machine (Dart VM) کدهای Dart را بصورت Native یا بومی ماشین اجرا می‌کند. Dart VM کدهای خود را در Dartium که یک ویرایش ویژه از مرورگر Chromium می‌باشد اجرا می‌کند که می‌تواند برنامه‌های تحت Dart را بصورت Native اجرا کند.

- فایل packages/browser/dart.js پشتیبانی مرورگر از کد Native دارت را بررسی می‌کند و در صورت پشتیبانی، Dart VM را راه اندازی می‌کند و در غیر این صورت JavaScript کامپایل شده را بارگزاری می‌نماید.


کد موجود در piratebadge.dart

void main() {
  // Your app starts here.
}

- این فایل شامل تابع main می‌باشد که تنها نقطه ورود به application است. تگ <script> موجود در piratebadge.html برنامه را با فراخوانی این تابع راه اندازی می‌کند.

- تابع main() یک تابع سطح بالا یا top-level می‌باشد.

- متغیرها و توابع top-level عناصری هستند که خارج از ساختار تعریف کلاس ایجاد می‌شوند.

جهت اجرای برنامه در Dart Editor بر روی piratebadge.html کلیک راست نمایید و گزینه Run in Dartium را اجرا کنید. این فایل توسط Dartium اجرا می‌شود و تابع main() را فراخوانی می‌کند و صفحه ای همانند شکل زیر را نمایش می‌دهد.


گام دوم: افزودن فیلد input

توجه داشته باشید که در این مرحله یا می‌توانید تغییرات مورد نظر خود را در طی آموزش بر روی پوشه‌ی 1-blankbadge اعمال کنید و یا به پوشه‌های تهیه شده در نمونه کد موجود در همین پروژه مراجعه نمایید.

در این مرحله یک تگ <input> به تگ <div class=”widgets”> اضافه کنید.

...
<div>
  <div>
    <input type="text" id="inputName" maxlength="15">
  </div>
</div>
...

سپس کتابخانه dart:html را به ابتدای فایل piratebadge.dart اضافه کنید.

import 'dart:html';

توضیحات

- دستور فوق کلاس‌ها و Resource ‌های موجود در کتابخانه dart:html را اضافه می‌کند.

- از حجیم شدن کدهای خود نگران نباشید، زیرا فرایند کامپایل کدهای اضافی را حذف خواهد کرد.

- کتابخانه dart:html شامل کلاسهایی جهت کار با عناصر DOM و توابعی جهت دسترسی به این عناصر می‌باشد.

- در مباحث بعدی یاد می‌گیرید که با استفاده از کلمه کلیدی show فقط کلاسهایی را import کنید که به آن نیاز دارید.

- اگر کتابخانه ای در هیچ بخش کد استفاده نشود، خود Dart Editor به صورت warning اخطار می‌دهد و می‌توانید آن را حذف کنید.


دستور زیر را در تابع main بنویسید تا رویداد مربوط به ورود اطلاعات  در فیلد input را مدیریت نمایید.

void main() {
  querySelector('#inputName').onInput.listen(updateBadge);
}

توضیحات

- تابع querySelector() در کتابخانه dart:html تعریف شده است و یک المنت DOM را جستجو می‌نماید. پارامتر ورودی آن یک selector می‌باشد که در اینجا فیلد input را توسط #inputName جستجو نمودیم که یک ID Selector می‌باشد.

- نوع خروجی این متد یک شی از نوع DOM می‌باشد.

- تابع onInput.Listen() رویدادی را برای پاسخگویی به ورود اطلاعات در فیلد input تعریف می‌کند. زمانی که کاربر اطلاعاتی را وارد نماید، تابع updateBadge فراخوانی می‌گردد.

- رویداد input زمانی رخ می‌دهد که کاربر کلیدی را از صفحه کلید فشار دهد.

- رشته‌ها همانند جاوا اسکریپت می‌توانند در " یا '  قرار بگیرند.


تابع زیر را به صورت top-level یعنی خارج از تابع main تعریف کنید.

...

void updateBadge(Event e) { 
  querySelector('#badgeName').text = e.target.value;
}

توضیحات

- این تابع محتوای المنت badgeName را به محتوای وارد شده در فیلد input تغییر می‌دهد.

- پارامتر ورودی این تابع شی e از نوع Event می‌باشد و به همین دلیل می‌توانیم این تابع را یک Event Handler بنامیم.

- e.target به شی ای اشاره می‌کند که موجب رخداد رویداد شده است و در اینجا همان فیلد input می‌باشد

- با نوشتن کد فوق یک warning را مشاهده می‌کنید که بیان می‌کند ممکن است خصوصیت value برای e.target وجود نداشته باشد. برای حل این مسئله کد را بصورت زیر تغییر دهید.

...

void updateBadge(Event e) { 
  querySelector('#badgeName').text = (e.target as InputElement).value;
}

توضیحات

- کلمه کلیدی as به منظور تبدیل نوع استفاده می‌شود که e.target را به یک InputElement تبدیل می‌کند.

همانند گام اول برنامه را اجرا کنید و نتیجه را مشاهده نمایید. با تایپ کردن در فیلد input به صورت همزمان در کادر قرمز رنگ نیز نتیجه تایپ را مشاهده می‌نمایید. 

مطالب
معرفی Selector های CSS - قسمت 5
41- :checked
برای تگ‌های radio و checkbox استفاده می‌شود و آنهایی را انتخاب می‌کند که گزینه‌ی آن‌ها انتخاب شده است یا شامل ویژگی checked می‌باشند.
<style>
    :checked {
        width: 50px;
        height: 50px;
    }
</style>
<input type="checkbox" checked="checked"/>
<input type="checkbox"/>
<input type="radio" name="test"/>
<input type="radio" name="test" checked="checked"/>
<input type="radio" name="test"/>
در مثال فوق تمامی checkbox هایی که گزینه‌ی آن‌ها انتخاب شده‌اند با ابعاد 50 در 50 نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.2  9.6  9.0 3.5  4.0 :checked  3

42- :indeterminate
در HTML نمی‌توان وضعیت indeterminate را برای checkbox ایجاد نمود. اما با جاوا اسکریپت می‌توان این وضعیت را ایجاد کرد. هر checkbox می‌تواند دارای سه وضعیت انتخاب شده، انتخاب نشده و نامعلوم (indeterminate) باشد. این Selector تگهای checkbox ی را انتخاب می‌نماید که وضعیت نامعلوم دارند.
<style>
    :indeterminate {
        width: 50px;
        height: 50px;
    }
</style>
<input type="checkbox" id="chk1"/>
<input type="checkbox" id="chk2" checked="checked"/>
<input type="checkbox" id="chk3"/>
<script>
    document.getElementById("chk1").indeterminate=true;
</script>
در مثال فوق chk1 به صورت indeterminate انتخاب شده است که با ابعاد 50 در 50 نمایش می‌یابد.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 No   No   No  No 
 No :indeterminate  4

43- :default
برای تگ‌های radio و checkbox، آنهایی را انتخاب می‌کند که در زمان بارگزاری فرم و بصورت پیش فرض انتخاب شده‌اند. برای دکمه‌ی submit ایی نیز استفاده می‌شود که در حال حاضر در فرم فعال می‌باشد. پشتیبانی از این Selector در مرورگرها متفاوت می‌باشد؛ بنابراین در چند مرورگر کارآیی آن را بررسی کنید.
<style>
    :default {
        width: 50px;
        height: 50px;
        background: lime;
    }
</style>
<form>
    <input type="checkbox" checked="checked" />
    <input type="checkbox" />
    <input type="radio" name="radio1" />
    <input type="radio" name="radio1" checked="checked" />
    <input type="radio" name="radio1" />
    <input type="submit" value="Default" />
    <input type="submit" value="Submit 2" />
</form>
در مثال فوق checkbox و radio هایی که در لود اولیه فرم دارای ویژگی checked می‌باشند به همراه دکمه‌ی submit با عنوان Default با ابعاد 50 در 50 و رنگ پس زمینه‌ی لیمویی نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 No   No   No  No 
 No :default  4

44- :root
المنت ریشه‌ی یک صفحه را انتخاب می‌نماید. معمولا تگ html به عنوان المنت ریشه انتخاب می‌شود.
<style>
    :root {
        background: khaki;
    }
</style>
در مثال فوق رنگ پس زمینه به رنگ خاکی نمایش می‌یابد.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.2  9.6  9.0 3.5  4.0 :root  3

45- :after
جهت درج محتوا بعد از تگ استفاده می‌شود.
<style>
    form:after {
        content: "[ * : Required]";
        color: red;            
    }
        input+span:after {
            content: ' * ';
            color: red;
        }
</style>
<form>
    <div><input type="text" /><span></span></div>
    <div><input type="password" /><span></span></div>
    <div><input type="email" /><span></span></div>
</form>
در مثال فوق بعد از تمامی span‌های قرار گرفته در کنار تگ‌های input، یک کاراکتر * را به رنگ قرمز نمایش میدهد. بعد از فرم نیز رشته‌ی [ * : Required] را به رنگ قرمز نمایش می‌دهد.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.1 7.0  9.0 3.5  4.0 :after 2

46- :before
جهت درج محتوا قبل از تگ استفاده می‌شود.
<style>
    form:before {
        content: "[ * : Required]";
        color: red;
    }

    input + span:before {
        content: ' * ';
        color: red;
    }
</style>
<form>
    <div><input type="text" /><span></span></div>
    <div><input type="password" /><span></span></div>
    <div><input type="email" /><span></span></div>
</form>
در مثال فوق قبل از تمامی span‌های قرار گرفته در کنار تگ‌های input، یک کاراکتر * را به رنگ قرمز نمایش می‌دهد. قبل از فرم نیز رشته‌ی [ * : Required] را به رنگ قرمز نمایش می‌دهد.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.1 7.0  9.0 3.5  4.0 :before 2

47- ::selection
محتوایی را انتخاب می‌کند که در حال حاضر در صفحه انتخاب یا Select شده‌است.
<style>
    ::selection {
        background: navy;
        color: orange;
    }
</style>
<p>
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. 
    Maecenas porttitor congue massa. Fusce posuere, 
    magna sed pulvinar ultricies, purus lectus malesuada libero, 
    sit amet commodo magna eros quis urna. Nunc viverra imperdiet enim. Fusce est.
</p>
در مثال فوق با انتخاب متن توسط ماوس، رنگ زمینه‌ی متن انتخاب شده به صورت سرمه ای و رنگ متن آن نارنجی نمایش می‌یابد.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.1  9.6  9.0 2.0
-moz-
 4.0 ::selection  در CSS 3 معرفی و سپس حذف شد ولی امکان بازگشت مجدد وجود دارد

48- :not(S1,S2)
تگ هایی را انتخاب می‌کند که شامل Selector‌های S1 یا S2 یا ... یا Sn نباشند.
<style>
    :not([readonly]) {
        background: yellow;
    }
</style>
<input type="text"/>
<input type="text" readonly="readonly"/>
<input type="text"/>
<input type="text" readonly="readonly" />
در مثال فوق پس زمینه‌ی تگهای input که ویژگی readonly ندارند به رنگ زرد نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.2  9.6  9.0 3.5  4.0 :not(S1,S2)  3

49- :matches(S1,S2)
تگ هایی را انتخاب می‌کند که شامل Selector‌های S1 و/یا S2 و/یا ... و/یا Sn باشند. 
<style>
    :matches([readonly]) {
        background: yellow;
    }
</style>
<input type="text" />
<input type="text" readonly="readonly" />
<input type="text" />
<input type="text" readonly="readonly" />
در مثال فوق پس زمینه‌ی تگهای input که ویژگی readonly دارند به رنگ زرد نمایش می‌یابند. 
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 No   No   No  No 
 No :matches(S1,S2)  4

50- :has(S1,S2)
تگ هایی را انتخاب می‌کند که در ارتباط خاصی با Selector های S1 و/یا S2 و/یا ... و/یا Sn می‌باشند. 
<style>
    :has(>span) {
        color: red;
    }
    :has(+div) {
        color: blue;
    }
</style>
<div>
    <p>
        Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
        Maecenas <span>porttitor</span> congue massa. Fusce posuere,
        magna sed pulvinar ultricies, purus lectus malesuada libero,
        sit amet commodo magna eros quis urna. Nunc viverra imperdiet enim. Fusce est.
    </p>
    <h1>Header 1</h1>
    <div>
            
        Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
        Maecenas porttitor congue massa. Fusce posuere,
        magna sed pulvinar ultricies, purus lectus malesuada libero,
        sit amet commodo magna eros quis urna. Nunc viverra imperdiet enim. Fusce est.            
    </div>
در مثال فوق متن موجود در تگ p که دارای فرزند مستقیم span می‌باشد، با توجه به Selector ی که بصورت :has(>span) تعریف شده است، به رنگ قرمز نمایش می‌یابد. همچنین Header 1 که دارای تگ div هم تراز و دقیقا بعد از h1 است، با توجه به Selector ی که بصورت  :has(+div) تعریف شده است، به رنگ آبی نمایش می‌یابد.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 No   No   No  No 
 No :has(S1,S2)  4 
مطالب
آموزش فایرباگ - #4 - JavaScript Development
در قسمت قبل با توابع خط فرمان آشنا شدیم . در این قسمت با توابع کنسول آشنا خواهیم شد .

فایرباگ یک متغییر عمومی به نام console دارد که به همه‌ی صفحات باز شده در فایرفاکس اضافه می‌کند . این شیء متدهایی دارد که بوسیله آن‌ها می‌توانیم عملیاتی در برنامه مان انجام داده و اطلاعاتی را در کنسول چاپ کنیم .

بعضی از این متدها عملکردی مشابه متدهای خط فرمان ( که در قسمت قبل شرح داده شدند ، ) دارند که از توضیح مجدد آن‌ها اجتناب می‌کنیم .

توابع کنسول - Console API :

توجه : همانند قسمت قبل ، در این قسمت هم برای همراه شدن با تست‌ها ، کد صفحه‌ی زیر را ذخیره کنید و برای اجرای کدها ، آن‌ها را در قسمت خط فرمان ( در تب کنسول ) قرار بدهید و دکمه‌ی Run ( یا Ctrl + Enter ) را بزنید .
<input type="button" onclick="startTrace('Some Text')" value="startTrace" />
<input type="button" onclick="startError()" value="test Error" />

<script type="text/javascript">
    function startTrace(str) {
        return method1(100, 200);
    }
    function method1(arg1, arg2) {
        return method2(arg1 + arg2 + 100);
    }
    function method2(arg1) {
        var var1 = arg1 / 100;
        return method3(var1);
    }
    function method3(arg1) {
        console.trace();
        var total = arg1 * 100;
        return total;
    }

    function testCount() {
        // do something
        console.count("testCount() Calls Count .");
    }

    function startError() {
        testError();
    }

    function testError() {
        var errorObj = new Error();
        errorObj.message = "this is a test error";
        console.exception(errorObj);
    }

    function testFunc() {
        var t = 0;
        for (var i = 0; i < 100; i++) {
            t += i;
        }
    }
</script>
  • console.log(object[,object,...])

    این دستور یک پیغام در کنسول چاپ می‌کند .
    console.log("This is a log message!");
    نتیجه :



    این دستور را می‌توانیم به شکل‌های مختلفی فراخوانی کنیم .
    مثلا :
    console.log(1 , "+" , 2 , "=", (1+2));
    نتیجه :


    در این دستور می‌توانیم از چند حرف جایگزین هم استفاده کنیم .


    مثال :

    console.log("Firebug 1.0 beta was %s in December %i.","released",2006);
    نتیجه :


    عملکرد 3 جایگزین نخست با توجه با مثال قبل مشخص شد . پس به سراغ جایگزین %o و %c می‌رویم .
    اگر در رشته‌ی مورد نظر ، یک شیء ( تابع ، آرایه ، ... ) برای جایگزین %o ارسال کنیم ، در خروجی آن شیء بصورت لینک نمایش داده می‌شود که با کلیک بروی آن ، فایرباگ آن شیء را در تب مناسبش Inspect می‌کند .
    مثال :
    console.log("this is a test functin : %o",testFunc);

    نتیجه :



    و زمانی که بروی لینک testFunc کلیک کنیم :



    یک ترفند : بوسیله جایگزین %o توانستیم به تابع مورد نظر لینک بدهیم . اگر بجای جایگزین %o از %s استفاده کنیم ، می‌توانیم بدنه‌ی تابع را ببینیم :
    console.log("this is a test functin : %s",testFunc);
    نتیجه :




    توسط جایگزین %c هم می‌توانید خروجی را فرمت کنید .

    console.log("%cThis is a Style Formatted Log","color:green;text-decoration:underline;");

    نتیجه :


  • console.debug(object[, object, ...])
  • console.info(object[, object, ...])
  • console.warn(object[, object, ...])
  • console.error(object[, object, ...])

    مشابه با دستور log عمل می‌کنند با این تفاوت که خروجی را با استایل متفاوتی نمایش می‌دهند .
    همچنین هر یک از این دستورات ، توسط دکمه‌های همنام در کنسول قابل فیلتر شدن هستند .



  • console.assert(expression[, object, ...])

    چک می‌کند که عبارت ارسال شده true هست یا نه . اگر true نبود ، پیغام وارد شده را چاپ و یک استثناء ایجاد می‌کند .
    console.assert(1==1,"this is a test error");
    console.assert(1!=1,"this is a test error");

    نتیجه :



  • console.clear()
  • console.dir(object)
  • console.dirxml(node)
  • console.profile([title])
  • console.profileEnd()

  • این توابع معادل توابع همنامشان در خط فرمان هستند که در قسمت قبل با عملکردشان آشنا شدیم .

  • console.trace()

    با این متد می‌توانید پی ببرید که از کجا و توسط چه متدهایی برنامه به قسمت trace رسیده . برای درک بهتر مجددا اسکریپت صفحه‌ی تست این مقاله را بررسی کنید ( جایی که متد trace قرار داده شده است ) .
    اکنون صفحه‌ی تست را باز کنید و بروی دکمه‌ی startTrace کلیک کنید . خروجی ظاهر شده در کنسول را از پایین به بالا بررسی کنید .


    حتما متوجه شدید که متد method3 چگونه در کدهایمان فراخوانی شده است !؟
    ابتدا با کلیک بروی دکمه‌ی startTrace ، متد startTrace اجرا شده و به همین ترتیب متد startTrace متد method1 ، متد method1 هم متد method2 و در نهایت method2 متد method3 را فراخوانی کرده است .
    دستور trace زمانی که در حال بررسی کدهای برنامه نویسان دیگر هستید ، بسیار می‌تواند به شما کمک کند .

  • console.group(object[, object, ...])

    با این دستور می‌توانید لاگ‌های کنسول را بصورت تو در تو گروه بندی کنید .
    console.group("Group1");
    console.log("Log in Group1");
    console.group("Group2");
    console.log("Log in Group2");
    console.group("Group3");
    console.log("Log in Group3");
    نتیجه :



  • console.groupCollapsed(object[, object, ...])

    این دستور معادل دستور قبلی است با این تفاوت که هنگام ایجاد ، گروه را جمع می‌کند .

  • console.groupEnd()

    به آخرین گروه بندی ایجاد شده خاتمه می‌دهد .

  • console.time(name)

    یک تایمر با نام داده شده ایجاد می‌کند . زمانی که نیاز دارید زمان طی شده بین 2 نقطه را اندازه گیری کنید ، این تابع مفید خواهد بود .

  • console.timeEnd(name)

    تایمر همنام را متوقف و زمان طی شده را چاپ می‌کند .
    console.time("TestTime");
    var t = 1;
    for (var i = 0; i < 100000; i++) { t *= (i + t) }
    console.timeEnd("TestTime");
    نتیجه :


  • console.timeStamp()

    توضیحات کامل را از اینجا دریافت کنید .

  • console.count([title])

    تعداد دفعات فراخوانی شدن کدی که این متد در آنجا قرار دارد را چاپ می‌کند .
    البته ظاهرا در ورژن 10.0.1 که بنده با آن کار می‌کنم ، این دستور بی عیب کار نمی‌کند . زیرا بجای آنکه در هربار فراخوانی ، در همان خط تعداد فراخوانی را نمایش بدهد ، فقط اولین لاگ را آپدیت می‌کند .


  • console.exception(error-object[, object, ...])

    یک پیغام خطا را به همراه ردیابی کامل اجرای کدها تا زمان رویداد خطا ( مانند متد trace ) چاپ می‌کند .
    در صفحه‌ی تست این متد را اجرا کنید :
    startError();
    نتیجه :

     توجه کنید که ما برای مشاهده‌ی عملکرد صحیح این دستور ، آن را در تابع testError قرار دادیم و بوسیله تابع startError آن فراخوانی کردیم .

  • console.table(data[, columns])

    بوسیله این دستور می‌توانید مجموعه ای از اطلاعات را بصورت جدول بندی نمایش بدهید .
    این متد از متدهای جدیدی است که در فایرباگ قرار داده شده است .


    برای اطلاعات بیشتر به اینجا مراجعه کنید .

منابع :
مطالب
ایجاد یک HtmlHelper سفارشی با پشتیبانی از UnobtrusiveValidationAttributes
همانطور که می‌دانید، در MVC برای اعتبارسنجی داده‌ها در سمت کلاینت از کتابخانه‌ی jquery استفاده می‌شود. مایکروسافت از طریق jquery.validate.unobtrusive و گسترش کتابخانه‌ی jquery.validate توانسته منطق خود را برای اعتبارسنجی داده‌ها در سمت کلاینت پیاده سازی کند. 
برای این منظور MVC به کنترلهایی که باید اعتبارسنجی شوند، خصوصیاتی را از طریق Data Attribute اضافه می‌کند. برای مثال اگر در مدل خود فیلد ایمیل را به شکل زیر امضاء کرده باشید:
[Display(Name = "رایانامه")]
[Required(AllowEmptyStrings = false, ErrorMessage = "رایانامه خود را وارد کنید.")]
[RegularExpression("\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*", ErrorMessage = "نشانی رایانامه پذیرفتنی نمی‌باشد.")]
[ExistField(Action = "EmailExist", Namespace = "Parsnet.Controllers", Controller = "Account", ErrorMessage = "این رایانامه پیشتر به کار گرفته شده است.")]
        public string Email { get; set; }
و در View مورد نظر از Htmlhlper مربوطه به شکل زیر استفاده کرده باشید:
@Html.TextBoxFor(m => m.Email, new { @class = "form-control en", placeholder = @Html.DisplayNameFor(m => m.Email) })
در نهایت، Html خروجی در سمت کلاینت به شکل زیر خواهد بود:
<input data-val="true" data-val-existfiledvalidator="این رایانامه پیشتر به کار گرفته شده است." data-val-existfiledvalidator-url="/account/emailexist" data-val-regex="نشانی رایانامه پذیرفتنی نمی‌باشد." data-val-regex-pattern="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" data-val-required="رایانامه خود را وارد کنید." id="Email" name="Email" placeholder="رایانامه" value="" type="text">
و در اینجا کتابخانه‌ی اعتبارسنجی MVC با استفاده از همین خصوصیات *-data، اطلاعات مورد نیاز را جهت نمایش، اعتبارسنجی، تنظیم و بکارگیری، مورد استفاده قرار می‌دهد.
در یکی از پروژه‌هایی که در حال کار کردن بر روی آن هستم لازم شد تا این اطلاعات اعتبارسنجی به یک تگ span اعمال شوند. سناریوی مورد نظر به این صورت است که در بخش پروفایل کاربر، کاربر می‌تواند اطلاعات خود را بصورت inline ویرایش کنید. برای اینکار از کتابخانه X-editable استفاده کردم که از این لینک قابل دریافت است.
ابتدا اطلاعات موردنیاز در یک تگ span نمایش داده می‌شوند و در ادامه کاربر پس از کلیک بر روی آیکن ویرایش، امکان تغییر آن فیلد را دارد. برای اعتبارسنجی داده‌ها لازم بود تا تمامی اطلاعات مورد نیاز اعتبارسنجی در سمت کلاینت را به شکلی در اختیار داشته باشم و به ذهنم رسید تا با ایجاد یک Helper سفارشی، خصوصیات موردنظر را به تگ span اعمال کنم و سپس در سمت کلاینت از آن استفاده کنم. در واقع با اینکار با استفاده از همان کلاس مدل و این Helper سفارشی، از وارد کردن دستی داده‌ها و خصوصیات اجتناب کنم. (تصور کنید چیزی حدود 30 فیلد که هرکدام حداقل 4 خصوصیت دارند)
با نگاهی به سورس MVC دیدم پیاده سازی این قابلیت چندان سخت نیست و به راحتی با ایجاد یک Helper سفارشی، منطق خود را پیاده سازی و اعتبارسنجی در سمت کلاینت را به راحتی اعمال کردم.
برای ایجاد این Helper سفارشی ابتدا یک کلاس استاتیک ایجاد کنید و با استفاده از extension Method‌ها یک helper جدید را ایجاد کنید:
namespace Parsnet
{
     public static MvcHtmlString SpanFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
        {
            
            var sb = new StringBuilder();

            var span = new TagBuilder("span");

            var metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData);
            var name = ExpressionHelper.GetExpressionText(expression);
            var fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
            var value = "";

            if (metadata.Model != null && metadata.Model.GetType() == typeof(List<IdentityProvider.IdentityRole>))
            {
                var modelList = (List<IdentityProvider.IdentityRole>)metadata.Model;
                value = String.Join("، ", modelList.Select(r => r.Name));
            }
            else
            {
                value = htmlHelper.FormatValue(metadata.Model, null);
            }

            span.MergeAttributes<string, object>(((IDictionary<string, object>)HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)));

            var fieldName = fullName.Split('.')[1];
            span.MergeAttribute("data-name", fieldName, true);
            span.MergeAttributes<string, object>(htmlHelper.GetUnobtrusiveValidationAttributes(name, metadata));

            sb.Append(span.ToString(TagRenderMode.StartTag));
            sb.Append(value);
            sb.Append(span.ToString(TagRenderMode.EndTag));

            return new MvcHtmlString(sb.ToString());
        }
    }
}
ما در این helper سفارشی از عبارت‌های لامبدا استفاده می‌کنیم و با استفاده از این عبارات، فیلد مورد نظر مدل خود را به helper معرفی می‌کنیم. آرگومان htmlAttributes در متد helper نیز برای دریافت خصوصیات اضافی helper است؛ خصوصیاتی مانند class، id, style و غیره.
با استفاده از کلاس TagBuilder تگ مورد نظر خود را ایجاد می‌کنیم. در اینجا من تگ span را ایجاد کرده‌ام که شما می‌توانید هر تگ دلخواه دیگری را نیز ایجاد کنید. اولین مرحله، استخراج اطلاعات موردنیاز از metadata مدل است که در خط زیر با پردازش عبارت لامبدا اینکار صورت می‌گیرد:
var metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData);
سپس نام فیلد مورد نظر را از مدل استخراج می‌کنیم:
var name = ExpressionHelper.GetExpressionText(expression);
var fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
کدهای فوق نام فیلد جاری (در اینجا Email) را از MetaData برای ما استخراج می‌کند. متغیر value برای نگهداری مقدار این فیلد از مدل است. مرحله بعد استخراج مقدار فیلد و انتساب آن به متغیر value است.
در سناریوی من کاربر می‌تواند زمینه‌ی فعالیت خود را انتخاب کند که به صورت IdentityRole پیاده سازی شده است. من در اینجا چک می‌کنیم که اگر نوع داده‌ای این فیلد List<IdentityProvider.IdentityRole> بود زمینه فعالیت کاربر را از طریق "،" از هم جدا کرده و به صورت یک رشته تبدیل می‌کنم. در غیر اینصورت همان مقدار عادی فیلد را بکار می‌گیرم.
if (metadata.Model != null && metadata.Model.GetType() == typeof(List<IdentityProvider.IdentityRole>))
            {
                var modelList = (List<IdentityProvider.IdentityRole>)metadata.Model;
                value = String.Join("، ", modelList.Select(r => r.Name));
            }
            else
            {
                value = htmlHelper.FormatValue(metadata.Model, null);
            }
سپس خصوصیات سفارشی خود را که بصورت attribute‌های HTML هستند، در خط زیر به تگ سفارشی اعمال می‌شوند:
span.MergeAttributes<string, object>(((IDictionary<string, object>)HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)));
مهمترین مرحله که در واقع هدف اصلی من بود، استخراج خصوصیت‌های *-data برای اعتبارسجی است که در خط زیر اینکار صورت گرفته است:
 span.MergeAttributes<string, object>(htmlHelper.GetUnobtrusiveValidationAttributes(name, metadata));
نحوه‌ی استفاده از این helper سفارشی هم خیلی ساده است:
@Html.SpanFor(m => m.Profile.Email, new { @class = "editor", data_type = "text" })
و در نهایت HTML خروجی به شکل زیر است:
<span class="editor" data-name="Email" data-type="text" data-val="true" data-val-existfiledvalidator="این رایانامه پیشتر به کار گرفته شده است." data-val-existfiledvalidator-url="/account/emailexist" data-val-regex="نشانی رایانامه پذیرفتنی نمی‌باشد." data-val-regex-pattern="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" data-val-required="رایانامه خود را وارد کنید.">alireza_s_84@yahoo.com</span>
دیدن شکل‌های زیر خالی از لطف نیستند:

و پس از ویرایش:


البته برای درک بهتر این موضوع سعی خواهم کرد تا با یک مثال عملی کامل، نحوه‌ی پیاده سازی را در همینجا قرار دهم.
مطالب
معرفی Selector های CSS - قسمت 2
11- S1,S2
اگر بخواهیم قالب بندی را برای چند Selector به صورت یکجا انجام دهیم، این Selector‌ها را با کاما (,) از هم جدا می‌نماییم.
<style>
    div,.content,table.main {
        color: red;
    }
</style>
<div>Text 1</div>
<p>Text 2</p>
<table class="main" border="1">
    <tr>
        <td>Cell 1</td>
        <td>Cell 2</td>
        <td>Cell 3</td>
    </tr>
    <tr>
        <td>Cell 4</td>
        <td>Cell 5</td>
        <td>Cell 6</td>
    </tr>
</table>
<span class="content">Text 3</span>
<h1>Text 4</h1>
در مثال فوق Text 1 و Text 3 و همچنین محتوای تگ table به رنگ قرمز نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 Yes  Yes  Yes Yes   Yes S1,S2  1
توجه:
Selector‌ها می‌توانند به صورت ترکیبی نیز استفاده شوند. به مثال زیر توجه کنید:
<style>
    .content .tag {
        color: red;
    }

    h1#index {
        color: blue;
    }

    ul.list li.even {
        color: green;
    }
</style>
<h1 id="index">Index</h1>
<h1>Header 1</h1>
<div class="content">
    Lorem ipsum dolor sit amet, <span class="tag">consectetuer</span> adipiscing elit.
    Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies,
    purus lectus malesuada libero, <span class="tag">sit</span> amet commodo magna 
    eros quis urna. Nunc viverra <span class="tag">imperdiet</span> enim. Fusce est.
</div>
<h1>Header 2</h1>
<div class="content">
    <ul class="list">
        <li>Item 1</li>
        <li class="even">Item 2</li>
        <li>Item 3</li>
        <li class="even">Item 4</li>
        <li>Item 5</li>
        <li class="even">Item 6</li>
    </ul>
</div>
در مثال فوق، تگ h1 که ویژگی id آن برابر index می‌باشد، با توجه به Selector ی که بصورت h1#index تعریف شده است، به رنگ آبی نمایش می‌یابد. تمامی تگ‌های span که عضو کلاس tag می‌باشند و در داخل تگ div ی قرار دارند که عضو کلاس content است، با توجه به Selector ی که بصورت .content .tag تعریف شده است، به رنگ قرمز نمایش می‌یابند. تمامی تگهای li که ویژگی class آنها برابر even می‌باشد، و فرزند تگ ul ی هستند که عضو کلاس list است، با توجه به Selector ی که بصورت ul.list li.even تعریف شده است، به رنگ سبز نمایش می‌یابند.

12- [attribute]

تگ‌هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص باشند.
<style>
    [readonly] {
        background: green;
    }
</style>
<input type="text" value="Value 1" readonly="readonly"/>
<input type="text"/>
در مثال فوق، رنگ پس زمینه تگ input اول که دارای ویژگی readonly می‌باشد، به رنگ سبز نمایش می‌یابد.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.1  9.6  7.0 2.0  4.0 [attribute]    2

13- 
 [attribute=value] 
تگ هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی دقیقا برابر با value می‌باشد.
<style>
    [lang=fa] {
        direction:rtl;
    }
</style>
<div lang="fa">متن 1</div>
در مثال فوق، جهت نوشتاری محتوای تگ div که دارای ویژگی lang با مقدار fa می‌باشد، از راست به چپ می‌شود و در سمت راست صفحه نمایش می‌یابد.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.1 9.6 7.0 2.0 4.0 [attribute=value] 
 2

14-
   [attribute=value i]
تگ‌هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی دقیقا برابر با value می‌باشد. همچنین value، نسبت به حروف کوچک و بزرگ حساس نمی‌باشد. 
<style>
    [lang=fa] {
        direction:rtl;
    }
</style>
<div lang="FA">متن 1</div>
در مثال فوق، جهت نوشتاری محتوای تگ div که دارای ویژگی lang با مقدار FA می‌باشد، از راست به چپ می‌شود و در سمت راست صفحه نمایش می‌یابد. با اینکه در Selector مقدار fa با حروف کوچک ذکر شده است.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 No   No   No  No 
 No [attribute=value i] 
 4

15- 
 [attribute|=value] 
تگ هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی با یک value خاص آغاز می‌شود. کلمه آغازین مقدار حتما باید با value برابر باشد یا با dash (-) از کلمه‌ی بعدی جدا شده باشد.
<style>
    [class|=info] {
        color:red
    }
</style>
<div class="info">Text 1</div>
<div class="infobar">Text 2</div>
<div class="info bar">Text 3</div>
<div class="info-bar">Text 4</div>
<div class="btninfo">Text 5</div>
<div class="btn info">Text 6</div>
<div class="btn-info">Text 7</div>
<div class="toolinfoicon">Text 8</div>
<div class="tool info icon">Text 9</div>
<div class="tool-info-icon">Text 10</div>
در مثال فوق Text 1 و Text 4 به رنگ قرمز نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.1  9.6  7.0 2.0  4.0 [attribute|=value] 
 2

16- 
 [attribute^=value] 
تگ‌هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی با یک value خاص آغاز می شود.
<style>
    [class^=info] {
        color: red;
    }
</style>
<div class="info">Text 1</div>
<div class="infobar">Text 2</div>
<div class="info bar">Text 3</div>
<div class="info-bar">Text 4</div>
<div class="btninfo">Text 5</div>
<div class="btn info">Text 6</div>
<div class="btn-info">Text 7</div>
<div class="toolinfoicon">Text 8</div>
<div class="tool info icon">Text 9</div>
<div class="tool-info-icon">Text 10</div>
در مثال فوق Text 1 و Text 2 و Text 3 و Text 4 به رنگ قرمز نمایش می‌یابند. 
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.2  9.6  7.0 3.5  4.0 [attribute^=value] 
 3

17- 
 [attribute~=value] 
تگ‌هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی شامل یک value خاص می‌باشد که با Space یا فاصله‌ی خالی از سایر مقادیر جدا شده است. 
<style>
    [class~=info] {
        color: red;
    }
</style>
<div class="info">Text 1</div>
<div class="infobar">Text 2</div>
<div class="info bar">Text 3</div>
<div class="info-bar">Text 4</div>
<div class="btninfo">Text 5</div>
<div class="btn info">Text 6</div>
<div class="btn-info">Text 7</div>
<div class="toolinfoicon">Text 8</div>
<div class="tool info icon">Text 9</div>
<div class="tool-info-icon">Text 10</div>
در مثال فوق Text 1 و Text 3 و Text 6 و Text 9 به رنگ قرمز نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.1  9.6  7.0 2.0  4.0 [attribute~=value] 
 2

18- 
 [attribute*=value] 
تگ‌هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی شامل یک value خاص می‌باشد. 
<style>
    [class*=info] {
        color: red;
    }
</style>
<div class="info">Text 1</div>
<div class="infobar">Text 2</div>
<div class="info bar">Text 3</div>
<div class="info-bar">Text 4</div>
<div class="btninfo">Text 5</div>
<div class="btn info">Text 6</div>
<div class="btn-info">Text 7</div>
<div class="toolinfoicon">Text 8</div>
<div class="tool info icon">Text 9</div>
<div class="tool-info-icon">Text 10</div>
در مثال فوق تمامی متون به رنگ قرمز نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.2  9.6  7.0 3.5  4.0 [attribute*=value] 
 3

19- 
[attribute$=value]
تگ‌هایی را انتخاب می‌نماید که دارای یک attribute یا ویژگی خاص هستند و مقدار آن ویژگی به یک value خاص ختم می‌شود. 
<style>
    [class$=info] {
        color: red;
    }
</style>
<div class="info">Text 1</div>
<div class="infobar">Text 2</div>
<div class="info bar">Text 3</div>
<div class="info-bar">Text 4</div>
<div class="btninfo">Text 5</div>
<div class="btn info">Text 6</div>
<div class="btn-info">Text 7</div>
<div class="toolinfoicon">Text 8</div>
<div class="tool info icon">Text 9</div>
<div class="tool-info-icon">Text 10</div>
در مقال فوق Text 1 و Text 5 و Text 6 و Text 7 به رنگ قرمز نمایش می‌یابند.
پشتیبانی در مرورگرها:

 Selector نسخه CSS
 3.2  9.6  7.0 3.5  4.0 [attribute$=value] 
 3   
مطالب
آموزش (jQuery) جی کوئری 2#
در ادامه مطلب قبلی آموزش (jQuery) جی کوئری 1# به ادامه بحث می‌پردازیم.

توابع سودمند
با وجود آنکه انتخاب کردن و ایجاد مجموعه ای از عناصر صفحه یکی از معمول‌ترین و پراستفاده‌ترین کاربردهای تابع ()$ محسوب می‌شود، این تابع توانایی‌های دیگری نیز دارد. یکی از مفید‌ترین آنها استفاده شدن به عنوان فضای نام گروهی برای توابع سودمند می‌باشد. تعداد زیادی تابع سودمند با استفاده از $ به عنوان فضای نام قابل دسترسی می‌باشند که اکثر نیازهای یک صفحه را پاسخگو می‌باشند در این پست برخی از آنها را معرفی می‌کنیم در پست‌های آینده سعی می‌کنیم توابع سودمند بیشتری را شرح دهیم.

فراخوانی و استفاده از این توابع در ابتدا ممکن است کمی عجیب به نطر برسد. به مثال زیر دقت کنید که تابع سودمند () trim را فراخوانی کرده ایم.
$.trim(someString);
 
در صورتی که نوشتن علامت $ برای شما عجیب به نطر می‌رسد می‌توانید شناسه دیگر با نام jQuery به کار ببرید. کد زیر دقیقا مانند بالا عمل می‌کند شاید درک آن راحت‌تر هم باشد.
jQuery.trim(someString);

بدیهی است که از  jQuery یا $ تنها به عنوان فضای نامی که تابع ()trim در آن تعریف شده اند، استفاده شده باشد.

نکته: اگر چه در نوشته‌های آنلاین jQuery، این عناصر به عنوان توابع سودمند در معرفی شده اند اما در حقیقت آنها متدهایی برای تابع ()$ می‌باشند.

عملکرد صفحه آماده (The document ready handler)
هنگامی که از Unobtrusive JavaScriptاستفاده می‌کنیم، رفتار از ساختار جدا می‌شود، بنابراین برای انجام عملیات روی عناصر صفحه باید منتظر بمانیم تا انها ایجاد شوند. برای رسیدن به این هدف، ما نیاز به راهی داریم که تا زمان ایجاد عناصر DOM روی صفحه منتظر بماند قبل از آن عملیات را اجرا کند.
به طور معمول از onload برای نمونه‌های window استفاده می‌شود، که پس از لود شدن کامل صفحه ، دستور‌ها قابل اجرا می‌باشند. بنابراین ساختار کلی آن کدی مانند زیر خواهد بود:
window.onload = function() {
    $("table tr:nth-child(even)").addClass("even");
};

نوشتن کد به صورت بالا سبب می‌شود که کد پس از بارگذاری کامل صفحه اجرا شود. متاسفانه، مرورگرها تا بعد از ساخته شدن عناصر صفحه صبر نمی‌کنند، بلکه پس از ساخت درخت عناصر صفحه منتظر بارگذاری کامل منابع خارجی صفحه مانند تصاویر نیز می‌مانند و سپس آنها را در پنجره مرورگر نمایش می‌دهند. در نتیجه بازدید کننده زمان زیادی منتظر می‌ماند تا رویداد onload تکمیل شود.
حتی بدتر از آن، زمانی است که اگر به طور مثال یکی از تصاویر با مشکل مواجه شود که زمان قابل توجهی صرف بارگذاری آن شود، کاربر باید تمام این مدت را صبر کند تا پس از آن بتواند با این صفحه کار کند. این نکته می‌تواند دلیلی برای استفاده نکردن از Unobtrusive JavaScriptبرای شروع کار باشد.
اما راه بهتری نیز وجود دارد، می‌توانیم تنها زمانی که قسمت ساختار عناصر صفحه ترجمه شده و HTML به درخت عناصر تبدیل می‌شود، صبر کنیم . پس از آن کد مربوط به رفتار‌ها را اجرا کنیم. رسیدن به این روش برای استفاده از Cross-Browser کمی مشکل است، اما به لطف jQuery و قدرت آن، این امر به سادگی امکان پذیر است و دیگر نیازی به منتظر ماندن برای بارگذاری منابع صفحه مانند تصاویر و ویدیوها نمی‌باشد. Syntax زیر نمونه ای از چنین حالتی است:
$(document).ready(function() {
   $("table tr:nth-child(even)").addClass("even");
});

ابتدا صفحه مورد نظر را به تابع ()$ ارسال کرده ایم، سپس هر زمان که آن صفحه آماده شد (Ready) ، تابع ارسال شده به آن اجرا خواهد شد. البته می‌توان کد نوشته شده بالا را به شکل مختصرتری هم نوشت:
$(function() {
    $("table tr:nth-child(even)").addClass("even");
});

با ارسال تابع به ()$، ما مرورگر را مجبور می‌کنیم که برای اجرای کد تا زمانی که DOM کامل لود شود (فقط DOM لود شود) منتظر بماند. حتی بهتر از آن ما می‌توانیم از این تکنیک چندین با در همان سند HTML استفاده کرده و مرورگر تمامی تابع‌های مشخص شده توسط ما را به ترتیب اجرا خواهد کرد. (یعنی من در دیک صفحه می‌توانم چنین بار تابع ()ready را فراخوانی کنم). در مقابل روش OnLoad پنجره فقط اجازه اجرای یکبار تابع را به ما می‌دهد.
این هم یکی دیگر از کارکردهای دیگر تابع ()$ می‌باشد. حال به یکی دیگر از امکاناتی که این تابع برای ما فراهم می‌کند دقت کنید.

ساختن اجزای DOM (ساختن عناصر صفحه)
یکی دیگر از کارهایی که تابع ()$ می تواند برای ما انجام دهد ایجاد کردن عناصر صفحه است. به این منظور ورودی تابع ()$ را یک رشته که حاوی دستور HTML مربوط به ساخت یک عنصر می‌باشد، قرار می‌دهیم. برای مثال دستور زیر یک تگ p ایجاد می‌کند:
$("<p>Hi there!</p>")

اما ایجاد یک عنصر DOM یا (سلسله مراتب عناصر DOM) برای ما به تنهایی سودمند نیست، و هدف ما چیز دیگری است. ایجاد اشیا صفحه توسط ()$ زمانی برای ما مفید خواهد بود که بخواهیم به هنگام ساخت، تابعی بروی آن اعمال کنیم یا به محض ساخت آن را به تابعی ارسال کنیم به کد زیر دقت کنید:
<html>
   <head>
        <title>Follow me!</title>
        <script type="text/javascript" src="../scripts/jquery-1.2.js"></script>
        <script type="text/javascript">
           // در زمان Reday بودن صفحه عنصر مورد نظر ایجاد می‌شود
           $(function(){
              $("<p>Hi there!</p>").insertAfter("#followMe");
           });
        </script>
    </head>
<body>
     <p id="followMe">Follow me!</p>
</body>
</html>

در کد بالا زمانی که صفحه مورد نظر Ready شد تابع مورد نظر ما اجرا شده و در عناصر صفحه بعد از عنصری که id آن followMe می‌باشد یک عنصر p را ایجاد می‌کند. که خروجی آن شبیه تصویر زیر خواهد بود.

مزیت دیگر jQuery این است که در صورتی که امکانی را ندارد شما به آسانی می‌توانید آن را توسعه داده و برای آن پلاگین طراحی کنید.

برای پایان دادن به این پست همانطور که دیدیم jQuery قادر به انجام کارهای زیر است:
  • انتخاب عناصر و ایجاد مجموعه ای از آنها که آماده اعمال متد‌های مختلف می‌باشند.
  • استفاده به عنوان یک فضای نام برای توابع سودمند.
  • ایجاد اشیا مختلف HTML بروی صفحه.
  • اجرای کد به محض آماده شدن اشیای صفحه.

موفق وموید باشید

مطالب
آموزش (jQuery) جی کوئری 1#
با سلام خدمت دوستان عزیز
تصمیم گرفتم در طی چندین پست در حد توانم به آموزش jQuery بپردازم. (مطالب نوشته شده برداشت ازادی از کتاب jQuery in action است)

جی کوئری (jQuery) چیست؟
jQuery یک کتابخانه بسیار مفید برای جاوا اسکریپت است. بسیار ساده و کارآمد است و مشکل جاوا اسکریپت را برای تطابق با مرورگرهای اینترنتی مختلف برطرف نموده است؛ یادگیریjQuery بسیار آسان است. در جی کوئری کد جاوا اسکریپت از فایل HTML جدا شده و بنابراین کنترل کدھا و بھینه‌سازی آنھا بسیار ساده‌تر خواھد شد. توابعی برای کار با AJAX فراھم نموده و در این زمینه نیز کار را بسیار ساده کرده است. در جی کوئری می‌توان از خصوصیت فراخوانی زنجیره‌ای متدھا استفاده نمود و این باعث می‌شود چندین کد فقط در یک سطر قرار گیرد و در نتیجه کد بسیار مختصر گردد. در مقایسه با سایر ابزارهایی که تاکید عمده‌ای بروی تکنیک‌های هوشمند جاوا اسکریپت دارند، هدف جی کوئری تغییر تفکر سازندگان وب سایت‌ها، به ایجاد صفحه‌هایی با کارکرد بالا می‌باشد. به جای صرف زمان برای مقابله با پیچیدگی‌های جاوا اسکریپت پیشرفته، طراحان می‌توانند با استفاده از زمان و دانش خود در زمینه‌ی CSS، HTML، XHTML و جاوا اسکریپت‌های ساده، عناصر صفحه را مستقیما دستکاری کنند و از همین طریق تغییرهای گشترده و سریعی انجام دهند.

نکته: برای استفاده از جی کوئری باید HTML و CSS و جاوا اسکریپت آشنایی داشته باشید.

چگونه از جی کوئری استفاده کنیم؟
برای استفاده از جی کوئری باید ابتدا فایل آن را از سایت آن دانلود کرده و در پروژه خود استفاده نمایید. البته روش‌های دیگری برای استفاده از این فایل وجود دارد که در آینده بیشتر با آن آشنا خواهیم شد. برای استفاده از این فایل در پروژه باید به شکل زیر آن را به صفحه HTML خود معرفی کنیم.
<html>
   <head>
       <script type="text/javascript" src="jquery-1.9.1.min.js"></script>
   </head>
   <body>
   </body>
</html>
سپس بعد از معرفی خط فوق در قسمت head صفحه باید کد‌های خود را در یک تگ script بنویسیم.

کوتاه کردن کد: هر زمان شما خواسته باشید کارکرد یک صفحه وب را پویا‌تر کنید، در اکثر مواقع به ناچار این کار از طریق عناصری بروی صفحه انجام داده اید که با توجه به انتخاب شدن آنها، صفحه کارکردی خاص خواهد داشت. مثلا در جاوا اسکریپت اگر بخواهیم عنصری را که در یک radioGroup انتخاب شده است را برگردانیم باید کد‌های زیر را بنویسیم:
var checkedValue;
var elements = document.getElementByTagName ('input');
for (var n = 0; n < elements.length; n++) {
       if (elements[n].type == 'radio' && elements[n].name == 'myRadioGroup' && elements[n].checked) {
               checkedValue = elements[n].value;
       }
}
اما اگر بخواهیم همین کد را با جی کوئری بنویسیم:
var checkedValue = $ ('[name="myRadioGroup"]:checked').val();
ممکن است مثال بالا کمی گنگ باشد نگران نباشید در آینده با این دستورات بیشتر آشنا خواهیم شد.
قدرت اصلی جی کوئری برگفته از انتخاب‌کننده‌ها (Selector) هاست، انتخاب‌کننده ، یک عبارت است که دسترسی به عنصری خاص بر روی صفحه را موجب می‌شود؛ انتخاب‌کننده این امکان را فراهم می‌سازد تا به سادگی عنصر مورد نظر را مشخص و به آن دسترسی پیدا کنیم که در مثال فوق، عنصر مورد نظر ما گزینه انتخاب شده از myRadioGroup بود.
Unobtrusive JavaScript: اگر پیش از پیدایش CSS در کار ایجاد صفحه‌های اینترنتی بوده‌اید حتما مشکلات و مشقات آن دوران را به خاطر می‌آورید. در آن زمان برای فرمت‌دهی به اجزای مختلف صفحه ، به ناچار علائم فرمت‌دهی را به همراه دستورات خود اجزا، در صفحه‌های HTML استفاده می‌کردیم. اکنون بسیار بعید به نظر می‌رسد کسی ترجیح دهد فرمت‌دهی اجزا را به همراه دستورهای HTML آن انجام دهد. اگر چه هنوز دستوری مانند زیر بسیار عادی به نظر می‌آید:
<button type="button" onclick="document.getElementById('xyz').style.color='red';">
        Click Me
</button>
نکته ای که در مثال فوق حائز اهمیت است، این است که خصوصیات ظاهری دکمه ایجاد شده از قبیل فونت و عنوان دکمه، از طریق تگ <font> و یا پارامترهای قابل استفاده در خود دستور دکمه تعیین نشده است، بلکه CSS وظیفه تعیین آنها را دارد. اما اگرچه در این مثال فرمت‌دهی و دستور خود دکمه از یکدیگر جدا شده‌اند؛ شاهد ترکیب این دکمه با رفتار آن هستیم. در جی کوئری می‌توانیم رفتار را از اجزا به آسانی جدا کنیم.

مجموعه عناصر در جی کوئری:

زمانی که CSS به عنوان یک تکنولوژی به منظور جداسازی طراحی از ساختار به دنیای صفحه‌های اینترنتی معرفی شد، می‌بایست راهی برای اشاره به اجزای صفحات از طرف فایل CSS نیز معرفی می‌شد. این امر از طریق انتخاب‌کننده‌ها (Selector) صورت پذیرفت.

برای مثال انتخاب‌کننده زیر، به تمام عناصر <a> اشاره دارد که در یک عنصر <p> قرار گرفته‌اند:

p a
جی کوئری نیز از چنین انتخاب‌کننده‌هایی استفاده می‌کند، الته نه تنها از انتخاب‌کننده‌هایی که هم اکنون در CSS موجود می‌باشند، بلکه برخی از انتخاب‌کننده‌هایی که هنوز در تمام مرورگرها پشتیبانی نمی‌شوند.
برای انتخاب مجموعه‌ای از عناصر از یکی از دو Syntax زیر استفاده می‌کنیم.
$(Selector)
یا
jQuery(Selector)
ممکن است در ابتدا ()$ کمی نا معمول به نظر آید، اما اکثر کسانی که با جی کوئری کار می‌کنند از اختصار و کوتاهی این ساختار استفاده می‌کنند.
مثال زیر نمونه‌ای دیگر است که در آن مجموعه‌ای از تمام لینک‌هایی که درون تگ <p> قرار دارند را انتخاب می‌کند:
$("p a")
تابع ()$ که در حقیقت نام خلاصه‌ای برای ()jQuery می‌باشد، نوع خروجی مخصوصی دارد که شامل یک آرایه از اشیایی می‌شود که انتخاب‌کننده آن را برگزیده است. این نوع خروجی این مزیت را دارد که شمار زیادی متد از پیش تعریف شده را داراست که به سادگی قابل اعمال می‌باشند.
در اصطلاح برنامه نویسی به چنین توابعی که گروهی از عناصر را جمع می‌کنند، Wrapper می‌گویند زیرا تمام عناصر مطلوب را تحت یک شی بسته‌بندی می‌کند. در جی‌کوئری به آنها Wrapped Set یا jQuery Wrapper می‌گویند و به متدهایی که قابل اعمال بروی اینها به نام jQuery Wrapper Methodes شناخته می‌شوند.
در مثال زیر می‌خواهیم تمام عناصر <div> در صورتی که دارای کلاس notLongForThisWorldباشند را مخفی (با فید شدن) کنیم.

$("div.notLongForThisWorld").fadeOut();
یکی از مزیت‌های اکثر متدهای قابل اجرا بروی مجموعه عناصر انتخاب شده آن است که خروجی خود آنها مجموعه‌ای دیگر است. به این معنا که خروجی این متد، آماده اعمال یک متد دیگر است.
فرض کنید در مثال بالا بخواهیم پس از مخفی کردن هر <div> بخواهیم یک کلاس به نام removedبه آن بیافزاییم. به این منظور می‌توان کدی مانند زیر نوشت:
$("div.notLongForThisWorld").fadeOut().addClass("removed");
این زنجیره متدها می‌توانند به هرتعداد ادامه پیدا کند.

چند نمونه  انتخاب کننده:

نتیجه
  انتخاب کننده
 تمام <p>‌های زوج را انتخاب می‌کند

$('p:even')
 سطر اول هر جدول را انتخاب می‌کند

$("tr:nth-child(1)");
 <div>هایی که مستقیما در <body> تعریف شده باشند را انتخاب می‌کند.

$("body > div");
 لینک هایی که به یک فایل pdf اشاره دارند را انتخاب می‌کند.

$("a[href$=pdf]");
 تمام <div> هایی که مستقیما در <body> معرفی شده اند و دارای لینک می‌باشند را انتخاب می‌کند.

$("body > div:has(a)")
   

ادامه مطالب در پست‌های بعدی تشریح خواهد شد.


جهت مطالعه بیشتر می‌توانید از این منابع ^  و  ^  و  ^  و  ^  و  ^ استفاده کنید.
موفق و موید باشید