ソースを参照

Merge branch 'develop' into image-pf-fix

version-14
Saqib 4年前
committed by GitHub
コミット
d9737c1d25
この署名に対応する既知のキーがデータベースに存在しません GPGキーID: 4AEE18F83AFDEB23
100個のファイルの変更755行の追加7284行の削除
  1. +2
    -1
      .eslintrc
  2. +3
    -3
      cypress/integration/control_rating.js
  3. +0
    -1
      cypress/support/commands.js
  4. +5
    -2
      frappe/app.py
  5. +7
    -2
      frappe/boot.py
  6. +2
    -2
      frappe/core/doctype/doctype/doctype.json
  7. +1
    -1
      frappe/core/doctype/navbar_settings/navbar_settings.py
  8. +37
    -26
      frappe/core/doctype/scheduled_job_type/scheduled_job_type.py
  9. +2
    -37
      frappe/core/doctype/server_script/server_script.js
  10. +16
    -2
      frappe/core/doctype/server_script/server_script.json
  11. +122
    -42
      frappe/core/doctype/server_script/server_script.py
  12. +4
    -3
      frappe/core/workspace/build/build.json
  13. +0
    -0
      frappe/custom/doctype/client_script/README.md
  14. +0
    -0
      frappe/custom/doctype/client_script/__init__.py
  15. +1
    -1
      frappe/custom/doctype/client_script/client_script.js
  16. +8
    -15
      frappe/custom/doctype/client_script/client_script.json
  17. +2
    -2
      frappe/custom/doctype/client_script/client_script.py
  18. +2
    -2
      frappe/custom/doctype/client_script/test_client_script.py
  19. +12
    -5
      frappe/custom/workspace/customization/customization.json
  20. +64
    -6
      frappe/desk/doctype/kanban_board/kanban_board.py
  21. +1
    -1
      frappe/desk/form/meta.py
  22. +1
    -1
      frappe/desk/form/utils.py
  23. +1
    -1
      frappe/desk/page/leaderboard/leaderboard.js
  24. +3
    -1
      frappe/desk/search.py
  25. +5
    -6
      frappe/email/test_email_body.py
  26. +1
    -1
      frappe/integrations/doctype/social_login_key/social_login_key.py
  27. +1
    -1
      frappe/model/__init__.py
  28. +20
    -3
      frappe/model/base_document.py
  29. +1
    -1
      frappe/model/delete_doc.py
  30. +2
    -0
      frappe/model/document.py
  31. +2
    -0
      frappe/patches.txt
  32. +1
    -0
      frappe/patches/v12_0/reset_home_settings.py
  33. +2
    -3
      frappe/patches/v13_0/enable_custom_script.py
  34. +9
    -0
      frappe/patches/v13_0/rename_custom_client_script.py
  35. +20
    -0
      frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py
  36. +7
    -15
      frappe/public/build.json
  37. +0
    -253
      frappe/public/css/common.css
  38. +0
    -604
      frappe/public/css/docs.css
  39. +19
    -1
      frappe/public/css/fonts/inter/inter.css
  40. +0
    -729
      frappe/public/css/form.css
  41. +0
    -411
      frappe/public/css/mobile.css
  42. +0
    -0
      frappe/public/css/variables.css
  43. +12
    -3
      frappe/public/icons/timeless/symbol-defs.svg
  44. バイナリ
      frappe/public/images/favicon.png
  45. +0
    -52
      frappe/public/js/docs.js
  46. +5
    -4
      frappe/public/js/frappe/chat.js
  47. +2
    -2
      frappe/public/js/frappe/data_import/import_preview.js
  48. +7
    -19
      frappe/public/js/frappe/desk.js
  49. +15
    -7
      frappe/public/js/frappe/file_uploader/FilePreview.vue
  50. +14
    -18
      frappe/public/js/frappe/file_uploader/FileUploader.vue
  51. +11
    -2
      frappe/public/js/frappe/file_uploader/index.js
  52. +1
    -0
      frappe/public/js/frappe/form/controls/autocomplete.js
  53. +9
    -2
      frappe/public/js/frappe/form/controls/barcode.js
  54. +1
    -1
      frappe/public/js/frappe/form/controls/base_control.js
  55. +1
    -1
      frappe/public/js/frappe/form/controls/image.js
  56. +1
    -0
      frappe/public/js/frappe/form/controls/int.js
  57. +1
    -1
      frappe/public/js/frappe/form/controls/link.js
  58. +1
    -0
      frappe/public/js/frappe/form/controls/multiselect_list.js
  59. +5
    -5
      frappe/public/js/frappe/form/controls/multiselect_pills.js
  60. +16
    -14
      frappe/public/js/frappe/form/controls/rating.js
  61. +12
    -6
      frappe/public/js/frappe/form/controls/signature.js
  62. +5
    -5
      frappe/public/js/frappe/form/controls/table_multiselect.js
  63. +1
    -1
      frappe/public/js/frappe/form/form.js
  64. +8
    -5
      frappe/public/js/frappe/form/formatters.js
  65. +1
    -1
      frappe/public/js/frappe/form/grid.js
  66. +1
    -1
      frappe/public/js/frappe/form/grid_row.js
  67. +1
    -1
      frappe/public/js/frappe/form/script_manager.js
  68. +1
    -1
      frappe/public/js/frappe/form/sidebar/form_sidebar.js
  69. +1
    -1
      frappe/public/js/frappe/list/list_sidebar.html
  70. +12
    -6
      frappe/public/js/frappe/list/list_view.js
  71. +13
    -7
      frappe/public/js/frappe/list/list_view_select.js
  72. +1
    -1
      frappe/public/js/frappe/model/model.js
  73. +1
    -1
      frappe/public/js/frappe/request.js
  74. +2
    -1
      frappe/public/js/frappe/ui/colors.js
  75. +2
    -0
      frappe/public/js/frappe/ui/dialog.js
  76. +0
    -57
      frappe/public/js/frappe/ui/dropzone.js
  77. +1
    -0
      frappe/public/js/frappe/ui/filters/filter.js
  78. +5
    -3
      frappe/public/js/frappe/ui/filters/filter_list.js
  79. +4
    -9
      frappe/public/js/frappe/ui/notifications/notifications.js
  80. +1
    -0
      frappe/public/js/frappe/ui/page.js
  81. +1
    -1
      frappe/public/js/frappe/ui/toolbar/navbar.html
  82. +2
    -2
      frappe/public/js/frappe/ui/toolbar/search.js
  83. +6
    -0
      frappe/public/js/frappe/ui/toolbar/toolbar.js
  84. +0
    -27
      frappe/public/js/frappe/ui/upload.html
  85. +24
    -0
      frappe/public/js/frappe/ui/workspace_loading_skeleton.html
  86. +0
    -6
      frappe/public/js/frappe/utils/rating_icons.html
  87. +0
    -8
      frappe/public/js/frappe/utils/ratings.html
  88. +4
    -3
      frappe/public/js/frappe/views/breadcrumbs.js
  89. +6
    -2
      frappe/public/js/frappe/views/calendar/calendar.js
  90. +19
    -17
      frappe/public/js/frappe/views/communication.js
  91. +82
    -6
      frappe/public/js/frappe/views/kanban/kanban_board.js
  92. +4
    -1
      frappe/public/js/frappe/views/kanban/kanban_card.html
  93. +4
    -0
      frappe/public/js/frappe/views/kanban/kanban_view.js
  94. +42
    -59
      frappe/public/js/frappe/views/workspace/workspace.js
  95. +0
    -23
      frappe/public/js/lib/README.md
  96. +0
    -104
      frappe/public/js/lib/awesomplete/awesomplete.css
  97. +0
    -3
      frappe/public/js/lib/awesomplete/awesomplete.min.js
  98. +0
    -617
      frappe/public/js/lib/beautify-html.js
  99. +0
    -1
      frappe/public/js/lib/bootstrap-paginator.min.js
  100. +0
    -3981
      frappe/public/js/lib/frappe-datatable.js

+ 2
- 1
.eslintrc ファイルの表示

@@ -147,6 +147,7 @@
"context": true,
"before": true,
"beforeEach": true,
"qz": true
"qz": true,
"localforage": true
}
}

+ 3
- 3
cypress/integration/control_rating.js ファイルの表示

@@ -18,7 +18,7 @@ context('Control Rating', () => {
get_dialog_with_rating().as('dialog');

cy.get('div.rating')
.children('i.fa')
.children('svg')
.first()
.click()
.should('have.class', 'star-click');
@@ -33,11 +33,11 @@ context('Control Rating', () => {
get_dialog_with_rating();

cy.get('div.rating')
.children('i.fa')
.children('svg')
.first()
.invoke('trigger', 'mouseenter')
.should('have.class', 'star-hover')
.invoke('trigger', 'mouseleave')
.should('not.have.class', 'star-hover');
});
});
});

+ 0
- 1
cypress/support/commands.js ファイルの表示

@@ -312,7 +312,6 @@ Cypress.Commands.add('add_filter', () => {
cy.get('.filter-section .filter-button').click();
cy.wait(300);
cy.get('.filter-popover').should('exist');
cy.get('.filter-popover').find('.add-filter').click();
});

Cypress.Commands.add('clear_filters', () => {


+ 5
- 2
frappe/app.py ファイルの表示

@@ -152,10 +152,10 @@ def process_response(response):

def set_cors_headers(response):
origin = frappe.request.headers.get('Origin')
if not origin:
allow_cors = frappe.conf.allow_cors
if not (origin and allow_cors):
return

allow_cors = frappe.conf.allow_cors
if allow_cors != "*":
if not isinstance(allow_cors, list):
allow_cors = [allow_cors]
@@ -181,6 +181,9 @@ def make_form_dict(request):
else:
args = request.form or request.args

if not isinstance(args, dict):
frappe.throw("Invalid request arguments")

try:
frappe.local.form_dict = frappe._dict({ k:v[0] if isinstance(v, (list, tuple)) else v \
for k, v in iteritems(args) })


+ 7
- 2
frappe/boot.py ファイルの表示

@@ -21,7 +21,7 @@ from frappe.website.doctype.web_page_view.web_page_view import is_tracking_enabl
from frappe.social.doctype.energy_point_log.energy_point_log import get_energy_points
from frappe.model.base_document import get_controller
from frappe.social.doctype.post.post import frequently_visited_links
from frappe.core.doctype.navbar_settings.navbar_settings import get_navbar_settings
from frappe.core.doctype.navbar_settings.navbar_settings import get_navbar_settings, get_app_logo

def get_bootinfo():
"""build and return boot info"""
@@ -62,6 +62,7 @@ def get_bootinfo():
doclist.extend(get_meta_bundle("Page"))
bootinfo.home_folder = frappe.db.get_value("File", {"is_home_folder": 1})
bootinfo.navbar_settings = get_navbar_settings()
bootinfo.notification_settings = get_notification_settings()

# ipinfo
if frappe.session.data.get('ipinfo'):
@@ -90,6 +91,7 @@ def get_bootinfo():
bootinfo.link_preview_doctypes = get_link_preview_doctypes()
bootinfo.additional_filters_config = get_additional_filters_from_hooks()
bootinfo.desk_settings = get_desk_settings()
bootinfo.app_logo_url = get_app_logo()

return bootinfo

@@ -323,4 +325,7 @@ def get_desk_settings():
for key in desk_properties:
desk_settings[key] = desk_settings.get(key) or role.get(key)

return desk_settings
return desk_settings

def get_notification_settings():
return frappe.get_cached_doc('Notification Settings', frappe.session.user)

+ 2
- 2
frappe/core/doctype/doctype/doctype.json ファイルの表示

@@ -555,7 +555,7 @@
},
{
"group": "Customization",
"link_doctype": "Custom Script",
"link_doctype": "Client Script",
"link_fieldname": "dt"
},
{
@@ -609,7 +609,7 @@
"link_fieldname": "reference_doctype"
}
],
"modified": "2020-12-10 15:10:09.227205",
"modified": "2021-02-04 15:10:09.227205",
"modified_by": "Administrator",
"module": "Core",
"name": "DocType",


+ 1
- 1
frappe/core/doctype/navbar_settings/navbar_settings.py ファイルの表示

@@ -25,7 +25,7 @@ class NavbarSettings(Document):

@frappe.whitelist(allow_guest=True)
def get_app_logo():
app_logo = frappe.db.get_single_value('Navbar Settings', 'app_logo')
app_logo = frappe.db.get_single_value('Navbar Settings', 'app_logo', cache=True)
if not app_logo:
app_logo = frappe.get_hooks('app_logo_url')[-1]



+ 37
- 26
frappe/core/doctype/scheduled_job_type/scheduled_job_type.py ファイルの表示

@@ -3,6 +3,7 @@
# For license information, please see license.txt

from __future__ import unicode_literals
from typing import Dict, List

import frappe, json
from frappe.model.document import Document
@@ -11,12 +12,13 @@ from datetime import datetime
from croniter import croniter
from frappe.utils.background_jobs import enqueue, get_jobs


class ScheduledJobType(Document):
def autoname(self):
self.name = '.'.join(self.method.split('.')[-2:])
self.name = ".".join(self.method.split(".")[-2:])

def validate(self):
if self.frequency != 'All':
if self.frequency != "All":
# force logging for all events other than continuous ones (ALL)
self.create_log = 1

@@ -84,7 +86,7 @@ class ScheduledJobType(Document):

def log_status(self, status):
# log file
frappe.logger("scheduler").info('Scheduled Job {0}: {1} for {2}'.format(status, self.method, frappe.local.site))
frappe.logger("scheduler").info(f"Scheduled Job {status}: {self.method} for {frappe.local.site}")
self.update_scheduler_log(status)

def update_scheduler_log(self, status):
@@ -111,28 +113,28 @@ class ScheduledJobType(Document):


@frappe.whitelist()
def execute_event(doc):
frappe.only_for('System Manager')
def execute_event(doc: str):
frappe.only_for("System Manager")
doc = json.loads(doc)
frappe.get_doc('Scheduled Job Type', doc.get('name')).enqueue(force=True)
frappe.get_doc("Scheduled Job Type", doc.get("name")).enqueue(force=True)


def run_scheduled_job(job_type):
'''This is a wrapper function that runs a hooks.scheduler_events method'''
def run_scheduled_job(job_type: str):
"""This is a wrapper function that runs a hooks.scheduler_events method"""
try:
frappe.get_doc('Scheduled Job Type', dict(method=job_type)).execute()
frappe.get_doc("Scheduled Job Type", dict(method=job_type)).execute()
except Exception:
print(frappe.get_traceback())


def sync_jobs(hooks=None):
def sync_jobs(hooks: Dict = None):
frappe.reload_doc("core", "doctype", "scheduled_job_type")
scheduler_events = hooks or frappe.get_hooks("scheduler_events")
all_events = insert_events(scheduler_events)
clear_events(all_events)


def insert_events(scheduler_events):
def insert_events(scheduler_events: Dict) -> List:
cron_jobs, event_jobs = [], []
for event_type in scheduler_events:
events = scheduler_events.get(event_type)
@@ -144,7 +146,7 @@ def insert_events(scheduler_events):
return cron_jobs + event_jobs


def insert_cron_jobs(events):
def insert_cron_jobs(events: Dict) -> List:
cron_jobs = []
for cron_format in events:
for event in events.get(cron_format):
@@ -153,25 +155,29 @@ def insert_cron_jobs(events):
return cron_jobs


def insert_event_jobs(events, event_type):
def insert_event_jobs(events: List, event_type: str) -> List:
event_jobs = []
for event in events:
event_jobs.append(event)
frequency = event_type.replace('_', ' ').title()
frequency = event_type.replace("_", " ").title()
insert_single_event(frequency, event)
return event_jobs


def insert_single_event(frequency, event, cron_format=None):
def insert_single_event(frequency: str, event: str, cron_format: str = None):
cron_expr = {"cron_format": cron_format} if cron_format else {}
doc = frappe.get_doc({
"doctype": "Scheduled Job Type",
"method": event,
"cron_format": cron_format,
"frequency": frequency
})

if not frappe.db.exists("Scheduled Job Type", {"method": event, "frequency": frequency, **cron_expr }):
doc = frappe.get_doc(
{
"doctype": "Scheduled Job Type",
"method": event,
"cron_format": cron_format,
"frequency": frequency,
}
)

if not frappe.db.exists(
"Scheduled Job Type", {"method": event, "frequency": frequency, **cron_expr}
):
try:
doc.insert()
except frappe.DuplicateEntryError:
@@ -179,7 +185,12 @@ def insert_single_event(frequency, event, cron_format=None):
doc.insert()


def clear_events(all_events):
for event in frappe.get_all("Scheduled Job Type", ("name", "method")):
if event.method not in all_events:
def clear_events(all_events: List):
for event in frappe.get_all(
"Scheduled Job Type", fields=["name", "method", "server_script"]
):
is_server_script = event.server_script
is_defined_in_hooks = event.method in all_events

if not (is_defined_in_hooks or is_server_script):
frappe.delete_doc("Scheduled Job Type", event.name)

+ 2
- 37
frappe/core/doctype/server_script/server_script.js ファイルの表示

@@ -6,46 +6,11 @@ frappe.ui.form.on('Server Script', {
frm.trigger('setup_help');
},
refresh: function(frm) {
if (frm.doc.script_type === 'Scheduler Event' && !frm.doc.disabled) {
frm.add_custom_button('Schedule Script', function() {
var d = new frappe.ui.Dialog({
title: "Schedule Script Execution",
fields: [
{
fieldname: "event_type",
label: __('Select Event Type'),
fieldtype: "Select",
options: "All\nHourly\nDaily\nWeekly\nMonthly\nYearly\nHourly Long\nDaily Long\nWeekly Long\nMonthly Long"
},
],
primary_action_label: __('Schedule Script'),
primary_action: () => {
d.get_primary_btn().attr('disabled', true);
var data = d.get_values();
d.hide();
if(data) {
frm.events.schedule_script(frm, data);
}

}
});

d.show();

});
if (frm.doc.script_type != 'Scheduler Event') {
frm.dashboard.hide();
}
},

schedule_script(frm, data) {
frm.call({
method: "frappe.core.doctype.server_script.server_script.setup_scheduler_events",
args: {
'script_name': frm.doc.name,
'frequency': data.event_type
}
});
},

setup_help(frm) {
frm.get_field('help_html').html(`
<h4>DocType Event</h4>


+ 16
- 2
frappe/core/doctype/server_script/server_script.json ファイルの表示

@@ -8,6 +8,7 @@
"field_order": [
"script_type",
"reference_doctype",
"event_frequency",
"doctype_event",
"api_method",
"allow_guest",
@@ -84,11 +85,24 @@
{
"fieldname": "help_html",
"fieldtype": "HTML"
},
{
"depends_on": "eval:doc.script_type == \"Scheduler Event\"",
"fieldname": "event_frequency",
"fieldtype": "Select",
"label": "Event Frequency",
"mandatory_depends_on": "eval:doc.script_type == \"Scheduler Event\"",
"options": "All\nHourly\nDaily\nWeekly\nMonthly\nYearly\nHourly Long\nDaily Long\nWeekly Long\nMonthly Long"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-01-03 18:50:14.767595",
"links": [
{
"link_doctype": "Scheduled Job Type",
"link_fieldname": "server_script"
}
],
"modified": "2021-02-18 12:36:19.803425",
"modified_by": "Administrator",
"module": "Core",
"name": "Server Script",


+ 122
- 42
frappe/core/doctype/server_script/server_script.py ファイルの表示

@@ -5,6 +5,7 @@
from __future__ import unicode_literals

import ast
from typing import Dict, List

import frappe
from frappe.model.document import Document
@@ -14,67 +15,146 @@ from frappe import _

class ServerScript(Document):
def validate(self):
frappe.only_for('Script Manager', True)
frappe.only_for("Script Manager", True)
self.validate_script()
self.sync_scheduled_jobs()
self.clear_scheduled_events()

def on_update(self):
frappe.cache().delete_value("server_script_map")
self.sync_scheduler_events()

def on_trash(self):
if self.script_type == "Scheduler Event":
for job in self.scheduled_jobs:
frappe.delete_doc("Scheduled Job Type", job.name)

@property
def scheduled_jobs(self) -> List[Dict[str, str]]:
return frappe.get_all(
"Scheduled Job Type",
filters={"server_script": self.name},
fields=["name", "stopped"],
)

def validate_script(self):
"""Utilizes the ast module to check for syntax errors
"""
ast.parse(self.script)

@staticmethod
def on_update():
frappe.cache().delete_value('server_script_map')

def execute_method(self):
if self.script_type == 'API':
# validate if guest is allowed
if frappe.session.user == 'Guest' and not self.allow_guest:
raise frappe.PermissionError
_globals, _locals = safe_exec(self.script)
return _globals.frappe.flags # output can be stored in flags
else:
# wrong report type!
def sync_scheduled_jobs(self):
"""Sync Scheduled Job Type statuses if Server Script's disabled status is changed
"""
if self.script_type != "Scheduler Event" or not self.has_value_changed("disabled"):
return

for scheduled_job in self.scheduled_jobs:
if bool(scheduled_job.stopped) != bool(self.disabled):
job = frappe.get_doc("Scheduled Job Type", scheduled_job.name)
job.stopped = self.disabled
job.save()

def sync_scheduler_events(self):
"""Create or update Scheduled Job Type documents for Scheduler Event Server Scripts
"""
if not self.disabled and self.event_frequency and self.script_type == "Scheduler Event":
setup_scheduler_events(script_name=self.name, frequency=self.event_frequency)

def clear_scheduled_events(self):
"""Deletes existing scheduled jobs by Server Script if self.event_frequency has changed
"""
if self.script_type == "Scheduler Event" and self.has_value_changed("event_frequency"):
for scheduled_job in self.scheduled_jobs:
frappe.delete_doc("Scheduled Job Type", scheduled_job.name)

def execute_method(self) -> Dict:
"""Specific to API endpoint Server Scripts

Raises:
frappe.DoesNotExistError: If self.script_type is not API
frappe.PermissionError: If self.allow_guest is unset for API accessed by Guest user

Returns:
dict: Evaluates self.script with frappe.utils.safe_exec.safe_exec and returns the flags set in it's safe globals
"""
# wrong report type!
if self.script_type != "API":
raise frappe.DoesNotExistError

def execute_doc(self, doc):
# execute event
safe_exec(self.script, None, dict(doc = doc))
# validate if guest is allowed
if frappe.session.user == "Guest" and not self.allow_guest:
raise frappe.PermissionError

# output can be stored in flags
_globals, _locals = safe_exec(self.script)
return _globals.frappe.flags

def execute_doc(self, doc: Document):
"""Specific to Document Event triggered Server Scripts

Args:
doc (Document): Executes script with for a certain document's events
"""
safe_exec(self.script, _locals={"doc": doc})

def execute_scheduled_method(self):
if self.script_type == 'Scheduler Event':
safe_exec(self.script)
else:
# wrong report type!
"""Specific to Scheduled Jobs via Server Scripts

Raises:
frappe.DoesNotExistError: If script type is not a scheduler event
"""
if self.script_type != "Scheduler Event":
raise frappe.DoesNotExistError

def get_permission_query_conditions(self, user):
safe_exec(self.script)

def get_permission_query_conditions(self, user: str) -> List[str]:
"""Specific to Permission Query Server Scripts

Args:
user (str): Takes user email to execute script and return list of conditions

Returns:
list: Returns list of conditions defined by rules in self.script
"""
locals = {"user": user, "conditions": ""}
safe_exec(self.script, None, locals)
if locals["conditions"]:
return locals["conditions"]


@frappe.whitelist()
def setup_scheduler_events(script_name, frequency):
method = frappe.scrub('{0}-{1}'.format(script_name, frequency))
scheduled_script = frappe.db.get_value('Scheduled Job Type',
dict(method=method))
"""Creates or Updates Scheduled Job Type documents based on the specified script name and frequency

if not scheduled_script:
doc = frappe.get_doc(dict(
doctype = 'Scheduled Job Type',
method = method,
frequency = frequency,
server_script = script_name
))
Args:
script_name (str): Name of the Server Script document
frequency (str): Event label compatible with the Frappe scheduler
"""
method = frappe.scrub(f"{script_name}-{frequency}")
scheduled_script = frappe.db.get_value("Scheduled Job Type", {"method": method})

doc.insert()
if not scheduled_script:
frappe.get_doc(
{
"doctype": "Scheduled Job Type",
"method": method,
"frequency": frequency,
"server_script": script_name,
}
).insert()

frappe.msgprint(_('Enabled scheduled execution for script {0}').format(script_name))
frappe.msgprint(_("Enabled scheduled execution for script {0}").format(script_name))

else:
doc = frappe.get_doc('Scheduled Job Type', scheduled_script)
doc.update(dict(
doctype = 'Scheduled Job Type',
method = method,
frequency = frequency,
server_script = script_name
))
doc = frappe.get_doc("Scheduled Job Type", scheduled_script)

if doc.frequency == frequency:
return

doc.frequency = frequency
doc.save()

frappe.msgprint(_('Scheduled execution for script {0} has updated').format(script_name))
frappe.msgprint(
_("Scheduled execution for script {0} has updated").format(script_name)
)

+ 4
- 3
frappe/core/workspace/build/build.json ファイルの表示

@@ -11,6 +11,7 @@
"hide_custom": 0,
"icon": "tool",
"idx": 0,
"is_default": 0,
"is_standard": 1,
"label": "Build",
"links": [
@@ -163,8 +164,8 @@
{
"hidden": 0,
"is_query_report": 0,
"label": "Custom Script",
"link_to": "Custom Script",
"label": "Client Script",
"link_to": "Client Script",
"link_type": "DocType",
"onboard": 0,
"only_for": "",
@@ -181,7 +182,7 @@
"type": "Link"
}
],
"modified": "2021-01-02 14:03:15.029699",
"modified": "2021-02-04 13:48:48.493146",
"modified_by": "Administrator",
"module": "Core",
"name": "Build",


frappe/custom/doctype/custom_script/README.md → frappe/custom/doctype/client_script/README.md ファイルの表示


frappe/custom/doctype/custom_script/__init__.py → frappe/custom/doctype/client_script/__init__.py ファイルの表示


frappe/custom/doctype/custom_script/custom_script.js → frappe/custom/doctype/client_script/client_script.js ファイルの表示

@@ -1,7 +1,7 @@
// Copyright (c) 2016, Frappe Technologies and contributors
// For license information, please see license.txt

frappe.ui.form.on('Custom Script', {
frappe.ui.form.on('Client Script', {
refresh(frm) {
if (frm.doc.dt && frm.doc.script) {
frm.add_custom_button(__('Go to {0}', [frm.doc.dt]),

frappe/custom/doctype/custom_script/custom_script.json → frappe/custom/doctype/client_script/client_script.json ファイルの表示

@@ -2,7 +2,7 @@
"actions": [],
"allow_import": 1,
"creation": "2013-01-10 16:34:01",
"description": "Adds a client custom script to a DocType",
"description": "Adds a custom client script to a DocType",
"doctype": "DocType",
"document_type": "Document",
"engine": "InnoDB",
@@ -22,9 +22,7 @@
"oldfieldname": "dt",
"oldfieldtype": "Link",
"options": "DocType",
"reqd": 1,
"show_days": 1,
"show_seconds": 1
"reqd": 1
},
{
"fieldname": "script",
@@ -32,35 +30,29 @@
"label": "Script",
"oldfieldname": "script",
"oldfieldtype": "Code",
"options": "JS",
"show_days": 1,
"show_seconds": 1
"options": "JS"
},
{
"fieldname": "sample",
"fieldtype": "HTML",
"label": "Sample",
"options": "<h3>Custom Script Help</h3>\n<p>Custom Scripts are executed only on the client-side (i.e. in Forms). Here are some examples to get you started</p>\n<pre><code>\n\n// fetch local_tax_no on selection of customer \n// cur_frm.add_fetch(link_field, source_fieldname, target_fieldname); \ncur_frm.add_fetch('customer', 'local_tax_no', 'local_tax_no');\n\n// additional validation on dates \nfrappe.ui.form.on('Task', 'validate', function(frm) {\n if (frm.doc.from_date &lt; get_today()) {\n msgprint('You can not select past date in From Date');\n validated = false;\n } \n});\n\n// make a field read-only after saving \nfrappe.ui.form.on('Task', {\n refresh: function(frm) {\n // use the __islocal value of doc, to check if the doc is saved or not\n frm.set_df_property('myfield', 'read_only', frm.doc.__islocal ? 0 : 1);\n } \n});\n\n// additional permission check\nfrappe.ui.form.on('Task', {\n validate: function(frm) {\n if(user=='user1@example.com' &amp;&amp; frm.doc.purpose!='Material Receipt') {\n msgprint('You are only allowed Material Receipt');\n validated = false;\n }\n } \n});\n\n// calculate sales incentive\nfrappe.ui.form.on('Sales Invoice', {\n validate: function(frm) {\n // calculate incentives for each person on the deal\n total_incentive = 0\n $.each(frm.doc.sales_team, function(i, d) {\n // calculate incentive\n var incentive_percent = 2;\n if(frm.doc.base_grand_total &gt; 400) incentive_percent = 4;\n // actual incentive\n d.incentives = flt(frm.doc.base_grand_total) * incentive_percent / 100;\n total_incentive += flt(d.incentives)\n });\n frm.doc.total_incentive = total_incentive;\n } \n})\n\n</code></pre>",
"show_days": 1,
"show_seconds": 1
"options": "<h3>Client Script Help</h3>\n<p>Client Scripts are executed only on the client-side (i.e. in Forms). Here are some examples to get you started</p>\n<pre><code>\n\n// fetch local_tax_no on selection of customer \n// cur_frm.add_fetch(link_field, source_fieldname, target_fieldname); \ncur_frm.add_fetch('customer', 'local_tax_no', 'local_tax_no');\n\n// additional validation on dates \nfrappe.ui.form.on('Task', 'validate', function(frm) {\n if (frm.doc.from_date &lt; get_today()) {\n msgprint('You can not select past date in From Date');\n validated = false;\n } \n});\n\n// make a field read-only after saving \nfrappe.ui.form.on('Task', {\n refresh: function(frm) {\n // use the __islocal value of doc, to check if the doc is saved or not\n frm.set_df_property('myfield', 'read_only', frm.doc.__islocal ? 0 : 1);\n } \n});\n\n// additional permission check\nfrappe.ui.form.on('Task', {\n validate: function(frm) {\n if(user=='user1@example.com' &amp;&amp; frm.doc.purpose!='Material Receipt') {\n msgprint('You are only allowed Material Receipt');\n validated = false;\n }\n } \n});\n\n// calculate sales incentive\nfrappe.ui.form.on('Sales Invoice', {\n validate: function(frm) {\n // calculate incentives for each person on the deal\n total_incentive = 0\n $.each(frm.doc.sales_team, function(i, d) {\n // calculate incentive\n var incentive_percent = 2;\n if(frm.doc.base_grand_total &gt; 400) incentive_percent = 4;\n // actual incentive\n d.incentives = flt(frm.doc.base_grand_total) * incentive_percent / 100;\n total_incentive += flt(d.incentives)\n });\n frm.doc.total_incentive = total_incentive;\n } \n})\n\n</code></pre>"
},
{
"default": "0",
"fieldname": "enabled",
"fieldtype": "Check",
"label": "Enabled",
"show_days": 1,
"show_seconds": 1
"label": "Enabled"
}
],
"icon": "fa fa-glass",
"idx": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2020-08-24 21:56:07.719579",
"modified": "2021-02-04 13:57:56.509437",
"modified_by": "Administrator",
"module": "Custom",
"name": "Custom Script",
"name": "Client Script",
"owner": "Administrator",
"permissions": [
{
@@ -86,6 +78,7 @@
"write": 1
}
],
"sort_field": "modified",
"sort_order": "ASC",
"track_changes": 1
}

frappe/custom/doctype/custom_script/custom_script.py → frappe/custom/doctype/client_script/client_script.py ファイルの表示

@@ -5,9 +5,9 @@ import frappe

from frappe.model.document import Document

class CustomScript(Document):
class ClientScript(Document):
def autoname(self):
self.name = self.dt + "-Client"
self.name = self.dt

def on_update(self):
frappe.clear_cache(doctype=self.dt)

frappe/custom/doctype/custom_script/test_custom_script.py → frappe/custom/doctype/client_script/test_client_script.py ファイルの表示

@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
import unittest

# test_records = frappe.get_test_records('Custom Script')
# test_records = frappe.get_test_records('Client Script')

class TestCustomScript(unittest.TestCase):
class TestClientScript(unittest.TestCase):
pass

+ 12
- 5
frappe/custom/workspace/customization/customization.json ファイルの表示

@@ -10,6 +10,7 @@
"hide_custom": 0,
"icon": "customization",
"idx": 0,
"is_default": 0,
"is_standard": 1,
"label": "Customization",
"links": [
@@ -81,8 +82,8 @@
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Custom Script",
"link_to": "Custom Script",
"label": "Client Script",
"link_to": "Client Script",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
@@ -115,7 +116,7 @@
"type": "Link"
}
],
"modified": "2020-12-01 13:38:39.843773",
"modified": "2021-02-04 13:50:35.750463",
"modified_by": "Administrator",
"module": "Custom",
"name": "Customization",
@@ -134,8 +135,14 @@
"type": "DocType"
},
{
"label": "Custom Script",
"link_to": "Custom Script",
"label": "Client Script",
"link_to": "Client Script",
"type": "DocType"
},
{
"doc_view": "",
"label": "Server Script",
"link_to": "Server Script",
"type": "DocType"
}
]

+ 64
- 6
frappe/desk/doctype/kanban_board/kanban_board.py ファイルの表示

@@ -17,6 +17,10 @@ class KanbanBoard(Document):
def on_update(self):
frappe.clear_cache(doctype=self.reference_doctype)

def before_insert(self):
for column in self.columns:
column.order = get_order_for_column(self, column.column_name)

def validate_column_name(self):
for column in self.columns:
if not column.column_name:
@@ -125,6 +129,53 @@ def update_order(board_name, order):
board.save()
return board, updated_cards

@frappe.whitelist()
def update_order_for_single_card(board_name, docname, from_colname, to_colname, old_index, new_index):
'''Save the order of cards in columns'''
board = frappe.get_doc('Kanban Board', board_name)
doctype = board.reference_doctype
fieldname = board.field_name
old_index = frappe.parse_json(old_index)
new_index = frappe.parse_json(new_index)

# save current order and index of columns to be updated
from_col_order, from_col_idx = get_kanban_column_order_and_index(board, from_colname)
to_col_order, to_col_idx = get_kanban_column_order_and_index(board, to_colname)

if from_colname == to_colname:
from_col_order = to_col_order

to_col_order.insert(new_index, from_col_order.pop((old_index)))

# save updated order
board.columns[from_col_idx].order = frappe.as_json(from_col_order)
board.columns[to_col_idx].order = frappe.as_json(to_col_order)
board.save()

# update changed value in doc
frappe.set_value(doctype, docname, fieldname, to_colname)

return board

def get_kanban_column_order_and_index(board, colname):
for i, col in enumerate(board.columns):
if col.column_name == colname:
col_order = frappe.parse_json(col.order)
col_idx = i

return col_order, col_idx

@frappe.whitelist()
def add_card(board_name, docname, colname):
board = frappe.get_doc('Kanban Board', board_name)

col_order, col_idx = get_kanban_column_order_and_index(board, colname)
col_order.insert(0, docname)

board.columns[col_idx].order = frappe.as_json(col_order)

board.save()
return board

@frappe.whitelist()
def quick_kanban_board(doctype, board_name, field_name, project=None):
@@ -133,6 +184,13 @@ def quick_kanban_board(doctype, board_name, field_name, project=None):
doc = frappe.new_doc('Kanban Board')
meta = frappe.get_meta(doctype)

doc.kanban_board_name = board_name
doc.reference_doctype = doctype
doc.field_name = field_name

if project:
doc.filters = '[["Task","project","=","{0}"]]'.format(project)

options = ''
for field in meta.fields:
if field.fieldname == field_name:
@@ -149,12 +207,6 @@ def quick_kanban_board(doctype, board_name, field_name, project=None):
column_name=column
))

doc.kanban_board_name = board_name
doc.reference_doctype = doctype
doc.field_name = field_name

if project:
doc.filters = '[["Task","project","=","{0}"]]'.format(project)

if doctype in ['Note', 'ToDo']:
doc.private = 1
@@ -162,6 +214,12 @@ def quick_kanban_board(doctype, board_name, field_name, project=None):
doc.save()
return doc

def get_order_for_column(board, colname):
filters = [[board.reference_doctype, board.field_name, '=', colname]]
if board.filters:
filters.append(frappe.parse_json(board.filters)[0])

return frappe.as_json(frappe.get_list(board.reference_doctype, filters=filters, pluck='name'))

@frappe.whitelist()
def update_column_order(board_name, order):


+ 1
- 1
frappe/desk/form/meta.py ファイルの表示

@@ -130,7 +130,7 @@ class FormMeta(Meta):
def add_custom_script(self):
"""embed all require files"""
# custom script
custom = frappe.db.get_value("Custom Script", {"dt": self.name, "enabled": 1}, "script") or ""
custom = frappe.db.get_value("Client Script", {"dt": self.name, "enabled": 1}, "script") or ""

self.set("__custom_js", custom)



+ 1
- 1
frappe/desk/form/utils.py ファイルの表示

@@ -47,7 +47,7 @@ def validate_link():
except Exception as e:
error_message = str(e).split("Unknown column '")
fieldname = None if len(error_message)<=1 else error_message[1].split("'")[0]
frappe.msgprint(_("Wrong fieldname <b>{0}</b> in add_fetch configuration of custom script").format(fieldname))
frappe.msgprint(_("Wrong fieldname <b>{0}</b> in add_fetch configuration of custom client script").format(fieldname))
frappe.errprint(frappe.get_traceback())

if fetch_value:


+ 1
- 1
frappe/desk/page/leaderboard/leaderboard.js ファイルの表示

@@ -141,7 +141,7 @@ class Leaderboard {
}

create_date_range_field() {
let timespan_field = $(this.parent).find(`.frappe-control[data-original-title='Timespan']`);
let timespan_field = $(this.parent).find(`.frappe-control[data-original-title=${__('Timespan')}]`);
this.date_range_field = $(`<div class="from-date-field"></div>`).insertAfter(timespan_field).hide();

let date_field = frappe.ui.form.make_control({


+ 3
- 1
frappe/desk/search.py ファイルの表示

@@ -80,13 +80,15 @@ def search_widget(doctype, txt, query=None, searchfield=None, start=0,
is_whitelisted(frappe.get_attr(query))
frappe.response["values"] = frappe.call(query, doctype, txt,
searchfield, start, page_length, filters, as_dict=as_dict)
except Exception as e:
except frappe.exceptions.PermissionError as e:
if frappe.local.conf.developer_mode:
raise e
else:
frappe.respond_as_web_page(title='Invalid Method', html='Method not found',
indicator_color='red', http_status_code=404)
return
except Exception as e:
raise e
elif not query and doctype in standard_queries:
# from standard queries
search_widget(doctype, txt, standard_queries[doctype][0],


+ 5
- 6
frappe/email/test_email_body.py ファイルの表示

@@ -17,7 +17,7 @@ class TestEmailBody(unittest.TestCase):
<div>
<h3>Hey John Doe!</h3>
<p>This is embedded image you asked for</p>
<img embed="assets/frappe/images/favicon.png" />
<img embed="assets/frappe/images/frappe-favicon.svg" />
</div>
'''
email_text = '''
@@ -25,7 +25,7 @@ Hey John Doe!
This is the text version of this email
'''

img_path = os.path.abspath('assets/frappe/images/favicon.png')
img_path = os.path.abspath('assets/frappe/images/frappe-favicon.svg')
with open(img_path, 'rb') as f:
img_content = f.read()
img_base64 = base64.b64encode(img_content).decode()
@@ -77,12 +77,11 @@ This is the text version of this email

def test_image(self):
img_signature = '''
Content-Type: image/png
Content-Type: image/svg+xml
MIME-Version: 1.0
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename="favicon.png"
Content-Disposition: inline; filename="frappe-favicon.svg"
'''

self.assertTrue(img_signature in self.email_string)
self.assertTrue(self.img_base64 in self.email_string)

@@ -117,7 +116,7 @@ w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
def test_replace_filename_with_cid(self):
original_message = '''
<div>
<img embed="assets/frappe/images/favicon.png" alt="test" />
<img embed="assets/frappe/images/frappe-favicon.svg" alt="test" />
<img embed="notexists.jpg" />
</div>
'''


+ 1
- 1
frappe/integrations/doctype/social_login_key/social_login_key.py ファイルの表示

@@ -124,7 +124,7 @@ class SocialLoginKey(Document):
"provider_name": "Frappe",
"enable_social_login": 1,
"custom_base_url": 1,
"icon":"/assets/frappe/images/favicon.png",
"icon":"/assets/frappe/images/frappe-favicon.svg",
"redirect_url": "/api/method/frappe.www.login.login_via_frappe",
"api_endpoint": "/api/method/frappe.integrations.oauth2.openid_profile",
"api_endpoint_args":None,


+ 1
- 1
frappe/model/__init__.py ファイルの表示

@@ -118,7 +118,7 @@ core_doctypes_list = (
'Customize Form Field',
'Property Setter',
'Custom Field',
'Custom Script'
'Client Script'
)

log_types = (


+ 20
- 3
frappe/model/base_document.py ファイルの表示

@@ -69,13 +69,13 @@ def get_controller(doctype):

if frappe.local.dev_server:
return _get_controller()
site_controllers = frappe.controllers.setdefault(frappe.local.site, {})
if doctype not in site_controllers:
site_controllers[doctype] = _get_controller()
return site_controllers[doctype]
class BaseDocument(object):
ignore_in_getter = ("doctype", "_meta", "meta", "_table_fields", "_valid_columns")

@@ -94,6 +94,14 @@ class BaseDocument(object):
return self._meta

def update(self, d):
""" Update multiple fields of a doctype using a dictionary of key-value pairs.

Example:
doc.update({
"user": "admin",
"balance": 42000
})
"""
if "doctype" in d:
self.set("doctype", d.get("doctype"))

@@ -159,6 +167,15 @@ class BaseDocument(object):
del self.__dict__[key]

def append(self, key, value=None):
""" Append an item to a child table.

Example:
doc.append("childtable", {
"child_table_field": "value",
"child_table_int_field": 0,
...
})
"""
if value==None:
value={}
if isinstance(value, (dict, BaseDocument)):


+ 1
- 1
frappe/model/delete_doc.py ファイルの表示

@@ -68,7 +68,7 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa
check_permission_and_not_submitted(doc)

frappe.db.sql("delete from `tabCustom Field` where dt = %s", name)
frappe.db.sql("delete from `tabCustom Script` where dt = %s", name)
frappe.db.sql("delete from `tabClient Script` where dt = %s", name)
frappe.db.sql("delete from `tabProperty Setter` where doc_type = %s", name)
frappe.db.sql("delete from `tabReport` where ref_doctype=%s", name)
frappe.db.sql("delete from `tabCustom DocPerm` where parent=%s", name)


+ 2
- 0
frappe/model/document.py ファイルの表示

@@ -1015,6 +1015,8 @@ class Document(BaseDocument):

def notify_update(self):
"""Publish realtime that the current document is modified"""
if frappe.flags.in_patch: return

frappe.publish_realtime("doc_update", {"modified": self.modified, "doctype": self.doctype, "name": self.name},
doctype=self.doctype, docname=self.name, after_commit=True)



+ 2
- 0
frappe/patches.txt ファイルの表示

@@ -35,6 +35,7 @@ frappe.patches.v11_0.change_email_signature_fieldtype
execute:frappe.reload_doc('core', 'doctype', 'activity_log')
execute:frappe.reload_doc('core', 'doctype', 'deleted_document')
execute:frappe.reload_doc('core', 'doctype', 'domain_settings')
frappe.patches.v13_0.rename_custom_client_script
frappe.patches.v8_0.rename_page_role_to_has_role #2017-03-16
frappe.patches.v7_2.setup_custom_perms #2017-01-19
frappe.patches.v8_0.set_user_permission_for_page_and_report #2017-03-20
@@ -329,3 +330,4 @@ frappe.core.doctype.page.patches.drop_unused_pages
execute:frappe.get_doc('Role', 'Guest').save() # remove desk access
frappe.patches.v13_0.rename_desk_page_to_workspace # 02.02.2021
frappe.patches.v13_0.delete_package_publish_tool
frappe.patches.v13_0.rename_list_view_setting_to_list_view_settings

+ 1
- 0
frappe/patches/v12_0/reset_home_settings.py ファイルの表示

@@ -1,6 +1,7 @@
import frappe

def execute():
frappe.reload_doc('core', 'doctype', 'user')
frappe.db.sql('''
UPDATE `tabUser`
SET `home_settings` = ''


+ 2
- 3
frappe/patches/v13_0/enable_custom_script.py ファイルの表示

@@ -5,9 +5,8 @@ from __future__ import unicode_literals
import frappe

def execute():
"""Enable all the existing custom script"""
frappe.reload_doc("Custom", "doctype", "Custom Script")
"""Enable all the existing Client script"""

frappe.db.sql("""
UPDATE `tabCustom Script` SET enabled=1
UPDATE `tabClient Script` SET enabled=1
""")

+ 9
- 0
frappe/patches/v13_0/rename_custom_client_script.py ファイルの表示

@@ -0,0 +1,9 @@
import frappe


def execute():
if frappe.db.exists("DocType", "Client Script"):
return

frappe.rename_doc("DocType", "Custom Script", "Client Script")
frappe.reload_doctype("Client Script", force=True)

+ 20
- 0
frappe/patches/v13_0/rename_list_view_setting_to_list_view_settings.py ファイルの表示

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

from __future__ import unicode_literals
import frappe


def execute():
if frappe.db.table_exists('List View Setting'):
existing_list_view_settings = frappe.get_all('List View Settings', as_list=True)
for list_view_setting in frappe.get_all('List View Setting', fields = ['disable_count', 'disable_sidebar_stats', 'disable_auto_refresh', 'name']):
name = list_view_setting.pop('name')
if name not in [x[0] for x in existing_list_view_settings]:
list_view_setting['doctype'] = 'List View Settings'
list_view_settings = frappe.get_doc(list_view_setting)
# setting name here is necessary because autoname is set as prompt
list_view_settings.name = name
list_view_settings.insert()
frappe.delete_doc("DocType", "List View Setting", force=True)
frappe.db.commit()

+ 7
- 15
frappe/public/build.json ファイルの表示

@@ -27,8 +27,6 @@
"public/js/frappe/microtemplate.js",
"public/js/frappe/query_string.js",

"public/js/frappe/ui/dropzone.js",
"public/js/frappe/ui/upload.html",
"public/js/frappe/upload.js",

"public/js/frappe/model/meta.js",
@@ -36,7 +34,6 @@
"public/js/frappe/model/perm.js",

"website/js/website.js",
"public/js/frappe/utils/rating_icons.html",
"public/js/frappe/socketio_client.js"
],
"js/bootstrap-4-web.min.js": "website/js/bootstrap-4.js",
@@ -62,7 +59,6 @@
],
"js/dialog.min.js": [
"public/js/frappe/dom.js",

"public/js/frappe/form/formatters.js",
"public/js/frappe/form/layout.js",
"public/js/frappe/ui/field_group.js",
@@ -79,8 +75,6 @@
"public/css/octicons/octicons.css",
"public/less/desk.less",
"public/less/module.less",
"public/less/link_preview.less",
"public/less/form.less",
"public/less/mobile.less",
"public/less/controls.less",
"public/less/chat.less",
@@ -99,22 +93,22 @@
"public/scss/print.scss"
],
"concat:js/libs.min.js": [
"public/js/lib/awesomplete/awesomplete.min.js",
"public/js/lib/Sortable.min.js",
"public/js/lib/jquery/jquery.hotkeys.js",
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
"node_modules/vue/dist/vue.min.js",
"node_modules/moment/min/moment-with-locales.min.js",
"node_modules/moment-timezone/builds/moment-timezone-with-data.min.js",
"public/js/lib/socket.io.min.js",
"node_modules/socket.io-client/dist/socket.io.slim.js",
"node_modules/localforage/dist/localforage.min.js",
"public/js/lib/jSignature.min.js",
"public/js/frappe/translate.js",
"public/js/lib/leaflet/leaflet.js",
"public/js/lib/leaflet/leaflet.draw.js",
"public/js/lib/leaflet/L.Control.Locate.js",
"public/js/lib/leaflet/easy-button.js"
],
"js/desk.min.js": [
"public/js/frappe/translate.js",
"public/js/frappe/class.js",
"public/js/frappe/polyfill.js",
"public/js/frappe/provide.js",
@@ -152,7 +146,6 @@
"public/js/frappe/ui/dialog.js",
"public/js/frappe/ui/capture.js",
"public/js/frappe/ui/app_icon.js",
"public/js/frappe/ui/dropzone.js",
"public/js/frappe/ui/theme_switcher.js",

"public/js/frappe/model/model.js",
@@ -179,7 +172,6 @@
"public/js/frappe/utils/preview_email.js",
"public/js/frappe/utils/file_manager.js",

"public/js/frappe/ui/upload.html",
"public/js/frappe/upload.js",
"public/js/frappe/ui/tree.js",

@@ -209,11 +201,11 @@
"public/js/frappe/ui/sort_selector.js",

"public/js/frappe/change_log.html",
"public/js/frappe/ui/workspace_loading_skeleton.html",
"public/js/frappe/desk.js",
"public/js/frappe/query_string.js",

"public/js/frappe/ui/comment.js",
"public/js/frappe/utils/rating_icons.html",

"public/js/frappe/chat.js",
"public/js/frappe/utils/energy_point_utils.js",
@@ -231,7 +223,6 @@
"public/js/frappe/form/form.js",
"public/js/frappe/meta_tag.js"
],
"css/list.min.css": "public/less/gantt.less",
"js/list.min.js": [
"public/js/frappe/ui/listing.html",

@@ -298,11 +289,12 @@
"css/web_form.css": [
"website/css/web_form.css",
"public/css/octicons/octicons.css",
"public/less/controls.less",
"public/scss/controls.scss",
"node_modules/frappe-datatable/dist/frappe-datatable.css"
],
"css/email.css": "public/scss/email.scss",
"js/barcode_scanner.min.js": "public/js/frappe/barcode_scanner/quagga.js",
"js/user_profile_controller.min.js": "desk/page/user_profile/user_profile_controller.js",
"css/login.css": "public/scss/login.scss"
"css/login.css": "public/scss/login.scss",
"js/data_import_tools.min.js": "public/js/frappe/data_import/index.js"
}

+ 0
- 253
frappe/public/css/common.css ファイルの表示

@@ -1,253 +0,0 @@
/* the element that this class is applied to, should have a max width for this to work*/
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
}
a {
cursor: pointer;
}
a,
a:hover,
a:active,
a:focus,
.btn,
.btn:hover,
.btn:active,
.btn:focus {
outline: 0;
}
img {
max-width: 100%;
}
p {
margin: 10px 0px;
}
.text-color {
color: #36414C !important;
}
.text-muted {
color: #8D99A6 !important;
}
.text-extra-muted {
color: #d1d8dd !important;
}
a,
.badge {
-webkit-transition: 0.2s;
-o-transition: 0.2s;
transition: 0.2s;
}
.btn {
-webkit-transition: background-color 0.2s;
-o-transition: background-color 0.2s;
transition: background-color 0.2s;
}
a.disabled,
a.disabled:hover {
color: #888;
cursor: default;
text-decoration: none;
}
a.grey,
.sidebar-section a,
.control-value a,
.data-row a {
text-decoration: none;
}
a.grey:hover,
.sidebar-section a:hover,
.control-value a:hover,
.data-row a:hover,
a.grey:focus,
.sidebar-section a:focus,
.control-value a:focus,
.data-row a:focus {
text-decoration: underline;
}
a.text-muted,
a.text-extra-muted {
text-decoration: none;
}
.underline {
text-decoration: underline;
}
.inline-block {
display: inline-block;
}
.bold,
.strong {
font-weight: bold;
}
kbd {
color: inherit;
background-color: #F0F4F7;
}
.btn [class^="fa fa-"],
.nav [class^="fa fa-"],
.btn [class*="fa fa-"],
.nav [class*="fa fa-"] {
display: inline-block;
}
.dropdown-menu > li > a {
padding: 14px;
white-space: normal;
}
.dropdown-menu {
min-width: 200px;
padding: 0px;
font-size: 12px;
max-height: 400px;
overflow: auto;
border-radius: 0px 0px 4px 4px;
}
.dropdown-menu .dropdown-header {
padding: 3px 14px;
font-size: 11px;
font-weight: 200;
padding-top: 12px;
}
.dropdown-menu .divider {
margin: 0px;
}
a.badge-hover:hover .badge,
a.badge-hover:focus .badge,
a.badge-hover:active .badge {
background-color: #D8DFE5;
}
.msgprint {
word-wrap: break-word;
}
.msgprint pre {
text-align: left;
}
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
}
.border-top {
border-top: 1px solid #d1d8dd;
}
.border-bottom {
border-bottom: 1px solid #d1d8dd;
}
.border-left {
border-left: 1px solid #d1d8dd;
}
.border-right {
border-right: 1px solid #d1d8dd;
}
.border {
border: 1px solid #d1d8dd;
}
.close-inline {
font-size: 120%;
font-weight: bold;
line-height: 1;
cursor: pointer;
color: inherit;
display: inline-block;
}
.close-inline:hover,
.close-inline:focus {
text-decoration: none;
}
.middle {
vertical-align: middle;
}
.full-center-container {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.full-center {
position: absolute;
top: 50%;
left: 50%;
width: 100%;
transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
}
#freeze {
z-index: 1020;
bottom: 0px;
opacity: 0;
background-color: #fafbfc;
}
#freeze .freeze-message-container {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
#freeze .freeze-message {
position: absolute;
top: 50%;
left: 50%;
width: 100%;
transform: translate(-50%, -50%);
-webkit-transform: translate(-50%, -50%);
text-align: center;
color: #36414C !important;
}
#freeze.dark {
background-color: #334143;
}
#freeze.in {
opacity: 0.5;
}
a.no-decoration {
text-decoration: none;
color: inherit;
}
a.no-decoration:hover,
a.no-decoration:focus,
a.no-decoration:active {
text-decoration: none;
color: inherit;
}
.padding {
padding: 15px;
}
.margin {
margin: 15px;
}
.margin-top {
margin-top: 15px;
}
.margin-bottom {
margin-bottom: 15px;
}
.margin-left {
margin-left: 15px;
}
.margin-right {
margin-right: 15px;
}
@media (max-width: 767px) {
.text-center-xs {
text-align: center;
}
}
.grayscale {
-webkit-filter: grayscale(100%);
filter: grayscale(100%);
}
.uppercase {
padding-bottom: 4px;
text-transform: uppercase;
font-size: 12px;
letter-spacing: 0.4px;
color: #8D99A6;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
vertical-align: middle;
}

+ 0
- 604
frappe/public/css/docs.css ファイルの表示

@@ -1,604 +0,0 @@
/* the element that this class is applied to, should have a max width for this to work*/
.navbar .dropdown-toggle {
padding-top: 8px;
padding-bottom: 8px;
}
.navbar-fixed-top {
left: 0px;
right: 0px;
}
.navbar a {
font-size: 12px;
font-weight: bold;
}
.navbar-icon-home {
vertical-align: middle;
}
.navbar-icon-home:hover,
.navbar-icon-home:focus,
.navbar-icon-home:active,
.navbar-icon-home-hover {
opacity: 1;
Filter: alpha(opacity=100);
/* For IE8 and earlier */
}
.navbar-user-image {
width: 24px;
height: 24px;
margin-right: 3px;
border-radius: 4px;
}
@media (max-width: 991px) {
.navbar-desk {
width: 35% !important;
}
.navbar-desk ~ ul > li {
float: left;
}
.navbar-desk ~ ul > li a {
padding-left: 10px !important;
padding-right: 10px !important;
}
.navbar-desk ~ ul > li a .avatar {
margin-right: 0;
}
.dropdown-navbar-new-comments > a {
padding: 8px 0 !important;
margin-left: 0 !important;
}
}
@media (max-width: 767px) {
.navbar-desk {
width: 50% !important;
}
}
#search-modal .modal-dialog,
#search-modal .modal-content {
background: transparent;
}
#search-modal .modal-header {
background: #fff;
width: 100%;
}
#search-modal .modal-header form {
vertical-align: middle;
}
#search-modal .modal-header button {
line-height: 0;
position: absolute;
right: 0;
top: 0;
z-index: 9;
padding: 9px;
}
.dropdown-navbar-new-comments > a {
border: 0;
}
.dropdown-navbar-new-comments .dropdown-menu {
margin-top: 0;
}
.dropdown-help .dropdown-menu {
width: 350px !important;
max-height: 440px;
overflow: auto;
}
.dropdown-help .dropdown-menu .input-group {
width: 100%;
background-color: #f5f7fa;
padding: 8px 12px;
}
.dropdown-help .dropdown-menu input {
width: 100%;
padding: 5px 10px;
outline: none;
border-radius: 3px 0 0 3px;
border: 1px solid #d1d8dd;
opacity: 0.9;
line-height: 1.5;
}
.dropdown-help .dropdown-menu button {
border: 1px solid #d1d8dd;
}
@media (max-width: 767px) {
.dropdown-help .dropdown-menu {
position: fixed !important;
top: 40px;
width: 100% !important;
}
}
@media (max-width: 767px) {
.dropdown-mobile.open .dropdown-menu {
position: absolute;
border-top: 1px solid rgba(0, 0, 0, 0.14902);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
background-color: #fff;
right: 0;
left: auto;
}
.dropdown-mobile.open .dropdown-menu > li > a {
padding: 12px;
}
.dropdown-help {
display: none !important;
}
}
.navbar-new-comments {
display: inline-block;
min-width: 24px;
height: 24px;
border-radius: 4px;
color: #fff;
text-align: center;
padding: 2px 5px;
background-color: #b8c2cc;
}
.navbar-new-comments-true {
background-color: #ff5858;
}
.navbar-form .awesomplete {
margin-left: -15px;
width: 300px;
}
@media (max-width: 1199px) {
.navbar-form .awesomplete {
width: 280px;
}
}
@media (max-width: 991px) {
.navbar-form .awesomplete {
width: 250px;
}
}
#navbar-search {
width: 100%;
background-color: rgba(255, 255, 255, 0.9);
}
.navbar .navbar-search-icon {
color: #6C7680;
font-size: inherit;
position: relative;
right: 24px;
top: 1px;
}
.navbar .badge {
font-weight: normal;
}
#navbar-search-results {
left: auto;
right: inherit;
margin-top: -1px;
max-height: 300px;
overflow-y: auto;
overflow-x: hidden;
}
.navbar-center {
float: left;
color: #6C7680;
}
#navbar-breadcrumbs > li > a:before {
font-family: FontAwesome;
font-weight: normal;
font-style: normal;
text-decoration: inherit;
-webkit-font-smoothing: antialiased;
*margin-right: 0.3em;
display: inline-block;
speak: none;
font-size: 24px;
transition: 0.2s;
position: relative;
top: 3px;
content: "\f105";
margin-right: 10px;
color: #C0C9D2;
}
#navbar-breadcrumbs > li > a:hover:before,
#navbar-breadcrumbs > li > a:focus:before,
#navbar-breadcrumbs > li > a:active:before {
color: #36414C;
}
#navbar-breadcrumbs > li > a {
padding: 6px 15px 10px 0px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 170px;
}
@media (min-width: 991px) and (max-width: 1199px) {
#navbar-breadcrumbs > li > a {
max-width: 120px;
}
}
.toolbar-user-fullname {
max-width: 150px;
display: inline-block;
}
.navbar-brand > img {
display: inline-block;
}
.toggle-sidebar {
margin-right: 10px;
}
.navbar-default .navbar-nav > li > a,
.navbar-default .navbar-brand {
color: #8D99A6;
}
body {
font-size: 16px;
line-height: 1.65em;
color: #454e57;
-webkit-font-smoothing: antialiased;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
}
.container {
max-width: 870px;
}
img {
max-width: 100%;
}
.splash {
border-bottom: 1px solid #d1d8dd;
}
.splash .jumbotron {
background-color: transparent;
padding: 40px 0 60px 0;
text-align: center;
}
.splash .jumbotron h1 {
font-size: 48px;
font-weight: 400;
opacity: 0.9;
color: #2E3338;
}
.splash .jumbotron p {
font-size: 24px;
font-color: #8D99A6 !important;
letter-spacing: 0px;
opacity: 0.7;
margin-bottom: 90px;
font-weight: 300;
line-height: 1.4em;
}
.splash .section {
padding: 30px 0 0 0;
}
.page-container {
padding-top: 38px;
margin: 0 auto;
max-width: 870px;
}
.page-container .webpage-content ol > li,
.page-container .webpage-content ul > li {
margin: 13px auto;
}
.page-container .webpage-content ol > li li,
.page-container .webpage-content ul > li li {
margin: 4px auto;
}
.page-container .webpage-content ol li ol {
list-style-type: disc;
}
.page-container .webpage-content ul,
.page-container .webpage-content ol {
margin-bottom: 32px;
}
@media (min-width: 768px) {
.page-container .page-content {
width: 83%;
margin: 0 auto;
}
}
#page-index {
padding-top: 0;
width: 100%;
margin: 0;
}
#page-index .page-content {
width: 100%;
margin: 0;
}
body[data-path="index"] .navbar .toggle-sidebar i {
color: #fff;
}
code {
color: #e66a12;
background: #fff6df;
}
pre {
background: #fafbfc;
border: 1px solid #e1e9f0;
border-radius: 2px;
}
.hljs {
background: transparent;
border: none;
padding: 1.2em 1.5em 1.5em;
color: #454e57;
}
.hljs-keyword,
.hljs-tag,
.css .hljs-class,
.css .hljs-id,
.lisp .hljs-title,
.nginx .hljs-title,
.hljs-request,
.hljs-status,
.clojure .hljs-attribute {
color: #e66a12;
}
.diff .hljs-deletion,
.hljs-string,
.hljs-tag .hljs-value,
.hljs-preprocessor,
.hljs-pragma,
.hljs-built_in,
.hljs-javadoc,
.smalltalk .hljs-class,
.smalltalk .hljs-localvars,
.smalltalk .hljs-array,
.css .hljs-rules .hljs-value,
.hljs-attr_selector,
.hljs-pseudo,
.apache .hljs-cbracket,
.tex .hljs-formula,
.coffeescript .hljs-attribute {
color: #dd4a68;
}
.hljs-number,
.hljs-date,
.hljs-regexp,
.hljs-literal,
.hljs-hexcolor,
.smalltalk .hljs-symbol,
.smalltalk .hljs-char,
.go .hljs-constant,
.hljs-change,
.lasso .hljs-variable,
.makefile .hljs-variable,
.asciidoc .hljs-bullet,
.markdown .hljs-bullet,
.asciidoc .hljs-link_url,
.markdown .hljs-link_url {
color: #7575ff;
}
.hljs-shebang,
.diff .hljs-addition,
.hljs-comment,
.hljs-annotation,
.hljs-template_comment,
.hljs-pi,
.hljs-doctype {
color: #6a906a;
}
.dos .hljs-keyword,
.hljs-decorator,
.hljs-title,
.hljs-type,
.diff .hljs-header,
.ruby .hljs-class .hljs-parent,
.apache .hljs-tag,
.nginx .hljs-built_in,
.tex .hljs-command,
.hljs-prompt {
color: #4f4fa4;
}
.navbar {
background-color: #36414C !important;
margin-left: auto;
margin-right: auto;
}
.navbar .container {
max-width: 870px;
}
.navbar .brand-logo {
width: 30px;
margin-top: -4px;
margin-right: 7px;
}
.navbar a {
font-size: 16px;
font-weight: normal;
color: #fff !important;
}
.navbar a.navbar-brand {
font-weight: bold;
}
.navbar a.toggle-sidebar {
margin-top: 8px;
}
.sidebar a {
font-size: 14px;
padding-top: 14px !important;
padding-bottom: 14px !important;
}
.breadcrumb {
line-height: 1em;
color: #8D99A6;
background-color: transparent;
margin-bottom: 32px;
padding: 0px;
padding-left: 20px;
background: url('/assets/img/up.png') 0% 30% no-repeat;
}
.breadcrumb .icon {
display: none;
}
.breadcrumb a,
.breadcrumb a:hover,
.breadcrumb a:focus,
.breadcrumb a:visited {
color: #7575ff;
font-size: 16px;
}
.hero-and-content a,
.hero-and-content a:hover,
.hero-and-content a:focus,
.hero-and-content a:visited {
color: #5E64FF;
}
.hero-and-content a.btn {
color: inherit;
}
a.btn-primary {
color: #7575ff;
}
a.btn-primary:hover,
a.btn-primary:focus,
a.btn-primary:visited {
color: #7575ff;
}
.btn-next-wrapper {
margin-top: 32px;
text-align: right;
}
h2 {
margin-top: 48px;
font-size: 24px;
}
h3,
h4 {
margin-top: 48px;
}
p {
margin-bottom: 16px;
}
.hero-and-content > p {
max-width: 723px;
margin: 0 auto;
}
.navbar {
background-color: transparent;
border: none;
padding: 15px 0px;
border-radius: 0px;
border-bottom: 1px solid #d1d8dd;
}
.section {
padding: 64px 0 0 0;
}
.dev-header {
margin-bottom: 30px;
}
.docs-footer {
padding: 30px 0px 60px 0px;
border-top: 1px solid #d1d8dd;
max-width: 870px;
margin: 0 auto;
margin-top: 80px;
font-size: 14px;
}
.docs-footer h3 {
margin-top: 24px;
font-size: 16px;
}
.docs-footer img.frappe-bird {
width: 40px;
height: 40px;
background: #fff;
margin-bottom: 10px;
padding: 5px;
}
.docs-footer a {
color: #8D99A6;
}
.docs-footer li {
display: inline-block;
margin: 0 10px;
}
.docs-footer .built-with-frappe {
margin-top: -50px;
}
.browser-image {
min-height: 200px;
border: 1px solid #d1d8dd;
border-bottom: 0px;
}
.fake-browser-frame {
position: relative;
margin: 24px auto 0px;
box-shadow: 0px -6px 100px 1px rgba(0, 0, 0, 0.1), 0px -6px 50px 1px rgba(0, 0, 0, 0.4);
}
.fake-browser-frame::before {
content: "";
height: 24px;
position: absolute;
top: -24px;
left: 0px;
right: 0px;
border: 1px solid #d1d8dd;
background: #f5f7fa;
border-bottom: none;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.fake-browser-frame::after {
content: '\f111 \00a0\00a0 \f111 \00a0\00a0 \f111';
position: absolute;
color: #d1d8dd;
top: -15px;
left: 8px;
/* octicon */
font: normal normal;
font-size: 8px;
font-family: 'FontAwesome';
line-height: 1;
display: inline-block;
text-decoration: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.fake-iphone-frame {
position: relative;
padding: 40px 8px;
border: 1px solid #d1d8dd;
border-radius: 15px;
}
.fake-ipad-frame {
position: relative;
padding: 8px 40px;
border: 1px solid #d1d8dd;
border-radius: 15px;
}
hr {
margin: 48px 0px 30px;
}
.edit {
color: #8d99a6;
}
a.edit,
a.edit:hover,
a.edit:focus,
a.edit:visited,
.edit-container .icon {
color: #8d99a6;
}
.btn-next {
margin-top: 30px;
margin-bottom: 0px;
}
.btn-next:after {
content: " \2192";
}
#current td {
font-weight: bold;
}
#current td code {
font-weight: normal;
background: transparent;
font-family: "Helvetica Neue", Helvetica, Arial, "Open Sans", sans-serif;
color: #454e57;
font-size: 16px;
}
.hero-and-content [data-html-block="hero"] {
overflow-y: hidden;
}
.page-content-wrapper > .row .col-sm-8 {
width: 100%;
}
.page-content-wrapper > .row .col-sm-4 {
display: none;
}

+ 19
- 1
frappe/public/css/fonts/inter/inter.css ファイルの表示

@@ -1,5 +1,6 @@
@font-face {
font-family: 'Inter';
font-display: swap;
font-style: normal;
font-weight: 100;
src: url("/assets/frappe/css/fonts/inter/inter_thin.woff2") format("woff2"),
@@ -7,6 +8,7 @@
}
@font-face {
font-family: 'Inter';
font-display: swap;
font-style: italic;
font-weight: 100;
src: url("/assets/frappe/css/fonts/inter/inter_thinitalic.woff2") format("woff2"),
@@ -15,6 +17,7 @@

@font-face {
font-family: 'Inter';
font-display: swap;
font-style: normal;
font-weight: 200;
src: url("/assets/frappe/css/fonts/inter/inter_extralight.woff2") format("woff2"),
@@ -22,6 +25,7 @@
}
@font-face {
font-family: 'Inter';
font-display: swap;
font-style: italic;
font-weight: 200;
src: url("/assets/frappe/css/fonts/inter/inter_extralightitalic.woff2") format("woff2"),
@@ -30,6 +34,7 @@

@font-face {
font-family: 'Inter';
font-display: swap;
font-style: normal;
font-weight: 300;
src: url("/assets/frappe/css/fonts/inter/inter_light.woff2") format("woff2"),
@@ -37,6 +42,7 @@
}
@font-face {
font-family: 'Inter';
font-display: swap;
font-style: italic;
font-weight: 300;
src: url("/assets/frappe/css/fonts/inter/inter_lightitalic.woff2") format("woff2"),
@@ -45,6 +51,7 @@

@font-face {
font-family: 'Inter';
font-display: swap;
font-style: normal;
font-weight: 400;
src: url("/assets/frappe/css/fonts/inter/inter_regular.woff2") format("woff2"),
@@ -52,6 +59,7 @@
}
@font-face {
font-family: 'Inter';
font-display: swap;
font-style: italic;
font-weight: 400;
src: url("/assets/frappe/css/fonts/inter/inter_italic.woff2") format("woff2"),
@@ -60,6 +68,7 @@

@font-face {
font-family: 'Inter';
font-display: swap;
font-style: normal;
font-weight: 500;
src: url("/assets/frappe/css/fonts/inter/inter_medium.woff2") format("woff2"),
@@ -67,6 +76,7 @@
}
@font-face {
font-family: 'Inter';
font-display: swap;
font-style: italic;
font-weight: 500;
src: url("/assets/frappe/css/fonts/inter/inter_mediumitalic.woff2") format("woff2"),
@@ -75,6 +85,7 @@

@font-face {
font-family: 'Inter';
font-display: swap;
font-style: normal;
font-weight: 600;
src: url("/assets/frappe/css/fonts/inter/inter_semibold.woff2") format("woff2"),
@@ -82,6 +93,7 @@
}
@font-face {
font-family: 'Inter';
font-display: swap;
font-style: italic;
font-weight: 600;
src: url("/assets/frappe/css/fonts/inter/inter_semibolditalic.woff2") format("woff2"),
@@ -90,6 +102,7 @@

@font-face {
font-family: 'Inter';
font-display: swap;
font-style: normal;
font-weight: 700;
src: url("/assets/frappe/css/fonts/inter/inter_bold.woff2") format("woff2"),
@@ -97,6 +110,7 @@
}
@font-face {
font-family: 'Inter';
font-display: swap;
font-style: italic;
font-weight: 700;
src: url("/assets/frappe/css/fonts/inter/inter_bolditalic.woff2") format("woff2"),
@@ -105,6 +119,7 @@

@font-face {
font-family: 'Inter';
font-display: swap;
font-style: normal;
font-weight: 800;
src: url("/assets/frappe/css/fonts/inter/inter_extrabold.woff2") format("woff2"),
@@ -112,6 +127,7 @@
}
@font-face {
font-family: 'Inter';
font-display: swap;
font-style: italic;
font-weight: 800;
src: url("/assets/frappe/css/fonts/inter/inter_extrabolditalic.woff2") format("woff2"),
@@ -120,6 +136,7 @@

@font-face {
font-family: 'Inter';
font-display: swap;
font-style: normal;
font-weight: 900;
src: url("/assets/frappe/css/fonts/inter/inter_black.woff2") format("woff2"),
@@ -127,8 +144,9 @@
}
@font-face {
font-family: 'Inter';
font-display: swap;
font-style: italic;
font-weight: 900;
src: url("/assets/frappe/css/fonts/inter/inter_blackitalic.woff2") format("woff2"),
url("/assets/frappe/css/fonts/inter/inter_blackitalic.woff") format("woff");
}
}

+ 0
- 729
frappe/public/css/form.css ファイルの表示

@@ -1,729 +0,0 @@
.form-print-wrapper {
border: 1px solid #d1d8dd;
border-top: none;
}
.print-preview-wrapper {
padding: 30px 0px;
background-color: #f5f7fa;
}
.print-toolbar {
margin: 0px;
padding: 10px 0px;
border-bottom: 1px solid #d1d8dd;
}
.print-toolbar > div {
padding-right: 0px;
}
.print-toolbar > div:last-child {
padding-right: 15px;
}
.form-inner-toolbar {
padding: 10px 15px 0px;
background-color: #fafbfc;
text-align: right;
}
.form-inner-toolbar .btn {
margin-bottom: 10px;
}
.form-clickable-section {
border-top: 1px solid #d1d8dd;
padding: 10px 15px;
background-color: #F7FAFC;
}
.form-page.second-page {
border-top: 1px solid #d1d8dd;
}
.form-message {
padding: 15px 30px;
border-bottom: 1px solid #d1d8dd;
}
.document-flow-wrapper {
padding: 40px 15px 30px;
font-size: 12px;
border-bottom: 1px solid #EBEFF2;
}
.document-flow-wrapper .document-flow {
display: inline-block;
position: relative;
left: 50%;
transform: translateX(-50%);
}
.document-flow-wrapper .document-flow .document-flow-link-wrapper {
width: 140px;
display: inline-block;
}
.document-flow-wrapper .document-flow .document-flow-link-wrapper:not(:last-child) {
border-top: 1px solid #b8c2cc;
margin-right: -4px;
}
.document-flow-wrapper .document-flow .document-flow-link-wrapper:last-child {
margin-right: -140px;
}
.document-flow-wrapper .document-flow .document-flow-link {
margin-top: -10px;
display: inline-block;
}
.document-flow-wrapper .document-flow .document-flow-link:not(.disabled):hover .document-flow-link-label,
.document-flow-wrapper .document-flow .document-flow-link:not(.disabled):focus .document-flow-link-label,
.document-flow-wrapper .document-flow .document-flow-link:not(.disabled):active .document-flow-link-label {
text-decoration: underline;
}
.document-flow-wrapper .document-flow .document-flow-link-label {
display: inline-block;
margin-left: -50%;
margin-top: 5px;
}
@media (max-width: 767px) {
.document-flow-wrapper {
display: none;
}
}
.form-dashboard {
background-color: #fafbfc;
}
.form-dashboard-wrapper {
margin: -15px 0px;
}
.form-documents h6 {
margin-top: 15px;
}
.form-dashboard-section {
margin: 0px -15px;
padding: 15px 30px;
border-bottom: 1px solid #EBEFF2;
}
.form-dashboard-section:first-child {
padding-top: 0px;
}
.form-dashboard-section:last-child {
border-bottom: none;
}
.form-heatmap .heatmap {
display: flex;
justify-content: center;
}
.form-heatmap .heatmap-message {
margin-top: 10px;
}
@media (max-width: 991px) {
.form-heatmap {
overflow: hidden;
overflow-x: scroll;
}
}
.inline-graph .inline-graph-half {
width: 48%;
display: inline-block;
position: relative;
height: 30px;
}
.inline-graph .inline-graph-half .inline-graph-count {
font-size: 10px;
position: absolute;
left: 0;
right: 0;
top: 3px;
padding: 0px 5px;
text-align: left;
}
.inline-graph .inline-graph-half .inline-graph-bar {
position: absolute;
left: 0;
right: 0;
top: 20px;
}
.inline-graph .inline-graph-half .inline-graph-bar-inner {
display: block;
float: left;
background-color: #d1d8dd;
height: 6px;
border-radius: 0px 3px 3px 0px;
}
.inline-graph .inline-graph-half .inline-graph-bar-inner.dark {
background-color: #36414C;
}
.inline-graph .inline-graph-half:first-child {
border-right: 1px solid #d1d8dd;
margin-right: -3px;
}
.inline-graph .inline-graph-half:first-child .inline-graph-count {
text-align: right;
}
.inline-graph .inline-graph-half:first-child .inline-graph-bar-inner {
float: right;
border-radius: 3px 0px 0px 3px;
}
.progress-area {
padding-top: 15px;
padding-bottom: 15px;
}
.form-links .document-link {
margin-bottom: 10px;
height: 22px;
}
.form-links .document-link:hover .badge-link {
text-decoration: underline;
}
.form-links .document-link:hover .badge-link[disabled='disabled'] {
text-decoration: none;
}
.form-links .count {
display: inline-block;
margin-left: 5px;
margin-right: 5px;
}
h6.uppercase,
.h6.uppercase {
font-size: 11px;
font-weight: normal;
letter-spacing: 0.4px;
text-transform: uppercase;
color: #8D99A6;
}
.form-section {
margin: 0px;
padding: 15px;
}
.form-section .form-section-description {
margin-bottom: 10px;
}
.form-section .form-section-heading {
margin: 10px 0px;
}
.form-section .section-head {
margin: 0px 0px 15px 15px;
cursor: pointer;
}
.form-section .section-head .collapse-indicator {
color: #d1d8dd;
margin-left: 10px;
position: relative;
bottom: -1px;
}
.form-section .section-head .collapse-indicator.octicon-chevron-up {
bottom: -2px;
}
.form-section .section-head.collapsed {
margin-bottom: 0px;
}
.form-section:not(:last-child),
.form-inner-toolbar {
border-bottom: 1px solid #d1d8dd;
}
.empty-section {
display: none !important;
}
.modal .form-layout {
margin: -15px;
}
.modal .form-grid .form-layout {
margin: 0px;
}
.modal .form-section {
padding: 15px 7px;
}
.help ol {
padding-left: 19px;
}
.field_description_top {
margin-bottom: 3px;
}
.user-actions {
margin-bottom: 15px;
}
.user-actions a {
font-weight: bold;
}
.badge-important {
background-color: #e74c3c;
}
.address-box {
background-color: #fafbfc;
padding: 0px 15px;
margin: 15px 0px;
border: 1px solid #d1d8dd;
border-radius: 3px;
font-size: 12px;
}
.timeline {
margin: 30px 0px;
}
.timeline .timeline-head .comment-input {
height: auto;
}
.timeline-item {
margin-top: 0px;
}
.timeline-item b {
color: #36414C !important;
}
.timeline-item blockquote {
font-size: inherit;
}
.timeline-item .btn-more {
margin-left: 65px;
}
.timeline-item .gmail_extra {
display: none;
}
.timeline-items {
position: relative;
}
.timeline {
position: relative;
}
.timeline::before {
content: " ";
border-left: 1px solid #d1d8dd;
position: absolute;
top: 0px;
bottom: -124px;
left: 43px;
z-index: 0;
}
.timeline.in-dialog::before {
bottom: 0px;
}
@media (max-width: 991px) {
.timeline::before {
bottom: -64px;
}
}
.timeline-item.user-content {
margin: 30px 0px 30px 27px;
}
.timeline-item.user-content .media-body {
border: 1px solid #d1d8dd;
border-radius: 3px;
margin-left: -7px;
position: relative;
max-width: calc(100% - 50px);
padding-right: 0px;
overflow: visible;
}
.timeline-item.user-content .avatar-medium {
margin-right: 10px;
height: 45px;
width: 45px;
}
.timeline-item.user-content .action-btns {
position: absolute;
right: 0;
padding: 8px 15px 0 5px;
}
.timeline-item.user-content .action-btns .edit-btn-container {
margin-right: 13px;
}
.timeline-item.user-content .comment-header {
background-color: #fafbfc;
padding: 10px 15px 8px 13px;
margin: 0px;
color: #8D99A6;
border-bottom: 1px solid #EBEFF2;
}
.timeline-item.user-content .comment-header.links-active {
padding-right: 77px;
}
.timeline-item.user-content .comment-header .asset-details {
display: inline-block;
width: 100%;
}
.timeline-item.user-content .comment-header .asset-details .btn-link {
border: 0;
border-radius: 0;
padding: 0;
}
.timeline-item.user-content .comment-header .asset-details .btn-link:hover {
text-decoration: none;
}
.timeline-item.user-content .comment-header .commented-on-small {
display: none;
}
.timeline-item.user-content .comment-header .octicon-heart {
color: #ff5858;
cursor: pointer;
}
.timeline-item.user-content .reply {
padding: 15px;
overflow: auto;
}
.timeline-item.user-content .reply > div > p:first-child {
margin-top: 0px;
}
.timeline-item.user-content .reply > div > p:last-child {
margin-bottom: 0px;
}
.timeline-item.user-content .reply hr {
margin: 10px 0px;
}
.timeline-item.user-content .close-btn-container .close {
color: inherit;
opacity: 1;
padding: 0;
font-size: 18px;
}
.timeline-item.user-content .edit-btn-container {
padding: 0;
}
.timeline-item.user-content .edit-btn-container .edit {
color: inherit;
font-size: 21px;
line-height: 1;
}
.timeline-item.user-content .edit-btn-container .edit .octicon-check {
font-size: 1em;
}
.timeline-item.user-content .edit-btn-container .edit:hover,
.timeline-item.user-content .edit-btn-container .edit:focus {
color: #000;
}
.timeline-item.user-content .comment-likes {
margin-left: 5px;
}
.timeline-item.user-content .media-body:after,
.timeline-item.user-content .media-body:before {
right: 100%;
top: 15px;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.timeline-item.user-content .media-body:after {
border-color: rgba(136, 183, 213, 0);
border-right-color: #fafbfc;
border-width: 6px;
margin-top: -6px;
}
.timeline-item.user-content .media-body:before {
border-color: rgba(194, 225, 245, 0);
border-right-color: #d1d8dd;
border-width: 7px;
margin-top: -7px;
}
.timeline-item.notification-content {
padding-left: 30px;
margin: 30px 0px;
position: relative;
color: #8D99A6;
}
.timeline-item.notification-content * {
color: #8D99A6;
}
.timeline-item.notification-content .fa-fw {
margin-left: 36px;
}
.timeline-item.notification-content div.small {
padding-left: 40px;
}
.timeline-item.notification-content div.small .fa-fw {
margin-left: 0px;
}
.timeline-item.notification-content .octicon-heart {
color: #ff5858 !important;
}
.timeline-item.notification-content::before {
content: " ";
width: 7px;
height: 7px;
background-color: #d1d8dd;
position: absolute;
left: 40px;
border-radius: 50%;
top: 5px;
}
.timeline-item .reply-link {
margin-left: 15px;
font-size: 12px;
}
.timeline-head {
background-color: white;
border: 1px solid #d1d8dd;
border-radius: 3px;
position: relative;
z-index: 1;
}
.timeline-head .comment-input-header {
background-color: #fafbfc;
padding: 7px 15px;
border-bottom: 1px solid #EBEFF2;
}
.timeline-head .comment-input-container {
padding: 15px;
}
.timeline-head .comment-input-container .awesomplete > ul {
min-width: 200px;
}
.timeline-head .comment-input {
border-color: #EBEFF2;
max-width: 100%;
}
.timeline-head .comment-input:focus {
box-shadow: none;
}
@media (max-width: 767px) {
.timeline-head {
border-left: none;
border-right: none;
border-radius: 0px;
}
}
.signature-field {
min-height: 300px;
background: #fff;
border: 1px solid #d1d8dd;
border-radius: 3px;
position: relative;
margin-top: -10px;
}
.signature-display {
margin: 7px 0px;
background: #fff;
}
.signature-btn-row {
position: absolute;
bottom: 12px;
right: 12px;
}
.signature-reset {
z-index: 10;
height: 30px;
width: 30px;
padding: 4px 0px;
}
.signature-img {
background: #fff;
border-radius: 3px;
margin-top: 5px;
max-height: 150px;
}
.timeline-new-email {
margin: 30px 0px;
padding-left: 70px;
position: relative;
}
.timeline-new-email::before {
content: " ";
width: 7px;
height: 7px;
background-color: #d1d8dd;
position: absolute;
left: 40px;
border-radius: 50%;
top: 5px;
}
.form-footer h5 {
margin: 15px 0px;
font-weight: bold;
}
.control-label,
.grid-heading-row {
color: #8D99A6;
font-size: 12px;
}
.control-label {
margin-bottom: 5px;
font-weight: normal;
}
.like-disabled-input {
margin-bottom: 7px;
min-height: 30px;
font-weight: bold;
background-color: #f5f7fa;
padding: 5px 10px;
border-radius: 3px;
}
.disabled-check {
color: #f5f7fa;
margin-right: 5px;
margin-bottom: -2px;
}
.like-disabled-input.for-description {
font-weight: normal;
font-size: 12px;
}
.frappe-control {
margin-bottom: 10px;
}
.frappe-control .help-box {
margin-top: 3px;
}
.frappe-control pre {
white-space: pre-wrap;
background-color: inherit;
border: none;
padding: 0px;
margin: 0px;
}
.flex-justify-center {
display: flex;
justify-content: center;
}
.flex-justify-end {
display: flex;
justify-content: flex-end;
}
.hide-control {
display: none !important;
}
.shared-user {
margin-bottom: 10px;
}
.attach-missing-image,
.attach-image-display {
cursor: pointer;
}
select.form-control {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.form-control.bold {
color: #000;
font-weight: bold;
background-color: #fffdf4;
}
.form-control[data-fieldtype="Password"] {
position: inherit;
}
.password-strength-indicator {
float: right;
padding: 15px;
margin-top: -41px;
margin-right: -7px;
}
.password-strength-message {
margin-top: -10px;
}
.control-code,
.control-code.bold {
height: 400px;
font-family: Monaco, "Courier New", monospace;
color: #36414C;
font-size: 12px;
line-height: 1.7em;
}
.delivery-status-indicator {
display: inline-block;
margin-top: -3px;
margin-left: 1px;
font-weight: 500;
color: #8D99A6;
}
.attach-btn {
margin-top: 10px;
}
@media (min-width: 768px) {
.layout-main .form-column.col-sm-12 > form > .input-max-width {
max-width: 50%;
padding-right: 15px;
}
.col-sm-6 .form-grid .form-column.col-sm-12 > form > .input-max-width {
max-width: none;
padding-right: 0px;
}
.form-column.col-sm-6 textarea[data-fieldtype="Code"] {
height: 120px !important;
}
}
@media (max-width: 991px) {
.form-section .form-section-heading {
margin-top: 10px;
}
}
@media (max-width: 767px) {
.form-section .section-head {
padding: 15px 15px 15px 0px;
}
.form-section .section-body .form-column:first-child .radio,
.form-section .section-body .form-column:first-child .checkbox {
margin-top: 0;
}
.form-column {
border-bottom: 1px solid #EBEFF2;
padding-top: 15px;
padding-bottom: 15px;
}
.form-column:last-child {
border-bottom: 0px;
}
.form-section {
padding-left: 0px !important;
padding-right: 0px !important;
}
.form-grid {
margin-left: -17px;
margin-right: -17px;
border-left: none !important;
border-right: none !important;
border-radius: none;
}
.form-page .form-section {
padding: 0px 15px;
}
.frappe-control.form-page {
padding: 7px 15px;
border-bottom: 1px solid #EBEFF2;
margin: 0px -15px;
}
.frappe-control.form-page .link-btn {
top: -2px;
}
.frappe-control.form-page .like-disabled-input {
min-height: 0px !important;
}
.frappe-control.form-page:last-child {
margin-bottom: 0px;
}
.form-page .frappe-control:last-child {
border-bottom: 0px;
}
.form-page .frappe-control[data-fieldtype="Table"] {
padding: 0px 15px;
margin-top: -1px;
border-bottom: none;
}
.form-page .frappe-control[data-fieldtype="Table"] label {
margin-top: 7px;
}
.form-page .form-control {
border: none;
border-bottom: 1px solid #d1d8dd;
box-shadow: none;
background-color: inherit;
height: auto;
padding: 0px;
margin-bottom: 7px;
border-radius: 0px;
text-align: left !important;
}
.form-page .form-control:focus {
box-shadow: none;
}
}
/* goals */
.goals-page-container {
background-color: #fafbfc;
padding-top: 1px;
}
.goals-page-container .goal-container {
background-color: #fff;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
border-radius: 2px;
padding: 10px;
margin: 10px;
}
body[data-route^="Form/Communication"] textarea[data-fieldname="subject"] {
height: 80px !important;
}
.frappe-control[data-fieldtype="Attach"] .attached-file {
position: relative;
margin-top: 5px;
}
.frappe-control[data-fieldtype="Attach"] .attached-file .close {
position: absolute;
top: 0;
right: 0;
}

+ 0
- 411
frappe/public/css/mobile.css ファイルの表示

@@ -1,411 +0,0 @@
/* the element that this class is applied to, should have a max width for this to work*/
html {
min-height: 100%;
}
body {
height: 100%;
margin: 0px;
padding: 0px !important;
}
html,
body {
overflow-x: hidden;
overflow-y: overlay;
}
@media (max-width: 991px) {
.intro-area,
.footnote-area {
padding: 15px;
}
.grid-row-open {
top: 0;
}
.layout-main {
position: relative;
}
body[data-route^="Form"] .page-title h1 {
margin-top: 12px;
}
body[data-route^="Form"] .page-title h1.editable-title {
padding-right: 80px;
}
body[data-route^="Form"] .page-title .indicator {
display: inline-block;
margin-top: 12px;
}
body[data-route^="Form"] .page-actions {
padding-top: 20px !important;
padding-bottom: 0px !important;
padding-left: 0px !important;
}
body[data-route^="Form"] .page-head .sub-heading {
font-weight: normal;
font-size: 10px;
display: block;
position: absolute;
right: 140px;
min-width: 200px;
}
body[data-route^="Form"] .title-text {
margin-top: 10px;
}
.toggle-navbar-new-comments {
padding: 8px 0px !important;
}
.navbar > .container > .navbar-header {
float: left;
width: 80%;
}
.navbar > .container > .navbar-right {
float: right;
}
.module-item {
padding: 7px 0px !important;
}
.module-item h4 {
font-weight: normal;
}
#navbar-breadcrumbs {
margin: 0px;
display: inline-block;
max-width: 150px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
#navbar-breadcrumbs > li,
#navbar-breadcrumbs > li > a {
display: inline-block;
vertical-align: middle;
}
#navbar-breadcrumbs > li > a:before {
content: "\f104";
margin-right: 10px;
color: #6C7680;
}
#navbar-breadcrumbs li:not(:nth-last-child(-n+1)) {
display: none;
}
.navbar-nav {
margin: 0px;
margin-right: -15px;
}
.sidebar .form-group {
margin-bottom: 0px;
}
#sidebar-search {
height: 27px;
}
.sidebar .navbar-search-icon {
float: right;
color: #6C7680;
font-size: inherit;
position: relative;
right: 7px;
top: -20px;
height: 0;
}
.sidebar form {
padding: 7px;
}
.sidebar .main-menu {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 41px;
overflow-y: auto;
}
.sidebar .user-menu {
padding: 9px 14px;
background-color: #f5f7fa;
position: absolute;
left: 0;
bottom: 0;
right: 0;
}
.sidebar .user-menu,
.sidebar .user-menu .octicon {
color: #6C7680;
}
.sidebar .user-menu img {
margin-top: -1px;
}
body[data-route^="Module"] .navbar-center {
display: block !important;
position: absolute;
top: 10px;
left: 25%;
right: 25%;
text-align: center;
}
body.no-breadcrumbs .navbar .navbar-home {
display: inline-block !important;
padding-left: 0px;
margin-left: 0px;
padding-top: 6px;
}
body.no-breadcrumbs .navbar .navbar-home:before {
font-family: FontAwesome;
font-weight: normal;
font-style: normal;
text-decoration: inherit;
-webkit-font-smoothing: antialiased;
*margin-right: 0.3em;
display: inline-block;
speak: none;
font-size: 24px;
transition: 0.2s;
position: relative;
top: 3px;
content: "\f104";
margin-right: 10px;
color: #6C7680;
}
body.no-breadcrumbs .navbar .navbar-home:hover:before,
body.no-breadcrumbs .navbar .navbar-home:focus:before,
body.no-breadcrumbs .navbar .navbar-home:active:before {
color: #36414C !important;
}
body[data-route=""] .navbar .navbar-home,
body[data-route="desktop"] .navbar .navbar-home {
padding: 8px 10px;
}
body[data-route=""] .navbar .navbar-home:before,
body[data-route="desktop"] .navbar .navbar-home:before {
display: none;
}
body[data-route=""] .navbar .navbar-home img,
body[data-route="desktop"] .navbar .navbar-home img {
margin-top: 0;
}
body[data-route=""] .toggle-sidebar,
body[data-route="desktop"] .toggle-sidebar {
display: none !important;
}
body[data-sidebar="0"] .toggle-sidebar {
display: none !important;
}
body[data-sidebar="0"] #navbar-breadcrumbs,
body[data-sidebar="0"] .navbar-home {
margin-left: 15px !important;
}
}
@media (max-width: 991px) and (max-width: 480px) {
#navbar-breadcrumbs li > a {
width: 100px;
}
}
@media (max-width: 767px) {
.toggle-sidebar {
margin-right: 0;
}
body[data-route^="Form"] .page-title .title-text {
font-size: 16px;
width: calc(100% - 90px);
}
body[data-route^="Form"] .page-title .indicator {
float: left;
margin-top: 10px;
margin-right: 5px;
}
.modal .modal-dialog {
margin: 0px;
padding: 0px;
width: 100%;
background-color: #fff;
}
.modal .modal-content {
border-radius: 0px;
border: none;
height: 100%;
}
.modal .modal-body .form-layout {
margin: -15px;
}
.modal .file-upload .input-upload {
width: 100%;
text-align: center;
}
.modal .file-upload .input-upload .btn-browse {
width: 100%;
}
.modal .file-upload .web-link-wrapper {
display: block;
width: 100% !important;
text-align: center;
}
.modal .file-upload .web-link-wrapper .file-upload-or {
display: block;
margin: 15px 24px;
}
.modal .file-upload .web-link-wrapper .input-link {
width: 100% !important;
}
.layout-main-section-wrapper {
padding: 0px;
}
.layout-main-section {
border-left-color: transparent !important;
border-right-color: transparent !important;
}
.list-row {
padding: 13px 15px !important;
}
.doclist-row {
position: relative;
padding-right: 10px;
}
.doclist-row .list-id {
font-weight: normal;
}
.doclist-row .list-row-id {
left: 18px;
text-align: left;
margin-top: 3px;
}
.doclist-row.has-checkbox .list-row-id {
left: 40px;
}
.doclist-row .list-row-indicator {
position: absolute;
right: 0px;
top: -20px;
}
.doclist-row .list-row-modified {
margin-right: -10px;
}
.doclist-row .list-row-left {
z-index: 1;
}
.doclist-row .list-row-right {
float: right;
}
.doclist-row .list-row-right .list-row-indicator {
top: 4px;
}
.doclist-row .list-row-right .list-row-indicator .indicator::before,
.doclist-row .list-row-right .list-row-indicator .indicator::after {
height: 12px;
width: 12px;
border-radius: 12px;
}
.doclist-row .list-row-right.no-right-column {
position: absolute;
top: 0;
right: 10px;
left: -10px;
width: 100%;
}
body[data-route^="chat"] .navbar-center {
display: block !important;
position: absolute;
top: 10px;
left: 25%;
right: 25%;
text-align: center;
}
#page-chat .layout-side-section {
position: relative;
left: 0px;
border-right: 1px solid #d1d8dd;
padding-left: 0px;
float: left;
width: 76px;
}
#page-chat .layout-main-section-wrapper {
position: absolute;
left: 75px;
right: 0px;
border-left: 1px solid #d1d8dd;
float: left;
}
#page-chat .module-sidebar-item {
margin: 0px;
}
#page-chat .module-sidebar-item .chat-sidebar-link {
padding: 15px;
}
#page-chat .timeline-head {
padding: 15px 15px 7px;
}
#page-chat .list-row {
padding: 7px 0px;
}
#page-chat .message-row-right {
margin-top: 10px;
text-align: left;
}
body[data-route^="Form"] .page-head .sub-heading {
right: 90px;
}
.timeline::before {
content: none;
}
.timeline .timeline-new-email {
margin: 20px 0;
padding-left: 15px;
}
.timeline .timeline-new-email::before {
content: none;
}
.timeline .timeline-item.user-content {
margin: 20px 15px;
}
.timeline .timeline-item.user-content .media-body {
margin-left: 0;
max-width: 100%;
overflow: hidden;
}
.timeline .timeline-item.user-content .media-body:before {
content: none;
}
.timeline .timeline-item.user-content .action-btns {
padding: 7px 10px 2px 5px;
}
.timeline .timeline-item.user-content .action-btns .edit-btn-container {
margin-right: 0;
}
.timeline .timeline-item.user-content .comment-header {
padding: 7px 10px;
}
.timeline .timeline-item.user-content .comment-header .links-active {
padding-right: 10px;
}
.timeline .timeline-item.user-content .comment-header .reply-link {
margin-left: 0;
}
.timeline .timeline-item.user-content .comment-header .asset-details {
width: calc(100% - 30px);
}
.timeline .timeline-item.user-content .avatar-medium {
margin-right: 10px;
}
.timeline .timeline-item.user-content .reply {
padding: 10px;
}
.timeline .timeline-item.user-content .commented-on-small {
display: inline-block;
}
.timeline .timeline-item.user-content .commented-on-small {
display: inline-block;
}
.timeline .timeline-item.notification-content {
padding-left: 15px;
margin: 20px 0;
}
.timeline .timeline-item.notification-content::before {
content: none;
}
.timeline .timeline-item.notification-content .small {
padding-left: 0;
}
.timeline .timeline-item .delivery-status-indicator {
float: left;
margin: 0 5px 0 0;
}
.timeline .asset-details {
line-height: 24px;
/*Height of avtar image -36px to align text center vertically*/
}
}

+ 0
- 0
frappe/public/css/variables.css ファイルの表示


+ 12
- 3
frappe/public/icons/timeless/symbol-defs.svg ファイルの表示

@@ -1,4 +1,4 @@
<svg width="0" height="0" class="d-block" xmlns="http://www.w3.org/2000/svg">
<svg aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;" class="d-block" xmlns="http://www.w3.org/2000/svg">
<symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-resting">
<path d="M7.606 3.799L8 4.302l.394-.503.106-.14c.048-.065.08-.108.129-.159a3.284 3.284 0 0 1 4.72 0c.424.434.655 1.245.65 2.278-.006 1.578-.685 2.931-1.728 4.159-1.05 1.234-2.439 2.308-3.814 3.328a.763.763 0 0 1-.914 0c-1.375-1.02-2.764-2.094-3.814-3.328C2.686 8.709 2.007 7.357 2 5.778c-.004-1.033.227-1.844.651-2.278a3.284 3.284 0 0 1 4.72 0c.05.05.081.094.129.158.028.038.061.083.106.14z"
stroke="var(--icon-stroke)"></path>
@@ -138,7 +138,10 @@
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.25 6C3.25 5.72386 3.47386 5.5 3.75 5.5H20.2474C20.5236 5.5 20.7474 5.72386 20.7474 6C20.7474 6.27614 20.5236 6.5 20.2474 6.5H3.75C3.47386 6.5 3.25 6.27614 3.25 6ZM3.25 12C3.25 11.7239 3.47386 11.5 3.75 11.5H20.2474C20.5236 11.5 20.7474 11.7239 20.7474 12C20.7474 12.2761 20.5236 12.5 20.2474 12.5H3.75C3.47386 12.5 3.25 12.2761 3.25 12ZM3.75 17.5C3.47386 17.5 3.25 17.7239 3.25 18C3.25 18.2761 3.47386 18.5 3.75 18.5H20.2474C20.5236 18.5 20.7474 18.2761 20.7474 18C20.7474 17.7239 20.5236 17.5 20.2474 17.5H3.75Z" fill="var(--icon-stroke)"/>
</symbol>
<symbol fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" id="icon-lock">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.077 1.45h-.055a3.356 3.356 0 00-3.387 3.322v.35H3.75a2 2 0 00-2 2v5.391a2 2 0 002 2h8.539a2 2 0 002-2V7.122a2 2 0 00-2-2h-.885v-.285A3.356 3.356 0 008.082 1.45h-.005zm2.327 3.672V4.83a2.356 2.356 0 00-2.33-2.38h-.06a2.356 2.356 0 00-2.38 2.33v.342h4.77zm-6.654 1a1 1 0 00-1 1v5.391a1 1 0 001 1h8.539a1 1 0 001-1V7.122a1 1 0 00-1-1H3.75zm4.27 4.269a.573.573 0 100-1.147.573.573 0 000 1.147zm1.573-.574a1.573 1.573 0 11-3.147 0 1.573 1.573 0 013.147 0z"></path>
<path stroke="none" fill-rule="evenodd" clip-rule="evenodd" d="M8.077 1.45h-.055a3.356 3.356 0 00-3.387 3.322v.35H3.75a2 2 0 00-2 2v5.391a2 2 0 002 2h8.539a2 2 0 002-2V7.122a2 2 0 00-2-2h-.885v-.285A3.356 3.356 0 008.082 1.45h-.005zm2.327 3.672V4.83a2.356 2.356 0 00-2.33-2.38h-.06a2.356 2.356 0 00-2.38 2.33v.342h4.77zm-6.654 1a1 1 0 00-1 1v5.391a1 1 0 001 1h8.539a1 1 0 001-1V7.122a1 1 0 00-1-1H3.75zm4.27 4.269a.573.573 0 100-1.147.573.573 0 000 1.147zm1.573-.574a1.573 1.573 0 11-3.147 0 1.573 1.573 0 013.147 0z" fill="#1F272E"></path>
</symbol>
<symbol width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" id="icon-unlock">
<path stroke="none" fill-rule="evenodd" clip-rule="evenodd" d="M8.07685 1.45034H8.02155C7.13255 1.44218 6.2766 1.78707 5.64159 2.40938C5.00596 3.03229 4.64377 3.88215 4.63464 4.77206L4.63462 4.77206V4.77719V5.12175H3.75C2.64543 5.12175 1.75 6.01719 1.75 7.12175V12.5134C1.75 13.6179 2.64543 14.5134 3.75 14.5134H12.2885C13.393 14.5134 14.2885 13.6179 14.2885 12.5134V7.12175C14.2885 6.01718 13.393 5.12175 12.2885 5.12175H5.63462V4.77988C5.64166 4.156 5.89586 3.56033 6.34152 3.12359C6.78776 2.68627 7.38942 2.4441 8.01419 2.45031L8.01418 2.45034H8.01916H8.07417C8.69805 2.45738 9.29371 2.71158 9.73045 3.15724C9.92373 3.35446 10.2403 3.35766 10.4375 3.16438C10.6347 2.9711 10.6379 2.65453 10.4447 2.45731C9.82175 1.82169 8.97189 1.45949 8.08198 1.45036L8.08198 1.45034H8.07685ZM3.75 6.12175C3.19772 6.12175 2.75 6.56947 2.75 7.12175V12.5134C2.75 13.0656 3.19772 13.5134 3.75 13.5134H12.2885C12.8407 13.5134 13.2885 13.0656 13.2885 12.5134V7.12175C13.2885 6.56947 12.8407 6.12175 12.2885 6.12175H3.75ZM8.01936 10.3909C8.33605 10.3909 8.59279 10.1342 8.59279 9.81752C8.59279 9.50083 8.33605 9.24409 8.01936 9.24409C7.70266 9.24409 7.44593 9.50083 7.44593 9.81752C7.44593 10.1342 7.70266 10.3909 8.01936 10.3909ZM9.59279 9.81752C9.59279 10.6865 8.88834 11.3909 8.01936 11.3909C7.15038 11.3909 6.44593 10.6865 6.44593 9.81752C6.44593 8.94854 7.15038 8.24409 8.01936 8.24409C8.88834 8.24409 9.59279 8.94854 9.59279 9.81752Z" fill="#1F272E"/>
</symbol>
<symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-list_alt">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.5 3.722c0-.454.316-.722.59-.722h9.82c.274 0 .59.268.59.722v8.556c0 .454-.316.722-.59.722H3.09c-.274 0-.59-.268-.59-.722V3.722zM3.09 2c-.93 0-1.59.826-1.59 1.722v8.556c0 .896.66 1.722 1.59 1.722h9.82c.93 0 1.59-.826 1.59-1.722V3.722C14.5 2.826 13.84 2 12.91 2H3.09zM5 4.5a.5.5 0 0 0 0 1h4.002a.5.5 0 1 0 0-1H5zM5 7a.5.5 0 0 0 0 1h5.002a.5.5 0 1 0 0-1H5zm-.5 3a.5.5 0 0 1 .5-.5h2.27a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5z"
@@ -265,7 +268,7 @@
<path d="M16.127 13.077l3.194 3.194a2.588 2.588 0 0 1 0 3.66 2.589 2.589 0 0 1-3.66 0l-2.902-2.902" stroke="var(--icon-stroke)" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M11.315 10.095l-4.96-4.96a1.294 1.294 0 1 0-1.83 1.83l4.877 4.877" stroke="var(--icon-stroke)" stroke-miterlimit="10"></path>
<path d="M18.56 11.949l-.353.353a.5.5 0 0 0 .707 0l-.354-.353zM21 9.509l.354.353a.5.5 0 0 0 0-.705L21 9.509zm-5.47-5.51l.354-.352-.004-.004-.35.357zm-4.9.02l-.353-.353a.5.5 0 0 0 0 .707l.353-.354zm8.284 8.283l2.44-2.44-.707-.707-2.44 2.44.707.707zm2.44-3.145l-5.47-5.51-.71.705 5.471 5.51.71-.705zM15.88 3.643A3.977 3.977 0 0 0 13.074 2.5l.004 1a2.977 2.977 0 0 1 2.1.856l.702-.713zM13.074 2.5a3.977 3.977 0 0 0-2.797 1.166l.707.706a2.977 2.977 0 0 1 2.094-.872l-.004-1zm-2.797 1.873l7.93 7.93.707-.708-7.93-7.93-.707.708z"
fill="#4C5A67" stroke="none"></path>
fill="var(--icon-stroke)" stroke="none"></path>
<path d="M14.133 7.522L3.398 17.325a1.219 1.219 0 0 0-.04 1.764L4.6 20.331a1.22 1.22 0 0 0 1.764-.04l9.789-10.75" stroke="var(--icon-stroke)" stroke-miterlimit="10"></path>
</symbol>
<symbol viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" id="icon-support">
@@ -684,4 +687,10 @@
<path d="M10 6.00223L1 5.99973" stroke="var(--icon-stroke)" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.70015 3.00244L10.7001 6.00244L7.70015 9.00244" stroke="var(--icon-stroke)" stroke-linecap="round" stroke-linejoin="round"/>
</symbol>
<symbol viewBox="0 0 16 22" xmlns="http://www.w3.org/2000/svg" id="icon-dialpad">
<path fill-rule="evenodd" stroke="none" fill="var(--icon-stroke)" d="M8 18c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zM2 0C.9 0 0 .9 0 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6C.9 6 0 6.9 0 8s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12-8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-6 8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zM8 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6C6.9 0 6 .9 6 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" stroke="var(--icon-stroke)" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</symbol>
<symbol viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" id="icon-star">
<path d="M11.5516 2.90849C11.735 2.53687 12.265 2.53687 12.4484 2.90849L14.8226 7.71919C14.8954 7.86677 15.0362 7.96905 15.1991 7.99271L20.508 8.76415C20.9181 8.82374 21.0818 9.32772 20.7851 9.61699L16.9435 13.3616C16.8257 13.4765 16.7719 13.642 16.7997 13.8042L17.7066 19.0916C17.7766 19.5001 17.3479 19.8116 16.9811 19.6187L12.2327 17.1223C12.087 17.0457 11.913 17.0457 11.7673 17.1223L7.01888 19.6187C6.65207 19.8116 6.22335 19.5001 6.29341 19.0916L7.20028 13.8042C7.2281 13.642 7.17433 13.4765 7.05648 13.3616L3.21491 9.61699C2.91815 9.32772 3.08191 8.82374 3.49202 8.76415L8.80094 7.99271C8.9638 7.96905 9.10458 7.86677 9.17741 7.71919L11.5516 2.90849Z" fill="var(--star-fill)" stroke="var(--star-fill)"/>
</symbol>
</svg>

バイナリ
frappe/public/images/favicon.png ファイルの表示

変更前 変更後
幅: 128  |  高さ: 128  |  サイズ: 4.5 KiB

+ 0
- 52
frappe/public/js/docs.js ファイルの表示

@@ -1,52 +0,0 @@
// used in documenation site built via document generator

$(function() {
if(window.hljs) {
$('pre code').each(function(i, block) {
hljs.highlightBlock(block);
});
}

// search
$('.sidebar-navbar-items .octicon-search, .navbar .octicon-search').parent().on("click", function() {
var modal = frappe.get_modal("Search",
'<p><input class="search-input form-control" type="text" placeholder="Search text..." tabindex="1"></p>\
<p><a class="btn btn-sm btn-default btn-search" href="#" target="_blank" tabindex="2">Search via Google</a></p>');
modal.find(".search-input").on("keyup", function(e) {
if(e.which===13) {
modal.find(".btn-search").trigger("click");
}
if(e.which===9) {
e.preventDefault();
modal.find(".btn-search").focus();
return false;
}
var text = $(this).val();
modal.find(".btn-search").attr("href", "https://google.com/search?q="
+ text + "+site:" + (window.docs_base_url || ""));
});
modal.modal("show");
return false;
});

});

frappe = {
get_modal: function(title, body_html) {
var modal = $('<div class="modal" style="overflow: auto;" tabindex="-1">\
<div class="modal-dialog">\
<div class="modal-content">\
<div class="modal-header">\
<a type="button" class="close"\
data-dismiss="modal" aria-hidden="true">&times;</a>\
<h4 class="modal-title">'+title+'</h4>\
</div>\
<div class="modal-body ui-front">'+body_html+'\
</div>\
</div>\
</div>\
</div>').appendTo(document.body);

return modal;
},
};

+ 5
- 4
frappe/public/js/frappe/chat.js ファイルの表示

@@ -2781,7 +2781,8 @@ frappe.chat.setup = () => {
}
}

$(document).on('ready toolbar_setup', () =>
{
frappe.chat.setup()
})
// TODO: Re-enable after re-designing chat
// $(document).on('ready toolbar_setup', () =>
// {
// frappe.chat.setup()
// })

+ 2
- 2
frappe/public/js/frappe/data_import/import_preview.js ファイルの表示

@@ -188,8 +188,8 @@ frappe.data_import.ImportPreview = class ImportPreview {
.join(',');
this.datatable.style.setStyle(row_classes, {
pointerEvents: 'none',
backgroundColor: frappe.ui.color.get_color_shade('white', 'light'),
color: frappe.ui.color.get_color_shade('black', 'extra-light')
backgroundColor: frappe.ui.color.get_color_shade('gray', 'extra-light'),
color: frappe.ui.color.get_color_shade('gray', 'dark')
});
}



+ 7
- 19
frappe/public/js/frappe/desk.js ファイルの表示

@@ -45,10 +45,7 @@ frappe.Application = Class.extend({
this.setup_frappe_vue();
this.load_bootinfo();
this.load_user_permissions();
this.set_app_logo_url()
.then(() => {
this.make_nav_bar();
});
this.make_nav_bar();
this.set_favicon();
this.setup_analytics();
this.set_fullwidth_if_enabled();
@@ -82,8 +79,11 @@ frappe.Application = Class.extend({
}

if (frappe.user_roles.includes('System Manager')) {
this.show_change_log();
this.show_update_available();
// delayed following requests to make boot faster
setTimeout(() => {
this.show_change_log();
this.show_update_available();
}, 1000);
}

if (!frappe.boot.developer_mode) {
@@ -470,19 +470,6 @@ frappe.Application = Class.extend({
$('<link rel="shortcut icon" href="' + link + '" type="image/x-icon">').appendTo("head");
$('<link rel="icon" href="' + link + '" type="image/x-icon">').appendTo("head");
},

set_app_logo_url: function() {
return frappe.call('frappe.core.doctype.navbar_settings.navbar_settings.get_app_logo')
.then(r => {
frappe.app.logo_url = r.message;
if (window.cordova) {
let host = frappe.request.url;
host = host.slice(0, host.length - 1);
frappe.app.logo_url = host + frappe.app.logo_url;
}
});
},

trigger_primary_action: function() {
if(window.cur_dialog && cur_dialog.display) {
// trigger primary
@@ -498,6 +485,7 @@ frappe.Application = Class.extend({
if (frappe.utils.is_rtl()) {
var ls = document.createElement('link');
ls.rel="stylesheet";
ls.type = "text/css";
ls.href= "assets/css/frappe-rtl.css";
document.getElementsByTagName('head')[0].appendChild(ls);
$('body').addClass('frappe-rtl');


+ 15
- 7
frappe/public/js/frappe/file_uploader/FilePreview.vue ファイルの表示

@@ -11,17 +11,18 @@
</div>
<div>
<div>
<a :href="file.doc.file_url" v-if="file.doc" target="_blank">
<a class="flex" :href="file.doc.file_url" v-if="file.doc" target="_blank">
<span class="file-name">{{ file.name | file_name }}</span>
<i v-html="frappe.utils.icon(file.doc.is_private ? 'lock' : 'unlock')"></i>
<div class="ml-2" v-html="private_icon"></div>
</a>
<span class="flex" v-else>
<span class="file-name">{{ file.name | file_name }}</span>
<span class="cursor-pointer" @click="$emit('toggle_private')" :title="__('Toggle Public/Private')">
<i v-html="frappe.utils.icon(file.is_private ? 'lock' : 'unlock')"></i>
</span>
<button class="ml-2 btn-reset" @click="$emit('toggle_private')" :title="__('Toggle Public/Private')">
<div v-html="private_icon"></div>
</button>
</span>
</div>

<div>
<span class="file-size">
{{ file.file_obj.size | file_size }}
@@ -30,7 +31,7 @@
</div>
<div class="file-actions">
<ProgressRing
v-show="file.uploading"
v-show="file.uploading && !uploaded"
primary="var(--primary-color)"
secondary="var(--gray-200)"
radius="24"
@@ -76,6 +77,12 @@ export default {
}
},
computed: {
private_icon() {
return frappe.utils.icon(this.is_private ? 'lock' : 'unlock');
},
is_private() {
return this.file.doc ? this.file.doc.is_private : this.file.private;
},
uploaded() {
return this.file.total && this.file.total === this.file.progress && !this.file.failed;
},
@@ -156,9 +163,10 @@ export default {
}

.file-actions {
width: 2.5rem;
width: 3rem;
flex-shrink: 0;
margin-left: auto;
text-align: center;
}

.file-actions .btn {


+ 14
- 18
frappe/public/js/frappe/file_uploader/FileUploader.vue ファイルの表示

@@ -73,21 +73,13 @@
</div>
</div>
<div class="file-preview-area" v-show="files.length && !show_file_browser && !show_web_link">
<!-- <div class="margin-bottom" v-if="!upload_complete">
<label>
<input type="checkbox" class="input-with-feedback" @change="e => toggle_all_private(e.target.checked)">
<span class="text-medium" style="font-weight: normal;">
{{ __('Make all attachments private') }}
</span>
</label>
</div> -->
<div class="file-preview-container">
<FilePreview
v-for="(file, i) in files"
:key="file.name"
:file="file"
@remove="remove_file(i)"
@toggle_private="toggle_private(i)"
@remove="remove_file(file)"
@toggle_private="file.private = !file.private"
/>
</div>
<div class="flex align-center" v-if="show_upload_button && currently_uploading === -1">
@@ -217,15 +209,19 @@ export default {
on_file_input(e) {
this.add_files(this.$refs.file_input.files);
},
remove_file(i) {
this.files = this.files.filter((file, j) => i !== j);
},
toggle_private(i) {
this.files[i].private = !this.files[i].private;
remove_file(file) {
this.files = this.files.filter(f => f !== file);
},
toggle_all_private(flag) {
if (flag == null) {
flag = this.files.every(file => file.private);
toggle_all_private() {
let flag;
let private_values = this.files.filter(file => file.private);
if (private_values.length < this.files.length) {
// there are some private and some public
// set all to private
flag = true;
} else {
// all are private, set all to public
flag = false;
}
this.files = this.files.map(file => {
file.private = flag;


+ 11
- 2
frappe/public/js/frappe/file_uploader/index.js ファイルの表示

@@ -48,6 +48,13 @@ export default class FileUploader {

this.uploader = this.$fileuploader.$children[0];

this.uploader.$watch('files', (files) => {
let all_private = files.every(file => file.private);
if (this.dialog) {
this.dialog.set_secondary_action_label(all_private ? __('Set all public') : __('Set all private'));
}
}, { deep: true });

if (files && files.length) {
this.uploader.add_files(files);
}
@@ -66,8 +73,10 @@ export default class FileUploader {
title: __('Upload'),
primary_action_label: __('Upload'),
primary_action: () => this.upload_files(),
secondary_action_label: __('Toggle Private'),
secondary_action: () => this.uploader.toggle_all_private()
secondary_action_label: __('Set all private'),
secondary_action: () => {
this.uploader.toggle_all_private();
}
});

this.wrapper = this.dialog.body;


+ 1
- 0
frappe/public/js/frappe/form/controls/autocomplete.js ファイルの表示

@@ -1,6 +1,7 @@
import Awesomplete from 'awesomplete';

frappe.ui.form.ControlAutocomplete = frappe.ui.form.ControlData.extend({
trigger_change_on_input_event: false,
make_input() {
this._super();
this.setup_awesomplete();


+ 9
- 2
frappe/public/js/frappe/form/controls/barcode.js ファイルの表示

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

get_options(value) {
// get JsBarcode options
let options = JSON.parse('{ "height" : 40 }');
let options = {};
options.background = "var(--control-bg)";
options.lineColor = "var(--text-color)";
options.font = "var(--font-stack)";
options.fontSize = "16";
options.width = "3";
options.height = "50";

if (frappe.utils.is_json(this.df.options)) {
options = JSON.parse(this.df.options);
if (options.format && options.format === 'EAN') {


+ 1
- 1
frappe/public/js/frappe/form/controls/base_control.js ファイルの表示

@@ -74,7 +74,7 @@ frappe.ui.form.Control = Class.extend({
frappe.model.get_doc(this.doctype, this.docname), this.perm || (this.frm && this.frm.perm), explain);

// Match parent grid controls read only status
if (status === 'Write' && (this.grid || (this.layout && this.layout.grid))) {
if (status === 'Write' && (this.grid || (this.layout && this.layout.grid) && !cint(this.df.allow_on_submit))) {
var grid = this.grid || this.layout.grid;
if (grid.display_status == 'Read') {
status = 'Read';


+ 1
- 1
frappe/public/js/frappe/form/controls/image.js ファイルの表示

@@ -14,7 +14,7 @@ frappe.ui.form.ControlImage = frappe.ui.form.Control.extend({
this.$img = $("<img src='"+doc[this.df.options]+"' class='img-responsive'>")
.appendTo(this.$body);
} else {
this.$buffer = $("<div class='missing-image'><i class='octicon octicon-circle-slash'></i></div>")
this.$buffer = $(`<div class='missing-image'>${frappe.utils.icon('restriction', 'md')}</div>`)
.appendTo(this.$body);
}
return false;


+ 1
- 0
frappe/public/js/frappe/form/controls/int.js ファイルの表示

@@ -1,4 +1,5 @@
frappe.ui.form.ControlInt = frappe.ui.form.ControlData.extend({
trigger_change_on_input_event: false,
make: function () {
this._super();
// $(this.label_area).addClass('pull-right');


+ 1
- 1
frappe/public/js/frappe/form/controls/link.js ファイルの表示

@@ -136,7 +136,7 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
return $('<li></li>')
.data('item.autocomplete', d)
.prop('aria-selected', 'false')
.html('<a><p>' + html + '</p></a>')
.html(`<a><p class="ellipsis" title="${_label}">${html}</p></a>`)
.get(0);
},
sort: function() {


+ 1
- 0
frappe/public/js/frappe/form/controls/multiselect_list.js ファイルの表示

@@ -1,4 +1,5 @@
frappe.ui.form.ControlMultiSelectList = frappe.ui.form.ControlData.extend({
trigger_change_on_input_event: false,
make_input() {
let template = `
<div class="multiselect-list dropdown">


+ 5
- 5
frappe/public/js/frappe/form/controls/multiselect_pills.js ファイルの表示

@@ -84,12 +84,12 @@ frappe.ui.form.ControlMultiSelectPills = frappe.ui.form.ControlAutocomplete.exte

get_pill_html(value) {
const encoded_value = encodeURIComponent(value);
return `<div class="btn-group tb-selected-value" data-value="${encoded_value}">
<button class="btn btn-default btn-xs btn-link-to-form">${__(value)}</button>
<button class="btn btn-default btn-xs btn-remove">
${frappe.utils.icon('close')}
return `
<button class="data-pill btn tb-selected-value" data-value="${encoded_value}">
<span class="btn-link-to-form">${__(value)}</span>
<span class="btn-remove">${frappe.utils.icon('close')}</span>
</button>
</div>`;
`;
},

get_awesomplete_settings() {


+ 16
- 14
frappe/public/js/frappe/form/controls/rating.js ファイルの表示

@@ -1,22 +1,24 @@
frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
make_input() {
this._super();
let stars = '';
[1, 2, 3, 4, 5].forEach(i => {
stars += `<svg class="icon icon-md" data-rating=${i}>
<use href="#icon-star"></use>
</svg>`;
});
const star_template = `
<div class="rating">
<i class="fa fa-fw fa-star" data-rating=1></i>
<i class="fa fa-fw fa-star" data-rating=2></i>
<i class="fa fa-fw fa-star" data-rating=3></i>
<i class="fa fa-fw fa-star" data-rating=4></i>
<i class="fa fa-fw fa-star" data-rating=5></i>
${stars}
</div>
`;

$(this.input_area).html(star_template);

$(this.input_area).find('i').hover((ev) => {
$(this.input_area).find('svg').hover((ev) => {
const el = $(ev.currentTarget);
let star_value = el.data('rating');
el.parent().children('i.fa').each( function(e) {
el.parent().children('svg').each( function(e) {
if (e < star_value) {
$(this).addClass('star-hover');
} else {
@@ -25,16 +27,16 @@ frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
});
}, (ev) => {
const el = $(ev.currentTarget);
el.parent().children('i.fa').each( function() {
el.parent().children('svg').each( function() {
$(this).removeClass('star-hover');
});
});

$(this.input_area).find('i').click((ev) => {
$(this.input_area).find('svg').click((ev) => {
const el = $(ev.currentTarget);
let star_value = el.data('rating');
el.parent().children('i.fa').each( function(e) {
if (e < star_value){
el.parent().children('svg').each( function(e) {
if (e < star_value) {
$(this).addClass('star-click');
} else {
$(this).removeClass('star-click');
@@ -50,8 +52,8 @@ frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
return cint(this.value, null);
},
set_formatted_input(value) {
let el = $(this.input_area).find('i');
el.children('i.fa').prevObject.each( function(e) {
let el = $(this.input_area).find('svg');
el.children('svg').prevObject.each( function(e) {
if (e < value) {
$(this).addClass('star-click');
} else {
@@ -59,4 +61,4 @@ frappe.ui.form.ControlRating = frappe.ui.form.ControlInt.extend({
}
});
}
});
});

+ 12
- 6
frappe/public/js/frappe/form/controls/signature.js ファイルの表示

@@ -18,7 +18,7 @@ frappe.ui.form.ControlSignature = frappe.ui.form.ControlData.extend({

this.img_wrapper = $(`<div class="signature-display">
<div class="missing-image attach-missing-image">
<i class="octicon octicon-circle-slash"></i>
${frappe.utils.icon('restriction', 'md')}</i>
</div></div>`)
.appendTo(this.wrapper);
this.img = $("<img class='img-responsive attach-image-display'>")
@@ -29,15 +29,21 @@ frappe.ui.form.ControlSignature = frappe.ui.form.ControlData.extend({
let width = this.body.width();
if (width > 0 && !this.$pad) {
this.$pad = this.body.jSignature({
height: 300,
height: 200,
color: "var(--text-color)",
width: this.body.width(),
lineWidth: 3
lineWidth: 2,
"background-color": "var(--control-bg)"
}).on('change',
this.on_save_sign.bind(this));
this.load_pad();
this.$reset_button_wrapper = $(`<div class="signature-btn-row">
<a href="#" type="button" class="signature-reset btn btn-default">
<i class="glyphicon glyphicon-repeat"></i></a>`)
this.$reset_button_wrapper = $(`
<div class="signature-btn-row">
<a href="#" type="button" class="signature-reset btn icon-btn">
${frappe.utils.icon('refresh', 'sm')}
</a>
</div>
`)
.appendTo(this.$pad)
.on("click", '.signature-reset', () => {
this.on_reset_sign();


+ 5
- 5
frappe/public/js/frappe/form/controls/table_multiselect.js ファイルの表示

@@ -123,12 +123,12 @@ frappe.ui.form.ControlTableMultiSelect = frappe.ui.form.ControlLink.extend({
},
get_pill_html(value) {
const encoded_value = encodeURIComponent(value);
return `<div class="btn-group tb-selected-value" data-value="${encoded_value}">
<button class="btn btn-default btn-xs btn-link-to-form">${__(value)}</button>
<button class="btn btn-default btn-xs btn-remove">
${frappe.utils.icon('close')}
return `
<button class="data-pill btn tb-selected-value" data-value="${encoded_value}">
<span class="btn-link-to-form">${__(value)}</span>
<span class="btn-remove">${frappe.utils.icon('close')}</span>
</button>
</div>`;
`;
},
get_options() {
return (this.get_link_field() || {}).options;


+ 1
- 1
frappe/public/js/frappe/form/form.js ファイルの表示

@@ -1498,7 +1498,7 @@ frappe.ui.form.Form = class FrappeForm {

const escaped_name = encodeURIComponent(value);

return `<a class="indicator ${get_color(doc || {})}" href="/app/${frappe.router.slug(df.options)}/${escaped_name}" data-doctype="${doctype}" data-name="${value}">${label}</a>'`;
return `<a class="indicator ${get_color(doc || {})}" href="/app/${frappe.router.slug(df.options)}/${escaped_name}" data-doctype="${doctype}" data-name="${value}">${label}</a>`;
} else {
return '';
}


+ 8
- 5
frappe/public/js/frappe/form/formatters.js ファイルの表示

@@ -61,11 +61,14 @@ frappe.form.formatters = {
return frappe.form.formatters._right(flt(value, precision) + "%", options);
},
Rating: function(value) {
return `<span class="rating">
${Array.from(new Array(5)).map((_, i) =>
`<i class="fa fa-fw fa-star ${i < (value || 0) ? "star-click": "" } star-icon" data-idx="${(i+1)}"></i>`
).join('')}
</span>`;
const rating_html = `${[1, 2, 3, 4, 5].map(i =>
`<svg class="icon icon-md ${i <= (value || 0) ? "star-click": "" }" data-idx="${i}">
<use href="#icon-star"></use>
</svg>`
).join('')}`;
return `<div class="rating">
${rating_html}
</div>`;
},
Currency: function (value, docfield, options, doc) {
var currency = frappe.meta.get_field_currency(docfield, doc);


+ 1
- 1
frappe/public/js/frappe/form/grid.js ファイルの表示

@@ -268,7 +268,7 @@ export default class Grid {
}

refresh(force) {
if (this.frm.setting_dependency) return;
if (this.frm && this.frm.setting_dependency) return;

this.data = this.get_data();



+ 1
- 1
frappe/public/js/frappe/form/grid_row.js ファイルの表示

@@ -229,7 +229,7 @@ export default class GridRow {
this.open_form_button = $(`
<div class="btn-open-row">
<a>${frappe.utils.icon('edit', 'xs')}</a>
<div class="hidden-xs edit-grid-row">Edit</div>
<div class="hidden-xs edit-grid-row">${ __("Edit") }</div>
</div>
`)
.appendTo($('<div class="col col-xs-1"></div>').appendTo(this.row))


+ 1
- 1
frappe/public/js/frappe/form/script_manager.js ファイルの表示

@@ -176,7 +176,7 @@ frappe.ui.form.ScriptManager = Class.extend({
eval(doctype.__custom_js);
} catch(e) {
frappe.msgprint({
title: __('Error in Custom Script'),
title: __('Error in Client Script'),
indicator: 'orange',
message: '<pre class="small"><code>' + e.stack + '</code></pre>'
});


+ 1
- 1
frappe/public/js/frappe/form/sidebar/form_sidebar.js ファイルの表示

@@ -210,7 +210,7 @@ frappe.ui.form.Sidebar = class {
if (follow == null) {
follow = this.frm.get_docinfo().is_document_followed;
}
this.follow_button.text(follow ? "Unfollow" : "Follow");
this.follow_button.text(follow ? __("Unfollow") : __("Follow"));
}

refresh_like() {


+ 1
- 1
frappe/public/js/frappe/list/list_sidebar.html ファイルの表示

@@ -56,7 +56,7 @@
</a>
<ul class="dropdown-menu list-stats-dropdown" role="menu">
<div class="dropdown-search">
<input type="text" placeholder="Search" data-element="search" class="form-control input-xs">
<input type="text" placeholder={{__("Search") }} data-element="search" class="form-control input-xs">
</div>
<div class="stat-result">
</div>


+ 12
- 6
frappe/public/js/frappe/list/list_view.js ファイルの表示

@@ -164,7 +164,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
const match_rules_list = frappe.perm.get_match_rules(this.doctype);
if (match_rules_list.length) {
this.restricted_list = $(
`<button class="btn btn-default btn-xs restricted-button flex align-center">
`<button class="btn btn-xs restricted-button flex align-center">
${frappe.utils.icon('restriction', 'xs')}
</button>`
).click(() => this.show_restrictions(match_rules_list)).appendTo(this.page.page_form);
@@ -676,7 +676,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {

if (col.type === "Tag") {
const tags_display_class = !this.tags_shown ? 'hide' : '';
let tags_html = doc._user_tags ? this.get_tags_html(doc._user_tags) : '<div class="tags-empty">-</div>';
let tags_html = doc._user_tags ? this.get_tags_html(doc._user_tags, 2) : '<div class="tags-empty">-</div>';
return `
<div class="list-row-col tag-col ${tags_display_class} hidden-xs ellipsis">
${tags_html}
@@ -732,7 +732,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
html = df.options ? `<img src="${doc[df.options]}"
style="max-height: 30px; max-width: 100%;">`
: `<div class="missing-image small">
<span class="octicon octicon-circle-slash"></span>
${frappe.utils.icon('restriction')}
</div>`;
} else if (df.fieldtype === "Select") {
html = `<span class="filterable indicator-pill ${frappe.utils.guess_colour(
@@ -790,13 +790,19 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
`;
}

get_tags_html(user_tags) {
get_tags_html(user_tags, limit, colored=false) {
let get_tag_html = tag => {
let color = '', style = '';
if (tag) {
return `<div class="tag-pill ellipsis" title="${tag}">${tag}</div>`;
if (colored) {
color = frappe.get_palette(tag);
style = `background-color: var(${color[0]}); color: var(${color[1]})`;
}

return `<div class="tag-pill ellipsis" title="${tag}" style="${style}">${tag}</div>`;
}
};
return user_tags.split(',').slice(1, 3).map(get_tag_html).join('');
return user_tags.split(',').slice(1, limit + 1).map(get_tag_html).join('');
}

get_meta_html(doc) {


+ 13
- 7
frappe/public/js/frappe/list/list_view_select.js ファイルの表示

@@ -10,7 +10,7 @@ frappe.views.ListViewSelect = class ListViewSelect {
add_view_to_menu(view, action) {
let $el = this.page.add_custom_menu_item(
this.parent,
view,
__(view),
action,
true,
null,
@@ -51,10 +51,15 @@ frappe.views.ListViewSelect = class ListViewSelect {
action: () => this.set_route("report"),
current_view_handler: () => {
const reports = this.get_reports();
this.setup_dropdown_in_sidebar("Report", reports, {
label: __("Report Builder"),
action: () => this.set_route("report")
});
let default_action = {};
// Only add action if current route is not report builder
if (frappe.get_route().length > 3) {
default_action = {
label: __("Report Builder"),
action: () => this.set_route("report")
};
}
this.setup_dropdown_in_sidebar("Report", reports, default_action);
}
},
Dashboard: {
@@ -147,8 +152,9 @@ frappe.views.ListViewSelect = class ListViewSelect {
${__("No {} Found", [view])}
</div>`;
} else {
const page_name = this.get_page_name();
items.map(item => {
if (item.name == this.get_page_name()) {
if (item.name.toLowerCase() == page_name.toLowerCase()) {
placeholder = item.name;
}
html += `<li><a class="dropdown-item" href="${item.route}">${
@@ -212,7 +218,7 @@ frappe.views.ListViewSelect = class ListViewSelect {
const report_type =
r.report_type === "Report Builder"
? `/app/list/${r.ref_doctype}/report`
: "query-report";
: "/app/query-report";

const route =
r.route || report_type + "/" + (r.title || r.name);


+ 1
- 1
frappe/public/js/frappe/model/model.js ファイルの表示

@@ -15,7 +15,7 @@ $.extend(frappe.model, {

core_doctypes_list: ['DocType', 'DocField', 'DocPerm', 'User', 'Role', 'Has Role',
'Page', 'Module Def', 'Print Format', 'Report', 'Customize Form',
'Customize Form Field', 'Property Setter', 'Custom Field', 'Custom Script'],
'Customize Form Field', 'Property Setter', 'Custom Field', 'Client Script'],

std_fields: [
{fieldname:'name', fieldtype:'Link', label:__('ID')},


+ 1
- 1
frappe/public/js/frappe/request.js ファイルの表示

@@ -492,7 +492,7 @@ frappe.request.report_error = function(xhr, request_opts) {

if (!frappe.error_dialog) {
frappe.error_dialog = new frappe.ui.Dialog({
title: 'Server Error',
title: __('Server Error'),
primary_action_label: __('Report'),
primary_action: () => {
if (error_report_email) {


+ 2
- 1
frappe/public/js/frappe/ui/colors.js ファイルの表示

@@ -39,7 +39,8 @@ frappe.ui.color = {
};

if(Object.keys(shades).includes(shade)) {
return frappe.ui.color_map[color_name][shades[shade]];
const color = this.get_color(color_name);
return color ? color[shades[shade]] : color_name;
} else {
// eslint-disable-next-line
console.warn(`'shade' can be one of ${Object.keys(shades)} and not ${shade}`);


+ 2
- 0
frappe/public/js/frappe/ui/dialog.js ファイルの表示

@@ -35,6 +35,8 @@ frappe.ui.Dialog = class Dialog extends frappe.ui.FieldGroup {
$(this.wrapper).addClass("modal-sm");
else if (this.size == "large" )
$(this.wrapper).addClass("modal-lg");
else if (this.size == "extra-large" )
$(this.wrapper).addClass("modal-xl");

this.make_head();
this.modal_body = this.$wrapper.find(".modal-body");


+ 0
- 57
frappe/public/js/frappe/ui/dropzone.js ファイルの表示

@@ -1,57 +0,0 @@
// DropZone
frappe.ui.DropZone = class
{
constructor (selector, options) {
this.options = Object.assign({ }, frappe.ui.DropZone.OPTIONS, options);
this.$container = $(selector);
this.$wrapper = $(frappe.ui.DropZone.TEMPLATE);

this.make();
}

make ( ) {
const me = this;
const $dropzone = this.$wrapper.find('.panel-body');
const $title = $dropzone.find('.dropzone-title');
$title.html(this.options.title);

$dropzone.on('dragover', function (e) {
e.preventDefault();

$title.html(__('Drop'));
});
$dropzone.on('dragleave', function (e) {
e.preventDefault();

$title.html(me.options.title);
});
$dropzone.on('drop', function (e) {
e.preventDefault();

const files = e.originalEvent.dataTransfer.files;
me.options.drop(files);

$title.html(me.options.title);
});

this.$container.html(this.$wrapper);
}
};
frappe.ui.DropZone.TEMPLATE =
`
<div class="panel panel-default"
style="
border: none !important;
box-shadow: none !important;
margin-bottom: 0 !important
">
<div class="panel-body">
<div class="dropzone-title text-muted text-center">
</div>
</div>
</div>
`;
frappe.ui.DropZone.OPTIONS =
{
title: __('Drop Here')
};

+ 1
- 0
frappe/public/js/frappe/ui/filters/filter.js ファイルの表示

@@ -214,6 +214,7 @@ frappe.ui.Filter = class {
df.read_only = 0;
df.hidden = 0;
df.is_filter = true;
delete df.hidden_due_to_dependency;

let c = condition ? condition : this.utils.get_default_condition(df);
this.set_condition(c);


+ 5
- 3
frappe/public/js/frappe/ui/filters/filter_list.js ファイルの表示

@@ -74,8 +74,8 @@ frappe.ui.FilterGroup = class {
}
this.set_filter_events();
}
hide_empty_filters && this.toggle_empty_filters(false);
this.toggle_empty_filters(false);
!hide_empty_filters && this.add_filter(this.doctype, 'name');
});

this.filter_button.on('hidden.bs.popover', () => {
@@ -286,7 +286,9 @@ frappe.ui.FilterGroup = class {
return $(`
<div class="filter-area">
<div class="filter-edit-area">
<div class="text-muted empty-filters text-center">${__('No filters selected')}</div>
<div class="text-muted empty-filters text-center">
${__('No filters selected')}
</div>
</div>
<hr class="divider"></hr>
<div class="filter-action-buttons">


+ 4
- 9
frappe/public/js/frappe/ui/notifications/notifications.js ファイルの表示

@@ -3,12 +3,8 @@ frappe.provide('frappe.search');
frappe.ui.Notifications = class Notifications {
constructor() {
this.tabs = {};
frappe.model
.with_doc('Notification Settings', frappe.session.user)
.then(doc => {
this.notifications_settings = doc;
this.make();
});
this.notification_settings = frappe.boot.notification_settings;
this.make();
}

make() {
@@ -23,7 +19,6 @@ frappe.ui.Notifications = class Notifications {
this.user = frappe.session.user;

this.setup_headers();
let me = this;
this.setup_dropdown_events();
}

@@ -109,7 +104,7 @@ frappe.ui.Notifications = class Notifications {
let tabView = new item.view(
item.el,
this.dropdown,
this.notifications_settings
this.notification_settings
);
this.tabs[item.id] = tabView;
}
@@ -444,4 +439,4 @@ class EventsView extends BaseNotificationsView {

this.container.html(html);
}
}
}

+ 1
- 0
frappe/public/js/frappe/ui/page.js ファイルの表示

@@ -114,6 +114,7 @@ frappe.ui.Page = Class.extend({
this.get_main_icon(this.icon);

this.body = this.main = this.wrapper.find(".layout-main-section");
this.container = this.wrapper.find(".page-body");
this.sidebar = this.wrapper.find(".layout-side-section");
this.footer = this.wrapper.find(".layout-footer");
this.indicator = this.wrapper.find(".indicator-pill");


+ 1
- 1
frappe/public/js/frappe/ui/toolbar/navbar.html ファイルの表示

@@ -1,7 +1,7 @@
<header class="navbar navbar-expand sticky-top" role="navigation">
<div class="container">
<a class="navbar-brand navbar-home" href="/app">
<img class="app-logo" style="width: {{ navbar_settings.logo_width || 24 }}px" src="{{ frappe.app.logo_url }}">
<img class="app-logo" style="width: {{ navbar_settings.logo_width || 24 }}px" src="{{ frappe.boot.app_logo_url }}">
</a>
<ul class="nav navbar-nav d-none d-sm-flex" id="navbar-breadcrumbs"></ul>
<div class="collapse navbar-collapse justify-content-end">


+ 2
- 2
frappe/public/js/frappe/ui/toolbar/search.js ファイルの表示

@@ -303,7 +303,7 @@ frappe.search.SearchDialog = class {

let $results_list = $(`<div class="results-summary">
<div class="result-section full-list ${type}-section col-sm-12">
<div class="result-title">${type}</div>
<div class="result-title"> ${ __(type) }</div>
<div class="result-body">
</div>
</div>
@@ -340,7 +340,7 @@ frappe.search.SearchDialog = class {
}

let $result_section = $(`<div class="col-sm-12 result-section" data-type="${type}">
<div class="result-title">${type}</div>
<div class="result-title">${__(type)}</div>
<div class="result-body">
${more_html}
</div>


+ 6
- 0
frappe/public/js/frappe/ui/toolbar/toolbar.js ファイルの表示

@@ -126,6 +126,12 @@ frappe.ui.toolbar.Toolbar = class {
if (frappe.boot.desk_settings.search_bar) {
let awesome_bar = new frappe.search.AwesomeBar();
awesome_bar.setup("#navbar-search");

// TODO: Remove this in v14
frappe.search.utils.make_function_searchable(function() {
frappe.set_route("List", "Client Script");
}, __("Custom Script List"));

}
}



+ 0
- 27
frappe/public/js/frappe/ui/upload.html ファイルの表示

@@ -1,27 +0,0 @@
<div class="file-upload">
<div class="input-upload">
<input class="input-upload-file hidden" type="file" {{ opts.allow_multiple ? "multiple" : "" }} name="filedata" />
<button class="btn btn-primary btn-sm btn-browse">{%= __("Browse") %}</button>
</div>
<div class="uploaded-filename hidden" style="width: 100%; margin-top: 12px;"></div>
<div class="web-link-wrapper" style="width: calc(100% - 80px);">
<span class="text-muted file-upload-or">{%= __("or") %}</span>
<div class="input-link" style="width: calc(100% - 30px);">
<div class="input-group">
<div class="input-group-addon">
<span class="hidden-xs">{%= __("Web Link") %}</span>
<i class="fa fa-link visible-xs"></i>
</div>
<input class="form-control" type="text" name="file_url"
placeholder="{%= (opts.sample_url || "e.g. http://example.com/somefile.png") %}"/>
</div>
</div>
</div>
<div class="private-file hidden">
<div class="checkbox">
<label>
<input type="checkbox" checked> {{ __("Private") }}
</label>
</div>
</div>
</div>

+ 24
- 0
frappe/public/js/frappe/ui/workspace_loading_skeleton.html ファイルの表示

@@ -0,0 +1,24 @@
<div class="workspace-skeleton">
<div class="widget-group">
<div class="widget-group-head skeleton-header">
<div class="widget-group-title skeleton-card"></div>
</div>
<div class="widget-group-body grid-col-3">
<div class="widget shortcut-widget-box skeleton-card"></div>
<div class="widget shortcut-widget-box skeleton-card"></div>
<div class="widget shortcut-widget-box skeleton-card"></div>
</div>
</div>
<div class="widget-group skeleton-body">
<div class="widget-group-head skeleton-header">
<div class="widget-group-title skeleton-card"></div>
</div>
<div class="widget-group-body grid-col-3">
<div class="widget links-widget-box skeleton-card"></div>
<div class="widget links-widget-box skeleton-card"></div>
<div class="widget links-widget-box skeleton-card"></div>
<div class="widget links-widget-box skeleton-card"></div>
<div class="widget links-widget-box skeleton-card"></div>
</div>
</div>
</div>

+ 0
- 6
frappe/public/js/frappe/utils/rating_icons.html ファイルの表示

@@ -1,6 +0,0 @@
{% if show_label %}
{{ __("Rating: ") }}
{% endif %}
{% for(var i=1, l=6; i<l; i++) { %}
<i class="fa fa-fw {{ i<=rating? "fa-star": "fa-star-o" }} star-icon" data-idx=1></i>
{% } %}

+ 0
- 8
frappe/public/js/frappe/utils/ratings.html ファイルの表示

@@ -1,8 +0,0 @@
<div>
{% if label && data.show_label %}
{{ __("{0}: ", label) }}
{% endif %}
{% for(var i=1, l=6; i<l; i++) { %}
<i class="fa fa-fw {{ i<=rating? "fa-star": "fa-star-o" }} star-icon" data-idx=1></i>
{% } %}
</div>

+ 4
- 3
frappe/public/js/frappe/views/breadcrumbs.js ファイルの表示

@@ -125,8 +125,9 @@ frappe.breadcrumbs = {

set_list_breadcrumb(breadcrumbs) {
const doctype = breadcrumbs.doctype;
const doctype_meta = frappe.get_doc('DocType', doctype);
if ((doctype==="User" && !frappe.user.has_role('System Manager'))
|| frappe.get_doc('DocType', doctype).issingle) {
|| (doctype_meta && doctype_meta.issingle)) {
// no user listview for non-system managers and single doctypes
} else {
let route;
@@ -137,7 +138,7 @@ frappe.breadcrumbs = {
} else {
route = doctype_route;
}
$(`<li><a href="/app/${route}">${doctype}</a></li>`)
$(`<li><a href="/app/${route}">${__(doctype)}</a></li>`)
.appendTo(this.$breadcrumbs);
}
},
@@ -146,7 +147,7 @@ frappe.breadcrumbs = {
const doctype = breadcrumbs.doctype;
const docname = frappe.get_route()[2];
let form_route = `/app/${frappe.router.slug(doctype)}/${docname}`;
$(`<li><a href="${form_route}">${docname}</a></li>`)
$(`<li><a href="${form_route}">${__(docname)}</a></li>`)
.appendTo(this.$breadcrumbs);

if (view === "form") {


+ 6
- 2
frappe/public/js/frappe/views/calendar/calendar.js ファイルの表示

@@ -94,11 +94,15 @@ frappe.views.CalendarView = class CalendarView extends frappe.views.ListView {
}

get required_libs() {
return [
let assets = [
'assets/frappe/js/lib/fullcalendar/fullcalendar.min.css',
'assets/frappe/js/lib/fullcalendar/fullcalendar.min.js',
'assets/frappe/js/lib/fullcalendar/locale-all.js'
];
let user_language = frappe.boot.user.language;
if (user_language && user_language !== 'en') {
assets.push('assets/frappe/js/lib/fullcalendar/locale-all.js');
}
return assets;
}
};



+ 19
- 17
frappe/public/js/frappe/views/communication.js ファイルの表示

@@ -591,26 +591,28 @@ frappe.views.CommunicationComposer = Class.extend({

save_as_draft: function() {
if (this.dialog && this.frm) {
try {
let message = this.dialog.get_value('content');
message = message.split(frappe.separator_element)[0];
localStorage.setItem(this.frm.doctype + this.frm.docname, message);
} catch (e) {
// silently fail
console.log(e);
console.warn('[Communication] localStorage is full. Cannot save message as draft');
}
let message = this.dialog.get_value('content');
message = message.split(frappe.separator_element)[0];
localforage.setItem(this.frm.doctype + this.frm.docname, message).catch(e => {
if (e) {
// silently fail
console.log(e); // eslint-disable-line
console.warn('[Communication] localStorage is full. Cannot save message as draft'); // eslint-disable-line
}
});

}
},

delete_saved_draft() {
if (this.dialog) {
try {
localStorage.removeItem(this.frm.doctype + this.frm.docname);
} catch (e) {
console.log(e);
console.warn('[Communication] Cannot delete localStorage item'); // eslint-disable-line
}
localforage.getItem(this.frm.doctype + this.frm.docname).catch(e => {
if (e) {
// silently fail
console.log(e); // eslint-disable-line
console.warn('[Communication] localStorage is full. Cannot save message as draft'); // eslint-disable-line
}
});
}
},

@@ -721,7 +723,7 @@ frappe.views.CommunicationComposer = Class.extend({
signature = res.message.signature;
}

if(!frappe.utils.is_html(signature)) {
if (signature && !frappe.utils.is_html(signature)) {
signature = signature.replace(/\n/g, "<br>");
}

@@ -731,7 +733,7 @@ frappe.views.CommunicationComposer = Class.extend({
// saved draft in localStorage
const { doctype, docname } = this.frm || {};
if (doctype && docname) {
this.message = localStorage.getItem(doctype + docname) || '';
this.message = await localforage.getItem(doctype + docname) || '';
}
}



+ 82
- 6
frappe/public/js/frappe/views/kanban/kanban_board.js ファイルの表示

@@ -124,7 +124,12 @@ frappe.provide("frappe.views");
const new_cards = state.cards.slice();
new_cards[index] = card;
updater.set({ cards: new_cards });
fluxify.doAction('update_order');
const args = {
new: 1,
name: card.name,
colname: updated_doc[state.board.field_name],
};
fluxify.doAction('update_order_for_single_card', args);
});
} else {
frappe.new_doc(this.doctype, doc);
@@ -155,6 +160,53 @@ frappe.provide("frappe.views");
fluxify.doAction('update_card', updated_card);
});
},
update_order_for_single_card: function(updater, card) {
// cache original order
const _cards = this.cards.slice();
const _columns = this.columns.slice();
let args = {};
let method_name = "";

if (card.new) {
method_name = "add_card";
args = {
board_name: this.board.name,
docname: card.name,
colname: card.colname,
};
} else {
method_name = "update_order_for_single_card";
args = {
board_name: this.board.name,
docname: unescape(card.name),
from_colname: card.from_colname,
to_colname: card.to_colname,
old_index: card.old_index,
new_index: card.new_index,
};
}

frappe.call({
method: method_prefix + method_name,
args: args,
callback: (r) => {
let board = r.message;
let updated_cards = [{'name': card.name, 'column': card.to_colname || card.colname}];
let cards = update_cards_column(updated_cards);
let columns = prepare_columns(board.columns);
updater.set({
cards: cards,
columns: columns
});
}
}).fail(function() {
// revert original order
updater.set({
cards: _cards,
columns: _columns
});
});
},
update_order: function(updater) {
// cache original order
const _cards = this.cards.slice();
@@ -446,16 +498,24 @@ frappe.provide("frappe.views");
group: "cards",
animation: 150,
dataIdAttr: 'data-name',
forceFallback: true,
onStart: function() {
wrapper.find('.kanban-card.add-card').fadeOut(200, function() {
wrapper.find('.kanban-cards').height('100vh');
});
},
onEnd: function() {
onEnd: function(e) {
wrapper.find('.kanban-card.add-card').fadeIn(100);
wrapper.find('.kanban-cards').height('auto');
// update order
fluxify.doAction('update_order');
const args = {
name: $(e.item).attr('data-name'),
from_colname: $(e.from).parents('.kanban-column').attr('data-column-value'),
to_colname: $(e.to).parents('.kanban-column').attr('data-column-value'),
old_index: e.oldIndex,
new_index: e.newIndex,
};
fluxify.doAction('update_order_for_single_card', args);
},
onAdd: function() {
},
@@ -546,14 +606,24 @@ frappe.provide("frappe.views");
var opts = {
name: card.name,
title: remove_img_tags(card.title),
disable_click: card._disable_click ? 'disable-click' : ''
disable_click: card._disable_click ? 'disable-click' : '',
creation: card.creation,
};
self.$card = $(frappe.render_template('kanban_card', opts))
.appendTo(wrapper);
}

function get_tags_html(card) {
return card.tags
? `<div class="kanban-tags">
${cur_list.get_tags_html(card.tags, 3, true)}
</div>`
: '';
}

function render_card_meta() {
var html = "";
let html = get_tags_html(card);

if (card.comment_count > 0)
html +=
`<span class="list-comment-count small text-muted ">
@@ -563,7 +633,10 @@ frappe.provide("frappe.views");

const $assignees_group = get_assignees_group();

html += `<span class="kanban-assignments"></span>`;
html += `
<span class="kanban-assignments"></span>
${cur_list.get_like_html(card)}
`;

if (card.color && frappe.ui.color.validate_hex(card.color)) {
const $div = $('<div>');
@@ -630,6 +703,9 @@ frappe.provide("frappe.views");
doctype: state.doctype,
name: card.name,
title: card[state.card_meta.title_field.fieldname],
creation: moment(card.creation).format('MMM DD, YYYY'),
_liked_by: card._liked_by,
tags: card._user_tags,
column: card[state.board.field_name],
assigned_list: card.assigned_list || assigned_list,
comment_count: card.comment_count || comment_count,


+ 4
- 1
frappe/public/js/frappe/views/kanban/kanban_card.html ファイルの表示

@@ -2,9 +2,12 @@
<a class="kanban-card-redirect" href="#">
<div class="kanban-card content">
<div class="kanban-title-area">
<div class="kanban-card-title ellipsis" title="{{title}}">
<div class="kanban-card-title" title="{{title}}">
{{ title }}
</div>
<div class="kanban-card-creation">
{{ creation }}
</div>
</div>
<div class="kanban-card-meta">
</div>


+ 4
- 0
frappe/public/js/frappe/views/kanban/kanban_view.js ファイルの表示

@@ -73,7 +73,11 @@ frappe.views.KanbanView = class KanbanView extends frappe.views.ListView {
}

setup_view() {
if (this.board.columns.length > 5) {
this.page.container.addClass('full-width');
}
this.setup_realtime_updates();
this.setup_like();
}

set_fields() {


+ 42
- 59
frappe/public/js/frappe/views/workspace/workspace.js ファイルの表示

@@ -51,9 +51,11 @@ frappe.views.Workspace = class Workspace {
}

prepare_container() {
let list_sidebar = $(`<div class="list-sidebar overlay-sidebar hidden-xs hidden-sm">
<div class="desk-sidebar list-unstyled sidebar-menu"></div>
</div>`).appendTo(this.wrapper.find(".layout-side-section"));
let list_sidebar = $(`
<div class="list-sidebar overlay-sidebar hidden-xs hidden-sm">
<div class="desk-sidebar list-unstyled sidebar-menu"></div>
</div>
`).appendTo(this.wrapper.find(".layout-side-section"));
this.sidebar = list_sidebar.find(".desk-sidebar");

this.body = this.wrapper.find(".layout-main-section");
@@ -240,18 +242,17 @@ class DesktopPage {

make() {
this.page = $(`<div class="desk-page" data-page-name=${this.page_name}></div>`);
this.page.append(frappe.render_template('workspace_loading_skeleton'));
this.page.appendTo(this.container);

this.get_data().then(res => {
this.data = res.message;
this.get_data().then(() => {
if (!this.data) {
delete localStorage.current_workspace;
frappe.set_route("space");
frappe.set_route("workspace");
return;
}

this.refresh();
});
}).finally(this.page.find('.workspace_loading_skeleton').remove);
}

refresh() {
@@ -263,15 +264,26 @@ class DesktopPage {
}

this.data.onboarding && this.data.onboarding.items.length && this.make_onboarding();
this.make_charts().then(() => {
this.make_shortcuts();
this.make_cards();
});
this.make_charts();
this.make_shortcuts();
this.make_cards();
}

get_data() {
return frappe.call("frappe.desk.desktop.get_desktop_page", {
return frappe.xcall("frappe.desk.desktop.get_desktop_page", {
page: this.page_name
}).then(data => {
this.data = data;
if (!this.data) return;

return frappe.dashboard_utils.get_dashboard_settings().then(settings => {
let chart_config = settings.chart_config ? JSON.parse(settings.chart_config) : {};
if (this.data.charts.items) {
this.data.charts.items.map(chart => {
chart.chart_settings = chart_config[chart.chart_name] || {};
});
}
});
});
}

@@ -310,7 +322,7 @@ class DesktopPage {
frappe.throw({ message: __("Something went wrong while saving customizations"), indicator: "red" });
this.reload();
}
})
});
}

reset_customization() {
@@ -344,30 +356,21 @@ class DesktopPage {
}

make_charts() {
return frappe.dashboard_utils.get_dashboard_settings().then(settings => {
let chart_config = settings.chart_config ? JSON.parse(settings.chart_config) : {};
if (this.data.charts.items) {
this.data.charts.items.map(chart => {
chart.chart_settings = chart_config[chart.chart_name] || {};
});
}

this.sections["charts"] = new frappe.widget.WidgetGroup({
container: this.page,
type: "chart",
columns: 1,
class_name: "widget-charts",
hidden: Boolean(this.onboarding_widget),
options: {
allow_sorting: this.allow_customization,
allow_create: this.allow_customization,
allow_delete: this.allow_customization,
allow_hiding: false,
allow_edit: true,
max_widget_count: 2,
},
widgets: this.data.charts.items
});
this.sections["charts"] = new frappe.widget.WidgetGroup({
container: this.page,
type: "chart",
columns: 1,
class_name: "widget-charts",
hidden: Boolean(this.onboarding_widget),
options: {
allow_sorting: this.allow_customization,
allow_create: this.allow_customization,
allow_delete: this.allow_customization,
allow_hiding: false,
allow_edit: true,
max_widget_count: 2,
},
widgets: this.data.charts.items
});
}

@@ -405,25 +408,5 @@ class DesktopPage {
});

this.sections["cards"] = cards;

// const legend = [
// {
// color: "blue",
// description: __("Important")
// },
// {
// color: "yellow",
// description: __("No Records Created")
// }
// ].map(item => {
// return `<div class="legend-item text-muted justify-flex-start">
// <span class="indicator-pill no-margin ${item.color}"></span>
// <span class="link-content ellipsis" draggable="false">${item.description}</span>
// </div>`;
// });

// $(`<div class="legend">
// ${legend.join("\n")}
// </div>`).insertAfter(cards.body);
}
}
}

+ 0
- 23
frappe/public/js/lib/README.md ファイルの表示

@@ -1,23 +0,0 @@
# 3rd party libraries

Import / Upgrade Guide

## JQuery UI

Download modules

- core
- interactions
- autocomplete
- datepicker

## JQuery UI Bootstrap theme

Changes images urls

- from: url(images
- to: url(../lib/js/lib/jquery/bootstrap_theme/images

## JQuery Gantt

Not a very mature project. Please check css / js after updating

+ 0
- 104
frappe/public/js/lib/awesomplete/awesomplete.css ファイルの表示

@@ -1,104 +0,0 @@
.awesomplete [hidden] {
display: none;
}

.awesomplete .visually-hidden {
position: absolute;
clip: rect(0, 0, 0, 0);
}

.awesomplete {
display: inline-block;
position: relative;
}

.awesomplete > input {
display: block;
}

.awesomplete > ul {
position: absolute;
left: 0;
z-index: 1;
min-width: 100%;
box-sizing: border-box;
list-style: none;
padding: 0;
margin: 0;
background: #fff;
}

.awesomplete > ul:empty {
display: none;
}

.awesomplete > ul {
border-radius: .3em;
margin: .2em 0 0;
background: hsla(0,0%,100%,.9);
background: linear-gradient(to bottom right, white, hsla(0,0%,100%,.8));
border: 1px solid rgba(0,0,0,.3);
box-shadow: .05em .2em .6em rgba(0,0,0,.2);
text-shadow: none;
}

@supports (transform: scale(0)) {
.awesomplete > ul {
transition: .3s cubic-bezier(.4,.2,.5,1.4);
transform-origin: 1.43em -.43em;
}

.awesomplete > ul[hidden],
.awesomplete > ul:empty {
opacity: 0;
transform: scale(0);
display: block;
transition-timing-function: ease;
}
}

/* Pointer */
.awesomplete > ul:before {
content: "";
position: absolute;
top: -.43em;
left: 1em;
width: 0; height: 0;
padding: .4em;
background: white;
border: inherit;
border-right: 0;
border-bottom: 0;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}

.awesomplete > ul > li {
position: relative;
padding: .2em .5em;
cursor: pointer;
}

.awesomplete > ul > li:hover {
background: hsl(200, 40%, 80%);
color: black;
}

.awesomplete > ul > li[aria-selected="true"] {
background: hsl(205, 40%, 40%);
color: white;
}

.awesomplete mark {
background: hsl(65, 100%, 50%);
}

.awesomplete li:hover mark {
background: hsl(68, 100%, 41%);
}

.awesomplete li[aria-selected="true"] mark {
background: hsl(86, 100%, 21%);
color: inherit;
}
/*# sourceMappingURL=awesomplete.css.map */

+ 0
- 3
frappe/public/js/lib/awesomplete/awesomplete.min.js
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 0
- 617
frappe/public/js/lib/beautify-html.js ファイルの表示

@@ -1,617 +0,0 @@
/*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
/*

The MIT License (MIT)

Copyright (c) 2007-2013 Einar Lielmanis and contributors.

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


Style HTML
---------------

Written by Nochum Sossonko, (nsossonko@hotmail.com)

Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv>
http://jsbeautifier.org/

Usage:
style_html(html_source);

style_html(html_source, options);

The options are:
indent_size (default 4) — indentation size,
indent_char (default space) — character to indent with,
max_char (default 250) - maximum amount of characters per line (0 = disable)
brace_style (default "collapse") - "collapse" | "expand" | "end-expand"
put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line.
unformatted (defaults to inline tags) - list of tags, that shouldn't be reformatted
indent_scripts (default normal) - "keep"|"separate"|"normal"

e.g.

style_html(html_source, {
'indent_size': 2,
'indent_char': ' ',
'max_char': 78,
'brace_style': 'expand',
'unformatted': ['a', 'sub', 'sup', 'b', 'i', 'u']
});
*/

(function() {

function style_html(html_source, options, js_beautify, css_beautify) {
//Wrapper function to invoke all the necessary constructors and deal with the output.

var multi_parser,
indent_size,
indent_character,
max_char,
brace_style,
unformatted;

options = options || {};
indent_size = options.indent_size || 4;
indent_character = options.indent_char || ' ';
brace_style = options.brace_style || 'collapse';
max_char = options.max_char === 0 ? Infinity : options.max_char || 250;
unformatted = options.unformatted || ['a', 'span', 'bdo', 'em', 'strong', 'dfn', 'code', 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'q', 'sub', 'sup', 'tt', 'i', 'b', 'big', 'small', 'u', 's', 'strike', 'font', 'ins', 'del', 'pre', 'address', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];

function Parser() {

this.pos = 0; //Parser position
this.token = '';
this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT
this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values
parent: 'parent1',
parentcount: 1,
parent1: ''
};
this.tag_type = '';
this.token_text = this.last_token = this.last_text = this.token_type = '';

this.Utils = { //Uilities made available to the various functions
whitespace: "\n\r\t ".split(''),
single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed,?php,?,?='.split(','), //all the single tags for HTML
extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them
in_array: function (what, arr) {
for (var i=0; i<arr.length; i++) {
if (what === arr[i]) {
return true;
}
}
return false;
}
};

this.get_content = function () { //function to capture regular content between tags

var input_char = '',
content = [],
space = false; //if a space is needed

while (this.input.charAt(this.pos) !== '<') {
if (this.pos >= this.input.length) {
return content.length?content.join(''):['', 'TK_EOF'];
}

input_char = this.input.charAt(this.pos);
this.pos++;
this.line_char_count++;

if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
if (content.length) {
space = true;
}
this.line_char_count--;
continue; //don't want to insert unnecessary space
}
else if (space) {
if (this.line_char_count >= this.max_char) { //insert a line when the max_char is reached
content.push('\n');
for (var i=0; i<this.indent_level; i++) {
content.push(this.indent_string);
}
this.line_char_count = 0;
}
else{
content.push(' ');
this.line_char_count++;
}
space = false;
}
content.push(input_char); //letter at-a-time (or string) inserted to an array
}
return content.length?content.join(''):'';
};

this.get_contents_to = function (name) { //get the full content of a script or style to pass to js_beautify
if (this.pos === this.input.length) {
return ['', 'TK_EOF'];
}
var input_char = '';
var content = '';
var reg_match = new RegExp('</' + name + '\\s*>', 'igm');
reg_match.lastIndex = this.pos;
var reg_array = reg_match.exec(this.input);
var end_script = reg_array?reg_array.index:this.input.length; //absolute end of script
if(this.pos < end_script) { //get everything in between the script tags
content = this.input.substring(this.pos, end_script);
this.pos = end_script;
}
return content;
};

this.record_tag = function (tag){ //function to record a tag and its parent in this.tags Object
if (this.tags[tag + 'count']) { //check for the existence of this tag type
this.tags[tag + 'count']++;
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
}
else { //otherwise initialize this tag type
this.tags[tag + 'count'] = 1;
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
}
this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; //set the parent (i.e. in the case of a div this.tags.div1parent)
this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1')
};

this.retrieve_tag = function (tag) { //function to retrieve the opening tag to the corresponding closer
if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it
var temp_parent = this.tags.parent; //check to see if it's a closable tag.
while (temp_parent) { //till we reach '' (the initial value);
if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it
break;
}
temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree
}
if (temp_parent) { //if we caught something
this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly
this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent
}
delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference...
delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself
if (this.tags[tag + 'count'] === 1) {
delete this.tags[tag + 'count'];
}
else {
this.tags[tag + 'count']--;
}
}
};

this.get_tag = function (peek) { //function to get a full tag and parse its type
var input_char = '',
content = [],
comment = '',
space = false,
tag_start, tag_end,
orig_pos = this.pos,
orig_line_char_count = this.line_char_count;

peek = peek !== undefined ? peek : false;

do {
if (this.pos >= this.input.length) {
if (peek) {
this.pos = orig_pos;
this.line_char_count = orig_line_char_count;
}
return content.length?content.join(''):['', 'TK_EOF'];
}

input_char = this.input.charAt(this.pos);
this.pos++;
this.line_char_count++;

if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space
space = true;
this.line_char_count--;
continue;
}

if (input_char === "'" || input_char === '"') {
if (!content[1] || content[1] !== '!') { //if we're in a comment strings don't get treated specially
input_char += this.get_unformatted(input_char);
space = true;
}
}

if (input_char === '=') { //no space before =
space = false;
}

if (content.length && content[content.length-1] !== '=' && input_char !== '>' && space) {
//no space after = or before >
if (this.line_char_count >= this.max_char) {
this.print_newline(false, content);
this.line_char_count = 0;
}
else {
content.push(' ');
this.line_char_count++;
}
space = false;
}
if (input_char === '<') {
tag_start = this.pos - 1;
}
content.push(input_char); //inserts character at-a-time (or string)
} while (input_char !== '>');

var tag_complete = content.join('');
var tag_index;
if (tag_complete.indexOf(' ') !== -1) { //if there's whitespace, thats where the tag name ends
tag_index = tag_complete.indexOf(' ');
}
else { //otherwise go with the tag ending
tag_index = tag_complete.indexOf('>');
}
var tag_check = tag_complete.substring(1, tag_index).toLowerCase();
if (tag_complete.charAt(tag_complete.length-2) === '/' ||
this.Utils.in_array(tag_check, this.Utils.single_token)) { //if this tag name is a single tag type (either in the list or has a closing /)
if ( ! peek) {
this.tag_type = 'SINGLE';
}
}
else if (tag_check === 'script') { //for later script handling
if ( ! peek) {
this.record_tag(tag_check);
this.tag_type = 'SCRIPT';
}
}
else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content)
if ( ! peek) {
this.record_tag(tag_check);
this.tag_type = 'STYLE';
}
}
else if (this.is_unformatted(tag_check, unformatted)) { // do not reformat the "unformatted" tags
comment = this.get_unformatted('</'+tag_check+'>', tag_complete); //...delegate to get_unformatted function
content.push(comment);
// Preserve collapsed whitespace either before or after this tag.
if (tag_start > 0 && this.Utils.in_array(this.input.charAt(tag_start - 1), this.Utils.whitespace)){
content.splice(0, 0, this.input.charAt(tag_start - 1));
}
tag_end = this.pos - 1;
if (this.Utils.in_array(this.input.charAt(tag_end + 1), this.Utils.whitespace)){
content.push(this.input.charAt(tag_end + 1));
}
this.tag_type = 'SINGLE';
}
else if (tag_check.charAt(0) === '!') { //peek for <!-- comment
if (tag_check.indexOf('[if') !== -1) { //peek for <!--[if conditional comment
if (tag_complete.indexOf('!IE') !== -1) { //this type needs a closing --> so...
comment = this.get_unformatted('-->', tag_complete); //...delegate to get_unformatted
content.push(comment);
}
if ( ! peek) {
this.tag_type = 'START';
}
}
else if (tag_check.indexOf('[endif') !== -1) {//peek for <!--[endif end conditional comment
this.tag_type = 'END';
this.unindent();
}
else if (tag_check.indexOf('[cdata[') !== -1) { //if it's a <[cdata[ comment...
comment = this.get_unformatted(']]>', tag_complete); //...delegate to get_unformatted function
content.push(comment);
if ( ! peek) {
this.tag_type = 'SINGLE'; //<![CDATA[ comments are treated like single tags
}
}
else {
comment = this.get_unformatted('-->', tag_complete);
content.push(comment);
this.tag_type = 'SINGLE';
}
}
else if ( ! peek) {
if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending
this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors
this.tag_type = 'END';
}
else { //otherwise it's a start-tag
this.record_tag(tag_check); //push it on the tag stack
this.tag_type = 'START';
}
if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line
this.print_newline(true, this.output);
}
}

if (peek) {
this.pos = orig_pos;
this.line_char_count = orig_line_char_count;
}

return content.join(''); //returns fully formatted tag
};

this.get_unformatted = function (delimiter, orig_tag) { //function to return unformatted content in its entirety

if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) !== -1) {
return '';
}
var input_char = '';
var content = '';
var space = true;
do {

if (this.pos >= this.input.length) {
return content;
}

input_char = this.input.charAt(this.pos);
this.pos++;

if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
if (!space) {
this.line_char_count--;
continue;
}
if (input_char === '\n' || input_char === '\r') {
content += '\n';
/* Don't change tab indention for unformatted blocks. If using code for html editing, this will greatly affect <pre> tags if they are specified in the 'unformatted array'
for (var i=0; i<this.indent_level; i++) {
content += this.indent_string;
}
space = false; //...and make sure other indentation is erased
*/
this.line_char_count = 0;
continue;
}
}
content += input_char;
this.line_char_count++;
space = true;


} while (content.toLowerCase().indexOf(delimiter) === -1);
return content;
};

this.get_token = function () { //initial handler for token-retrieval
var token;

if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript
var type = this.last_token.substr(7);
token = this.get_contents_to(type);
if (typeof token !== 'string') {
return token;
}
return [token, 'TK_' + type];
}
if (this.current_mode === 'CONTENT') {
token = this.get_content();
if (typeof token !== 'string') {
return token;
}
else {
return [token, 'TK_CONTENT'];
}
}

if (this.current_mode === 'TAG') {
token = this.get_tag();
if (typeof token !== 'string') {
return token;
}
else {
var tag_name_type = 'TK_TAG_' + this.tag_type;
return [token, tag_name_type];
}
}
};

this.get_full_indent = function (level) {
level = this.indent_level + level || 0;
if (level < 1) {
return '';
}

return Array(level + 1).join(this.indent_string);
};

this.is_unformatted = function(tag_check, unformatted) {
//is this an HTML5 block-level link?
if (!this.Utils.in_array(tag_check, unformatted)){
return false;
}

if (tag_check.toLowerCase() !== 'a' || !this.Utils.in_array('a', unformatted)){
return true;
}

//at this point we have an tag; is its first child something we want to remain
//unformatted?
var next_tag = this.get_tag(true /* peek. */);

// tets next_tag to see if it is just html tag (no external content)
var tag = (next_tag || "").match(/^\s*<\s*\/?([a-z]*)\s*[^>]*>\s*$/);

// if next_tag comes back but is not an isolated tag, then
// let's treat the 'a' tag as having content
// and respect the unformatted option
if (!tag || this.Utils.in_array(tag, unformatted)){
return true;
} else {
return false;
}
};

this.printer = function (js_source, indent_character, indent_size, max_char, brace_style) { //handles input/output and some other printing functions

this.input = js_source || ''; //gets the input for the Parser
this.output = [];
this.indent_character = indent_character;
this.indent_string = '';
this.indent_size = indent_size;
this.brace_style = brace_style;
this.indent_level = 0;
this.max_char = max_char;
this.line_char_count = 0; //count to see if max_char was exceeded

for (var i=0; i<this.indent_size; i++) {
this.indent_string += this.indent_character;
}

this.print_newline = function (ignore, arr) {
this.line_char_count = 0;
if (!arr || !arr.length) {
return;
}
if (!ignore) { //we might want the extra line
while (this.Utils.in_array(arr[arr.length-1], this.Utils.whitespace)) {
arr.pop();
}
}
arr.push('\n');
for (var i=0; i<this.indent_level; i++) {
arr.push(this.indent_string);
}
};

this.print_token = function (text) {
this.output.push(text);
};

this.indent = function () {
this.indent_level++;
};

this.unindent = function () {
if (this.indent_level > 0) {
this.indent_level--;
}
};
};
return this;
}

/*_____________________--------------------_____________________*/

multi_parser = new Parser(); //wrapping functions Parser
multi_parser.printer(html_source, indent_character, indent_size, max_char, brace_style); //initialize starting values

while (true) {
var t = multi_parser.get_token();
multi_parser.token_text = t[0];
multi_parser.token_type = t[1];

if (multi_parser.token_type === 'TK_EOF') {
break;
}

switch (multi_parser.token_type) {
case 'TK_TAG_START':
multi_parser.print_newline(false, multi_parser.output);
multi_parser.print_token(multi_parser.token_text);
multi_parser.indent();
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_TAG_STYLE':
case 'TK_TAG_SCRIPT':
multi_parser.print_newline(false, multi_parser.output);
multi_parser.print_token(multi_parser.token_text);
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_TAG_END':
//Print new line only if the tag has no content and has child
if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') {
var tag_name = multi_parser.token_text.match(/\w+/)[0];
var tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length -1].match(/<\s*(\w+)/);
if (tag_extracted_from_last_output === null || tag_extracted_from_last_output[1] !== tag_name) {
multi_parser.print_newline(true, multi_parser.output);
}
}
multi_parser.print_token(multi_parser.token_text);
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_TAG_SINGLE':
// Don't add a newline before elements that should remain unformatted.
var tag_check = multi_parser.token_text.match(/^\s*<([a-z]+)/i);
if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)){
multi_parser.print_newline(false, multi_parser.output);
}
multi_parser.print_token(multi_parser.token_text);
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_CONTENT':
if (multi_parser.token_text !== '') {
multi_parser.print_token(multi_parser.token_text);
}
multi_parser.current_mode = 'TAG';
break;
case 'TK_STYLE':
case 'TK_SCRIPT':
if (multi_parser.token_text !== '') {
multi_parser.output.push('\n');
var text = multi_parser.token_text,
_beautifier,
script_indent_level = 1;
if (multi_parser.token_type === 'TK_SCRIPT') {
_beautifier = typeof js_beautify === 'function' && js_beautify;
} else if (multi_parser.token_type === 'TK_STYLE') {
_beautifier = typeof css_beautify === 'function' && css_beautify;
}

if (options.indent_scripts === "keep") {
script_indent_level = 0;
} else if (options.indent_scripts === "separate") {
script_indent_level = -multi_parser.indent_level;
}

var indentation = multi_parser.get_full_indent(script_indent_level);
if (_beautifier) {
// call the Beautifier if avaliable
text = _beautifier(text.replace(/^\s*/, indentation), options);
} else {
// simply indent the string otherwise
var white = text.match(/^\s*/)[0];
var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1;
var reindent = multi_parser.get_full_indent(script_indent_level -_level);
text = text.replace(/^\s*/, indentation)
.replace(/\r\n|\r|\n/g, '\n' + reindent)
.replace(/\s*$/, '');
}
if (text) {
multi_parser.print_token(text);
multi_parser.print_newline(true, multi_parser.output);
}
}
multi_parser.current_mode = 'TAG';
break;
}
multi_parser.last_token = multi_parser.token_type;
multi_parser.last_text = multi_parser.token_text;
}
return multi_parser.output.join('');
}

// If we're running a web page and don't have either of the above, add our one global
window.html_beautify = function(html_source, options) {
return style_html(html_source, options, window.js_beautify, window.css_beautify);
};

}());

+ 0
- 1
frappe/public/js/lib/bootstrap-paginator.min.js
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 0
- 3981
frappe/public/js/lib/frappe-datatable.js
ファイル差分が大きすぎるため省略します
ファイルの表示


変更されたファイルが多すぎるため、一部のファイルは表示されません

読み込み中…
キャンセル
保存