Skip to content

Commit 037d1af

Browse files
committed
v2-Beta17 release
1 parent ac14036 commit 037d1af

File tree

5 files changed

+200
-89
lines changed

5 files changed

+200
-89
lines changed

README.md

+12-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ It supports RTL layout and dark mode out of the box.
55

66
⚠️ **v2 is still in BETA stage** ⚠️
77

8-
![v2 Beta16](https://img.shields.io/badge/v2_Beta16-2024/05/30-green?style=plastic)
8+
![v2 Beta17](https://img.shields.io/badge/v2_Beta17-2024/06/13-green?style=plastic)
99

1010
**Apologies in advance for any problem or bug you face with this module.**
1111
**Please report any problem or bug you face so it can be fixed.**
@@ -35,9 +35,10 @@ It supports RTL layout and dark mode out of the box.
3535
#### Version 2
3636
- [![MohsinAli](https://img.shields.io/badge/MohsinAli-Debug_%7C_Test_%7C_Fix-red?style=plastic)](https://github.com/mohsinalimat)
3737
- [![Robert C](https://img.shields.io/badge/Robert_C-Debug_%7C_Test-blue?style=plastic)](https://github.com/robert1112)
38-
- [![NirajRegmi](https://img.shields.io/badge/NirajRegmi-Debug_%7C_Test-orange?style=plastic)](https://github.com/NirajRegmi)
38+
- [![NirajRegmi](https://img.shields.io/badge/NirajRegmi-Debug_%7C_Test-blue?style=plastic)](https://github.com/NirajRegmi)
39+
- [![galaxlabs](https://img.shields.io/badge/galaxlabs-Enhancement-a2eeef?style=plastic)](https://github.com/galaxlabs)
3940
#### Version 1
40-
- [![CA. B.C.Chechani](https://img.shields.io/badge/CA._B.C.Chechani-Debug_%7C_Test-green?style=plastic)](https://github.com/chechani)
41+
- [![CA. B.C.Chechani](https://img.shields.io/badge/CA._B.C.Chechani-Debug_%7C_Test-blue?style=plastic)](https://github.com/chechani)
4142

4243
---
4344

@@ -179,7 +180,7 @@ You can't modify the original fields of a doctype, so create a new field or clon
179180
| :--- | :--- |
180181
| **dialog_title** | Upload dialog title to be displayed ️(🔶Frappe >= v14.0.0).<br /><br />🔹Example: **"Upload Images"**<br />🔹Default: **"Upload"** |
181182
| **upload_notes** | Upload text to be displayed.<br /><br />🔹Example: **"Only images and videos, with maximum size of 2MB, are allowed to be uploaded"**<br />🔹Default: **""** |
182-
| **disable_auto_save** 🔴 | Disable form auto save after upload.<br /><br />🔹Default: **false** |
183+
| **disable_auto_save** | Disable form auto save after upload.<br /><br />🔹Default: **false** |
183184
| **disable_file_browser** | Disable file browser uploads.<br /><br />⚠️ *(File browser is always disabled in Web Form)*<br /><br />🔹Default: **false** |
184185
| **allow_multiple** | Allow multiple uploads.<br /><br />⚠️ *(Field value is a JSON array of files url)*<br /><br />🔹Default: **false** |
185186
| **max_file_size** | Maximum file size (in bytes) that is allowed to be uploaded.<br /><br />🔹Example: **2048** for **2KB**<br />🔹Default: **Value of maximum file size in Frappe's settings** |
@@ -190,17 +191,23 @@ You can't modify the original fields of a doctype, so create a new field or clon
190191
| **allowed_filename** | Only allow files that match a specific file name to be uploaded.<br /><br />🔹Example: (String)**"picture.png"** or (RegExp String)**"/picture\-([0-9]+)\.png/"**<br />🔹Default: **null** |
191192
| **allow_reload** | Allow reloading attachments (🔶Frappe >= v13.0.0).<br /><br />🔶 Affect the visibility of the reload button.🔶<br /><br />🔹Default: **true** |
192193
| **allow_remove** | Allow removing and clearing attachments.<br /><br />🔶 Affect the visibility of the remove and clear buttons.🔶<br /><br />🔹Default: **true** |
194+
| **users** 🔴 | Array of custom options for a specific user or group of users.<br /><br />🔹Example: **[{"for": "Guest", "disabled": true}, {"for": ["Administrator", "user"], "allow_multiple": true}]**<br />🔹Default: **null** |
195+
| **roles** 🔴 | Array of custom options for a specific role or group of roles.<br />⚠️ *(Custom options for users is prioritized over roles.)*<br /><br />🔹Example: **[{"for": ["Administrator", "System"], "allow_multiple": true}]**<br />🔹Default: **null** |
196+
197+
🔴 New - 🔶 Changed
193198

194199
---
195200

196201
### Available JavaScript Methods
197202
| Method | Description |
198203
| :--- | :--- |
199-
| **auto_save(enable: Boolean)** | Enable/Disable form auto save after upload. |
204+
| **toggle_auto_save(enable: Boolean !Optional)** 🔶 | Enable/Disable form auto save after upload. |
200205
| **toggle_reload(allow: Boolean !Optional)** | Allow/Deny reloading attachments and toggle the reload button (🔶Frappe >= v13.0.0). |
201206
| **toggle_remove(allow: Boolean !Optional)** | Allow/Deny removing and clearing attachments and toggle the clear and remove buttons. |
202207
| **set_options(options: JSON Object)** | Set or change the plugin options. |
203208

209+
🔴 New - 🔶 Changed
210+
204211
---
205212

206213
### Supported Fields

frappe_better_attach_control/public/js/controls/attach.js

+51-25
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,14 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro
166166
super.refresh();
167167
if (Helpers.isString(this.df.options))
168168
this.df.options = Helpers.parseJson(this.df.options, {});
169-
if (!Helpers.isPlainObject(this.df.options)) this.df.options = {};
169+
else if (!Helpers.isPlainObject(this.df.options)) this.df.options = {};
170170
if (!Helpers.isEqual(this.df.options, this._ls_options))
171-
this.set_options(this.df.options);
171+
this._update_options(true);
172172
}
173173
// Custom Methods
174-
auto_save(enable) {
175-
this._disable_auto_save = enable ? false : true;
174+
toggle_auto_save(enable) {
175+
if (enable != null) this._disable_auto_save = enable ? false : true;
176+
else this._disable_auto_save = !this._disable_auto_save;
176177
}
177178
toggle_reload(allow) {
178179
if (allow != null) this._allow_reload = !!allow;
@@ -187,8 +188,10 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro
187188
set_options(opts) {
188189
if (Helpers.isString(opts) && opts.length) opts = Helpers.parseJson(opts, null);
189190
if (Helpers.isEmpty(opts) || !Helpers.isPlainObject(opts)) return;
190-
$.extend(true, this.df.options, opts);
191-
this._update_options();
191+
opts = Helpers.merge(this.df.options, opts);
192+
if (Helpers.isEqual(this.df.options, opts)) return;
193+
this.df.options = opts;
194+
this._update_options(true);
192195
}
193196
// Private Methods
194197
_setup_control() {
@@ -231,16 +234,37 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro
231234
this.df.options = Helpers.parseJson(this.df.options, {});
232235
if (!Helpers.isPlainObject(this.df.options)) this.df.options = {};
233236
}
234-
_update_options() {
235-
this._ls_options = Helpers.deepClone(this.df.options);
236-
let opts;
237-
if (Helpers.isEmpty(this._ls_options)) opts = {};
238-
else opts = this._parse_options(this._ls_options);
239-
this._options = opts.options || null;
237+
_update_options(force) {
238+
if (!force && this._ls_options) return;
239+
this._ls_options = !Helpers.isEmpty(this.df.options) ? Helpers.deepClone(this.df.options) : {};
240+
let opts = {};
241+
if (!Helpers.isEmpty(this._ls_options)) {
242+
opts = this._parse_options(this._ls_options);
243+
if (!opts.disabled) {
244+
if (Helpers.isArray(this._ls_options.users) && this._ls_options.users.length) {
245+
let users = Helpers.filter(this._ls_options.users, function(v) {
246+
return this.isPlainObject(v) && (
247+
(this.isString(v.for) && v.for === frappe.session.user)
248+
|| (this.isArray(v.for) && v.for.indexOf(frappe.session.user) >= 0)
249+
);
250+
});
251+
if (users.length) opts = Helpers.merge(opts, this._parse_options(users[0]));
252+
} else if (Helpers.isArray(this._ls_options.roles)) {
253+
let roles = Helpers.filter(this._ls_options.roles, function(v) {
254+
return this.isPlainObject(v)
255+
&& (this.isString(v.for) || this.isArray(v.for))
256+
&& frappe.user.has_role(v.for);
257+
});
258+
if (roles.length) opts = Helpers.merge(opts, this._parse_options(roles[0]));
259+
}
260+
}
261+
}
262+
this._options = !opts.disabled ? (opts.options || null) : null;
240263
this._reload_control(opts);
241264
}
242265
_parse_options(opts) {
243266
var tmp = {options: {restrictions: {}, extra: {}}};
267+
tmp.disabled = Helpers.toBool(Helpers.ifNull(opts.disabled, false));
244268
tmp.allow_reload = Helpers.toBool(Helpers.ifNull(opts.allow_reload, true));
245269
tmp.allow_remove = Helpers.toBool(Helpers.ifNull(opts.allow_remove, true));
246270
Helpers.each([
@@ -279,22 +303,24 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro
279303
}
280304
_parse_allowed_file_types(opts) {
281305
opts.extra.allowed_file_types = [];
282-
if (Helpers.isEmpty(opts.restrictions.allowed_file_types)) return;
306+
if (!opts.restrictions.allowed_file_types.length) return;
283307
opts.restrictions.allowed_file_types = Helpers.filter(
284308
opts.restrictions.allowed_file_types,
285-
function(v) { return this.isRegExp(v) || (this.isString(v) && v.length); }
286-
);
287-
Helpers.each(opts.restrictions.allowed_file_types, function(t, i) {
288-
if (this.isString(t)) {
289-
if (t[0] === '$') t = new RegExp(t.substring(1));
290-
else if (t.substring(t.length - 2) === '/*')
291-
t = new RegExp(t.substring(0, t.length - 1) + '/(.*?)');
309+
function(v) {
310+
if (this.isString(v)) {
311+
if (!v.length) return false;
312+
if (v[0] === '$') {
313+
opts.extra.allowed_file_types.push(new RegExp(v.substring(1)));
314+
return false;
315+
}
316+
if (v.substring(v.length - 2) === '/*')
317+
opts.extra.allowed_file_types.push(new RegExp(v.substring(0, v.length - 1) + '/(.*?)'));
318+
return true;
319+
} else if (this.isRegExp(v)) {
320+
opts.extra.allowed_file_types.push(v);
321+
}
322+
return false;
292323
}
293-
opts.extra.allowed_file_types.push(t);
294-
});
295-
opts.restrictions.allowed_file_types = Helpers.filter(
296-
opts.restrictions.allowed_file_types,
297-
function(v) { return this.isString(v) && v[0] !== '$'; }
298324
);
299325
}
300326
_toggle_remove_button() {

frappe_better_attach_control/public/js/controls/v12/attach.js

+51-25
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,15 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
147147
this._super();
148148
if (Helpers.isString(this.df.options))
149149
this.df.options = Helpers.parseJson(this.df.options, {});
150-
if (!Helpers.isPlainObject(this.df.options)) this.df.options = {};
150+
else if (!Helpers.isPlainObject(this.df.options)) this.df.options = {};
151151
if (!Helpers.isEqual(this.df.options, this._ls_options))
152-
this.set_options(this.df.options);
152+
this._update_options(true);
153153
this.set_input(Helpers.toArray(this.value));
154154
},
155155
// Custom Methods
156-
auto_save: function(enable) {
157-
this._disable_auto_save = enable ? false : true;
156+
toggle_auto_save: function(enable) {
157+
if (enable != null) this._disable_auto_save = enable ? false : true;
158+
else this._disable_auto_save = !this._disable_auto_save;
158159
},
159160
toggle_remove: function(allow) {
160161
if (allow != null) this._allow_remove = !!allow;
@@ -164,8 +165,10 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
164165
set_options: function(opts) {
165166
if (Helpers.isString(opts) && opts.length) opts = Helpers.parseJson(opts, null);
166167
if (Helpers.isEmpty(opts) || !Helpers.isPlainObject(opts)) return;
167-
$.extend(true, this.df.options, opts);
168-
this._update_options();
168+
opts = Helpers.merge(this.df.options, opts);
169+
if (Helpers.isEqual(this.df.options, opts)) return;
170+
this.df.options = opts;
171+
this._update_options(true);
169172
},
170173
// Private Methods
171174
_setup_control: function() {
@@ -207,16 +210,37 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
207210
this.df.options = Helpers.parseJson(this.df.options, {});
208211
if (!Helpers.isPlainObject(this.df.options)) this.df.options = {};
209212
},
210-
_update_options: function() {
211-
this._ls_options = Helpers.deepClone(this.df.options);
212-
let opts;
213-
if (Helpers.isEmpty(this._ls_options)) opts = {};
214-
else opts = this._parse_options(this._ls_options);
215-
this._options = opts.options || null;
213+
_update_options: function(force) {
214+
if (!force && this._ls_options) return;
215+
this._ls_options = !Helpers.isEmpty(this.df.options) ? Helpers.deepClone(this.df.options) : {};
216+
let opts = {};
217+
if (!Helpers.isEmpty(this._ls_options)) {
218+
opts = this._parse_options(this._ls_options);
219+
if (!opts.disabled) {
220+
if (Helpers.isArray(this._ls_options.users) && this._ls_options.users.length) {
221+
let users = Helpers.filter(this._ls_options.users, function(v) {
222+
return this.isPlainObject(v) && (
223+
(this.isString(v.for) && v.for === frappe.session.user)
224+
|| (this.isArray(v.for) && v.for.indexOf(frappe.session.user) >= 0)
225+
);
226+
});
227+
if (users.length) opts = Helpers.merge(opts, this._parse_options(users[0]));
228+
} else if (Helpers.isArray(this._ls_options.roles)) {
229+
let roles = Helpers.filter(this._ls_options.roles, function(v) {
230+
return this.isPlainObject(v)
231+
&& (this.isString(v.for) || this.isArray(v.for))
232+
&& frappe.user.has_role(v.for);
233+
});
234+
if (roles.length) opts = Helpers.merge(opts, this._parse_options(roles[0]));
235+
}
236+
}
237+
}
238+
this._options = !opts.disabled ? (opts.options || null) : null;
216239
this._reload_control(opts);
217240
},
218241
_parse_options: function(opts) {
219242
var tmp = {options: {restrictions: {}, extra: {}}};
243+
tmp.disabled = Helpers.toBool(Helpers.ifNull(opts.disabled, false));
220244
tmp.allow_remove = Helpers.toBool(Helpers.ifNull(opts.allow_remove, true));
221245
Helpers.each([
222246
['upload_notes', 's'], ['disable_auto_save', 'b'],
@@ -251,22 +275,24 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
251275
},
252276
_parse_allowed_file_types: function(opts) {
253277
opts.extra.allowed_file_types = [];
254-
if (Helpers.isEmpty(opts.restrictions.allowed_file_types)) return;
278+
if (!opts.restrictions.allowed_file_types.length) return;
255279
opts.restrictions.allowed_file_types = Helpers.filter(
256280
opts.restrictions.allowed_file_types,
257-
function(v) { return this.isRegExp(v) || (this.isString(v) && v.length); }
258-
);
259-
Helpers.each(opts.restrictions.allowed_file_types, function(t, i) {
260-
if (this.isString(t)) {
261-
if (t[0] === '$') t = new RegExp(t.substring(1));
262-
else if (t.substring(t.length - 2) === '/*')
263-
t = new RegExp(t.substring(0, t.length - 1) + '/(.*?)');
281+
function(v) {
282+
if (this.isString(v)) {
283+
if (!v.length) return false;
284+
if (v[0] === '$') {
285+
opts.extra.allowed_file_types.push(new RegExp(v.substring(1)));
286+
return false;
287+
}
288+
if (v.substring(v.length - 2) === '/*')
289+
opts.extra.allowed_file_types.push(new RegExp(v.substring(0, v.length - 1) + '/(.*?)'));
290+
return true;
291+
} else if (this.isRegExp(v)) {
292+
opts.extra.allowed_file_types.push(v);
293+
}
294+
return false;
264295
}
265-
opts.extra.allowed_file_types.push(t);
266-
});
267-
opts.restrictions.allowed_file_types = Helpers.filter(
268-
opts.restrictions.allowed_file_types,
269-
function(v) { return this.isString(v) && v[0] !== '$'; }
270296
);
271297
},
272298
_toggle_remove_button: function() {

0 commit comments

Comments
 (0)