Browse Source

Merge branch 'develop' into workspace-deleted-issue

version-14
Suraj Shetty 4 years ago
committed by GitHub
parent
commit
d7b40ded9e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 2558 additions and 1313 deletions
  1. +12
    -0
      .git-blame-ignore-revs
  2. +3
    -3
      .github/workflows/publish-assets-develop.yml
  3. +2
    -2
      .github/workflows/publish-assets-releases.yml
  4. +1
    -1
      .github/workflows/server-mariadb-tests.yml
  5. +1
    -1
      .github/workflows/ui-tests.yml
  6. +1
    -0
      .gitignore
  7. +1
    -1
      cypress/integration/recorder.js
  8. +486
    -0
      esbuild/esbuild.js
  9. +43
    -0
      esbuild/frappe-html.js
  10. +11
    -0
      esbuild/ignore-assets.js
  11. +1
    -0
      esbuild/index.js
  12. +29
    -0
      esbuild/sass_options.js
  13. +145
    -0
      esbuild/utils.js
  14. +9
    -4
      frappe/__init__.py
  15. +60
    -47
      frappe/build.py
  16. +3
    -0
      frappe/cache_manager.py
  17. +23
    -20
      frappe/commands/utils.py
  18. +2
    -2
      frappe/core/doctype/data_import/data_import.js
  19. +1
    -1
      frappe/core/page/recorder/recorder.js
  20. +8
    -7
      frappe/desk/page/activity/activity.js
  21. +5
    -11
      frappe/email/email_body.py
  22. +10
    -8
      frappe/hooks.py
  23. +5
    -2
      frappe/printing/page/print/print.js
  24. +64
    -64
      frappe/printing/page/print_format_builder/print_format_builder.js
  25. +1
    -1
      frappe/public/html/print_template.html
  26. +1
    -0
      frappe/public/js/barcode_scanner.bundle.js
  27. +64
    -0
      frappe/public/js/bootstrap-4-web.bundle.js
  28. +1
    -0
      frappe/public/js/chat.bundle.js
  29. +1
    -0
      frappe/public/js/checkout.bundle.js
  30. +18
    -0
      frappe/public/js/controls.bundle.js
  31. +1
    -0
      frappe/public/js/data_import_tools.bundle.js
  32. +105
    -0
      frappe/public/js/desk.bundle.js
  33. +7
    -0
      frappe/public/js/dialog.bundle.js
  34. +17
    -0
      frappe/public/js/form.bundle.js
  35. +26
    -0
      frappe/public/js/frappe-web.bundle.js
  36. +15
    -1
      frappe/public/js/frappe/assets.js
  37. +1
    -1
      frappe/public/js/frappe/barcode_scanner/index.js
  38. +111
    -0
      frappe/public/js/frappe/build_events/BuildError.vue
  39. +52
    -0
      frappe/public/js/frappe/build_events/BuildSuccess.vue
  40. +48
    -0
      frappe/public/js/frappe/build_events/build_events.bundle.js
  41. +1
    -1
      frappe/public/js/frappe/class.js
  42. +58
    -60
      frappe/public/js/frappe/desk.js
  43. +15
    -15
      frappe/public/js/frappe/form/controls/attach.js
  44. +5
    -5
      frappe/public/js/frappe/form/controls/attach_image.js
  45. +11
    -11
      frappe/public/js/frappe/form/controls/autocomplete.js
  46. +7
    -7
      frappe/public/js/frappe/form/controls/barcode.js
  47. +30
    -30
      frappe/public/js/frappe/form/controls/base_control.js
  48. +36
    -36
      frappe/public/js/frappe/form/controls/base_input.js
  49. +16
    -16
      frappe/public/js/frappe/form/controls/button.js
  50. +16
    -15
      frappe/public/js/frappe/form/controls/check.js
  51. +13
    -12
      frappe/public/js/frappe/form/controls/code.js
  52. +19
    -14
      frappe/public/js/frappe/form/controls/color.js
  53. +13
    -13
      frappe/public/js/frappe/form/controls/comment.js
  54. +5
    -5
      frappe/public/js/frappe/form/controls/currency.js
  55. +38
    -34
      frappe/public/js/frappe/form/controls/data.js
  56. +26
    -26
      frappe/public/js/frappe/form/controls/date.js
  57. +14
    -14
      frappe/public/js/frappe/form/controls/date_range.js
  58. +12
    -12
      frappe/public/js/frappe/form/controls/datetime.js
  59. +21
    -21
      frappe/public/js/frappe/form/controls/duration.js
  60. +4
    -4
      frappe/public/js/frappe/form/controls/dynamic_link.js
  61. +9
    -9
      frappe/public/js/frappe/form/controls/float.js
  62. +12
    -12
      frappe/public/js/frappe/form/controls/geolocation.js
  63. +3
    -3
      frappe/public/js/frappe/form/controls/heading.js
  64. +12
    -12
      frappe/public/js/frappe/form/controls/html.js
  65. +5
    -5
      frappe/public/js/frappe/form/controls/html_editor.js
  66. +6
    -6
      frappe/public/js/frappe/form/controls/image.js
  67. +14
    -14
      frappe/public/js/frappe/form/controls/int.js
  68. +28
    -28
      frappe/public/js/frappe/form/controls/link.js
  69. +11
    -11
      frappe/public/js/frappe/form/controls/markdown_editor.js
  70. +20
    -20
      frappe/public/js/frappe/form/controls/multicheck.js
  71. +10
    -10
      frappe/public/js/frappe/form/controls/multiselect.js
  72. +15
    -15
      frappe/public/js/frappe/form/controls/multiselect_list.js
  73. +14
    -14
      frappe/public/js/frappe/form/controls/multiselect_pills.js
  74. +12
    -12
      frappe/public/js/frappe/form/controls/password.js
  75. +5
    -5
      frappe/public/js/frappe/form/controls/rating.js
  76. +5
    -5
      frappe/public/js/frappe/form/controls/read_only.js
  77. +18
    -18
      frappe/public/js/frappe/form/controls/select.js
  78. +49
    -41
      frappe/public/js/frappe/form/controls/signature.js
  79. +19
    -18
      frappe/public/js/frappe/form/controls/table.js
  80. +15
    -15
      frappe/public/js/frappe/form/controls/table_multiselect.js
  81. +13
    -13
      frappe/public/js/frappe/form/controls/text.js
  82. +13
    -13
      frappe/public/js/frappe/form/controls/text_editor.js
  83. +25
    -25
      frappe/public/js/frappe/form/controls/time.js
  84. +11
    -11
      frappe/public/js/frappe/form/footer/footer.js
  85. +14
    -6
      frappe/public/js/frappe/form/form.js
  86. +89
    -89
      frappe/public/js/frappe/form/layout.js
  87. +9
    -9
      frappe/public/js/frappe/form/link_selector.js
  88. +35
    -35
      frappe/public/js/frappe/form/quick_entry.js
  89. +17
    -17
      frappe/public/js/frappe/form/script_manager.js
  90. +22
    -22
      frappe/public/js/frappe/form/sidebar/assign_to.js
  91. +33
    -33
      frappe/public/js/frappe/form/sidebar/attachments.js
  92. +18
    -18
      frappe/public/js/frappe/form/sidebar/share.js
  93. +15
    -15
      frappe/public/js/frappe/form/workflow.js
  94. +9
    -9
      frappe/public/js/frappe/module_editor.js
  95. +1
    -1
      frappe/public/js/frappe/ui/chart.js
  96. +1
    -0
      frappe/public/js/frappe/ui/dialog.js
  97. +31
    -31
      frappe/public/js/frappe/ui/field_group.js
  98. +10
    -10
      frappe/public/js/frappe/ui/filters/field_select.js
  99. +17
    -17
      frappe/public/js/frappe/ui/iconbar.js
  100. +138
    -138
      frappe/public/js/frappe/ui/page.js

+ 12
- 0
.git-blame-ignore-revs View File

@@ -0,0 +1,12 @@
# Since version 2.23 (released in August 2019), git-blame has a feature
# to ignore or bypass certain commits.
#
# This file contains a list of commits that are not likely what you
# are looking for in a blame, such as mass reformatting or renaming.
# You can set this file as a default ignore file for blame by running
# the following command.
#
# $ git config blame.ignoreRevsFile .git-blame-ignore-revs

# Replace use of Class.extend with native JS class
fe20515c23a3ac41f1092bf0eaf0a0a452ec2e85

+ 3
- 3
.github/workflows/publish-assets-develop.yml View File

@@ -15,11 +15,11 @@ jobs:
path: 'frappe'
- uses: actions/setup-node@v1
with:
python-version: '12.x'
node-version: 14
- uses: actions/setup-python@v2
with:
python-version: '3.6'
- name: Set up bench for current push
- name: Set up bench and build assets
run: |
npm install -g yarn
pip3 install -U frappe-bench
@@ -29,7 +29,7 @@ jobs:
- name: Package assets
run: |
mkdir -p $GITHUB_WORKSPACE/build
tar -cvpzf $GITHUB_WORKSPACE/build/$GITHUB_SHA.tar.gz ./frappe-bench/sites/assets/js ./frappe-bench/sites/assets/css
tar -cvpzf $GITHUB_WORKSPACE/build/$GITHUB_SHA.tar.gz ./frappe-bench/sites/assets/frappe/dist

- name: Publish assets to S3
uses: jakejarvis/s3-sync-action@master


+ 2
- 2
.github/workflows/publish-assets-releases.yml View File

@@ -22,7 +22,7 @@ jobs:
- uses: actions/setup-python@v2
with:
python-version: '3.6'
- name: Set up bench for current push
- name: Set up bench and build assets
run: |
npm install -g yarn
pip3 install -U frappe-bench
@@ -32,7 +32,7 @@ jobs:
- name: Package assets
run: |
mkdir -p $GITHUB_WORKSPACE/build
tar -cvpzf $GITHUB_WORKSPACE/build/assets.tar.gz ./frappe-bench/sites/assets/js ./frappe-bench/sites/assets/css
tar -cvpzf $GITHUB_WORKSPACE/build/assets.tar.gz ./frappe-bench/sites/assets/frappe/dist

- name: Get release
id: get_release


+ 1
- 1
.github/workflows/server-mariadb-tests.yml View File

@@ -35,7 +35,7 @@ jobs:

- uses: actions/setup-node@v2
with:
node-version: '14'
node-version: 14
check-latest: true

- name: Add to Hosts


+ 1
- 1
.github/workflows/ui-tests.yml View File

@@ -35,7 +35,7 @@ jobs:

- uses: actions/setup-node@v2
with:
node-version: '12'
node-version: 14
check-latest: true

- name: Add to Hosts


+ 1
- 0
.gitignore View File

@@ -9,6 +9,7 @@ locale
dist/
# build/
frappe/docs/current
frappe/public/dist
.vscode
node_modules
.kdev4/


+ 1
- 1
cypress/integration/recorder.js View File

@@ -50,7 +50,7 @@ context('Recorder', () => {
cy.get('.result-list').should('contain', '/api/method/frappe.desk.reportview.get');
});

it.only('Recorder View Request', () => {
it('Recorder View Request', () => {
cy.get('.primary-action').should('contain', 'Start').click();

cy.visit('/app/List/DocType/List');


+ 486
- 0
esbuild/esbuild.js View File

@@ -0,0 +1,486 @@
/* eslint-disable no-console */
let path = require("path");
let fs = require("fs");
let glob = require("fast-glob");
let esbuild = require("esbuild");
let vue = require("esbuild-vue");
let yargs = require("yargs");
let cliui = require("cliui")();
let chalk = require("chalk");
let html_plugin = require("./frappe-html");
let postCssPlugin = require("esbuild-plugin-postcss2").default;
let ignore_assets = require("./ignore-assets");
let sass_options = require("./sass_options");
let {
app_list,
assets_path,
apps_path,
sites_path,
get_app_path,
get_public_path,
log,
log_warn,
log_error,
bench_path,
get_redis_subscriber
} = require("./utils");

let argv = yargs
.usage("Usage: node esbuild [options]")
.option("apps", {
type: "string",
description: "Run build for specific apps"
})
.option("skip_frappe", {
type: "boolean",
description: "Skip building frappe assets"
})
.option("files", {
type: "string",
description: "Run build for specified bundles"
})
.option("watch", {
type: "boolean",
description: "Run in watch mode and rebuild on file changes"
})
.option("production", {
type: "boolean",
description: "Run build in production mode"
})
.option("run-build-command", {
type: "boolean",
description: "Run build command for apps"
})
.example(
"node esbuild --apps frappe,erpnext",
"Run build only for frappe and erpnext"
)
.example(
"node esbuild --files frappe/website.bundle.js,frappe/desk.bundle.js",
"Run build only for specified bundles"
)
.version(false).argv;

const APPS = (!argv.apps ? app_list : argv.apps.split(",")).filter(
app => !(argv.skip_frappe && app == "frappe")
);
const FILES_TO_BUILD = argv.files ? argv.files.split(",") : [];
const WATCH_MODE = Boolean(argv.watch);
const PRODUCTION = Boolean(argv.production);
const RUN_BUILD_COMMAND = !WATCH_MODE && Boolean(argv["run-build-command"]);

const TOTAL_BUILD_TIME = `${chalk.black.bgGreen(" DONE ")} Total Build Time`;
const NODE_PATHS = [].concat(
// node_modules of apps directly importable
app_list
.map(app => path.resolve(get_app_path(app), "../node_modules"))
.filter(fs.existsSync),
// import js file of any app if you provide the full path
app_list
.map(app => path.resolve(get_app_path(app), ".."))
.filter(fs.existsSync)
);

execute()
.then(() => RUN_BUILD_COMMAND && run_build_command_for_apps(APPS))
.catch(e => console.error(e));

if (WATCH_MODE) {
// listen for open files in editor event
open_in_editor();
}

async function execute() {
console.time(TOTAL_BUILD_TIME);
if (!FILES_TO_BUILD.length) {
await clean_dist_folders(APPS);
}

let result;
try {
result = await build_assets_for_apps(APPS, FILES_TO_BUILD);
} catch (e) {
log_error("There were some problems during build");
log();
log(chalk.dim(e.stack));
return;
}

if (!WATCH_MODE) {
log_built_assets(result.metafile);
console.timeEnd(TOTAL_BUILD_TIME);
log();
} else {
log("Watching for changes...");
}
return await write_assets_json(result.metafile);
}

function build_assets_for_apps(apps, files) {
let { include_patterns, ignore_patterns } = files.length
? get_files_to_build(files)
: get_all_files_to_build(apps);

return glob(include_patterns, { ignore: ignore_patterns }).then(files => {
let output_path = assets_path;

let file_map = {};
for (let file of files) {
let relative_app_path = path.relative(apps_path, file);
let app = relative_app_path.split(path.sep)[0];

let extension = path.extname(file);
let output_name = path.basename(file, extension);
if (
[".css", ".scss", ".less", ".sass", ".styl"].includes(extension)
) {
output_name = path.join("css", output_name);
} else if ([".js", ".ts"].includes(extension)) {
output_name = path.join("js", output_name);
}
output_name = path.join(app, "dist", output_name);

if (Object.keys(file_map).includes(output_name)) {
log_warn(
`Duplicate output file ${output_name} generated from ${file}`
);
}

file_map[output_name] = file;
}

return build_files({
files: file_map,
outdir: output_path
});
});
}

function get_all_files_to_build(apps) {
let include_patterns = [];
let ignore_patterns = [];

for (let app of apps) {
let public_path = get_public_path(app);
include_patterns.push(
path.resolve(
public_path,
"**",
"*.bundle.{js,ts,css,sass,scss,less,styl}"
)
);
ignore_patterns.push(
path.resolve(public_path, "node_modules"),
path.resolve(public_path, "dist")
);
}

return {
include_patterns,
ignore_patterns
};
}

function get_files_to_build(files) {
// files: ['frappe/website.bundle.js', 'erpnext/main.bundle.js']
let include_patterns = [];
let ignore_patterns = [];

for (let file of files) {
let [app, bundle] = file.split("/");
let public_path = get_public_path(app);
include_patterns.push(path.resolve(public_path, "**", bundle));
ignore_patterns.push(
path.resolve(public_path, "node_modules"),
path.resolve(public_path, "dist")
);
}

return {
include_patterns,
ignore_patterns
};
}

function build_files({ files, outdir }) {
return esbuild.build({
entryPoints: files,
entryNames: "[dir]/[name].[hash]",
outdir,
sourcemap: true,
bundle: true,
metafile: true,
minify: PRODUCTION,
nodePaths: NODE_PATHS,
define: {
"process.env.NODE_ENV": JSON.stringify(
PRODUCTION ? "production" : "development"
)
},
plugins: [
html_plugin,
ignore_assets,
vue(),
postCssPlugin({
plugins: [require("autoprefixer")],
sassOptions: sass_options
})
],
watch: get_watch_config()
});
}

function get_watch_config() {
if (WATCH_MODE) {
return {
async onRebuild(error, result) {
if (error) {
log_error("There was an error during rebuilding changes.");
log();
log(chalk.dim(error.stack));
notify_redis({ error });
} else {
let {
assets_json,
prev_assets_json
} = await write_assets_json(result.metafile);
if (prev_assets_json) {
log_rebuilt_assets(prev_assets_json, assets_json);
}
notify_redis({ success: true });
}
}
};
}
return null;
}

async function clean_dist_folders(apps) {
for (let app of apps) {
let public_path = get_public_path(app);
await fs.promises.rmdir(path.resolve(public_path, "dist", "js"), {
recursive: true
});
await fs.promises.rmdir(path.resolve(public_path, "dist", "css"), {
recursive: true
});
}
}

function log_built_assets(metafile) {
let column_widths = [60, 20];
cliui.div(
{
text: chalk.cyan.bold("File"),
width: column_widths[0]
},
{
text: chalk.cyan.bold("Size"),
width: column_widths[1]
}
);
cliui.div("");

let output_by_dist_path = {};
for (let outfile in metafile.outputs) {
if (outfile.endsWith(".map")) continue;
let data = metafile.outputs[outfile];
outfile = path.resolve(outfile);
outfile = path.relative(assets_path, outfile);
let filename = path.basename(outfile);
let dist_path = outfile.replace(filename, "");
output_by_dist_path[dist_path] = output_by_dist_path[dist_path] || [];
output_by_dist_path[dist_path].push({
name: filename,
size: (data.bytes / 1000).toFixed(2) + " Kb"
});
}

for (let dist_path in output_by_dist_path) {
let files = output_by_dist_path[dist_path];
cliui.div({
text: dist_path,
width: column_widths[0]
});

for (let i in files) {
let file = files[i];
let branch = "";
if (i < files.length - 1) {
branch = "├─ ";
} else {
branch = "└─ ";
}
let color = file.name.endsWith(".js") ? "green" : "blue";
cliui.div(
{
text: branch + chalk[color]("" + file.name),
width: column_widths[0]
},
{
text: file.size,
width: column_widths[1]
}
);
}
cliui.div("");
}
log(cliui.toString());
}

// to store previous build's assets.json for comparison
let prev_assets_json;
let curr_assets_json;

async function write_assets_json(metafile) {
prev_assets_json = curr_assets_json;
let out = {};
for (let output in metafile.outputs) {
let info = metafile.outputs[output];
let asset_path = "/" + path.relative(sites_path, output);
if (info.entryPoint) {
out[path.basename(info.entryPoint)] = asset_path;
}
}

let assets_json_path = path.resolve(
assets_path,
"frappe",
"dist",
"assets.json"
);
let assets_json;
try {
assets_json = await fs.promises.readFile(assets_json_path, "utf-8");
} catch (error) {
assets_json = "{}";
}
assets_json = JSON.parse(assets_json);
// update with new values
assets_json = Object.assign({}, assets_json, out);
curr_assets_json = assets_json;

await fs.promises.writeFile(
assets_json_path,
JSON.stringify(assets_json, null, 4)
);
await update_assets_json_in_cache(assets_json);
return {
assets_json,
prev_assets_json
};
}

function update_assets_json_in_cache(assets_json) {
// update assets_json cache in redis, so that it can be read directly by python
return new Promise(resolve => {
let client = get_redis_subscriber("redis_cache");
// handle error event to avoid printing stack traces
client.on("error", _ => {
log_warn("Cannot connect to redis_cache to update assets_json");
});
client.set("assets_json", JSON.stringify(assets_json), err => {
client.unref();
resolve();
});
});
}

function run_build_command_for_apps(apps) {
let cwd = process.cwd();
let { execSync } = require("child_process");

for (let app of apps) {
if (app === "frappe") continue;

let root_app_path = path.resolve(get_app_path(app), "..");
let package_json = path.resolve(root_app_path, "package.json");
if (fs.existsSync(package_json)) {
let { scripts } = require(package_json);
if (scripts && scripts.build) {
log("\nRunning build command for", chalk.bold(app));
process.chdir(root_app_path);
execSync("yarn build", { encoding: "utf8", stdio: "inherit" });
}
}
}

process.chdir(cwd);
}

async function notify_redis({ error, success }) {
// notify redis which in turns tells socketio to publish this to browser
let subscriber = get_redis_subscriber("redis_socketio");
subscriber.on("error", _ => {
log_warn("Cannot connect to redis_socketio for browser events");
});

let payload = null;
if (error) {
let formatted = await esbuild.formatMessages(error.errors, {
kind: "error",
terminalWidth: 100
});
let stack = error.stack.replace(new RegExp(bench_path, "g"), "");
payload = {
error,
formatted,
stack
};
}
if (success) {
payload = {
success: true
};
}

subscriber.publish(
"events",
JSON.stringify({
event: "build_event",
message: payload
})
);
}

function open_in_editor() {
let subscriber = get_redis_subscriber("redis_socketio");
subscriber.on("error", _ => {
log_warn("Cannot connect to redis_socketio for open_in_editor events");
});
subscriber.on("message", (event, file) => {
if (event === "open_in_editor") {
file = JSON.parse(file);
let file_path = path.resolve(file.file);
log("Opening file in editor:", file_path);
let launch = require("launch-editor");
launch(`${file_path}:${file.line}:${file.column}`);
}
});
subscriber.subscribe("open_in_editor");
}

function log_rebuilt_assets(prev_assets, new_assets) {
let added_files = [];
let old_files = Object.values(prev_assets);
let new_files = Object.values(new_assets);

for (let filepath of new_files) {
if (!old_files.includes(filepath)) {
added_files.push(filepath);
}
}

log(
chalk.yellow(
`${new Date().toLocaleTimeString()}: Compiled ${
added_files.length
} files...`
)
);
for (let filepath of added_files) {
let filename = path.basename(filepath);
log(" " + filename);
}
log();
}

+ 43
- 0
esbuild/frappe-html.js View File

@@ -0,0 +1,43 @@
module.exports = {
name: "frappe-html",
setup(build) {
let path = require("path");
let fs = require("fs/promises");

build.onResolve({ filter: /\.html$/ }, args => {
return {
path: path.join(args.resolveDir, args.path),
namespace: "frappe-html"
};
});

build.onLoad({ filter: /.*/, namespace: "frappe-html" }, args => {
let filepath = args.path;
let filename = path.basename(filepath).split(".")[0];

return fs
.readFile(filepath, "utf-8")
.then(content => {
content = scrub_html_template(content);
return {
contents: `\n\tfrappe.templates['${filename}'] = \`${content}\`;\n`
};
})
.catch(() => {
return {
contents: "",
warnings: [
{
text: `There was an error importing ${filepath}`
}
]
};
});
});
}
};

function scrub_html_template(content) {
content = content.replace(/`/g, "\\`");
return content;
}

+ 11
- 0
esbuild/ignore-assets.js View File

@@ -0,0 +1,11 @@
module.exports = {
name: "frappe-ignore-asset",
setup(build) {
build.onResolve({ filter: /^\/assets\// }, args => {
return {
path: args.path,
external: true
};
});
}
};

+ 1
- 0
esbuild/index.js View File

@@ -0,0 +1 @@
require("./esbuild");

+ 29
- 0
esbuild/sass_options.js View File

@@ -0,0 +1,29 @@
let path = require("path");
let { get_app_path, app_list } = require("./utils");

let node_modules_path = path.resolve(
get_app_path("frappe"),
"..",
"node_modules"
);
let app_paths = app_list
.map(get_app_path)
.map(app_path => path.resolve(app_path, ".."));

module.exports = {
includePaths: [node_modules_path, ...app_paths],
importer: function(url) {
if (url.startsWith("~")) {
// strip ~ so that it can resolve from node_modules
url = url.slice(1);
}
if (url.endsWith(".css")) {
// strip .css from end of path
url = url.slice(0, -4);
}
// normal file, let it go
return {
file: url
};
}
};

+ 145
- 0
esbuild/utils.js View File

@@ -0,0 +1,145 @@
const path = require("path");
const fs = require("fs");
const chalk = require("chalk");

const frappe_path = path.resolve(__dirname, "..");
const bench_path = path.resolve(frappe_path, "..", "..");
const sites_path = path.resolve(bench_path, "sites");
const apps_path = path.resolve(bench_path, "apps");
const assets_path = path.resolve(sites_path, "assets");
const app_list = get_apps_list();

const app_paths = app_list.reduce((out, app) => {
out[app] = path.resolve(apps_path, app, app);
return out;
}, {});
const public_paths = app_list.reduce((out, app) => {
out[app] = path.resolve(app_paths[app], "public");
return out;
}, {});
const public_js_paths = app_list.reduce((out, app) => {
out[app] = path.resolve(app_paths[app], "public/js");
return out;
}, {});

const bundle_map = app_list.reduce((out, app) => {
const public_js_path = public_js_paths[app];
if (fs.existsSync(public_js_path)) {
const all_files = fs.readdirSync(public_js_path);
const js_files = all_files.filter(file => file.endsWith(".js"));

for (let js_file of js_files) {
const filename = path.basename(js_file).split(".")[0];
out[path.join(app, "js", filename)] = path.resolve(
public_js_path,
js_file
);
}
}

return out;
}, {});

const get_public_path = app => public_paths[app];

const get_build_json_path = app =>
path.resolve(get_public_path(app), "build.json");

function get_build_json(app) {
try {
return require(get_build_json_path(app));
} catch (e) {
// build.json does not exist
return null;
}
}

function delete_file(path) {
if (fs.existsSync(path)) {
fs.unlinkSync(path);
}
}

function run_serially(tasks) {
let result = Promise.resolve();
tasks.forEach(task => {
if (task) {
result = result.then ? result.then(task) : Promise.resolve();
}
});
return result;
}

const get_app_path = app => app_paths[app];

function get_apps_list() {
return fs
.readFileSync(path.resolve(sites_path, "apps.txt"), {
encoding: "utf-8"
})
.split("\n")
.filter(Boolean);
}

function get_cli_arg(name) {
let args = process.argv.slice(2);
let arg = `--${name}`;
let index = args.indexOf(arg);

let value = null;
if (index != -1) {
value = true;
}
if (value && args[index + 1]) {
value = args[index + 1];
}
return value;
}

function log_error(message, badge = "ERROR") {
badge = chalk.white.bgRed(` ${badge} `);
console.error(`${badge} ${message}`); // eslint-disable-line no-console
}

function log_warn(message, badge = "WARN") {
badge = chalk.black.bgYellowBright(` ${badge} `);
console.warn(`${badge} ${message}`); // eslint-disable-line no-console
}

function log(...args) {
console.log(...args); // eslint-disable-line no-console
}

function get_redis_subscriber(kind) {
// get redis subscriber that aborts after 10 connection attempts
let { get_redis_subscriber: get_redis } = require("../node_utils");
return get_redis(kind, {
retry_strategy: function(options) {
// abort after 10 connection attempts
if (options.attempt > 10) {
return undefined;
}
return Math.min(options.attempt * 100, 2000);
}
});
}

module.exports = {
app_list,
bench_path,
assets_path,
sites_path,
apps_path,
bundle_map,
get_public_path,
get_build_json_path,
get_build_json,
get_app_path,
delete_file,
run_serially,
get_cli_arg,
log,
log_warn,
log_error,
get_redis_subscriber
};

+ 9
- 4
frappe/__init__.py View File

@@ -10,9 +10,16 @@ be used to build database driven apps.

Read the documentation: https://frappeframework.com/docs
"""
import os, warnings

_dev_server = os.environ.get('DEV_SERVER', False)

if _dev_server:
warnings.simplefilter('always', DeprecationWarning)
warnings.simplefilter('always', PendingDeprecationWarning)

from werkzeug.local import Local, release_local
import os, sys, importlib, inspect, json, warnings
import sys, importlib, inspect, json
import typing
from past.builtins import cmp
import click
@@ -31,8 +38,6 @@ __title__ = "Frappe Framework"

local = Local()
controllers = {}
warnings.simplefilter('always', DeprecationWarning)
warnings.simplefilter('always', PendingDeprecationWarning)

class _dict(dict):
"""dict like object that exposes keys as attributes"""
@@ -197,7 +202,7 @@ def init(site, sites_path=None, new_site=False):
local.meta_cache = {}
local.form_dict = _dict()
local.session = _dict()
local.dev_server = os.environ.get('DEV_SERVER', False)
local.dev_server = _dev_server

setup_module_map()



+ 60
- 47
frappe/build.py View File

@@ -5,6 +5,7 @@ import os
import re
import json
import shutil
import subprocess
from tempfile import mkdtemp, mktemp
from distutils.spawn import find_executable

@@ -15,6 +16,7 @@ import click
import psutil
from urllib.parse import urlparse
from simple_chalk import green
from semantic_version import Version


timestamps = {}
@@ -36,35 +38,36 @@ def download_file(url, prefix):


def build_missing_files():
# check which files dont exist yet from the build.json and tell build.js to build only those!
'''Check which files dont exist yet from the assets.json and run build for those files'''

missing_assets = []
current_asset_files = []
frappe_build = os.path.join("..", "apps", "frappe", "frappe", "public", "build.json")

for type in ["css", "js"]:
current_asset_files.extend(
[
"{0}/{1}".format(type, name)
for name in os.listdir(os.path.join(sites_path, "assets", type))
]
)
folder = os.path.join(sites_path, "assets", "frappe", "dist", type)
current_asset_files.extend(os.listdir(folder))

with open(frappe_build) as f:
all_asset_files = json.load(f).keys()
development = frappe.local.conf.developer_mode or frappe.local.dev_server
build_mode = "development" if development else "production"

for asset in all_asset_files:
if asset.replace("concat:", "") not in current_asset_files:
missing_assets.append(asset)
assets_json = frappe.read_file(frappe.get_app_path('frappe', 'public', 'dist', 'assets.json'))
if assets_json:
assets_json = frappe.parse_json(assets_json)

if missing_assets:
from subprocess import check_call
from shlex import split
for bundle_file, output_file in assets_json.items():
if not output_file.startswith('/assets/frappe'):
continue

click.secho("\nBuilding missing assets...\n", fg="yellow")
command = split(
"node rollup/build.js --files {0} --no-concat".format(",".join(missing_assets))
)
check_call(command, cwd=os.path.join("..", "apps", "frappe"))
if os.path.basename(output_file) not in current_asset_files:
missing_assets.append(bundle_file)

if missing_assets:
click.secho("\nBuilding missing assets...\n", fg="yellow")
files_to_build = ["frappe/" + name for name in missing_assets]
bundle(build_mode, files=files_to_build)
else:
# no assets.json, run full build
bundle(build_mode, apps="frappe")


def get_assets_link(frappe_head):
@@ -200,49 +203,51 @@ def setup():
assets_path = os.path.join(frappe.local.sites_path, "assets")


def get_node_pacman():
exec_ = find_executable("yarn")
if exec_:
return exec_
raise ValueError("Yarn not found")


def bundle(no_compress, app=None, hard_link=False, verbose=False, skip_frappe=False):
def bundle(mode, apps=None, hard_link=False, make_copy=False, restore=False, verbose=False, skip_frappe=False, files=None):
"""concat / minify js files"""
setup()
make_asset_dirs(hard_link=hard_link)

pacman = get_node_pacman()
mode = "build" if no_compress else "production"
command = "{pacman} run {mode}".format(pacman=pacman, mode=mode)
mode = "production" if mode == "production" else "build"
command = "yarn run {mode}".format(mode=mode)

if app:
command += " --app {app}".format(app=app)
if apps:
command += " --apps {apps}".format(apps=apps)

if skip_frappe:
command += " --skip_frappe"

frappe_app_path = os.path.abspath(os.path.join(app_paths[0], ".."))
check_yarn()
if files:
command += " --files {files}".format(files=','.join(files))

command += " --run-build-command"

check_node_executable()
frappe_app_path = frappe.get_app_path("frappe", "..")
frappe.commands.popen(command, cwd=frappe_app_path, env=get_node_env())


def watch(no_compress):
def watch(apps=None):
"""watch and rebuild if necessary"""
setup()

pacman = get_node_pacman()
command = "yarn run watch"
if apps:
command += " --apps {apps}".format(apps=apps)

frappe_app_path = os.path.abspath(os.path.join(app_paths[0], ".."))
check_yarn()
check_node_executable()
frappe_app_path = frappe.get_app_path("frappe", "..")
frappe.commands.popen("{pacman} run watch".format(pacman=pacman),
cwd=frappe_app_path, env=get_node_env())
frappe.commands.popen(command, cwd=frappe_app_path, env=get_node_env())


def check_yarn():
def check_node_executable():
node_version = Version(subprocess.getoutput('node -v')[1:])
warn = '⚠️ '
if node_version.major < 14:
click.echo(f"{warn} Please update your node version to 14")
if not find_executable("yarn"):
print("Please install yarn using below command and try again.\nnpm install -g yarn")
click.echo(f"{warn} Please install yarn using below command and try again.\nnpm install -g yarn")
click.echo()

def get_node_env():
node_env = {
@@ -312,13 +317,20 @@ def clear_broken_symlinks():



def unstrip(message):
def unstrip(message: str) -> str:
"""Pads input string on the right side until the last available column in the terminal
"""
_len = len(message)
try:
max_str = os.get_terminal_size().columns
except Exception:
max_str = 80
_len = len(message)
_rem = max_str - _len

if _len < max_str:
_rem = max_str - _len
else:
_rem = max_str % _len

return f"{message}{' ' * _rem}"


@@ -331,6 +343,7 @@ def make_asset_dirs(hard_link=False):
start_message = unstrip(f"{'Copying assets from' if hard_link else 'Linking'} {source} to {target}")
fail_message = unstrip(f"Cannot {'copy' if hard_link else 'link'} {source} to {target}")

# Used '\r' instead of '\x1b[1K\r' to print entire lines in smaller terminal sizes
try:
print(start_message, end="\r")
link_assets_dir(source, target, hard_link=hard_link)


+ 3
- 0
frappe/cache_manager.py View File

@@ -13,6 +13,8 @@ common_default_keys = ["__default", "__global"]
doctype_map_keys = ('energy_point_rule_map', 'assignment_rule_map',
'milestone_tracker_map', 'event_consumer_document_type_map')

bench_cache_keys = ('assets_json',)

global_cache_keys = ("app_hooks", "installed_apps", 'all_apps',
"app_modules", "module_app", "system_settings",
'scheduler_events', 'time_zone', 'webhooks', 'active_domains',
@@ -58,6 +60,7 @@ def clear_global_cache():
clear_doctype_cache()
clear_website_cache()
frappe.cache().delete_value(global_cache_keys)
frappe.cache().delete_value(bench_cache_keys)
frappe.setup_module_map()

def clear_defaults_cache(user=None):


+ 23
- 20
frappe/commands/utils.py View File

@@ -16,24 +16,34 @@ from frappe.utils import get_bench_path, update_progress_bar, cint

@click.command('build')
@click.option('--app', help='Build assets for app')
@click.option('--apps', help='Build assets for specific apps')
@click.option('--hard-link', is_flag=True, default=False, help='Copy the files instead of symlinking')
@click.option('--make-copy', is_flag=True, default=False, help='[DEPRECATED] Copy the files instead of symlinking')
@click.option('--restore', is_flag=True, default=False, help='[DEPRECATED] Copy the files instead of symlinking with force')
@click.option('--production', is_flag=True, default=False, help='Build assets in production mode')
@click.option('--verbose', is_flag=True, default=False, help='Verbose')
@click.option('--force', is_flag=True, default=False, help='Force build assets instead of downloading available')
def build(app=None, hard_link=False, make_copy=False, restore=False, verbose=False, force=False):
"Minify + concatenate JS and CSS files, build translations"
def build(app=None, apps=None, hard_link=False, make_copy=False, restore=False, production=False, verbose=False, force=False):
"Compile JS and CSS source files"
from frappe.build import bundle, download_frappe_assets
frappe.init('')
# don't minify in developer_mode for faster builds
no_compress = frappe.local.conf.developer_mode or False

if not apps and app:
apps = app

# dont try downloading assets if force used, app specified or running via CI
if not (force or app or os.environ.get('CI')):
if not (force or apps or os.environ.get('CI')):
# skip building frappe if assets exist remotely
skip_frappe = frappe.build.download_frappe_assets(verbose=verbose)
skip_frappe = download_frappe_assets(verbose=verbose)
else:
skip_frappe = False

# don't minify in developer_mode for faster builds
development = frappe.local.conf.developer_mode or frappe.local.dev_server
mode = "development" if development else "production"
if production:
mode = "production"

if make_copy or restore:
hard_link = make_copy or restore
click.secho(
@@ -41,21 +51,17 @@ def build(app=None, hard_link=False, make_copy=False, restore=False, verbose=Fal
fg="yellow",
)

frappe.build.bundle(
skip_frappe=skip_frappe,
no_compress=no_compress,
hard_link=hard_link,
verbose=verbose,
app=app,
)
bundle(mode, apps=apps, hard_link=hard_link, verbose=verbose, skip_frappe=skip_frappe)



@click.command('watch')
def watch():
"Watch and concatenate JS and CSS files as and when they change"
import frappe.build
@click.option('--apps', help='Watch assets for specific apps')
def watch(apps=None):
"Watch and compile JS and CSS files as and when they change"
from frappe.build import watch
frappe.init('')
frappe.build.watch(True)
watch(apps)


@click.command('clear-cache')
@@ -501,8 +507,6 @@ frappe.db.connect()
@pass_context
def console(context):
"Start ipython console for a site"
import warnings

site = get_site(context)
frappe.init(site=site)
frappe.connect()
@@ -523,7 +527,6 @@ def console(context):
if failed_to_import:
print("\nFailed to import:\n{}".format(", ".join(failed_to_import)))

warnings.simplefilter('ignore')
IPython.embed(display_banner="", header="", colors="neutral")




+ 2
- 2
frappe/core/doctype/data_import/data_import.js View File

@@ -203,7 +203,7 @@ frappe.ui.form.on('Data Import', {
},

download_template(frm) {
frappe.require('/assets/js/data_import_tools.min.js', () => {
frappe.require('data_import_tools.bundle.js', () => {
frm.data_exporter = new frappe.data_import.DataExporter(
frm.doc.reference_doctype,
frm.doc.import_type
@@ -287,7 +287,7 @@ frappe.ui.form.on('Data Import', {
return;
}

frappe.require('/assets/js/data_import_tools.min.js', () => {
frappe.require('data_import_tools.bundle.js', () => {
frm.import_preview = new frappe.data_import.ImportPreview({
wrapper: frm.get_field('import_preview').$wrapper,
doctype: frm.doc.reference_doctype,


+ 1
- 1
frappe/core/page/recorder/recorder.js View File

@@ -11,7 +11,7 @@ frappe.pages['recorder'].on_page_load = function(wrapper) {
frappe.recorder.show();
});

frappe.require('/assets/js/frappe-recorder.min.js');
frappe.require('recorder.bundle.js');
};

class Recorder {


+ 8
- 7
frappe/desk/page/activity/activity.js View File

@@ -67,8 +67,8 @@ frappe.pages['activity'].on_page_show = function () {
}

frappe.activity.last_feed_date = false;
frappe.activity.Feed = Class.extend({
init: function (row, data) {
frappe.activity.Feed = class Feed {
constructor(row, data) {
this.scrub_data(data);
this.add_date_separator(row, data);
if (!data.add_class)
@@ -97,8 +97,9 @@ frappe.activity.Feed = Class.extend({
$(row)
.append(frappe.render_template("activity_row", data))
.find("a").addClass("grey");
},
scrub_data: function (data) {
}

scrub_data(data) {
data.by = frappe.user.full_name(data.owner);
data.avatar = frappe.avatar(data.owner);

@@ -113,9 +114,9 @@ frappe.activity.Feed = Class.extend({

data.when = comment_when(data.creation);
data.feed_type = data.comment_type || data.communication_medium;
},
}

add_date_separator: function (row, data) {
add_date_separator(row, data) {
var date = frappe.datetime.str_to_obj(data.creation);
var last = frappe.activity.last_feed_date;

@@ -137,7 +138,7 @@ frappe.activity.Feed = Class.extend({
}
frappe.activity.last_feed_date = date;
}
});
};

frappe.activity.render_heatmap = function (page) {
$('<div class="heatmap-container" style="text-align:center">\


+ 5
- 11
frappe/email/email_body.py View File

@@ -292,18 +292,12 @@ def inline_style_in_html(html):
''' Convert email.css and html to inline-styled html
'''
from premailer import Premailer
from frappe.utils.jinja_globals import bundled_asset

apps = frappe.get_installed_apps()

# add frappe email css file
css_files = ['assets/css/email.css']
if 'frappe' in apps:
apps.remove('frappe')

for app in apps:
path = 'assets/{0}/css/email.css'.format(app)
css_files.append(path)

# get email css files from hooks
css_files = frappe.get_hooks('email_css')
css_files = [bundled_asset(path) for path in css_files]
css_files = [path.lstrip('/') for path in css_files]
css_files = [css_file for css_file in css_files if os.path.exists(os.path.abspath(css_file))]

p = Premailer(html=html, external_styles=css_files, strip_important=False)


+ 10
- 8
frappe/hooks.py View File

@@ -29,16 +29,16 @@ page_js = {

# website
app_include_js = [
"/assets/js/libs.min.js",
"/assets/js/desk.min.js",
"/assets/js/list.min.js",
"/assets/js/form.min.js",
"/assets/js/control.min.js",
"/assets/js/report.min.js",
"libs.bundle.js",
"desk.bundle.js",
"list.bundle.js",
"form.bundle.js",
"controls.bundle.js",
"report.bundle.js",
]
app_include_css = [
"/assets/css/desk.min.css",
"/assets/css/report.min.css",
"desk.bundle.css",
"report.bundle.css",
]

doctype_js = {
@@ -52,6 +52,8 @@ web_include_js = [

web_include_css = []

email_css = ['email.bundle.css']

website_route_rules = [
{"from_route": "/blog/<category>", "to_route": "Blog Post"},
{"from_route": "/kb/<category>", "to_route": "Help Article"},


+ 5
- 2
frappe/printing/page/print/print.js View File

@@ -408,14 +408,17 @@ frappe.ui.form.PrintView = class {

setup_print_format_dom(out, $print_format) {
this.print_wrapper.find('.print-format-skeleton').remove();
let base_url = frappe.urllib.get_base_url();
let print_css = frappe.assets.bundled_asset('print.bundle.css');
this.$print_format_body.find('head').html(
`<style type="text/css">${out.style}</style>
<link href="${frappe.urllib.get_base_url()}/assets/css/printview.css" rel="stylesheet">`
<link href="${base_url}${print_css}" rel="stylesheet">`
);

if (frappe.utils.is_rtl(this.lang_code)) {
let rtl_css = frappe.assets.bundled_asset('frappe-rtl.bundle.css');
this.$print_format_body.find('head').append(
`<link type="text/css" rel="stylesheet" href="${frappe.urllib.get_base_url()}/assets/css/frappe-rtl.css"></link>`
`<link type="text/css" rel="stylesheet" href="${base_url}${rtl_css}"></link>`
);
}



+ 64
- 64
frappe/printing/page/print_format_builder/print_format_builder.js View File

@@ -23,13 +23,13 @@ frappe.pages['print-format-builder'].on_page_show = function(wrapper) {
}
}

frappe.PrintFormatBuilder = Class.extend({
init: function(parent) {
frappe.PrintFormatBuilder = class PrintFormatBuilder {
constructor(parent) {
this.parent = parent;
this.make();
this.refresh();
},
refresh: function() {
}
refresh() {
this.custom_html_count = 0;
if(!this.print_format) {
this.show_start();
@@ -37,8 +37,8 @@ frappe.PrintFormatBuilder = Class.extend({
this.page.set_title(this.print_format.name);
this.setup_print_format();
}
},
make: function() {
}
make() {
this.page = frappe.ui.make_app_page({
parent: this.parent,
title: __("Print Format Builder"),
@@ -56,15 +56,15 @@ frappe.PrintFormatBuilder = Class.extend({
this.setup_edit_custom_html();
// $(this.page.sidebar).css({"position": 'fixed'});
// $(this.page.main).parent().css({"margin-left": '16.67%'});
},
show_start: function() {
}
show_start() {
this.page.main.html(frappe.render_template("print_format_builder_start", {}));
this.page.clear_actions();
this.page.set_title(__("Print Format Builder"));
this.start_edit_print_format();
this.start_new_print_format();
},
start_edit_print_format: function() {
}
start_edit_print_format() {
// print format control
var me = this;
this.print_format_input = frappe.ui.form.make_control({
@@ -89,8 +89,8 @@ frappe.PrintFormatBuilder = Class.extend({
frappe.set_route('print-format-builder', name);
});
});
},
start_new_print_format: function() {
}
start_new_print_format() {
var me = this;
this.doctype_input = frappe.ui.form.make_control({
parent: this.page.main.find(".doctype-selector"),
@@ -125,8 +125,8 @@ frappe.PrintFormatBuilder = Class.extend({
me.setup_new_print_format(doctype, name);

});
},
setup_new_print_format: function(doctype, name, based_on) {
}
setup_new_print_format(doctype, name, based_on) {
frappe.call({
method: 'frappe.printing.page.print_format_builder.print_format_builder.create_custom_format',
args: {
@@ -143,8 +143,8 @@ frappe.PrintFormatBuilder = Class.extend({
}
},
});
},
setup_print_format: function() {
}
setup_print_format() {
var me = this;
frappe.model.with_doctype(this.print_format.doc_type, function(doctype) {
me.meta = frappe.get_meta(me.print_format.doc_type);
@@ -163,23 +163,23 @@ frappe.PrintFormatBuilder = Class.extend({
frappe.set_route("Form", "Print Format", me.print_format.name);
});
});
},
setup_sidebar: function() {
}
setup_sidebar() {
// prepend custom HTML field
var fields = [this.get_custom_html_field()].concat(this.meta.fields);
this.page.sidebar.html(
$(frappe.render_template("print_format_builder_sidebar", {fields: fields}))
);
this.setup_field_filter();
},
get_custom_html_field: function() {
}
get_custom_html_field() {
return {
fieldtype: "Custom HTML",
fieldname: "_custom_html",
label: __("Custom HTML")
}
},
render_layout: function() {
};
}
render_layout() {
this.page.main.empty();
this.prepare_data();
$(frappe.render_template("print_format_builder_layout", {
@@ -190,8 +190,8 @@ frappe.PrintFormatBuilder = Class.extend({
this.setup_edit_heading();
this.setup_field_settings();
this.setup_html_data();
},
prepare_data: function() {
}
prepare_data() {
this.print_heading_template = null;
this.data = JSON.parse(this.print_format.format_data || "[]");
if(!this.data.length) {
@@ -280,22 +280,22 @@ frappe.PrintFormatBuilder = Class.extend({
this.layout_data = $.map(this.layout_data, function(s) {
return s.has_fields ? s : null
});
},
get_new_section: function() {
}
get_new_section() {
return {columns: [], no_of_columns: 0, label:''};
},
get_new_column: function() {
}
get_new_column() {
return {fields: []}
},
add_table_properties: function(f) {
}
add_table_properties(f) {
// build table columns and widths in a dict
// visible_columns
var me = this;
if(!f.visible_columns) {
me.init_visible_columns(f);
}
},
init_visible_columns: function(f) {
}
init_visible_columns(f) {
f.visible_columns = []
$.each(frappe.get_meta(f.options).fields, function(i, _f) {
if(!in_list(["Section Break", "Column Break"], _f.fieldtype) &&
@@ -306,8 +306,8 @@ frappe.PrintFormatBuilder = Class.extend({
print_width: (_f.width || ""), print_hide:0});
}
});
},
setup_sortable: function() {
}
setup_sortable() {
var me = this;

// drag from fields library
@@ -332,8 +332,8 @@ frappe.PrintFormatBuilder = Class.extend({
Sortable.create(this.page.main.find(".print-format-builder-layout").get(0),
{ handle: ".print-format-builder-section-head" }
);
},
setup_sortable_for_column: function(col) {
}
setup_sortable_for_column(col) {
var me = this;
Sortable.create(col, {
group: {
@@ -363,8 +363,8 @@ frappe.PrintFormatBuilder = Class.extend({
}
});

},
setup_field_filter: function() {
}
setup_field_filter() {
var me = this;
this.page.sidebar.find(".filter-fields").on("keyup", function() {
var text = $(this).val();
@@ -373,8 +373,8 @@ frappe.PrintFormatBuilder = Class.extend({
$(this).parent().toggle(show);
})
});
},
setup_section_settings: function() {
}
setup_section_settings() {
var me = this;
this.page.main.on("click", ".section-settings", function() {
var section = $(this).parent().parent();
@@ -431,8 +431,8 @@ frappe.PrintFormatBuilder = Class.extend({

return false;
});
},
setup_field_settings: function() {
}
setup_field_settings() {
this.page.main.find(".field-settings").on("click", e => {
const field = $(e.currentTarget).parent();
// new dialog
@@ -482,8 +482,8 @@ frappe.PrintFormatBuilder = Class.extend({

return false;
});
},
setup_html_data: function() {
}
setup_html_data() {
// set JQuery `data` for Custom HTML fields, since editing the HTML
// directly causes problem becuase of HTML reformatting
//
@@ -496,8 +496,8 @@ frappe.PrintFormatBuilder = Class.extend({
var html = me.custom_html_dict[parseInt(content.attr('data-custom-html-id'))].options;
content.data('content', html);
})
},
update_columns_in_section: function(section, no_of_columns, new_no_of_columns) {
}
update_columns_in_section(section, no_of_columns, new_no_of_columns) {
var col_size = 12 / new_no_of_columns,
me = this,
resize = function() {
@@ -539,8 +539,8 @@ frappe.PrintFormatBuilder = Class.extend({
resize();
}

},
setup_add_section: function() {
}
setup_add_section() {
var me = this;
this.page.main.find(".print-format-builder-add-section").on("click", function() {
// boostrap new section info
@@ -554,8 +554,8 @@ frappe.PrintFormatBuilder = Class.extend({

me.setup_sortable_for_column($section.find(".print-format-builder-column").get(0));
});
},
setup_edit_heading: function() {
}
setup_edit_heading() {
var me = this;
var $heading = this.page.main.find(".print-format-builder-print-heading");

@@ -565,8 +565,8 @@ frappe.PrintFormatBuilder = Class.extend({
this.page.main.find(".edit-heading").on("click", function() {
var d = me.get_edit_html_dialog(__("Edit Heading"), __("Heading"), $heading);
})
},
setup_column_selector: function() {
}
setup_column_selector() {
var me = this;
this.page.main.on("click", ".select-columns", function() {
var parent = $(this).parents(".print-format-builder-field:first"),
@@ -657,24 +657,24 @@ frappe.PrintFormatBuilder = Class.extend({

return false;
});
},
get_visible_columns_string: function(f) {
}
get_visible_columns_string(f) {
if(!f.visible_columns) {
this.init_visible_columns(f);
}
return $.map(f.visible_columns, function(v) { return v.fieldname + "|" + (v.print_width || "") }).join(",");
},
get_no_content: function() {
}
get_no_content() {
return __("Edit to add content")
},
setup_edit_custom_html: function() {
}
setup_edit_custom_html() {
var me = this;
this.page.main.on("click", ".edit-html", function() {
me.get_edit_html_dialog(__("Edit Custom HTML"), __("Custom HTML"),
$(this).parents(".print-format-builder-field:first").find(".html-content"));
});
},
get_edit_html_dialog: function(title, label, $content) {
}
get_edit_html_dialog(title, label, $content) {
var me = this;
var d = new frappe.ui.Dialog({
title: title,
@@ -710,8 +710,8 @@ frappe.PrintFormatBuilder = Class.extend({
d.show();

return d;
},
save_print_format: function() {
}
save_print_format() {
var data = [],
me = this;

@@ -789,4 +789,4 @@ frappe.PrintFormatBuilder = Class.extend({
}
});
}
});
};

+ 1
- 1
frappe/public/html/print_template.html View File

@@ -7,7 +7,7 @@
<meta name="description" content="">
<meta name="author" content="">
<title>{{ title }}</title>
<link href="{{ base_url }}/assets/css/printview.css" rel="stylesheet">
<link href="{{ base_url }}{{ frappe.assets.bundled_asset('print.bundle.css') }}" rel="stylesheet">
<style>
{{ print_css }}
</style>


+ 1
- 0
frappe/public/js/barcode_scanner.bundle.js View File

@@ -0,0 +1 @@
import "./frappe/barcode_scanner/quagga";

+ 64
- 0
frappe/public/js/bootstrap-4-web.bundle.js View File

@@ -0,0 +1,64 @@

// multilevel dropdown
$('.dropdown-menu a.dropdown-toggle').on('click', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
if (!$(this).next().hasClass('show')) {
$(this).parents('.dropdown-menu').first().find('.show').removeClass("show");
}
var $subMenu = $(this).next(".dropdown-menu");
$subMenu.toggleClass('show');


$(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function () {
$('.dropdown-submenu .show').removeClass("show");
});

return false;
});

frappe.get_modal = function (title, content) {
return $(
`<div class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">${title}</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
${frappe.utils.icon('close-alt', 'sm', 'close-alt')}
</button>
</div>
<div class="modal-body">
${content}
</div>
<div class="modal-footer hidden">
<button type="button" class="btn btn-default btn-sm btn-modal-close" data-dismiss="modal">
<i class="octicon octicon-x visible-xs" style="padding: 1px 0px;"></i>
<span class="hidden-xs">${__("Close")}</span>
</button>
<button type="button" class="btn btn-sm btn-primary hidden"></button>
</div>
</div>
</div>
</div>`
);
};

frappe.ui.Dialog = class Dialog extends frappe.ui.Dialog {
get_primary_btn() {
return this.$wrapper.find(".modal-footer .btn-primary");
}

set_primary_action(label, click) {
this.$wrapper.find('.modal-footer').removeClass('hidden');
return super.set_primary_action(label, click)
.removeClass('hidden');
}

make() {
super.make();
if (this.fields) {
this.$wrapper.find('.section-body').addClass('w-100');
}
}
};

+ 1
- 0
frappe/public/js/chat.bundle.js View File

@@ -0,0 +1 @@
import "./frappe/chat";

+ 1
- 0
frappe/public/js/checkout.bundle.js View File

@@ -0,0 +1 @@
import "./integrations/razorpay";

+ 18
- 0
frappe/public/js/controls.bundle.js View File

@@ -0,0 +1,18 @@
import "air-datepicker/dist/js/datepicker.min.js";
import "air-datepicker/dist/js/i18n/datepicker.cs.js";
import "air-datepicker/dist/js/i18n/datepicker.da.js";
import "air-datepicker/dist/js/i18n/datepicker.de.js";
import "air-datepicker/dist/js/i18n/datepicker.en.js";
import "air-datepicker/dist/js/i18n/datepicker.es.js";
import "air-datepicker/dist/js/i18n/datepicker.fi.js";
import "air-datepicker/dist/js/i18n/datepicker.fr.js";
import "air-datepicker/dist/js/i18n/datepicker.hu.js";
import "air-datepicker/dist/js/i18n/datepicker.nl.js";
import "air-datepicker/dist/js/i18n/datepicker.pl.js";
import "air-datepicker/dist/js/i18n/datepicker.pt-BR.js";
import "air-datepicker/dist/js/i18n/datepicker.pt.js";
import "air-datepicker/dist/js/i18n/datepicker.ro.js";
import "air-datepicker/dist/js/i18n/datepicker.sk.js";
import "air-datepicker/dist/js/i18n/datepicker.zh.js";
import "./frappe/ui/capture.js";
import "./frappe/form/controls/control.js";

+ 1
- 0
frappe/public/js/data_import_tools.bundle.js View File

@@ -0,0 +1 @@
import "./frappe/data_import";

+ 105
- 0
frappe/public/js/desk.bundle.js View File

@@ -0,0 +1,105 @@
import "./frappe/translate.js";
import "./frappe/class.js";
import "./frappe/polyfill.js";
import "./frappe/provide.js";
import "./frappe/assets.js";
import "./frappe/format.js";
import "./frappe/form/formatters.js";
import "./frappe/dom.js";
import "./frappe/ui/messages.js";
import "./frappe/ui/keyboard.js";
import "./frappe/ui/colors.js";
import "./frappe/ui/sidebar.js";
import "./frappe/ui/link_preview.js";

import "./frappe/request.js";
import "./frappe/socketio_client.js";
import "./frappe/utils/utils.js";
import "./frappe/event_emitter.js";
import "./frappe/router.js";
import "./frappe/router_history.js";
import "./frappe/defaults.js";
import "./frappe/roles_editor.js";
import "./frappe/module_editor.js";
import "./frappe/microtemplate.js";

import "./frappe/ui/page.html";
import "./frappe/ui/page.js";
import "./frappe/ui/slides.js";
// import "./frappe/ui/onboarding_dialog.js";
import "./frappe/ui/find.js";
import "./frappe/ui/iconbar.js";
import "./frappe/form/layout.js";
import "./frappe/ui/field_group.js";
import "./frappe/form/link_selector.js";
import "./frappe/form/multi_select_dialog.js";
import "./frappe/ui/dialog.js";
import "./frappe/ui/capture.js";
import "./frappe/ui/app_icon.js";
import "./frappe/ui/theme_switcher.js";

import "./frappe/model/model.js";
import "./frappe/db.js";
import "./frappe/model/meta.js";
import "./frappe/model/sync.js";
import "./frappe/model/create_new.js";
import "./frappe/model/perm.js";
import "./frappe/model/workflow.js";
import "./frappe/model/user_settings.js";

import "./frappe/utils/user.js";
import "./frappe/utils/common.js";
import "./frappe/utils/urllib.js";
import "./frappe/utils/pretty_date.js";
import "./frappe/utils/tools.js";
import "./frappe/utils/datetime.js";
import "./frappe/utils/number_format.js";
import "./frappe/utils/help.js";
import "./frappe/utils/help_links.js";
import "./frappe/utils/address_and_contact.js";
import "./frappe/utils/preview_email.js";
import "./frappe/utils/file_manager.js";

import "./frappe/upload.js";
import "./frappe/ui/tree.js";

import "./frappe/views/container.js";
import "./frappe/views/breadcrumbs.js";
import "./frappe/views/factory.js";
import "./frappe/views/pageview.js";

import "./frappe/ui/toolbar/awesome_bar.js";
// import "./frappe/ui/toolbar/energy_points_notifications.js";
import "./frappe/ui/notifications/notifications.js";
import "./frappe/ui/toolbar/search.js";
import "./frappe/ui/toolbar/tag_utils.js";
import "./frappe/ui/toolbar/search.html";
import "./frappe/ui/toolbar/search_utils.js";
import "./frappe/ui/toolbar/about.js";
import "./frappe/ui/toolbar/navbar.html";
import "./frappe/ui/toolbar/toolbar.js";
// import "./frappe/ui/toolbar/notifications.js";
import "./frappe/views/communication.js";
import "./frappe/views/translation_manager.js";
import "./frappe/views/workspace/workspace.js";

import "./frappe/widgets/widget_group.js";

import "./frappe/ui/sort_selector.html";
import "./frappe/ui/sort_selector.js";

import "./frappe/change_log.html";
import "./frappe/ui/workspace_loading_skeleton.html";
import "./frappe/desk.js";
import "./frappe/query_string.js";

// import "./frappe/ui/comment.js";

import "./frappe/chat.js";
import "./frappe/utils/energy_point_utils.js";
import "./frappe/utils/dashboard_utils.js";
import "./frappe/ui/chart.js";
import "./frappe/ui/datatable.js";
import "./frappe/ui/driver.js";
import "./frappe/ui/plyr.js";
import "./frappe/barcode_scanner/index.js";

+ 7
- 0
frappe/public/js/dialog.bundle.js View File

@@ -0,0 +1,7 @@
import "./frappe/dom.js";
import "./frappe/form/formatters.js";
import "./frappe/form/layout.js";
import "./frappe/ui/field_group.js";
import "./frappe/form/link_selector.js";
import "./frappe/form/multi_select_dialog.js";
import "./frappe/ui/dialog.js";

+ 17
- 0
frappe/public/js/form.bundle.js View File

@@ -0,0 +1,17 @@
import "./frappe/form/templates/address_list.html";
import "./frappe/form/templates/contact_list.html";
import "./frappe/form/templates/form_dashboard.html";
import "./frappe/form/templates/form_footer.html";
import "./frappe/form/templates/form_links.html";
import "./frappe/form/templates/form_sidebar.html";
import "./frappe/form/templates/print_layout.html";
import "./frappe/form/templates/report_links.html";
import "./frappe/form/templates/set_sharing.html";
import "./frappe/form/templates/timeline_message_box.html";
import "./frappe/form/templates/users_in_sidebar.html";

import "./frappe/form/controls/control.js";
import "./frappe/views/formview.js";
import "./frappe/form/form.js";
import "./frappe/meta_tag.js";


+ 26
- 0
frappe/public/js/frappe-web.bundle.js View File

@@ -0,0 +1,26 @@
import "./jquery-bootstrap";
import "./frappe/class.js";
import "./frappe/polyfill.js";
import "./lib/md5.min.js";
import "./frappe/provide.js";
import "./frappe/format.js";
import "./frappe/utils/number_format.js";
import "./frappe/utils/utils.js";
import "./frappe/utils/common.js";
import "./frappe/ui/messages.js";
import "./frappe/translate.js";
import "./frappe/utils/pretty_date.js";
import "./frappe/microtemplate.js";
import "./frappe/query_string.js";

import "./frappe/upload.js";

import "./frappe/model/meta.js";
import "./frappe/model/model.js";
import "./frappe/model/perm.js";

import "./bootstrap-4-web.bundle";


import "../../website/js/website.js";
import "./frappe/socketio_client.js";

+ 15
- 1
frappe/public/js/frappe/assets.js View File

@@ -9,7 +9,14 @@ frappe.require = function(items, callback) {
if(typeof items === "string") {
items = [items];
}
frappe.assets.execute(items, callback);
items = items.map(item => frappe.assets.bundled_asset(item));

return new Promise(resolve => {
frappe.assets.execute(items, () => {
resolve();
callback && callback();
});
});
};

frappe.assets = {
@@ -160,4 +167,11 @@ frappe.assets = {
frappe.dom.set_style(txt);
}
},

bundled_asset(path) {
if (!path.startsWith('/assets') && path.includes('.bundle.')) {
return frappe.boot.assets_json[path] || path;
}
return path;
}
};

+ 1
- 1
frappe/public/js/frappe/barcode_scanner/index.js View File

@@ -13,7 +13,7 @@ frappe.barcode.scan_barcode = function() {
}
}, reject);
} else {
frappe.require('/assets/js/barcode_scanner.min.js', () => {
frappe.require('barcode_scanner.bundle.js', () => {
frappe.barcode.get_barcode().then(barcode => {
resolve(barcode);
});


+ 111
- 0
frappe/public/js/frappe/build_events/BuildError.vue View File

@@ -0,0 +1,111 @@
<template>
<div class="build-error-overlay" @click.self="data = null" v-show="data">
<div class="window" v-if="data">
<div v-for="(error, i) in data.formatted" :key="i">
<!-- prettier-ignore -->
<pre class="frame"><component :is="error_component(error, i)" /></pre>
</div>
<pre class="stack">{{ data.stack }}</pre>
</div>
</div>
</template>
<script>
export default {
name: "BuildError",
data() {
return {
data: null
};
},
methods: {
show(data) {
this.data = data;
},
hide() {
this.data = null;
},
open_in_editor(location) {
frappe.socketio.socket.emit("open_in_editor", location);
},
error_component(error, i) {
let location = this.data.error.errors[i].location;
let location_string = `${location.file}:${location.line}:${
location.column
}`;
let template = error.replace(
" > " + location_string,
` &gt; <a class="file-link" @click="open">${location_string}</a>`
);

return {
template: `<div>${template}</div>`,
methods: {
open() {
frappe.socketio.socket.emit("open_in_editor", location);
}
}
};
}
}
};
</script>
<style>
.build-error-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9999;
margin: 0;
background: rgba(0, 0, 0, 0.66);
--monospace: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier,
monospace;
--dim: var(--gray-400);
}
.window {
font-family: var(--monospace);
line-height: 1.5;
width: 800px;
color: #d8d8d8;
margin: 30px auto;
padding: 25px 40px;
position: relative;
background: #181818;
border-radius: 6px 6px 8px 8px;
box-shadow: 0 19px 38px rgba(0, 0, 0, 0.3), 0 15px 12px rgba(0, 0, 0, 0.22);
overflow: hidden;
border-top: 8px solid var(--red);
}

pre {
font-family: var(--monospace);
font-size: 13px;
margin-top: 0;
margin-bottom: 1em;
overflow-x: auto;
scrollbar-width: none;
}
code {
font-size: 13px;
font-family: var(--monospace);
color: var(--yellow);
}

.message {
line-height: 1.3;
font-weight: 600;
white-space: pre-wrap;
}
.frame {
color: var(--yellow);
}
.stack {
font-size: 13px;
color: var(--dim);
}
.file-link {
text-decoration: underline !important;
cursor: pointer;
}
</style>

+ 52
- 0
frappe/public/js/frappe/build_events/BuildSuccess.vue View File

@@ -0,0 +1,52 @@
<template>
<div
v-if="is_shown"
class="flex justify-between build-success-message align-center"
>
<div class="mr-4">Compiled successfully</div>
<a class="text-white underline" href="/" @click.prevent="reload">
Refresh
</a>
</div>
</template>
<script>
export default {
name: "BuildSuccess",
data() {
return {
is_shown: false
};
},
methods: {
show() {
this.is_shown = true;
if (this.timeout) {
clearTimeout(this.timeout);
}
this.timeout = setTimeout(() => {
this.hide();
}, 10000);
},
hide() {
this.is_shown = false;
},
reload() {
window.location.reload();
}
}
};
</script>
<style>
.build-success-message {
position: fixed;
z-index: 9999;
bottom: 0;
right: 0;
background: rgba(0, 0, 0, 0.6);
border-radius: var(--border-radius);
padding: 0.5rem 1rem;
color: white;
font-weight: 500;
margin: 1rem;
}
</style>

+ 48
- 0
frappe/public/js/frappe/build_events/build_events.bundle.js View File

@@ -0,0 +1,48 @@
import BuildError from "./BuildError.vue";
import BuildSuccess from "./BuildSuccess.vue";

let $container = $("#build-events-overlay");
let success = null;
let error = null;

frappe.realtime.on("build_event", data => {
if (data.success) {
show_build_success(data);
} else if (data.error) {
show_build_error(data);
}
});

function show_build_success() {
if (error) {
error.hide();
}
if (!success) {
let target = $('<div class="build-success-container">')
.appendTo($container)
.get(0);
let vm = new Vue({
el: target,
render: h => h(BuildSuccess)
});
success = vm.$children[0];
}
success.show();
}

function show_build_error(data) {
if (success) {
success.hide();
}
if (!error) {
let target = $('<div class="build-error-container">')
.appendTo($container)
.get(0);
let vm = new Vue({
el: target,
render: h => h(BuildError)
});
error = vm.$children[0];
}
error.show(data);
}

+ 1
- 1
frappe/public/js/frappe/class.js View File

@@ -80,4 +80,4 @@ To subclass, use:

// export
global.Class = Class;
})(this);
})(window);

+ 58
- 60
frappe/public/js/frappe/desk.js View File

@@ -24,12 +24,12 @@ $(document).ready(function() {
frappe.start_app();
});

frappe.Application = Class.extend({
init: function() {
frappe.Application = class Application {
constructor() {
this.startup();
},
}

startup: function() {
startup() {
frappe.socketio.init();
frappe.model.init();

@@ -115,7 +115,7 @@ frappe.Application = Class.extend({
});

// listen to build errors
this.setup_build_error_listener();
this.setup_build_events();

if (frappe.sys_defaults.email_user_password) {
var email_list = frappe.sys_defaults.email_user_password.split(',');
@@ -160,7 +160,7 @@ frappe.Application = Class.extend({
}, 600000); // check every 10 minutes
}
}
},
}

set_route() {
frappe.flags.setting_original_route = true;
@@ -175,14 +175,14 @@ frappe.Application = Class.extend({
frappe.router.on('change', () => {
$(".tooltip").hide();
});
},
}

setup_frappe_vue() {
Vue.prototype.__ = window.__;
Vue.prototype.frappe = window.frappe;
},
}

set_password: function(user) {
set_password(user) {
var me=this;
frappe.call({
method: 'frappe.core.doctype.user.user.get_email_awaiting',
@@ -199,9 +199,9 @@ frappe.Application = Class.extend({
}
}
});
},
}

email_password_prompt: function(email_account,user,i) {
email_password_prompt(email_account,user,i) {
var me = this;
let d = new frappe.ui.Dialog({
title: __('Password missing in Email Account'),
@@ -255,8 +255,8 @@ frappe.Application = Class.extend({
});
});
d.show();
},
load_bootinfo: function() {
}
load_bootinfo() {
if(frappe.boot) {
this.setup_workspaces();
frappe.model.sync(frappe.boot.docs);
@@ -278,7 +278,7 @@ frappe.Application = Class.extend({
} else {
this.set_as_guest();
}
},
}

setup_workspaces() {
frappe.modules = {};
@@ -289,26 +289,26 @@ frappe.Application = Class.extend({
}
if (!frappe.workspaces['home']) {
// default workspace is settings for Frappe
frappe.workspaces['home'] = frappe.workspaces['build'];
frappe.workspaces['home'] = frappe.workspaces[Object.keys(frappe.workspaces)[0]];
}
},
}

load_user_permissions: function() {
load_user_permissions() {
frappe.defaults.update_user_permissions();

frappe.realtime.on('update_user_permissions', frappe.utils.debounce(() => {
frappe.defaults.update_user_permissions();
}, 500));
},
}

check_metadata_cache_status: function() {
check_metadata_cache_status() {
if(frappe.boot.metadata_version != localStorage.metadata_version) {
frappe.assets.clear_local_storage();
frappe.assets.init_local_storage();
}
},
}

set_globals: function() {
set_globals() {
frappe.session.user = frappe.boot.user.name;
frappe.session.logged_in_user = frappe.boot.user.name;
frappe.session.user_email = frappe.boot.user.email;
@@ -360,8 +360,8 @@ frappe.Application = Class.extend({
}
}
});
},
sync_pages: function() {
}
sync_pages() {
// clear cached pages if timestamp is not found
if(localStorage["page_info"]) {
frappe.boot.allowed_pages = [];
@@ -376,8 +376,8 @@ frappe.Application = Class.extend({
frappe.boot.allowed_pages = Object.keys(frappe.boot.page_info);
}
localStorage["page_info"] = JSON.stringify(frappe.boot.page_info);
},
set_as_guest: function() {
}
set_as_guest() {
frappe.session.user = 'Guest';
frappe.session.user_email = '';
frappe.session.user_fullname = 'Guest';
@@ -385,23 +385,23 @@ frappe.Application = Class.extend({
frappe.user_defaults = {};
frappe.user_roles = ['Guest'];
frappe.sys_defaults = {};
},
make_page_container: function() {
}
make_page_container() {
if ($("#body").length) {
$(".splash").remove();
frappe.temp_container = $("<div id='temp-container' style='display: none;'>")
.appendTo("body");
frappe.container = new frappe.views.Container();
}
},
make_nav_bar: function() {
}
make_nav_bar() {
// toolbar
if(frappe.boot && frappe.boot.home_page!=='setup-wizard') {
frappe.frappe_toolbar = new frappe.ui.toolbar.Toolbar();
}

},
logout: function() {
}
logout() {
var me = this;
me.logged_out = true;
return frappe.call({
@@ -413,8 +413,8 @@ frappe.Application = Class.extend({
me.redirect_to_login();
}
});
},
handle_session_expired: function() {
}
handle_session_expired() {
if(!frappe.app.session_expired_dialog) {
var dialog = new frappe.ui.Dialog({
title: __('Session Expired'),
@@ -464,16 +464,16 @@ frappe.Application = Class.extend({
'background-color': '#4B4C9D'
});
}
},
redirect_to_login: function() {
}
redirect_to_login() {
window.location.href = '/';
},
set_favicon: function() {
}
set_favicon() {
var link = $('link[type="image/x-icon"]').remove().attr("href");
$('<link rel="shortcut icon" href="' + link + '" type="image/x-icon">').appendTo("head");
$('<link rel="icon" href="' + link + '" type="image/x-icon">').appendTo("head");
},
trigger_primary_action: function() {
}
trigger_primary_action() {
// to trigger change event on active input before triggering primary action
$(document.activeElement).blur();
// wait for possible JS validations triggered after blur (it might change primary button)
@@ -487,20 +487,20 @@ frappe.Application = Class.extend({
frappe.container.page.save_action();
}
}, 100);
},
}

set_rtl: function() {
set_rtl() {
if (frappe.utils.is_rtl()) {
var ls = document.createElement('link');
ls.rel="stylesheet";
ls.type = "text/css";
ls.href= "/assets/css/frappe-rtl.css";
ls.href= frappe.assets.bundled_asset("frappe-rtl.bundle.css");
document.getElementsByTagName('head')[0].appendChild(ls);
$('body').addClass('frappe-rtl');
}
},
}

show_change_log: function() {
show_change_log() {
var me = this;
let change_log = frappe.boot.change_log;

@@ -531,15 +531,15 @@ frappe.Application = Class.extend({
});
me.show_notes();
};
},
}

show_update_available: () => {
show_update_available() {
frappe.call({
"method": "frappe.utils.change_log.show_update_popup"
});
},
}

setup_analytics: function() {
setup_analytics() {
if(window.mixpanel) {
window.mixpanel.identify(frappe.session.user);
window.mixpanel.people.set({
@@ -549,17 +549,17 @@ frappe.Application = Class.extend({
"$email": frappe.session.user
});
}
},
}

add_browser_class() {
$('html').addClass(frappe.utils.get_browser().name.toLowerCase());
},
}

set_fullwidth_if_enabled() {
frappe.ui.toolbar.set_fullwidth_if_enabled();
},
}

show_notes: function() {
show_notes() {
var me = this;
if(frappe.boot.notes.length) {
frappe.boot.notes.forEach(function(note) {
@@ -586,21 +586,19 @@ frappe.Application = Class.extend({
}
});
}
},
}

setup_build_error_listener() {
setup_build_events() {
if (frappe.boot.developer_mode) {
frappe.realtime.on('build_error', (data) => {
console.log(data);
});
frappe.require("build_events.bundle.js");
}
},
}

setup_energy_point_listeners() {
frappe.realtime.on('energy_point_alert', (message) => {
frappe.show_alert(message);
});
},
}

setup_copy_doc_listener() {
$('body').on('paste', (e) => {
@@ -634,7 +632,7 @@ frappe.Application = Class.extend({
}
});
}
});
}

frappe.get_module = function(m, default_module) {
var module = frappe.modules[m] || default_module;


+ 15
- 15
frappe/public/js/frappe/form/controls/attach.js View File

@@ -1,5 +1,5 @@
frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
make_input: function() {
frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.ControlData {
make_input() {
let me = this;
this.$input = $('<button class="btn btn-default btn-sm btn-attach">')
.html(__("Attach"))
@@ -26,8 +26,8 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({

frappe.utils.bind_actions_with_object(this.$value, this);
this.toggle_reload_button();
},
clear_attachment: function() {
}
clear_attachment() {
let me = this;
if(this.frm) {
me.parse_validate_and_set_in_model(null);
@@ -44,16 +44,16 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
this.parse_validate_and_set_in_model(null);
this.refresh();
}
},
}
reload_attachment() {
if (this.file_uploader) {
this.file_uploader.uploader.upload_files();
}
},
}
on_attach_click() {
this.set_upload_options();
this.file_uploader = new frappe.ui.FileUploader(this.upload_options);
},
}
set_upload_options() {
let options = {
allow_multiple: false,
@@ -73,9 +73,9 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
Object.assign(options, this.df.options);
}
this.upload_options = options;
},
}

set_input: function(value, dataurl) {
set_input(value, dataurl) {
this.value = value;
if(this.value) {
this.$input.toggle(false);
@@ -94,23 +94,23 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
this.$input.toggle(true);
this.$value.toggle(false);
}
},
}

get_value: function() {
get_value() {
return this.value || null;
},
}

on_upload_complete: function(attachment) {
on_upload_complete(attachment) {
if(this.frm) {
this.parse_validate_and_set_in_model(attachment.file_url);
this.frm.attachments.update_attachment(attachment);
this.frm.doc.docstatus == 1 ? this.frm.save('Update') : this.frm.save();
}
this.set_value(attachment.file_url);
},
}

toggle_reload_button() {
this.$value.find('[data-action="reload_attachment"]')
.toggle(this.file_uploader && this.file_uploader.uploader.files.length > 0);
}
});
};

+ 5
- 5
frappe/public/js/frappe/form/controls/attach_image.js View File

@@ -1,6 +1,6 @@
frappe.ui.form.ControlAttachImage = frappe.ui.form.ControlAttach.extend({
frappe.ui.form.ControlAttachImage = class ControlAttachImage extends frappe.ui.form.ControlAttach {
make_input() {
this._super();
super.make_input();

let $file_link = this.$value.find('.attached-file-link');
$file_link.popover({
@@ -16,10 +16,10 @@ frappe.ui.form.ControlAttachImage = frappe.ui.form.ControlAttach.extend({
},
html: true
});
},
}
set_upload_options() {
this._super();
super.set_upload_options();
this.upload_options.restrictions = {};
this.upload_options.restrictions.allowed_file_types = ['image/*'];
}
});
};

+ 11
- 11
frappe/public/js/frappe/form/controls/autocomplete.js View File

@@ -1,19 +1,19 @@
import Awesomplete from 'awesomplete';

frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
trigger_change_on_input_event: false,
frappe.ui.form.ControlAutocomplete = class ControlAutoComplete extends frappe.ui.form.ControlData {
static trigger_change_on_input_event = false
make_input() {
this._super();
super.make_input();
this.setup_awesomplete();
this.set_options();
},
}

set_options() {
if (this.df.options) {
let options = this.df.options || [];
this._data = this.parse_options(options);
}
},
}

get_awesomplete_settings() {
var me = this;
@@ -63,7 +63,7 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
return 0;
}
};
},
}

setup_awesomplete() {
this.awesomplete = new Awesomplete(
@@ -100,7 +100,7 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
this.$input.on('awesomplete-selectcomplete', () => {
this.$input.trigger('change');
});
},
}

validate(value) {
if (this.df.ignore_validation) {
@@ -115,7 +115,7 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
} else {
return '';
}
},
}

parse_options(options) {
if (typeof options === 'string') {
@@ -125,11 +125,11 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
options = options.map(o => ({ label: o, value: o }));
}
return options;
},
}

get_data() {
return this._data || [];
},
}

set_data(data) {
data = this.parse_options(data);
@@ -138,4 +138,4 @@ frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
}
this._data = data;
}
});
};

+ 7
- 7
frappe/public/js/frappe/form/controls/barcode.js View File

@@ -1,9 +1,9 @@
import JsBarcode from 'jsbarcode';

frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
frappe.ui.form.ControlBarcode = class ControlBarcode extends frappe.ui.form.ControlData {
make_wrapper() {
// Create the elements for barcode area
this._super();
super.make_wrapper();

this.default_svg = '<svg height=80></svg>';
let $input_wrapper = this.$wrapper.find('.control-input-wrapper');
@@ -11,7 +11,7 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
`<div class="barcode-wrapper">${this.default_svg}</div>`
);
this.barcode_area.appendTo($input_wrapper);
},
}

parse(value) {
// Parse raw value
@@ -22,7 +22,7 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
return this.get_barcode_html(value);
}
return '';
},
}

set_formatted_input(value) {
// Set values to display
@@ -40,7 +40,7 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({

this.$input.val(barcode_value || value);
this.barcode_area.html(svg || this.default_svg);
},
}

get_barcode_html(value) {
if (value) {
@@ -51,7 +51,7 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
$(svg).attr('width', '100%');
return this.barcode_area.html();
}
},
}

get_options(value) {
// get JsBarcode options
@@ -76,4 +76,4 @@ frappe.ui.form.ControlBarcode = frappe.ui.form.ControlData.extend({
}
return options;
}
});
};

+ 30
- 30
frappe/public/js/frappe/form/controls/base_control.js View File

@@ -1,5 +1,5 @@
frappe.ui.form.Control = Class.extend({
init: function(opts) {
frappe.ui.form.Control = class BaseControl {
constructor(opts) {
$.extend(this, opts);
this.make();

@@ -11,31 +11,31 @@ frappe.ui.form.Control = Class.extend({
if(this.render_input) {
this.refresh();
}
},
make: function() {
}
make() {
this.make_wrapper();
this.$wrapper
.attr("data-fieldtype", this.df.fieldtype)
.attr("data-fieldname", this.df.fieldname);
this.wrapper = this.$wrapper.get(0);
this.wrapper.fieldobj = this; // reference for event handlers
},
}

make_wrapper: function() {
make_wrapper() {
this.$wrapper = $("<div class='frappe-control'></div>").appendTo(this.parent);

// alias
this.wrapper = this.$wrapper;
},
}

toggle: function(show) {
toggle(show) {
this.df.hidden = show ? 0 : 1;
this.refresh();
},
}

// returns "Read", "Write" or "None"
// as strings based on permissions
get_status: function(explain) {
get_status(explain) {
if (this.df.get_status) {
return this.df.get_status(this);
}
@@ -93,8 +93,8 @@ frappe.ui.form.Control = Class.extend({
}

return status;
},
refresh: function() {
}
refresh() {
this.disp_status = this.get_status();
this.$wrapper
&& this.$wrapper.toggleClass("hide-control", this.disp_status=="None")
@@ -104,7 +104,7 @@ frappe.ui.form.Control = Class.extend({
var value = this.get_value();

this.show_translatable_button(value);
},
}
show_translatable_button(value) {
// Disable translation non-string fields or special string fields
if (!frappe.model
@@ -138,26 +138,26 @@ frappe.ui.form.Control = Class.extend({
}
});

},
get_doc: function() {
}
get_doc() {
return this.doctype && this.docname
&& locals[this.doctype] && locals[this.doctype][this.docname] || {};
},
get_model_value: function() {
}
get_model_value() {
if(this.doc) {
return this.doc[this.df.fieldname];
}
},
set_value: function(value) {
}
set_value(value) {
return this.validate_and_set_in_model(value);
},
parse_validate_and_set_in_model: function(value, e) {
}
parse_validate_and_set_in_model(value, e) {
if(this.parse) {
value = this.parse(value);
}
return this.validate_and_set_in_model(value, e);
},
validate_and_set_in_model: function(value, e) {
}
validate_and_set_in_model(value, e) {
var me = this;
let force_value_set = (this.doc && this.doc.__run_link_triggers);
let is_value_same = (this.get_model_value() === value);
@@ -193,8 +193,8 @@ frappe.ui.form.Control = Class.extend({
// all clear
return set(value);
}
},
get_value: function() {
}
get_value() {
if(this.get_status()==='Write') {
return this.get_input_value ?
(this.parse ? this.parse(this.get_input_value()) : this.get_input_value()) :
@@ -202,8 +202,8 @@ frappe.ui.form.Control = Class.extend({
} else {
return this.value || undefined;
}
},
set_model_value: function(value) {
}
set_model_value(value) {
if(this.frm) {
this.last_value = value;
return frappe.model.set_value(this.doctype, this.docname, this.df.fieldname,
@@ -215,11 +215,11 @@ frappe.ui.form.Control = Class.extend({
this.set_input(value);
return Promise.resolve();
}
},
set_focus: function() {
}
set_focus() {
if(this.$input) {
this.$input.get(0).focus();
return true;
}
}
});
};

+ 36
- 36
frappe/public/js/frappe/form/controls/base_input.js View File

@@ -1,14 +1,14 @@
frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
horizontal: true,
make: function() {
frappe.ui.form.ControlInput = class ControlInput extends frappe.ui.form.Control {
static horizontal = true
make() {
// parent element
this._super();
super.make();
this.set_input_areas();

// set description
this.set_max_width();
},
make_wrapper: function() {
}
make_wrapper() {
if(this.only_input) {
this.$wrapper = $('<div class="form-group frappe-control">').appendTo(this.parent);
} else {
@@ -25,14 +25,14 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
</div>\
</div>').appendTo(this.parent);
}
},
toggle_label: function(show) {
}
toggle_label(show) {
this.$wrapper.find(".control-label").toggleClass("hide", !show);
},
toggle_description: function(show) {
}
toggle_description(show) {
this.$wrapper.find(".help-box").toggleClass("hide", !show);
},
set_input_areas: function() {
}
set_input_areas() {
if(this.only_input) {
this.input_area = this.wrapper;
} else {
@@ -43,17 +43,17 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
// like links, currencies, HTMLs etc.
this.disp_area = this.$wrapper.find(".control-value").get(0);
}
},
set_max_width: function() {
if(this.horizontal) {
}
set_max_width() {
if(this.constructor.horizontal) {
this.$wrapper.addClass("input-max-width");
}
},
}

// update input value, label, description
// display (show/hide/read-only),
// mandatory style on refresh
refresh_input: function() {
refresh_input() {
var me = this;
var make_input = function() {
if (!me.has_input) {
@@ -106,13 +106,13 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
me.set_bold();
me.set_required();
}
},
}

can_write() {
return this.disp_status == "Write";
},
}

set_disp_area: function(value) {
set_disp_area(value) {
if(in_list(["Currency", "Int", "Float"], this.df.fieldtype)
&& (this.value === 0 || value === 0)) {
// to set the 0 value in readonly for currency, int, float field
@@ -126,8 +126,8 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
let doc = this.doc || (this.frm && this.frm.doc);
let display_value = frappe.format(value, this.df, { no_icon: true, inline: true }, doc);
this.disp_area && $(this.disp_area).html(display_value);
},
set_label: function(label) {
}
set_label(label) {
if(label) this.df.label = label;

if(this.only_input || this.df.label==this._label)
@@ -137,8 +137,8 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
this.label_span.innerHTML = (icon ? '<i class="'+icon+'"></i> ' : "") +
__(this.df.label) || "&nbsp;";
this._label = this.df.label;
},
set_description: function(description) {
}
set_description(description) {
if (description !== undefined) {
this.df.description = description;
}
@@ -151,17 +151,17 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
this.set_empty_description();
}
this._description = this.df.description;
},
set_new_description: function(description) {
}
set_new_description(description) {
this.$wrapper.find(".help-box").html(description);
},
set_empty_description: function() {
}
set_empty_description() {
this.$wrapper.find(".help-box").html("");
},
set_mandatory: function(value) {
}
set_mandatory(value) {
this.$wrapper.toggleClass("has-error", Boolean(this.df.reqd && is_null(value)));
},
set_invalid: function () {
}
set_invalid () {
let invalid = !!this.df.invalid;
if (this.grid) {
this.$wrapper.parents('.grid-static-col').toggleClass('invalid', invalid);
@@ -170,11 +170,11 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
} else {
this.$wrapper.toggleClass('has-error', invalid);
}
},
}
set_required() {
this.label_area && $(this.label_area).toggleClass('reqd', Boolean(this.df.reqd));
},
set_bold: function() {
}
set_bold() {
if(this.$input) {
this.$input.toggleClass("bold", !!(this.df.bold || this.df.reqd));
}
@@ -182,4 +182,4 @@ frappe.ui.form.ControlInput = frappe.ui.form.Control.extend({
$(this.disp_area).toggleClass("bold", !!(this.df.bold || this.df.reqd));
}
}
});
};

+ 16
- 16
frappe/public/js/frappe/form/controls/button.js View File

@@ -1,9 +1,9 @@
frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
frappe.ui.form.ControlButton = class ControlButton extends frappe.ui.form.ControlData {
can_write() {
// should be always true in case of button
return true;
},
make_input: function() {
}
make_input() {
var me = this;
const btn_type = this.df.primary ? 'btn-primary': 'btn-default';
const btn_size = this.df.btn_size
@@ -18,8 +18,8 @@ frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
this.set_input_attributes();
this.has_input = true;
this.toggle_label(false);
},
onclick: function() {
}
onclick() {
if (this.frm && this.frm.doc) {
if (this.frm.script_manager.has_handlers(this.df.fieldname, this.doctype)) {
this.frm.script_manager.trigger(this.df.fieldname, this.doctype, this.docname);
@@ -31,8 +31,8 @@ frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
} else if (this.df.click) {
this.df.click();
}
},
run_server_script: function() {
}
run_server_script() {
// DEPRECATE
var me = this;
if(this.frm && this.frm.docname) {
@@ -47,18 +47,18 @@ frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
}
});
}
},
}
hide() {
this.$input.hide();
},
set_input_areas: function() {
this._super();
}
set_input_areas() {
super.set_input_areas();
$(this.disp_area).removeClass().addClass("hide");
},
set_empty_description: function() {
}
set_empty_description() {
this.$wrapper.find(".help-box").empty().toggle(false);
},
set_label: function(label) {
}
set_label(label) {
if (label) {
this.df.label = label;
}
@@ -66,4 +66,4 @@ frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
$(this.label_span).html("&nbsp;");
this.$input && this.$input.html(label);
}
});
};

+ 16
- 15
frappe/public/js/frappe/form/controls/check.js View File

@@ -1,6 +1,7 @@
frappe.ui.form.ControlCheck = frappe.ui.form.ControlData.extend({
input_type: "checkbox",
make_wrapper: function() {
frappe.ui.form.ControlCheck = class ControlCheck extends frappe.ui.form.ControlData {
static html_element = "input"
static input_type = "checkbox"
make_wrapper() {
this.$wrapper = $(`<div class="form-group frappe-control">
<div class="checkbox">
<label>
@@ -11,23 +12,23 @@ frappe.ui.form.ControlCheck = frappe.ui.form.ControlData.extend({
<p class="help-box small text-muted"></p>
</div>
</div>`).appendTo(this.parent);
},
set_input_areas: function() {
}
set_input_areas() {
this.label_area = this.label_span = this.$wrapper.find(".label-area").get(0);
this.input_area = this.$wrapper.find(".input-area").get(0);
this.disp_area = this.$wrapper.find(".disp-area").get(0);
},
make_input: function() {
this._super();
}
make_input() {
super.make_input();
this.$input.removeClass("form-control");
},
get_input_value: function() {
}
get_input_value() {
return this.input && this.input.checked ? 1 : 0;
},
validate: function(value) {
}
validate(value) {
return cint(value);
},
set_input: function(value) {
}
set_input(value) {
value = cint(value);
if(this.input) {
this.input.checked = (value ? 1 : 0);
@@ -36,4 +37,4 @@ frappe.ui.form.ControlCheck = frappe.ui.form.ControlData.extend({
this.set_mandatory(value);
this.set_disp_area(value);
}
});
};

+ 13
- 12
frappe/public/js/frappe/form/controls/code.js View File

@@ -1,8 +1,8 @@
frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
frappe.ui.form.ControlCode = class ControlCode extends frappe.ui.form.ControlText {
make_input() {
if (this.editor) return;
this.load_lib().then(() => this.make_ace_editor());
},
}

make_ace_editor() {
if (this.editor) return;
@@ -34,6 +34,7 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({

// setup autocompletion when it is set the first time
Object.defineProperty(this.df, 'autocompletions', {
configurable: true,
get() {
return this._autocompletions || [];
},
@@ -42,7 +43,7 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
this.df._autocompletions = value;
}
});
},
}

setup_autocompletion() {
if (this._autocompletion_setup) return;
@@ -82,20 +83,20 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
});
});
this._autocompletion_setup = true;
},
}

refresh_height() {
this.ace_editor_target.css('height', this.expanded ? 600 : 300);
this.editor.resize();
},
}

toggle_label() {
this.$expand_button && this.$expand_button.text(this.get_button_label());
},
}

get_button_label() {
return this.expanded ? __('Collapse', null, 'Shrink code field.') : __('Expand', null, 'Enlarge code field.');
},
}

set_language() {
const language_map = {
@@ -122,14 +123,14 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
const ace_language_mode = language_map[language] || '';
this.editor.session.setMode(ace_language_mode);
this.editor.setKeyboardHandler('ace/keyboard/vscode');
},
}

parse(value) {
if (value == null) {
value = "";
}
return value;
},
}

set_formatted_input(value) {
return this.load_lib().then(() => {
@@ -138,11 +139,11 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
if (value === this.get_input_value()) return;
this.editor.session.setValue(value);
});
},
}

get_input_value() {
return this.editor ? this.editor.session.getValue() : '';
},
}

load_lib() {
if (this.library_loaded) return this.library_loaded;
@@ -162,4 +163,4 @@ frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({

return this.library_loaded;
}
});
};

+ 19
- 14
frappe/public/js/frappe/form/controls/color.js View File

@@ -1,12 +1,13 @@
import Picker from '../../color_picker/color_picker';

frappe.ui.form.ControlColor = frappe.ui.form.ControlData.extend({
make_input: function () {
frappe.ui.form.ControlColor = class ControlColor extends frappe.ui.form.ControlData {
make_input() {
this.df.placeholder = this.df.placeholder || __('Choose a color');
this._super();
super.make_input();
this.make_color_input();
},
make_color_input: function () {
}

make_color_input() {
let picker_wrapper = $('<div>');
this.picker = new Picker({
parent: picker_wrapper[0],
@@ -73,27 +74,31 @@ frappe.ui.form.ControlColor = frappe.ui.form.ControlData.extend({
this.$wrapper.popover('hide');
});
});
},
}

refresh() {
this._super();
super.refresh();
let color = this.get_color();
if (this.picker && this.picker.color !== color) {
this.picker.color = color;
this.picker.refresh();
}
},
set_formatted_input: function(value) {
this._super(value);
}

set_formatted_input(value) {
super.set_formatted_input(value);
this.$input.val(value);
this.selected_color.css({
"background-color": value || 'transparent',
});
this.selected_color.toggleClass('no-value', !value);
},
}

get_color() {
return this.validate(this.get_value());
},
validate: function (value) {
}

validate(value) {
if (value === '') {
return '';
}
@@ -103,4 +108,4 @@ frappe.ui.form.ControlColor = frappe.ui.form.ControlData.extend({
}
return null;
}
});
};

+ 13
- 13
frappe/public/js/frappe/form/controls/comment.js View File

@@ -3,7 +3,7 @@ import Mention from './quill-mention/quill.mention';

Quill.register('modules/mention', Mention, true);

frappe.ui.form.ControlComment = frappe.ui.form.ControlTextEditor.extend({
frappe.ui.form.ControlComment = class ControlComment extends frappe.ui.form.ControlTextEditor {
make_wrapper() {
this.comment_wrapper = !this.no_wrapper ? $(`
<div class="comment-input-wrapper">
@@ -32,10 +32,10 @@ frappe.ui.form.ControlComment = frappe.ui.form.ControlTextEditor.extend({
this.wrapper = this.$wrapper;

this.button = this.comment_wrapper.find('.btn-comment');
},
}

bind_events() {
this._super();
super.bind_events();

this.button.click(() => {
this.submit();
@@ -52,11 +52,11 @@ frappe.ui.form.ControlComment = frappe.ui.form.ControlTextEditor.extend({
this.quill.on('text-change', frappe.utils.debounce(() => {
this.update_state();
}, 300));
},
}

submit() {
this.on_submit && this.on_submit(this.get_value());
},
}

update_state() {
const value = this.get_value();
@@ -65,17 +65,17 @@ frappe.ui.form.ControlComment = frappe.ui.form.ControlTextEditor.extend({
} else {
this.button.addClass('btn-default').removeClass('btn-primary');
}
},
}

get_quill_options() {
const options = this._super();
const options = super.get_quill_options();
return Object.assign(options, {
theme: 'bubble',
modules: Object.assign(options.modules, {
mention: this.get_mention_options()
})
});
},
}

get_mention_options() {
if (!this.enable_mentions) {
@@ -98,7 +98,7 @@ frappe.ui.form.ControlComment = frappe.ui.form.ControlTextEditor.extend({
return `${value} ${item.is_group ? frappe.utils.icon('users') : ''}`;
}
};
},
}

get_toolbar_options() {
return [
@@ -108,19 +108,19 @@ frappe.ui.form.ControlComment = frappe.ui.form.ControlTextEditor.extend({
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
['clean']
];
},
}

clear() {
this.quill.setText('');
},
}

disable() {
this.quill.disable();
this.button.prop('disabled', true);
},
}

enable() {
this.quill.enable();
this.button.prop('disabled', false);
}
});
};

+ 5
- 5
frappe/public/js/frappe/form/controls/currency.js View File

@@ -1,10 +1,10 @@
frappe.ui.form.ControlCurrency = frappe.ui.form.ControlFloat.extend({
format_for_input: function(value) {
frappe.ui.form.ControlCurrency = class ControlCurrency extends frappe.ui.form.ControlFloat {
format_for_input(value) {
var formatted_value = format_number(value, this.get_number_format(), this.get_precision());
return isNaN(Number(value)) ? "" : formatted_value;
},
}

get_precision: function() {
get_precision() {
// always round based on field precision or currency's precision
// this method is also called in this.parse()
if (!this.df.precision) {
@@ -17,4 +17,4 @@ frappe.ui.form.ControlCurrency = frappe.ui.form.ControlFloat.extend({

return this.df.precision;
}
});
};

+ 38
- 34
frappe/public/js/frappe/form/controls/data.js View File

@@ -1,14 +1,16 @@
frappe.provide('frappe.phone_call');

frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
html_element: "input",
input_type: "text",
trigger_change_on_input_event: true,
make_input: function() {
frappe.ui.form.ControlData = class ControlData extends frappe.ui.form.ControlInput {
static html_element = "input";
static input_type = "text";
static trigger_change_on_input_event = true;
make_input() {
if(this.$input) return;

this.$input = $("<"+ this.html_element +">")
.attr("type", this.input_type)
let { html_element, input_type } = this.constructor;

this.$input = $("<"+ html_element +">")
.attr("type", input_type)
.attr("autocomplete", "off")
.addClass("input-with-feedback form-control")
.prependTo(this.input_area);
@@ -32,7 +34,7 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
let doctype_edit_link = null;
if (this.frm.meta.custom) {
doctype_edit_link = frappe.utils.get_form_link(
'DocType',
'DocType',
this.frm.doctype, true,
__('this form')
);
@@ -65,8 +67,9 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
if (this.df.options == 'URL') {
this.setup_url_field();
}
},
setup_url_field: function() {
}

setup_url_field() {
this.$wrapper.find('.control-input').append(
`<span class="link-btn">
<a class="btn-open no-decoration" title="${__("Open Link")}" target="_blank">
@@ -74,14 +77,14 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
</a>
</span>`
);
this.$link = this.$wrapper.find('.link-btn');
this.$link_open = this.$link.find('.btn-open');
this.$input.on("focus", () => {
setTimeout(() => {
let inputValue = this.get_input_value();
if (inputValue && validate_url(inputValue)) {
this.$link.toggle(true);
this.$link_open.attr('href', this.get_input_value());
@@ -100,7 +103,7 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
this.$link.toggle(false);
}
});
this.$input.on("blur", () => {
// if this disappears immediately, the user's click
// does not register, hence timeout
@@ -108,8 +111,9 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
this.$link.toggle(false);
}, 500);
});
},
bind_change_event: function() {
}

bind_change_event() {
const change_handler = e => {
if (this.change) this.change(e);
else {
@@ -118,12 +122,12 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
}
};
this.$input.on("change", change_handler);
if (this.trigger_change_on_input_event) {
if (this.constructor.trigger_change_on_input_event) {
// debounce to avoid repeated validations on value change
this.$input.on("input", frappe.utils.debounce(change_handler, 500));
}
},
setup_autoname_check: function() {
}
setup_autoname_check() {
if (!this.df.parent) return;
this.meta = frappe.get_meta(this.df.parent);
if (this.meta && ((this.meta.autoname
@@ -152,8 +156,8 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
}
});
}
},
set_input_attributes: function() {
}
set_input_attributes() {
this.$input
.attr("data-fieldtype", this.df.fieldtype)
.attr("data-fieldname", this.df.fieldname)
@@ -167,24 +171,24 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
if(this.df.input_class) {
this.$input.addClass(this.df.input_class);
}
},
set_input: function(value) {
}
set_input(value) {
this.last_value = this.value;
this.value = value;
this.set_formatted_input(value);
this.set_disp_area(value);
this.set_mandatory && this.set_mandatory(value);
},
set_formatted_input: function(value) {
}
set_formatted_input(value) {
this.$input && this.$input.val(this.format_for_input(value));
},
get_input_value: function() {
}
get_input_value() {
return this.$input ? this.$input.val() : undefined;
},
format_for_input: function(val) {
}
format_for_input(val) {
return val==null ? "" : val;
},
validate: function(v) {
}
validate(v) {
if (!v) {
return '';
}
@@ -217,9 +221,9 @@ frappe.ui.form.ControlData = frappe.ui.form.ControlInput.extend({
} else {
return v;
}
},
toggle_container_scroll: function(el_class, scroll_class, add=false) {
}
toggle_container_scroll(el_class, scroll_class, add=false) {
let el = this.$input.parents(el_class)[0];
if (el) $(el).toggleClass(scroll_class, add);
}
});
};

+ 26
- 26
frappe/public/js/frappe/form/controls/date.js View File

@@ -1,16 +1,16 @@
frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({
trigger_change_on_input_event: false,
make_input: function() {
this._super();
frappe.ui.form.ControlDate = class ControlDate extends frappe.ui.form.ControlData {
static trigger_change_on_input_event = false
make_input() {
super.make_input();
this.make_picker();
},
make_picker: function() {
}
make_picker() {
this.set_date_options();
this.set_datepicker();
this.set_t_for_today();
},
set_formatted_input: function(value) {
this._super(value);
}
set_formatted_input(value) {
super.set_formatted_input(value);
if (this.timepicker_only) return;
if (!this.datepicker) return;
if (!value) {
@@ -39,8 +39,8 @@ frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({
if(should_refresh) {
this.datepicker.selectDate(frappe.datetime.str_to_obj(value));
}
},
set_date_options: function() {
}
set_date_options() {
// webformTODO:
let sysdefaults = frappe.boot.sysdefaults;

@@ -75,8 +75,8 @@ frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({
this.update_datepicker_position();
}
};
},
set_datepicker: function() {
}
set_datepicker() {
this.$input.datepicker(this.datepicker_options);
this.datepicker = this.$input.data('datepicker');

@@ -87,8 +87,8 @@ frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({
.click(() => {
this.datepicker.selectDate(this.get_now_date());
});
},
update_datepicker_position: function() {
}
update_datepicker_position() {
if(!this.frm) return;
// show datepicker above or below the input
// based on scroll position
@@ -110,11 +110,11 @@ frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({
}

this.datepicker.update('position', position);
},
get_now_date: function() {
}
get_now_date() {
return frappe.datetime.now_date(true);
},
set_t_for_today: function() {
}
set_t_for_today() {
var me = this;
this.$input.on("keydown", function(e) {
if(e.which===84) { // 84 === t
@@ -128,19 +128,19 @@ frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({
return false;
}
});
},
parse: function(value) {
}
parse(value) {
if(value) {
return frappe.datetime.user_to_str(value);
}
},
format_for_input: function(value) {
}
format_for_input(value) {
if(value) {
return frappe.datetime.str_to_user(value);
}
return "";
},
validate: function(value) {
}
validate(value) {
if(value && !frappe.datetime.validate(value)) {
let sysdefaults = frappe.sys_defaults;
let date_format = sysdefaults && sysdefaults.date_format
@@ -150,4 +150,4 @@ frappe.ui.form.ControlDate = frappe.ui.form.ControlData.extend({
}
return value;
}
});
};

+ 14
- 14
frappe/public/js/frappe/form/controls/date_range.js View File

@@ -1,11 +1,11 @@
frappe.ui.form.ControlDateRange = frappe.ui.form.ControlData.extend({
make_input: function() {
this._super();
frappe.ui.form.ControlDateRange = class ControlDateRange extends frappe.ui.form.ControlData {
make_input() {
super.make_input();
this.set_date_options();
this.set_datepicker();
this.refresh();
},
set_date_options: function() {
}
set_date_options() {
var me = this;
this.datepicker_options = {
language: "en",
@@ -18,12 +18,12 @@ frappe.ui.form.ControlDateRange = frappe.ui.form.ControlData.extend({
this.datepicker_options.onSelect = function() {
me.$input.trigger('change');
};
},
set_datepicker: function() {
}
set_datepicker() {
this.$input.datepicker(this.datepicker_options);
this.datepicker = this.$input.data('datepicker');
},
set_input: function(value, value2) {
}
set_input(value, value2) {
this.last_value = this.value;
if (value && value2) {
this.value = [value, value2];
@@ -38,8 +38,8 @@ frappe.ui.form.ControlDateRange = frappe.ui.form.ControlData.extend({
}
this.set_disp_area(value || '');
this.set_mandatory && this.set_mandatory(value);
},
parse: function(value) {
}
parse(value) {
// replace the separator (which can be in user language) with comma
const to = __('{0} to {1}').replace('{0}', '').replace('{1}', '');
value = value.replace(to, ',');
@@ -50,8 +50,8 @@ frappe.ui.form.ControlDateRange = frappe.ui.form.ControlData.extend({
var to_date = moment(frappe.datetime.user_to_obj(vals[vals.length-1])).format('YYYY-MM-DD');
return [from_date, to_date];
}
},
format_for_input: function(value1, value2) {
}
format_for_input(value1, value2) {
if(value1 && value2) {
value1 = frappe.datetime.str_to_user(value1);
value2 = frappe.datetime.str_to_user(value2);
@@ -59,4 +59,4 @@ frappe.ui.form.ControlDateRange = frappe.ui.form.ControlData.extend({
}
return "";
}
});
};

+ 12
- 12
frappe/public/js/frappe/form/controls/datetime.js View File

@@ -1,6 +1,6 @@
frappe.ui.form.ControlDatetime = frappe.ui.form.ControlDate.extend({
set_date_options: function() {
this._super();
frappe.ui.form.ControlDatetime = class ControlDatetime extends frappe.ui.form.ControlDate {
set_date_options() {
super.set_date_options();
this.today_text = __("Now");
let sysdefaults = frappe.boot.sysdefaults;
this.date_format = frappe.defaultDatetimeFormat;
@@ -10,11 +10,11 @@ frappe.ui.form.ControlDatetime = frappe.ui.form.ControlDate.extend({
timepicker: true,
timeFormat: time_format.toLowerCase().replace("mm", "ii")
});
},
get_now_date: function() {
}
get_now_date() {
return frappe.datetime.now_datetime(true);
},
set_description: function() {
}
set_description() {
const { description } = this.df;
const { time_zone } = frappe.sys_defaults;
if (!this.df.hide_timezone && !frappe.datetime.is_timezone_same()) {
@@ -24,10 +24,10 @@ frappe.ui.form.ControlDatetime = frappe.ui.form.ControlDate.extend({
this.df.description += '<br>' + time_zone;
}
}
this._super();
},
set_datepicker: function() {
this._super();
super.set_description();
}
set_datepicker() {
super.set_datepicker();
if (this.datepicker.opts.timeFormat.indexOf('s') == -1) {
// No seconds in time format
const $tp = this.datepicker.timepicker;
@@ -36,4 +36,4 @@ frappe.ui.form.ControlDatetime = frappe.ui.form.ControlDate.extend({
$tp.$secondsText.prev().css('display', 'none');
}
}
});
};

+ 21
- 21
frappe/public/js/frappe/form/controls/duration.js View File

@@ -1,10 +1,10 @@
frappe.ui.form.ControlDuration = frappe.ui.form.ControlData.extend({
make_input: function() {
this._super();
frappe.ui.form.ControlDuration = class ControlDuration extends frappe.ui.form.ControlData {
make_input() {
super.make_input();
this.make_picker();
},
}

make_picker: function() {
make_picker() {
this.inputs = [];
this.set_duration_options();
this.$picker = $(
@@ -21,9 +21,9 @@ frappe.ui.form.ControlDuration = frappe.ui.form.ControlData.extend({
this.$picker.hide();
this.bind_events();
this.refresh();
},
}

build_numeric_input: function(label, hidden, max) {
build_numeric_input(label, hidden, max) {
let $duration_input = $(`
<input class="input-sm duration-input" data-duration="${label}" type="number" min="0" value="0">
`);
@@ -47,13 +47,13 @@ frappe.ui.form.ControlDuration = frappe.ui.form.ControlData.extend({
}
$control.prepend($input);
$control.appendTo(this.$picker.find(".picker-row"));
},
}

set_duration_options() {
this.duration_options = frappe.utils.get_duration_options(this.df);
},
}

set_duration_picker_value: function(value) {
set_duration_picker_value(value) {
let total_duration = frappe.utils.seconds_to_duration(value, this.duration_options);

if (this.$picker) {
@@ -61,9 +61,9 @@ frappe.ui.form.ControlDuration = frappe.ui.form.ControlData.extend({
this.inputs[duration].prop("value", total_duration[duration]);
});
}
},
}

bind_events: function() {
bind_events() {
// flag to handle the display property of the picker
let clicked = false;

@@ -103,21 +103,21 @@ frappe.ui.form.ControlDuration = frappe.ui.form.ControlData.extend({
this.$picker.hide();
}
});
},
}

get_value() {
return cint(this.value);
},
}

refresh_input: function() {
this._super();
refresh_input() {
super.refresh_input();
this.set_duration_options();
this.set_duration_picker_value(this.value);
},
}

format_for_input: function(value) {
format_for_input(value) {
return frappe.utils.get_formatted_duration(value, this.duration_options);
},
}

get_duration() {
// returns an object of days, hours, minutes and seconds from the inputs array
@@ -138,7 +138,7 @@ frappe.ui.form.ControlDuration = frappe.ui.form.ControlData.extend({
}
}
return total_duration;
},
}

is_duration_picker_set(inputs) {
let is_set = false;
@@ -149,4 +149,4 @@ frappe.ui.form.ControlDuration = frappe.ui.form.ControlData.extend({
});
return is_set;
}
});
};

+ 4
- 4
frappe/public/js/frappe/form/controls/dynamic_link.js View File

@@ -1,5 +1,5 @@
frappe.ui.form.ControlDynamicLink = frappe.ui.form.ControlLink.extend({
get_options: function() {
frappe.ui.form.ControlDynamicLink = class ControlDynamicLink extends frappe.ui.form.ControlLink {
get_options() {
let options = '';
if (this.df.get_options) {
options = this.df.get_options();
@@ -28,5 +28,5 @@ frappe.ui.form.ControlDynamicLink = frappe.ui.form.ControlLink.extend({
}

return options;
},
});
}
};

+ 9
- 9
frappe/public/js/frappe/form/controls/float.js View File

@@ -1,27 +1,27 @@
frappe.ui.form.ControlFloat = frappe.ui.form.ControlInt.extend({
parse: function(value) {
frappe.ui.form.ControlFloat = class ControlFloat extends frappe.ui.form.ControlInt {
parse(value) {
value = this.eval_expression(value);
return isNaN(parseFloat(value)) ? null : flt(value, this.get_precision());
},
}

format_for_input: function(value) {
format_for_input(value) {
var number_format;
if (this.df.fieldtype==="Float" && this.df.options && this.df.options.trim()) {
number_format = this.get_number_format();
}
var formatted_value = format_number(value, number_format, this.get_precision());
return isNaN(Number(value)) ? "" : formatted_value;
},
}

get_number_format: function() {
get_number_format() {
var currency = frappe.meta.get_field_currency(this.df, this.get_doc());
return get_number_format(currency);
},
}

get_precision: function() {
get_precision() {
// round based on field precision or float precision, else don't round
return this.df.precision || cint(frappe.boot.sysdefaults.float_precision, null);
}
});
};

frappe.ui.form.ControlPercent = frappe.ui.form.ControlFloat;

+ 12
- 12
frappe/public/js/frappe/form/controls/geolocation.js View File

@@ -1,11 +1,11 @@
frappe.provide('frappe.utils.utils');

frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({
horizontal: false,
frappe.ui.form.ControlGeolocation = class ControlGeolocation extends frappe.ui.form.ControlData {
static horizontal = false

make_wrapper() {
// Create the elements for map area
this._super();
super.make_wrapper();

let $input_wrapper = this.$wrapper.find('.control-input-wrapper');
this.map_id = frappe.dom.get_unique_id();
@@ -24,14 +24,14 @@ frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({
this.make_map();
});
}
},
}

make_map() {
this.bind_leaflet_map();
this.bind_leaflet_draw_control();
this.bind_leaflet_locate_control();
this.bind_leaflet_refresh_button();
},
}

format_for_input(value) {
if (!this.map) return;
@@ -65,7 +65,7 @@ frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({
} else if ((value===undefined) || (value == JSON.stringify(new L.FeatureGroup().toGeoJSON()))) {
this.locate_control.start();
}
},
}

bind_leaflet_map() {
var circleToGeoJSON = L.Circle.prototype.toGeoJSON;
@@ -97,13 +97,13 @@ frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({

L.tileLayer(frappe.utils.map_defaults.tiles,
frappe.utils.map_defaults.options).addTo(this.map);
},
}

bind_leaflet_locate_control() {
// To request location update and set location, sets current geolocation on load
this.locate_control = L.control.locate({position:'topright'});
this.locate_control.addTo(this.map);
},
}

bind_leaflet_draw_control() {
this.editableLayers = new L.FeatureGroup();
@@ -160,7 +160,7 @@ frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({
this.editableLayers.removeLayer(layer);
this.set_value(JSON.stringify(this.editableLayers.toGeoJSON()));
});
},
}

bind_leaflet_refresh_button() {
L.easyButton({
@@ -177,7 +177,7 @@ frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({
icon: 'fa fa-refresh'
}]
}).addTo(this.map);
},
}

add_non_group_layers(source_layer, target_group) {
// https://gis.stackexchange.com/a/203773
@@ -189,11 +189,11 @@ frappe.ui.form.ControlGeolocation = frappe.ui.form.ControlData.extend({
} else {
target_group.addLayer(source_layer);
}
},
}

clear_editable_layers() {
this.editableLayers.eachLayer((l)=>{
this.editableLayers.removeLayer(l);
});
}
});
};

+ 3
- 3
frappe/public/js/frappe/form/controls/heading.js View File

@@ -1,5 +1,5 @@
frappe.ui.form.ControlHeading = frappe.ui.form.ControlHTML.extend({
get_content: function() {
frappe.ui.form.ControlHeading = class ControlHeading extends frappe.ui.form.ControlHTML {
get_content() {
return "<h4>" + __(this.df.label) + "</h4>";
}
});
};

+ 12
- 12
frappe/public/js/frappe/form/controls/html.js View File

@@ -1,13 +1,13 @@
frappe.ui.form.ControlHTML = frappe.ui.form.Control.extend({
make: function() {
this._super();
frappe.ui.form.ControlHTML = class ControlHTML extends frappe.ui.form.Control {
make() {
super.make();
this.disp_area = this.wrapper;
},
refresh_input: function() {
}
refresh_input() {
var content = this.get_content();
if(content) this.$wrapper.html(content);
},
get_content: function() {
}
get_content() {
var content = this.df.options || "";
content = __(content);
try {
@@ -15,11 +15,11 @@ frappe.ui.form.ControlHTML = frappe.ui.form.Control.extend({
} catch (e) {
return content;
}
},
html: function(html) {
}
html(html) {
this.$wrapper.html(html || this.get_content());
},
set_value: function(html) {
}
set_value(html) {
if(html.appendTo) {
// jquery object
html.appendTo(this.$wrapper.empty());
@@ -29,4 +29,4 @@ frappe.ui.form.ControlHTML = frappe.ui.form.Control.extend({
this.html(html);
}
}
});
};

+ 5
- 5
frappe/public/js/frappe/form/controls/html_editor.js View File

@@ -1,13 +1,13 @@
frappe.ui.form.ControlHTMLEditor = frappe.ui.form.ControlMarkdownEditor.extend({
editor_class: 'html',
frappe.ui.form.ControlHTMLEditor = class ControlHTMLEditor extends frappe.ui.form.ControlMarkdownEditor {
static editor_class = 'html';
set_language() {
this.df.options = 'HTML';
this._super();
},
super.set_language();
}
update_preview() {
if (!this.markdown_preview) return;
let value = this.get_value() || '';
value = frappe.dom.remove_script_and_style(value);
this.markdown_preview.html(value);
}
});
};

+ 6
- 6
frappe/public/js/frappe/form/controls/image.js View File

@@ -1,12 +1,12 @@
frappe.ui.form.ControlImage = frappe.ui.form.Control.extend({
make: function() {
this._super();
frappe.ui.form.ControlImage = class ControlImage extends frappe.ui.form.Control {
make() {
super.make();
this.$wrapper.css({"margin": "0px"});
this.$body = $("<div></div>").appendTo(this.$wrapper)
.css({"margin-bottom": "10px"});
$('<div class="clearfix"></div>').appendTo(this.$wrapper);
},
refresh_input: function() {
}
refresh_input() {
this.$body.empty();

var doc = this.get_doc();
@@ -19,4 +19,4 @@ frappe.ui.form.ControlImage = frappe.ui.form.Control.extend({
}
return false;
}
});
};

+ 14
- 14
frappe/public/js/frappe/form/controls/int.js View File

@@ -1,13 +1,13 @@
frappe.ui.form.ControlInt = frappe.ui.form.ControlData.extend({
trigger_change_on_input_event: false,
make: function () {
this._super();
frappe.ui.form.ControlInt = class ControlInt extends frappe.ui.form.ControlData {
static trigger_change_on_input_event = false
make () {
super.make();
// $(this.label_area).addClass('pull-right');
// $(this.disp_area).addClass('text-right');
},
make_input: function () {
}
make_input () {
var me = this;
this._super();
super.make_input();
this.$input
// .addClass("text-right")
.on("focus", function () {
@@ -19,11 +19,11 @@ frappe.ui.form.ControlInt = frappe.ui.form.ControlData.extend({
}, 100);
return false;
});
},
validate: function (value) {
}
validate (value) {
return this.parse(value);
},
eval_expression: function (value) {
}
eval_expression (value) {
if (typeof value === 'string') {
if (value.match(/^[0-9+\-/* ]+$/)) {
// If it is a string containing operators
@@ -36,8 +36,8 @@ frappe.ui.form.ControlInt = frappe.ui.form.ControlData.extend({
}
}
return value;
},
parse: function (value) {
}
parse (value) {
return cint(this.eval_expression(value), null);
}
});
};

+ 28
- 28
frappe/public/js/frappe/form/controls/link.js View File

@@ -8,9 +8,9 @@ import Awesomplete from 'awesomplete';

frappe.ui.form.recent_link_validations = {};

frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
trigger_change_on_input_event: false,
make_input: function() {
frappe.ui.form.ControlLink = class ControlLink extends frappe.ui.form.ControlData {
static trigger_change_on_input_event = false
make_input() {
var me = this;
$(`<div class="link-field ui-front" style="position: relative;">
<input type="text" class="input-with-feedback form-control">
@@ -53,23 +53,23 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
this.setup_buttons();
this.setup_awesomeplete();
this.bind_change_event();
},
get_options: function() {
}
get_options() {
return this.df.options;
},
}
get_reference_doctype() {
// this is used to get the context in which link field is loaded
if (this.doctype) return this.doctype;
else {
return frappe.get_route && frappe.get_route()[0] === 'List' ? frappe.get_route()[1] : null;
}
},
setup_buttons: function() {
}
setup_buttons() {
if(this.only_input && !this.with_link_btn) {
this.$input_area.find(".link-btn").remove();
}
},
open_advanced_search: function() {
}
open_advanced_search() {
var doctype = this.get_options();
if(!doctype) return;
new frappe.ui.form.LinkSelector({
@@ -78,8 +78,8 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
txt: this.get_input_value()
});
return false;
},
new_doc: function() {
}
new_doc() {
var doctype = this.get_options();
var me = this;

@@ -109,8 +109,8 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
});

return false;
},
setup_awesomeplete: function() {
}
setup_awesomeplete() {
var me = this;

this.$input.cache = {};
@@ -284,7 +284,7 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
me.$input.val("");
}
});
},
}

merge_duplicates(results) {
// in case of result like this
@@ -301,7 +301,7 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
return [...newArr, currElem];
}, []);
// returns [{value: 'Manufacturer 1', 'description': 'mobile part 1, mobile part 2'}]
},
}

toggle_href(doctype) {
if (frappe.model.can_select(doctype) && !frappe.model.can_read(doctype)) {
@@ -310,7 +310,7 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
} else {
this.$input_area.find(".link-btn").removeClass('hide');
}
},
}

get_filter_description(filters) {
let doctype = this.get_options();
@@ -369,9 +369,9 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
.join(', ');

return __('Filters applied for {0}', [filter_string]);
},
}

set_custom_query: function(args) {
set_custom_query(args) {
var set_nulls = function(obj) {
$.each(obj, function(key, value) {
if(value!==undefined) {
@@ -439,8 +439,8 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
if(!args.filters) args.filters = {};
$.extend(args.filters, this.df.filters);
}
},
validate: function(value) {
}
validate(value) {
// validate the value just entered
if(this.df.options=="[Select]" || this.df.ignore_link_validation) {
return value;
@@ -448,8 +448,8 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({

return this.validate_link_and_fetch(this.df, this.get_options(),
this.docname, value);
},
validate_link_and_fetch: function(df, doctype, docname, value) {
}
validate_link_and_fetch(df, doctype, docname, value) {
if(value) {
return new Promise((resolve) => {
var fetch = '';
@@ -464,7 +464,7 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
this.fetch_and_validate_link(resolve, df, doctype, docname, value, fetch);
});
}
},
}

fetch_and_validate_link(resolve, df, doctype, docname, value, fetch) {
frappe.call({
@@ -487,15 +487,15 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
}
}
});
},
}

set_fetch_values: function(df, docname, fetch_values) {
set_fetch_values(df, docname, fetch_values) {
var fl = this.frm.fetch_dict[df.fieldname].fields;
for(var i=0; i < fl.length; i++) {
frappe.model.set_value(df.parent, docname, fl[i], fetch_values[i], df.fieldtype);
}
},
});
}
};

if (Awesomplete) {
Awesomplete.prototype.get_item = function(value) {


+ 11
- 11
frappe/public/js/frappe/form/controls/markdown_editor.js View File

@@ -1,10 +1,10 @@
frappe.ui.form.ControlMarkdownEditor = frappe.ui.form.ControlCode.extend({
editor_class: 'markdown',
frappe.ui.form.ControlMarkdownEditor = class ControlMarkdownEditor extends frappe.ui.form.ControlCode {
static editor_class = 'markdown'
make_ace_editor() {
this._super();
super.make_ace_editor();

this.ace_editor_target.wrap(`<div class="${this.editor_class}-container">`);
this.markdown_container = this.$input_wrapper.find(`.${this.editor_class}-container`);
this.markdown_container = this.$input_wrapper.find(`.${this.constructor.editor_class}-container`);

this.editor.getSession().setUseWrapMode(true);

@@ -27,26 +27,26 @@ frappe.ui.form.ControlMarkdownEditor = frappe.ui.form.ControlCode.extend({

this.markdown_preview = $(`<div class="${this.editor_class}-preview border rounded">`).hide();
this.markdown_container.append(this.markdown_preview);
},
}

set_language() {
this.df.options = 'Markdown';
this._super();
},
super.set_language();
}

update_preview() {
const value = this.get_value() || "";
this.markdown_preview.html(frappe.markdown(value));
},
}

set_formatted_input(value) {
this._super(value)
super.set_formatted_input(value)
.then(() => {
this.update_preview();
});
},
}

set_disp_area(value) {
this.disp_area && $(this.disp_area).text(value);
}
});
};

+ 20
- 20
frappe/public/js/frappe/form/controls/multicheck.js View File

@@ -1,10 +1,10 @@
frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({
frappe.ui.form.ControlMultiCheck = class ControlMultiCheck extends frappe.ui.form.Control {
// UI: multiple checkboxes
// Value: Array of values
// Options: Array of label/value/checked option objects

make() {
this._super();
super.make();
if (this.df.label) {
this.$label = $(`<label class="control-label">${this.df.label}</label>`).appendTo(this.wrapper);
}
@@ -15,18 +15,18 @@ frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({
const row = this.get_column_size() === 12 ? '' : 'row';
this.$checkbox_area = $(`<div class="checkbox-options ${row}"></div>`).appendTo(this.wrapper);
this.refresh();
},
}

refresh() {
this.set_options();
this.bind_checkboxes();
this.refresh_input();
this._super();
},
super.refresh();
}

refresh_input() {
this.select_options(this.selected_options);
},
}


set_options() {
@@ -47,7 +47,7 @@ frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({
} else {
this.make_checkboxes();
}
},
}

parse_df_options() {
if(Array.isArray(this.df.options)) {
@@ -62,7 +62,7 @@ frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({
} else {
this.options = [];
}
},
}

make_checkboxes() {
this.$load_state.hide();
@@ -78,7 +78,7 @@ frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({
this.setup_select_all();
}
this.set_checked_options();
},
}

bind_checkboxes() {
$(this.wrapper).on('change', ':checkbox', e => {
@@ -95,14 +95,14 @@ frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({
}
this.df.on_change && this.df.on_change();
});
},
}

set_checked_options() {
this.selected_options = this.options
.filter(o => o.checked)
.map(o => o.value);
this.select_options(this.selected_options);
},
}

setup_select_all() {
this.$select_buttons.show();
@@ -112,31 +112,31 @@ frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({
this.$select_buttons.find('.deselect-all').on('click', () => {
this.select_all(true);
});
},
}

select_all(deselect=false) {
$(this.wrapper).find(`:checkbox`).prop("checked", deselect).trigger('click');
},
}

select_options(selected_options) {
this.options.map(option => option.value).forEach(value => {
let $checkbox = $(this.wrapper).find(`:checkbox[data-unit="${value}"]`)[0];
if($checkbox) $checkbox.checked = selected_options.includes(value);
});
},
}

get_value() {
return this.selected_options;
},
}

get_checked_options() {
return this.get_value();
},
}

get_unchecked_options() {
return this.options.map(o => o.value)
.filter(value => !this.selected_options.includes(value));
},
}

get_checkbox_element(option) {
const column_size = this.get_column_size();
@@ -148,7 +148,7 @@ frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({
</label>
</div>
`);
},
}

get_select_buttons() {
return $(`
@@ -161,9 +161,9 @@ frappe.ui.form.ControlMultiCheck = frappe.ui.form.Control.extend({
</button>
</div>
`);
},
}

get_column_size() {
return 12 / (+this.df.columns || 1);
}
});
};

+ 10
- 10
frappe/public/js/frappe/form/controls/multiselect.js View File

@@ -1,8 +1,8 @@
import Awesomplete from 'awesomplete';

frappe.ui.form.ControlMultiSelect = frappe.ui.form.ControlAutocomplete.extend({
frappe.ui.form.ControlMultiSelect = class ControlMultiSelect extends frappe.ui.form.ControlAutocomplete {
get_awesomplete_settings() {
const settings = this._super();
const settings = super.get_awesomplete_settings();

return Object.assign(settings, {
filter: function(text, input) {
@@ -30,10 +30,10 @@ frappe.ui.form.ControlMultiSelect = frappe.ui.form.ControlAutocomplete.extend({
this.input.value = before + text + ", ";
}
});
},
}

get_value() {
let data = this._super();
let data = super.get_value();
// find value of label from option list and return actual value string
if (this.df.options && this.df.options.length && this.df.options[0].label) {
data = data.split(',').map(op => op.trim());
@@ -43,7 +43,7 @@ frappe.ui.form.ControlMultiSelect = frappe.ui.form.ControlAutocomplete.extend({
}).filter(n => n != null).join(', ');
}
return data;
},
}

set_formatted_input(value) {
if (!value) return;
@@ -54,15 +54,15 @@ frappe.ui.form.ControlMultiSelect = frappe.ui.form.ControlAutocomplete.extend({
return option ? option.label : val;
}).filter(n => n != null).join(', ');
}
this._super(value);
},
super.set_formatted_input(value);
}

get_values() {
const value = this.get_value() || '';
const values = value.split(/\s*,\s*/).filter(d => d);

return values;
},
}

get_data() {
let data;
@@ -70,7 +70,7 @@ frappe.ui.form.ControlMultiSelect = frappe.ui.form.ControlAutocomplete.extend({
data = this.df.get_data();
if (data) this.set_data(data);
} else {
data = this._super();
data = super.get_data();
}
const values = this.get_values() || [];

@@ -78,4 +78,4 @@ frappe.ui.form.ControlMultiSelect = frappe.ui.form.ControlAutocomplete.extend({
if(data) data.filter(d => !values.includes(d));
return data;
}
});
};

+ 15
- 15
frappe/public/js/frappe/form/controls/multiselect_list.js View File

@@ -1,5 +1,5 @@
frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
trigger_change_on_input_event: false,
frappe.ui.form.ControlMultiSelectList = class ControlMultiSelectList extends frappe.ui.form.ControlData {
static trigger_change_on_input_event = false
make_input() {
let template = `
<div class="multiselect-list dropdown">
@@ -84,7 +84,7 @@ frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
this._options = [];
this._selected_values = [];
this.highlighted = -1;
},
}

set_input_attributes() {
this.$list_wrapper
@@ -102,7 +102,7 @@ frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
if(this.df.input_class) {
this.$list_wrapper.addClass(this.df.input_class);
}
},
}

toggle_select_item($selectable_item) {
$selectable_item.toggleClass('selected');
@@ -116,7 +116,7 @@ frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
this.update_selected_values(value);
this.parse_validate_and_set_in_model('');
this.update_status();
},
}

set_value(value) {
if (!value) return Promise.resolve();
@@ -130,7 +130,7 @@ frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
this.parse_validate_and_set_in_model('');
this.update_status();
return Promise.resolve();
},
}

update_selected_values(value) {
this._selected_values = this._selected_values || [];
@@ -142,7 +142,7 @@ frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
this._selected_values = this._selected_values.filter(opt => opt.value !== value);
}
}
},
}

update_status() {
let text;
@@ -156,15 +156,15 @@ frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
text = __('{0} values selected', [this.values.length]);
}
this.set_status(text);
},
}

get_placeholder_text() {
return `<span class="text-extra-muted">${this.df.placeholder || ''}</span>`;
},
}

set_status(text) {
this.$list_wrapper.find('.status-text').html(text);
},
}

set_options() {
let promise = Promise.resolve();
@@ -200,7 +200,7 @@ frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
this._options = process_options(this.df.options);
}
return promise;
},
}

set_selectable_items(options) {
let html = options.map(option => {
@@ -222,11 +222,11 @@ frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
.html(html);

this.highlighted = -1;
},
}

get_value() {
return this.values;
},
}

highlight_item(value) {
this.highlighted += value;
@@ -246,7 +246,7 @@ frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
}
this._$last_highlighted = $($item).addClass('highlighted');
this.scroll_dropdown_if_needed($item);
},
}

scroll_dropdown_if_needed($item) {
if ($item.scrollIntoView) {
@@ -255,4 +255,4 @@ frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
$item.parentNode.scrollTop = $item.offsetTop - $item.parentNode.offsetTop;
}
}
});
};

+ 14
- 14
frappe/public/js/frappe/form/controls/multiselect_pills.js View File

@@ -1,8 +1,8 @@
import Awesomplete from 'awesomplete';

frappe.ui.form.ControlMultiSelectPills = frappe.ui.form.ControlAutocomplete.extend({
frappe.ui.form.ControlMultiSelectPills = class ControlMultiSelectPills extends frappe.ui.form.ControlAutocomplete {
make_input() {
this._super();
super.make_input();
this.$input_area = $(this.input_area);
this.$multiselect_wrapper = $('<div>')
.addClass('form-control table-multiselect')
@@ -35,7 +35,7 @@ frappe.ui.form.ControlMultiSelectPills = frappe.ui.form.ControlAutocomplete.exte
this.parse_validate_and_set_in_model('');
}
});
},
}

parse(value) {
if (value) {
@@ -43,7 +43,7 @@ frappe.ui.form.ControlMultiSelectPills = frappe.ui.form.ControlAutocomplete.exte
}

return this.rows;
},
}

validate(value) {
const rows = (value || []).slice();
@@ -66,12 +66,12 @@ frappe.ui.form.ControlMultiSelectPills = frappe.ui.form.ControlAutocomplete.exte
}

return rows;
},
}

set_formatted_input(value) {
this.rows = value || [];
this.set_pill_html(this.rows);
},
}

set_pill_html(values) {
const html = values
@@ -80,7 +80,7 @@ frappe.ui.form.ControlMultiSelectPills = frappe.ui.form.ControlAutocomplete.exte

this.$multiselect_wrapper.find('.tb-selected-value').remove();
this.$multiselect_wrapper.prepend(html);
},
}

get_pill_html(value) {
const encoded_value = encodeURIComponent(value);
@@ -90,10 +90,10 @@ frappe.ui.form.ControlMultiSelectPills = frappe.ui.form.ControlAutocomplete.exte
<span class="btn-remove">${frappe.utils.icon('close')}</span>
</button>
`;
},
}

get_awesomplete_settings() {
const settings = this._super();
const settings = super.get_awesomplete_settings();

return Object.assign(settings, {
filter: function(text, input) {
@@ -116,15 +116,15 @@ frappe.ui.form.ControlMultiSelectPills = frappe.ui.form.ControlAutocomplete.exte
return v;
}
});
},
}

get_value() {
return this.rows;
},
}

get_values() {
return this.rows;
},
}

get_data() {
let data;
@@ -140,7 +140,7 @@ frappe.ui.form.ControlMultiSelectPills = frappe.ui.form.ControlAutocomplete.exte
this.set_data(data);
}
} else {
data = this._super();
data = super.get_data();
}
const values = this.get_values() || [];

@@ -148,4 +148,4 @@ frappe.ui.form.ControlMultiSelectPills = frappe.ui.form.ControlAutocomplete.exte
if (data) data.filter(d => !values.includes(d));
return data;
}
});
};

+ 12
- 12
frappe/public/js/frappe/form/controls/password.js View File

@@ -1,11 +1,11 @@
frappe.ui.form.ControlPassword = frappe.ui.form.ControlData.extend({
input_type: "password",
make: function() {
this._super();
},
make_input: function() {
frappe.ui.form.ControlPassword = class ControlPassword extends frappe.ui.form.ControlData {
static input_type = "password"
make() {
super.make();
}
make_input() {
var me = this;
this._super();
super.make_input();
this.$input.parent().append($('<span class="password-strength-indicator indicator"></span>'));
this.$wrapper.find('.control-input-wrapper').append($('<p class="password-strength-message text-muted small hidden"></p>'));

@@ -18,8 +18,8 @@ frappe.ui.form.ControlPassword = frappe.ui.form.ControlData.extend({
me.get_password_strength(me.$input.val());
}, 500);
});
},
get_password_strength: function(value) {
}
get_password_strength(value) {
var me = this;
frappe.call({
type: 'POST',
@@ -41,10 +41,10 @@ frappe.ui.form.ControlPassword = frappe.ui.form.ControlData.extend({
}

});
},
set_strength_indicator: function(color) {
}
set_strength_indicator(color) {
var message = __("Include symbols, numbers and capital letters in the password");
this.indicator.removeClass().addClass('password-strength-indicator indicator ' + color);
this.message.html(message).removeClass('hidden');
}
});
};

+ 5
- 5
frappe/public/js/frappe/form/controls/rating.js View File

@@ -1,6 +1,6 @@
frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
frappe.ui.form.ControlRating = class ControlRating extends frappe.ui.form.ControlInt {
make_input() {
this._super();
super.make_input();
let stars = '';
[1, 2, 3, 4, 5].forEach(i => {
stars += `<svg class="icon icon-md" data-rating=${i}>
@@ -47,10 +47,10 @@ frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
this.set_input(star_value);
}
});
},
}
get_value() {
return cint(this.value, null);
},
}
set_formatted_input(value) {
let el = $(this.input_area).find('svg');
el.children('svg').prevObject.each( function(e) {
@@ -61,4 +61,4 @@ frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
}
});
}
});
};

+ 5
- 5
frappe/public/js/frappe/form/controls/read_only.js View File

@@ -1,8 +1,8 @@
frappe.ui.form.ControlReadOnly = frappe.ui.form.ControlData.extend({
get_status: function(explain) {
var status = this._super(explain);
frappe.ui.form.ControlReadOnly = class ControlReadOnly extends frappe.ui.form.ControlData {
get_status(explain) {
var status = super.get_status(explain);
if(status==="Write")
status = "Read";
return;
},
});
}
};

+ 18
- 18
frappe/public/js/frappe/form/controls/select.js View File

@@ -1,7 +1,7 @@
frappe.ui.form.ControlSelect = frappe.ui.form.ControlData.extend({
html_element: 'select',
make_input: function() {
this._super();
frappe.ui.form.ControlSelect = class ControlSelect extends frappe.ui.form.ControlData {
static html_element = 'select';
make_input() {
super.make_input();

const is_xs_input = this.df.input_class
&& this.df.input_class.includes('input-xs');
@@ -10,8 +10,8 @@ frappe.ui.form.ControlSelect = frappe.ui.form.ControlData.extend({

this.$input.addClass('ellipsis');
this.set_options();
},
set_icon: function(is_xs_input) {
}
set_icon(is_xs_input) {
const select_icon_html =
`<div class="select-icon ${is_xs_input ? 'xs' : ''}">
${frappe.utils.icon('select', is_xs_input ? 'xs' : 'sm')}
@@ -23,8 +23,8 @@ frappe.ui.form.ControlSelect = frappe.ui.form.ControlData.extend({
.addClass('flex align-center')
.append(select_icon_html);
}
},
set_placeholder: function(is_xs_input) {
}
set_placeholder(is_xs_input) {
const placeholder_html =
`<div class="placeholder ellipsis text-extra-muted ${is_xs_input ? 'xs' : ''}">
<span>${this.df.placeholder}</span>
@@ -36,14 +36,14 @@ frappe.ui.form.ControlSelect = frappe.ui.form.ControlData.extend({
}
this.toggle_placeholder();
this.$input && this.$input.on('select-change', () => this.toggle_placeholder());
},
set_formatted_input: function(value) {
}
set_formatted_input(value) {
// refresh options first - (new ones??)
if(value==null) value = '';
this.set_options(value);

// set in the input element
this._super(value);
super.set_formatted_input(value);

// check if the value to be set is selected
var input_value = '';
@@ -56,8 +56,8 @@ frappe.ui.form.ControlSelect = frappe.ui.form.ControlData.extend({
// model value must be same as whatever the input is
this.set_model_value(input_value);
}
},
set_options: function(value) {
}
set_options(value) {
// reset options, if something new is set
var options = this.df.options || [];

@@ -79,8 +79,8 @@ frappe.ui.form.ControlSelect = frappe.ui.form.ControlData.extend({
this.$input.val(selected);
}
}
},
get_file_attachment_list: function() {
}
get_file_attachment_list() {
if(!this.frm) return;
var fl = frappe.model.docinfo[this.frm.doctype][this.frm.docname];
if(fl && fl.attachments) {
@@ -94,12 +94,12 @@ frappe.ui.form.ControlSelect = frappe.ui.form.ControlData.extend({
this.set_description(__("Please attach a file first."));
return [""];
}
},
toggle_placeholder: function() {
}
toggle_placeholder() {
const input_set = Boolean(this.$input.find('option:selected').text());
this.$wrapper.find('.placeholder').toggle(!input_set);
}
});
};

// add <option> list to <select>
(function($) {


+ 49
- 41
frappe/public/js/frappe/form/controls/signature.js View File

@@ -1,31 +1,24 @@
frappe.ui.form.ControlSignature = frappe.ui.form.ControlData.extend({
saving: false,
loading: false,
make: function() {
frappe.ui.form.ControlSignature = class ControlSignature extends frappe.ui.form.ControlData {
make() {
var me = this;
this._super();
this.saving = false;
this.loading = false;
super.make();

// make jSignature field
this.body = $('<div class="signature-field"></div>').appendTo(me.wrapper);
this.load_lib().then(() => {
// make jSignature field
this.body = $('<div class="signature-field"></div>').appendTo(me.wrapper);

if (this.body.is(':visible')) {
this.make_pad();
} else {
$(document).on('frappe.ui.Dialog:shown', () => {
if (this.body.is(':visible')) {
this.make_pad();
});
}

this.img_wrapper = $(`<div class="signature-display">
<div class="missing-image attach-missing-image">
${frappe.utils.icon('restriction', 'md')}</i>
</div></div>`)
.appendTo(this.wrapper);
this.img = $("<img class='img-responsive attach-image-display'>")
.appendTo(this.img_wrapper).toggle(false);

},
make_pad: function() {
} else {
$(document).on('frappe.ui.Dialog:shown', () => {
this.make_pad();
});
}
});
}
make_pad() {
let width = this.body.width();
if (width > 0 && !this.$pad) {
this.$pad = this.body.jSignature({
@@ -51,8 +44,16 @@ frappe.ui.form.ControlSignature = frappe.ui.form.ControlData.extend({
});

}
},
refresh_input: function(e) {

this.img_wrapper = $(`<div class="signature-display">
<div class="missing-image attach-missing-image">
${frappe.utils.icon('restriction', 'md')}</i>
</div></div>`)
.appendTo(this.wrapper);
this.img = $("<img class='img-responsive attach-image-display'>")
.appendTo(this.img_wrapper).toggle(false);
}
refresh_input(e) {
// prevent to load the second time
this.make_pad();
this.$wrapper.find(".control-input").toggle(false);
@@ -61,8 +62,8 @@ frappe.ui.form.ControlSignature = frappe.ui.form.ControlData.extend({
if(this.get_status()=="Read") {
$(this.disp_area).toggle(false);
}
},
set_image: function(value) {
}
set_image(value) {
if(value) {
$(this.img_wrapper).find(".missing-image").toggle(false);
this.img.attr("src", value).toggle(true);
@@ -70,8 +71,8 @@ frappe.ui.form.ControlSignature = frappe.ui.form.ControlData.extend({
$(this.img_wrapper).find(".missing-image").toggle(true);
this.img.toggle(false);
}
},
load_pad: function() {
}
load_pad() {
// make sure not triggered during saving
if (this.saving) return;
// get value
@@ -95,8 +96,8 @@ frappe.ui.form.ControlSignature = frappe.ui.form.ControlData.extend({

this.loading = false;
}
},
set_editable: function(editable) {
}
set_editable(editable) {
this.$pad && this.$pad.toggle(editable);
this.img_wrapper.toggle(!editable);
if (this.$reset_button_wrapper) {
@@ -108,26 +109,33 @@ frappe.ui.form.ControlSignature = frappe.ui.form.ControlData.extend({
this.$reset_button_wrapper.removeClass('editing');
}
}
},
set_my_value: function(value) {
}
set_my_value(value) {
if (this.saving || this.loading) return;
this.saving = true;
this.set_value(value);
this.saving = false;
},
get_value: function() {
}
get_value() {
return this.value ? this.value: this.get_model_value();
},
}
// reset signature canvas
on_reset_sign: function() {
on_reset_sign() {
this.$pad.jSignature("reset");
this.set_my_value("");
},
}
// save signature value to model and display
on_save_sign: function() {
on_save_sign() {
if (this.saving || this.loading) return;
var base64_img = this.$pad.jSignature("getData");
this.set_my_value(base64_img);
this.set_image(this.get_value());
}
});

load_lib() {
if (!this.load_lib_promise) {
this.load_lib_promise = frappe.require('/assets/frappe/js/lib/jSignature.min.js');
}
return this.load_lib_promise;
}
};

+ 19
- 18
frappe/public/js/frappe/form/controls/table.js View File

@@ -1,8 +1,8 @@
import Grid from '../grid';

frappe.ui.form.ControlTable = frappe.ui.form.Control.extend({
make: function() {
this._super();
frappe.ui.form.ControlTable = class ControlTable extends frappe.ui.form.Control {
make() {
super.make();

// add title if prev field is not column / section heading or html
this.grid = new Grid({
@@ -84,19 +84,20 @@ frappe.ui.form.ControlTable = frappe.ui.form.Control.extend({
});
return false; // Prevent the default handler from running.
});
},
}
get_field(field_name) {
let fieldname;
field_name = field_name.toLowerCase();
this.grid.meta.fields.some(field => {
if (frappe.model.no_value_type.includes(field.fieldtype)) {
return false;
}

field_name = field_name.toLowerCase();
const is_field_matching = field_name => {
const is_field_matching = () => {
return (
field.fieldname.toLowerCase() === field_name ||
(field.label || '').toLowerCase() === field_name
(field.label || '').toLowerCase() === field_name ||
(__(field.label) || '').toLowerCase() === field_name
);
};

@@ -106,22 +107,22 @@ frappe.ui.form.ControlTable = frappe.ui.form.Control.extend({
}
});
return fieldname;
},
refresh_input: function() {
}
refresh_input() {
this.grid.refresh();
},
get_value: function() {
}
get_value() {
if(this.grid) {
return this.grid.get_data();
}
},
set_input: function( ) {
}
set_input( ) {
//
},
validate: function() {
}
validate() {
return this.get_value();
},
}
check_all_rows() {
this.$wrapper.find('.grid-row-check')[0].click();
}
});
};

+ 15
- 15
frappe/public/js/frappe/form/controls/table_multiselect.js View File

@@ -1,6 +1,6 @@
frappe.ui.form.ControlTableMultiSelect = frappe.ui.form.ControlLink.extend({
frappe.ui.form.ControlTableMultiSelect = class ControlTableMultiSelect extends frappe.ui.form.ControlLink {
make_input() {
this._super();
super.make_input();

this.$input_area.addClass('form-control table-multiselect');
this.$input.removeClass('form-control');
@@ -45,10 +45,10 @@ frappe.ui.form.ControlTableMultiSelect = frappe.ui.form.ControlLink.extend({
this.parse_validate_and_set_in_model('');
}
});
},
}
setup_buttons() {
this.$input_area.find('.link-btn').remove();
},
}
parse(value) {
const link_field = this.get_link_field();

@@ -65,11 +65,11 @@ frappe.ui.form.ControlTableMultiSelect = frappe.ui.form.ControlLink.extend({
}
this._rows_list = this.rows.map(row => row[link_field.fieldname]);
return this.rows;
},
}
get_model_value() {
let value = this._super();
let value = super.get_model_value();
return value ? value.filter(d => !d.__islocal) : value;
},
}
validate(value) {
const rows = (value || []).slice();

@@ -110,13 +110,13 @@ frappe.ui.form.ControlTableMultiSelect = frappe.ui.form.ControlLink.extend({
return rows;
}
});
},
}
set_formatted_input(value) {
this.rows = value || [];
const link_field = this.get_link_field();
const values = this.rows.map(row => row[link_field.fieldname]);
this.set_pill_html(values);
},
}
set_pill_html(values) {
const html = values
.map(value => this.get_pill_html(value))
@@ -124,7 +124,7 @@ frappe.ui.form.ControlTableMultiSelect = frappe.ui.form.ControlLink.extend({

this.$input_area.find('.tb-selected-value').remove();
this.$input_area.prepend(html);
},
}
get_pill_html(value) {
const encoded_value = encodeURIComponent(value);
return `
@@ -133,10 +133,10 @@ frappe.ui.form.ControlTableMultiSelect = frappe.ui.form.ControlLink.extend({
<span class="btn-remove">${frappe.utils.icon('close')}</span>
</button>
`;
},
}
get_options() {
return (this.get_link_field() || {}).options;
},
}
get_link_field() {
if (!this._link_field) {
const meta = frappe.get_meta(this.df.options);
@@ -146,8 +146,8 @@ frappe.ui.form.ControlTableMultiSelect = frappe.ui.form.ControlLink.extend({
}
}
return this._link_field;
},
custom_awesomplete_filter: function(awesomplete) {
}
custom_awesomplete_filter(awesomplete) {
let me = this;

awesomplete.filter = function(item) {
@@ -158,4 +158,4 @@ frappe.ui.form.ControlTableMultiSelect = frappe.ui.form.ControlLink.extend({
return true;
};
}
});
};

+ 13
- 13
frappe/public/js/frappe/form/controls/text.js View File

@@ -1,20 +1,20 @@
frappe.ui.form.ControlText = frappe.ui.form.ControlData.extend({
html_element: "textarea",
horizontal: false,
make_wrapper: function() {
this._super();
frappe.ui.form.ControlText = class ControlText extends frappe.ui.form.ControlData {
static html_element = "textarea"
static horizontal = false
make_wrapper() {
super.make_wrapper();
this.$wrapper.find(".like-disabled-input").addClass("for-description");
},
make_input: function() {
this._super();
}
make_input() {
super.make_input();
this.$input.css({'height': '300px'});
}
});
};

frappe.ui.form.ControlLongText = frappe.ui.form.ControlText;
frappe.ui.form.ControlSmallText = frappe.ui.form.ControlText.extend({
make_input: function() {
this._super();
frappe.ui.form.ControlSmallText = class ControlSmallText extends frappe.ui.form.ControlText {
make_input() {
super.make_input();
this.$input.css({'height': '150px'});
}
});
};

+ 13
- 13
frappe/public/js/frappe/form/controls/text_editor.js View File

@@ -68,22 +68,22 @@ CustomColor.tagName = "font";

Quill.register(CustomColor, true);

frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({
frappe.ui.form.ControlTextEditor = class ControlTextEditor extends frappe.ui.form.ControlCode {
make_wrapper() {
this._super();
},
super.make_wrapper();
}

make_input() {
this.has_input = true;
this.make_quill_editor();
},
}

make_quill_editor() {
if (this.quill) return;
this.quill_container = $('<div>').appendTo(this.input_area);
this.quill = new Quill(this.quill_container[0], this.get_quill_options());
this.bind_events();
},
}

bind_events() {
this.quill.on('text-change', frappe.utils.debounce((delta, oldDelta, source) => {
@@ -135,13 +135,13 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({

e.preventDefault();
});
},
}

is_quill_dirty(source) {
if (source === 'api') return false;
let input_value = this.get_input_value();
return this.value !== input_value;
},
}

get_quill_options() {
return {
@@ -152,7 +152,7 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({
},
theme: 'snow'
};
},
}

get_toolbar_options() {
return [
@@ -174,14 +174,14 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({
'delete-table',
]}],
];
},
}

parse(value) {
if (value == null) {
value = "";
}
return frappe.dom.remove_script_and_style(value);
},
}

set_formatted_input(value) {
if (!this.quill) return;
@@ -195,7 +195,7 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({
// set html without triggering a focus
const delta = this.quill.clipboard.convert({ html: value, text: '' });
this.quill.setContents(delta);
},
}

get_input_value() {
let value = this.quill ? this.quill.root.innerHTML : '';
@@ -211,9 +211,9 @@ frappe.ui.form.ControlTextEditor = frappe.ui.form.ControlCode.extend({
}

return value;
},
}

set_focus() {
this.quill.focus();
}
});
};

+ 25
- 25
frappe/public/js/frappe/form/controls/time.js View File

@@ -1,17 +1,17 @@
frappe.ui.form.ControlTime = frappe.ui.form.ControlDate.extend({
set_formatted_input: function(value) {
this._super(value);
},
make_input: function() {
frappe.ui.form.ControlTime = class ControlTime extends frappe.ui.form.ControlDate {
set_formatted_input(value) {
super.set_formatted_input(value);
}
make_input() {
this.timepicker_only = true;
this._super();
},
make_picker: function() {
super.make_input();
}
make_picker() {
this.set_time_options();
this.set_datepicker();
this.refresh();
},
set_time_options: function() {
}
set_time_options() {
let sysdefaults = frappe.boot.sysdefaults;

let time_format = sysdefaults && sysdefaults.time_format
@@ -38,9 +38,9 @@ frappe.ui.form.ControlTime = frappe.ui.form.ControlDate.extend({
keyboardNav: false,
todayButton: true
};
},
set_input: function(value) {
this._super(value);
}
set_input(value) {
super.set_input(value);
if (value
&& ((this.last_value && this.last_value !== this.value)
|| (!this.datepicker.selectedDates.length))) {
@@ -49,8 +49,8 @@ frappe.ui.form.ControlTime = frappe.ui.form.ControlDate.extend({
var date_obj = frappe.datetime.moment_to_date_obj(moment(value, time_format));
this.datepicker.selectDate(date_obj);
}
},
set_datepicker: function() {
}
set_datepicker() {
this.$input.datepicker(this.datepicker_options);
this.datepicker = this.$input.data('datepicker');

@@ -67,8 +67,8 @@ frappe.ui.form.ControlTime = frappe.ui.form.ControlDate.extend({
$tp.$secondsText.css('display', 'none');
$tp.$secondsText.prev().css('display', 'none');
}
},
set_description: function() {
}
set_description() {
const { description } = this.df;
const { time_zone } = frappe.sys_defaults;
if (!frappe.datetime.is_timezone_same()) {
@@ -78,20 +78,20 @@ frappe.ui.form.ControlTime = frappe.ui.form.ControlDate.extend({
this.df.description += '<br>' + time_zone;
}
}
this._super();
},
parse: function(value) {
super.set_description();
}
parse(value) {
if (value) {
return frappe.datetime.user_to_str(value, true);
}
},
format_for_input: function(value) {
}
format_for_input(value) {
if (value) {
return frappe.datetime.str_to_user(value, true);
}
return "";
},
validate: function(value) {
}
validate(value) {
if (value && !frappe.datetime.validate(value)) {
let sysdefaults = frappe.sys_defaults;
let time_format = sysdefaults && sysdefaults.time_format
@@ -101,4 +101,4 @@ frappe.ui.form.ControlTime = frappe.ui.form.ControlDate.extend({
}
return value;
}
});
};

+ 11
- 11
frappe/public/js/frappe/form/footer/footer.js View File

@@ -1,8 +1,8 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
import FormTimeline from "./form_timeline";
frappe.ui.form.Footer = Class.extend({
init: function(opts) {
frappe.ui.form.Footer = class FormFooter {
constructor(opts) {
$.extend(this, opts);
this.make();
this.make_comment_box();
@@ -11,15 +11,15 @@ frappe.ui.form.Footer = Class.extend({
$(this.frm.wrapper).on("render_complete", () => {
this.refresh();
});
},
make: function() {
}
make() {
this.wrapper = $(frappe.render_template("form_footer", {}))
.appendTo(this.parent);
this.wrapper.find(".btn-save").click(() => {
this.frm.save('Save', null, this);
});
},
make_comment_box: function() {
}
make_comment_box() {
this.frm.comment_box = frappe.ui.form.make_control({
parent: this.wrapper.find(".comment-box"),
render_input: true,
@@ -50,19 +50,19 @@ frappe.ui.form.Footer = Class.extend({
}
}
});
},
}
make_timeline() {
this.frm.timeline = new FormTimeline({
parent: this.wrapper.find(".timeline"),
frm: this.frm
});
},
refresh: function() {
}
refresh() {
if (this.frm.doc.__islocal) {
this.parent.addClass("hide");
} else {
this.parent.removeClass("hide");
this.frm.timeline.refresh();
}
},
});
}
};

+ 14
- 6
frappe/public/js/frappe/form/form.js View File

@@ -13,11 +13,11 @@ import './script_helpers';
import './sidebar/form_sidebar';
import './footer/footer';

frappe.ui.form.Controller = Class.extend({
init: function(opts) {
frappe.ui.form.Controller = class FormController {
constructor(opts) {
$.extend(this, opts);
}
});
};

frappe.ui.form.Form = class FrappeForm {
constructor(doctype, parent, in_form, doctype_layout_name) {
@@ -1125,9 +1125,17 @@ frappe.ui.form.Form = class FrappeForm {

add_custom_button(label, fn, group) {
// temp! old parameter used to be icon
if(group && group.indexOf("fa fa-")!==-1) group = null;
var btn = this.page.add_inner_button(label, fn, group);
if(btn) {
if (group && group.indexOf("fa fa-") !== -1)
group = null;

let btn = this.page.add_inner_button(label, fn, group);

if (btn) {
// Add actions as menu item in Mobile View
let menu_item_label = group ? `${group} > ${label}` : label;
let menu_item = this.page.add_menu_item(menu_item_label, fn, false);
menu_item.parent().addClass("hidden-lg");

this.custom_buttons[label] = btn;
}
return btn;


+ 89
- 89
frappe/public/js/frappe/form/layout.js View File

@@ -1,7 +1,7 @@
import '../class';

frappe.ui.form.Layout = Class.extend({
init: function (opts) {
frappe.ui.form.Layout = class Layout {
constructor (opts) {
this.views = {};
this.pages = [];
this.sections = [];
@@ -9,8 +9,8 @@ frappe.ui.form.Layout = Class.extend({
this.fields_dict = {};

$.extend(this, opts);
},
make: function() {
}
make() {
if (!this.parent && this.body) {
this.parent = this.body;
}
@@ -21,14 +21,14 @@ frappe.ui.form.Layout = Class.extend({
}
this.setup_tabbing();
this.render();
},
show_empty_form_message: function() {
}
show_empty_form_message() {
if (!(this.wrapper.find(".frappe-control:visible").length || this.wrapper.find(".section-head.collapsed").length)) {
this.show_message(__("This form does not have any input"));
}
},
}

get_doctype_fields: function() {
get_doctype_fields() {
let fields = [
this.get_new_name_field()
];
@@ -39,7 +39,7 @@ frappe.ui.form.Layout = Class.extend({
}

return fields;
},
}

get_new_name_field() {
return {
@@ -58,7 +58,7 @@ frappe.ui.form.Layout = Class.extend({
return 'None';
}
};
},
}

get_fields_from_layout() {
const fields = [];
@@ -68,9 +68,9 @@ frappe.ui.form.Layout = Class.extend({
fields.push(docfield);
}
return fields;
},
}

show_message: function(html, color) {
show_message(html, color) {
if (this.message_color) {
// remove previous color
this.message.removeClass(this.message_color);
@@ -86,8 +86,8 @@ frappe.ui.form.Layout = Class.extend({
} else {
this.message.empty().addClass('hidden');
}
},
render: function (new_fields) {
}
render (new_fields) {
var me = this;
var fields = new_fields || this.fields;

@@ -117,19 +117,19 @@ frappe.ui.form.Layout = Class.extend({
}
});

},
}

no_opening_section: function () {
no_opening_section () {
return (this.fields[0] && this.fields[0].fieldtype != "Section Break") || !this.fields.length;
},
}

setup_dashboard_section: function () {
setup_dashboard_section () {
if (this.no_opening_section()) {
this.fields.unshift({fieldtype: 'Section Break'});
}
},
}

replace_field: function (fieldname, df, render) {
replace_field (fieldname, df, render) {
df.fieldname = fieldname; // change of fieldname is avoided
if (this.fields_dict[fieldname] && this.fields_dict[fieldname].df) {
const fieldobj = this.init_field(df, render);
@@ -143,9 +143,9 @@ frappe.ui.form.Layout = Class.extend({
this.section.fields_dict[fieldname] = fieldobj;
this.refresh_fields([df]);
}
},
}

make_field: function (df, colspan, render) {
make_field (df, colspan, render) {
!this.section && this.make_section();
!this.column && this.make_column();

@@ -159,9 +159,9 @@ frappe.ui.form.Layout = Class.extend({
this.section.fields_list.push(fieldobj);
this.section.fields_dict[df.fieldname] = fieldobj;
fieldobj.section = this.section;
},
}

init_field: function (df, render = false) {
init_field (df, render = false) {
const fieldobj = frappe.ui.form.make_control({
df: df,
doctype: this.doctype,
@@ -174,9 +174,9 @@ frappe.ui.form.Layout = Class.extend({

fieldobj.layout = this;
return fieldobj;
},
}

make_page: function (df) { // eslint-disable-line no-unused-vars
make_page (df) { // eslint-disable-line no-unused-vars
var me = this,
head = $('<div class="form-clickable-section text-center">\
<a class="btn-fold h6 text-muted">' + __("Show more details") + '</a>\
@@ -200,13 +200,13 @@ frappe.ui.form.Layout = Class.extend({

this.section = null;
this.folded = true;
},
}

unfold: function () {
unfold () {
this.fold_btn.trigger('click');
},
}

make_section: function (df) {
make_section (df) {
this.section = new frappe.ui.form.Section(this, df);

// append to layout fields
@@ -216,16 +216,16 @@ frappe.ui.form.Layout = Class.extend({
}

this.column = null;
},
}

make_column: function (df) {
make_column (df) {
this.column = new frappe.ui.form.Column(this.section, df);
if (df && df.fieldname) {
this.fields_list.push(this.column);
}
},
}

refresh: function (doc) {
refresh (doc) {
var me = this;
if (doc) this.doc = doc;

@@ -250,9 +250,9 @@ frappe.ui.form.Layout = Class.extend({
// collapse sections
this.refresh_section_collapse();
}
},
}

refresh_sections: function() {
refresh_sections() {
// hide invisible sections
this.wrapper.find(".form-section:not(.hide-control)").each(function() {
const section = $(this).removeClass("empty-section visible-section");
@@ -266,9 +266,9 @@ frappe.ui.form.Layout = Class.extend({

this.frm && this.frm.dashboard.refresh();

},
}

refresh_fields: function (fields) {
refresh_fields (fields) {
let fieldnames = fields.map((field) => {
if (field.fieldname) return field.fieldname;
});
@@ -281,14 +281,14 @@ frappe.ui.form.Layout = Class.extend({
}
}
});
},
}

add_fields: function (fields) {
add_fields (fields) {
this.render(fields);
this.refresh_fields(fields);
},
}

refresh_section_collapse: function () {
refresh_section_collapse () {
if (!(this.sections && this.sections.length)) return;

for (var i = 0; i < this.sections.length; i++) {
@@ -308,9 +308,9 @@ frappe.ui.form.Layout = Class.extend({
section.collapse(collapse);
}
}
},
}

attach_doc_and_docfields: function (refresh) {
attach_doc_and_docfields (refresh) {
var me = this;
for (var i = 0, l = this.fields_list.length; i < l; i++) {
var fieldobj = this.fields_list[i];
@@ -328,14 +328,14 @@ frappe.ui.form.Layout = Class.extend({
}
refresh && fieldobj.df && fieldobj.refresh && fieldobj.refresh();
}
},
}

refresh_section_count: function () {
refresh_section_count () {
this.wrapper.find(".section-count-label:visible").each(function (i) {
$(this).html(i + 1);
});
},
setup_tabbing: function () {
}
setup_tabbing () {
var me = this;
this.wrapper.on("keydown", function (ev) {
if (ev.which == 9) {
@@ -346,8 +346,8 @@ frappe.ui.form.Layout = Class.extend({
return me.handle_tab(doctype, fieldname, ev.shiftKey);
}
});
},
handle_tab: function (doctype, fieldname, shift) {
}
handle_tab (doctype, fieldname, shift) {
var me = this,
grid_row = null,
prev = null,
@@ -405,8 +405,8 @@ frappe.ui.form.Layout = Class.extend({
}

return false;
},
focus_on_next_field: function (start_idx, fields) {
}
focus_on_next_field (start_idx, fields) {
// loop to find next eligible fields
for (var i = start_idx + 1, len = fields.length; i < len; i++) {
var field = fields[i];
@@ -427,11 +427,11 @@ frappe.ui.form.Layout = Class.extend({
}
}
}
},
is_visible: function (field) {
}
is_visible (field) {
return field.disp_status === "Write" && (field.$wrapper && field.$wrapper.is(":visible"));
},
set_focus: function (field) {
}
set_focus (field) {
// next is table, show the table
if (field.df.fieldtype=="Table") {
if (!field.grid.grid_rows.length) {
@@ -444,11 +444,11 @@ frappe.ui.form.Layout = Class.extend({
} else if (field.$input) {
field.$input.focus();
}
},
get_open_grid_row: function () {
}
get_open_grid_row () {
return $(".grid-row-open").data("grid_row");
},
refresh_dependency: function () {
}
refresh_dependency () {
// Resolve "depends_on" and show / hide accordingly
var me = this;

@@ -498,8 +498,8 @@ frappe.ui.form.Layout = Class.extend({
}

this.refresh_section_count();
},
set_dependant_property: function (condition, fieldname, property) {
}
set_dependant_property (condition, fieldname, property) {
let set_property = this.evaluate_depends_on_value(condition);
let value = set_property ? 1 : 0;
let form_obj;
@@ -520,8 +520,8 @@ frappe.ui.form.Layout = Class.extend({
form_obj.set_df_property(fieldname, property, value);
}
}
},
evaluate_depends_on_value: function (expression) {
}
evaluate_depends_on_value (expression) {
var out = null;
var doc = this.doc;

@@ -543,7 +543,7 @@ frappe.ui.form.Layout = Class.extend({

} else if (expression.substr(0, 5)=='eval:') {
try {
out = eval(expression.substr(5));
out = frappe.utils.eval(expression.substr(5), { doc });
if (parent && parent.istable && expression.includes('is_submittable')) {
out = true;
}
@@ -564,10 +564,10 @@ frappe.ui.form.Layout = Class.extend({

return out;
}
});
};

frappe.ui.form.Section = Class.extend({
init: function(layout, df) {
frappe.ui.form.Section = class FormSection {
constructor(layout, df) {
this.layout = layout;
this.df = df || {};
this.fields_list = [];
@@ -581,8 +581,8 @@ frappe.ui.form.Section = Class.extend({
};

this.refresh();
},
make: function() {
}
make() {
if (!this.layout.page) {
this.layout.page = $('<div class="form-page"></div>').appendTo(this.layout.wrapper);
}
@@ -609,9 +609,9 @@ frappe.ui.form.Section = Class.extend({

// for bc
this.body = $('<div class="section-body">').appendTo(this.wrapper);
},
}

make_head: function () {
make_head () {
this.head = $(`<div class="section-head">
${__(this.df.label)}
<span class="ml-2 collapse-indicator mb-1">
@@ -628,8 +628,8 @@ frappe.ui.form.Section = Class.extend({

this.indicator.show();
}
},
refresh: function() {
}
refresh() {
if (!this.df)
return;

@@ -642,8 +642,8 @@ frappe.ui.form.Section = Class.extend({
}

this.wrapper.toggleClass("hide-control", !!hide);
},
collapse: function (hide) {
}
collapse (hide) {
// unknown edge case
if (!(this.head && this.body)) {
return;
@@ -666,13 +666,13 @@ frappe.ui.form.Section = Class.extend({
f.refresh();
}
});
},
}

is_collapsed() {
return this.body.hasClass('hide');
},
}

has_missing_mandatory: function () {
has_missing_mandatory () {
var missing_mandatory = false;
for (var j = 0, l = this.fields_list.length; j < l; j++) {
var section_df = this.fields_list[j].df;
@@ -683,18 +683,18 @@ frappe.ui.form.Section = Class.extend({
}
return missing_mandatory;
}
});
};

frappe.ui.form.Column = Class.extend({
init: function(section, df) {
frappe.ui.form.Column = class FormColumn {
constructor(section, df) {
if (!df) df = {};

this.df = df;
this.section = section;
this.make();
this.resize_all_columns();
},
make: function () {
}
make () {
this.wrapper = $('<div class="form-column">\
<form>\
</form>\
@@ -708,8 +708,8 @@ frappe.ui.form.Column = Class.extend({
$('<label class="control-label">' + __(this.df.label)
+ '</label>').appendTo(this.wrapper);
}
},
resize_all_columns: function () {
}
resize_all_columns () {
// distribute all columns equally
var colspan = cint(12 / this.section.wrapper.find(".form-column").length);

@@ -717,8 +717,8 @@ frappe.ui.form.Column = Class.extend({
.addClass("form-column")
.addClass("col-sm-" + colspan);

},
refresh: function () {
}
refresh () {
this.section.refresh();
}
});
};

+ 9
- 9
frappe/public/js/frappe/form/link_selector.js View File

@@ -1,8 +1,8 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.ui.form.LinkSelector = Class.extend({
init: function (opts) {
frappe.ui.form.LinkSelector = class LinkSelector {
constructor (opts) {
/* help: Options: doctype, get_query, target */
$.extend(this, opts);

@@ -14,8 +14,8 @@ frappe.ui.form.LinkSelector = Class.extend({
} else {
this.make();
}
},
make: function () {
}
make () {
var me = this;

this.start = 0;
@@ -54,8 +54,8 @@ frappe.ui.form.LinkSelector = Class.extend({
});
this.dialog.show();
this.search();
},
search: function () {
}
search () {
var args = {
txt: this.dialog.fields_dict.txt.get_value(),
searchfield: "name",
@@ -129,8 +129,8 @@ frappe.ui.form.LinkSelector = Class.extend({

}, this.dialog.get_primary_btn());

},
set_in_grid: function (value) {
}
set_in_grid (value) {
var me = this, updated = false;
var d = null;
if (this.qty_fieldname) {
@@ -174,7 +174,7 @@ frappe.ui.form.LinkSelector = Class.extend({
frappe.show_alert(__("{0} added", [value]));
}
}
});
};

frappe.link_search = function (doctype, args, callback, btn) {
if (!args) {


+ 35
- 35
frappe/public/js/frappe/form/quick_entry.js View File

@@ -18,16 +18,16 @@ frappe.ui.form.make_quick_entry = (doctype, after_insert, init_callback, doc, fo
return frappe.quick_entry.setup();
};

frappe.ui.form.QuickEntryForm = Class.extend({
init: function(doctype, after_insert, init_callback, doc, force) {
frappe.ui.form.QuickEntryForm = class QuickEntryForm {
constructor(doctype, after_insert, init_callback, doc, force) {
this.doctype = doctype;
this.after_insert = after_insert;
this.init_callback = init_callback;
this.doc = doc;
this.force = force ? force : false;
},
}

setup: function() {
setup() {
return new Promise(resolve => {
frappe.model.with_doctype(this.doctype, () => {
this.check_quick_entry_doc();
@@ -47,9 +47,9 @@ frappe.ui.form.QuickEntryForm = Class.extend({
}
});
});
},
}

set_meta_and_mandatory_fields: function() {
set_meta_and_mandatory_fields() {
this.meta = frappe.get_meta(this.doctype);
let fields = this.meta.fields;

@@ -57,15 +57,15 @@ frappe.ui.form.QuickEntryForm = Class.extend({
this.mandatory = fields.filter(df => {
return ((df.reqd || df.bold || df.allow_in_quick_entry) && !df.read_only);
});
},
}

check_quick_entry_doc: function() {
check_quick_entry_doc() {
if (!this.doc) {
this.doc = frappe.model.get_new_doc(this.doctype, null, null, true);
}
},
}

is_quick_entry: function() {
is_quick_entry() {
if(this.meta.quick_entry != 1) {
return false;
}
@@ -77,33 +77,33 @@ frappe.ui.form.QuickEntryForm = Class.extend({
}

return true;
},
}

too_many_mandatory_fields: function() {
too_many_mandatory_fields() {
if(this.mandatory.length > 7) {
// too many fields, show form
return true;
}
return false;
},
}

has_child_table: function(){
has_child_table(){
if($.map(this.mandatory, function(d) {
return d.fieldtype==='Table' ? d : null; }).length) {
// has mandatory table, quit!
return true;
}
return false;
},
}

validate_for_prompt_autoname: function() {
validate_for_prompt_autoname() {
if(this.meta.autoname && this.meta.autoname.toLowerCase()==='prompt') {
this.mandatory = [{fieldname:'__newname', label:__('{0} Name', [this.meta.name]),
reqd: 1, fieldtype:'Data'}].concat(this.mandatory);
}
},
}

render_dialog: function() {
render_dialog() {
var me = this;
this.dialog = new frappe.ui.Dialog({
title: __("New {0}", [__(this.doctype)]),
@@ -134,9 +134,9 @@ frappe.ui.form.QuickEntryForm = Class.extend({
if (this.init_callback) {
this.init_callback(this.dialog);
}
},
}

register_primary_action: function() {
register_primary_action() {
var me = this;
this.dialog.set_primary_action(__('Save'), function() {
if(me.dialog.working) {
@@ -152,9 +152,9 @@ frappe.ui.form.QuickEntryForm = Class.extend({
});
}
});
},
}

insert: function() {
insert() {
let me = this;
return new Promise(resolve => {
me.update_doc();
@@ -202,9 +202,9 @@ frappe.ui.form.QuickEntryForm = Class.extend({
freeze: true
});
});
},
}

submit: function(doc) {
submit(doc) {
var me = this;
frappe.call({
method: "frappe.client.submit",
@@ -229,9 +229,9 @@ frappe.ui.form.QuickEntryForm = Class.extend({
cur_frm && cur_frm.reload_doc();
}
});
},
}

open_form_if_not_list: function() {
open_form_if_not_list() {
let route = frappe.get_route();
let doc = this.dialog.doc;
if (route && !(route[0]==='List' && route[1]===doc.doctype)) {
@@ -239,9 +239,9 @@ frappe.ui.form.QuickEntryForm = Class.extend({
() => frappe.set_route('Form', doc.doctype, doc.name)
]);
}
},
}

update_doc: function(){
update_doc(){
var me = this;
var data = this.dialog.get_values(true);
$.each(data, function(key, value) {
@@ -250,9 +250,9 @@ frappe.ui.form.QuickEntryForm = Class.extend({
}
});
return this.dialog.doc;
},
}

open_doc: function(set_hooks) {
open_doc(set_hooks) {
this.dialog.hide();
this.update_doc();
if (set_hooks && this.after_insert) {
@@ -262,17 +262,17 @@ frappe.ui.form.QuickEntryForm = Class.extend({
};
}
frappe.set_route('Form', this.doctype, this.doc.name);
},
}

render_edit_in_full_page_link: function() {
render_edit_in_full_page_link() {
var me = this;
this.dialog.add_custom_action(
`${frappe.utils.icon('edit', 'xs')} ${__("Edit in full page")}`,
() => me.open_doc(true)
);
},
}

set_defaults: function() {
set_defaults() {
var me = this;
// set defaults
$.each(this.dialog.fields_dict, function(fieldname, field) {
@@ -284,4 +284,4 @@ frappe.ui.form.QuickEntryForm = Class.extend({
}
});
}
});
};

+ 17
- 17
frappe/public/js/frappe/form/script_manager.js View File

@@ -69,15 +69,15 @@ frappe.ui.form.trigger = function(doctype, fieldname) {
cur_frm.script_manager.trigger(fieldname, doctype);
}

frappe.ui.form.ScriptManager = Class.extend({
init: function(opts) {
frappe.ui.form.ScriptManager = class ScriptManager {
constructor(opts) {
$.extend(this, opts);
},
make: function(ControllerClass) {
}
make(ControllerClass) {
this.frm.cscript = $.extend(this.frm.cscript,
new ControllerClass({frm: this.frm}));
},
trigger: function(event_name, doctype, name) {
}
trigger(event_name, doctype, name) {
// trigger all the form level events that
// are bound to this event_name
let me = this;
@@ -130,12 +130,12 @@ frappe.ui.form.ScriptManager = Class.extend({

// run them serially
return frappe.run_serially(tasks);
},
has_handlers: function(event_name, doctype) {
}
has_handlers(event_name, doctype) {
let handlers = this.get_handlers(event_name, doctype);
return handlers && (handlers.old_style.length || handlers.new_style.length);
},
get_handlers: function(event_name, doctype) {
}
get_handlers(event_name, doctype) {
// returns list of all functions to be called (old style and new style)
let me = this;
let handlers = {
@@ -154,8 +154,8 @@ frappe.ui.form.ScriptManager = Class.extend({
handlers.old_style.push("custom_" + event_name);
}
return handlers;
},
setup: function() {
}
setup() {
const doctype = this.frm.meta;
const me = this;
let client_script;
@@ -206,8 +206,8 @@ frappe.ui.form.ScriptManager = Class.extend({
doctype.__css && frappe.dom.set_style(doctype.__css);

this.trigger('setup');
},
log_error: function(caller, e) {
}
log_error(caller, e) {
frappe.show_alert({message: __("Error in Client Script."), indicator: "error"});
console.group && console.group();
console.log("----- error in client script -----");
@@ -217,8 +217,8 @@ frappe.ui.form.ScriptManager = Class.extend({
console.trace && console.trace();
console.log("----- end of error message -----");
console.group && console.groupEnd();
},
copy_from_first_row: function(parentfield, current_row, fieldnames) {
}
copy_from_first_row(parentfield, current_row, fieldnames) {
var data = this.frm.doc[parentfield];
if(data.length===1 || data[0]===current_row) return;

@@ -231,4 +231,4 @@ frappe.ui.form.ScriptManager = Class.extend({
data[0][fieldname]);
});
}
});
};

+ 22
- 22
frappe/public/js/frappe/form/sidebar/assign_to.js View File

@@ -3,23 +3,23 @@



frappe.ui.form.AssignTo = Class.extend({
init: function(opts) {
frappe.ui.form.AssignTo = class AssignTo {
constructor(opts) {
$.extend(this, opts);
this.btn = this.parent.find(".add-assignment-btn").on("click", () => this.add());
this.btn_wrapper = this.btn.parent();

this.refresh();
},
refresh: function() {
}
refresh() {
if(this.frm.doc.__islocal) {
this.parent.toggle(false);
return;
}
this.parent.toggle(true);
this.render(this.frm.get_docinfo().assignments);
},
render: function(assignments) {
}
render(assignments) {
this.frm.get_docinfo().assignments = assignments;

let assignments_wrapper = this.parent.find('.assignments');
@@ -42,8 +42,8 @@ frappe.ui.form.AssignTo = Class.extend({
frm: this.frm
});
});
},
add: function() {
}
add() {
var me = this;

if (this.frm.is_new()) {
@@ -64,8 +64,8 @@ frappe.ui.form.AssignTo = Class.extend({
}
me.assign_to.dialog.clear();
me.assign_to.dialog.show();
},
remove: function(owner) {
}
remove(owner) {
if (this.frm.is_new()) {
frappe.throw(__("Please save the document before removing assignment"));
return;
@@ -79,17 +79,17 @@ frappe.ui.form.AssignTo = Class.extend({
this.render(assignments);
});
}
});
};


frappe.ui.form.AssignToDialog = Class.extend({
init: function(opts) {
frappe.ui.form.AssignToDialog = class AssignToDialog {
constructor(opts) {
$.extend(this, opts);

this.make();
this.set_description_from_doc();
},
make: function() {
}
make() {
let me = this;

me.dialog = new frappe.ui.Dialog({
@@ -126,8 +126,8 @@ frappe.ui.form.AssignToDialog = Class.extend({
}
},
});
},
assign_to_me: function() {
}
assign_to_me() {
let me = this;
let assign_to = [];

@@ -136,15 +136,15 @@ frappe.ui.form.AssignToDialog = Class.extend({
}

me.dialog.set_value("assign_to", assign_to);
},
set_description_from_doc: function() {
}
set_description_from_doc() {
let me = this;

if (me.frm && me.frm.meta.title_field) {
me.dialog.set_value("description", me.frm.doc[me.frm.meta.title_field]);
}
},
get_fields: function() {
}
get_fields() {
let me = this;

return [
@@ -206,7 +206,7 @@ frappe.ui.form.AssignToDialog = Class.extend({
}
];
}
});
};


frappe.ui.form.AssignmentDialog = class {


+ 33
- 33
frappe/public/js/frappe/form/sidebar/attachments.js View File

@@ -1,20 +1,20 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.ui.form.Attachments = Class.extend({
init: function(opts) {
frappe.ui.form.Attachments = class Attachments {
constructor(opts) {
$.extend(this, opts);
this.make();
},
make: function() {
}
make() {
var me = this;
this.parent.find(".add-attachment-btn").click(function() {
me.new_attachment();
});
this.add_attachment_wrapper = this.parent.find(".add_attachment").parent();
this.attachments_label = this.parent.find(".attachments-label");
},
max_reached: function(raise_exception=false) {
}
max_reached(raise_exception=false) {
const attachment_count = Object.keys(this.get_attachments()).length;
const attachment_limit = this.frm.meta.max_attachments;
if (attachment_limit && attachment_count >= attachment_limit) {
@@ -27,8 +27,8 @@ frappe.ui.form.Attachments = Class.extend({
return true;
}
return false;
},
refresh: function() {
}
refresh() {
var me = this;

if(this.frm.doc.__islocal) {
@@ -51,11 +51,11 @@ frappe.ui.form.Attachments = Class.extend({
this.attachments_label.removeClass("has-attachments");
}

},
get_attachments: function() {
}
get_attachments() {
return this.frm.get_docinfo().attachments;
},
add_attachment: function(attachment) {
}
add_attachment(attachment) {
var file_name = attachment.file_name;
var file_url = this.get_file_url(attachment);
var fileid = attachment.name;
@@ -95,8 +95,8 @@ frappe.ui.form.Attachments = Class.extend({
))
.insertAfter(this.attachments_label.addClass("has-attachments"));

},
get_file_url: function(attachment) {
}
get_file_url(attachment) {
var file_url = attachment.file_url;
if (!file_url) {
if (attachment.file_name.indexOf('files/') === 0) {
@@ -108,8 +108,8 @@ frappe.ui.form.Attachments = Class.extend({
}
// hash is not escaped, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
return encodeURI(file_url).replace(/#/g, '%23');
},
get_file_id_from_file_url: function(file_url) {
}
get_file_id_from_file_url(file_url) {
var fid;
$.each(this.get_attachments(), function(i, attachment) {
if (attachment.file_url === file_url) {
@@ -118,11 +118,11 @@ frappe.ui.form.Attachments = Class.extend({
}
});
return fid;
},
remove_attachment_by_filename: function(filename, callback) {
}
remove_attachment_by_filename(filename, callback) {
this.remove_attachment(this.get_file_id_from_file_url(filename), callback);
},
remove_attachment: function(fileid, callback) {
}
remove_attachment(fileid, callback) {
if (!fileid) {
if (callback) callback();
return;
@@ -147,8 +147,8 @@ frappe.ui.form.Attachments = Class.extend({
if (callback) callback();
}
});
},
new_attachment: function(fieldname) {
}
new_attachment(fieldname) {
if (this.dialog) {
// remove upload dialog
this.dialog.$wrapper.remove();
@@ -163,15 +163,15 @@ frappe.ui.form.Attachments = Class.extend({
this.attachment_uploaded(file_doc);
}
});
},
get_args: function() {
}
get_args() {
return {
from_form: 1,
doctype: this.frm.doctype,
docname: this.frm.docname,
}
},
attachment_uploaded: function(attachment) {
}
attachment_uploaded(attachment) {
this.dialog && this.dialog.hide();
this.update_attachment(attachment);
this.frm.sidebar.reload_docinfo();
@@ -179,22 +179,22 @@ frappe.ui.form.Attachments = Class.extend({
if(this.fieldname) {
this.frm.set_value(this.fieldname, attachment.file_url);
}
},
update_attachment: function(attachment) {
}
update_attachment(attachment) {
if(attachment.name) {
this.add_to_attachments(attachment);
this.refresh();
}
},
add_to_attachments: function (attachment) {
}
add_to_attachments (attachment) {
var form_attachments = this.get_attachments();
for(var i in form_attachments) {
// prevent duplicate
if(form_attachments[i]["name"] === attachment.name) return;
}
form_attachments.push(attachment);
},
remove_fileid: function(fileid) {
}
remove_fileid(fileid) {
var attachments = this.get_attachments();
var new_attachments = [];
$.each(attachments, function(i, attachment) {
@@ -205,4 +205,4 @@ frappe.ui.form.Attachments = Class.extend({
this.frm.get_docinfo().attachments = new_attachments;
this.refresh();
}
});
};

+ 18
- 18
frappe/public/js/frappe/form/sidebar/share.js View File

@@ -3,15 +3,15 @@



frappe.ui.form.Share = Class.extend({
init: function(opts) {
frappe.ui.form.Share = class Share {
constructor(opts) {
$.extend(this, opts);
this.shares = this.parent.find('.shares');
},
refresh: function() {
}
refresh() {
this.render_sidebar();
},
render_sidebar: function() {
}
render_sidebar() {
const shared = this.shared || this.frm.get_docinfo().shared;
const shared_users = shared.filter(Boolean).map(s => s.user);

@@ -33,8 +33,8 @@ frappe.ui.form.Share = Class.extend({
this.shares.show();
// REDESIGN-TODO: handle "shared with everyone"
this.shares.append(frappe.avatar_group(shared_users, 5, {'align': 'left', 'overlap': true}));
},
show: function() {
}
show() {
var me = this;
var d = new frappe.ui.Dialog({
title: __("Share {0} with", [this.frm.doc.name]),
@@ -62,8 +62,8 @@ frappe.ui.form.Share = Class.extend({
}

d.show();
},
render_shared: function(shared) {
}
render_shared(shared) {
if(shared)
this.shared = shared;
var d = this.dialog;
@@ -88,8 +88,8 @@ frappe.ui.form.Share = Class.extend({
// if cannot share, disable sharing settings.
$(d.body).find(".edit-share").prop("disabled", true);
}
},
make_user_input: function() {
}
make_user_input() {
// make add-user input
this.dialog.share_with = frappe.ui.form.make_control({
parent: $(this.dialog.body).find(".input-wrapper-add-share"),
@@ -107,8 +107,8 @@ frappe.ui.form.Share = Class.extend({
render_input: true
});

},
add_share_button: function() {
}
add_share_button() {
var me = this, d = this.dialog;
$(d.body).find(".btn-add-share").on("click", function() {
var user = d.share_with.get_value();
@@ -142,8 +142,8 @@ frappe.ui.form.Share = Class.extend({
}
});
});
},
set_edit_share_events: function() {
}
set_edit_share_events() {
var me = this, d = this.dialog;
$(d.body).find(".edit-share").on("click", function() {
var user = $(this).parents(".shared-user:first").attr("data-user") || "",
@@ -186,5 +186,5 @@ frappe.ui.form.Share = Class.extend({
}
});
});
},
});
}
};

+ 15
- 15
frappe/public/js/frappe/form/workflow.js View File

@@ -1,8 +1,8 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.ui.form.States = Class.extend({
init: function(opts) {
frappe.ui.form.States = class FormStates {
constructor(opts) {
$.extend(this, opts);
this.state_fieldname = frappe.workflow.get_state_fieldname(this.frm.doctype);

@@ -16,9 +16,9 @@ frappe.ui.form.States = Class.extend({
$(this.frm.wrapper).bind("render_complete", function() {
me.refresh();
});
},
}

setup_help: function() {
setup_help() {
var me = this;
this.frm.page.add_action_item(__("Help"), function() {
frappe.workflow.setup(me.frm.doctype);
@@ -44,9 +44,9 @@ frappe.ui.form.States = Class.extend({
d.show();
});
}, true);
},
}

refresh: function() {
refresh() {
// hide if its not yet saved
if(this.frm.doc.__islocal) {
this.set_default_state();
@@ -60,9 +60,9 @@ frappe.ui.form.States = Class.extend({
// show actions from that state
this.show_actions(state);
}
},
}

show_actions: function() {
show_actions() {
var added = false;
var me = this;

@@ -107,28 +107,28 @@ frappe.ui.form.States = Class.extend({
this.setup_btn(added);
});

},
}

setup_btn: function(action_added) {
setup_btn(action_added) {
if(action_added) {
this.frm.page.btn_primary.addClass("hide");
this.frm.page.btn_secondary.addClass("hide");
this.frm.toolbar.current_status = "";
this.setup_help();
}
},
}

set_default_state: function() {
set_default_state() {
var default_state = frappe.workflow.get_default_state(this.frm.doctype, this.frm.doc.docstatus);
if(default_state) {
this.frm.set_value(this.state_fieldname, default_state);
}
},
}

get_state: function() {
get_state() {
if(!this.frm.doc[this.state_fieldname]) {
this.set_default_state();
}
return this.frm.doc[this.state_fieldname];
}
});
};

+ 9
- 9
frappe/public/js/frappe/module_editor.js View File

@@ -1,10 +1,10 @@
frappe.ModuleEditor = Class.extend({
init: function(frm, wrapper) {
frappe.ModuleEditor = class ModuleEditor {
constructor(frm, wrapper) {
this.wrapper = $('<div class="row module-block-list"></div>').appendTo(wrapper);
this.frm = frm;
this.make();
},
make: function() {
}
make() {
var me = this;
this.frm.doc.__onload.all_modules.forEach(function(m) {
$(repl('<div class="col-sm-6"><div class="checkbox">\
@@ -12,15 +12,15 @@ frappe.ModuleEditor = Class.extend({
%(module)s</label></div></div>', {module: m})).appendTo(me.wrapper);
});
this.bind();
},
refresh: function() {
}
refresh() {
var me = this;
this.wrapper.find(".block-module-check").prop("checked", true);
$.each(this.frm.doc.block_modules, function(i, d) {
me.wrapper.find(".block-module-check[data-module='"+ d.module +"']").prop("checked", false);
});
},
bind: function() {
}
bind() {
var me = this;
this.wrapper.on("change", ".block-module-check", function() {
var module = $(this).attr('data-module');
@@ -36,4 +36,4 @@ frappe.ModuleEditor = Class.extend({
}
});
}
});
};

+ 1
- 1
frappe/public/js/frappe/ui/chart.js View File

@@ -1,3 +1,3 @@
import { Chart } from "frappe-charts"
import { Chart } from "frappe-charts/dist/frappe-charts.esm";

frappe.Chart = Chart;

+ 1
- 0
frappe/public/js/frappe/ui/dialog.js View File

@@ -232,6 +232,7 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup {
this.get_minimize_btn().html(frappe.utils.icon(icon));
this.on_minimize_toggle && this.on_minimize_toggle(this.is_minimized);
this.header.find('.modal-title').toggleClass('cursor-pointer');
$("body").css("overflow", this.is_minimized ? "auto" : "hidden");
}

add_custom_action(label, action, css_class=null) {


+ 31
- 31
frappe/public/js/frappe/ui/field_group.js View File

@@ -2,11 +2,11 @@ import '../form/layout';

frappe.provide('frappe.ui');

frappe.ui.FieldGroup = frappe.ui.form.Layout.extend({
init: function(opts) {
$.extend(this, opts);
frappe.ui.FieldGroup = class FieldGroup extends frappe.ui.form.Layout {
constructor(opts) {
super(opts);
this.first_button = false;
this.dirty = false;
this._super();
$.each(this.fields || [], function(i, f) {
if(!f.fieldname && f.label) {
f.fieldname = f.label.replace(/ /g, "_").toLowerCase();
@@ -15,11 +15,11 @@ frappe.ui.FieldGroup = frappe.ui.form.Layout.extend({
if(this.values) {
this.set_values(this.values);
}
},
make: function() {
}
make() {
var me = this;
if(this.fields) {
this._super();
super.make();
this.refresh();
// set default
$.each(this.fields_list, function(i, field) {
@@ -50,9 +50,9 @@ frappe.ui.FieldGroup = frappe.ui.form.Layout.extend({
});

}
},
first_button: false,
focus_on_first_input: function() {
}
focus_on_first_input() {
if(this.no_focus) return;
$.each(this.fields_list, function(i, f) {
if(!in_list(['Date', 'Datetime', 'Time', 'Check'], f.df.fieldtype) && f.set_focus) {
@@ -60,8 +60,8 @@ frappe.ui.FieldGroup = frappe.ui.form.Layout.extend({
return false;
}
});
},
catch_enter_as_submit: function() {
}
catch_enter_as_submit() {
var me = this;
$(this.body).find('input[type="text"], input[type="password"], select').keypress(function(e) {
if(e.which==13) {
@@ -71,15 +71,15 @@ frappe.ui.FieldGroup = frappe.ui.form.Layout.extend({
}
}
});
},
get_input: function(fieldname) {
}
get_input(fieldname) {
var field = this.fields_dict[fieldname];
return $(field.txt ? field.txt : field.input);
},
get_field: function(fieldname) {
}
get_field(fieldname) {
return this.fields_dict[fieldname];
},
get_values: function(ignore_errors) {
}
get_values(ignore_errors) {
var ret = {};
var errors = [];
for (var key in this.fields_dict) {
@@ -110,12 +110,12 @@ frappe.ui.FieldGroup = frappe.ui.form.Layout.extend({
return null;
}
return ret;
},
get_value: function(key) {
}
get_value(key) {
var f = this.fields_dict[key];
return f && (f.get_value ? f.get_value() : null);
},
set_value: function(key, val){
}
set_value(key, val){
return new Promise(resolve => {
var f = this.fields_dict[key];
if(f) {
@@ -128,11 +128,11 @@ frappe.ui.FieldGroup = frappe.ui.form.Layout.extend({
resolve();
}
});
},
set_input: function(key, val) {
}
set_input(key, val) {
return this.set_value(key, val);
},
set_values: function(dict) {
}
set_values(dict) {
let promises = [];
for(var key in dict) {
if(this.fields_dict[key]) {
@@ -141,18 +141,18 @@ frappe.ui.FieldGroup = frappe.ui.form.Layout.extend({
}

return Promise.all(promises);
},
clear: function() {
}
clear() {
for(var key in this.fields_dict) {
var f = this.fields_dict[key];
if(f && f.set_input) {
f.set_input(f.df['default'] || '');
}
}
},
set_df_property: function (fieldname, prop, value) {
}
set_df_property (fieldname, prop, value) {
const field = this.get_field(fieldname);
field.df[prop] = value;
field.refresh();
}
});
};

+ 10
- 10
frappe/public/js/frappe/ui/filters/field_select.js View File

@@ -1,7 +1,7 @@
// <select> widget with all fields of a doctype as options
frappe.ui.FieldSelect = Class.extend({
frappe.ui.FieldSelect = class FieldSelect {
// opts parent, doctype, filter_fields, with_blank, select
init(opts) {
constructor(opts) {
var me = this;
$.extend(this, opts);
this.fields_by_name = {};
@@ -44,22 +44,22 @@ frappe.ui.FieldSelect = Class.extend({
this.build_options();
}
this.set_value(this.doctype, "name");
},
}
get_value() {
return this.selected_doctype ? this.selected_doctype + "." + this.selected_fieldname : null;
},
}
val(value) {
if(value===undefined) {
return this.get_value();
} else {
this.set_value(value);
}
},
}
clear() {
this.selected_doctype = null;
this.selected_fieldname = null;
this.$input.val("");
},
}
set_value(doctype, fieldname) {
var me = this;
this.clear();
@@ -80,7 +80,7 @@ frappe.ui.FieldSelect = Class.extend({
return false;
}
});
},
}
build_options() {
var me = this;
me.table_fields = [];
@@ -135,7 +135,7 @@ frappe.ui.FieldSelect = Class.extend({
});
}
});
},
}

add_field_option(df) {
let me = this;
@@ -170,5 +170,5 @@ frappe.ui.FieldSelect = Class.extend({
if(!me.fields_by_name[df.parent]) me.fields_by_name[df.parent] = {};
me.fields_by_name[df.parent][df.fieldname] = df;
}
},
});
}
};

+ 17
- 17
frappe/public/js/frappe/ui/iconbar.js View File

@@ -1,19 +1,19 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.ui.IconBar = Class.extend({
init: function(parent, n_groups) {
frappe.ui.IconBar = class IconBar {
constructor(parent, n_groups) {
this.parent = parent;
this.buttons = {};
this.make(n_groups);
},
make: function(n_groups) {
}
make(n_groups) {
this.$wrapper = $('<div class="iconbar-wrapper hide"></div>').appendTo(this.parent);
for(var i=0; i<n_groups; i++) {
this.get_group(i+1);
}
},
get_group: function(group) {
}
get_group(group) {
var $ul = this.$wrapper.find(".iconbar-"+group+" ul");

if(!$ul.length)
@@ -21,8 +21,8 @@ frappe.ui.IconBar = Class.extend({
.appendTo(this.$wrapper).find("ul");

return $ul;
},
add_btn: function(group, icon, label, click) {
}
add_btn(group, icon, label, click) {
var $ul = this.get_group(group);
var $li = $('<li><i class="'+icon+'"></i></li>')
.appendTo($ul)
@@ -37,16 +37,16 @@ frappe.ui.IconBar = Class.extend({
this.$wrapper.find(".iconbar-" + group).removeClass("hide")
this.show();
return $li;
},
hide: function(group) {
}
hide(group) {
if(group) {
this.$wrapper.find(".iconbar-" + group).addClass("hide");
this.check_if_all_hidden();
} else {
this.$wrapper.addClass("hide").trigger("hidden");
}
},
show: function(group) {
}
show(group) {
if(group) {
this.$wrapper.find(".iconbar-" + group).removeClass("hide");
this.show();
@@ -54,15 +54,15 @@ frappe.ui.IconBar = Class.extend({
if(this.$wrapper.hasClass("hide"))
this.$wrapper.removeClass("hide").trigger("shown");
}
},
clear: function(group) {
}
clear(group) {
var me = this;
this.$wrapper.find(".iconbar-" + group).addClass("hide").find("ul").empty();
this.check_if_all_hidden();
},
check_if_all_hidden: function() {
}
check_if_all_hidden() {
if(!this.$wrapper.find(".iconbar:visible").length) {
this.hide();
}
}
})
};

+ 138
- 138
frappe/public/js/frappe/ui/page.js View File

@@ -26,8 +26,8 @@ frappe.ui.make_app_page = function(opts) {

frappe.ui.pages = {};

frappe.ui.Page = Class.extend({
init: function(opts) {
frappe.ui.Page = class Page {
constructor(opts) {
$.extend(this, opts);

this.set_document_title = true;
@@ -37,14 +37,14 @@ frappe.ui.Page = Class.extend({

this.make();
frappe.ui.pages[frappe.get_route_str()] = this;
},
}

make: function() {
make() {
this.wrapper = $(this.parent);
this.add_main_section();
this.setup_scroll_handler();
this.setup_sidebar_toggle();
},
}

setup_scroll_handler() {
window.addEventListener('scroll', () => {
@@ -54,9 +54,9 @@ frappe.ui.Page = Class.extend({
$('.page-head').removeClass('drop-shadow');
}
});
},
}

get_empty_state: function(title, message, primary_action) {
get_empty_state(title, message, primary_action) {
let $empty_state = $(`<div class="page-card-container">
<div class="page-card">
<div class="page-card-head">
@@ -71,13 +71,13 @@ frappe.ui.Page = Class.extend({
</div>`);

return $empty_state;
},
}

load_lib: function(callback) {
load_lib(callback) {
frappe.require(this.required_libs, callback);
},
}

add_main_section: function() {
add_main_section() {
$(frappe.render_template("page", {})).appendTo(this.wrapper);
if (this.single_column) {
// nesting under col-sm-12 for consistency
@@ -100,9 +100,9 @@ frappe.ui.Page = Class.extend({
}

this.setup_page();
},
}

setup_page: function() {
setup_page() {
this.$title_area = this.wrapper.find(".title-area");

this.$sub_title_area = this.wrapper.find("h6");
@@ -154,7 +154,7 @@ frappe.ui.Page = Class.extend({
frappe.ui.keys
.get_shortcut_group(this.page_actions[0])
.add(action_btn, action_btn.find('.actions-btn-group-label'));
},
}

setup_sidebar_toggle() {
let sidebar_toggle = $('.page-head').find('.sidebar-toggle-btn');
@@ -176,7 +176,7 @@ frappe.ui.Page = Class.extend({
this.update_sidebar_icon();
});
}
},
}

setup_overlay_sidebar() {
let overlay_sidebar = this.sidebar.find('.overlay-sidebar')
@@ -196,7 +196,7 @@ frappe.ui.Page = Class.extend({
.removeClass('text-muted');
});
};
},
}

update_sidebar_icon() {
let sidebar_toggle = $('.page-head').find('.sidebar-toggle-btn');
@@ -204,13 +204,13 @@ frappe.ui.Page = Class.extend({
let sidebar_wrapper = this.wrapper.find('.layout-side-section');
let is_sidebar_visible = $(sidebar_wrapper).is(":visible");
sidebar_toggle_icon.html(frappe.utils.icon(is_sidebar_visible ? 'sidebar-collapse' : 'sidebar-expand', 'md'));
},
}

set_indicator: function(label, color) {
set_indicator(label, color) {
this.clear_indicator().removeClass("hide").html(`<span>${label}</span>`).addClass(color);
},
}

add_action_icon: function(icon, click, css_class='', tooltip_label) {
add_action_icon(icon, click, css_class='', tooltip_label) {
const button = $(`
<button class="text-muted btn btn-default ${css_class} icon-btn">
${frappe.utils.icon(icon)}
@@ -223,13 +223,13 @@ frappe.ui.Page = Class.extend({
.tooltip({ delay: { "show": 600, "hide": 100 }, trigger: "hover" });

return button;
},
}

clear_indicator: function() {
clear_indicator() {
return this.indicator.removeClass().addClass("indicator-pill whitespace-nowrap hide");
},
}

get_icon_label: function(icon, label) {
get_icon_label(icon, label) {
let icon_name = icon;
let size = 'xs';
if (typeof icon === 'object') {
@@ -237,9 +237,9 @@ frappe.ui.Page = Class.extend({
size = icon.size || 'xs';
}
return `${icon ? frappe.utils.icon(icon_name, size) : ''} <span class="hidden-xs"> ${__(label)} </span>`;
},
}

set_action: function(btn, opts) {
set_action(btn, opts) {
let me = this;
if (opts.icon) {
opts.label = this.get_icon_label(opts.icon, opts.label);
@@ -264,9 +264,9 @@ frappe.ui.Page = Class.extend({
frappe.ui.keys
.get_shortcut_group(this)
.add(btn, text_span.length ? text_span : btn);
},
}

set_primary_action: function(label, click, icon, working_label) {
set_primary_action(label, click, icon, working_label) {
this.set_action(this.btn_primary, {
label: label,
click: click,
@@ -275,9 +275,9 @@ frappe.ui.Page = Class.extend({
});
return this.btn_primary;

},
}

set_secondary_action: function(label, click, icon, working_label) {
set_secondary_action(label, click, icon, working_label) {
this.set_action(this.btn_secondary, {
label: label,
click: click,
@@ -286,37 +286,37 @@ frappe.ui.Page = Class.extend({
});

return this.btn_secondary;
},
}


clear_action_of: function(btn) {
clear_action_of(btn) {
btn.addClass("hide").unbind("click").removeAttr("data-working-label");
},
}

clear_primary_action: function() {
clear_primary_action() {
this.clear_action_of(this.btn_primary);
},
}

clear_secondary_action: function() {
clear_secondary_action() {
this.clear_action_of(this.btn_secondary);
},
}

clear_actions: function() {
clear_actions() {
this.clear_primary_action();
this.clear_secondary_action();
},
}

clear_custom_actions() {
this.custom_actions.addClass("hide").empty();
},
}

clear_icons: function() {
clear_icons() {
this.icon_group.addClass("hide").empty();
},
}

//--- Menu --//

add_menu_item: function(label, click, standard, shortcut) {
add_menu_item(label, click, standard, shortcut) {
return this.add_dropdown_item({
label,
click,
@@ -324,9 +324,9 @@ frappe.ui.Page = Class.extend({
parent: this.menu,
shortcut
});
},
}

add_custom_menu_item: function(parent, label, click, standard, shortcut, icon=null) {
add_custom_menu_item(parent, label, click, standard, shortcut, icon=null) {
return this.add_dropdown_item({
label,
click,
@@ -335,49 +335,49 @@ frappe.ui.Page = Class.extend({
shortcut,
icon
});
},
}

clear_menu: function() {
clear_menu() {
this.clear_btn_group(this.menu);
},
}

show_menu: function() {
show_menu() {
this.menu_btn_group.removeClass("hide");
},
}

hide_menu: function() {
hide_menu() {
this.menu_btn_group.addClass("hide");
},
}

show_icon_group: function() {
show_icon_group() {
this.icon_group.removeClass("hide");
},
}

hide_icon_group: function() {
hide_icon_group() {
this.icon_group.addClass("hide");
},
}

//--- Actions Menu--//

show_actions_menu: function() {
show_actions_menu() {
this.actions_btn_group.removeClass("hide");
},
}

hide_actions_menu: function() {
hide_actions_menu() {
this.actions_btn_group.addClass("hide");
},
}


add_action_item: function(label, click, standard) {
add_action_item(label, click, standard) {
return this.add_dropdown_item({
label,
click,
standard,
parent: this.actions
});
},
}

add_actions_menu_item: function(label, click, standard) {
add_actions_menu_item(label, click, standard) {
return this.add_dropdown_item({
label,
click,
@@ -385,11 +385,11 @@ frappe.ui.Page = Class.extend({
parent: this.actions,
show_parent: false
});
},
}

clear_actions_menu: function() {
clear_actions_menu() {
this.clear_btn_group(this.actions);
},
}


//-- Generic --//
@@ -404,7 +404,7 @@ frappe.ui.Page = Class.extend({
* @param {string} shortcut - Keyboard shortcut associated with the element
* @param {Boolean} show_parent - Whether to show the dropdown button if dropdown item is added
*/
add_dropdown_item: function({label, click, standard, parent, shortcut, show_parent=true, icon=null}) {
add_dropdown_item({label, click, standard, parent, shortcut, show_parent=true, icon=null}) {
if (show_parent) {
parent.parent().removeClass("hide");
}
@@ -460,7 +460,7 @@ frappe.ui.Page = Class.extend({
.add($link, $link.find('.menu-item-label'));

return $link;
},
}

prepare_shortcut_obj(shortcut, click, label) {
let shortcut_obj;
@@ -489,7 +489,7 @@ frappe.ui.Page = Class.extend({
// page
shortcut_obj.page = this;
return shortcut_obj;
},
}

/*
* Check if there already exists a button with a specified label in a specified button group
@@ -497,7 +497,7 @@ frappe.ui.Page = Class.extend({
* @param {string} selector - CSS Selector of the button to be searched for. By default, it is `li`.
* @param {string} label - Label of the button
*/
is_in_group_button_dropdown: function(parent, selector, label) {
is_in_group_button_dropdown(parent, selector, label) {

if (!selector) selector = 'li';

@@ -509,18 +509,18 @@ frappe.ui.Page = Class.extend({
return $(item).attr('data-label') === label;
});
return result.length > 0;
},
}

clear_btn_group: function(parent) {
clear_btn_group(parent) {
parent.empty();
parent.parent().addClass("hide");
},
}

add_divider: function() {
add_divider() {
return $('<li class="dropdown-divider"></li>').appendTo(this.menu);
},
}

get_or_add_inner_group_button: function(label) {
get_or_add_inner_group_button(label) {
var $group = this.inner_toolbar.find(`.inner-group-button[data-label="${encodeURIComponent(label)}"]`);
if (!$group.length) {
$group = $(
@@ -534,17 +534,17 @@ frappe.ui.Page = Class.extend({
).appendTo(this.inner_toolbar);
}
return $group;
},
}

get_inner_group_button: function(label) {
get_inner_group_button(label) {
return this.inner_toolbar.find(`.inner-group-button[data-label="${encodeURIComponent(label)}"]`);
},
}

set_inner_btn_group_as_primary: function(label) {
set_inner_btn_group_as_primary(label) {
this.get_or_add_inner_group_button(label).find("button").removeClass("btn-default").addClass("btn-primary");
},
}

btn_disable_enable: function(btn, response) {
btn_disable_enable(btn, response) {
if (response && response.then) {
btn.prop('disabled', true);
response.then(() => {
@@ -556,7 +556,7 @@ frappe.ui.Page = Class.extend({
btn.prop('disabled', false);
});
}
},
}

/*
* Add button to button group. If there exists another button with the same label,
@@ -567,7 +567,7 @@ frappe.ui.Page = Class.extend({
* @param {object} action - function to be called when button is clicked
* @param {string} group - Label of the group button
*/
add_inner_button: function(label, action, group, type="default") {
add_inner_button(label, action, group, type="default") {
var me = this;
let _action = function() {
let btn = $(this);
@@ -595,9 +595,9 @@ frappe.ui.Page = Class.extend({
}
return button;
}
},
}

remove_inner_button: function(label, group) {
remove_inner_button(label, group) {
if (typeof label === 'string') {
label = [label];
}
@@ -613,23 +613,23 @@ frappe.ui.Page = Class.extend({
} else {
this.inner_toolbar.find(`button[data-label="${encodeURIComponent(label)}"]`).remove();
}
},
}

add_inner_message: function(message) {
add_inner_message(message) {
let $message = $(`<span class='inner-page-message text-muted small'>${message}</div>`);
this.inner_toolbar.find('.inner-page-message').remove();
this.inner_toolbar.removeClass("hide").prepend($message);

return $message;
},
}

clear_inner_toolbar: function() {
clear_inner_toolbar() {
this.inner_toolbar.empty().addClass("hide");
},
}

//-- Sidebar --//

add_sidebar_item: function(label, action, insert_after, prepend) {
add_sidebar_item(label, action, insert_after, prepend) {
var parent = this.sidebar.find(".sidebar-menu.standard-actions");
var li = $('<li>');
var link = $('<a>').html(label).on("click", action).appendTo(li);
@@ -644,20 +644,20 @@ frappe.ui.Page = Class.extend({
}
}
return link;
},
}

//---//

clear_user_actions: function() {
clear_user_actions() {
this.menu.find(".user-action").remove();
},
}

// page::title
get_title_area: function() {
get_title_area() {
return this.$title_area;
},
}

set_title: function(title, icon=null, strip=true, tab_title="") {
set_title(title, icon=null, strip=true, tab_title="") {
if (!title) title = "";
if (strip) {
title = strip_html(title);
@@ -670,24 +670,24 @@ frappe.ui.Page = Class.extend({
let title_wrapper = this.$title_area.find(".title-text");
title_wrapper.html(title);
title_wrapper.attr('title', this.title);
},
}

set_title_sub: function(txt) {
set_title_sub(txt) {
// strip icon
this.$sub_title_area.html(txt).toggleClass("hide", !!!txt);
},
}

get_main_icon: function(icon) {
get_main_icon(icon) {
return this.$title_area.find(".title-icon")
.html('<i class="'+icon+' fa-fw"></i> ')
.toggle(true);
},
}

add_help_button: function(txt) {
add_help_button(txt) {
//
},
}

add_button: function(label, click, opts) {
add_button(label, click, opts) {
if (!opts) opts = {};
let button = $(`<button
class="btn ${opts.btn_class || 'btn-default'} ${opts.btn_size || 'btn-sm'} ellipsis">
@@ -699,9 +699,9 @@ frappe.ui.Page = Class.extend({
this.custom_actions.removeClass('hide');

return button;
},
}

add_custom_button_group: function(label, icon, parent) {
add_custom_button_group(label, icon, parent) {
let dropdown_label = `<span class="hidden-xs">
<span class="custom-btn-group-label">${__(label)}</span>
${frappe.utils.icon('select', 'xs')}
@@ -731,40 +731,40 @@ frappe.ui.Page = Class.extend({
parent.removeClass('hide').append(custom_btn_group);

return custom_btn_group.find('.dropdown-menu');
},
}

add_dropdown_button: function(parent, label, click, icon) {
add_dropdown_button(parent, label, click, icon) {
frappe.ui.toolbar.add_dropdown_button(parent, label, click, icon);
},
}

// page::form
add_label: function(label) {
add_label(label) {
this.show_form();
return $("<label class='col-md-1 page-only-label'>"+label+" </label>")
.appendTo(this.page_form);
},
add_select: function(label, options) {
}
add_select(label, options) {
var field = this.add_field({label:label, fieldtype:"Select"});
return field.$wrapper.find("select").empty().add_options(options);
},
add_data: function(label) {
}
add_data(label) {
var field = this.add_field({label: label, fieldtype: "Data"});
return field.$wrapper.find("input").attr("placeholder", label);
},
add_date: function(label, date) {
}
add_date(label, date) {
var field = this.add_field({label: label, fieldtype: "Date", "default": date});
return field.$wrapper.find("input").attr("placeholder", label);
},
add_check: function(label) {
}
add_check(label) {
return $("<div class='checkbox'><label><input type='checkbox'>" + label + "</label></div>")
.appendTo(this.page_form)
.find("input");
},
add_break: function() {
}
add_break() {
// add further fields in the next line
this.page_form.append('<div class="clearfix invisible-xs"></div>');
},
add_field: function(df, parent) {
}
add_field(df, parent) {
this.show_form();

if (!df.placeholder) {
@@ -810,24 +810,24 @@ frappe.ui.Page = Class.extend({
f.set_input(df["default"])
this.fields_dict[df.fieldname || df.label] = f;
return f;
},
clear_fields: function() {
}
clear_fields() {
this.page_form.empty();
},
show_form: function() {
}
show_form() {
this.page_form.removeClass("hide");
},
hide_form: function() {
}
hide_form() {
this.page_form.addClass("hide");
},
get_form_values: function() {
}
get_form_values() {
var values = {};
this.page_form.fields_dict.forEach(function(field, key) {
values[key] = field.get_value();
});
return values;
},
add_view: function(name, html) {
}
add_view(name, html) {
let element = html;
if(typeof (html) === "string") {
element = $(html);
@@ -839,8 +839,8 @@ frappe.ui.Page = Class.extend({
this.views[name].toggle(false);
}
return this.views[name];
},
set_view: function(name) {
}
set_view(name) {
if(this.current_view_name===name)
return;
this.current_view && this.current_view.toggle(false);
@@ -852,5 +852,5 @@ frappe.ui.Page = Class.extend({
this.views[name].toggle(true);

this.wrapper.trigger('view-change');
},
});
}
};

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save