اذهب إلى المحتوى

تنسيق البيانات داخل جداول بيانات جوجل باستخدام Apps Script


Mostafa Amaan

مرحبًا بك في المقال الخامس من دليل تعلم أساسيات برمجة التطبيقات باستخدام جداول بيانات جوجل، فبعد إكمالك لهذا المقال سوف يصبح لديك المعرفة في كيفية تنسيق بيانات جدول البيانات في Apps Script، وكتابة دوال مخصصة لإنشاء جداول بيانات منظمة مليئة بالبيانات المنسقة التي جُلبت من واجهة برمجة تطبيقات عامة API.

هذا هو المقال الرابع في دليل تعلم أساسيات برمجة التطبيقات مع جداول بيانات جوجل، وقبل البدء تأكد من إكمال المقالات السابقة:

  1. أساسيات برمجة التطبيقات Apps Script.
  2. جداول البيانات والأوراق والنطاقات.
  3. العمل مع البيانات.
  4. استدعاء واجهة برمجة تطبيقات API عامة.

ماذا ستتعلم

  1. كيفية تطبيق عمليات تنسيق جداول بيانات جوجل المختلفة في Apps Script.
  2. كيفية تحويل قائمة كائنات JSON وسماتها إلى ورقة منظمة من البيانات باستخدام Apps Script.

ماذا ستحتاج

  • فهم موضوعات Apps Script الأساسية التي استكشفناها في المقالين السابقين من هذا الدليل.
  • الإلمام الأساسي بمحرر الشيفرات البرمجية Apps Script.
  • الإلمام الأساسي بجداول بيانات Google.
  • الإلمام الأساسي بلغة البرمجة JavaScript وصنف 'String' الخاص به.

الإعداد للعمل

قبل المتابعة أنت بحاجة إلى جدول بيانات يحتوي على بعض البيانات كما فعلنا في المقالات السابقة، لا تقلق فقد وفرنا لك جدول بيانات جاهز لاستخدامه في هذا التمرين، نزله وارفعه على حسابك في درايف باستخدام إحدى الطريقتين اللتين وضحناهما في المقال الأول، ويجب أن تبدو الورقة على هذا النحو مع بعض المعلومات الأساسية حول أول ثلاثة أجزاء من فيلم حرب النجوم:

001 - تنسيق البيانات 1.png

افتح محرر النصوص البرمجية لـ Apps Script بالنقر على "الإضافات" ثم اختيار "محرر تطبيقات جوجل"، وبعدها انقر على عنوان مشروع برمجة التطبيقات وغيره من "مشروع بلا عنوان" إلى "Data Formatting"، ثم انقر على زر "إعادة تسمية" لحفظ تغيير العنوان.

الآن بحصولك على جدول بيانات ومشروع Apps Script فأنت على استعداد لبدء المقال، انتقل إلى القسم التالي من هذا المقال للتعرف على التنسيق الأساسي في Apps Script.

إنشاء قائمة مخصصة

يمكنك تطبيق العديد من طرائق التنسيق الأساسية في Apps Script على جداول البيانات الخاصة بك، وتوضح التمارين التالية بعض هذه الطرائق لمساعدتك في التحكم في إجراءات التنسيق الخاصة بك، لذلك سوف نعمل على إنشاء قائمة مخصصة بالعناصر التي ستحتاج إليها، لقد شرحنا عملية إنشاء القوائم المخصصة في المقال السابق "العمل مع البيانات"، ولكننا سنلخصها هنا مرة أخرى.

التطبيق

دعنا نبدأ في إنشاء قائمة مخصصة باتباع الخطوات التالية:

  • أولًا، استبدل الشيفرة البرمجية في مشروع Apps Script الذي أسميناه "Data Formatting" بما يلي:
/**
 دالة خاصة يتم تشغيلها عند فتح جدول البيانات أو إعادة تحميله *
 وتستخدم لإضافة قائمة مخصصة إلى جدول البيانات *
 */
function onOpen() {
  الحصول على كائن واجهة المستخدم الخاص بجدول البيانات //
  var ui = SpreadsheetApp.getUi();

  إنشاء وإضافة القائمة المخصصة وعناصرها إلى شريط القوائم //
  ui.createMenu('تنسيقات سريعة')
   .addItem('تنسيق رأس الصف', 'formatRowHeader')
   .addItem('تنسيق رأس العمود', 'formatColumnHeader')
   .addItem('تنسيق البيانات', 'formatDataset') 
  .addToUi();
}
  • ثانيًا، احفظ مشروع نصك البرمجي.
  • ثالثًا، في محرر Apps Script حدد اسم الدالة "onOpen" من قائمة الدوال، ثم انقر على الزر "Run"، سيعمل هذا الإجراء على تشغيل الدالة ()onOpen لإنشاء القائمة المخصصة بجدول البيانات دون الحاجة إلى إعادة تحميل جدول البيانات.

مراجعة الشيفرة البرمجية

دعنا نراجع هذه الشيفرة البرمجية لفهم كيفية عمل الدالة ()onOpen.

يستخدم السطر الأول التابع()getUi للحصول على كائن "Ui" يمثل واجهة المستخدم لجدول البيانات النشط الذي يرتبط به هذا النص البرمجي أو السكربت.

تعمل الأسطر الثلاثة التالية على إنشاء قائمة مخصصة باسم "تنسيقات سريعة" ثم إضافة ثلاثة عناصر داخل هذه القائمة باسم "تنسيق رأس الصف" و "تنسيق رأس العمود" و "تنسيق البيانات"، ثم إضافة هذه القائمة المخصصة إلى واجهة جدول البيانات، ونفذنا ذلك باستخدام ثلاث توابع متتالية على النحو التالي:

  • أولاً، التابع ()createMenu والذي يأخذ معامل واحد فقط وهو "اسم القائمة المخصصة".
  • ثانيًا، التابع ()addItem والذي يأخذ معاملين، الأول "اسم العنصر داخل القائمة المخصصة"، والثاني "اسم الدالة بالإنجليزية".
  • ثالثًا، التابع ()addToUi وهو لا يأخذ أي معاملات.

ينشيء التابع ()addItem اتصالاً بين تسمية العنصر الموجود داخل القائمة المخصصة مثل (تنسيق رأس الصف) ودالة Apps Script المرتبطة بهذا العنصر formatRowHeader (التي لم نوفرها بعد) لتشغيلها.

النتائج

اذهب إلى جداول بيانات جوجل الذي نتدرب عليه "تنسيق البيانات" ثم انقر على القائمة المخصصة "تنسيقات سريعة" لعرض عناصر هذه القائمة.

002 - تنسيق البيانات 2.png

ويؤدي النقر على أي من هذه العناصر إلى حدوث خطأ وذلك نظرًا لأنك لم تنفذ الدالة المقابلة لكل عنصر منهم، لذلك دعنا نفعل ذلك في القسم التالي من هذا المقال.

تنسيق رؤوس الصفوف

غالبًا ما تحتوي مجموعات البيانات في جداول البيانات على رأس صف لتحديد البيانات في كل عمود، ومن الجيد تنسيق رأس الصف لفصله بصريًا عن باقي البيانات في جدول البيانات.

في المقال الأول من هذا الدليل أنشأنا ماكرو لرأس الصف وضبطت الشيفرة البرمجية الخاصة بها، لكن هنا سنعمل على تنسيق رأس الصف من البداية باستخدام Apps Script، وسيؤدي تنسيق رأس الصف الذي ستنشئه إلى جعل نص الرأس غامقًا، ولون الخلفية باللون الأزرق الداكن والأخضر، ولون النص باللون الأبيض، وإضافة بعض الخطوط الحدودية للخلايا.

التطبيق

لتنفيذ عملية التنسيق ستستخدم نفس توابع خدمة جدول البيانات التي استخدمتها من قبل، بالإضافة أيضًا إلى بعض توابع التنسيق الخاصة بالخدمة، فقط افتح المشروع الذي أنشأناه في Apps Script باسم "Data Formatting"، ثم أضف الدالة التالية إلى نهاية النص البرمجي:

/**
 دالة تعمل على تنسيق الصف العلوي من الورقة باستخدام نمط رأس الصف الخاص بنا *
 */
function formatRowHeader() {
 الحصول على الورقة النشطة الحالية ونطاق الصف العلوي //
  var sheet = SpreadsheetApp.getActiveSheet();
  var headerRange = sheet.getRange(1, 1, 1, sheet.getLastColumn());

  تطبيق هذه التنسيقات على الصف العلوي //
  نص أبيض غامق وخلفية زرقاء وخضراء //
  وحدود سوداء صلبة حول الخلايا //
  headerRange
    .setFontWeight('bold')
    .setFontColor('#ffffff')
    .setBackground('#007272')
    .setBorder(
      true, true, true, true, null, null,
      null,
      SpreadsheetApp.BorderStyle.SOLID_MEDIUM);

}

احفظ مشروع نصك البرمجي.

مراجعة الشيفرة البرمجية

مثل العديد من مهام التنسيق تكون الشيفرة البرمجية المنفذة في Apps Script واضحة ومباشرة.

يستخدم أول سطرين توابع رأيتها من قبل للحصول على مرجع للورقة النشطة الحالية من خلال المتغير sheet، والصف العلوي للورقة من خلال المتغير headerRange.

يحدد التابع ()Sheet.getRange الصف العلوي بما في ذلك الأعمدة التي تحتوي على بيانات فقط، وهذا التابع يأخذ أربع معاملات، هم: الأول "رقم الصف" والثاني "رقم العمود" والثالث "عدد الصفوف" والرابع "عدد الأعمدة".

يعمل التابع ()Sheet.getLastColumn على إرجاع الفهرس الخاص بالعمود الأخير الذي يحتوي على بيانات في الورقة، وفي مثالنا إنه العمود "E" المسمى "الرابط".

اقتباس

تنويه: نفترض هنا أن رأس الصف الذي نريد تنسيقه موجود دائمًا في الصف "1" ، وأن بياناتنا تبدأ من "A1"، وأنها تمتد عبر عدد من الأعمدة المتجاورة، لا بأس بذلك في هذا التمرين، ولكن بصفة عامة قد ترغب في تجنب هذه الافتراضات من خلال السماح للمستخدمين بتحديد الخلايا المطلوب تنسيقها في حالة اختلاف بنية جدول البيانات الخاص بهم.

تستدعي باقي الشيفرة البرمجية ببساطة توابع Range لتطبيق خيارات التنسيق على جميع الخلايا في المتغير headerRange، وللحفاظ على سهولة قراءة الشيفرة البرمجية نستخدم تسلسل التابع لاستدعاء كل تابع تنسيق واحدة تلو الأخرى كما يلي:

  1. بالنسبة للتابع ()Range.setFontWeight الذي يأخذ معامل (وزن الخط)، يعمل على ضبط قيمة وزن الخط إلى غامق.
  2. أما التابع ()Range.setFontColor الذي يأخذ معامل (لون الخط)، يعمل على تعيين لون الخط إلى الأبيض.
  3. والتابع ()Range.setBackground الذي يأخذ معامل (لون الخلفية)، يعمل على ضبط لون الخلفية على الأزرق الداكن والأخضر.
  4. وأخيرًا التابع ()setBorder يعمل على وضع حدًا أسودًا خالصًا حول خلايا النطاق، وهذا التابع له عدة معاملات (أعلى - يسار - أسفل - يمين - عمودي - أفقي - لون - نمط) لذلك دعنا نراجع ما يفعله كل معامل منهم:
  • تخبر المعاملات الأربعة الأولى هنا (جميعها مضبوطة على "true") أنه يجب إضافة الحد أعلى وأسفل وإلى يسار ويمين النطاق.
  • توجّه المعاملتان الخامسة والسادسة (مضبوطتان على "null") برمجة التطبيقات مباشرة لتجنب تغيير أي خطوط حد ضمن النطاق المحدد.
  • يشير المعامل السابعة (مضبوطة على "null") إلى أن لون الحد يجب أن يكون افتراضيًا باللون الأسود.
  • أخيرًا يحدد المعامل الأخير نوع نمط الحدود المراد استخدامه، مأخوذ من الخيارات التي يوفرها SpreadsheetApp.BorderStyle.

النتائج

يمكنك رؤية دالة التنسيق الخاصة بك وهي تعمل عن طريق تنفيذ ما يلي:

  1. إذهب إلى جداول بيانات جوجل الذي نتدرب عليه "تنسيق البيانات" ثم انقر على القائمة "تنسيقات سريعة" في شريط القوائم، ثم اختر منها القائمة الفرعية "تنسيق رأس الصف".
  2. إذا ظهر لك مربع حوار "لم يتم التحقق من هذا التطبيق" فاتبع الخطوات التي تعلمتها في المقالات السابقة لإعطاء الإذن للماكرو لكي يعمل.
  3. يجب أن تبدو النتائج كما يلي:

003 - تنسيق البيانات 3.gif

تهانينا، لقد أتممت الآن مهمة التنسيق لرؤوس الصفوف تلقائيًا، يطبق القسم التالي نفس الأسلوب لإنشاء نمط تنسيق مختلف لرؤوس الأعمدة.

تنسيق رؤوس الأعمدة

إذا كان بإمكانك إنشاء رأس صف مخصص فيمكنك إنشاء رأس عمود مخصص أيضًا، وتزيد عملية تنسيق رؤوس الأعمدة من قابلية القراءة للبيانات، فعلى سبيل المثال: يمكنك تحسين العمود المسمى "العنوان" في جدول البيانات الذي تتمرن عليه بخيارات التنسيق التالية:

  • تحويل النص إلى عريض.
  • تحويل النص إلى مائل.
  • إضافة حدود للخلية.
  • إدراج ارتباطات تشعبية باستخدام محتويات العمود المسمى "الرابط"، وبمجرد إضافة هذه الارتباطات التشعبية يمكنك إزالة العمود المسمى "الرابط" للمساعدة في تنظيف الورقة.

في القسم التالي من هذا المقال ستعمل على إنشاء الدالة ()formatColumnHeader لتنفيذ هذه التنسيقات على العمود الأول في الورقة، وللمساعدة في جعل الشيفرة البرمجية أسهل قليلاً في القراءة سوف ننفذها في دالتين بدلاً من دالة واحدة.

التطبيق

لإضافة دالة تعمل على أتمتة تنسيق رأس العمود، فقط اتبع الخطوات التالية:

أولًا، في مشروع Apps Script الذي باسم "Data Formatting" أضف الدالة التالية إلى نهاية النص البرمجي:

/**
 تنسيق رؤوس العواميد الخاصة بالورقة النشطة *
 */ 
function formatColumnHeader() {  
  var sheet = SpreadsheetApp.getActiveSheet();

  الحصول على العدد الإجمالي للصفوف في نطاق البيانات //
  بدون تضمين رؤوس الصفوف //
  var numRows = sheet.getDataRange().getLastRow() - 1;

  الحصول على نطاق رؤوس الأعمدة //
  var columnHeaderRange = sheet.getRange(2, 1, numRows, 1);

  تطبيق تنسيق النص وإضافة حدود //
  columnHeaderRange
    .setFontWeight('bold')
    .setFontStyle('italic')
    .setBorder(
      true, true, true, true, null, null,
      null,
      SpreadsheetApp.BorderStyle.SOLID_MEDIUM);

  استدعاء صنف مساعد لتحويل محتويات العمود الأول إلى رابط تشعبي //
  مضمن بالروابط الموجودة داخل عمود "العنوان" //
  hyperlinkColumnHeaders_(columnHeaderRange, numRows); 
}

ثانيا، أضف الدالتين التاليتين إلى نهاية النص البرمجي:

/**
 دالة مساعدة تربط محتويات العمود الأول بمحتويات العمود "الرابط" *
 ثم تقوم الدالة بعد ذلك بإزالة العمود "الرابط" *
 *
 * @param {object} headerRange هو نطاق عنوان العمود المراد تحديثه
 * @param {number} numRows هو عدد رؤوس الأعمدة
 */
function hyperlinkColumnHeaders_(headerRange, numRows) {
  الحصول على رقم فهرس عمود "العنوان" وعمود "الرابط" //
  var headerColIndex = 1; 
  var urlColIndex = columnIndexOf_('الرابط');  

  الخروج إذا كان عمود "الرابط" مفقودًا //
  if(urlColIndex == -1)
    return; 

  الحصول على قيم خلية "العنوان" و "الرابط" //
  var urlRange =
    headerRange.offset(0, urlColIndex - headerColIndex);
  var headerValues = headerRange.getValues();
  var urlValues = urlRange.getValues();

  تحديث القيم بعمود "العنوان" إلى قيم ذات روابط تشعبية //
  for(var row = 0; row < numRows; row++){
    headerValues[row][0] = '=HYPERLINK("' + urlValues[row]
      + '","' + headerValues[row] + '")';
  }
  headerRange.setValues(headerValues);

  حذف عمود "الرابط" لتنظيف الورقة //
  SpreadsheetApp.getActiveSheet().deleteColumn(urlColIndex);
}

/**
 * دالة مساعدة تمر عبر رؤوس جميع الأعمدة *
 وتعيد فهرس العمود بالاسم المحدد في الصف 1 *
 وفي حالة عدم وجود عمود بهذا الاسم *
 ترجع هذه الدالة القيمة -1 *
 إذا كان هناك أعمدة متعددة لها نفس الاسم في الصف 1 *
 فسيتم إرجاع فهرس أول عمود تم اكتشافه *
 * 
* @param {string} colName هو الاسم المراد العثور عليه
في رؤوس الأعمدة * 
* @return إرجاع فهرس هذا العمود في الورقة النشطة
 أو القيمة -1 إذا لم يتم العثور على الاسم *
 */ 
function columnIndexOf_(colName) {
 الحصول على أسماء الأعمدة الحالية //
  var sheet = SpreadsheetApp.getActiveSheet();
  var columnHeaders =
    sheet.getRange(1, 1, 1, sheet.getLastColumn());
  var columnNames = columnHeaders.getValues();

 حلقة تكرار خلال كل عمود لإرجاع رقم فهرس العمود //
// colName إذا كانت قيمة الصف 1 لهذا العمود تطابق
  for(var col = 1; col <= columnNames[0].length; col++)
  {
    if(columnNames[0][col-1] === colName)
      return col; 
  }

  إرجاع القيمة -1 إذا كان العمود المسمى colName غير موجود // 
  return -1; 
}

أخيرًا، احفظ مشروع نصك البرمجي.

مراجعة الشيفرة البرمجية

دعنا نراجع الشيفرة البرمجية للدوال الثلاث:

1. الدالة ()formatColumnHeader

نعم توقعك صحيح، فالأسطر القليلة الأولى من هذه الدالة تحدد المتغيرات التي تشير إلى الورقة والنطاق الذي نهتم به.

  • يعمل المتغير Sheet على تخزين الورقة النشطة.
  • يعمل المتغير numRows على حساب عدد الصفوف الموجودة في رأس العمود وحفظها، وتطرح الشيفرة البرمجية "1" حتى لا يشتمل عدد الصفوف على رأس العمود المسمى "العنوان".
  • يعمل المتغير columnHeaderRange على تخزين النطاق الذي يغطي رأس العمود.
  • تشرع الشيفرة البرمجية في تنفيذ تنسيقات الحدود والكتابة على نطاق رأس العمود، تمامًا كما هو الحال في الدالة ()formatRowHeader، الجديد في هذه الدالة أننا استخدمنا التابع ()Range.setFontStyle لجعل النص مائلًا.
  • تعد إضافة الارتباطات التشعبية إلى عمود الرأس عملية معقدة، لذا فإن الدالة ()formatColumnHeader تستدعي التابع ()_hyperlinkColumnHeaders لتولي هذه المهمة، وهو تابع يأخذ معاملين الأول "نطاق رأس العمود" والثاني "عدد الصفوف"، ويساعد هذا الإجراء في الحفاظ على الشيفرة البرمجية منظمة وقابلة للقراءة.

2. الدالة ()_hyperlinkColumnHeaders

تأخذ هذه الدالة معاملين الأول "نطاق الرأس" والثاني "عدد الصفوف"، وتحدد هذه الدالة أولاً فهارس العمود الخاصة بالرأس (من المفترض أن يكون الفهرس رقم 1) والعمود المسمى "الرابط"، فتعمل على استدعاء التابع ()_columnIndexOf للحصول على فهرس العمود المسمى "الرابط"، وفي حالة عدم عثوره عليه ينهي التابع عمله دون تعديل أي بيانات.

تحصل الدالة على نطاق جديد من خلال المتغير urlRange يغطي عناوين الروابط المقابلة لصفوف رأس العمود، وينفذ هذا الإجراء باستخدام التابع ()Range.offset الذي يأخذ معاملين الأول "إزاحة الصف" والثاني "إزاحة العمود"، وذلك لضمان أن النطاقين سيكونان بالحجم نفسه، ثم يسترد المتغير headerValues والمتغير urlValues القيم الموجودة في رأس العمود، والخلايا بالعمود المسمى "الرابط".

تنفذ الدالة بعد ذلك حلقة التكرار For لقيمة كل خلية في رأس العمود ثم تستبدلها بصيغة جداول بيانات ()HYPERLINK= باستخدام محتويات رأس العمود والخلايا بالعمود المسمى "الرابط"، ثم يلي ذلك إدراج قيم الرأس المعدلة في الورقة باستخدام التابع ()Range.setValues.

أخيرًا، وللمساعدة في الحفاظ على الورقة نظيفة من خلال التخلص من المعلومات الزائدة عن الحاجة، يُستدعى التابع ()Sheet.deleteColumn الذي يأخذ معامل واحد وهو "موضع العمود"، لإزالة العمود المسمى "الرابط" بالكامل.

3. الدالة ()_columnIndexOf

تأخذ هذه الدالة معامل واحد فقط وهو "اسم العمود"، وتبحث هذه الدالة في الصف الأول من الورقة عن اسم محدد، وتستخدم الأسطر الثلاثة الأولى توابع رأيتها بالفعل للحصول على قائمة بأسماء رؤوس الأعمدة من الصف رقم "1" بجدول البيانات، ثم تُخزن هذه الأسماء في المتغير columnNames.

تعمل الدالة بعد ذلك على مراجعة كل اسم بالترتيب، فإذا عثرت على اسم يطابق الاسم الذي تبحث عنه، فإنها تتوقف وتعيد رقم فهرس العمود، أما إذا وصلت إلى نهاية قائمة الأسماء دون العثور على الاسم الذي تبحث عنه، فإنها ترجع الرقم "-1" للإشارة إلى عدم العثور على الاسم.

النتائج

يمكنك رؤية دالة التنسيق الخاصة بك وهي تعمل عن طريق تنفيذ ما يلي:

  1. إذهب إلى جداول بيانات جوجل الذي نتدرب عليه "تنسيق البيانات" ثم انقر على القائمة "تنسيقات سريعة" في شريط القوائم، ثم اختر منها القائمة الفرعية "تنسيق رأس الصف".
  2. يجب أن تبدو النتائج كما يلي:

004 - تنسيق البيانات 4.gif

تهانينا، لقد أتممت الآن مهمة التنسيق لرؤوس الأعمدة تلقائيًا، يطبق القسم التالي كيفية تنسيق البيانات.

تنسيق البيانات

الآن بعد أن أصبح لديك رؤوس الصفوف والأعمدة منسقة، دعنا ننشئ دالة تعمل على تنسيق بقية البيانات في الورقة الخاصة بك، وسنستخدم خيارات التنسيق التالية:

  • تناوب ألوان خلفية الصف (صف بلون أبيض وآخر بلون رمادي).
  • تغيير صيغة التاريخ.
  • تطبيق حدود الخلية.
  • ضبط جميع مقاسات الأعمدة والصفوف تلقائيًا لسهولة قراءة البيانات بداخلهم.

ولتنفيذ ذلك سنعمل على إنشاء الدالة ()formatDataset، بالإضافة إلى دالة مساعدة لتطبيق هذه التنسيقات على بيانات الورقة الخاصة بك.

التطبيق

لإضافة دالة تعمل على أتمتة تنسيق البيانات، فقط اتبع الخطوات التالية:

أولًا، في مشروع Apps Script الذي باسم "Data Formatting" أضف الدالة التالية إلى نهاية النص البرمجي:

/**
 * تنسيق بيانات الورقة باستثناء رؤوس الصفوف والأعمدة *
 تطبيق الحدود وينسق عمود "تاريخ العرض" *
وضبط الأعمدة والصفوف تلقائيًا *
 */
function formatDataset() {
  الحصول على الورقة النشطة ونطاق البيانات //
  var sheet = SpreadsheetApp.getActiveSheet(); 
  var fullDataRange = sheet.getDataRange();

  تطبيق خطوط مرئية من الألوان المتناقضة على البيانات //
  باستثناء رؤوس الصفوف والأعمدة //
  تطبيق خطوط مرئية من الألوان المتناقضة فقط إذا لم يكن النطاق يحتوي عليها بالفعل //
  var noHeadersRange = fullDataRange.offset(
    1, 1,
    fullDataRange.getNumRows() - 1,
    fullDataRange.getNumColumns() - 1);

  if (! noHeadersRange.getBandings()[0]) {
    النطاق لا يحتوي بالفعل على خطوط مرئية من الألوان المتناقضة //
    لذلك من الآمن تطبيقه //
    noHeadersRange.applyRowBanding(
      SpreadsheetApp.BandingTheme.LIGHT_GREY,
      false, false);
  }

  استدعاء الدالة المساعدة لتطبيق تنسيق التاريخ //
 على العمود المسمى "تاريخ العرض" //
  formatDates_( columnIndexOf_('تاريخ العرض') );

  عيّن حدًا حول كل البيانات //
  تغيير حجم الأعمدة والصفوف لتناسب البيانات //
  fullDataRange.setBorder(
    true, true, true, true, null, null,
    null,
    SpreadsheetApp.BorderStyle.SOLID_MEDIUM);

  sheet.autoResizeColumns(1, fullDataRange.getNumColumns());
  sheet.autoResizeRows(1, fullDataRange.getNumRows());
}

ثانيًا، أضف الدالة المساعدة التالية في نهاية مشروع البرنامج النصي بعد الدالة ()formatDataset.

/** 
 الصنف المساعد الذي يطبق تنسيق التاريخ *
 شهر، يوم، سنة (اسم اليوم من الأسبوع) *
 على العمود المشار إليه في الورقة النشطة * 
 *
* @param {number} colIndex فهرس العمود
المطلوب تنسيقه *
 */ 
function formatDates_(colIndex) {
  اخرج إذا كان فهرس العمود المحدد هو -1 //
  مما يشير إلى أن العمود المطلوب تنسيقه غير موجود في الورقة //
  if (colIndex < 0)
    return; 

  قم بتعيين تنسيق التاريخ لعمود "تاريخ العرض" //
  باستثناء رؤوس الصفوف //
  var sheet = SpreadsheetApp.getActiveSheet();
  sheet.getRange(2, colIndex, sheet.getLastRow() - 1, 1)
    .setNumberFormat("mmmm dd, yyyy (dddd)");
}

احفظ مشروع نصك البرمجي.

مراجعة الشيفرة البرمجية

دعنا نراجع الشيفرة البرمجية لهاتين الدالتين:

1. دالة ()formatDataset

تتبع هذه الدالة نمطًا مشابهًا لدوال التنسيق السابقة التي نفذتها، فهي تحتوي على المتغير Sheet لتخزين الورقة النشطة، والمتغير fullDataRange لتخزين نطاق البيانات.

أما المتغير noHeadersRange يستخدم التابع ()Range.offset الذي يأخذ أربع معاملات، هي: الأول "إزاحة الصف" والثاني "إزاحة العمود" والثالث "عدد الصفوف" والرابع "عدد الأعمدة"، ويعمل هذا التابع على إنشاء نطاق يغطي جميع البيانات الموجودة في الورقة، باستثناء رؤوس الأعمدة والصفوف.

تتحقق الشيفرة البرمجية بعد ذلك مما إذا كان هذا النطاق الجديد يحتوي على خطوط مرئية من الألوان المتناقضة (الأبيض والرمادي بالتناوب) في خلفية الخلية باستخدام التابع ()Range.getBandings، ويعد هذا أمرًا ضروريًا لأن Apps Script تظهر خطأ إذا حاولت تطبيق هذا الأمر في نطاق يوجد به خطوط مرئية من الألوان المتناقضة بالفعل.

في حالة عدم وجود خطوط مرئية من الألوان المتناقضة في النطاق الجديد، تضيف الدالة خطًا مرئيًا رماديًا فاتحًا باستخدام التابع ()Range.applyRowBanding الذي يأخذ ثلاث معاملات، هي: الأول "سمة لون الخط" والثاني "إظهار الرأس" والثالث "إظهار التذييل"، وبخلاف ذلك تُكمل الدالة عملها.

في الخطوة التالية نستدعي ()_formatDates الذي يأخذ معامل واحد فقط وهو "رقم فهرس العمود"، وتعمل على تنسيق التواريخ في العمود المسمى "تاريخ العرض" وحُدد هذا العمود باستخدام ()columnIndexOf الذي يأخذ معامل واحد فقط وهو "اسم العمود"، وهو تابع استخدمته من قبل.

أخيرًا، نتمم هذا التنسيق عن طريق إضافة حدود الخلايا كما فعلنا من قبل، وتغيير حجم كل عمود وصف تلقائيًا لملاءمة البيانات التي تحتوي عليها باستخدام التابع ()Sheet.autoResizeColumns الذي يأخذ معامل واحد فقط وهو "موضع العمود"، والتابع ()Sheet.autoResizeRows الذي يأخذ معامل واحد فقط وهو "موضع الصف".

2: دالة ()_formatDates

تأخذ هذه الدالة معامل واحد وهو "رقم فهرس العمود"، وتعمل هذه الدالة على تطبيق تنسيق تاريخ محدد على العمود المسمى "تاريخ العرض"، وذلك باستخدام رقم فهرس العمود المقدم من الدالة، وعلى وجه التحديد تُنسق قيم التاريخ هكذا: "شهر، يوم ، سنة (اسم اليوم من الأسبوع)".

تتحقق الدالة أولاً من صلاحية رقم فهرس العمود المقدم (هل هو 0 أو أكبر) فإذا لم يكن كذلك فإنها تعود دون فعل أي شيء، ويمنع هذا الإجراء الأخطاء التي قد تحدث، مثل إذا لم تكن الورقة تحتوي على عمود باسم "تاريخ العرض".

بمجرد التحقق من صحة فهرس العمود، تحصل الدالة على النطاق الذي يغطي هذا العمود (باستثناء رأس الصف) ثم تستخدم ()Range.setNumberFormat لتطبيق التنسيق.

النتائج

يمكنك رؤية دالة التنسيق الخاصة بك وهي تعمل عن طريق تنفيذ ما يلي:

  1. إذهب إلى جداول بيانات جوجل الذي نتدرب عليه "تنسيق البيانات" ثم انقر على القائمة "تنسيقات سريعة" في شريط القوائم، ثم اختر منها القائمة الفرعية "تنسيق البيانات".
  2. يجب أن تبدو النتائج كما يلي:

005 - تنسيق البيانات 5.gif

تهانينا، لقد أتممت مهمة تنسيق أخرى تلقائيًا، الآن بعد أن توفرت لديك أدوات التنسيق هذه دعنا نضيف المزيد من البيانات لتطبيقها عليها.

إحضار وتنسيق بيانات من API

لقد تعلمت في هذا المقال كيف يمكنك استخدام Apps Script كوسيلة بديلة لتنسيق جدول البيانات الخاص بك، والآن ستتعلم كيفية كتابة شيفرة برمجية تعمل على سحب البيانات من واجهة برمجة تطبيقات عامة API، ثم تُدرجها في جدول البيانات الخاص بك، ثم تنسيقها لتتمكن من قراءتها.

في المقال السابق تعلمت كيفية سحب البيانات من واجهة برمجة التطبيقات API، وستستخدم نفس الأساليب في هذا التمرين، سوف نعمل مع واجهة برمجة تطبيقات عامة اسمها Star Wars API والمعروفة اختصارًا بـ SWAPI لملء جدول البيانات الخاص بك، وعلى وجه التحديد ستستخدم واجهة برمجة التطبيقات هذه للحصول على معلومات حول الشخصيات الرئيسية التي ظهرت في أفلام Star Wars الثلاثة الأصلية.

ستعمل الشيفرة البرمجية على استدعاء الـ API للحصول على كمية كبيرة من بيانات JSON، ثم تحليل الاستجابة، ثم وضع البيانات في ورقة جدول بيانات جديدة، ثم تنسيق الورقة.

التطبيق

في هذا القسم ستضيف بعض العناصر للقائمة المخصصة "تنسيقات سريعة"، يستدعي كل عنصر منهم سكريبت مجمّع يمرر متغيرات خاصة بهذا العنصر إلى الدالة الرئيسية ()_createResourceSheet.

لذلك أنت تحتاج إلى إنشاء هذه الدالة بالإضافة إلى ثلاث دوال مساعدة لها، فالدوال المساعدة تعمل على عزل الأجزاء المقسمة منطقيًا للمهمة، كما تساعد في الحفاظ على الشيفرة البرمجية قابلة للقراءة.

ولتنفيذ ذلك اتخذ الإجراءات التالية:

  • أولًا، في محرر Apps Script حدث الدالة ()onOpen في مشروع النص البرمجي المسمى "Data Formatting" لمطابقة ما يلي:
/**
 وظيفة خاصة يتم تشغيلها عند فتح جدول البيانات أو إعادة تحميله *
 تستخدم لإضافة قائمة مخصصة إلى جدول البيانات *
 */
function onOpen() {
  الحصول على كائن واجهة المستخدم لجدول البيانات //
  var ui = SpreadsheetApp.getUi();

 إنشاء وإضافة قائمة خاصة وعناصرها إلى شريط القوائم //
  ui.createMenu('تنسيقات سريعة')
   .addItem('تنسيق رأس الصف', 'formatRowHeader')
   .addItem('تنسيق رأس العمود', 'formatColumnHeader')
   .addItem('تنسيق البيانات', 'formatDataset') 
  .addSeparator()
    .addSubMenu(ui.createMenu('أبطال ثلاثية حرب النجوم')
                .addItem('الجزء الرابع', 'createPeopleSheetIV')
                .addItem('الجزء الخامس', 'createPeopleSheetV')
                .addItem('الجزء السادس', 'createPeopleSheetVI')
                )
    .addToUi();
}

احفظ مشروع نصك البرمجي.

  • ثانيًا، في محرر Apps Script حدد اسم الدالة "onOpen" من قائمة الدوال، ثم انقر على الزر "Run" لتشغيل الدالة حتى تنفذ الشيفرة البرمجية لإضافة العناصر الجديدة داخل القائمة المخصصة "تنسيقات سريعة".
  • ثالثًا، أنشئ ملف Apps Script جديد، وذلك بالنقر على أيقونة (+) الموجودة أعلى يمين النافذة وبجوار كلمة "الملفات"، ثم اختر "نص برمجي".
  • رابعًا، أعط اسمًا لمف النص البرمجي الجديد "API" ثم اضغط على زر "Enter" من لوحة المفاتيح حتى يُلحق Apps Script تلقائيًا امتداد "gs." إلى اسم ملف النص البرمجي.
  • خامسًا، استبدل الشيفرة البرمجية في ملف "API.gs" الجديد بما يلي:
/**
 الدالة الغالفة التي تمرر المعاملات *
 لإنشاء ورقة موارد تصف الشخصيات من الجزء الرابع *
 */
function createPeopleSheetIV() {
  createResourceSheet_('characters', 1, "الجزء الرابع");
}

/**
 الدالة الغالفة التي تمرر المعاملات *
 لإنشاء ورقة موارد تصف الشخصيات من الجزء الخامس *
 */
function createPeopleSheetV() {
  createResourceSheet_('characters', 2, "الجزء الخامس");
}

/**
 الدالة الغالفة التي تمرر المعاملات *
 لإنشاء ورقة موارد تصف الشخصيات من الجزء السادس *
 */
function createPeopleSheetVI() {
  createResourceSheet_('characters', 3, "الجزء السادس");
}

/** 
 إنشاء ورقة منسقة مليئة بالمعلومات التي يحددها المستخدم *
 من خلال Star Wars API *
 فإذا كانت الورقة التي تحتوي على هذه البيانات موجودة *
 فسيتم استبدال الورقة بمعلومات الـ API *
 *
* @param {string} resourceType نوع المصدر
* @param {number} idNumber رقم التعريف الخاص بالفيلم
* @param {number} episodeNumber رقم الجزء الخاص بالفيلم
يستخدم هذا فقط في اسم الورقة *
 */
function createResourceSheet_(
    resourceType, idNumber, episodeNumber) { 

  إحضار بيانات الفيلم الأساسية من الـ API // 
  var filmData = fetchApiResourceObject_(
      "https://swapi.dev/api/films/" + idNumber);

  استخراج عناوين URL لواجهة برمجة التطبيقات لكل مورد //
  حتى تتمكن الشيفرة من استدعاء واجهة برمجة التطبيقات للحصول على مزيد من البيانات حول كل منها على حدة //
  var resourceUrls = filmData[resourceType];

  إحضار كل مورد من الـ API على حدة //
  ثم دفعهم إلى قائمة كائنات جديدة //
  var resourceDataList = []; 
  for(var i = 0; i < resourceUrls.length; i++){
    resourceDataList.push(
      fetchApiResourceObject_(resourceUrls[i])
    ); 
  } 

  الحصول على المفاتيح المستخدمة للإشارة إلى كل جزء من البيانات داخل الموارد //
  ويُفترض أن تكون المفاتيح متطابقة لكل كائن //
  نظرًا لأنها جميعها من نفس نوع المورد //
  var resourceObjectKeys = Object.keys(resourceDataList[0]);

  إنشاء الورقة بالاسم المناسب //
  وتصبح الورقة النشطة تلقائيًا بعد إنشائها //
  var resourceSheet = createNewSheet_(
      "شخصيات " + episodeNumber);

  إضافة بيانات الـ API إلى الورقة الجديدة //
  باستخدام كل مفتاح كائن كرأس عمود // 
  fillSheetWithData_(resourceSheet, resourceObjectKeys, resourceDataList);

  تنسيق الورقة الجديدة باستخدام نفس الأنماط التي تطبقها عناصر قائمة المخصصة "تنسيقات سريعة" //
  وتعمل كل هذه التوابع على الورقة النشطة //
  التي تم إنشاؤها للتو //
  formatRowHeader();
  formatColumnHeader();   
  formatDataset();
}

سادسًا، أضف الدوال المساعدة التالية إلى نهاية ملف مشروع النص البرمجي "API.gs":

/** 
 الدالة المساعدة التي تسترد كائن JSON *
 الذي يحتوي على استجابة من واجهة برمجة تطبيقات عامة *
*
* @param {string} url عنوان الرابط لكائن واجهة برمجة التطبيقات الذي يتم جلبه
* @return {object} resourceObject كائن جيسون الذي تم جلبه
 من طلب الـ URL إلى الـ API *
 */
function fetchApiResourceObject_(url) {
  تقديم طلب إلى الـ API والحصول على رد //
  var response =
    UrlFetchApp.fetch(url, {'muteHttpExceptions': true});

  تحليل وإرجاع الاستجابة ككائن JSON //
  var json = response.getContentText();
  var responseObject = JSON.parse(json); 
  return responseObject; 
}

/** 
 الدالة المساعدة التي تقوم بإنشاء ورقة *
 أو إرجاع ورقة موجودة بنفس الاسم *
 *
 * @param {string} name اسم الورقة
 * @return {object} الورقة المنشأة أو الحالية وتحمل الاسم نفسه
 لتصبح هذه الورقة نشطة *
 */ 
function createNewSheet_(name) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();

  إرجاع ورقة موجودة إذا كانت تحمل الاسم المحدد //
  وتنشيط الورقة قبل إرجاعها //
  var sheet = ss.getSheetByName(name);
  if (sheet) {
    return sheet.activate();
  }

  وإلا أنشيء ورقة جديدة واضبط اسمها وأعدها //
  والأوراق الجديدة التي تم إنشاؤها بهذه الطريقة //
  تصبح الورقة النشطة تلقائيًا //
  sheet = ss.insertSheet(name); 
  return sheet; 
}

/** 
 الدالة المساعدة التي تضيف بيانات الـ API إلى الورقة *
 ويتم استخدام كل مفتاح كائن كرأس عمود في الورقة الجديدة *
 *
 * @param {object} resourceSheet كائن الورقة التي تم تعديلها
 * @param {object} objectKeys قائمة مفاتيح الموارد
 * @param {object} resourceDataList قائمة كائنات موارد واجهة برمجة التطبيقات
 التي تحتوي على بيانات لإضافتها إلى الورقة *
 */
function fillSheetWithData_(
    resourceSheet, objectKeys, resourceDataList) {
  تعيين أبعاد نطاق البيانات التي يتم إضافتها إلى الورقة //
  var numRows = resourceDataList.length;
  var numColumns = objectKeys.length;

  الحصول على نطاق الموارد ومجموعة القيم المرتبطة بها //
  وإضافة صفًا إضافيًا لرؤوس الأعمدة //
  var resourceRange =
    resourceSheet.getRange(1, 1, numRows + 1, numColumns);
  var resourceValues = resourceRange.getValues(); 

 عمل حلقة تكرار فوق كل قيمة ومفتاح للمورد //
  واستخراج البيانات ووضعها في مصفوفة قيم الموارد الثنائية //
  for (var column = 0; column < numColumns; column++) {

    ضبط رأس العمود //
    var columnHeader = objectKeys[column];
    resourceValues[0][column] = columnHeader;

    قراءة وضبط كل صف في هذا العمود //
    for (var row = 1; row < numRows + 1; row++) {
      var resource = resourceDataList[row - 1];
      var value = resource[columnHeader];
      resourceValues[row][column] = value;
    }
  }

  إزالة أي بيانات موجودة في الورقة وتعيين القيم الجديدة محلها //
  resourceSheet.clear()
  resourceRange.setValues(resourceValues);
}

احفظ مشروع نصك البرمجي.

مراجعة الشيفرة البرمجية

لقد أضفت للتو الكثير من الشيفرات البرمجية، دعنا ننتقل إلى كل دالة على حدة لفهم كيفية عملها:

1. الدالة ()onOpen

لقد أضفت هنا بعض العناصر الجديدة للقائمة المخصصة "تنسيقات سريعة"، لقد عينت خط فاصل ثم استخدمت التابع ()Menu.addSubMenu الذي يأخذ معامل واحد فقط، وهو"اسم القائمة الفرعية"، وذلك لإنشاء بنية قائمة متداخلة مع ثلاثة عناصر جديدة، وأضيفت العناصر الفرعية الجديدة باستخدام التابع ()Menu.addItem الذي يأخذ معاملين فقط، وهما: "اسم عنصر القائمة" و "اسم الدالة" ويكون الاسم باللغة الإنجليزية كما نوهنا سابقًا.

2. الدوال الغالفة لعناصر القائمة الفرعية المخصصة

جميع عناصر القائمة الفرعية الجديدة تفعل شيئًا مشابهًا، إنهم يحاولون إنشاء ورقة جدول ببيانات سُحبت SWAPI، الاختلاف الوحيد هو أن كل دالة تركز على جزء مختلف من الفيلم.

نعم سيكون من الملائم كتابة دالة واحدة فقط لإنشاء ورقة جدول البيانات، من خلال جعل الدالة تقبل معامل لتحديد الفيلم الذي يجب سحب بياناته، لكن المشكلة هنا أن التابع ()Menu.addItem لا يسمح لك بتمرير المعاملات إليه عندما تستدعيه القائمة الفرعية المخصصة، إذن كيف تتجنب كتابة نفس الشيفرة البرمجية ثلاث مرات؟

الجواب هو "الدالة الغالفة wrapper functions" وهي دوال خفيفة يمكنك الاتصال بها لكي تستدعي على الفور دالة أخرى مع ضبط معاملات محددة لها.

هنا تستخدم الشيفرة البرمجية ثلاث دوال غالفة: الأولى ()createPeopleSheetIV، والثانية ()createPeopleSheetV، والثالثة ()createPeopleSheetVI، وعناصر القائمة الفرعية مرتبطة بهذه الدوال.

فعند النقر على أحد عناصر القائمة الفرعية، تعمل الدالة الغالفة على استدعاء دالة منشئ الورقة الرئيسية على الفور ()_createResourceSheet، لتمرير المعاملات المناسبة لعنصر القائمة الفرعية، وتحديدًا ثلاثة معاملات، هم: "نوع المصدر" و "رقم معرف الفيلم" و "رقم جزء الفيلم"، وينتج عن هذا الإجراء إنشاء ورقة جدول بيانات مليئة ببيانات الشخصيات الرئيسية من أحد أجزاء فيلم "Star Wars".

3. الدالة (createResourceSheet_(‎

هذه هي دالة بناء ورقة جدول البيانات الرئيسية لهذا التمرين، فبمساعدة بعض الدوال المساعدة تحصل على بيانات من SWAPI، ثم تنشئ ورقة جدول بيانات جديدة، ثم تكتب بيانات الواجهة API في الورقة، ثم تنسق الورقة باستخدام الدوال التي أنشأتها في الأقسام السابقة من هذا المقال، وإليك التفاصيل:

بدايةً، تستخدم الدالة ()_fetchApiResourceObject التي تأخذ معامل واحد فقط، وهو: "الرابط"، وذلك لتقديم طلب إلى SWAPI لاسترداد معلومات الفيلم الأساسية، وتتضمن استجابة واجهة برمجة التطبيقات SWAPI مجموعة من الروابط التي يمكن أن تستخدمها الشيفرة البرمجية للحصول على مزيد من التفاصيل حول أشخاص محددين (يُعرفون هنا باسم resources) من الأفلام، تجمع الشيفرة البرمجية كل شيء في المصفوفة ResourceUrls.

بعد ذلك تستخدم الشيفرة البرمجية ()_fetchApiResourceObject لتكرار استدعاء الـ API لكل رابط في المصفوفة ResourceUrls، وتُخزن النتائج في المصفوفة ResourceDataList، وكل عنصر في هذه المصفوفة هو كائن يصف شخصية مختلفة من الفيلم.

تحتوي البيانات التي خُزنت في المصفوفة ResourceDataList على العديد من المفاتيح العامة التي عُينت لمعلومات حول الشخصيات التي مثلت في هذا الفيلم، فعلى سبيل المثال: يرمز المفتاح "name" إلى اسم الشخصية في الفيلم، ونحن نفترض أن أسماء المفاتيح لكل كائن بيانات متطابقة مع نوع البيانات بداخلها، لأنها تهدف إلى استخدام هياكل بيانات مشتركة، ولأننا سوف نحتاج إلى قائمة المفاتيح لاحقًا، لذلك تخزن الشيفرة البرمجية قائمة المفاتيح في المتغير ResourceObjectKeys باستخدام التابع من لغة جافا سكريبت ()Object.keys.

بعد ذلك تستدعي دالة البناء الدالة المساعدة ()_createNewSheet التي تأخذ معامل واحد فقط، وهو: "اسم الورقة"، وذلك لإنشاء الورقة التي سوف توضع البيانات الجديدة بداخلها، ويؤدي استدعاء الدالة المساعدة أيضًا إلى تنشيط الورقة الجديدة.

بعد إنشاء الورقة تُستدعى الدالة المساعدة ()_fillSheetWithData التي تأخذ ثلاث معاملات، هم: "الورقة الجديدة" و "قائمة مفاتيح الكائنات" و "قائمة كائنات موارد الـ API"، وذلك لإضافة جميع بيانات الـ API إلى الورقة.

أخيرًا تُستدعى جميع دوال التنسيق التي أنشأتها مسبقًا لتطبيق نفس قواعد التنسيق على البيانات الجديدة، نظرًا لأن الورقة الجديدة هي الورقة النشطة يمكن للشيفرة البرمجية إعادة استخدام هذه الدوال دون تعديل.

4: الدالة ()fetchApiResourceObject

تشبه الدالة المساعدة هذه الدالة المساعدة ()_fetchBookData التي استخدمناها في المقال السابق "العمل مع البيانات"، فهي تأخذ الرابط المحدد ثم تستخدم التابع ()UrlFetchApp.fetch الذي يأخذ معاملين، هما: "الرابط" و "المعاملات"، وذلك للحصول على استجابة، ثم تُحَلل الاستجابة في كائن JSON باستخدام التابع ()HTTPResponse.getContextText وتابع جافا سكريبت (JSON.parse(json، ثم يُرجع كائن JSON الناتج.

5: الدالة ()_createNewSheet

هذه الدالة المساعدة بسيطة إلى حدٍ ما، فهي تتحقق أولاً من وجود ورقة بالاسم المحدد في جدول البيانات، فإن وجدته تعمل الدالة على تنشيط الورقة وإعادتها.

أما إذا لم تكن الورقة موجودة، تعمل الدالة على إنشائها باستخدام ()Spreadsheet.insertSheet الذي يأخذ معامل واحد فقط، هو: "اسم الورقة"، ثم تنشيطها وإرجاع الورقة الجديدة.

6: الدالة ()_fillSheetWithData

هذه الدالة المساعدة مسؤولة عن ملء الورقة الجديدة ببيانات الـ API، فهي تأخذ كمعاملات ( الورقة الجديدة، وقائمة مفاتيح الكائنات، وقائمة كائنات موارد الـ API)، ويمثل كل مفتاح كائن عمودًا في الورقة الجديدة، ويمثل كل كائن مورد صفًا.

أولاً تحسب الدالة عدد الصفوف والأعمدة المطلوبة لتقديم بيانات الـ API الجديدة وهو حجم قائمة الموارد والمفاتيح على التوالي، بعد ذلك تحدد الدالة نطاق الإخراج من خلال المتغير ResourceRange لوضع البيانات مع إضافة صف إضافي للاحتفاظ برؤوس الأعمدة، وتحتوي قيم المتغير ResourceValues على مصفوفة ثنائية مستخرجة من المتغير ResourceRange.

بعد ذلك تسنخدم الدالة حلقة التكرار For عبر كل مفتاح كائن في قائمة ObjectKeys ثم يُعين المفتاح كرأس للعمود، ثم تمر حلقة تكرار For ثانية عبر كل كائن مورد، ولكل زوج (صف، عمود) تُنسخ معلومات الـ API المقابلة لهما إلى [resourceValues[row][column.

تنويه: تذكر أن الصفوف والأعمدة في "جداول البيانات" تبدأ فهرستها بالرقم "1"، بينما مصفوفات جافا سكريبت تبدأ فهرستها بالرقم "0"، وبسبب هذا الاختلاف غالبًا ما نضطر إلى إضافة أو طرح "1" من الفهارس عند البرمجة في Apps Script.

بعد ملء المتغير ResourceValues بالبيانات، تُمسح ورقة الوجهة باستخدام ()Sheet.clear في حالة احتوائها على بيانات من نقرات على عنصر القائمة الفرعية. أخيرًا تُكتب القيم الجديدة في الورقة.

النتائج

يمكنك رؤية نتائج عملك عن طريق تنفيذ ما يلي:

  1. إذهب إلى جداول بيانات جوجل الذي نتدرب عليه "تنسيق البيانات" ثم انقر على القائمة "تنسيقات سريعة" في شريط القوائم، ثم اختر منها القائمة الفرعية "أبطال ثلاثية حرب النجوم" ثم اختر من القائمة المنبثقة "الجزء الرابع" .
  2. يجب أن تبدو النتائج كما يلي:

006 - تنسيق البيانات 6.gif

تهانينا، لقد كتبت الآن شيفرة برمجية لاستيراد البيانات من API إلى جداول البيانات وتنسيقها تلقائيًا، لكن هل لاحظت أن الورقة اتجاه عرضها من اليسار إلى اليمين؟

إن كان الأمر مناسبًا لك فلا بأس، أما إن كنت تريد اتجاه عرض الورقة يكون من اليمين إلى اليسار فكل ما عليك فعله هو إضافة الثلاثة أسطر التالية إلى شيفرتك البرمجية:

تحويل اتجاه عرض ورقة جدول البيانات إلى: من اليمين إلى اليسار //
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  ss.getSheets().forEach(s => s.setRightToLeft(true));

نعم، أحيّك على انتباهك معي، أنا بالفعل لم أذكر لك أين تضع هذه الأسطر الثلاثة في شيفرتك البرمجية، لذلك اعتبر هذا الأمر بمثابة تدريب لك، فقط سوف أسهل عليك الأمر وأعطيك تلميح "الدوال الغالفة".

الآن أريد منك استخدم هذه الأسطر الثلاثة في شيفرتك البرمجية لتصبح النتيجة النهائية تبدو كما يلي:

007 - تنسيق البيانات 7.gif

خاتمة

وإلى هنا نكون قد وصلنا إلى نهاية هذا المقال من دليل أساسيات برمجة التطبيقات باستخدام جداول بيانات جوجل الذي تعلمنا فيه كيفية تطبيق عمليات تنسيق جداول البيانات المختلفة باستخدام Apps Script، وكيفية إنشاء قوائم فرعية باستخدام الدالة ()onOpen، وكيفية تنسيق قائمة كائنات JSON التي جلبناها في ورقة جديدة من البيانات باستخدام Apps Script.

وفي المقال القادم سوف نتعلم كيفية استخدام Apps Script لتصور البيانات في مخطط، ثم تصدير هذه المخططات إلى برنامج العروض التقديمية من جوجل.

نتمنى أن يكون هذا الدليل قد أضاف لكم معلومات جديدة ومفيدة، وفي حالة وجود أي استفسارات لا تترددوا في ذكرها لنا في التعليقات.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...