diff --git a/README.md b/README.md
index db93113..6690424 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ It supports RTL layout and dark mode out of the box.
⚠️ **v2 is still in BETA stage** ⚠️
-![v2 Beta15](https://img.shields.io/badge/v2_Beta15-2024/05/02-green?style=plastic)
+![v2 Beta16](https://img.shields.io/badge/v2_Beta16-2024/05/30-green?style=plastic)
**Apologies in advance for any problem or bug you face with this module.**
**Please report any problem or bug you face so it can be fixed.**
@@ -177,16 +177,17 @@ You can't modify the original fields of a doctype, so create a new field or clon
### Available Field Options
| Option | Description |
| :--- | :--- |
-| **dialog_title** 🔴 | Upload dialog title to be displayed ️(🔶Frappe >= v14.0.0).
🔹Example: **"Upload Images"**
🔹Default: **"Upload"** |
+| **dialog_title** | Upload dialog title to be displayed ️(🔶Frappe >= v14.0.0).
🔹Example: **"Upload Images"**
🔹Default: **"Upload"** |
| **upload_notes** | Upload text to be displayed.
🔹Example: **"Only images and videos, with maximum size of 2MB, are allowed to be uploaded"**
🔹Default: **""** |
-| **disable_file_browser** 🔴 | Disable file browser uploads.
⚠️ *(File browser is always disabled in Web Form)*
🔹Default: **false** |
+| **disable_auto_save** 🔴 | Disable form auto save after upload.
🔹Default: **false** |
+| **disable_file_browser** | Disable file browser uploads.
⚠️ *(File browser is always disabled in Web Form)*
🔹Default: **false** |
| **allow_multiple** | Allow multiple uploads.
⚠️ *(Field value is a JSON array of files url)*
🔹Default: **false** |
| **max_file_size** | Maximum file size (in bytes) that is allowed to be uploaded.
🔹Example: **2048** for **2KB**
🔹Default: **Value of maximum file size in Frappe's settings** |
| **allowed_file_types** | Array of allowed file types (mimes) or extensions to upload. Prefix escaped RegExp string types with **$**.
⚠️ *(File extensions must have a leading dot ".")*
⚠️ *(RegExp string types will not be used to in HTML accept attribute)*
🔹Example: **["image/*", "video/*", ".pdf", ".doc", "$audio\/([a-z]+)"]**
🔹Default: **null** or **["image/*"]** |
| **max_number_of_files** | Maximum number of files allowed to be uploaded if multiple upload is allowed.
⚠️ *(Bypassing the maximum attachments of doctype might not work)*
🔹Example: **4**
🔹Default: **Value of maximum attachments set for the doctype** |
| **crop_image_aspect_ratio** | Crop aspect ratio for images (🔶Frappe >= v14.0.0).
🔹Example: **1** or **16/9** or **4/3**
🔹Default: **null** |
| **as_public** | Force uploads to be saved in public folder by default.
🔹Default: **false** |
-| **allowed_filename** 🔴 | Only allow files that match a specific file name to be uploaded.
🔹Example: (String)**"picture.png"** or (RegExp String)**"/picture\-([0-9]+)\.png/"**
🔹Default: **null** |
+| **allowed_filename** | Only allow files that match a specific file name to be uploaded.
🔹Example: (String)**"picture.png"** or (RegExp String)**"/picture\-([0-9]+)\.png/"**
🔹Default: **null** |
| **allow_reload** | Allow reloading attachments (🔶Frappe >= v13.0.0).
🔶 Affect the visibility of the reload button.🔶
🔹Default: **true** |
| **allow_remove** | Allow removing and clearing attachments.
🔶 Affect the visibility of the remove and clear buttons.🔶
🔹Default: **true** |
@@ -195,6 +196,7 @@ You can't modify the original fields of a doctype, so create a new field or clon
### Available JavaScript Methods
| Method | Description |
| :--- | :--- |
+| **auto_save(enable: Boolean)** | Enable/Disable form auto save after upload. |
| **toggle_reload(allow: Boolean !Optional)** | Allow/Deny reloading attachments and toggle the reload button (🔶Frappe >= v13.0.0). |
| **toggle_remove(allow: Boolean !Optional)** | Allow/Deny removing and clearing attachments and toggle the clear and remove buttons. |
| **set_options(options: JSON Object)** | Set or change the plugin options. |
diff --git a/frappe_better_attach_control/api/attachment.py b/frappe_better_attach_control/api/attachment.py
index 87c1c1b..b4ad77c 100644
--- a/frappe_better_attach_control/api/attachment.py
+++ b/frappe_better_attach_control/api/attachment.py
@@ -5,14 +5,6 @@
import frappe
-from frappe import _, is_whitelisted
-from frappe.utils import cint
-
-from .common import (
- is_version_gt,
- parse_json_if_valid,
- send_console_log
-)
_FILE_DOCTYPE_ = "File"
@@ -33,6 +25,8 @@
@frappe.whitelist(allow_guest=True)
def upload_file():
+ from frappe_better_attach_control.version import is_version_gt
+
user = None
ignore_permissions = False
@@ -91,6 +85,8 @@ def upload_file():
):
filetype = mimetypes.guess_type(filename)[0]
if filetype not in _ALLOWED_MIMETYPES_:
+ from frappe import _
+
frappe.throw(_("You can only upload JPG, PNG, PDF, TXT or Microsoft documents."))
elif is_version_gt(12):
@@ -99,9 +95,11 @@ def upload_file():
if method:
method = frappe.get_attr(method)
- is_whitelisted(method)
+ frappe.is_whitelisted(method)
return method()
else:
+ from frappe.utils import cint
+
ret = frappe.get_doc({
"doctype": _FILE_DOCTYPE_,
"attached_to_doctype": doctype,
@@ -124,10 +122,12 @@ def upload_file():
@frappe.whitelist(methods=["POST"], allow_guest=True)
def remove_files(files):
if files and isinstance(files, str):
+ from .common import parse_json_if_valid
+
files = parse_json_if_valid(files)
if not files or not isinstance(files, list):
- send_console_log({
+ _send_console_log({
"message": "Invalid files list",
"data": files
})
@@ -148,7 +148,7 @@ def remove_files(files):
file_names.append(file)
if not file_urls and not file_names:
- send_console_log({
+ _send_console_log({
"message": "Invalid files path",
"data": files
})
@@ -176,8 +176,15 @@ def remove_files(files):
return 1
- send_console_log({
+ _send_console_log({
"message": "Files not found",
"data": files
})
- return 3
\ No newline at end of file
+ return 3
+
+
+# [Internal]
+def _send_console_log(data):
+ from .common import send_console_log
+
+ send_console_log(data)
\ No newline at end of file
diff --git a/frappe_better_attach_control/api/common.py b/frappe_better_attach_control/api/common.py
index 9fdb454..a3f5660 100644
--- a/frappe_better_attach_control/api/common.py
+++ b/frappe_better_attach_control/api/common.py
@@ -7,26 +7,17 @@
import json
import frappe
-from frappe import __version__, _, _dict
-
-
-__frappe_base_ver__ = int(__version__.split(".")[0])
-
-
-def is_version_gt(num: int):
- return __frappe_base_ver__ > num
-
-
-def is_version_lt(num: int):
- return __frappe_base_ver__ < num
+from frappe import _, _dict
def error(msg, throw=True):
+ from frappe_better_attach_control.version import is_version_lt
+
title = "Better Attach Control"
if is_version_lt(14):
- frappe.log_error(text, title)
+ frappe.log_error(msg, title)
else:
- frappe.log_error(title, text)
+ frappe.log_error(title, msg)
if throw:
frappe.throw(msg, title=title)
diff --git a/frappe_better_attach_control/api/field.py b/frappe_better_attach_control/api/field.py
index 09ad52c..98f7357 100644
--- a/frappe_better_attach_control/api/field.py
+++ b/frappe_better_attach_control/api/field.py
@@ -6,20 +6,18 @@
import frappe
-from .common import send_console_log
-
@frappe.whitelist(methods=["POST"], allow_guest=True)
def get_options(doctype, name, webform):
if not doctype or not isinstance(doctype, str):
- send_console_log({
+ _send_console_log({
"message": "Empty or invalid field doctype",
"data": [doctype, name]
})
return ""
if not name or not isinstance(name, str):
- send_console_log({
+ _send_console_log({
"message": "Empty or invalid field name",
"data": [doctype, name]
})
@@ -67,8 +65,15 @@ def get_options(doctype, name, webform):
if options and isinstance(options, str):
return options
- send_console_log({
+ _send_console_log({
"message": "Empty or invalid field options",
"data": [doctype, name, options]
})
- return ""
\ No newline at end of file
+ return ""
+
+
+# [Internal]
+def _send_console_log(data):
+ from .common import send_console_log
+
+ send_console_log(data)
\ No newline at end of file
diff --git a/frappe_better_attach_control/api/file_manager.py b/frappe_better_attach_control/api/file_manager.py
index a457d78..46c779e 100644
--- a/frappe_better_attach_control/api/file_manager.py
+++ b/frappe_better_attach_control/api/file_manager.py
@@ -8,12 +8,9 @@
import frappe
from frappe import _
-from frappe.utils import flt, cint, cstr, get_url, get_files_path
-from frappe.utils.file_manager import is_safe_path
+from frappe.utils import cint, cstr, get_url
from frappe.core.doctype.file.file import URL_PREFIXES
-from .common import error, get_cached_value
-
_FILE_DOCTYPE_ = "File"
_FILE_FIELDS_ = [
@@ -48,6 +45,8 @@ def _get_files_in_folder(folder, start, page_length):
)
if folder == "Home":
+ from .common import get_cached_value
+
attachment_folder = get_cached_value(
_FILE_DOCTYPE_,
"Home/Attachments",
@@ -87,6 +86,8 @@ def _prepare_files(files):
file = files[i]
file["size"] = 0
if not cint(file["is_folder"]):
+ from frappe.utils import flt
+
file["size"] = flt(file["file_size"])
if not file["size"]:
try:
@@ -114,21 +115,34 @@ def _get_full_path(file):
file_path = f"/files/{file_path}"
if file_path.startswith("/private/files/"):
+ from frappe.utils import get_files_path
+
file_path = get_files_path(*file_path.split("/private/files/", 1)[1].split("/"), is_private=1)
elif file_path.startswith("/files/"):
+ from frappe.utils import get_files_path
+
file_path = get_files_path(*file_path.split("/files/", 1)[1].split("/"))
elif file_path.startswith(URL_PREFIXES):
pass
elif not file["file_url"]:
- error(_("There is some problem with the file url: {0}").format(file_path))
+ _error(_("There is some problem with the file url: {0}").format(file_path))
+
+ from frappe.utils.file_manager import is_safe_path
if not is_safe_path(file_path):
- error(_("Cannot access file path {0}").format(file_path))
+ _error(_("Cannot access file path {0}").format(file_path))
if os.path.sep in file["file_name"]:
- error(_("File name cannot have {0}").format(os.path.sep))
+ _error(_("File name cannot have {0}").format(os.path.sep))
+
+ return file_path
+
+
+# [Internal]
+def _error(msg):
+ from .common import error
- return file_path
\ No newline at end of file
+ error(msg)
\ No newline at end of file
diff --git a/frappe_better_attach_control/api/website.py b/frappe_better_attach_control/api/website.py
index d3f2da0..edbc482 100644
--- a/frappe_better_attach_control/api/website.py
+++ b/frappe_better_attach_control/api/website.py
@@ -8,20 +8,19 @@
import frappe
from frappe import _
+from frappe.utils import cstr
def website_context(context):
if (
not context.get("doc", "") or
- not hasattr(context.doc, "doctype") or
- not hasattr(context.doc, "name") or
+ "doctype" not in context.doc or
+ "name" not in context.doc or
context.doc.doctype != "Web Form" or
not context.doc.name
):
return 0
- from .common import error
-
try:
fields = frappe.get_all(
"Web Form Field",
@@ -33,17 +32,18 @@ def website_context(context):
"fieldtype": ["in", ["Attach", "Attach Image"]],
}
)
- if not fields:
+ if not fields or not isinstance(fields, list):
return 0
options = {}
- for field in fields:
+ for v in fields:
+ v["options"] = cstr(v["options"]).strip()
if (
- field["options"] and
- isinstance(field["options"], str) and
- field["options"][0] == "{"
+ v["options"] and
+ v["options"].startswith("{") and
+ v["options"].endswith("{")
):
- options[field["fieldname"]] = field["options"]
+ options[v["fieldname"]] = v["options"]
if not options:
return 0
@@ -59,7 +59,7 @@ def website_context(context):
script = f"{script}\nfrappe.BAC.options = {options};"
set_context(context, "script", script)
except Exception:
- error(_("Unable to get the Attach fields of the web form."), throw=False)
+ _error(_("Unable to get the Attach fields of the web form."))
return 0
app_name = "frappe_better_attach_control"
@@ -73,13 +73,13 @@ def website_context(context):
set_context(context, "script", scripts)
js_loaded = True
except Exception:
- error(_("Unable to inject the js bundled file to context."), throw=False)
+ _error(_("Unable to inject the js bundled file to context."))
if not js_loaded:
try:
js_files = frappe.get_hooks("better_webform_include_js", default=None, app_name=app_name)
if not js_files:
- error(_("Unable to inject the js files to context."), throw=False)
+ _error(_("Unable to inject the js files to context."))
else:
if not isinstance(js_files, list):
js_files = [js_files]
@@ -91,7 +91,7 @@ def website_context(context):
data = read_file(path)
scripts.append(f"// {js}\n{data}")
else:
- error(_("Unable to inject the js file \"{0}\" to context.").format(js), throw=False)
+ _error(_("Unable to inject the js file \"{0}\" to context.").format(js))
if scripts:
scripts = clean_js_script("\n\n\n".join(scripts))
@@ -99,12 +99,12 @@ def website_context(context):
write_file(bundled_js, scripts)
set_context(context, "script", scripts)
except Exception:
- error(_("Unable to inject the js files to context."), throw=False)
+ _error(_("Unable to inject the js files to context."))
try:
css_files = frappe.get_hooks("better_webform_include_css", default=None, app_name=app_name)
if not css_files:
- error(_("Unable to inject the css files to context."), throw=False)
+ _error(_("Unable to inject the css files to context."))
else:
if not isinstance(css_files, list):
css_files = [css_files]
@@ -116,12 +116,12 @@ def website_context(context):
data = read_file(path)
styles.append(f"// {css}\n{data}")
else:
- error(_("Unable to inject the css file \"{0}\" to context.").format(css), throw=False)
+ _error(_("Unable to inject the css file \"{0}\" to context.").format(css))
if styles:
set_context(context, "style", "\n\n\n".join(styles))
except Exception:
- error(_("Unable to inject the css files to context."), throw=False)
+ _error(_("Unable to inject the css files to context."))
def set_context(context, key, data):
@@ -177,4 +177,10 @@ def clean_js_script(data):
data = re.sub("(" + "|".join(rgx) + ")", "", data)
data = re.sub("^([\s\n\r]+)", "", data)
data = re.sub("([\n\r]{3,})", "\n\n\n", data)
- return data
\ No newline at end of file
+ return data
+
+
+def _error(msg):
+ from .common import error
+
+ error(msg, throw=False)
\ No newline at end of file
diff --git a/frappe_better_attach_control/hooks.py b/frappe_better_attach_control/hooks.py
index ddab61d..1e3df76 100644
--- a/frappe_better_attach_control/hooks.py
+++ b/frappe_better_attach_control/hooks.py
@@ -4,8 +4,7 @@
# Licence: Please refer to LICENSE file
-from . import __version__ as app_version
-from frappe import __version__ as frappe_version
+from .version import is_version_gt
app_name = "frappe_better_attach_control"
@@ -18,13 +17,9 @@
app_license = "MIT"
-is_frappe_above_v13 = int(frappe_version.split(".")[0]) > 13
-is_frappe_above_v12 = int(frappe_version.split(".")[0]) > 12
-
-
app_include_css = [
"better_attach.bundle.css"
-] if is_frappe_above_v13 else [
+] if is_version_gt(13) else [
"/assets/frappe_better_attach_control/css/better_attach.css"
]
@@ -36,9 +31,9 @@
app_include_js = [
"better_attach.bundle.js"
-] if is_frappe_above_v13 else ([
+] if is_version_gt(13) else ([
"/assets/frappe_better_attach_control/js/better_attach_v13.bundle.js"
-] if is_frappe_above_v12 else [
+] if is_version_gt(12) else [
"/assets/frappe_better_attach_control/js/better_attach_v12.bundle.js"
])
@@ -49,13 +44,13 @@
"/assets/frappe_better_attach_control/js/uploader/index.js",
"/assets/frappe_better_attach_control/js/controls/attach.js",
"/assets/frappe_better_attach_control/js/controls/attach_image.js"
-] if is_frappe_above_v13 else ([
+] if is_version_gt(13) else ([
"/assets/frappe_better_attach_control/js/utils/index.js",
"/assets/frappe_better_attach_control/js/filetypes/index.js",
"/assets/frappe_better_attach_control/js/uploader/v13/index.js",
"/assets/frappe_better_attach_control/js/controls/v13/attach.js",
"/assets/frappe_better_attach_control/js/controls/v13/attach_image.js"
-] if is_frappe_above_v12 else [
+] if is_version_gt(12) else [
"/assets/frappe_better_attach_control/js/utils/index.js",
"/assets/frappe_better_attach_control/js/filetypes/index.js",
"/assets/frappe_better_attach_control/js/uploader/v12/index.js",
diff --git a/frappe_better_attach_control/public/js/controls/attach.js b/frappe_better_attach_control/public/js/controls/attach.js
index ec9ab8e..9b3cb6d 100644
--- a/frappe_better_attach_control/public/js/controls/attach.js
+++ b/frappe_better_attach_control/public/js/controls/attach.js
@@ -171,6 +171,9 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro
this.set_options(this.df.options);
}
// Custom Methods
+ auto_save(enable) {
+ this._disable_auto_save = enable ? false : true;
+ }
toggle_reload(allow) {
if (allow != null) this._allow_reload = !!allow;
else this._allow_reload = !this._allow_reload;
@@ -182,14 +185,13 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro
this._toggle_remove_button();
}
set_options(opts) {
+ if (Helpers.isString(opts) && opts.length) opts = Helpers.parseJson(opts, null);
if (Helpers.isEmpty(opts) || !Helpers.isPlainObject(opts)) return;
$.extend(true, this.df.options, opts);
this._update_options();
}
// Private Methods
_setup_control() {
- if (this._is_better) return;
- this._is_better = 1;
this._doctype = (this.frm && this.frm.doctype)
|| this.doctype
|| (this.doc && this.doc.doctype)
@@ -212,6 +214,7 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro
this._options = null;
this._value = [];
this._files = [];
+ this._disable_auto_save = false;
this._allow_multiple = false;
this._max_attachments = {};
this._allow_reload = true;
@@ -241,8 +244,9 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro
tmp.allow_reload = Helpers.toBool(Helpers.ifNull(opts.allow_reload, true));
tmp.allow_remove = Helpers.toBool(Helpers.ifNull(opts.allow_remove, true));
Helpers.each([
- ['upload_notes', 's'], ['allow_multiple', 'b'],
- ['disable_file_browser', 'b'], ['dialog_title', 's'],
+ ['upload_notes', 's'], ['disable_auto_save', 'b'],
+ ['allow_multiple', 'b'], ['disable_file_browser', 'b'],
+ ['dialog_title', 's'],
], function(k) {
tmp.options[k[0]] = this._parse_options_val(opts[k[0]], k[1]);
}, this);
@@ -305,6 +309,8 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro
if (this.upload_options)
this.upload_options = this.image_upload_options = null;
+ this._disable_auto_save = this._options && this._options.disable_auto_save;
+
if (Helpers.ifNull(opts.allow_reload, true) !== this._allow_reload)
this.toggle_reload(!this._allow_reload);
if (Helpers.ifNull(opts.allow_remove, true) !== this._allow_remove)
@@ -687,6 +693,7 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro
});
}
_form_save() {
+ if (this._disable_auto_save) return;
this.frm.doc.docstatus == 1 ? this.frm.save('Update') : this.frm.save();
}
};
diff --git a/frappe_better_attach_control/public/js/controls/v12/attach.js b/frappe_better_attach_control/public/js/controls/v12/attach.js
index ab4f5a0..6c524a9 100644
--- a/frappe_better_attach_control/public/js/controls/v12/attach.js
+++ b/frappe_better_attach_control/public/js/controls/v12/attach.js
@@ -153,20 +153,22 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
this.set_input(Helpers.toArray(this.value));
},
// Custom Methods
+ auto_save: function(enable) {
+ this._disable_auto_save = enable ? false : true;
+ },
toggle_remove: function(allow) {
if (allow != null) this._allow_remove = !!allow;
else this._allow_remove = !this._allow_remove;
this._toggle_remove_button();
},
set_options: function(opts) {
+ if (Helpers.isString(opts) && opts.length) opts = Helpers.parseJson(opts, null);
if (Helpers.isEmpty(opts) || !Helpers.isPlainObject(opts)) return;
$.extend(true, this.df.options, opts);
this._update_options();
},
// Private Methods
_setup_control: function() {
- if (this._is_better) return;
- this._is_better = 1;
this._doctype = (this.frm && this.frm.doctype)
|| this.doctype
|| (this.doc && this.doc.doctype)
@@ -189,6 +191,7 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
this._options = null;
this._value = [];
this._files = [];
+ this._disable_auto_save = false;
this._allow_multiple = false;
this._max_attachments = {};
this._allow_remove = true;
@@ -216,8 +219,8 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
var tmp = {options: {restrictions: {}, extra: {}}};
tmp.allow_remove = Helpers.toBool(Helpers.ifNull(opts.allow_remove, true));
Helpers.each([
- ['upload_notes', 's'], ['allow_multiple', 'b'],
- ['disable_file_browser', 'b'],
+ ['upload_notes', 's'], ['disable_auto_save', 'b'],
+ ['allow_multiple', 'b'], ['disable_file_browser', 'b'],
], function(k) {
tmp.options[k[0]] = this._parse_options_val(opts[k[0]], k[1]);
}, this);
@@ -277,6 +280,8 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
_reload_control: function(opts) {
if (this.upload_options) this.upload_options = null;
+ this._disable_auto_save = this._options && this._options.disable_auto_save;
+
if (Helpers.ifNull(opts.allow_remove, true) !== this._allow_remove)
this.toggle_remove(!this._allow_remove);
@@ -654,6 +659,7 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
});
},
_form_save: function() {
+ if (this._disable_auto_save) return;
this.frm.doc.docstatus == 1 ? this.frm.save('Update') : this.frm.save();
}
});
\ No newline at end of file
diff --git a/frappe_better_attach_control/public/js/controls/v13/attach.js b/frappe_better_attach_control/public/js/controls/v13/attach.js
index 0d31b60..d758292 100644
--- a/frappe_better_attach_control/public/js/controls/v13/attach.js
+++ b/frappe_better_attach_control/public/js/controls/v13/attach.js
@@ -163,6 +163,9 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
this.set_input(Helpers.toArray(this.value));
},
// Custom Methods
+ auto_save: function(enable) {
+ this._disable_auto_save = enable ? false : true;
+ },
toggle_reload: function(allow) {
if (allow != null) this._allow_reload = !!allow;
else this._allow_reload = !this._allow_reload;
@@ -174,14 +177,13 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
this._toggle_remove_button();
},
set_options: function(opts) {
+ if (Helpers.isString(opts) && opts.length) opts = Helpers.parseJson(opts, null);
if (Helpers.isEmpty(opts) || !Helpers.isPlainObject(opts)) return;
$.extend(true, this.df.options, opts);
this._update_options();
},
// Private Methods
_setup_control: function() {
- if (this._is_better) return;
- this._is_better = 1;
this._doctype = (this.frm && this.frm.doctype)
|| this.doctype
|| (this.doc && this.doc.doctype)
@@ -204,6 +206,7 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
this._options = null;
this._value = [];
this._files = [];
+ this._disable_auto_save = false;
this._allow_multiple = false;
this._max_attachments = {};
this._allow_reload = true;
@@ -233,8 +236,8 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
tmp.allow_reload = Helpers.toBool(Helpers.ifNull(opts.allow_reload, true));
tmp.allow_remove = Helpers.toBool(Helpers.ifNull(opts.allow_remove, true));
Helpers.each([
- ['upload_notes', 's'], ['allow_multiple', 'b'],
- ['disable_file_browser', 'b'],
+ ['upload_notes', 's'], ['disable_auto_save', 'b'],
+ ['allow_multiple', 'b'], ['disable_file_browser', 'b'],
], function(k) {
tmp.options[k[0]] = this._parse_options_val(opts[k[0]], k[1]);
}, this);
@@ -294,6 +297,8 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
_reload_control: function(opts) {
if (this.upload_options) this.upload_options = null;
+ this._disable_auto_save = this._options && this._options.disable_auto_save;
+
if (Helpers.ifNull(opts.allow_reload, true) !== this._allow_reload)
this.toggle_reload(!this._allow_reload);
if (Helpers.ifNull(opts.allow_remove, true) !== this._allow_remove)
@@ -673,6 +678,7 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlAttach.extend({
});
},
_form_save: function() {
+ if (this._disable_auto_save) return;
this.frm.doc.docstatus == 1 ? this.frm.save('Update') : this.frm.save();
}
});
\ No newline at end of file
diff --git a/frappe_better_attach_control/public/js/uploader/v12/index.js b/frappe_better_attach_control/public/js/uploader/v12/index.js
index ab24db0..c3f4d13 100644
--- a/frappe_better_attach_control/public/js/uploader/v12/index.js
+++ b/frappe_better_attach_control/public/js/uploader/v12/index.js
@@ -18,7 +18,7 @@ frappe.ui.FileUploader = class FileUploader extends frappe.ui.FileUploader {
super(opts);
if (this.uploader) this._override_uploader(opts, extra);
}
- _override_uploader(opts) {
+ _override_uploader(opts, extra) {
var up = this.uploader,
me = this;
up._extra_restrictions = extra;
@@ -92,6 +92,7 @@ frappe.ui.FileUploader = class FileUploader extends frappe.ui.FileUploader {
'File skipped because it exceeds the allowed specified limit of ' + max_number_of_files + ' uploads',
file
);
+ var MSG;
if (up.doctype) {
MSG = __('File "{0}" was skipped because only {1} uploads are allowed for DocType "{2}"',
[file.name, max_number_of_files, up.doctype]);
diff --git a/frappe_better_attach_control/public/js/uploader/v13/index.js b/frappe_better_attach_control/public/js/uploader/v13/index.js
index 2d76a96..60204a8 100644
--- a/frappe_better_attach_control/public/js/uploader/v13/index.js
+++ b/frappe_better_attach_control/public/js/uploader/v13/index.js
@@ -92,6 +92,7 @@ frappe.ui.FileUploader = class FileUploader extends frappe.ui.FileUploader {
'File skipped because it exceeds the allowed specified limit of ' + max_number_of_files + ' uploads',
file
);
+ var MSG;
if (up.doctype) {
MSG = __('File "{0}" was skipped because only {1} uploads are allowed for DocType "{2}"',
[file.name, max_number_of_files, up.doctype]);
diff --git a/frappe_better_attach_control/public/js/utils/index.js b/frappe_better_attach_control/public/js/utils/index.js
index f61e01b..c6af81d 100644
--- a/frappe_better_attach_control/public/js/utils/index.js
+++ b/frappe_better_attach_control/public/js/utils/index.js
@@ -115,7 +115,7 @@ var Helpers = {
if (!this.isIteratable(data) || !this.isIteratable(base)) return data == base;
var ret = true;
this.each(data, function(v, k) {
- if (!this.isEqual(y, base[k])) return (ret = false);
+ if (!this.isEqual(v, base[k])) return (ret = false);
});
return ret;
},
diff --git a/frappe_better_attach_control/version.py b/frappe_better_attach_control/version.py
new file mode 100644
index 0000000..941d72d
--- /dev/null
+++ b/frappe_better_attach_control/version.py
@@ -0,0 +1,21 @@
+# Frappe Better Attach Control © 2024
+# Author: Ameen Ahmed
+# Company: Level Up Marketing & Software Development Services
+# Licence: Please refer to LICENSE file
+
+
+from frappe import __version__
+
+
+# [Internal]
+__frappe_version__ = int(__version__.split(".")[0])
+
+
+# [Hooks, Attachment]
+def is_version_gt(num: int):
+ return __frappe_version__ > num
+
+
+# [Common]
+def is_version_lt(num: int):
+ return __frappe_version__ < num
\ No newline at end of file