مطالب
بهبود SEO برنامه‌های Angular
یکی از موارد مهم بهینه سازی صفحات سایت برای موتورهای جستجو، افزودن عنوانی مناسب، به همراه توضیحات و واژه‌های کلیدی، twitter card ،Facebook Graph و امثال آن‌ها است. برای این منظور Angular به همراه سرویس‌هایی است که امکان افزودن این متاتگ‌ها را به صورت پویا مهیا می‌کنند.


آشنایی با امکانات بسته‌ی angular/platform-browser@

در ماژول angular/platform-browser@، دو سرویس Meta و Title، امکان تغییر پویای متاتگ‌های صفحه‌ی جاری را مهیا می‌کنند. برای نمونه فرض کنید قصد دارید یک چنین متاتگ‌هایی را به صفحه‌ی جاری اضافه کنید:
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" type="image/x-icon" href="favicon.ico">
    <title>newTitle ...</title>
    <base href="/">
    <meta name="description" content="Angular meta service">
<meta name="author" content="DNT">
<meta name="keywords" content="Angular, Meta Service">
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@my_site">
<meta name="twitter:title" content="Front-end Web Development">
<meta name="twitter:description" content="Learn frontend web development...">
<meta name="twitter:image" content="https://site/images/image.png">
<meta name="author" content="Other Author">
</head>
قدم اول انجام اینکار، تزریق سرویس‌های توکار Meta و Title به سازنده‌ی کامپوننت جاری است:
import { Component, OnInit } from "@angular/core";
import { Meta, Title } from "@angular/platform-browser";

@Component({
  selector: "app-seo-tests",
  templateUrl: "./seo-tests.component.html",
  styleUrls: ["./seo-tests.component.css"]
})
export class SeoTestsComponent implements OnInit {

  constructor(private metaService: Meta, private titleService: Title) {
  }
در ادامه متدهای مختلف این سرویس‌ها را بررسی خواهیم کرد:

افزودن یک یا چند متاتگ

متد addTag سرویس Meta، کار افزودن پویای یک متا تگ جدید را به همراه ویژگی‌های name و content آن، انجام می‌دهد. در ذیل چندین مثال از آن‌را مشاهده می‌کنید. در اینجا یا می‌توان از متد addTag استفاده کرد که تنها یک متاتگ را به صفحه اضافه می‌کند و یا از متد addTags کمک گرفت که می‌تواند آرایه‌ای از متاتگ‌ها را به صورت پویا به صفحه‌ی جاری اضافه کند:
    // addTag & addTags
    this.metaService.addTag({ name: "description", content: "How to optimize your Angular App for search engine and other crawlers." });
    this.metaService.addTag({ name: "author", content: "DNT" });
    this.metaService.addTag({ name: "keywords", content: "Angular, Meta Service" });
    // Or
    this.metaService.addTags([
      { name: "description", content: "How to optimize your Angular App for search engine and other crawlers." },
      { name: "author", content: "DNT" },
      { name: "keywords", content: "Angular, Meta Service" }
    ], false); // --> forceCreation = false

    this.metaService.addTag({ name: "twitter:card", content: "summary_large_image" });
    this.metaService.addTag({ name: "twitter:site", content: "@my_site" });
    this.metaService.addTag({ name: "twitter:title", content: "Front-end Web Development" });
    this.metaService.addTag({ name: "twitter:description", content: "Learn frontend web development..." });
    this.metaService.addTag({ name: "twitter:image", content: "https://site/images/image.png" });
    // Or
    this.metaService.addTags([
      { name: "twitter:card", content: "summary_large_image" },
      { name: "twitter:site", content: "@my_site" },
    ], false); // --> forceCreation = false
هر دو متد addTag و addTags دارای پارامتر boolean دومی به نام forceCreation نیز هستند. برای مثال اگر این پارامتر را به true تنظیم کنید، این متاتگ حتی اگر وجود هم داشته باشد، یکبار دیگر به صفحه اضافه خواهد شد.


دریافت محتوای متاتگ‌های موجود

با استفاده از متد getTag می‌توان یک متاتگ مشخص را به صورت HTMLMetaElement دریافت کرد:
    // getTag & getTags
    const viewport = this.metaService.getTag("name=viewport");
    if (viewport) {
      console.log(viewport.content); // width=device-width, initial-scale=1
    }
    const author = this.metaService.getTag("name=author");
    if (author) {
      console.log(author.content); // DNT
    }

    this.metaService.addTag({ name: "author", content: "DNT" });
    this.metaService.addTag({ name: "author", content: "Other Author" }, true);
    const authors = this.metaService.getTags("name=author");
    console.log(authors[0]); // <meta name="author" content="DNT">
    console.log(authors[1]); // <meta name="author" content="Other Author">
کار متد getTags بازگشت تمام متاتگ‌هایی با attribute-selector یکسان است. برای مثال در اینجا دوبار متاتگ author به صفحه اضافه شده‌است و خروجی getTags به همراه دو عنصر است.


به روز رسانی متاتگ‌های موجود

می‌توان از متد updateTag برای تغییر محتوای متاتگی موجود، استفاده کرد:
    // updateTag
    this.metaService.addTag({ name: "twitter:card", content: "summary_large_image" });
    this.metaService.updateTag({ name: "twitter:card", content: "summary" }, `name='twitter:card'`);

    this.metaService.updateTag({ name: "description", content: "Angular meta service" });
در اینجا اگر پارامتر اختیاری دوم ذکر نشود، جستجوی یافتن عناصر، بر اساس name ذکر شده صورت می‌گیرد و سپس content آن‌ها به روز می‌شود.


حذف تگ‌های موجود

در اینجا می‌توان از دو متد removeTag که یک attribute-selector را دریافت می‌کند و یا removeTagElement که یک HTMLMetaElement را توسط متد getTag دریافت می‌کند، برای حذف کامل این تگ‌ها استفاده کرد:
    // removeTag & removeTagElement
    this.metaService.removeTag("charset");
    // Or
    const chartsetTag = this.metaService.getTag("charset");
    if (chartsetTag) {
      this.metaService.removeTagElement(chartsetTag);
    }


تنظیم عنوان صفحه‌ی جاری

سرویس توکار دیگری به نام Title امکان تغییر عنوان صفحه‌ی جاری را به صورت پویا میسر می‌کند:
    // Setting the browser page Title in an Angular app
    const currentTitle = this.titleService.getTitle();
    console.log(currentTitle);
    this.titleService.setTitle("newTitle ...");
متد getTitle، عنوان فعلی صفحه را باز می‌گرداند و متد setTitle، این عنوان را به روز رسانی می‌کند.


طراحی سرویسی برای افزودن پویای متاتگ‌ها به صفحات مختلف سایت

می‌توان شبیه به مطلب «نمایش Breadcrumbs در برنامه‌های Angular» به قسمت data مسیریابی، اطلاعات عنوان صفحه و همچنین  metaTags آن‌را اضافه کرد:
const routes: Routes = [
  {
    path: "seo", component: SeoTestsComponent,
    data: {
      title: "Page Title",
      metaTags: {
        description: "Page Description or some content here",
        keywords: "some, keywords, here, separated, by, a comma"
      }
    }
  }
];
سپس سرویسی را طراحی نمود که با پایان یافتن مسیریابی فعلی، این تنظیمات را به صورت خودکار انجام دهد و نیازی نباشد تا مدام به تمام کامپوننت‌ها، سرویس‌های Meta و Title را به صورت دستی اضافه کرد و این اطلاعات را تغییر داد.
به همین جهت سرویس SEO را در مسیر src\app\core\seo-service.ts به صورت ذیل ایجاد می‌کنیم:
import { Injectable } from "@angular/core";
import { Title, Meta } from "@angular/platform-browser";
import { Router, NavigationEnd, ActivatedRouteSnapshot } from "@angular/router";

@Injectable()
export class SeoService {

  constructor(private titleService: Title, private metaService: Meta, private router: Router) { }

  enableSeo() {
    this.router.events
      .filter(event => event instanceof NavigationEnd)
      .distinctUntilChanged()
      .subscribe(() => {
        this.addMetaData(this.router.routerState.snapshot.root);
      });
  }

  private addMetaData(root: ActivatedRouteSnapshot): void {
    if (root.children && root.children.length) {
      this.addMetaData(root.children[0]);
    } else if (root.data) {
      this.setTitle(root.data);
      this.setMetaTags(root.data);
    }
  }

  private setMetaTags(routeData: { [name: string]: any; }) {
    const routeDataMetaTagsKey = "metaTags";
    const metaTags = routeData[routeDataMetaTagsKey];
    if (!metaTags) { return; }
    for (const tag in metaTags) {
      if (metaTags.hasOwnProperty(tag)) {
        const newTag = { name: tag, content: metaTags[tag] };
        console.log("new tag", newTag);
        this.metaService.addTag(newTag);
      }
    }
  }

  private setTitle(routeData: { [name: string]: any; }) {
    const routeDataTitleKey = "title";
    const title = routeData[routeDataTitleKey];
    if (title) {
      console.log("new title", title);
      this.titleService.setTitle(title);
    }
  }
}
توضیحات:
در اینجا در ابتدای کار مشترک رخ‌داد NavigationEnd سیستم مسیریابی خواهیم شد:
    this.router.events
      .filter(event => event instanceof NavigationEnd)
      .distinctUntilChanged()
      .subscribe(() => {
        this.addMetaData(this.router.routerState.snapshot.root);
      });
هر زمانیکه رخ‌داد مرور صفحه‌ی جاری به پایان رسید، بر اساس مسیر ریشه‌ی آن، متد addMetaData فراخوانی می‌شود. این متد، یک متد بازگشتی است. از این جهت که مسیر جاری می‌تواند حاصل مرور یک مسیر والد و سپس چندین مسیر تو در توی فرزند و والد آن باشد.
سپس در این متد خاصیت data مسیرنهایی را خوانده و کلیدهای title و metaTags آن‌را استخراج می‌کنیم و سپس توسط متدهای this.titleService.setTitle و this.metaService.addTag، این عنوان و متاتگ‌های جدید را به صورت پویا به صفحه اضافه خواهیم کرد.

پس از تعریف این سرویس، برای معرفی آن به برنامه، ابتدا آن‌را به قسمت providers مربوط به CoreModule اضافه می‌کنیم:
import { SeoService } from "./seo-service";

@NgModule({
  providers: [
    SeoService
  ]
})
export class CoreModule {}
و در آخر به فایل app.component.ts مراجعه کرده و این سرویس را فعالسازی می‌کنیم:
import { SeoService } from "./core/seo-service";

export class AppComponent {
  constructor(private seoService: SeoService) {
    this.seoService.enableSeo();
  }
}
از این پس تمام مسیرهای برنامه به صورت خودکار تحت نظر قرار گرفته و درصورتیکه خاصیت data آن‌ها دارای کلیدهای title و metaTags باشند، به صورت خودکار پردازش خواهند شد.



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

یکی از دوستان در قسمت تماس با من پیغام گذاشته بود که چگونه تصاویر یک صفحه را می‌شود به صورت موقت کوچک کرد؟ برای نمونه، این مشکلی است که در فوروم‌ها زیاد وجود دارد. گاهی از اوقات یکی از کاربران تصویری را ارسال می‌کند که اندازه‌ی آن در حد یک تابلوی دیواری است!
با استفاده از محصول سورس بازی به نام popBox می‌توان تصاویر دلخواهی را ابتدا با اندازه‌ی کوچک در صفحه نشان داد و پس از کلیک بر روی آن، تصویر به اندازه اصلی آن نمایش داده خواهد شد. به این صورت صفحه از شکل نخواهد افتاد. این اسکریپت از آدرس زیر قابل دریافت است:
http://www.c6software.com/products/popbox/default.aspx
نحوه استفاده و مثال‌های مربوطه هم در همان آدرس قابل مشاهده است و نکته خاصی ندارد.

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

با استفاده از jQuery ، اسکریپت selectAll.js را به این مجموعه اضافه کردم. ابتدا تمامی تصاویر صفحه پیدا می‌شوند و سپس به آنهایی که طول و عرض بزرگتری از حد مجاز دارند به صورت خودکار ویژگی‌های popBox افزوده خواهد شد. چون این روش اسکریپتی است : الف) نیازی به تغییر در سورس‌های موجود نیست. ب) توسط هر تکنولوژی سمت سروری نیز قابل استفاده است. ج) به صورت خودکار به تمامی تصاویر بزرگ صفحه اعمال می‌شود و نیازی به ویرایش دستی هیچ موردی جهت اعمال ویژگی‌های مورد نظر وجود نخواهد داشت.

نکته جالبی که با jQuery وجود دارد، روال رخ‌داد گردان document.ready آن است. این رخداد پیش از window.onload استاندارد و زمانیکه DOM آماده استفاده است فراخوانی می‌شود.

برای استفاده از آن ابتدا باید دو فولدر scripts و images به سرور کپی شوند. سپس سه سطر زیر را به هدر صفحه اضافه کنید (به سورس صفحه sample.html فایل پیوست می‌توان مراجعه کرد):

<script src="scripts/jquery.min.js" type="text/javascript"></script>
<script src="scripts/PopBox.js" type="text/javascript"></script>
<script type="text/javascript" src="scripts/selectAll.js"></script>

در مورد سایر تنظیمات، فایل selectAll.js را گشوده و موارد زیر را در صورت لزوم ویرایش نمائید:
popBoxWaitImage.src = "images/spinner40.gif";
popBoxRevertImage = "images/magminus.gif";
popBoxPopImage = "images/magplus.gif";
popBoxRevertText = "کوچک‌ نمایی";
popBoxPopText = "بزرگ‌ نمایی";
popBoxCaptionMoreText = "بیشتر";
popBoxCaptionLessText = "کمتر";
MaximumAllowedWidth = 500;
MaximumAllowedHeight = 480;

در این فایل قسمتی از تابع rescaleImage از سایت stack overflow قرض گرفته شد و تغییرات لازم جهت اعمال ویژگی‌های popbox‌ به آن اعمال گردید. با استفاده از این تابع نسبت‌های طول و عرض تصویر به میزان ثابتی کوچک می‌شوند و تصویر کوچک شده با کیفیت بهتری نمایش داده خواهد شد.
موارد ذکر شده را از این آدرس می‌توانید دریافت نمائید.


اشتراک‌ها
یک گرید ساده با قابلیت راست به چپ و پیجینگ در ری اکت
در این مقاله قصد دارم شمارو را با امکانات لایبرری "ری اکت انگرید " برای ری اکت جی اس آشنا کنم. این لایبرری شامل یک کامپوننت گرید با قابلیت‌های زیر هست:

1-ساپورت راست به چپ
2- نمایش پیجینگ
3-  نمایش لودر
4- امکان تغییر کلمات
5- امکان جاگذاری کامپوننت در هر سل

نحوه استفاده از این کامپوننت به این شکل هست:

1- تعریف ستونها:
const columns = [
    {
      field: "fullname",
      headerName: "First & last Name",
      description: "name of user",
      width: 50,
    },
    {
      field: "age",
      headerName: "Age",
      description: "age of user",
      width: 50,
      renderCell:(info)=><strong>Age is : {info.data.age}</strong>
    }
]

2- تعریف استیت‌های لازم برا ست کردن سطر ها، لودر، تعداد کل, شماره صفحه و بزرگی هر صفحه(دقت شود که امکان استفاده بدون پیجینگ هم وجود دارد و امکانات کامل را در لینک لایبرری میتوانید مطالعه نمایید) 
...
const [rows,setRows] = useState([]);
const [loading,setLoading] = useState(false);
const [totalCount,setTotalCount] = useState(0);
const [filter,setFilter] = useState({ pageSize:10, pageNumber:1 });
const _fetchData = async () => { if (!active) return; //mock api, you can call your api then set data to table like commented line below return new Promise((resolve) => { setLoading(true); setTimeout(() => { setRows(data);// SetRows, note that data comes from api and must be array of objects setTotalCount(7);//=== set total page size for pagination part resolve(); setLoading(false); }, 2000); }); }
3- در نهایت کامپوننت مورد نظر:
import Angrid from "rect-angrid";
...
_handlePageChange = (newPage)=>{
    setFilter(p=>({...p,pageNumber:newPage}))
}
...
      <AnGrid
        loading={loading}
        columns={columns}
        rows={rows}
        showRowNumber={true}
        pageSize={filter.pageSize}
        pageNumber={filter.pageNumber}
        totalCount={totalCount}
        onPageChange={_handlePageChange}
        theme="dark"
        minHeight={300}
        emptyList={<strong>There Is No Info</strong>}
      />
نمایی از گرید:



یک گرید ساده با قابلیت راست به چپ و پیجینگ در ری اکت
مطالب دوره‌ها
تغییرات صورت گرفته در المان‌های تایپوگرافی و شیوه‌ نامه‌های بوت استرپ 3
مبحث پیشین «استفاده از Twitter Bootstrap در کارهای روزمره طراحی وب» را احتمالا بخاطر دارید. آن مطلب برای بوت استرپ 2 تهیه شده بود و پس از مطالعه نکات «بررسی سیستم جدید گرید بوت استرپ 3» تفاوت‌های حاصل در سیستم طرحبندی آن‌را به خوبی می‌توان تشخیص داد. در ادامه مباحث دوره جاری، به تکمیل این نکات، جهت ارتقاء به بوت استرپ 3 پرداخته و تفاوت‌های مهم را برخواهیم شمرد.


تغییرات انجام شده در تعاریف ستون‌ها جهت سازگاری با اندازه‌های مختلف صفحه

علاوه بر نکات یاد شده در قسمت قبل مانند چهار اندازه جدید سیستم گریدهای بوت استرپ 3، یا امکان ترکیب این‌ها در ستون‌های مختلف، امکان مخفی کردن یا نمایش دادن مثلا یک پاراگراف یا حتی یک div ساده بر اساس اندازه صفحه نیز از بوت استرپ 2 میسر بوده است. برای به روز رسانی یک چنین کدهایی تنها کافی است به جدول ذیل دقت داشت. در این جدول نام کلاس‌های قدیمی بوت استرپ 2 و جدید بوت استرپ 3 را ملاحظه می‌کنید:
Bootstrap 2           Bootstrap 3
.visible-phone        .visible-sm
.visible-tablet       .visible-md
.visible-desktop      .visible-lg
.hidden-phone         .hidden-sm
.hidden-tablet        .hidden-md
.hidden-desktop       .hidden-lg


تغییرات صورت گرفته در تعاریف دکمه‌ها

تعاریف دکمه‌ها با نکات عنوان شده در مطلب «استفاده از Twitter Bootstrap در کارهای روزمره طراحی وب» آنچنان تفاوتی ندارند. تنها باید دقت داشت که اینبار اندازه دکمه‌ها نیز همانند اندازه ستون‌های گریدهای بوت استرپ باید مقدار دهی شوند. مثلا اگر در بوت استرپ 2، یک دکمه کوچک را به صورت btn btn-success btn-mini تعریف می‌کردیم، اینبار معادل btn-mini را باید همانند ستون‌ها، به btn-xs تغییر دهیم؛ یعنی باید نوشت btn btn-success btn-xs. خلاصه کاربردی این تغییرات را جهت به روز رسانی کدهای بوت استرپ 2 به 3 در جدول ذیل مشاهده می‌نمائید:
Bootstrap 2     Bootstrap 3
.btn.btn        .btn-default
.btn-mini       .btn-xs
.btn-small      .btn-sm
.btn-large      .btn-lg


واکنشگرا کردن تصاویر و جداول سایت‌های طراحی شده با بوت استرپ 3

اگر تصویری در یک div یا یک لینک محصور شده، یا حتی در حالت معمولی نمایش داده می‌شود، برای اینکه با تغییر اندازه صفحه به صورت خودکار بزرگ و کوچک شود، تنها کافی است کلاس img-responsive بوت استرپ 3 را به المان‌های یاد شده اضافه کنیم.
در مورد جداول HTML نیز مساله واکنشگرا بودن درنظر گرفته شده است. در اینجا تنها کافی است کل جدول را با یک div محصور کنیم و سپس به این div کلاس table-responsive را انتساب دهیم تا جداول بوت استرپ 3 نیز به اندازه‌های مختلف صفحه واکنش نشان دهند.


تغییرات لازم جهت تعاریف آیکن‌ها در بوت استرپ 3

همانطور که در قسمت‌های پیشین نیز ذکر شد، در بوت استرپ 3 دیگر از PNG image sprites استفاده نمی‌شود و بجای آن‌ها از قلم‌هایی که حاوی آیکن‌ها هستند، کمک گرفته شده است. به این ترتیب رنگ آمیزی این آیکن‌ها ساده‌تر شده و همچنین به علت نمایش برداری گلیف‌های یک قلم، در اندازه‌های مختلف، به خوبی رندر و بدون افت کیفیت نمایش داده خواهند شد. در این حالت نحوه تعریف آیکن‌ها به صورت زیر تغییر یافته است:
<span class="glyphicon glyphicon-pushpin"></span>
لیست کامل آیکن‌های پیش فرض بوت استرپ 3 را در اینجا می‌توانید ملاحظه نمائید.