You are viewing limited content. For full access, please sign in.

Question

Question

Hijri and Gregorian Date

asked on April 19

Hello,

Can I enter both Hijri and Gregorian dates in the metadata for the same file in Laserfiche?

Currently, I understand that the date format (Hijri or Gregorian) is determined based on the operating system language. However, I would like to know if it is possible to select and display both date formats (Hijri and Gregorian) simultaneously within the same metadata field.

Thank you for your support.

1 0

Replies

replied on April 20

The calendar to use is based on the user's selected locale settings (whose default can be influenced by the OS and language but is configurable). Since it's part of the user's session settings, the calendar will be fixed for the whole UI and can't vary across fields.

1 0
replied on April 20

Hi, @████████, 

I'm not sure if what I'm about to share here will be helpful to you, but take a look anyway and let me know.
The following code works as follows:
You set up three fields, two text fields and one date field. In my proposed setup, I've named the first text field as follows:
1. Text Field: Gregorian Date
2. Text Field: Hijri Date (هجري)
3. Date Field: Date (We will hide this field using CSS; it will store the date in Gregorian format for use within Laserfiche).
In your specific case, take the IDs assigned to those fields in your environment and replace the corresponding IDs within the JavaScript code.

// =============================================
// CONFIGURATION
// =============================================
var ID_GREGORIAN = 1;  // Text field — Gregorian Date (visible to user)
var ID_HIJRI     = 2;  // Text field — Hijri Date (visible to user)
var ID_DATE_REPO = 3;  // Date field — hidden via CSS, stores value in repository
// =============================================

var isUpdating = false; // Prevents infinite loop between the two onChange listeners

// =============================================
// CONVERSION: Gregorian → Hijri
// Input:  string "YYYY-MM-DD" (Gregorian)
// Output: string "YYYY-MM-DD" (Hijri) or '' if invalid
// =============================================
function gregorianToHijri(dateStr) {
  if (!dateStr || dateStr.length < 10) return '';
  var parts = dateStr.split('-');
  if (parts.length !== 3) return '';
  var gy = parseInt(parts[0], 10);
  var gm = parseInt(parts[1], 10);
  var gd = parseInt(parts[2], 10);
  if (isNaN(gy) || isNaN(gm) || isNaN(gd)) return '';

  var a = Math.floor((14 - gm) / 12);
  var y = gy + 4800 - a;
  var m = gm + 12 * a - 3;
  var jdn = gd + Math.floor((153 * m + 2) / 5)
    + 365 * y + Math.floor(y / 4)
    - Math.floor(y / 100)
    + Math.floor(y / 400)
    - 32045;

  var l = jdn - 1948440 + 10632;
  var n = Math.floor((l - 1) / 10631);
  l = l - 10631 * n + 354;
  var j = Math.floor((10985 - l) / 5316)
    * Math.floor((50 * l) / 17719)
    + Math.floor(l / 5670)
    * Math.floor((43 * l) / 15238);
  l = l - Math.floor((30 - j) / 15)
    * Math.floor((17719 * j) / 50)
    - Math.floor(j / 16)
    * Math.floor((15238 * j) / 43)
    + 29;
  var hM = Math.floor((24 * l) / 709);
  var hD = l - Math.floor((709 * hM) / 24);
  var hY = 30 * n + j - 30;

  var mm = hM < 10 ? '0' + hM : '' + hM;
  var dd = hD < 10 ? '0' + hD : '' + hD;
  return hY + '-' + mm + '-' + dd;
}

// =============================================
// CONVERSION: Hijri → Gregorian
// Input:  string "YYYY-MM-DD" (Hijri)
// Output: string "YYYY-MM-DD" (Gregorian) or '' if invalid
// =============================================
function hijriToGregorian(dateStr) {
  if (!dateStr || dateStr.length < 10) return '';
  var parts = dateStr.split('-');
  if (parts.length !== 3) return '';
  var hY = parseInt(parts[0], 10);
  var hM = parseInt(parts[1], 10);
  var hD = parseInt(parts[2], 10);
  if (isNaN(hY) || isNaN(hM) || isNaN(hD)) return '';

  var jd = Math.floor((11 * hY + 3) / 30)
    + 354 * hY + 30 * hM
    - Math.floor((hM - 1) / 2)
    + hD + 1948440 - 385;

  var l  = jd + 68569;
  var n  = Math.floor(4 * l / 146097);
  l      = l - Math.floor((146097 * n + 3) / 4);
  var i  = Math.floor(4000 * (l + 1) / 1461001);
  l      = l - Math.floor(1461 * i / 4) + 31;
  var j  = Math.floor(80 * l / 2447);
  var gD = l - Math.floor(2447 * j / 80);
  l      = Math.floor(j / 11);
  var gM = j + 2 - 12 * l;
  var gY = 100 * (n - 49) + i + l;

  var mm = gM < 10 ? '0' + gM : '' + gM;
  var dd = gD < 10 ? '0' + gD : '' + gD;
  return gY + '-' + mm + '-' + dd;
}

// =============================================
// VALIDATION: Enforce YYYY-MM-DD format on keydown
// - Blocks any character that is not a digit or control key
// - Auto-inserts hyphens after position 4 and 7
// - Shows error subtext if format is incomplete on blur
// =============================================
function applyDateMask(fieldId) {
  var selector = '[data-field-id="' + fieldId + '"] input';
  var input = document.querySelector(selector);
  if (!input) return;

  input.addEventListener('keydown', function(e) {
    var allowed = ['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Tab', 'Enter'];
    if (allowed.indexOf(e.key) !== -1) return;
    if (!/^\d$/.test(e.key)) {
      e.preventDefault();
    }
  });

  input.addEventListener('input', function() {
    var raw = input.value.replace(/[^0-9]/g, '');
    var formatted = '';
    if (raw.length <= 4) {
      formatted = raw;
    } else if (raw.length <= 6) {
      formatted = raw.slice(0, 4) + '-' + raw.slice(4);
    } else {
      formatted = raw.slice(0, 4) + '-' + raw.slice(4, 6) + '-' + raw.slice(6, 8);
    }
    input.value = formatted;
  });

  input.addEventListener('blur', function() {
    var val = input.value;
    var isValid = /^\d{4}-\d{2}-\d{2}$/.test(val);
    if (val !== '' && !isValid) {
      LFForm.changeFieldSettings(
        {fieldId: fieldId},
        {subtext: '⚠ Invalid format. Please enter date as YYYY-MM-DD (e.g. 2024-05-15)'}
      );
    } else {
      LFForm.changeFieldSettings({fieldId: fieldId}, {subtext: ''});
    }
  });
}

// =============================================
// INIT — Runs on form load
// Sets placeholders and applies input masks to both date fields.
// setTimeout ensures the LF/Angular DOM is fully rendered before
// querying the input elements.
// =============================================
setTimeout(function() {
  LFForm.changeFieldSettings({fieldId: ID_GREGORIAN}, {placeholder: 'YYYY-MM-DD'});
  LFForm.changeFieldSettings({fieldId: ID_HIJRI},     {placeholder: 'YYYY-MM-DD'});
  applyDateMask(ID_GREGORIAN);
  applyDateMask(ID_HIJRI);
}, 500);

// =============================================
// LISTENER: Gregorian field changed
// Converts the entered Gregorian date to Hijri and updates:
//   - The Hijri text field (ID_HIJRI)
//   - The hidden Date field mapped to the repository (ID_DATE_REPO)
// Only triggers when the value matches YYYY-MM-DD format.
// =============================================
LFForm.onFieldChange(function() {
  if (isUpdating) return;
  var val = LFForm.getFieldValues({fieldId: ID_GREGORIAN});
  if (val && val.match(/^\d{4}-\d{2}-\d{2}$/)) {
    isUpdating = true;
    var hijri = gregorianToHijri(val);
    LFForm.setFieldValues({fieldId: ID_HIJRI}, hijri).then(function() {
      LFForm.setFieldValues({fieldId: ID_DATE_REPO}, {dateStr: val}).then(function() {
        isUpdating = false;
      });
    });
  }
}, {fieldId: ID_GREGORIAN});

// =============================================
// LISTENER: Hijri field changed
// Converts the entered Hijri date to Gregorian and updates:
//   - The Gregorian text field (ID_GREGORIAN)
//   - The hidden Date field mapped to the repository (ID_DATE_REPO)
// Only triggers when the value matches YYYY-MM-DD format.
// =============================================
LFForm.onFieldChange(function() {
  if (isUpdating) return;
  var val = LFForm.getFieldValues({fieldId: ID_HIJRI});
  if (val && val.match(/^\d{4}-\d{2}-\d{2}$/)) {
    isUpdating = true;
    var gregorian = hijriToGregorian(val);
    LFForm.setFieldValues({fieldId: ID_GREGORIAN}, gregorian).then(function() {
      LFForm.setFieldValues({fieldId: ID_DATE_REPO}, {dateStr: gregorian}).then(function() {
        isUpdating = false;
      });
    });
  }
}, {fieldId: ID_HIJRI});

Now you need to hide the date field. In my case, I used the CSS class `hdate`; you can apply this to the field via the "Advanced Options" under "CSS Classes." This CSS code should be placed in the form's CSS section.

.hdate {
  display: none !important;
}

So, when you enter a date in either of the two fields, whether Gregorian or Hijri, it will automatically populate the Gregorian date; conversely, if you type in the Gregorian field, it will automatically populate the Hijri date.

Let me know if that helps. 

1 0
replied on April 20

thanks a lot Mr. Luis

The above code was implemented in a Laserfiche Form. I would like to know if it is possible to apply the same logic within the Laserfiche Web Client.

Is there a way to achieve similar functionality in the Web Client environment?

Thank you.

0 0
replied on April 20

any update ...

0 0
You are not allowed to follow up in this post.

Sign in to reply to this post.