json-rules-filter 1.0.8 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-rules-filter",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "para crear reglas avanzadas de filtrado sobre datasets JSON de forma dinámica y visual.",
5
5
  "main": "src/jquery.jsonRulesFilter.js",
6
6
  "scripts": {
package/readme.md CHANGED
@@ -58,7 +58,7 @@ Instalar via **cdn**:
58
58
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
59
59
 
60
60
  <!-- jsonRulesFilter -->
61
- <script src="https://unpkg.com/json-rules-filter@1.0.5/src/jquery.jsonRulesFilter.js" class="script_" type="text/javascript"></script>
61
+ <script src="https://unpkg.com/json-rules-filter@1.0.9/src/jquery.jsonRulesFilter.js" class="script_" type="text/javascript"></script>
62
62
  ```
63
63
 
64
64
  ---
@@ -96,10 +96,20 @@ $("#miFiltro").jsonRulesFilter(data,
96
96
 
97
97
  ## 🧠 Configuración
98
98
 
99
+ ### bsVersion
100
+
101
+ Define la compatibilidad del plugin con la version de bootstrap , actualmente solo acepta dos valores , **4** para **bootstrap4** y **5** para **bootstrap5**
102
+ ```javascript
103
+ bsVersion:5 //Bootstrap 5
104
+ ```
105
+ ---
106
+
99
107
  ### filters
100
108
 
101
109
  Define las columnas disponibles para filtrar.
102
-
110
+ - name: (título del filtro)
111
+ - type: tipo de filtrado. Las opciones disponibles son **number**,**string** y **select**
112
+ - data: clave de referencia en el dataset de JSON, se usa tanto para filtrar como para generar las opciones únicas de los tipo **select**
103
113
  ```javascript
104
114
  filters: [
105
115
  {
@@ -121,15 +131,23 @@ Personaliza los operadores de filtrado.
121
131
 
122
132
  ```javascript
123
133
  language: {
124
- string: {
125
- sContain: "Contiene",
126
- sEquals: "Igual a"
127
- },
128
- number: {
129
- nEquals: "Igual a",
130
- nGreatherThan: "Mayor que"
134
+ string: {
135
+ sContain: "Contiene",
136
+ sNotContain: "No contiene",
137
+ sEquals: "Igual a",
138
+ sDifference: "Diferente de",
139
+ sStartWith: "Empieza con",
140
+ sEndWith: "Termina con"
141
+ },
142
+ number: {
143
+ nEquals: "Igual a",
144
+ nDifference: "Diferente de",
145
+ nGreatherThan: "Mayor que",
146
+ nGreatherThanOrEquals: "Mayor o igual que",
147
+ nLowerThan: "Menor que",
148
+ nLowerThanOrEquals: "Menor o igual que"
149
+ }
131
150
  }
132
- }
133
151
  ```
134
152
 
135
153
  ---
@@ -162,7 +180,7 @@ buttons: {
162
180
  Título del componente.
163
181
 
164
182
  ```javascript
165
- title: "Reglas de filtrado"
183
+ title: {text:"Reglas de filtrado",className:"fs-4"}
166
184
  ```
167
185
 
168
186
  ---
@@ -212,7 +230,7 @@ onApply: function (rules, filteredData) {
212
230
  ## 🛠️ Métodos públicos
213
231
 
214
232
  ### updateData
215
-
233
+ El datasets de JSON se mantiene en memoria tras la inicialización , si tu datasets cambió , debes pasarle en todo momento los datos actualizados.
216
234
  ```javascript
217
235
  $("#miFiltro").jsonRulesFilter("updateData", nuevosDatos);
218
236
  ```
@@ -229,6 +247,7 @@ const empleados = [
229
247
  ];
230
248
 
231
249
  $("#container-rules").jsonRulesFilter(empleados, {
250
+ bsVersion:5,
232
251
  filters: [
233
252
  { name: "Nombre", type: "text", data: "name" },
234
253
  { name: "Total", type: "number", data: "total" },
@@ -238,10 +257,10 @@ $("#container-rules").jsonRulesFilter(empleados, {
238
257
  ],
239
258
  onApply: function (rules, results) {
240
259
  $("#container-rules-collapse").empty();
241
-
260
+ //aquí podemos actualizar la tabla de datos con los datos ya filtrados
242
261
  //generamos indicador budge para contenedor de filtros
243
262
  $.each(reglas, function (index, element) {
244
-
263
+
245
264
  let text = `${element.dataName} ${element.optionFilterText.join("").toLowerCase()} ${element.searchValue}`;
246
265
 
247
266
  if (element.typeFilter === 'select') {
@@ -282,7 +301,7 @@ $("#container-rules").jsonRulesFilter(empleados, {
282
301
  ---
283
302
 
284
303
  ## 📌 Notas
285
-
304
+ - Compatibilidad con bootstrap 4 y 5
286
305
  - Soporta propiedades anidadas (ej: user.name)
287
306
  - Usa lógica AND entre reglas
288
307
  - Basado en Select2
@@ -20,6 +20,7 @@
20
20
 
21
21
  // --- DEFAULT CONFIGURATION ---
22
22
  const settings = $.extend(true, {
23
+ bsVersion:5,
23
24
  filters: [
24
25
  { name: "Example", type: "number", data: "example", render: function(data){return data.text /*Callback to render html in options type select*/}}
25
26
  ],
@@ -33,10 +34,10 @@
33
34
  nGreatherThanOrEquals: "Mayor o igual que", nLowerThan: "Menor que", nLowerThanOrEquals: "Menor o igual que"
34
35
  }
35
36
  },
36
- title: "Reglas de filtrado",
37
+ title: {text:"Reglas de filtrado",className:"fs-4"},
37
38
  buttons: {
38
39
  reset: { text: "Resetear", className: "fw-semibold link-danger link-offset-2 link-underline link-underline-opacity-0" },
39
- dropdown: { text: "Añadir regla", className: "btn btn-secondary" },
40
+ dropdown: { text: "Añadir regla", className: "btn btn-secondary"},
40
41
  apply: { text: "Aplicar regla", className: "btn btn-primary" },
41
42
  },
42
43
  onApply: function (filtros, datosFiltrados) { }
@@ -51,6 +52,31 @@
51
52
  settings: settings,
52
53
  $contenedor: $contenedor,
53
54
 
55
+ // ---- Compatibility helper bs5/bs4 ------
56
+ bs: function(classes) {
57
+ if (this.settings.bootstrapVersion === 5) return classes;
58
+
59
+ const map = {
60
+ 'fw-semibold': 'font-weight-bold',
61
+ 'fw-bold': 'font-weight-bold',
62
+ 'link-danger': 'text-danger',
63
+ 'ms-': 'ml-', // Margin start -> Margin left
64
+ 'me-': 'mr-', // Margin end -> Margin right
65
+ 'ps-': 'pl-', // Padding start -> Padding left
66
+ 'pe-': 'pr-', // Padding end -> Padding right
67
+ 'g-': 'row-grid-',
68
+ 'link-offset-2': '',
69
+ 'link-underline': '',
70
+ 'link-underline-opacity-0': ''
71
+ };
72
+
73
+ let result = classes;
74
+ Object.keys(map).forEach(key => {
75
+ result = result.replace(new RegExp(key, 'g'), map[key]);
76
+ });
77
+ return result;
78
+ },
79
+
54
80
  // Updates dataset from external source and refreshes the UI
55
81
  updateData: function (newData) {
56
82
  this.data = newData;
@@ -88,28 +114,36 @@
88
114
 
89
115
  // Render main plugin skeleton
90
116
  render: function () {
91
- let columnasHtml = '<div class="row g-2">';
117
+ const self = this;
118
+ // Atributo de toggle dinámico
119
+ const toggleAttr = this.settings.bootstrapVersion === 4 ? 'data-toggle="dropdown"' : 'data-bs-toggle="dropdown"';
120
+
121
+ // Ajuste de Gutters para BS4 (usamos form-row en lugar de row g-2 si es BS4)
122
+ const rowClass = this.settings.bootstrapVersion === 4 ? 'form-row' : 'row g-2';
123
+ const colClass = this.settings.bootstrapVersion === 4 ? 'col-6' : 'col-6';
124
+
125
+ let columnasHtml = `<div class="${rowClass}">`;
92
126
  this.settings.filters.forEach((col, index) => {
93
127
  let icon = col.type === "number" ? "fa-solid fa-hashtag" : (col.type === "string" ? "fa-solid fa-language" : "fa-solid fa-circle-chevron-down");
94
128
  columnasHtml += `
95
- <li class="col-6 list-unstyled">
129
+ <li class="${colClass} list-unstyled">
96
130
  <a class="dropdown-item dropdown-rules-item" href="#" data-column-type="${col.type}" data-column-data="${col.data}" data-column-name="${col.name}">
97
131
  <i class="${icon}"></i> ${col.name}
98
132
  </a>
99
133
  </li>`;
100
- if (index % 2 !== 0 && index !== 0) columnasHtml += '</div><div class="row g-2">';
134
+ if (index % 2 !== 0 && index !== 0) columnasHtml += `</div><div class="${rowClass}">`;
101
135
  });
102
136
  columnasHtml += "</div>";
103
137
 
104
138
  let template = `
105
139
  <div class="d-flex justify-content-between">
106
- <b><h4>${this.settings.title}</h4></b>
107
- <p><a class="${this.settings.buttons.reset.className} remove-rules-containers" href="#">${this.settings.buttons.reset.text}</a></p>
140
+ <p class="${this.bs(this.settings.title.className)}">${this.settings.title.text}</p>
141
+ <p><a class="${this.bs(this.settings.buttons.reset.className)} remove-rules-containers" href="#">${this.settings.buttons.reset.text}</a></p>
108
142
  </div>
109
143
  <div class="py-2" id="container-rules-filters"></div>
110
144
  <div class="mt-2">
111
145
  <div class="d-flex justify-content-start dropdown">
112
- <button data-bs-popper-config='{"strategy":"fixed"}' class="${this.settings.buttons.dropdown.className} dropdown-toggle" type="button" data-bs-toggle="dropdown">
146
+ <button class="${this.bs(this.settings.buttons.dropdown.className)} dropdown-toggle" type="button" ${toggleAttr}>
113
147
  ${this.settings.buttons.dropdown.text}
114
148
  </button>
115
149
  <div class="dropdown-menu p-2 dropdown-rules-columns" style="min-width: 300px;">
@@ -117,7 +151,7 @@
117
151
  </div>
118
152
  </div>
119
153
  <div class="mt-2 d-flex justify-content-start">
120
- <button type="button" id="apply-rules-btn" class="${this.settings.buttons.apply.className}">${this.settings.buttons.apply.text}</button>
154
+ <button type="button" id="apply-rules-btn" class="${this.bs(this.settings.buttons.apply.className)}">${this.settings.buttons.apply.text}</button>
121
155
  </div>
122
156
  </div>`;
123
157
  this.$contenedor.append(template);
@@ -156,40 +190,41 @@
156
190
  addRuleRow: function (type, dataField, name) {
157
191
  const self = this;
158
192
  const $container = this.$contenedor.find("#container-rules-filters");
159
- let id_select = 0;
160
193
 
161
- // Generate unique ID for the new row based on the last element
194
+ // Generate unique ID for the new row based on the last element
195
+ let id_select = 0;
162
196
  const last_container = $contenedor.find("select[name=select-rule-option]").last();
163
- if (last_container.length > 0) {
164
- id_select = last_container.data("id") + 1;
165
- }
197
+ if (last_container.length > 0) { id_select = last_container.data("id") + 1; }
198
+
199
+ // Usar 'form-group' y 'font-weight-bold' si es BS4
200
+ const labelClass = this.settings.bootstrapVersion === 4 ? 'font-weight-bold' : 'form-label fw-bold';
201
+ const rowClass = this.settings.bootstrapVersion === 4 ? 'form-row' : 'row';
166
202
 
167
203
  // Define search input template (hidden for 'select' type)
168
204
  const searchInput = `
169
205
  <div class="col-7">
170
- <label class="form-label font-bold"><span class="text-danger">*</span>${type}</label>
206
+ <label class="${labelClass}"><span class="text-danger">*</span>${type}</label>
171
207
  <input type="text" class="form-control" name="input-rule-search" id="input-rule-search-${id_select}">
172
208
  </div>`;
173
209
 
174
210
  const row = `
175
211
  <div id="select-rule-container-${id_select}" class="d-flex justify-content-between mt-2 pt-2 mb-4 ${$contenedor.find("[name=select-rule-option]").length > 0 ? ' border-top my-3' : ""}">
176
- <div class="row flex-grow-1">
212
+ <div class="${rowClass} flex-grow-1">
177
213
  <div class="col-4">
178
- <label class="form-label font-bold">${name}</label>
179
- <select class="form-select" ${type === 'select' ? 'multiple' : ''} data-type="${type}" data-name="${name}" data-field="${dataField}" id="select-rule-option-${id_select}" data-id="${id_select}" name="select-rule-option"></select>
214
+ <label class="${labelClass}">${name}</label>
215
+ <select class="form-select form-control" ${type === 'select' ? 'multiple' : ''} data-type="${type}" data-name="${name}" data-field="${dataField}" id="select-rule-option-${id_select}" data-id="${id_select}" name="select-rule-option"></select>
180
216
  </div>
181
217
  ${type === 'select' ? '' : searchInput}
182
218
  </div>
183
- <div class="">
184
- <a href="#" class="link-danger btn-remove-rule" data-target="select-rule-container-${id_select}">
219
+ <div class="ml-2">
220
+ <a href="#" class="link-danger text-danger btn-remove-rule" data-target="select-rule-container-${id_select}">
185
221
  <i class="fa-solid fa-trash-can"></i>
186
222
  </a>
187
223
  </div>
188
224
  </div>`;
189
225
 
190
226
  $container.append(row);
191
-
192
- // Fetch custom render function from settings
227
+ // Fetch custom render function from settings
193
228
  const render = self.settings.filters.find((e) => e.data === dataField).render;
194
229
  this.initSelect2(id_select, type, dataField, render);
195
230
  },