ListView refactor (#2715)
* [list_settings] save last_view, kanban_board, gantt_mode * listview.js cleanup * image_view refactor * image_view done * wip * [photoswipe] wip * show view for calendar, kanban even if no results * [gantt_view] refactor into separate file * [imageview] 3 column border fix * [imageview] gallery working * delete old libs * indentation to tabs * [gantt] update lib, custom popup html * custom fontawesome checkbox * reset gantt state when not permitted * checkbox styling fix * working commit * image, calendar, gantt view working * more refactoring, kanban view * minor * removed old files * user settings improved * filters and sort selector de-coupling * wip * [imageview] white pswp background * kanban filters saving fixed * fixed reportview * minor * removed listing.js * minor fixes and cleanup * patch for UserSettings table * patch fix
This commit is contained in:
parent
4fecbd15af
commit
1a76d64781
73 changed files with 9451 additions and 4875 deletions
|
|
@ -1,5 +1,4 @@
|
|||
frappe.listview_settings['Communication'] = {
|
||||
add_fields: ["sent_or_received", "recipients", "subject", "communication_medium", "communication_type"],
|
||||
//default_filters: [["Communication", "communication_type", "=", "Communication"]],
|
||||
filters: [["status", "=", "Open"]]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ frappe.listview_settings['File'] = {
|
|||
doclist.listview.settings.setup_menu(doclist);
|
||||
doclist.listview.settings.setup_dragdrop(doclist);
|
||||
|
||||
doclist.$page.on("click", ".list-delete", function(event) {
|
||||
doclist.$page.on("click", ".list-row-checkbox", function(event) {
|
||||
doclist.listview.settings.add_menu_item_copy(doclist);
|
||||
})
|
||||
},
|
||||
|
|
@ -127,7 +127,7 @@ frappe.listview_settings['File'] = {
|
|||
add_menu_item_copy: function(doclist){
|
||||
if (!doclist.copy) {
|
||||
var copy_menu = doclist.page.add_menu_item(__("Copy"), function() {
|
||||
if(doclist.$page.find(".list-delete:checked").length){
|
||||
if(doclist.$page.find(".list-row-checkbox:checked").length){
|
||||
doclist.selected_files = doclist.get_checked_items();
|
||||
doclist.old_parent = doclist.current_folder;
|
||||
doclist.listview.settings.add_menu_item_paste(doclist);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import frappe.utils
|
|||
import frappe.share
|
||||
import frappe.defaults
|
||||
import frappe.desk.form.meta
|
||||
from frappe.model.utils.list_settings import get_list_settings
|
||||
from frappe.model.utils.user_settings import get_user_settings
|
||||
from frappe.permissions import get_doc_permissions
|
||||
from frappe import _
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ def getdoctype(doctype, with_parent=False, cached_timestamp=None):
|
|||
docs = get_meta_bundle(doctype)
|
||||
|
||||
frappe.response['user_permissions'] = get_user_permissions(docs)
|
||||
frappe.response['list_settings'] = get_list_settings(parent_dt or doctype)
|
||||
frappe.response['user_settings'] = get_user_settings(parent_dt or doctype)
|
||||
|
||||
if cached_timestamp and docs[0].modified==cached_timestamp:
|
||||
return "use_cache"
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ class FormMeta(Meta):
|
|||
|
||||
def load_kanban_boards(self):
|
||||
kanban_boards = frappe.get_all(
|
||||
'Kanban Board', filters={'reference_doctype': self.name})
|
||||
'Kanban Board', fields=['name', 'filters', 'reference_doctype'], filters={'reference_doctype': self.name})
|
||||
self.set("__kanban_boards", kanban_boards, as_value=True)
|
||||
|
||||
def load_kanban_column_fields(self):
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@ def get_form_params():
|
|||
data["fields"] = json.loads(data["fields"])
|
||||
if isinstance(data.get("docstatus"), basestring):
|
||||
data["docstatus"] = json.loads(data["docstatus"])
|
||||
if isinstance(data.get("save_list_settings"), basestring):
|
||||
data["save_list_settings"] = json.loads(data["save_list_settings"])
|
||||
if isinstance(data.get("save_user_settings"), basestring):
|
||||
data["save_user_settings"] = json.loads(data["save_user_settings"])
|
||||
else:
|
||||
data["save_list_settings"] = True
|
||||
data["save_user_settings"] = True
|
||||
|
||||
|
||||
# queries must always be server side
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ frappe.Inbox = frappe.ui.Listing.extend({
|
|||
$(me.page.sidebar).find(".list-row").removeClass("list-row-head").css("font-weight","normal");
|
||||
$(btn.currentTarget).closest(".list-row").addClass("list-row-head").css("font-weight","bold");
|
||||
me.cur_page = 1;
|
||||
$(me.page.main).find(".list-select-all,.list-delete").prop("checked",false);
|
||||
$(me.page.main).find(".list-select-all,.list-row-checkbox").prop("checked",false);
|
||||
me.toggle_actions();
|
||||
|
||||
if(me.account=="Sent"){
|
||||
|
|
@ -518,11 +518,11 @@ frappe.Inbox = frappe.ui.Listing.extend({
|
|||
var me = this;
|
||||
|
||||
$(".list-select-all").on("click", function () {
|
||||
$(me.wrapper).find('.list-delete').prop("checked", $(this).prop("checked"));
|
||||
$(me.wrapper).find('.list-row-checkbox').prop("checked", $(this).prop("checked"));
|
||||
me.toggle_actions();
|
||||
});
|
||||
|
||||
$(me.wrapper).on("click", ".list-delete", function (event) {
|
||||
$(me.wrapper).on("click", ".list-row-checkbox", function (event) {
|
||||
me.toggle_actions();
|
||||
|
||||
// multi-select using shift key
|
||||
|
|
@ -530,9 +530,9 @@ frappe.Inbox = frappe.ui.Listing.extend({
|
|||
if (event.shiftKey && $this.prop("checked")) {
|
||||
var $end_row = $this.parents(".list-row");
|
||||
var $start_row = $end_row.prevAll(".list-row")
|
||||
.find(".list-delete:checked").last().parents(".list-row");
|
||||
.find(".list-row-checkbox:checked").last().parents(".list-row");
|
||||
if ($start_row) {
|
||||
$start_row.nextUntil($end_row).find(".list-delete").prop("checked", true);
|
||||
$start_row.nextUntil($end_row).find(".list-row-checkbox").prop("checked", true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -563,7 +563,7 @@ frappe.Inbox = frappe.ui.Listing.extend({
|
|||
},
|
||||
toggle_actions: function () {
|
||||
var me = this;
|
||||
if (me.page.main.find(".list-delete:checked").length) {
|
||||
if (me.page.main.find(".list-row-checkbox:checked").length) {
|
||||
//show buttons
|
||||
$(me.page.actions_btn_group).show();
|
||||
$(me.page.btn_primary).hide()
|
||||
|
|
@ -625,10 +625,10 @@ frappe.Inbox = frappe.ui.Listing.extend({
|
|||
val:val
|
||||
}
|
||||
})
|
||||
$('.list-delete:checked').prop( "checked", false );
|
||||
$('.list-row-checkbox:checked').prop( "checked", false );
|
||||
},
|
||||
action_checked_items: function(action) {
|
||||
return $.map(this.page.main.find('.list-delete:checked'), function(e) {
|
||||
return $.map(this.page.main.find('.list-row-checkbox:checked'), function(e) {
|
||||
return eval('$(e).closest(".row-named")'+action);
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<div class="row">
|
||||
<div class="col-sm-2 list-col ellipsis col-xs-12">
|
||||
<span class="list-value">
|
||||
<input class="list-delete noclick" type="checkbox" style="margin: 0 7px 0 0; vertical-align: middle;">
|
||||
<input class="list-row-checkbox noclick" type="checkbox" style="margin: 0 7px 0 0; vertical-align: middle;">
|
||||
{% if (data.sender_full_name){var sender = data.sender_full_name} else {var sender = data.sender} %}
|
||||
<a class="grey" title="{%= sender %}">{%= sender %}</a>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ def create_database_and_user(force, verbose):
|
|||
frappe.db.close()
|
||||
|
||||
def create_list_settings_table():
|
||||
frappe.db.sql_ddl("""create table if not exists __ListSettings (
|
||||
frappe.db.sql_ddl("""create table if not exists __UserSettings (
|
||||
`user` VARCHAR(180) NOT NULL,
|
||||
`doctype` VARCHAR(180) NOT NULL,
|
||||
`data` TEXT,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import frappe.permissions
|
|||
from frappe.utils import flt, cint, getdate, get_datetime, get_time, make_filter_tuple, get_filter, add_to_date
|
||||
from frappe import _
|
||||
from frappe.model import optional_fields
|
||||
from frappe.model.utils.list_settings import get_list_settings, update_list_settings
|
||||
from frappe.model.utils.user_settings import get_user_settings, update_user_settings
|
||||
from datetime import datetime
|
||||
|
||||
class DatabaseQuery(object):
|
||||
|
|
@ -30,8 +30,8 @@ class DatabaseQuery(object):
|
|||
limit_page_length=None, as_list=False, with_childnames=False, debug=False,
|
||||
ignore_permissions=False, user=None, with_comment_count=False,
|
||||
join='left join', distinct=False, start=None, page_length=None, limit=None,
|
||||
ignore_ifnull=False, save_list_settings=False, save_list_settings_fields=False,
|
||||
update=None, add_total_row=None):
|
||||
ignore_ifnull=False, save_user_settings=False, save_user_settings_fields=False,
|
||||
update=None, add_total_row=None, user_settings=None):
|
||||
if not ignore_permissions and not frappe.has_permission(self.doctype, "read", user=user):
|
||||
raise frappe.PermissionError, self.doctype
|
||||
|
||||
|
|
@ -72,8 +72,10 @@ class DatabaseQuery(object):
|
|||
self.flags.ignore_permissions = ignore_permissions
|
||||
self.user = user or frappe.session.user
|
||||
self.update = update
|
||||
self.list_settings_fields = copy.deepcopy(self.fields)
|
||||
self.user_settings_fields = copy.deepcopy(self.fields)
|
||||
#self.debug = True
|
||||
if user_settings:
|
||||
self.user_settings = json.loads(user_settings)
|
||||
|
||||
if query:
|
||||
result = self.run_custom_query(query)
|
||||
|
|
@ -83,9 +85,9 @@ class DatabaseQuery(object):
|
|||
if with_comment_count and not as_list and self.doctype:
|
||||
self.add_comment_count(result)
|
||||
|
||||
if save_list_settings:
|
||||
self.save_list_settings_fields = save_list_settings_fields
|
||||
self.update_list_settings()
|
||||
if save_user_settings:
|
||||
self.save_user_settings_fields = save_user_settings_fields
|
||||
self.update_user_settings()
|
||||
|
||||
return result
|
||||
|
||||
|
|
@ -513,17 +515,17 @@ class DatabaseQuery(object):
|
|||
if "_comments" in r:
|
||||
r._comment_count = len(json.loads(r._comments or "[]"))
|
||||
|
||||
def update_list_settings(self):
|
||||
# update list settings if new search
|
||||
list_settings = json.loads(get_list_settings(self.doctype) or '{}')
|
||||
list_settings['filters'] = self.filters
|
||||
list_settings['limit'] = self.limit_page_length
|
||||
list_settings['order_by'] = self.order_by
|
||||
def update_user_settings(self):
|
||||
# update user settings if new search
|
||||
user_settings = json.loads(get_user_settings(self.doctype))
|
||||
|
||||
if self.save_list_settings_fields:
|
||||
list_settings['fields'] = self.list_settings_fields
|
||||
if hasattr(self, 'user_settings'):
|
||||
user_settings.update(self.user_settings)
|
||||
|
||||
update_list_settings(self.doctype, list_settings)
|
||||
if self.save_user_settings_fields:
|
||||
user_settings['fields'] = self.user_settings_fields
|
||||
|
||||
update_user_settings(self.doctype, user_settings)
|
||||
|
||||
def get_order_by(doctype, meta):
|
||||
order_by = ""
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
import frappe, json
|
||||
|
||||
def get_list_settings(doctype, for_update=False):
|
||||
list_settings = frappe.cache().hget('_list_settings',
|
||||
'{0}::{1}'.format(doctype, frappe.session.user))
|
||||
|
||||
if list_settings is None:
|
||||
list_settings = frappe.db.sql('''select data from __ListSettings
|
||||
where user=%s and doctype=%s''', (frappe.session.user, doctype))
|
||||
list_settings = list_settings and list_settings[0][0] or '{}'
|
||||
|
||||
if not for_update:
|
||||
update_list_settings(doctype, list_settings, True)
|
||||
|
||||
return list_settings
|
||||
|
||||
def update_list_settings(doctype, list_settings, for_update=False):
|
||||
'''update list settings in cache'''
|
||||
|
||||
if for_update:
|
||||
current = json.loads(list_settings)
|
||||
else:
|
||||
current = json.loads(get_list_settings(doctype, for_update = True))
|
||||
|
||||
if isinstance(current, basestring):
|
||||
# corrupt due to old code, remove this in a future release
|
||||
current = {}
|
||||
|
||||
current.update(list_settings)
|
||||
|
||||
frappe.cache().hset('_list_settings', '{0}::{1}'.format(doctype, frappe.session.user),
|
||||
json.dumps(current))
|
||||
|
||||
def sync_list_settings():
|
||||
'''Sync from cache to database (called asynchronously via the browser)'''
|
||||
for key, data in frappe.cache().hgetall('_list_settings').iteritems():
|
||||
doctype, user = key.split('::')
|
||||
frappe.db.sql('''insert into __ListSettings (user, doctype, data) values (%s, %s, %s)
|
||||
on duplicate key update data=%s''', (user, doctype, data, data))
|
||||
48
frappe/model/utils/user_settings.py
Normal file
48
frappe/model/utils/user_settings.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# Settings saved per user basis
|
||||
# such as page_limit, filters, last_view
|
||||
|
||||
import frappe, json
|
||||
|
||||
def get_user_settings(doctype, for_update=False):
|
||||
user_settings = frappe.cache().hget('_user_settings',
|
||||
'{0}::{1}'.format(doctype, frappe.session.user))
|
||||
|
||||
if user_settings is None:
|
||||
user_settings = frappe.db.sql('''select data from __UserSettings
|
||||
where user=%s and doctype=%s''', (frappe.session.user, doctype))
|
||||
user_settings = user_settings and user_settings[0][0] or '{}'
|
||||
|
||||
if not for_update:
|
||||
update_user_settings(doctype, user_settings, True)
|
||||
|
||||
return user_settings or '{}'
|
||||
|
||||
def update_user_settings(doctype, user_settings, for_update=False):
|
||||
'''update user settings in cache'''
|
||||
|
||||
if for_update:
|
||||
current = json.loads(user_settings)
|
||||
else:
|
||||
current = json.loads(get_user_settings(doctype, for_update = True))
|
||||
|
||||
if isinstance(current, basestring):
|
||||
# corrupt due to old code, remove this in a future release
|
||||
current = {}
|
||||
|
||||
current.update(user_settings)
|
||||
|
||||
frappe.cache().hset('_user_settings', '{0}::{1}'.format(doctype, frappe.session.user),
|
||||
json.dumps(current))
|
||||
|
||||
def sync_user_settings():
|
||||
'''Sync from cache to database (called asynchronously via the browser)'''
|
||||
for key, data in frappe.cache().hgetall('_user_settings').iteritems():
|
||||
doctype, user = key.split('::')
|
||||
frappe.db.sql('''insert into __UserSettings (user, doctype, data) values (%s, %s, %s)
|
||||
on duplicate key update data=%s''', (user, doctype, data, data))
|
||||
|
||||
@frappe.whitelist()
|
||||
def save(doctype, user_settings):
|
||||
user_settings = json.loads(user_settings or '{}')
|
||||
update_user_settings(doctype, user_settings)
|
||||
return user_settings
|
||||
|
|
@ -163,5 +163,5 @@ execute:frappe.rename_doc('Country', 'Macedonia, Republic of', 'Macedonia', igno
|
|||
execute:frappe.rename_doc('Country', 'Iran, Islamic Republic of', 'Iran', ignore_if_exists=True)
|
||||
execute:frappe.rename_doc('Country', 'Tanzania, United Republic of', 'Tanzania', ignore_if_exists=True)
|
||||
execute:frappe.rename_doc('Country', 'Syrian Arab Republic', 'Syria', ignore_if_exists=True)
|
||||
frappe.patches.v8_0.rename_listsettings_to_usersettings
|
||||
frappe.patches.v7_2.update_communications
|
||||
|
||||
|
|
|
|||
0
frappe/patches/v8_0/__init__.py
Normal file
0
frappe/patches/v8_0/__init__.py
Normal file
26
frappe/patches/v8_0/rename_listsettings_to_usersettings.py
Normal file
26
frappe/patches/v8_0/rename_listsettings_to_usersettings.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import frappe, json
|
||||
|
||||
def execute():
|
||||
for us in frappe.db.sql('''select user, doctype, data from __ListSettings''', as_dict=True):
|
||||
try:
|
||||
data = json.loads(us.data)
|
||||
except:
|
||||
continue
|
||||
|
||||
if 'List' in data:
|
||||
continue
|
||||
|
||||
if 'limit' in data:
|
||||
data['page_length'] = data['limit']
|
||||
del data['limit']
|
||||
|
||||
new_data = dict(List=data)
|
||||
new_data = json.dumps(new_data)
|
||||
|
||||
frappe.db.sql('''update __ListSettings
|
||||
set data=%(new_data)s
|
||||
where user=%(user)s
|
||||
and doctype=%(doctype)s''',
|
||||
{'new_data': new_data, 'user': us.user, 'doctype': us.doctype})
|
||||
|
||||
frappe.db.sql("RENAME TABLE __ListSettings to __UserSettings")
|
||||
|
|
@ -112,6 +112,7 @@
|
|||
"public/js/frappe/model/create_new.js",
|
||||
"public/js/frappe/model/perm.js",
|
||||
"public/js/frappe/model/workflow.js",
|
||||
"public/js/frappe/model/user_settings.js",
|
||||
|
||||
"public/js/lib/md5.min.js",
|
||||
"public/js/frappe/misc/user.js",
|
||||
|
|
@ -211,7 +212,9 @@
|
|||
],
|
||||
"js/list.min.js": [
|
||||
"public/js/frappe/ui/listing.html",
|
||||
"public/js/frappe/ui/listing.js",
|
||||
|
||||
"public/js/frappe/ui/base_list.js",
|
||||
|
||||
"public/js/frappe/model/indicator.js",
|
||||
"public/js/frappe/ui/filters/filters.js",
|
||||
"public/js/frappe/ui/filters/edit_filter.html",
|
||||
|
|
@ -222,7 +225,9 @@
|
|||
"public/js/frappe/ui/like.js",
|
||||
"public/js/frappe/ui/liked_by.html",
|
||||
"public/html/print_template.html",
|
||||
"public/js/frappe/list/doclistview.js",
|
||||
|
||||
"public/js/frappe/list/list_view.js",
|
||||
|
||||
"public/js/frappe/list/list_sidebar.js",
|
||||
"public/js/frappe/list/list_sidebar.html",
|
||||
"public/js/frappe/list/list_sidebar_stat.html",
|
||||
|
|
@ -232,14 +237,21 @@
|
|||
"public/js/frappe/list/list_item_row_head.html",
|
||||
"public/js/frappe/list/list_item_subject.html",
|
||||
"public/js/frappe/list/list_permission_footer.html",
|
||||
"public/js/frappe/list/listview.js",
|
||||
"public/js/frappe/views/calendar.js",
|
||||
"public/js/frappe/list/blueimp-gallery.html",
|
||||
"public/js/frappe/list/image_view_item_row.html",
|
||||
"public/js/frappe/list/image_view_item_main_head.html",
|
||||
|
||||
"public/js/frappe/list/list_renderer.js",
|
||||
"public/js/frappe/views/gantt/gantt_view.js",
|
||||
"public/js/frappe/views/calendar/calendar.js",
|
||||
"public/js/frappe/views/image/image_view.js",
|
||||
"public/js/frappe/views/kanban/kanban_view.js",
|
||||
|
||||
"public/js/frappe/list/header_select_all_like_filter.html",
|
||||
"public/js/frappe/list/item_assigned_to_comment_count.html",
|
||||
"public/js/frappe/views/treeview.js",
|
||||
|
||||
"public/js/frappe/views/image/image_view_item_row.html",
|
||||
"public/js/frappe/views/image/image_view_item_main_head.html",
|
||||
"public/js/frappe/views/image/photoswipe_dom.html",
|
||||
|
||||
"public/js/frappe/views/kanban/kanban_board.html",
|
||||
"public/js/frappe/views/kanban/kanban_column.html",
|
||||
"public/js/frappe/views/kanban/kanban_card.html"
|
||||
|
|
|
|||
|
|
@ -838,3 +838,29 @@ fieldset[disabled] .form-control {
|
|||
.c3-tooltip td.value {
|
||||
text-align: right;
|
||||
}
|
||||
input[type="checkbox"] {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
}
|
||||
input[type="checkbox"]:before {
|
||||
position: absolute;
|
||||
font-family: 'FontAwesome';
|
||||
content: '\f096';
|
||||
visibility: visible;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 14px;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
color: #d1d8dd;
|
||||
-webkit-transition: 150ms color;
|
||||
-o-transition: 150ms color;
|
||||
transition: 150ms color;
|
||||
}
|
||||
input[type="checkbox"]:checked:before {
|
||||
content: '\f14a';
|
||||
font-size: 13px;
|
||||
color: #3b99fc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
.grid-body .editable-row .checkbox {
|
||||
margin: 0px;
|
||||
text-align: center;
|
||||
margin-top: 9px;
|
||||
}
|
||||
.grid-body .editable-row textarea {
|
||||
height: 38px !important;
|
||||
|
|
|
|||
|
|
@ -110,6 +110,25 @@
|
|||
border-top: 1px solid #d1d8dd;
|
||||
}
|
||||
.list-value {
|
||||
display: table;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.list-value .list-row-checkbox,
|
||||
.list-value .liked-by,
|
||||
.list-value .list-id,
|
||||
.list-value .list-select-all {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.list-value .list-row-checkbox,
|
||||
.list-value .list-select-all {
|
||||
margin: 0;
|
||||
margin-right: 7px;
|
||||
}
|
||||
.list-value .liked-by {
|
||||
padding-top: 2px;
|
||||
}
|
||||
.list-value .list-col-title {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.progress {
|
||||
|
|
@ -118,7 +137,7 @@
|
|||
.doclist-row {
|
||||
font-size: 12px;
|
||||
}
|
||||
.doclist-row .likes-count {
|
||||
.likes-count {
|
||||
display: inline-block;
|
||||
width: 15px;
|
||||
margin-left: -5px;
|
||||
|
|
@ -164,9 +183,6 @@
|
|||
.listview-main-section .octicon-heart {
|
||||
cursor: pointer;
|
||||
}
|
||||
.list-row-head .octicon-heart {
|
||||
margin-right: 13px;
|
||||
}
|
||||
.like-action.octicon-heart {
|
||||
color: #ff5858;
|
||||
}
|
||||
|
|
@ -198,55 +214,6 @@
|
|||
width: 37px;
|
||||
text-align: left;
|
||||
}
|
||||
.image-view {
|
||||
float: left;
|
||||
}
|
||||
.image-view-subject {
|
||||
padding: inherit;
|
||||
}
|
||||
.image-view-col {
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.image-view-col a {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
table.field-info {
|
||||
opacity: 0;
|
||||
bottom: -20px;
|
||||
font-size: 8pt;
|
||||
color: white;
|
||||
background-color: #36414C;
|
||||
position: absolute;
|
||||
padding-bottom: 0px !important;
|
||||
border: 0px;
|
||||
}
|
||||
table.field-info tr td {
|
||||
border: none !important;
|
||||
}
|
||||
.zoom-view {
|
||||
top: 10px !important;
|
||||
right: 10px !important;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
opacity: 0;
|
||||
font-size: 16px;
|
||||
color: #36414C;
|
||||
position: absolute;
|
||||
padding: 0px !important;
|
||||
border-radius: 5px;
|
||||
border: 0px;
|
||||
}
|
||||
.image-field {
|
||||
background-size: contain;
|
||||
position: relative;
|
||||
}
|
||||
.image-field:hover .field-info {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.image-field:hover .zoom-view {
|
||||
opacity: 0.6;
|
||||
}
|
||||
.tag-row {
|
||||
margin-top: 5px;
|
||||
padding-left: 55px;
|
||||
|
|
@ -291,3 +258,99 @@ table.field-info tr td {
|
|||
font-size: 11px;
|
||||
max-width: 100px;
|
||||
}
|
||||
.image-view-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.image-view-container .image-view-item {
|
||||
flex: 0 0 25%;
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #EBEFF2;
|
||||
border-right: 1px solid #EBEFF2;
|
||||
}
|
||||
.image-view-container .image-view-item:nth-child(4n) {
|
||||
border-right: none;
|
||||
}
|
||||
.image-view-container .image-view-item:nth-last-child(-n + 4):nth-child(4n + 1),
|
||||
.image-view-container .image-view-item:nth-last-child(-n + 4):nth-child(4n + 1) ~ .image-view-item {
|
||||
border-bottom: none;
|
||||
}
|
||||
.image-view-container .image-view-header {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.image-view-container .image-view-body:hover .zoom-view {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.image-view-container .image-view-body a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.image-view-container .image-field {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
height: 200px;
|
||||
padding: 15px;
|
||||
}
|
||||
.image-view-container .image-field img {
|
||||
max-height: 100%;
|
||||
}
|
||||
.image-view-container .placeholder-text {
|
||||
font-size: 72px;
|
||||
color: #d1d8dd;
|
||||
}
|
||||
.image-view-container .zoom-view {
|
||||
bottom: 10px !important;
|
||||
right: 10px !important;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
opacity: 0;
|
||||
font-size: 16px;
|
||||
color: #36414C;
|
||||
position: absolute;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
.image-view-container .zoom-view {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
@media (max-width: 991px) {
|
||||
.image-view-container .image-view-item {
|
||||
flex: 0 0 33.33333333%;
|
||||
}
|
||||
.image-view-container .image-view-item:nth-child(3n) {
|
||||
border-right: none;
|
||||
}
|
||||
.image-view-container .image-view-item:nth-last-child(-n + 3):nth-child(3n + 1),
|
||||
.image-view-container .image-view-item:nth-last-child(-n + 3):nth-child(3n + 1) ~ .image-view-item {
|
||||
border-bottom: none;
|
||||
}
|
||||
.image-view-container .image-view-item:nth-child(4n) {
|
||||
border-right: 1px solid #EBEFF2;
|
||||
}
|
||||
.image-view-container .image-view-item:nth-last-child(-n + 4):nth-child(4n + 1),
|
||||
.image-view-container .image-view-item:nth-last-child(-n + 4):nth-child(4n + 1) ~ .image-view-item {
|
||||
border-bottom: 1px solid #EBEFF2;
|
||||
}
|
||||
}
|
||||
.pswp--svg .pswp__button,
|
||||
.pswp--svg .pswp__button--arrow--left:before,
|
||||
.pswp--svg .pswp__button--arrow--right:before {
|
||||
background-image: url('/assets/frappe/images/default-skin.svg') !important;
|
||||
}
|
||||
.pswp--svg .pswp__button--arrow--left,
|
||||
.pswp--svg .pswp__button--arrow--right {
|
||||
background: none !important;
|
||||
}
|
||||
.pswp__bg {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
.gantt .details-container .heading {
|
||||
margin-bottom: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.gantt .details-container .avatar-small {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,6 +121,9 @@ body[data-route^="Module"] .main-menu .form-sidebar {
|
|||
.form-sidebar .form-viewers .shared-with-everyone .octicon {
|
||||
color: #36414C !important;
|
||||
}
|
||||
.form-sidebar .liked-by {
|
||||
margin-left: -4px;
|
||||
}
|
||||
.form-sidebar .liked-by .octicon-heart {
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
|
|
|
|||
1
frappe/public/images/default-skin.svg
Executable file
1
frappe/public/images/default-skin.svg
Executable file
|
|
@ -0,0 +1 @@
|
|||
<svg width="264" height="88" viewBox="0 0 264 88" xmlns="http://www.w3.org/2000/svg"><title>default-skin 2</title><g fill="none" fill-rule="evenodd"><g><path d="M67.002 59.5v3.768c-6.307.84-9.184 5.75-10.002 9.732 2.22-2.83 5.564-5.098 10.002-5.098V71.5L73 65.585 67.002 59.5z" id="Shape" fill="#fff"/><g fill="#fff"><path d="M13 29v-5h2v3h3v2h-5zM13 15h5v2h-3v3h-2v-5zM31 15v5h-2v-3h-3v-2h5zM31 29h-5v-2h3v-3h2v5z" id="Shape"/></g><g fill="#fff"><path d="M62 24v5h-2v-3h-3v-2h5zM62 20h-5v-2h3v-3h2v5zM70 20v-5h2v3h3v2h-5zM70 24h5v2h-3v3h-2v-5z"/></g><path d="M20.586 66l-5.656-5.656 1.414-1.414L22 64.586l5.656-5.656 1.414 1.414L23.414 66l5.656 5.656-1.414 1.414L22 67.414l-5.656 5.656-1.414-1.414L20.586 66z" fill="#fff"/><path d="M111.785 65.03L110 63.5l3-3.5h-10v-2h10l-3-3.5 1.785-1.468L117 59l-5.215 6.03z" fill="#fff"/><path d="M152.215 65.03L154 63.5l-3-3.5h10v-2h-10l3-3.5-1.785-1.468L147 59l5.215 6.03z" fill="#fff"/><g><path id="Rectangle-11" fill="#fff" d="M160.957 28.543l-3.25-3.25-1.413 1.414 3.25 3.25z"/><path d="M152.5 27c3.038 0 5.5-2.462 5.5-5.5s-2.462-5.5-5.5-5.5-5.5 2.462-5.5 5.5 2.462 5.5 5.5 5.5z" id="Oval-1" stroke="#fff" stroke-width="1.5"/><path fill="#fff" d="M150 21h5v1h-5z"/></g><g><path d="M116.957 28.543l-1.414 1.414-3.25-3.25 1.414-1.414 3.25 3.25z" fill="#fff"/><path d="M108.5 27c3.038 0 5.5-2.462 5.5-5.5s-2.462-5.5-5.5-5.5-5.5 2.462-5.5 5.5 2.462 5.5 5.5 5.5z" stroke="#fff" stroke-width="1.5"/><path fill="#fff" d="M106 21h5v1h-5z"/><path fill="#fff" d="M109.043 19.008l-.085 5-1-.017.085-5z"/></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -128,7 +128,7 @@ frappe.ui.form.Sidebar = Class.extend({
|
|||
make_like: function() {
|
||||
this.like_wrapper = this.sidebar.find(".liked-by");
|
||||
this.like_icon = this.sidebar.find(".liked-by .octicon-heart");
|
||||
this.like_count = this.sidebar.find(".liked-by .like-count");
|
||||
this.like_count = this.sidebar.find(".liked-by .likes-count");
|
||||
frappe.ui.setup_like_popover(this.sidebar.find(".liked-by-parent"), ".liked-by");
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@
|
|||
<ul class="list-unstyled sidebar-menu text-muted">
|
||||
<li class="liked-by-parent">
|
||||
<span class="liked-by">
|
||||
<i class="octicon octicon-heart like-action text-extra-muted"></i>
|
||||
<span class="like-count"></span>
|
||||
<i class="octicon octicon-heart like-action text-extra-muted fa-fw"></i>
|
||||
<span class="likes-count"></span>
|
||||
</span>
|
||||
</li>
|
||||
<li class="modified-by"></li>
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls">
|
||||
<div class="slides"></div>
|
||||
<h3 class="title"></h3>
|
||||
<a class="prev">‹</a>
|
||||
<a class="next">›</a>
|
||||
<a class="close">×</a>
|
||||
<a class="play-pause"></a>
|
||||
<ol class="indicator"></ol>
|
||||
</div>
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,8 @@
|
|||
{% if (_checkbox) { %}
|
||||
<input class="list-select-all" type="checkbox" style="margin-right: 7px; margin-top: 2px;"
|
||||
<input class="list-select-all" type="checkbox"
|
||||
title="{%= __("Select All") %}">
|
||||
{% } %}
|
||||
|
||||
<i class="fa-fw octicon octicon-heart text-extra-muted not-liked like-action list-liked-by-me"
|
||||
title="{%= __("Likes") %}"></i>
|
||||
<span style="display: inline-block; width: 34px">
|
||||
<i class="fa-fw octicon octicon-heart text-extra-muted not-liked like-action list-liked-by-me"
|
||||
title="{%= __("Likes") %}"></i>
|
||||
</span>
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
<div class="col-xs-6 col-sm-4 col-md-3 doclist-row has-checkbox image-view ellipsis">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 image-view-col">
|
||||
{%= subject %}
|
||||
</div>
|
||||
</div>
|
||||
<!-- Image -->
|
||||
<div class="row">
|
||||
<div class="col-xs-12 image-view-col" align="center">
|
||||
<a data-name="{{ data.name }}" title="{{ data.name }}" href="#Form/{{ data.doctype }}/{{ data.name }}">
|
||||
<div class="pos-item-image image-field" data-name="{{ data.name }}" style="{% if (item_image) { %} background-image: {%= item_image %}; {% }
|
||||
else { %} background-color: {{ color }}; {% } %} border: 0px;">
|
||||
{% if (!item_image) { %}{%= frappe.get_abbr(data.name) %}{% } %}
|
||||
<button class="btn btn-info zoom-view">
|
||||
<i class="fa fa-zoom-in"></i>
|
||||
</button>
|
||||
<table class="table table-condensed field-info">
|
||||
{% for (var i=0, l=columns.length; i < l; i++ ) {
|
||||
var col = columns[i], value=data[col.fieldname]; %}
|
||||
{% if(in_list(allowed_type, col.fieldtype)) { %}
|
||||
<tr>
|
||||
<td align="right" width="40%">{%= col.title %}</td>
|
||||
<td align="left" width="60%">{%= value %}</td>
|
||||
</tr>
|
||||
{% } %}
|
||||
{% } %}
|
||||
</table>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<!-- comment -->
|
||||
<div class="col-xs-12 image-view-col">
|
||||
<div class="row">
|
||||
<div class="col-xs-4">{%= list.get_indicator(data) %}</div>
|
||||
<div class="col-xs-8 text-right">
|
||||
<!-- comments count and assigned to section -->
|
||||
{%= frappe.render_template("item_assigned_to_comment_count", { data: data }) %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
frappe.views.ImageView = Class.extend({
|
||||
init: function(opts){
|
||||
this.docnames = []
|
||||
this.doc_images = {}
|
||||
this.doctype = opts.doctype;
|
||||
this.docname = opts.docname;
|
||||
this.container = opts.container;
|
||||
|
||||
this.get_images(this.doctype, this.docname);
|
||||
},
|
||||
|
||||
get_images: function(doctype, docname){
|
||||
/* get the list of all the Images associated with doc */
|
||||
var me = this;
|
||||
if(Object.keys(this.doc_images).length == 0){
|
||||
frappe.call({
|
||||
method: "frappe.client.get_list",
|
||||
args: {
|
||||
doctype: "File",
|
||||
order_by: "attached_to_name",
|
||||
fields: [
|
||||
"'image/*' as type", "ifnull(thumbnail_url, file_url) as thumbnail",
|
||||
"concat(attached_to_name, ' - ', file_name) as title", "file_url as href",
|
||||
"attached_to_name as name"
|
||||
],
|
||||
filters: [
|
||||
["File", "attached_to_doctype", "=", this.doctype],
|
||||
["File", "attached_to_name", "in", this.get_docname_list()],
|
||||
["File", "is_folder", "!=", 1]
|
||||
]
|
||||
},
|
||||
freeze: true,
|
||||
freeze_message: "Fetching Images ..",
|
||||
callback: function(r){
|
||||
if(!r.message){
|
||||
msgprint("No Images found")
|
||||
} else{
|
||||
// filter image files from other
|
||||
images = r.message.filter(function(image){
|
||||
return frappe.utils.is_image_file(image.title? image.title: image.href);
|
||||
});
|
||||
|
||||
if(images){
|
||||
me.prepare_images(images);
|
||||
me.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.render()
|
||||
}
|
||||
},
|
||||
|
||||
get_docname_list: function(){
|
||||
var names = []
|
||||
$.each(cur_list.data, function(idx, doc){
|
||||
names.push(doc.name);
|
||||
});
|
||||
return names
|
||||
},
|
||||
|
||||
prepare_images: function(images){
|
||||
var me = this;
|
||||
this.doc_images = {}
|
||||
|
||||
$.each(images, function(idx, image){
|
||||
name = image.name;
|
||||
delete image.name;
|
||||
|
||||
_images = me.doc_images[name] || [];
|
||||
_images.push(image)
|
||||
|
||||
me.doc_images[name] = _images;
|
||||
delete _images;
|
||||
});
|
||||
|
||||
this.docnames = $.map(cur_list.data, function(doc, idx){
|
||||
if(inList(Object.keys(me.doc_images), doc.name)){
|
||||
return doc.name;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render: function(){
|
||||
if(this.docname in this.doc_images){
|
||||
this.gallery = blueimp.Gallery(this.doc_images[this.docname], this.get_options());
|
||||
this.setup_navigation();
|
||||
} else {
|
||||
msgprint("No Images found for <b>"+ this.doctype +"</b> : "+ this.docname);
|
||||
}
|
||||
},
|
||||
|
||||
setup_navigation: function(){
|
||||
// extend gallery library to enable document navigation using UP / Down arrow key
|
||||
var me = this;
|
||||
var args = {}
|
||||
|
||||
$.extend(me.gallery, {
|
||||
nextSlides:function(){
|
||||
args.offset = 1;
|
||||
me.navigate(args)
|
||||
},
|
||||
|
||||
prevSlides:function(){
|
||||
args.offset = -1;
|
||||
me.navigate(args)
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
navigate: function(args){
|
||||
var index = 0;
|
||||
var me = this;
|
||||
var last_idx = this.docnames.length - 1;
|
||||
|
||||
$.each(this.docnames, function(idx, name){
|
||||
if(name == me.docname){
|
||||
if(idx == last_idx && args.offset == 1){
|
||||
index = 0
|
||||
} else if(idx == 0 && args.offset == -1) {
|
||||
index = last_idx
|
||||
} else {
|
||||
index = idx + args.offset
|
||||
}
|
||||
me.docname = me.docnames[index];
|
||||
return false;
|
||||
}
|
||||
});
|
||||
this.gallery.close();
|
||||
window.setTimeout(function(){
|
||||
me.get_images(me.doctype, me.docname)
|
||||
}, 300);
|
||||
},
|
||||
|
||||
get_options: function(){
|
||||
/* options for the gallery plugin */
|
||||
return {
|
||||
indicatorContainer: 'ol',
|
||||
thumbnailIndicators: true,
|
||||
thumbnailProperty: 'thumbnail',
|
||||
activeIndicatorClass: 'active',
|
||||
container: this.container.find(".blueimp-gallery")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
{% if (col.type==="Subject") { %}
|
||||
{%= subject %}
|
||||
{% } else if (col.type==="Indicator") { %}
|
||||
{%= list.get_indicator(data) %}
|
||||
{%= indicator %}
|
||||
{% } else if (col.render) { %}
|
||||
{%= col.render(data) %}
|
||||
{% } else if (col.fieldtype==="Image") { %}
|
||||
|
|
@ -36,9 +36,8 @@
|
|||
<a class="filterable h6 text-muted grey"
|
||||
data-filter="{%= col.fieldname %},=,{%= value %}">{%= value %}</a>
|
||||
{% } else { %}
|
||||
{% if(list.settings.formatters
|
||||
&& list.settings.formatters[col.fieldname]) { %}
|
||||
{{ list.settings.formatters[col.fieldname](value, col.df, data) }}
|
||||
{% if(formatters && formatters[col.fieldname]) { %}
|
||||
{{ formatters[col.fieldname](value, col.df, data) }}
|
||||
{% } else { %}
|
||||
{{ frappe.format(value, col.df, null, data) }}
|
||||
{% } %}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,13 @@
|
|||
{% } %}
|
||||
{% if(col.df && ["Int", "Float", "Currency", "Percent"].indexOf(col.df.fieldtype)!==-1) { %}text-right{% } %}">
|
||||
|
||||
<span class="list-value">
|
||||
{% if (col.type==="Subject") { %}
|
||||
{%= frappe.render_template("header_select_all_like_filter", { _checkbox: _checkbox }) %}
|
||||
{% } %}
|
||||
<span class="list-col-title">{{ __(col.title) || __(col.label) || "" }}</span>
|
||||
</span>
|
||||
|
||||
<span class="list-value" {% if i==0 %}style="margin-left: -8px;"{% endif %}>
|
||||
{{ __(col.title) || __(col.label) || "" }}</span>
|
||||
</div>
|
||||
{% } %}
|
||||
{% } %}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<div class="row doclist-row {% if (data._checkbox) { %} has-checkbox {% } %}">
|
||||
<div class="col-xs-10
|
||||
{% if (list.meta.title_field && !list.settings.hide_name_column) { %}
|
||||
{% if (meta.title_field && !settings.hide_name_column) { %}
|
||||
col-sm-8
|
||||
{% } else { %}
|
||||
col-sm-10
|
||||
|
|
@ -10,8 +10,8 @@
|
|||
</div>
|
||||
|
||||
<!-- id -->
|
||||
{% if (list.meta.title_field && !list.settings.hide_name_column) {
|
||||
var is_different = data.name !== data[list.meta.title_field];
|
||||
{% if (meta.title_field && !settings.hide_name_column) {
|
||||
var is_different = data.name !== data[meta.title_field];
|
||||
%}
|
||||
<div class="list-col col-sm-2 hidden-xs text-right ellipsis list-row-id">
|
||||
{% if (is_different) { %}
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
<!-- comment -->
|
||||
<div class="list-col col-sm-2 col-xs-2
|
||||
text-right list-row-right" style="padding-left:0px">
|
||||
<div class="visible-xs list-row-indicator">{%= list.get_indicator_dot(data) %}</div>
|
||||
<div class="visible-xs list-row-indicator">{%= indicator_dot %}</div>
|
||||
<!-- comments count and assigned to section -->
|
||||
{%= frappe.render_template("item_assigned_to_comment_count", { data: data }) %}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="list-row list-row-head">
|
||||
<div class="list-row list-row-head" data-list-renderer="{{list.name}}">
|
||||
<div class="row doclist-row">
|
||||
<div class="col-xs-10
|
||||
{% if (list.meta.title_field && !list.settings.hide_name_column) { %}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
{% if (_checkbox) { %}
|
||||
<input class="list-delete" type="checkbox"
|
||||
style="margin: 0 7px 0 0; vertical-align: middle;">
|
||||
<input class="list-row-checkbox" type="checkbox" data-name="{{name}}">
|
||||
{% } %}
|
||||
<span class="liked-by" data-liked-by=\'{{ JSON.stringify(_liked_by) }}\'>
|
||||
<i class="octicon octicon-heart
|
||||
|
|
@ -14,7 +13,6 @@
|
|||
</span>
|
||||
<a class="grey list-id {{ css_seen }}"
|
||||
data-name="{{ _name }}"
|
||||
style="margin-right: 7px; margin-left: -8px;"
|
||||
href="#Form/{{ _doctype_encoded }}/{{ _name_encoded }}"
|
||||
title="{{ _full_title }}">{{ strip_html(_title) }}</a>
|
||||
{% if (_workflow && !_without_workflow) { %}
|
||||
|
|
|
|||
528
frappe/public/js/frappe/list/list_renderer.js
Normal file
528
frappe/public/js/frappe/list/list_renderer.js
Normal file
|
|
@ -0,0 +1,528 @@
|
|||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// MIT License. See license.txt
|
||||
|
||||
frappe.provide('frappe.views');
|
||||
|
||||
// Renders customized list
|
||||
// usually based on `in_list_view` property
|
||||
|
||||
frappe.views.ListRenderer = Class.extend({
|
||||
name: 'List',
|
||||
init: function (opts) {
|
||||
$.extend(this, opts);
|
||||
this.meta = frappe.get_meta(this.doctype);
|
||||
|
||||
this.init_settings();
|
||||
this.set_defaults();
|
||||
this.set_fields();
|
||||
this.set_columns();
|
||||
this.setup_cache();
|
||||
},
|
||||
set_defaults: function () {
|
||||
var me = this;
|
||||
this.page_title = __(this.doctype);
|
||||
|
||||
this.set_wrapper();
|
||||
this.prepare_render_view();
|
||||
|
||||
// flag to enable/disable realtime updates in list_view
|
||||
this.no_realtime = false;
|
||||
|
||||
// set false to render view even if no results
|
||||
// e.g Calendar
|
||||
this.show_no_result = true;
|
||||
|
||||
// hide sort selector
|
||||
this.hide_sort_selector = false;
|
||||
|
||||
// default settings
|
||||
this.order_by = this.order_by || 'modified desc';
|
||||
this.filters = this.filters || [];
|
||||
this.page_length = this.page_length || 20;
|
||||
},
|
||||
setup_cache: function () {
|
||||
frappe.provide('frappe.views.list_renderers.' + this.doctype);
|
||||
frappe.views.list_renderers[this.doctype][this.list_view.current_view] = this;
|
||||
},
|
||||
init_settings: function () {
|
||||
this.settings = frappe.listview_settings[this.doctype] || {};
|
||||
this.init_user_settings();
|
||||
|
||||
this.order_by = this.user_settings.order_by || this.settings.order_by;
|
||||
this.filters = this.user_settings.filters || this.settings.filters;
|
||||
this.page_length = this.user_settings.page_length || this.settings.page_length;
|
||||
|
||||
// default filter for submittable doctype
|
||||
if(frappe.model.is_submittable(this.doctype) && (!this.filters || !this.filters.length)) {
|
||||
this.filters = [[this.doctype, "docstatus", "!=", 2]];
|
||||
}
|
||||
},
|
||||
init_user_settings: function () {
|
||||
frappe.provide('frappe.model.user_settings.' + this.doctype + '.' + this.name);
|
||||
this.user_settings = frappe.get_user_settings(this.doctype)[this.name];
|
||||
},
|
||||
after_refresh: function() {
|
||||
// called after refresh in list_view
|
||||
},
|
||||
before_refresh: function() {
|
||||
// called before refresh in list_view
|
||||
},
|
||||
should_refresh: function() {
|
||||
return this.list_view.current_view !== this.list_view.last_view;
|
||||
},
|
||||
set_wrapper: function () {
|
||||
this.wrapper = this.list_view.wrapper.find('.result-list');
|
||||
},
|
||||
set_fields: function () {
|
||||
var me = this;
|
||||
var tabDoctype = '`tab' + this.doctype + '`.';
|
||||
this.fields = [];
|
||||
this.stats = ['_user_tags'];
|
||||
|
||||
var add_field = function (fieldname) {
|
||||
if (!fieldname.includes('`tab')) {
|
||||
fieldname = tabDoctype + '`' + fieldname + '`';
|
||||
}
|
||||
if (!me.fields.includes(fieldname))
|
||||
me.fields.push(fieldname);
|
||||
}
|
||||
|
||||
var defaults = [
|
||||
'name',
|
||||
'owner',
|
||||
'docstatus',
|
||||
'_user_tags',
|
||||
'_comments',
|
||||
'modified',
|
||||
'modified_by',
|
||||
'_assign',
|
||||
'_liked_by',
|
||||
'_seen'
|
||||
];
|
||||
defaults.map(add_field);
|
||||
|
||||
// add title field
|
||||
if (this.meta.title_field) {
|
||||
this.title_field = this.meta.title_field;
|
||||
add_field(this.meta.title_field);
|
||||
}
|
||||
|
||||
// enabled / disabled
|
||||
if (frappe.meta.has_field(this.doctype, 'enabled')) { add_field('enabled'); };
|
||||
if (frappe.meta.has_field(this.doctype, 'disabled')) { add_field('disabled'); };
|
||||
|
||||
// add workflow field (as priority)
|
||||
this.workflow_state_fieldname = frappe.workflow.get_state_fieldname(this.doctype);
|
||||
if (this.workflow_state_fieldname) {
|
||||
if (!frappe.workflow.workflows[this.doctype]['override_status']) {
|
||||
add_field(this.workflow_state_fieldname);
|
||||
}
|
||||
this.stats.push(this.workflow_state_fieldname);
|
||||
}
|
||||
|
||||
this.meta.fields.forEach(function (df, i) {
|
||||
if (df.in_list_view && frappe.perm.has_perm(me.doctype, df.permlevel, 'read')) {
|
||||
if (df.fieldtype == 'Image' && df.options) {
|
||||
add_field(df.options);
|
||||
} else {
|
||||
add_field(df.fieldname);
|
||||
}
|
||||
// currency field for symbol (multi-currency)
|
||||
if (df.fieldtype == 'Currency' && df.options) {
|
||||
if (df.options.includes(':')) {
|
||||
add_field(df.options.split(':')[1]);
|
||||
} else {
|
||||
add_field(df.options);
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// additional fields
|
||||
if (this.settings.add_fields) {
|
||||
this.settings.add_fields.forEach(add_field);
|
||||
}
|
||||
// kanban column fields
|
||||
if (me.meta.__kanban_column_fields) {
|
||||
me.fields = me.fields.concat(me.meta.__kanban_column_fields);
|
||||
}
|
||||
},
|
||||
set_columns: function () {
|
||||
var me = this;
|
||||
this.columns = [];
|
||||
var name_column = {
|
||||
colspan: this.settings.colwidths && this.settings.colwidths.subject || 6,
|
||||
type: 'Subject',
|
||||
title: 'Name'
|
||||
};
|
||||
if (this.meta.title_field) {
|
||||
name_column.title = frappe.meta.get_docfield(this.doctype, this.meta.title_field).label;
|
||||
}
|
||||
this.columns.push(name_column);
|
||||
|
||||
if (frappe.has_indicator(this.doctype)) {
|
||||
// indicator
|
||||
this.columns.push({
|
||||
colspan: this.settings.colwidths && this.settings.colwidths.indicator || 3,
|
||||
type: 'Indicator',
|
||||
title: 'Status'
|
||||
});
|
||||
}
|
||||
|
||||
// total_colspans
|
||||
this.total_colspans = this.columns.reduce(function (total, curr) {
|
||||
return total + curr.colspan;
|
||||
}, 0);
|
||||
|
||||
// overridden
|
||||
var overridden = (this.settings.add_columns || []).map(function (d) {
|
||||
return d.content;
|
||||
});
|
||||
|
||||
// custom fields in list_view
|
||||
var docfields_in_list_view =
|
||||
frappe.get_children('DocType', this.doctype, 'fields', { 'in_list_view': 1 })
|
||||
.sort(function (a, b) {
|
||||
return a.idx - b.idx
|
||||
});
|
||||
|
||||
docfields_in_list_view.forEach(function (d) {
|
||||
if (overridden.includes(d.fieldname) || d.fieldname === me.title_field) {
|
||||
return;
|
||||
}
|
||||
if (me.total_colspans < 12) {
|
||||
me.add_column(d);
|
||||
}
|
||||
});
|
||||
|
||||
// additional columns
|
||||
if (this.settings.add_columns) {
|
||||
this.settings.add_columns.forEach(function (d) {
|
||||
if (me.total_colspans < 12) {
|
||||
if (typeof d === 'string') {
|
||||
me.add_column(frappe.meta.get_docfield(me.doctype, d));
|
||||
} else {
|
||||
me.columns.push(d);
|
||||
me.total_colspans += parseInt(d.colspan);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// distribute remaining columns
|
||||
var empty_cols = flt(12 - this.total_colspans);
|
||||
while (empty_cols > 0) {
|
||||
this.columns = this.columns.map(function (col) {
|
||||
if (empty_cols > 0) {
|
||||
col.colspan = cint(col.colspan) + 1;
|
||||
empty_cols = empty_cols - 1;
|
||||
}
|
||||
return col;
|
||||
});
|
||||
}
|
||||
},
|
||||
add_column: function (df) {
|
||||
// field width
|
||||
var colspan = 3;
|
||||
if (in_list(['Int', 'Percent'], df.fieldtype)) {
|
||||
colspan = 2;
|
||||
} else if (in_list(['Check', 'Image'], df.fieldtype)) {
|
||||
colspan = 1;
|
||||
} else if (in_list(['name', 'subject', 'title'], df.fieldname)) {
|
||||
// subjects are longer
|
||||
colspan = 4;
|
||||
} else if (df.fieldtype == 'Text Editor' || df.fieldtype == 'Text') {
|
||||
colspan = 4;
|
||||
}
|
||||
|
||||
if (df.columns && df.columns > 0) {
|
||||
colspan = df.columns;
|
||||
} else if (this.settings.column_colspan && this.settings.column_colspan[df.fieldname]) {
|
||||
colspan = this.settings.column_colspan[df.fieldname];
|
||||
} else {
|
||||
colspan = 2;
|
||||
}
|
||||
this.total_colspans += parseInt(colspan);
|
||||
var col = {
|
||||
colspan: colspan,
|
||||
content: df.fieldname,
|
||||
type: df.fieldtype,
|
||||
df: df,
|
||||
fieldtype: df.fieldtype,
|
||||
fieldname: df.fieldname,
|
||||
title: __(df.label)
|
||||
};
|
||||
if (this.settings.column_render && this.settings.column_render[df.fieldname]) {
|
||||
col.render = this.settings.column_render[df.fieldname];
|
||||
}
|
||||
this.columns.push(col);
|
||||
},
|
||||
|
||||
setup_filterable: function () {
|
||||
var me = this;
|
||||
this.wrapper.on('click', '.filterable', function (e) {
|
||||
var filters = $(this).attr('data-filter').split('|');
|
||||
var added = false;
|
||||
|
||||
filters.forEach(function (f) {
|
||||
f = f.split(',');
|
||||
if (f[2] === 'Today') {
|
||||
f[2] = frappe.datetime.get_today();
|
||||
} else if (f[2] == 'User') {
|
||||
f[2] = frappe.session.user;
|
||||
}
|
||||
var new_filter = me.list_view.filter_list
|
||||
.add_filter(me.doctype, f[0], f[1], f.slice(2).join(','));
|
||||
|
||||
if (new_filter) {
|
||||
// set it to true if atleast 1 filter is added
|
||||
added = true;
|
||||
}
|
||||
});
|
||||
if (added) {
|
||||
me.list_view.refresh(true);
|
||||
}
|
||||
});
|
||||
this.wrapper.on('click', '.list-row-left', function (e) {
|
||||
// don't open in case of checkbox, like, filterable
|
||||
if ($(e.target).hasClass('filterable')
|
||||
|| $(e.target).hasClass('octicon-heart')
|
||||
|| $(e.target).is(':checkbox')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var link = $(this).parent().find('a.list-id').get(0);
|
||||
window.location.href = link.href;
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
render_view: function (values) {
|
||||
var me = this;
|
||||
values.map(function (value) {
|
||||
var row = $('<div class="list-row">')
|
||||
.data("data", me.meta)
|
||||
.appendTo(me.wrapper).get(0);
|
||||
me.render_item(row, value);
|
||||
});
|
||||
|
||||
this.setup_filterable();
|
||||
},
|
||||
|
||||
// renders data(doc) in element
|
||||
render_item: function (element, data) {
|
||||
|
||||
$(element).append(this.get_item_html(data));
|
||||
|
||||
if (this.settings.post_render_item) {
|
||||
this.settings.post_render_item(this, element, data);
|
||||
}
|
||||
},
|
||||
|
||||
// returns html for a data item,
|
||||
// usually based on a template
|
||||
get_item_html: function (data) {
|
||||
var main = frappe.render_template('list_item_main', {
|
||||
data: data,
|
||||
columns: this.columns,
|
||||
formatters: this.settings.formatters,
|
||||
subject: this.get_subject_html(data, true),
|
||||
indicator: this.get_indicator_html(data),
|
||||
right_column: this.settings.right_column
|
||||
});
|
||||
|
||||
return frappe.render_template('list_item_row', {
|
||||
data: data,
|
||||
main: main,
|
||||
settings: this.settings,
|
||||
meta: this.meta,
|
||||
indicator_dot: this.get_indicator_dot(data),
|
||||
right_column: this.settings.right_column
|
||||
})
|
||||
},
|
||||
|
||||
get_header_html: function () {
|
||||
var main = frappe.render_template('list_item_main_head', {
|
||||
columns: this.columns,
|
||||
right_column: this.settings.right_column,
|
||||
_checkbox: ((frappe.model.can_delete(this.doctype) || this.settings.selectable)
|
||||
&& !this.no_delete)
|
||||
});
|
||||
|
||||
return frappe.render_template('list_item_row_head', { main: main, list: this });
|
||||
},
|
||||
|
||||
render_tags: function (element, data) {
|
||||
var me = this;
|
||||
var tag_row = $(`<div class='tag-row'>
|
||||
<div class='list-tag hidden-xs'></div>
|
||||
<div class='clearfix'></div>
|
||||
</div>`).appendTo(element);
|
||||
|
||||
if (!me.list_view.tags_shown) {
|
||||
tag_row.addClass('hide');
|
||||
}
|
||||
|
||||
// add tags
|
||||
var tag_editor = new frappe.ui.TagEditor({
|
||||
parent: tag_row.find('.list-tag'),
|
||||
frm: {
|
||||
doctype: this.doctype,
|
||||
docname: data.name
|
||||
},
|
||||
list_sidebar: me.list_view.list_sidebar,
|
||||
user_tags: data._user_tags,
|
||||
on_change: function (user_tags) {
|
||||
data._user_tags = user_tags;
|
||||
}
|
||||
});
|
||||
tag_editor.wrapper.on('click', '.tagit-label', function () {
|
||||
me.list_view.set_filter('_user_tags', $(this).text());
|
||||
});
|
||||
},
|
||||
|
||||
get_subject_html: function (data, without_workflow) {
|
||||
data._without_workflow = without_workflow;
|
||||
return frappe.render_template('list_item_subject', data);
|
||||
},
|
||||
|
||||
get_indicator_html: function (doc) {
|
||||
var indicator = frappe.get_indicator(doc, this.doctype);
|
||||
if (indicator) {
|
||||
return `<span class='indicator ${indicator[1]} filterable'
|
||||
data-filter='${indicator[2]}'>
|
||||
${__(indicator[0])}
|
||||
<span>`;
|
||||
}
|
||||
return '';
|
||||
},
|
||||
|
||||
get_indicator_dot: function (doc) {
|
||||
var indicator = frappe.get_indicator(doc, this.doctype);
|
||||
if (!indicator) {
|
||||
return '';
|
||||
}
|
||||
return `<span class='indicator ${indicator[1]}' title='${__(indicator[0])}'></span>`;
|
||||
},
|
||||
|
||||
prepare_data: function (data) {
|
||||
if (data.modified)
|
||||
this.prepare_when(data, data.modified);
|
||||
|
||||
// nulls as strings
|
||||
for (key in data) {
|
||||
if (data[key] == null) {
|
||||
data[key] = '';
|
||||
}
|
||||
}
|
||||
|
||||
data.doctype = this.doctype;
|
||||
data._liked_by = JSON.parse(data._liked_by || '[]');
|
||||
data._checkbox = (frappe.model.can_delete(this.doctype) || this.settings.selectable) && !this.no_delete
|
||||
|
||||
data._doctype_encoded = encodeURIComponent(data.doctype);
|
||||
data._name = data.name.replace(/'/g, '\'');
|
||||
data._name_encoded = encodeURIComponent(data.name);
|
||||
data._submittable = frappe.model.is_submittable(this.doctype);
|
||||
|
||||
var title_field = frappe.get_meta(this.doctype).title_field || 'name';
|
||||
data._title = strip_html(data[title_field]) || data.name;
|
||||
data._full_title = data._title;
|
||||
|
||||
if (data._title.length > 35) {
|
||||
data._title = data._title.slice(0, 35) + '...';
|
||||
}
|
||||
|
||||
data._workflow = null;
|
||||
if (this.workflow_state_fieldname) {
|
||||
data._workflow = {
|
||||
fieldname: this.workflow_state_fieldname,
|
||||
value: data[this.workflow_state_fieldname],
|
||||
style: frappe.utils.guess_style(data[this.workflow_state_fieldname])
|
||||
}
|
||||
}
|
||||
|
||||
data._user = frappe.session.user;
|
||||
|
||||
data._tags = data._user_tags.split(',').filter(function (v) {
|
||||
// filter falsy values
|
||||
return v;
|
||||
});
|
||||
|
||||
data.css_seen = '';
|
||||
if (data._seen) {
|
||||
var seen = JSON.parse(data._seen);
|
||||
if (seen && in_list(seen, data._user)) {
|
||||
data.css_seen = 'seen'
|
||||
}
|
||||
}
|
||||
|
||||
data._assign_list = JSON.parse(data._assign || '[]');
|
||||
|
||||
// prepare data in settings
|
||||
if (this.settings.prepare_data)
|
||||
this.settings.prepare_data(data);
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
prepare_when: function (data, date_str) {
|
||||
if (!date_str) date_str = data.modified;
|
||||
// when
|
||||
data.when = (dateutil.str_to_user(date_str)).split(' ')[0];
|
||||
var diff = dateutil.get_diff(dateutil.get_today(), date_str.split(' ')[0]);
|
||||
if (diff === 0) {
|
||||
data.when = comment_when(date_str);
|
||||
}
|
||||
if (diff === 1) {
|
||||
data.when = __('Yesterday')
|
||||
}
|
||||
if (diff === 2) {
|
||||
data.when = __('2 days ago')
|
||||
}
|
||||
},
|
||||
|
||||
// for views which require 3rd party libs
|
||||
required_libs: null,
|
||||
|
||||
prepare_render_view: function () {
|
||||
var me = this;
|
||||
this._render_view = this.render_view;
|
||||
|
||||
var lib_exists = (typeof this.required_libs === 'string' && this.required_libs)
|
||||
|| ($.isArray(this.required_libs) && this.required_libs.length);
|
||||
|
||||
this.render_view = function (values) {
|
||||
// prepare data before rendering view
|
||||
values = values.map(me.prepare_data.bind(this));
|
||||
|
||||
if (lib_exists) {
|
||||
me.load_lib(function () {
|
||||
me._render_view(values);
|
||||
});
|
||||
} else {
|
||||
me._render_view(values);
|
||||
}
|
||||
}.bind(this);
|
||||
},
|
||||
|
||||
load_lib: function (callback) {
|
||||
frappe.require(this.required_libs, callback);
|
||||
},
|
||||
|
||||
render_bar_graph: function (parent, data, field, label) {
|
||||
var args = {
|
||||
percent: data[field],
|
||||
label: __(label)
|
||||
}
|
||||
$(parent).append(`<span class='progress' style='width: 100 %; float: left; margin: 5px 0px;'> \
|
||||
<span class='progress- bar' title='${args.percent}% ${args.label}' \
|
||||
style='width: ${args.percent}%;'></span>\
|
||||
</span>`);
|
||||
},
|
||||
render_icon: function (parent, icon_class, label) {
|
||||
var icon_html = `<i class='${icon_class}' title='${__(label) || ''}'></i>`;
|
||||
$(parent).append(icon_html);
|
||||
}
|
||||
});
|
||||
|
|
@ -17,7 +17,7 @@ frappe.views.ListSidebar = Class.extend({
|
|||
this.cat_tags = [];
|
||||
},
|
||||
make: function() {
|
||||
var sidebar_content = frappe.render_template("list_sidebar", {doctype: this.doclistview.doctype});
|
||||
var sidebar_content = frappe.render_template("list_sidebar", {doctype: this.list_view.doctype});
|
||||
|
||||
this.sidebar = $('<div class="list-sidebar overlay-sidebar hidden-xs hidden-sm"></div>')
|
||||
.html(sidebar_content)
|
||||
|
|
@ -63,7 +63,7 @@ frappe.views.ListSidebar = Class.extend({
|
|||
.attr('disabled', null).removeClass('disabled')
|
||||
|
||||
// show image link if image_view
|
||||
if(this.doclistview.meta.image_field) {
|
||||
if(this.list_view.meta.image_field) {
|
||||
this.sidebar.find('.list-link[data-view="Image"]').removeClass('hide');
|
||||
show_list_link = true;
|
||||
}
|
||||
|
|
@ -103,8 +103,8 @@ frappe.views.ListSidebar = Class.extend({
|
|||
}
|
||||
|
||||
// from reference doctype
|
||||
if(this.doclistview.listview.settings.reports) {
|
||||
add_reports(this.doclistview.listview.settings.reports)
|
||||
if(this.list_view.list_renderer.settings.reports) {
|
||||
add_reports(this.list_view.list_renderer.settings.reports)
|
||||
}
|
||||
|
||||
// from specially tagged reports
|
||||
|
|
@ -119,12 +119,12 @@ frappe.views.ListSidebar = Class.extend({
|
|||
var boards = frappe.get_meta(this.doctype).__kanban_boards;
|
||||
if (!boards) return;
|
||||
boards.forEach(function(board) {
|
||||
var route = ["List", board.parent, "Kanban", board.name].join('/');
|
||||
var route = ["List", board.reference_doctype, "Kanban", board.name].join('/');
|
||||
if(!divider) {
|
||||
$('<li role="separator" class="divider"></li>').appendTo($dropdown);
|
||||
divider = true;
|
||||
}
|
||||
$('<li><a href="#'+ route + '">'+board.name+'</a></li>').appendTo($dropdown);
|
||||
$(`<li><a href="#${route}">${__(board.name)}</a></li>`).appendTo($dropdown);
|
||||
});
|
||||
|
||||
$dropdown.find('.new-kanban-board').click(function() {
|
||||
|
|
@ -179,10 +179,8 @@ frappe.views.ListSidebar = Class.extend({
|
|||
|
||||
me.add_custom_column_field(custom_column)
|
||||
.then(function(custom_column) {
|
||||
console.log(custom_column)
|
||||
var f = custom_column ?
|
||||
'kanban_column' : values.field_name;
|
||||
console.log(f)
|
||||
return me.make_kanban_board(values.board_name, f)
|
||||
})
|
||||
.then(function() {
|
||||
|
|
@ -239,7 +237,7 @@ frappe.views.ListSidebar = Class.extend({
|
|||
setup_assigned_to_me: function() {
|
||||
var me = this;
|
||||
this.page.sidebar.find(".assigned-to-me a").on("click", function() {
|
||||
me.doclistview.assigned_to_me();
|
||||
me.list_view.assigned_to_me();
|
||||
});
|
||||
},
|
||||
get_cat_tags:function(){
|
||||
|
|
@ -280,7 +278,7 @@ frappe.views.ListSidebar = Class.extend({
|
|||
//render normal stats
|
||||
me.render_stat("_user_tags", (r.message.stats|| {})["_user_tags"]);
|
||||
}
|
||||
me.doclistview.set_sidebar_height();
|
||||
me.list_view.set_sidebar_height();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
|
@ -333,8 +331,8 @@ frappe.views.ListSidebar = Class.extend({
|
|||
var fieldname = $(this).attr('data-field');
|
||||
var label = $(this).attr('data-label');
|
||||
if (label == "No Tags") {
|
||||
me.doclistview.filter_list.add_filter(me.doclistview.doctype, fieldname, 'not like', '%,%')
|
||||
me.doclistview.run();
|
||||
me.list_view.filter_list.add_filter(me.list_view.doctype, fieldname, 'not like', '%,%')
|
||||
me.list_view.run();
|
||||
} else {
|
||||
me.set_filter(fieldname, label);
|
||||
}
|
||||
|
|
|
|||
853
frappe/public/js/frappe/list/list_view.js
Normal file
853
frappe/public/js/frappe/list/list_view.js
Normal file
|
|
@ -0,0 +1,853 @@
|
|||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// MIT License. See license.txt
|
||||
|
||||
frappe.provide('frappe.views.list_view');
|
||||
frappe.provide('frappe.views.list_renderers');
|
||||
|
||||
cur_list = null;
|
||||
frappe.views.ListFactory = frappe.views.Factory.extend({
|
||||
make: function (route) {
|
||||
var me = this;
|
||||
var doctype = route[1];
|
||||
|
||||
frappe.model.with_doctype(doctype, function () {
|
||||
if (locals['DocType'][doctype].issingle) {
|
||||
frappe.set_re_route('Form', doctype);
|
||||
} else {
|
||||
if (!frappe.views.list_view[doctype]) {
|
||||
frappe.views.list_view[doctype] = new frappe.views.ListView({
|
||||
doctype: doctype,
|
||||
parent: me.make_page(true, 'List/' + doctype)
|
||||
});
|
||||
} else {
|
||||
frappe.container.change_to(frappe.views.list_view[doctype].page_name);
|
||||
}
|
||||
me.set_cur_list();
|
||||
}
|
||||
});
|
||||
},
|
||||
show: function () {
|
||||
this.set_module_breadcrumb();
|
||||
this._super();
|
||||
this.set_cur_list();
|
||||
cur_list && cur_list.refresh();
|
||||
},
|
||||
set_module_breadcrumb: function () {
|
||||
if (frappe.route_history.length > 1) {
|
||||
var prev_route = frappe.route_history[frappe.route_history.length - 2];
|
||||
if (prev_route[0] === 'modules') {
|
||||
var doctype = frappe.get_route()[1],
|
||||
module = prev_route[1];
|
||||
if (frappe.module_links[module] && frappe.module_links[module].includes(doctype)) {
|
||||
// save the last page from the breadcrumb was accessed
|
||||
frappe.breadcrumbs.set_doctype_module(doctype, module);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
set_cur_list: function () {
|
||||
var route = frappe.get_route();
|
||||
cur_list = frappe.container.page && frappe.container.page.list_view;
|
||||
if (cur_list && cur_list.doctype !== route[1]) {
|
||||
// changing...
|
||||
cur_list = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('save', function (event, doc) {
|
||||
frappe.views.set_list_as_dirty(doc.doctype);
|
||||
});
|
||||
|
||||
frappe.views.set_list_as_dirty = function (doctype) {
|
||||
if (frappe.views.trees[doctype]) {
|
||||
frappe.views.trees[doctype].tree.refresh();
|
||||
}
|
||||
|
||||
var route = frappe.get_route();
|
||||
var current_view = route[2] || 'List';
|
||||
|
||||
var list_renderer = frappe.views.list_renderers[doctype];
|
||||
if (list_renderer
|
||||
&& list_renderer[current_view]
|
||||
&& list_renderer[current_view].no_realtime) {
|
||||
return;
|
||||
}
|
||||
|
||||
var list_page = 'List/' + doctype;
|
||||
if (frappe.pages[list_page]) {
|
||||
if (frappe.pages[list_page].list_view) {
|
||||
if (frappe.pages[list_page].list_view.dirty) {
|
||||
// already refreshing...
|
||||
return;
|
||||
}
|
||||
frappe.pages[list_page].list_view.dirty = true;
|
||||
}
|
||||
}
|
||||
if (route[0] === 'List' && route[1] === doctype) {
|
||||
setTimeout(function () {
|
||||
frappe.pages[list_page].list_view.refresh();
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
frappe.views.ListView = frappe.ui.BaseList.extend({
|
||||
init: function (opts) {
|
||||
$.extend(this, opts);
|
||||
|
||||
if (!frappe.boot.user.all_read.includes(this.doctype)) {
|
||||
frappe.show_not_permitted(frappe.get_route_str());
|
||||
return;
|
||||
}
|
||||
|
||||
this.page_name = 'List/' + this.doctype;
|
||||
this.dirty = true;
|
||||
this.tags_shown = false;
|
||||
|
||||
this.page_title = __(this.doctype);
|
||||
this.page_title =
|
||||
(this.page_title.toLowerCase().substr(-4) == 'list') && __(this.page_title)
|
||||
|| __(this.page_title) + ' ' + __('List');
|
||||
|
||||
this.make_page();
|
||||
this.setup();
|
||||
|
||||
// refresh on init
|
||||
this.refresh();
|
||||
},
|
||||
|
||||
make_page: function () {
|
||||
this.parent.list_view = this;
|
||||
this.page = this.parent.page;
|
||||
|
||||
this.$page = $(this.parent).css({ 'min-height': '400px' });
|
||||
|
||||
$(`<div class='frappe-list-area'></div>`)
|
||||
.appendTo(this.page.main);
|
||||
|
||||
this.page.main.addClass('listview-main-section');
|
||||
var module = locals.DocType[this.doctype].module;
|
||||
|
||||
frappe.breadcrumbs.add(module, this.doctype);
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
this.can_delete = frappe.model.can_delete(this.doctype);
|
||||
this.meta = frappe.get_meta(this.doctype);
|
||||
this.wrapper = this.$page.find('.frappe-list-area').empty();
|
||||
this.allow_delete = true;
|
||||
|
||||
this.load_last_view();
|
||||
this.setup_view_variables();
|
||||
|
||||
this.setup_list_renderer();
|
||||
this.init_base_list(false);
|
||||
this.list_renderer.set_wrapper();
|
||||
this.list_renderer_onload();
|
||||
|
||||
this.show_match_help();
|
||||
this.init_menu();
|
||||
this.init_sort_selector();
|
||||
this.init_filters();
|
||||
this.set_title();
|
||||
this.init_headers();
|
||||
},
|
||||
|
||||
refresh_surroundings: function() {
|
||||
this.init_sort_selector();
|
||||
this.init_filters();
|
||||
this.set_title();
|
||||
this.init_headers();
|
||||
},
|
||||
|
||||
setup_list_renderer: function () {
|
||||
frappe.provide('frappe.views.list_renderers.' + this.doctype);
|
||||
|
||||
var list_renderer = frappe.views.list_renderers[this.doctype][this.current_view];
|
||||
if (list_renderer) {
|
||||
this.list_renderer = list_renderer;
|
||||
this.list_renderer.init_settings();
|
||||
return;
|
||||
}
|
||||
|
||||
var opts = {
|
||||
doctype: this.doctype,
|
||||
list_view: this
|
||||
}
|
||||
|
||||
if (this.current_view === 'List') {
|
||||
this.list_renderer = new frappe.views.ListRenderer(opts);
|
||||
} else if (this.current_view === 'Gantt') {
|
||||
this.list_renderer = new frappe.views.GanttView(opts);
|
||||
} else if (this.current_view === 'Calendar') {
|
||||
this.list_renderer = new frappe.views.CalendarView(opts);
|
||||
} else if (this.current_view === 'Image') {
|
||||
this.list_renderer = new frappe.views.ImageView(opts);
|
||||
} else if (this.current_view === 'Kanban') {
|
||||
this.list_renderer = new frappe.views.KanbanView(opts);
|
||||
}
|
||||
},
|
||||
|
||||
render_view: function (values) {
|
||||
this.list_renderer.render_view(values);
|
||||
},
|
||||
|
||||
set_title: function () {
|
||||
if (this.list_renderer.page_title) {
|
||||
this.page.set_title(this.list_renderer.page_title);
|
||||
} else {
|
||||
this.page.set_title(this.page_title);
|
||||
}
|
||||
},
|
||||
|
||||
load_last_view: function () {
|
||||
var us = frappe.get_user_settings(this.doctype);
|
||||
var route = ['List', this.doctype];
|
||||
|
||||
if (us.last_view && us.last_view !== 'List') {
|
||||
route.push(us.last_view);
|
||||
|
||||
if (us.last_view === 'Kanban') {
|
||||
route.push(us['Kanban'].last_kanban_board);
|
||||
}
|
||||
}
|
||||
|
||||
frappe.set_route(route);
|
||||
},
|
||||
|
||||
init_headers: function () {
|
||||
this.page.main.find('.list-headers > .list-row-head').hide();
|
||||
this.list_header = this.page.main.find('.list-headers > '
|
||||
+ '.list-row-head[data-list-renderer="'
|
||||
+ this.list_renderer.name +'"]');
|
||||
|
||||
if(this.list_header.length > 0) {
|
||||
this.list_header.show();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var html = this.list_renderer.get_header_html();
|
||||
if(!html) {
|
||||
this.list_header = $();
|
||||
return;
|
||||
}
|
||||
|
||||
this.list_header = $(html).appendTo(this.page.main.find('.list-headers'));
|
||||
|
||||
this.setup_like();
|
||||
this.setup_select_all();
|
||||
this.setup_delete();
|
||||
},
|
||||
|
||||
list_renderer_onload: function () {
|
||||
if (this.list_renderer.settings.onload) {
|
||||
this.list_renderer.settings.onload(this);
|
||||
}
|
||||
},
|
||||
|
||||
set_sidebar_height: function () {
|
||||
var h_main = this.page.sidebar.height();
|
||||
var h_side = this.$page.find('.layout-side-section').height();
|
||||
if (h_side > h_main)
|
||||
this.$page.find('.layout-main-section').css({ 'min-height': h_side });
|
||||
},
|
||||
|
||||
init_filters: function () {
|
||||
this.filter_list = new frappe.ui.FilterList({
|
||||
base_list: this,
|
||||
parent: this.wrapper.find('.list-filters').show(),
|
||||
doctype: this.doctype,
|
||||
default_filters: []
|
||||
});
|
||||
this.set_filters(this.list_renderer.filters);
|
||||
},
|
||||
|
||||
set_filters: function (filters) {
|
||||
var me = this;
|
||||
$.each(filters, function (i, f) {
|
||||
if (f.length === 3) {
|
||||
f = [me.doctype, f[0], f[1], f[2]]
|
||||
}
|
||||
me.filter_list.add_filter(f[0], f[1], f[2], f[3]);
|
||||
});
|
||||
},
|
||||
|
||||
init_sort_selector: function () {
|
||||
var me = this;
|
||||
var order_by = this.list_renderer.order_by;
|
||||
|
||||
this.sort_selector = new frappe.ui.SortSelector({
|
||||
parent: this.wrapper.find('.list-filters'),
|
||||
doctype: this.doctype,
|
||||
args: order_by,
|
||||
change: function () { me.run(); }
|
||||
});
|
||||
},
|
||||
|
||||
show_match_help: function () {
|
||||
var me = this;
|
||||
var match_rules_list = frappe.perm.get_match_rules(this.doctype);
|
||||
var perm = frappe.perm.get_perm(this.doctype);
|
||||
|
||||
if (match_rules_list.length) {
|
||||
this.footnote_area =
|
||||
frappe.utils.set_footnote(this.footnote_area, this.$page.find('.layout-main-section'),
|
||||
frappe.render_template('list_permission_footer', {
|
||||
condition_list: match_rules_list
|
||||
}));
|
||||
$(this.footnote_area).css({ 'margin-top': '0px' });
|
||||
}
|
||||
},
|
||||
|
||||
setup_view_variables: function () {
|
||||
var route = frappe.get_route();
|
||||
this.last_view = this.current_view || '';
|
||||
this.current_view = route[2] || 'List';
|
||||
},
|
||||
|
||||
init_base_list: function (auto_run) {
|
||||
var me = this;
|
||||
// init list
|
||||
this.make({
|
||||
method: 'frappe.desk.reportview.get',
|
||||
save_user_settings: true,
|
||||
get_args: this.get_args,
|
||||
parent: this.wrapper,
|
||||
freeze: true,
|
||||
start: 0,
|
||||
page_length: this.list_renderer.page_length,
|
||||
show_filters: false,
|
||||
new_doctype: this.doctype,
|
||||
no_result_message: this.make_no_result(),
|
||||
show_no_result: function() {
|
||||
return me.list_renderer.show_no_result;
|
||||
}
|
||||
});
|
||||
|
||||
this.setup_make_new_doc();
|
||||
|
||||
if (auto_run !== false && auto_run !== 0)
|
||||
this.refresh();
|
||||
},
|
||||
|
||||
setup_make_new_doc: function () {
|
||||
var me = this;
|
||||
// make_new_doc can be overridden so that default values can be prefilled
|
||||
// for example - communication list in customer
|
||||
if (this.list_renderer.settings.list_view_doc) {
|
||||
this.list_renderer.settings.list_view_doc(this);
|
||||
} else {
|
||||
$(this.wrapper).on('click', `button[list_view_doc='${this.doctype}']`, function () {
|
||||
me.make_new_doc.apply(me, [me.doctype]);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
refresh: function (dirty) {
|
||||
var me = this;
|
||||
|
||||
if (dirty !== undefined) this.dirty = dirty;
|
||||
|
||||
this.refresh_sidebar();
|
||||
this.setup_view_variables();
|
||||
|
||||
if (this.list_renderer.should_refresh()) {
|
||||
this.setup_list_renderer();
|
||||
this.refresh_surroundings();
|
||||
this.dirty = true;
|
||||
}
|
||||
|
||||
if (this.list_renderer.settings.refresh) {
|
||||
this.list_renderer.settings.refresh(this);
|
||||
}
|
||||
|
||||
this.set_filters_before_run();
|
||||
this.execute_run();
|
||||
},
|
||||
|
||||
execute_run: function () {
|
||||
if (this.dirty) {
|
||||
this.run();
|
||||
if (this.clean_dash != true) {
|
||||
this.filter_list.reload_stats();
|
||||
}
|
||||
} else {
|
||||
if (new Date() - (this.last_updated_on || 0) > 30000) {
|
||||
// older than 5 mins, refresh
|
||||
this.run();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
save_user_settings_locally: function (args) {
|
||||
|
||||
frappe.provide('frappe.model.user_settings.' + this.doctype + '.' + this.list_renderer.name);
|
||||
var user_settings_common = frappe.model.user_settings[this.doctype];
|
||||
var user_settings = frappe.model.user_settings[this.doctype][this.list_renderer.name];
|
||||
|
||||
if (!user_settings) return;
|
||||
|
||||
var different = false;
|
||||
if (!frappe.utils.arrays_equal(args.filters, user_settings.filters)) {
|
||||
// settings are dirty if filters change
|
||||
user_settings.filters = args.filters;
|
||||
different = true;
|
||||
}
|
||||
|
||||
if (user_settings.order_by !== args.order_by) {
|
||||
user_settings.order_by = args.order_by;
|
||||
different = true;
|
||||
}
|
||||
|
||||
if (user_settings.page_length !== args.page_length) {
|
||||
user_settings.page_length = args.page_length || 20
|
||||
different = true;
|
||||
}
|
||||
|
||||
// save fields in list settings
|
||||
if (args.save_user_settings_fields) {
|
||||
user_settings.fields = args.fields;
|
||||
}
|
||||
|
||||
// save last view
|
||||
if (user_settings_common.last_view !== this.current_view) {
|
||||
user_settings_common.last_view = this.current_view;
|
||||
different = true;
|
||||
}
|
||||
|
||||
if (different) {
|
||||
user_settings_common.updated_on = moment().toString();
|
||||
}
|
||||
},
|
||||
|
||||
set_filters_before_run: function () {
|
||||
// set filters from frappe.route_options
|
||||
// before switching pages, frappe.route_options can have pre-set filters
|
||||
// for the list view
|
||||
var me = this;
|
||||
|
||||
if (frappe.route_options) {
|
||||
this.set_filters_from_route_options();
|
||||
this.dirty = true;
|
||||
}
|
||||
},
|
||||
|
||||
run: function (more) {
|
||||
// set filter from route
|
||||
var me = this;
|
||||
|
||||
if (this.fresh && !more) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.list_renderer.settings.before_run) {
|
||||
this.list_renderer.settings.before_run(this);
|
||||
}
|
||||
|
||||
if (!this.list_renderer.settings.use_route) {
|
||||
var route = frappe.get_route();
|
||||
if (route[2] && !in_list(['Image', 'Gantt', 'Kanban', 'Calendar'], route[2])) {
|
||||
$.each(frappe.utils.get_args_dict_from_url(route[2]), function (key, val) {
|
||||
me.set_filter(key, val, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.list_header.find('.list-liked-by-me')
|
||||
.toggleClass('text-extra-muted not-liked', !this.is_star_filtered());
|
||||
|
||||
this.last_updated_on = new Date();
|
||||
this.dirty = false;
|
||||
this.clean_dash = false;
|
||||
// set a fresh so that multiple refreshes do not happen
|
||||
// at the same time. This is true when deleting.
|
||||
// AJAX response will try to refresh and list_update notification
|
||||
// via async will also try to update.
|
||||
// It is not possible to guess which will reach first
|
||||
// (most probably async will) but this is a forced way
|
||||
// to prevent instant refreshes on mutilple triggers
|
||||
// in a loosly coupled way.
|
||||
this.fresh = true;
|
||||
setTimeout(function () {
|
||||
me.fresh = false;
|
||||
}, 1000);
|
||||
|
||||
this._super(more);
|
||||
|
||||
if (this.list_renderer.settings.post_render) {
|
||||
this.list_renderer.settings.post_render(this);
|
||||
}
|
||||
|
||||
this.wrapper.on('render-complete', function() {
|
||||
me.list_renderer.after_refresh();
|
||||
})
|
||||
},
|
||||
|
||||
make_no_result: function () {
|
||||
var new_button = frappe.boot.user.can_create.includes(this.doctype)
|
||||
? (`<p><button class='btn btn-primary btn-sm'
|
||||
list_view_doc='${this.doctype}'>
|
||||
${__('Make a new ' + __(this.doctype))}
|
||||
</button></p>`)
|
||||
: '';
|
||||
var no_result_message =
|
||||
`<div class='msg-box no-border'>
|
||||
<p>${__('No {0} found', [__(this.doctype)])}</p>
|
||||
${new_button}
|
||||
</div>`;
|
||||
|
||||
return no_result_message;
|
||||
},
|
||||
|
||||
get_args: function () {
|
||||
var args = {
|
||||
doctype: this.doctype,
|
||||
fields: this.list_renderer.fields,
|
||||
filters: this.get_filters_args(),
|
||||
order_by: this.get_order_by_args(),
|
||||
with_comment_count: true
|
||||
}
|
||||
return args;
|
||||
},
|
||||
get_filters_args: function() {
|
||||
var filters = [];
|
||||
if(this.filter_list) {
|
||||
// get filters from filter_list
|
||||
filters = this.filter_list.get_filters();
|
||||
} else {
|
||||
filters = this.list_renderer.filters;
|
||||
}
|
||||
// remove duplicates
|
||||
var uniq = filters.uniqBy(JSON.stringify);
|
||||
return uniq;
|
||||
},
|
||||
get_order_by_args: function() {
|
||||
var order_by = '';
|
||||
if(this.sort_selector) {
|
||||
// get order_by from sort_selector
|
||||
order_by = this.sort_selector.sort_by + ' ' + this.sort_selector.sort_order;
|
||||
} else {
|
||||
order_by = this.list_renderer.order_by;
|
||||
}
|
||||
return order_by;
|
||||
},
|
||||
assigned_to_me: function () {
|
||||
this.filter_list.add_filter(this.doctype, '_assign', 'like', '%' + user + '%');
|
||||
this.run();
|
||||
},
|
||||
liked_by_me: function () {
|
||||
this.filter_list.add_filter(this.doctype, '_liked_by', 'like', '%' + user + '%');
|
||||
this.run();
|
||||
},
|
||||
remove_liked_by_me: function () {
|
||||
this.filter_list.get_filter('_liked_by').remove();
|
||||
},
|
||||
is_star_filtered: function () {
|
||||
return this.filter_list.filter_exists(this.doctype, '_liked_by', 'like', '%' + user + '%');
|
||||
},
|
||||
init_menu: function () {
|
||||
var me = this;
|
||||
this.$page.on('click', '.list-tag-preview', function () { me.toggle_tags(); });
|
||||
|
||||
// Refresh button for large screens
|
||||
this.page.set_secondary_action(__('Refresh'), function () {
|
||||
me.refresh(true);
|
||||
}, 'octicon octicon-sync')
|
||||
.addClass('hidden-xs');
|
||||
|
||||
// Refresh button as menu item in small screens
|
||||
this.page.add_menu_item(__('Refresh'), function () {
|
||||
me.refresh(true);
|
||||
}, 'octicon octicon-sync')
|
||||
.addClass('visible-xs');
|
||||
|
||||
if (frappe.model.can_import(this.doctype)) {
|
||||
this.page.add_menu_item(__('Import'), function () {
|
||||
frappe.set_route('data-import-tool', {
|
||||
doctype: me.doctype
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
if (frappe.model.can_set_user_permissions(this.doctype)) {
|
||||
this.page.add_menu_item(__('User Permissions Manager'), function () {
|
||||
frappe.set_route('user-permissions', {
|
||||
doctype: me.doctype
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
if (user_roles.includes('System Manager')) {
|
||||
this.page.add_menu_item(__('Role Permissions Manager'), function () {
|
||||
frappe.set_route('permission-manager', {
|
||||
doctype: me.doctype
|
||||
});
|
||||
}, true);
|
||||
this.page.add_menu_item(__('Customize'), function () {
|
||||
frappe.set_route('Form', 'Customize Form', {
|
||||
doc_type: me.doctype
|
||||
})
|
||||
}, true);
|
||||
}
|
||||
|
||||
this.make_bulk_assignment();
|
||||
this.make_bulk_printing();
|
||||
|
||||
// add to desktop
|
||||
this.page.add_menu_item(__('Add to Desktop'), function () {
|
||||
frappe.add_to_desktop(me.doctype, me.doctype);
|
||||
}, true);
|
||||
|
||||
if (user_roles.includes('System Manager') && frappe.boot.developer_mode === 1) {
|
||||
// edit doctype
|
||||
this.page.add_menu_item(__('Edit DocType'), function () {
|
||||
frappe.set_route('Form', 'DocType', me.doctype);
|
||||
}, true);
|
||||
}
|
||||
|
||||
},
|
||||
make_bulk_assignment: function () {
|
||||
|
||||
var me = this;
|
||||
|
||||
//bulk assignment
|
||||
me.page.add_menu_item(__('Assign To'), function () {
|
||||
|
||||
var docnames = me.get_checked_items().map(function (doc) {
|
||||
return doc.name;
|
||||
});
|
||||
|
||||
if (docnames.length >= 1) {
|
||||
me.dialog = new frappe.ui.form.AssignToDialog({
|
||||
obj: me,
|
||||
method: 'frappe.desk.form.assign_to.add_multiple',
|
||||
doctype: me.doctype,
|
||||
docname: docnames,
|
||||
bulk_assign: true,
|
||||
re_assign: true,
|
||||
callback: function () {
|
||||
me.refresh(true);
|
||||
}
|
||||
});
|
||||
me.dialog.clear();
|
||||
me.dialog.show();
|
||||
}
|
||||
else {
|
||||
frappe.msgprint(__('Select records for assignment'))
|
||||
}
|
||||
}, true);
|
||||
|
||||
},
|
||||
make_bulk_printing: function () {
|
||||
var me = this;
|
||||
var print_settings = frappe.model.get_doc(':Print Settings', 'Print Settings')
|
||||
var allow_print_for_draft = cint(print_settings.allow_print_for_draft)
|
||||
var is_submittable = frappe.model.is_submittable(me.doctype)
|
||||
var allow_print_for_cancelled = cint(print_settings.allow_print_for_cancelled)
|
||||
|
||||
//bulk priting
|
||||
me.page.add_menu_item(__('Print'), function () {
|
||||
var items = me.get_checked_items();
|
||||
|
||||
var valid_docs =
|
||||
items.filter(function (doc) {
|
||||
return !is_submittable || doc.docstatus === 1 ||
|
||||
(allow_print_for_cancelled && doc.docstatus == 2) ||
|
||||
(allow_print_for_draft && doc.docstatus == 0) ||
|
||||
user_roles.includes('Administrator')
|
||||
}).map(function (doc) {
|
||||
return doc.name
|
||||
});
|
||||
|
||||
var invalid_docs = items.filter(function (doc) {
|
||||
return !valid_docs.includes(doc.name);
|
||||
});
|
||||
|
||||
if (invalid_docs.length >= 1) {
|
||||
frappe.msgprint('You selected Draft or Cancelled documents')
|
||||
return;
|
||||
}
|
||||
|
||||
if (valid_docs.length >= 1) {
|
||||
|
||||
var dialog = new frappe.ui.Dialog({
|
||||
title: 'Print Documents',
|
||||
fields: [
|
||||
{ 'fieldtype': 'Check', 'label': __('With Letterhead'), 'fieldname': 'with_letterhead' },
|
||||
{ 'fieldtype': 'Select', 'label': __('Print Format'), 'fieldname': 'print_sel' },
|
||||
]
|
||||
});
|
||||
|
||||
dialog.set_primary_action(__('Print'), function () {
|
||||
args = dialog.get_values();
|
||||
if (!args) return;
|
||||
var default_print_format = locals.DocType[me.doctype].default_print_format;
|
||||
with_letterhead = args.with_letterhead ? 1 : 0;
|
||||
print_format = args.print_sel ? args.print_sel : default_print_format;
|
||||
|
||||
var json_string = JSON.stringify(valid_docs);
|
||||
var w = window.open('/api/method/frappe.utils.print_format.download_multi_pdf?'
|
||||
+ 'doctype=' + encodeURIComponent(me.doctype)
|
||||
+ '&name=' + encodeURIComponent(json_string)
|
||||
+ '&format=' + encodeURIComponent(print_format)
|
||||
+ '&no_letterhead=' + (with_letterhead ? '0' : '1'));
|
||||
if (!w) {
|
||||
frappe.msgprint(__('Please enable pop-ups')); return;
|
||||
}
|
||||
});
|
||||
|
||||
print_formats = frappe.meta.get_print_formats(me.doctype);
|
||||
dialog.fields_dict.print_sel.$input.empty().add_options(print_formats);
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
else {
|
||||
frappe.msgprint(__('Select atleast 1 record for printing'))
|
||||
}
|
||||
}, true);
|
||||
},
|
||||
|
||||
setup_like: function () {
|
||||
var me = this;
|
||||
this.$page.find('.result-list').on('click', '.like-action', frappe.ui.click_toggle_like);
|
||||
this.list_header.find('.list-liked-by-me').on('click', function () {
|
||||
if (me.is_star_filtered()) {
|
||||
me.remove_liked_by_me();
|
||||
} else {
|
||||
me.liked_by_me();
|
||||
}
|
||||
});
|
||||
|
||||
if (!frappe.dom.is_touchscreen()) {
|
||||
frappe.ui.setup_like_popover(this.$page.find('.result-list'), '.liked-by');
|
||||
}
|
||||
},
|
||||
|
||||
setup_select_all: function () {
|
||||
var me = this;
|
||||
|
||||
if (this.can_delete || this.list_renderer.settings.selectable) {
|
||||
this.list_header.find('.list-select-all').on('click', function () {
|
||||
me.$page.find('.list-row-checkbox').prop('checked', $(this).prop('checked'));
|
||||
});
|
||||
|
||||
this.$page.on('click', '.list-row-checkbox', function (event) {
|
||||
// multi-select using shift key
|
||||
var $this = $(this);
|
||||
if (event.shiftKey && $this.prop('checked')) {
|
||||
var $end_row = $this.parents('.list-row');
|
||||
var $start_row = $end_row.prevAll('.list-row')
|
||||
.find('.list-row-checkbox:checked').last().parents('.list-row');
|
||||
if ($start_row) {
|
||||
$start_row.nextUntil($end_row).find('.list-row-checkbox').prop('checked', true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
setup_delete: function () {
|
||||
var me = this;
|
||||
if (!(this.can_delete || this.list_renderer.settings.selectable)) {
|
||||
return;
|
||||
}
|
||||
this.$page.find('.list-row-checkbox').change(function () {
|
||||
me.toggle_delete();
|
||||
});
|
||||
// after delete, hide delete button
|
||||
this.wrapper.on('render-complete', function () {
|
||||
me.toggle_delete();
|
||||
});
|
||||
},
|
||||
|
||||
toggle_delete: function () {
|
||||
var checked_items = this.get_checked_items();
|
||||
var checked_items_status = this.$page.find('.checked-items-status');
|
||||
|
||||
if (checked_items.length > 0) {
|
||||
this.page.set_primary_action(__('Delete'), function () {
|
||||
me.delete_items()
|
||||
}, 'octicon octicon-trashcan')
|
||||
.addClass('btn-danger');
|
||||
|
||||
checked_items_status.text(
|
||||
no_of_checked_items == 1
|
||||
? __('1 item selected')
|
||||
: __('{0} items selected', [checked_items.length])
|
||||
)
|
||||
checked_items_status.removeClass('hide');
|
||||
} else {
|
||||
this.page.btn_primary.removeClass('btn-danger');
|
||||
this.set_primary_action();
|
||||
checked_items_status.addClass('hide');
|
||||
}
|
||||
},
|
||||
|
||||
toggle_tags: function () {
|
||||
if (this.tags_shown) {
|
||||
$('.tag-row').addClass('hide');
|
||||
this.tags_shown = false;
|
||||
} else {
|
||||
$('.tag-row').removeClass('hide');
|
||||
this.tags_shown = true;
|
||||
}
|
||||
},
|
||||
|
||||
get_checked_items: function () {
|
||||
var names = this.$page.find('.list-row-checkbox:checked').map(function (i, item) {
|
||||
return $(item).data().name;
|
||||
}).toArray();
|
||||
|
||||
return this.data.filter(function (doc) {
|
||||
return names.includes(doc.name);
|
||||
});
|
||||
},
|
||||
|
||||
set_primary_action: function () {
|
||||
if (this.list_renderer.settings.set_primary_action) {
|
||||
this.list_renderer.settings.set_primary_action(this);
|
||||
} else {
|
||||
this._super();
|
||||
}
|
||||
},
|
||||
|
||||
delete_items: function () {
|
||||
var me = this;
|
||||
var to_delete = this.get_checked_items();
|
||||
if (!to_delete.length)
|
||||
return;
|
||||
|
||||
var docnames = to_delete.map(function (doc) {
|
||||
return doc.name;
|
||||
});
|
||||
|
||||
frappe.confirm(__('Delete {0} items permanently?', [to_delete.length]),
|
||||
function () {
|
||||
return frappe.call({
|
||||
method: 'frappe.desk.reportview.delete_items',
|
||||
freeze: true,
|
||||
args: {
|
||||
items: docnames,
|
||||
doctype: me.doctype
|
||||
},
|
||||
callback: function () {
|
||||
me.$page.find('.list-select-all').prop('checked', false);
|
||||
frappe.utils.play_sound('delete');
|
||||
me.refresh(true);
|
||||
}
|
||||
})
|
||||
}
|
||||
);
|
||||
},
|
||||
refresh_sidebar: function () {
|
||||
//TODO: refresh if already exist
|
||||
this.list_sidebar = new frappe.views.ListSidebar({
|
||||
doctype: this.doctype,
|
||||
stats: this.list_renderer.stats,
|
||||
parent: this.$page.find('.layout-side-section'),
|
||||
set_filter: this.set_filter.bind(this),
|
||||
default_filters: this.list_renderer.filters,
|
||||
page: this.page,
|
||||
list_view: this
|
||||
})
|
||||
}
|
||||
});
|
||||
|
|
@ -1,403 +0,0 @@
|
|||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// MIT License. See license.txt
|
||||
|
||||
frappe.views.get_listview = function(doctype, parent) {
|
||||
if(frappe.listviews[doctype]) {
|
||||
var listview = new frappe.listviews[doctype](parent);
|
||||
} else {
|
||||
var listview = new frappe.views.ListView(parent, doctype);
|
||||
}
|
||||
return listview;
|
||||
}
|
||||
|
||||
// Renders customized list
|
||||
// usually based on `in_list_view` property
|
||||
|
||||
frappe.views.ListView = Class.extend({
|
||||
init: function(doclistview, doctype) {
|
||||
this.doclistview = doclistview;
|
||||
this.doctype = doctype;
|
||||
this.meta = frappe.get_doc("DocType", this.doctype);
|
||||
this.image_field = this.meta.image_field || 'image';
|
||||
this.settings = frappe.listview_settings[this.doctype] || {};
|
||||
if(this.meta.__listview_template) {
|
||||
this.template_name = doctype + "_listview";
|
||||
frappe.templates[this.template_name] = this.meta.__listview_template;
|
||||
}
|
||||
this.set_fields();
|
||||
this.set_columns();
|
||||
this.id_list = [];
|
||||
if(this.settings.group_by)
|
||||
this.group_by = this.settings.group_by;
|
||||
|
||||
var me = this;
|
||||
this.doclistview.onreset = function() {
|
||||
me.id_list = [];
|
||||
}
|
||||
this.order_by = this.settings.order_by;
|
||||
this.group_by = this.settings.group_by;
|
||||
},
|
||||
set_fields: function() {
|
||||
var me = this;
|
||||
var t = "`tab"+this.doctype+"`.";
|
||||
this.fields = [];
|
||||
this.stats = ['_user_tags'];
|
||||
|
||||
var add_field = function(fieldname) {
|
||||
field = t + "`" + fieldname + "`"
|
||||
if(me.fields.indexOf(field)=== -1)
|
||||
me.fields.push(field);
|
||||
}
|
||||
|
||||
$.each(['name', 'owner', 'docstatus', '_user_tags', '_comments', 'modified',
|
||||
'modified_by', '_assign', '_liked_by', '_seen'],
|
||||
function(i, fieldname) { add_field(fieldname); })
|
||||
|
||||
// add title field
|
||||
if(this.meta.title_field) {
|
||||
this.title_field = this.meta.title_field;
|
||||
add_field(this.meta.title_field);
|
||||
}
|
||||
|
||||
// endabled / disabled
|
||||
if(frappe.meta.has_field(this.doctype, 'enabled')) { add_field('enabled'); };
|
||||
if(frappe.meta.has_field(this.doctype, 'disabled')) { add_field('disabled'); };
|
||||
|
||||
// add workflow field (as priority)
|
||||
this.workflow_state_fieldname = frappe.workflow.get_state_fieldname(this.doctype);
|
||||
if(this.workflow_state_fieldname) {
|
||||
if (!frappe.workflow.workflows[this.doctype]["override_status"]) {
|
||||
add_field(this.workflow_state_fieldname);
|
||||
}
|
||||
this.stats.push(this.workflow_state_fieldname);
|
||||
}
|
||||
|
||||
$.each(this.meta.fields, function(i,d) {
|
||||
if(d.in_list_view && frappe.perm.has_perm(me.doctype, d.permlevel, "read")) {
|
||||
if(d.fieldtype=="Image" && d.options) {
|
||||
add_field(d.options);
|
||||
} else {
|
||||
add_field(d.fieldname);
|
||||
}
|
||||
// currency field for symbol (multi-currency)
|
||||
if(d.fieldtype=="Currency" && d.options) {
|
||||
if(d.options.indexOf(":")!=-1) {
|
||||
add_field(d.options.split(":")[1]);
|
||||
} else {
|
||||
add_field(d.options);
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// additional fields
|
||||
if(this.settings.add_fields) {
|
||||
$.each(this.settings.add_fields, function(i, d) {
|
||||
if(d.indexOf("`tab")===-1) {
|
||||
d = "`tab" + me.doctype + "`." + d;
|
||||
}
|
||||
if(me.fields.indexOf(d)==-1)
|
||||
me.fields.push(d);
|
||||
});
|
||||
}
|
||||
|
||||
if(me.meta.__kanban_column_fields)
|
||||
me.fields = me.fields.concat(me.meta.__kanban_column_fields);
|
||||
},
|
||||
set_columns: function() {
|
||||
var me = this;
|
||||
this.columns = [];
|
||||
var name_column = {
|
||||
colspan: this.settings.colwidths && this.settings.colwidths.subject || 6,
|
||||
type: "Subject",
|
||||
title: "Name"
|
||||
};
|
||||
if (this.meta.title_field) {
|
||||
name_column.title = frappe.meta.get_docfield(this.doctype, this.meta.title_field).label;
|
||||
}
|
||||
this.columns.push(name_column);
|
||||
this.total_colspans = this.columns[0].colspan;
|
||||
|
||||
|
||||
if(frappe.has_indicator(this.doctype)) {
|
||||
// indicator
|
||||
this.columns.push({
|
||||
colspan: this.settings.colwidths && this.settings.colwidths.indicator || 3,
|
||||
type: "Indicator",
|
||||
title: "Status"
|
||||
});
|
||||
this.total_colspans += this.columns[1].colspan;
|
||||
}
|
||||
|
||||
// overridden
|
||||
var overridden = $.map(this.settings.add_columns || [], function(d) {
|
||||
return d.content;
|
||||
});
|
||||
var docfields_in_list_view = frappe.get_children("DocType", this.doctype, "fields",
|
||||
{"in_list_view":1}).sort(function(a, b) { return a.idx - b.idx })
|
||||
|
||||
$.each(docfields_in_list_view, function(i,d) {
|
||||
if(in_list(overridden, d.fieldname) || d.fieldname === me.title_field) {
|
||||
return;
|
||||
}
|
||||
if(me.total_colspans < 12) {
|
||||
me.add_column(d);
|
||||
}
|
||||
});
|
||||
|
||||
// additional columns
|
||||
if(this.settings.add_columns) {
|
||||
$.each(this.settings.add_columns, function(i, d) {
|
||||
if(me.total_colspans < 12) {
|
||||
if(typeof d==="string") {
|
||||
me.add_column(frappe.meta.get_docfield(me.doctype, d));
|
||||
} else {
|
||||
me.columns.push(d);
|
||||
me.total_colspans += parseInt(d.colspan);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var empty_cols = flt(12 - this.total_colspans);
|
||||
while(empty_cols > 0) {
|
||||
for(var i=0, l=this.columns.length; i < l && empty_cols > 0; i++) {
|
||||
this.columns[i].colspan = cint(this.columns[i].colspan) + 1;
|
||||
empty_cols = empty_cols - 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
add_column: function(df) {
|
||||
// field width
|
||||
var colspan = 3;
|
||||
if(in_list(["Int", "Percent"], df.fieldtype)) {
|
||||
colspan = 2;
|
||||
} else if(in_list(["Check", "Image"], df.fieldtype)) {
|
||||
colspan = 1;
|
||||
} else if(in_list(["name", "subject", "title"], df.fieldname)) { // subjects are longer
|
||||
colspan = 4;
|
||||
} else if(df.fieldtype=="Text Editor" || df.fieldtype=="Text") {
|
||||
colspan = 4;
|
||||
}
|
||||
if(df.columns && df.columns>0){
|
||||
colspan = df.columns;
|
||||
}
|
||||
else if(this.settings.column_colspan && this.settings.column_colspan[df.fieldname]) {
|
||||
colspan = this.settings.column_colspan[df.fieldname];
|
||||
}
|
||||
this.total_colspans += parseInt(colspan);
|
||||
var col = {
|
||||
colspan: colspan,
|
||||
content: df.fieldname,
|
||||
type: df.fieldtype,
|
||||
df:df,
|
||||
fieldtype: df.fieldtype,
|
||||
fieldname: df.fieldname,
|
||||
title:__(df.label)
|
||||
};
|
||||
if(this.settings.column_render && this.settings.column_render[df.fieldname]) {
|
||||
col.render = this.settings.column_render[df.fieldname];
|
||||
}
|
||||
this.columns.push(col);
|
||||
|
||||
},
|
||||
render: function(row, data) {
|
||||
this.prepare_data(data);
|
||||
|
||||
// maintain id_list to avoid duplication incase
|
||||
// of filtering by child table
|
||||
if(in_list(this.id_list, data.name)) {
|
||||
$(row).toggle(false);
|
||||
return;
|
||||
} else {
|
||||
this.id_list.push(data.name);
|
||||
}
|
||||
|
||||
this['render_row_' + this.doclistview.current_view](row, data);
|
||||
|
||||
if(this.settings.post_render_item) {
|
||||
this.settings.post_render_item(this, row, data);
|
||||
}
|
||||
|
||||
this.render_tags(row, data);
|
||||
|
||||
},
|
||||
render_row_List: function(row, data) {
|
||||
var main = frappe.render_template("list_item_main", {
|
||||
data: data,
|
||||
columns: this.columns,
|
||||
subject: this.get_avatar_and_id(data, true),
|
||||
list: this,
|
||||
right_column: this.settings.right_column
|
||||
});
|
||||
|
||||
$(frappe.render_template("list_item_row", {
|
||||
data: data,
|
||||
main: main,
|
||||
list: this,
|
||||
right_column: this.settings.right_column
|
||||
})).appendTo(row);
|
||||
},
|
||||
render_row_Image: function(row, data) {
|
||||
this.allowed_type = [
|
||||
"Check", "Currency", "Data", "Date",
|
||||
"Datetime", "Float", "Int", "Link",
|
||||
"Percent", "Select", "Read Only", "Time"
|
||||
];
|
||||
var image_url = (data.image && window.cordova && data.image.indexOf('http')===-1) ?
|
||||
frappe.base_url + data[this.image_field] : data[this.image_field];
|
||||
|
||||
img_col = $(frappe.render_template("image_view_item_row", {
|
||||
data: data,
|
||||
list: this,
|
||||
columns: this.columns,
|
||||
allowed_type: this.allowed_type,
|
||||
item_image: image_url ? "url('" + image_url + "')" : null,
|
||||
color: frappe.get_palette(data.item_name),
|
||||
subject: this.get_avatar_and_id(data, true),
|
||||
right_column: this.settings.right_column
|
||||
}))
|
||||
.data("data", data)
|
||||
.appendTo($(row).find(".image-view-marker"));
|
||||
},
|
||||
render_tags: function(row, data) {
|
||||
var me = this;
|
||||
var row2 = $('<div class="tag-row">\
|
||||
<div class="list-tag xs-hidden"></div>\
|
||||
<div class="clearfix"></div>\
|
||||
</div>').appendTo(row);
|
||||
|
||||
if(!me.doclistview.tags_shown) {
|
||||
row2.addClass("hide");
|
||||
}
|
||||
|
||||
// add tags
|
||||
var tag_editor = new frappe.ui.TagEditor({
|
||||
parent: row2.find(".list-tag"),
|
||||
frm: {
|
||||
doctype: this.doctype,
|
||||
docname: data.name
|
||||
},
|
||||
list_sidebar: me.doclistview.list_sidebar,
|
||||
user_tags: data._user_tags,
|
||||
on_change: function(user_tags) {
|
||||
data._user_tags = user_tags;
|
||||
//me.render_timestamp_and_comments(row, data);
|
||||
}
|
||||
});
|
||||
tag_editor.wrapper.on("click", ".tagit-label", function() {
|
||||
me.doclistview.set_filter("_user_tags",
|
||||
$(this).text());
|
||||
});
|
||||
},
|
||||
|
||||
get_avatar_and_id: function(data, without_workflow) {
|
||||
data._without_workflow = without_workflow;
|
||||
data.css_seen = '';
|
||||
|
||||
if(data._seen) {
|
||||
var seen = JSON.parse(data._seen);
|
||||
if(seen && seen.indexOf(frappe.session.user) !== -1) {
|
||||
data.css_seen = 'seen'
|
||||
}
|
||||
}
|
||||
|
||||
return frappe.render_template("list_item_subject", data);
|
||||
},
|
||||
|
||||
get_indicator: function(doc) {
|
||||
var indicator = frappe.get_indicator(doc, this.doctype);
|
||||
if(indicator) {
|
||||
return '<span class="indicator '+indicator[1]+' filterable" data-filter="'
|
||||
+indicator[2]+'">'+__(indicator[0])+'<span>';
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
|
||||
get_indicator_dot: function(doc) {
|
||||
var indicator = frappe.get_indicator(doc, this.doctype);
|
||||
if (!indicator) {
|
||||
return "";
|
||||
}
|
||||
return '<span class="indicator '+indicator[1]+'" title="'+__(indicator[0])+'"></span>';
|
||||
},
|
||||
|
||||
prepare_data: function(data) {
|
||||
if(data.modified)
|
||||
this.prepare_when(data, data.modified);
|
||||
|
||||
data._liked_by = data._liked_by ?
|
||||
JSON.parse(data._liked_by) : [];
|
||||
|
||||
data._checkbox = (frappe.model.can_delete(this.doctype) || this.settings.selectable) && !this.no_delete
|
||||
|
||||
data._doctype_encoded = encodeURIComponent(data.doctype);
|
||||
data._name = data.name.replace(/"/g, '\"');
|
||||
data._name_encoded = encodeURIComponent(data.name);
|
||||
data._submittable = frappe.model.is_submittable(this.doctype);
|
||||
|
||||
data._title = strip_html(data[this.title_field || "name"] || data["name"]);
|
||||
data._full_title = data._title;
|
||||
|
||||
if(data._title.length > 40) {
|
||||
data._title = data._title.slice(0, 40) + "...";
|
||||
}
|
||||
|
||||
data._workflow = null;
|
||||
if(this.workflow_state_fieldname) {
|
||||
data._workflow = {
|
||||
fieldname: this.workflow_state_fieldname,
|
||||
value: data[this.workflow_state_fieldname],
|
||||
style: frappe.utils.guess_style(data[this.workflow_state_fieldname])
|
||||
}
|
||||
}
|
||||
data._user = user;
|
||||
|
||||
data._tags = $.map((data._user_tags || "").split(","),
|
||||
function(v) { return v ? v : null; });
|
||||
data._assign_list = data._assign ? JSON.parse(data._assign) : [];
|
||||
|
||||
// nulls as strings
|
||||
for(key in data) {
|
||||
if(data[key]==null) {
|
||||
data[key]='';
|
||||
}
|
||||
}
|
||||
|
||||
// prepare data in settings
|
||||
if(this.settings.prepare_data)
|
||||
this.settings.prepare_data(data);
|
||||
},
|
||||
|
||||
prepare_when: function(data, date_str) {
|
||||
if (!date_str) date_str = data.modified;
|
||||
// when
|
||||
data.when = (dateutil.str_to_user(date_str)).split(' ')[0];
|
||||
var diff = dateutil.get_diff(dateutil.get_today(), date_str.split(' ')[0]);
|
||||
if(diff==0) {
|
||||
data.when = comment_when(date_str);
|
||||
}
|
||||
if(diff == 1) {
|
||||
data.when = __('Yesterday')
|
||||
}
|
||||
if(diff == 2) {
|
||||
data.when = __('2 days ago')
|
||||
}
|
||||
},
|
||||
|
||||
render_bar_graph: function(parent, data, field, label) {
|
||||
var args = {
|
||||
percent: data[field],
|
||||
label: __(label)
|
||||
}
|
||||
$(parent).append(repl('<span class="progress" style="width: 100%; float: left; margin: 5px 0px;"> \
|
||||
<span class="progress-bar" title="%(percent)s% %(label)s" \
|
||||
style="width: %(percent)s%;"></span>\
|
||||
</span>', args));
|
||||
},
|
||||
render_icon: function(parent, icon_class, label) {
|
||||
var icon_html = "<i class='%(icon_class)s' title='%(label)s'></i>";
|
||||
$(parent).append(repl(icon_html, {icon_class: icon_class, label: __(label) || ''}));
|
||||
}
|
||||
});
|
||||
|
|
@ -185,20 +185,21 @@ frappe.utils = {
|
|||
me.intro_area = null;
|
||||
}
|
||||
},
|
||||
set_footnote: function(me, wrapper, txt) {
|
||||
if(!me.footnote_area) {
|
||||
me.footnote_area = $('<div class="text-muted footnote-area">')
|
||||
set_footnote: function(footnote_area, wrapper, txt) {
|
||||
if(!footnote_area) {
|
||||
footnote_area = $('<div class="text-muted footnote-area">')
|
||||
.appendTo(wrapper);
|
||||
}
|
||||
|
||||
if(txt) {
|
||||
if(txt.search(/<p>/)==-1) txt = '<p>' + txt + '</p>';
|
||||
me.footnote_area.html(txt);
|
||||
if(!txt.includes('<p>'))
|
||||
txt = '<p>' + txt + '</p>';
|
||||
footnote_area.html(txt);
|
||||
} else {
|
||||
me.footnote_area.remove();
|
||||
me.footnote_area = null;
|
||||
footnote_area.remove();
|
||||
footnote_area = null;
|
||||
}
|
||||
return me.footnote_area;
|
||||
return footnote_area;
|
||||
},
|
||||
get_args_dict_from_url: function(txt) {
|
||||
var args = {};
|
||||
|
|
@ -593,3 +594,56 @@ frappe.utils = {
|
|||
return email_list;
|
||||
}
|
||||
};
|
||||
|
||||
// String.prototype.includes polyfill
|
||||
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/includes
|
||||
if (!String.prototype.includes) {
|
||||
String.prototype.includes = function(search, start) {
|
||||
'use strict';
|
||||
if (typeof start !== 'number') {
|
||||
start = 0;
|
||||
}
|
||||
if (start + search.length > this.length) {
|
||||
return false;
|
||||
} else {
|
||||
return this.indexOf(search, start) !== -1;
|
||||
}
|
||||
};
|
||||
}
|
||||
// Array.prototype.includes polyfill
|
||||
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
|
||||
if (!Array.prototype.includes) {
|
||||
Object.defineProperty(Array.prototype, 'includes', {
|
||||
value: function(searchElement, fromIndex) {
|
||||
if (this == null) {
|
||||
throw new TypeError('"this" is null or not defined');
|
||||
}
|
||||
var o = Object(this);
|
||||
var len = o.length >>> 0;
|
||||
if (len === 0) {
|
||||
return false;
|
||||
}
|
||||
var n = fromIndex | 0;
|
||||
var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
|
||||
while (k < len) {
|
||||
if (o[k] === searchElement) {
|
||||
return true;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
// Array de duplicate
|
||||
if (!Array.prototype.uniqBy) {
|
||||
Object.defineProperty(Array.prototype, 'uniqBy', {
|
||||
value: function (key) {
|
||||
var seen = {};
|
||||
return this.filter(function (item) {
|
||||
var k = key(item);
|
||||
return seen.hasOwnProperty(k) ? false : (seen[k] = true);
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ $.extend(frappe.model, {
|
|||
|
||||
new_names: {},
|
||||
events: {},
|
||||
list_settings: {},
|
||||
user_settings: {},
|
||||
|
||||
init: function() {
|
||||
// setup refresh if the document is updated somewhere else
|
||||
|
|
@ -105,7 +105,6 @@ $.extend(frappe.model, {
|
|||
if(r.exc) {
|
||||
msgprint(__("Unable to load: {0}", [__(doctype)]));
|
||||
throw "No doctype";
|
||||
return;
|
||||
}
|
||||
if(r.message=="use_cache") {
|
||||
frappe.model.sync(cached_doc);
|
||||
|
|
@ -115,10 +114,10 @@ $.extend(frappe.model, {
|
|||
frappe.model.init_doctype(doctype);
|
||||
frappe.defaults.set_user_permissions(r.user_permissions);
|
||||
|
||||
if(r.list_settings) {
|
||||
if(r.user_settings) {
|
||||
// remember filters and other settings from last view
|
||||
frappe.model.list_settings[doctype] = JSON.parse(r.list_settings);
|
||||
frappe.model.list_settings[doctype].updated_on = moment().toString();
|
||||
frappe.model.user_settings[doctype] = JSON.parse(r.user_settings);
|
||||
frappe.model.user_settings[doctype].updated_on = moment().toString();
|
||||
}
|
||||
callback && callback(r);
|
||||
}
|
||||
|
|
|
|||
41
frappe/public/js/frappe/model/user_settings.js
Normal file
41
frappe/public/js/frappe/model/user_settings.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
frappe.provide('frappe.model.user_settings');
|
||||
|
||||
$.extend(frappe.model.user_settings, {
|
||||
save: function(doctype, key, value) {
|
||||
var user_settings = frappe.model.user_settings[doctype] || {};
|
||||
|
||||
if ($.isPlainObject(value)) {
|
||||
$.extend(user_settings[key], value);
|
||||
} else {
|
||||
user_settings[key] = value;
|
||||
}
|
||||
|
||||
return this.update(doctype, user_settings);
|
||||
},
|
||||
remove: function(doctype, key) {
|
||||
var user_settings = frappe.model.user_settings[doctype] || {};
|
||||
delete user_settings[key];
|
||||
|
||||
return this.update(doctype, user_settings);
|
||||
},
|
||||
update: function(doctype, user_settings) {
|
||||
return frappe.call({
|
||||
method: 'frappe.model.utils.user_settings.save',
|
||||
args: {
|
||||
doctype: doctype,
|
||||
user_settings: user_settings
|
||||
},
|
||||
callback: function(r) {
|
||||
frappe.model.user_settings[doctype] = r.message;
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
frappe.get_user_settings = function(doctype, key) {
|
||||
var settings = frappe.model.user_settings[doctype] || {};
|
||||
if(key) {
|
||||
settings = settings[key] || {};
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
|
@ -124,7 +124,8 @@ frappe.set_route = function() {
|
|||
frappe.route_options = a;
|
||||
return null;
|
||||
} else {
|
||||
return a ? encodeURIComponent(a) : null;
|
||||
return a;
|
||||
// return a ? encodeURIComponent(a) : null;
|
||||
}
|
||||
}).join('/');
|
||||
|
||||
|
|
|
|||
434
frappe/public/js/frappe/ui/base_list.js
Normal file
434
frappe/public/js/frappe/ui/base_list.js
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// MIT License. See license.txt
|
||||
|
||||
// new re-re-factored Listing object
|
||||
// now called BaseList
|
||||
//
|
||||
// opts:
|
||||
// parent
|
||||
|
||||
// method (method to call on server)
|
||||
// args (additional args to method)
|
||||
// get_args (method to return args as dict)
|
||||
|
||||
// show_filters [false]
|
||||
// doctype
|
||||
// filter_fields (if given, this list is rendered, else built from doctype)
|
||||
|
||||
// query or get_query (will be deprecated)
|
||||
// query_max
|
||||
// buttons_in_frame
|
||||
|
||||
// no_result_message ("No result")
|
||||
|
||||
// page_length (20)
|
||||
// hide_refresh (False)
|
||||
// no_toolbar
|
||||
// new_doctype
|
||||
// [function] render_row(parent, data)
|
||||
// [function] onrun
|
||||
// no_loading (no ajax indicator)
|
||||
|
||||
frappe.provide('frappe.ui');
|
||||
|
||||
frappe.ui.BaseList = Class.extend({
|
||||
init: function (opts) {
|
||||
this.opts = opts || {};
|
||||
this.set_defaults();
|
||||
if (opts) {
|
||||
this.make();
|
||||
}
|
||||
},
|
||||
set_defaults: function () {
|
||||
this.page_length = 20;
|
||||
this.start = 0;
|
||||
this.data = [];
|
||||
},
|
||||
make: function (opts) {
|
||||
if (opts) {
|
||||
this.opts = opts;
|
||||
}
|
||||
this.prepare_opts();
|
||||
|
||||
$.extend(this, this.opts);
|
||||
|
||||
// make dom
|
||||
this.wrapper = $(frappe.render_template('listing', this.opts));
|
||||
this.parent.append(this.wrapper);
|
||||
|
||||
this.set_events();
|
||||
|
||||
if (this.page) {
|
||||
this.wrapper.find('.list-toolbar-wrapper').hide();
|
||||
}
|
||||
|
||||
if (this.show_filters) {
|
||||
this.make_filters();
|
||||
}
|
||||
},
|
||||
prepare_opts: function () {
|
||||
if (this.opts.new_doctype) {
|
||||
if (!frappe.boot.user.can_create.includes(this.opts.new_doctype)) {
|
||||
this.opts.new_doctype = null;
|
||||
}
|
||||
}
|
||||
if (!this.opts.no_result_message) {
|
||||
this.opts.no_result_message = __('Nothing to show');
|
||||
}
|
||||
if (!this.opts.page_length) {
|
||||
this.opts.page_length = this.user_settings && this.user_settings.limit || 20;
|
||||
}
|
||||
this.opts._more = __('More');
|
||||
},
|
||||
add_button: function (label, click, icon) {
|
||||
if (this.page) {
|
||||
return this.page.add_menu_item(label, click, icon)
|
||||
} else {
|
||||
this.wrapper.find('.list-toolbar-wrapper').removeClass('hide');
|
||||
return $('<button class="btn btn-default"></button>')
|
||||
.appendTo(this.wrapper.find('.list-toolbar'))
|
||||
.html((icon ? ('<i class="' + icon + '"></i> ') : '') + label)
|
||||
.click(click);
|
||||
}
|
||||
},
|
||||
set_events: function () {
|
||||
var me = this;
|
||||
|
||||
// next page
|
||||
this.wrapper.find('.btn-more').click(function () {
|
||||
me.run(true);
|
||||
});
|
||||
|
||||
this.wrapper.find(".btn-group-paging").on('click', '.btn', function () {
|
||||
me.page_length = cint($(this).attr("data-value"));
|
||||
|
||||
me.wrapper.find(".btn-group-paging .btn-info").removeClass("btn-info");
|
||||
$(this).addClass("btn-info");
|
||||
|
||||
// always reset when changing list page length
|
||||
me.run();
|
||||
});
|
||||
|
||||
// select the correct page length
|
||||
if (this.opts.page_length !== 20) {
|
||||
this.wrapper.find(".btn-group-paging .btn-info").removeClass("btn-info");
|
||||
this.wrapper
|
||||
.find(".btn-group-paging .btn[data-value='" + this.opts.page_length + "']")
|
||||
.addClass('btn-info');
|
||||
}
|
||||
|
||||
// title
|
||||
if (this.title) {
|
||||
this.wrapper.find('h3').html(this.title).show();
|
||||
}
|
||||
|
||||
// new
|
||||
this.set_primary_action();
|
||||
|
||||
if (me.no_toolbar || me.hide_toolbar) {
|
||||
me.wrapper.find('.list-toolbar-wrapper').hide();
|
||||
}
|
||||
},
|
||||
|
||||
set_primary_action: function () {
|
||||
var me = this;
|
||||
if (this.new_doctype) {
|
||||
this.page.set_primary_action(
|
||||
__("New"),
|
||||
me.make_new_doc.bind(me, me.new_doctype),
|
||||
"octicon octicon-plus"
|
||||
);
|
||||
} else {
|
||||
this.page.clear_primary_action();
|
||||
}
|
||||
},
|
||||
|
||||
make_new_doc: function (doctype) {
|
||||
var me = this;
|
||||
frappe.model.with_doctype(doctype, function () {
|
||||
if (me.custom_new_doc) {
|
||||
me.custom_new_doc(doctype);
|
||||
} else {
|
||||
if (me.filter_list) {
|
||||
frappe.route_options = {};
|
||||
me.filter_list.get_filters().forEach(function (f, i) {
|
||||
if (f[2] === "=" && !frappe.model.std_fields_list.includes(f[1])) {
|
||||
frappe.route_options[f[1]] = f[3];
|
||||
}
|
||||
});
|
||||
}
|
||||
frappe.new_doc(doctype, true);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
make_filters: function () {
|
||||
this.filter_list = new frappe.ui.FilterList({
|
||||
base_list: this,
|
||||
parent: this.wrapper.find('.list-filters').show(),
|
||||
doctype: this.doctype,
|
||||
filter_fields: this.filter_fields,
|
||||
default_filters: this.default_filters || []
|
||||
});
|
||||
// default filter for submittable doctype
|
||||
if (frappe.model.is_submittable(this.doctype)) {
|
||||
this.filter_list.add_filter(this.doctype, "docstatus", "!=", 2);
|
||||
};
|
||||
},
|
||||
|
||||
clear: function () {
|
||||
this.data = [];
|
||||
this.wrapper.find('.result-list').empty();
|
||||
this.wrapper.find('.result').show();
|
||||
this.wrapper.find('.no-result').hide();
|
||||
this.start = 0;
|
||||
this.onreset && this.onreset();
|
||||
},
|
||||
|
||||
set_filters_from_route_options: function () {
|
||||
var me = this;
|
||||
this.filter_list.clear_filters();
|
||||
|
||||
for(var field in frappe.route_options) {
|
||||
var value = frappe.route_options[field];
|
||||
var doctype = null;
|
||||
|
||||
// if `Child DocType.fieldname`
|
||||
if (field.includes(".")) {
|
||||
doctype = field.split(".")[0];
|
||||
field = field.split(".")[1];
|
||||
}
|
||||
|
||||
// find the table in which the key exists
|
||||
// for example the filter could be {"item_code": "X"}
|
||||
// where item_code is in the child table.
|
||||
|
||||
// we can search all tables for mapping the doctype
|
||||
if (!doctype) {
|
||||
doctype = frappe.meta.get_doctype_for_field(me.doctype, field);
|
||||
}
|
||||
|
||||
if (doctype) {
|
||||
if ($.isArray(value)) {
|
||||
me.filter_list.add_filter(doctype, field, value[0], value[1]);
|
||||
} else {
|
||||
me.filter_list.add_filter(doctype, field, "=", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
frappe.route_options = null;
|
||||
},
|
||||
|
||||
run: function (more) {
|
||||
var me = this;
|
||||
if (!more) {
|
||||
this.start = 0;
|
||||
this.onreset && this.onreset();
|
||||
}
|
||||
|
||||
var args = this.get_call_args();
|
||||
this.save_user_settings_locally(args);
|
||||
|
||||
// user_settings are saved by db_query.py when dirty
|
||||
$.extend(args, {
|
||||
user_settings: frappe.model.user_settings[this.doctype]
|
||||
});
|
||||
|
||||
return frappe.call({
|
||||
method: this.opts.method || 'frappe.desk.query_builder.runquery',
|
||||
type: "GET",
|
||||
freeze: this.opts.freeze !== undefined ? this.opts.freeze : true,
|
||||
args: args,
|
||||
callback: function (r) {
|
||||
me.dirty = false;
|
||||
me.render_results(r);
|
||||
},
|
||||
no_spinner: this.opts.no_loading
|
||||
});
|
||||
},
|
||||
save_user_settings_locally: function (args) {
|
||||
if (this.opts.save_user_settings && this.doctype && !this.docname) {
|
||||
// save list settings locally
|
||||
var user_settings = frappe.model.user_settings[this.doctype];
|
||||
var different = false;
|
||||
|
||||
if (!user_settings) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!frappe.utils.arrays_equal(args.filters, user_settings.filters)) {
|
||||
// settings are dirty if filters change
|
||||
user_settings.filters = args.filters;
|
||||
different = true;
|
||||
}
|
||||
|
||||
if (user_settings.order_by !== args.order_by) {
|
||||
user_settings.order_by = args.order_by;
|
||||
different = true;
|
||||
}
|
||||
|
||||
if (user_settings.limit !== args.limit_page_length) {
|
||||
user_settings.limit = args.limit_page_length || 20
|
||||
different = true;
|
||||
}
|
||||
|
||||
// save fields in list settings
|
||||
if (args.save_user_settings_fields) {
|
||||
user_settings.fields = args.fields;
|
||||
}
|
||||
|
||||
if (different) {
|
||||
user_settings.updated_on = moment().toString();
|
||||
}
|
||||
}
|
||||
},
|
||||
get_call_args: function () {
|
||||
// load query
|
||||
if (!this.method) {
|
||||
var query = this.get_query && this.get_query() || this.query;
|
||||
query = this.add_limits(query);
|
||||
var args = {
|
||||
query_max: this.query_max,
|
||||
as_dict: 1
|
||||
}
|
||||
args.simple_query = query;
|
||||
} else {
|
||||
var args = {
|
||||
start: this.start,
|
||||
page_length: this.page_length
|
||||
}
|
||||
}
|
||||
|
||||
// append user-defined arguments
|
||||
if (this.args)
|
||||
$.extend(args, this.args)
|
||||
|
||||
if (this.get_args) {
|
||||
$.extend(args, this.get_args());
|
||||
}
|
||||
return args;
|
||||
},
|
||||
render_results: function (r) {
|
||||
if (this.start === 0)
|
||||
this.clear();
|
||||
|
||||
this.wrapper.find('.btn-more, .list-loading').hide();
|
||||
|
||||
var values = [];
|
||||
|
||||
if (r.message) {
|
||||
values = this.get_values_from_response(r.message);
|
||||
}
|
||||
|
||||
if (values.length || !this.show_no_result()) {
|
||||
this.data = this.data.concat(values);
|
||||
this.render_view(values);
|
||||
this.update_paging(values);
|
||||
} else if (this.start === 0) {
|
||||
// show no result message
|
||||
this.wrapper.find('.result').hide();
|
||||
|
||||
var msg = '';
|
||||
var no_result_message = this.no_result_message;
|
||||
if(no_result_message && $.isFunction(no_result_message)) {
|
||||
msg = no_result_message();
|
||||
} else if(typeof no_result_message === 'string') {
|
||||
msg = no_result_message;
|
||||
} else {
|
||||
msg = __('No Results')
|
||||
}
|
||||
|
||||
this.wrapper.find('.no-result').html(msg).show();
|
||||
}
|
||||
|
||||
this.wrapper.find('.list-paging-area')
|
||||
.toggle(values.length || this.start > 0);
|
||||
|
||||
// callbacks
|
||||
if (this.onrun) this.onrun();
|
||||
if (this.callback) this.callback(r);
|
||||
this.wrapper.trigger("render-complete");
|
||||
},
|
||||
|
||||
get_values_from_response: function (data) {
|
||||
// make dictionaries from keys and values
|
||||
if (data.keys && $.isArray(data.keys)) {
|
||||
return frappe.utils.dict(data.keys, data.values);
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
},
|
||||
|
||||
render_view: function (values) {
|
||||
// override this method in derived class
|
||||
},
|
||||
|
||||
update_paging: function (values) {
|
||||
if (values.length >= this.page_length) {
|
||||
this.wrapper.find('.btn-more').show();
|
||||
this.start += this.page_length;
|
||||
}
|
||||
},
|
||||
|
||||
refresh: function () {
|
||||
this.run();
|
||||
},
|
||||
add_limits: function (query) {
|
||||
return query + ' LIMIT ' + this.start + ',' + (this.page_length + 1);
|
||||
},
|
||||
set_filter: function (fieldname, label, no_run, no_duplicate) {
|
||||
var filter = this.filter_list.get_filter(fieldname);
|
||||
if (filter) {
|
||||
var value = cstr(filter.field.get_parsed_value());
|
||||
if (value.includes(label)) {
|
||||
// already set
|
||||
return false
|
||||
|
||||
} else if (no_duplicate) {
|
||||
filter.set_values(this.doctype, fieldname, "=", label);
|
||||
} else {
|
||||
// second filter set for this field
|
||||
if (fieldname == '_user_tags' || fieldname == "_liked_by") {
|
||||
// and for tags
|
||||
this.filter_list.add_filter(this.doctype, fieldname, 'like', '%' + label + '%');
|
||||
} else {
|
||||
// or for rest using "in"
|
||||
filter.set_values(this.doctype, fieldname, 'in', value + ', ' + label);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no filter for this item,
|
||||
// setup one
|
||||
if (['_user_tags', '_comments', '_assign', '_liked_by'].includes(fieldname)) {
|
||||
this.filter_list.add_filter(this.doctype, fieldname, 'like', '%' + label + '%');
|
||||
} else {
|
||||
this.filter_list.add_filter(this.doctype, fieldname, '=', label);
|
||||
}
|
||||
}
|
||||
if (!no_run)
|
||||
this.run();
|
||||
},
|
||||
init_user_settings: function () {
|
||||
this.user_settings = frappe.model.user_settings[this.doctype] || {};
|
||||
},
|
||||
call_for_selected_items: function (method, args) {
|
||||
var me = this;
|
||||
args.names = this.get_checked_items().map(function (item) {
|
||||
return item.name;
|
||||
});
|
||||
|
||||
frappe.call({
|
||||
method: method,
|
||||
args: args,
|
||||
freeze: true,
|
||||
callback: function (r) {
|
||||
if (!r.exc) {
|
||||
if (me.list_header) {
|
||||
me.list_header.find(".list-select-all").prop("checked", false);
|
||||
}
|
||||
me.refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -5,7 +5,7 @@ frappe.ui.FilterList = Class.extend({
|
|||
init: function(opts) {
|
||||
$.extend(this, opts);
|
||||
this.filters = [];
|
||||
this.wrapper = this.$parent;
|
||||
this.wrapper = this.parent;
|
||||
this.stats = [];
|
||||
this.make();
|
||||
this.set_events();
|
||||
|
|
@ -13,6 +13,20 @@ frappe.ui.FilterList = Class.extend({
|
|||
make: function() {
|
||||
var me = this;
|
||||
|
||||
this.wrapper.find('.show_filters').remove();
|
||||
this.wrapper.append(`
|
||||
<div class="show_filters">
|
||||
<div class="set-filters">
|
||||
<button
|
||||
class="btn btn-default btn-xs show-filters text-muted"
|
||||
style="margin-right: 10px;">
|
||||
${__("Show Filters")}
|
||||
</button>
|
||||
<button style="margin-left: -5px;"
|
||||
class="btn btn-default btn-xs new-filter text-muted">
|
||||
<i class="octicon octicon-plus"></i></button>
|
||||
</div>
|
||||
</div>`);
|
||||
$(frappe.render_template("filter_dashboard", {})).appendTo(this.wrapper.find('.show_filters'));
|
||||
|
||||
//show filter dashboard
|
||||
|
|
@ -85,7 +99,7 @@ frappe.ui.FilterList = Class.extend({
|
|||
args: {
|
||||
stats: me.stats,
|
||||
doctype: me.doctype,
|
||||
filters:me.default_filters
|
||||
filters: me.default_filters
|
||||
},
|
||||
callback: function(r) {
|
||||
// This gives a predictable stats order
|
||||
|
|
@ -163,9 +177,9 @@ frappe.ui.FilterList = Class.extend({
|
|||
var noduplicate = true
|
||||
}
|
||||
if (label=="No Data"){
|
||||
me.listobj.set_filter(fieldname, '', false, noduplicate);
|
||||
me.base_list.set_filter(fieldname, '', false, noduplicate);
|
||||
}else{
|
||||
me.listobj.set_filter(fieldname, label, false, noduplicate);
|
||||
me.base_list.set_filter(fieldname, label, false, noduplicate);
|
||||
}
|
||||
return false;
|
||||
})
|
||||
|
|
@ -205,9 +219,9 @@ frappe.ui.FilterList = Class.extend({
|
|||
var noduplicate = true
|
||||
}
|
||||
if (item.label == "No Data") {
|
||||
me.listobj.set_filter(item.value, '', false, noduplicate);
|
||||
me.base_list.set_filter(item.value, '', false, noduplicate);
|
||||
} else {
|
||||
me.listobj.set_filter(item.value, item.label, false, noduplicate);
|
||||
me.base_list.set_filter(item.value, item.label, false, noduplicate);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -222,8 +236,8 @@ frappe.ui.FilterList = Class.extend({
|
|||
|
||||
this.wrapper.find('.clear-filters').bind('click', function() {
|
||||
me.clear_filters();
|
||||
$('.date-range-picker').val('');
|
||||
me.listobj.run();
|
||||
$('.date-range-picker').val('')
|
||||
me.base_list.run();
|
||||
$(this).addClass("hide");
|
||||
});
|
||||
|
||||
|
|
@ -247,8 +261,7 @@ frappe.ui.FilterList = Class.extend({
|
|||
df: {
|
||||
fieldtype: "Check",
|
||||
fieldname: "is_date_range",
|
||||
label: __("Date Range"),
|
||||
input_css: { "margin-top": "-2px" }
|
||||
label: __("Date Range")
|
||||
}
|
||||
});
|
||||
check.change = function() {
|
||||
|
|
@ -283,11 +296,11 @@ frappe.ui.FilterList = Class.extend({
|
|||
filt && filt.remove(true);
|
||||
if(!dateObj.length && dateObj && date.datepicker.opts.range===false) {
|
||||
me.add_filter(me.doctype, name, '=', moment(dateObj).format('YYYY-MM-DD'));
|
||||
me.listobj.run();
|
||||
me.base_list.run();
|
||||
} else if(dateObj.length===2 && date.datepicker.opts.range===true) {
|
||||
me.add_filter(me.doctype, name, 'Between',
|
||||
[moment(dateObj[0]).format('YYYY-MM-DD'), moment(dateObj[1]).format('YYYY-MM-DD')]);
|
||||
me.listobj.run();
|
||||
me.base_list.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -444,7 +457,7 @@ frappe.ui.Filter = Class.extend({
|
|||
|
||||
this.wrapper.find(".set-filter-and-run").on("click", function() {
|
||||
me.wrapper.removeClass("is-new-filter");
|
||||
me.flist.listobj.run();
|
||||
me.flist.base_list.run();
|
||||
});
|
||||
|
||||
// add help for "in" codition
|
||||
|
|
@ -482,9 +495,8 @@ frappe.ui.Filter = Class.extend({
|
|||
this.flist.update_filters();
|
||||
|
||||
if(!dont_run) {
|
||||
this.flist.listobj.dirty = true;
|
||||
this.flist.listobj.clean_dash = true;
|
||||
this.flist.listobj.refresh();
|
||||
this.flist.base_list.clean_dash = true;
|
||||
this.flist.base_list.refresh(true);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -559,7 +571,7 @@ frappe.ui.Filter = Class.extend({
|
|||
// run on enter
|
||||
$(me.field.wrapper).find(':input').keydown(function(ev) {
|
||||
if(ev.which==13) {
|
||||
me.flist.listobj.run();
|
||||
me.flist.base_list.run();
|
||||
}
|
||||
})
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,18 +1,5 @@
|
|||
<div class="frappe-list">
|
||||
<div class="list-filters" style="display: none;">
|
||||
<div class="show_filters">
|
||||
<div class="set-filters">
|
||||
<button class="btn btn-default btn-xs show-filters text-muted"
|
||||
style="margin-right: 10px;">
|
||||
{{ __("Show Filters") }}</button>
|
||||
<button style="margin-left: -5px;"
|
||||
class="btn btn-default btn-xs new-filter text-muted">
|
||||
<i class="octicon octicon-plus"></i></button>
|
||||
<button class="btn btn-default btn-xs clear-filters text-muted hide"
|
||||
style="margin-left: 5px;">
|
||||
{{ __("Clear Filters") }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom:9px" class="list-toolbar-wrapper hide">
|
||||
|
|
|
|||
|
|
@ -224,6 +224,11 @@ frappe.ui.Listing = Class.extend({
|
|||
var args = this.get_call_args();
|
||||
this.save_list_settings_locally(args);
|
||||
|
||||
// list_settings are saved by db_query.py when dirty
|
||||
$.extend(args, {
|
||||
list_settings: frappe.model.list_settings[this.doctype]
|
||||
});
|
||||
|
||||
return frappe.call({
|
||||
method: this.opts.method || 'frappe.desk.query_builder.runquery',
|
||||
type: "GET",
|
||||
|
|
@ -251,7 +256,7 @@ frappe.ui.Listing = Class.extend({
|
|||
|
||||
if(!frappe.utils.arrays_equal(args.filters, list_settings.filters)) {
|
||||
//dont save filters in Kanban view
|
||||
if(!frappe.get_route()[2]==="Kanban") {
|
||||
if(this.current_view!=="Kanban") {
|
||||
// settings are dirty if filters change
|
||||
list_settings.filters = args.filters || [];
|
||||
different = true;
|
||||
|
|
@ -271,7 +276,7 @@ frappe.ui.Listing = Class.extend({
|
|||
// save fields in list settings
|
||||
if(args.save_list_settings_fields) {
|
||||
list_settings.fields = args.fields;
|
||||
};
|
||||
}
|
||||
|
||||
if(different) {
|
||||
list_settings.updated_on = moment().toString();
|
||||
|
|
@ -318,9 +323,10 @@ frappe.ui.Listing = Class.extend({
|
|||
r.values = this.get_values_from_response(r.message);
|
||||
}
|
||||
|
||||
if(r.values.length) {
|
||||
if(r.values.length || this.force_render_view) {
|
||||
this.data = this.data.concat(r.values);
|
||||
this.render_list(r.values);
|
||||
this.render_view(r.values);
|
||||
// this.render_list(r.values);
|
||||
this.update_paging(r.values);
|
||||
} else {
|
||||
if(this.start===0) {
|
||||
|
|
@ -355,11 +361,20 @@ frappe.ui.Listing = Class.extend({
|
|||
}
|
||||
},
|
||||
|
||||
render_view: function(values) {
|
||||
this.list_view = new frappe.views.ListView({
|
||||
doctype: this.doctype,
|
||||
values: values,
|
||||
});
|
||||
},
|
||||
|
||||
render_list: function(values) {
|
||||
this.last_page = values;
|
||||
if(this.filter_list) {
|
||||
this.filter_values = this.filter_list.get_filters();
|
||||
}
|
||||
// TODO: where is this used?
|
||||
// this.last_page = values;
|
||||
// if(this.filter_list) {
|
||||
// // and this?
|
||||
// this.filter_values = this.filter_list.get_filters();
|
||||
// }
|
||||
|
||||
this.render_rows(values);
|
||||
},
|
||||
|
|
@ -370,33 +385,6 @@ frappe.ui.Listing = Class.extend({
|
|||
this.render_row(this.add_row(values[i]), values[i], this, i);
|
||||
}
|
||||
},
|
||||
render_image_gallery: function(){
|
||||
var me = this;
|
||||
frappe.require(
|
||||
[
|
||||
"assets/frappe/js/frappe/list/imageview.js",
|
||||
"assets/frappe/js/lib/gallery/js/blueimp-gallery.js",
|
||||
"assets/frappe/js/lib/gallery/css/blueimp-gallery.css",
|
||||
"assets/frappe/js/lib/gallery/js/blueimp-gallery-indicator.js",
|
||||
"assets/frappe/js/lib/gallery/css/blueimp-gallery-indicator.css"
|
||||
], function(){
|
||||
// remove previous gallery container
|
||||
me.wrapper.find(".blueimp-gallery").remove();
|
||||
// append gallery div
|
||||
var gallery = frappe.render_template("blueimp-gallery", {});
|
||||
$(gallery).appendTo(me.wrapper);
|
||||
|
||||
me.wrapper.find(".zoom-view").click(function(event){
|
||||
event.preventDefault();
|
||||
opts = {
|
||||
doctype: me.doctype,
|
||||
docname: $(this).parent().attr('data-name'),
|
||||
container: me.wrapper
|
||||
};
|
||||
new frappe.views.ImageView(opts);
|
||||
});
|
||||
});
|
||||
},
|
||||
update_paging: function(values) {
|
||||
if(values.length >= this.page_length) {
|
||||
this.wrapper.find('.btn-more').toggle(true);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,6 @@ frappe.ui.Page = Class.extend({
|
|||
|
||||
this.page_actions = this.wrapper.find(".page-actions");
|
||||
|
||||
this.checked_items_status = this.page_actions.find(".checked-items-status");
|
||||
this.btn_primary = this.page_actions.find(".primary-action");
|
||||
this.btn_secondary = this.page_actions.find(".btn-secondary");
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ frappe.ui.SortSelector = Class.extend({
|
|||
},
|
||||
make: function() {
|
||||
this.prepare_args();
|
||||
this.parent.find('.sort-selector').remove();
|
||||
this.wrapper = $(frappe.render_template('sort_selector', this.args)).appendTo(this.parent);
|
||||
this.bind_events();
|
||||
},
|
||||
|
|
@ -46,6 +47,26 @@ frappe.ui.SortSelector = Class.extend({
|
|||
if(!this.args) {
|
||||
this.args = {};
|
||||
}
|
||||
|
||||
// args as string
|
||||
if(this.args && typeof this.args === 'string') {
|
||||
var order_by = this.args;
|
||||
this.args = {}
|
||||
|
||||
if (order_by.includes('`.`')) {
|
||||
// scrub table name (separated by dot), like `tabTime Log`.`modified` desc`
|
||||
order_by = order_by.split('.')[1];
|
||||
}
|
||||
|
||||
var parts = order_by.split(' ');
|
||||
if (parts.length === 2) {
|
||||
var fieldname = strip(parts[0], '`');
|
||||
|
||||
this.args.sort_by = fieldname;
|
||||
this.args.sort_order = parts[1];
|
||||
}
|
||||
}
|
||||
|
||||
if(this.args.options) {
|
||||
this.args.options.forEach(function(o) {
|
||||
me.labels[o.fieldname] = o.label;
|
||||
|
|
@ -114,13 +135,8 @@ frappe.ui.SortSelector = Class.extend({
|
|||
_options.push({'fieldname': 'idx'});
|
||||
|
||||
// de-duplicate
|
||||
var added = [];
|
||||
this.args.options = [];
|
||||
_options.forEach(function(o) {
|
||||
if(added.indexOf(o.fieldname)===-1) {
|
||||
me.args.options.push(o);
|
||||
added.push(o.fieldname);
|
||||
}
|
||||
this.args.options = _options.uniqBy(function(obj) {
|
||||
return obj.fieldname;
|
||||
});
|
||||
|
||||
// add missing labels
|
||||
|
|
|
|||
|
|
@ -350,7 +350,7 @@ frappe.search.AwesomeBar = Class.extend({
|
|||
var route = frappe.get_route();
|
||||
if(route[0]==="List" && txt.indexOf(" in") === -1) {
|
||||
// search in title field
|
||||
var meta = frappe.get_meta(frappe.container.page.doclistview.doctype);
|
||||
var meta = frappe.get_meta(frappe.container.page.list_view.doctype);
|
||||
var search_field = meta.title_field || "name";
|
||||
var options = {};
|
||||
options[search_field] = ["like", "%" + txt + "%"];
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ frappe.views.show_open_count_list = function(element) {
|
|||
|
||||
var route = frappe.get_route();
|
||||
if(route[0]==="List" && route[1]===doctype) {
|
||||
frappe.pages["List/" + doctype].doclistview.refresh();
|
||||
frappe.pages["List/" + doctype].list_view.refresh();
|
||||
} else {
|
||||
frappe.set_route("List", doctype);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,35 @@
|
|||
frappe.provide("frappe.views.calendar");
|
||||
frappe.provide("frappe.views.calendars");
|
||||
|
||||
frappe.views.CalendarView = frappe.views.ListRenderer.extend({
|
||||
name: 'Calendar',
|
||||
render_view: function() {
|
||||
var me = this;
|
||||
var options = {
|
||||
doctype: this.doctype,
|
||||
parent: this.wrapper,
|
||||
page: this.list_view.page,
|
||||
filter_vals: this.list_view.filter_list.get_filters()
|
||||
}
|
||||
$.extend(options, frappe.views.calendar[this.doctype]);
|
||||
this.calendar = new frappe.views.Calendar(options);
|
||||
},
|
||||
set_defaults: function() {
|
||||
this._super();
|
||||
this.page_title = this.page_title + ' ' + __('Calendar');
|
||||
this.no_realtime = true;
|
||||
this.show_no_result = false;
|
||||
this.hide_sort_selector = true;
|
||||
},
|
||||
get_header_html: function() {
|
||||
return null;
|
||||
},
|
||||
required_libs: [
|
||||
'assets/frappe/js/lib/fullcalendar/fullcalendar.min.css',
|
||||
'assets/frappe/js/lib/fullcalendar/fullcalendar.min.js'
|
||||
]
|
||||
})
|
||||
|
||||
frappe.views.Calendar = Class.extend({
|
||||
init: function(options) {
|
||||
$.extend(this, options);
|
||||
|
|
@ -14,20 +43,6 @@ frappe.views.Calendar = Class.extend({
|
|||
make_page: function() {
|
||||
var me = this;
|
||||
|
||||
$(this.parent).on("show", function() {
|
||||
me.set_filters_from_route_options();
|
||||
});
|
||||
|
||||
var module = locals.DocType[this.doctype].module;
|
||||
this.page.set_title(__("Calendar") + " - " + __(this.doctype));
|
||||
|
||||
frappe.breadcrumbs.add(module, this.doctype);
|
||||
|
||||
this.page.set_primary_action(__("New"), function() {
|
||||
var doc = frappe.model.get_new_doc(me.doctype);
|
||||
frappe.set_route("Form", me.doctype, doc.name);
|
||||
});
|
||||
|
||||
// add links to other calendars
|
||||
$.each(frappe.boot.calendars, function(i, doctype) {
|
||||
if(frappe.model.can_read(doctype)) {
|
||||
|
|
@ -46,9 +61,9 @@ frappe.views.Calendar = Class.extend({
|
|||
var me = this;
|
||||
this.$wrapper = this.parent;
|
||||
this.$cal = $("<div>").appendTo(this.$wrapper);
|
||||
footnote = frappe.utils.set_footnote(this, this.$wrapper,
|
||||
this.footnote_area = frappe.utils.set_footnote(this.footnote_area, this.$wrapper,
|
||||
__("Select or drag across time slots to create a new event."));
|
||||
footnote.css({"border-top": "0px"});
|
||||
this.footnote_area.css({"border-top": "0px"});
|
||||
|
||||
this.$cal.fullCalendar(this.cal_options);
|
||||
this.set_css();
|
||||
|
|
@ -12,7 +12,7 @@ frappe.views.Container = Class.extend({
|
|||
init: function() {
|
||||
this.container = $('#body_div').get(0);
|
||||
this.page = null; // current page
|
||||
this.pagewidth = $('#body_div').width();
|
||||
this.pagewidth = $(this.container).width();
|
||||
this.pagemargin = 50;
|
||||
|
||||
var me = this;
|
||||
|
|
@ -36,7 +36,7 @@ frappe.views.Container = Class.extend({
|
|||
var page = $('<div class="content page-container"></div>')
|
||||
.attr('id', "page-" + label)
|
||||
.attr("data-page-route", label)
|
||||
.toggle(false)
|
||||
.hide()
|
||||
.appendTo(this.container).get(0);
|
||||
page.label = label;
|
||||
frappe.pages[label] = page;
|
||||
|
|
@ -69,7 +69,7 @@ frappe.views.Container = Class.extend({
|
|||
|
||||
// hide current
|
||||
if(this.page && this.page != page) {
|
||||
$(this.page).toggle(false);
|
||||
$(this.page).hide();
|
||||
$(this.page).trigger('hide');
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ frappe.views.Container = Class.extend({
|
|||
if(!this.page || this.page != page) {
|
||||
this.page = page;
|
||||
// $(this.page).fadeIn(300);
|
||||
$(this.page).toggle(true);
|
||||
$(this.page).show();
|
||||
}
|
||||
|
||||
$(document).trigger("page-change");
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ frappe.views.Factory = Class.extend({
|
|||
show: function() {
|
||||
var page_name = frappe.get_route_str(),
|
||||
me = this;
|
||||
if(frappe.pages[page_name] && page_name.indexOf("Form/")===-1) {
|
||||
if(frappe.pages[page_name] && !page_name.includes("Form/")) {
|
||||
frappe.container.change_to(frappe.pages[page_name]);
|
||||
if(me.on_show) {
|
||||
me.on_show();
|
||||
|
|
|
|||
201
frappe/public/js/frappe/views/gantt/gantt_view.js
Normal file
201
frappe/public/js/frappe/views/gantt/gantt_view.js
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
frappe.provide('frappe.views');
|
||||
|
||||
frappe.views.GanttView = frappe.views.ListRenderer.extend({
|
||||
name: 'Gantt',
|
||||
prepare: function(values) {
|
||||
this.items = values;
|
||||
this.prepare_tasks();
|
||||
this.prepare_dom();
|
||||
},
|
||||
|
||||
render_view: function(values) {
|
||||
var me = this;
|
||||
this.prepare(values);
|
||||
this.render_gantt();
|
||||
},
|
||||
|
||||
set_defaults: function() {
|
||||
this._super();
|
||||
this.no_realtime = true;
|
||||
this.page_title = this.page_title + ' ' + __('Gantt');
|
||||
},
|
||||
|
||||
init_settings: function() {
|
||||
this._super();
|
||||
this.field_map = frappe.views.calendar[this.doctype].field_map;
|
||||
this.order_by = this.order_by || this.field_map.start + ' asc';
|
||||
},
|
||||
|
||||
prepare_dom: function() {
|
||||
this.wrapper.css('overflow', 'auto')
|
||||
.append('<svg class="gantt-container" width="20" height="20"></svg>')
|
||||
},
|
||||
|
||||
render_gantt: function(tasks) {
|
||||
var me = this;
|
||||
this.gantt_view_mode = this.user_settings.gantt_view_mode || 'Day';
|
||||
var field_map = frappe.views.calendar[this.doctype].field_map;
|
||||
|
||||
this.gantt = new Gantt(".gantt-container", this.tasks, {
|
||||
view_mode: this.gantt_view_mode,
|
||||
date_format: "YYYY-MM-DD",
|
||||
on_click: function (task) {
|
||||
frappe.set_route('Form', task.doctype, task.id);
|
||||
},
|
||||
on_date_change: function(task, start, end) {
|
||||
if(!me.can_write()) return;
|
||||
me.update_gantt_task(task, start, end);
|
||||
},
|
||||
on_progress_change: function(task, progress) {
|
||||
if(!me.can_write()) return;
|
||||
var progress_fieldname = 'progress';
|
||||
|
||||
if($.isFunction(field_map.progress)) {
|
||||
progress_fieldname = null;
|
||||
} else if(field_map.progress) {
|
||||
progress_fieldname = field_map.progress;
|
||||
}
|
||||
|
||||
if(progress_fieldname) {
|
||||
frappe.db.set_value(task.doctype, task.id,
|
||||
progress_fieldname, parseInt(progress));
|
||||
}
|
||||
},
|
||||
on_view_change: function(mode) {
|
||||
// save view mode
|
||||
frappe.model.user_settings.save(me.doctype, 'Gantt', {
|
||||
gantt_view_mode: mode
|
||||
});
|
||||
},
|
||||
custom_popup_html: function(task) {
|
||||
var item = me.get_item(task.id);
|
||||
var list_item_subject = frappe.render_template('list_item_subject', item);
|
||||
var html = '<div class="heading">'+
|
||||
list_item_subject +'</div>';
|
||||
|
||||
// custom html in {doctype}_list.js
|
||||
var custom = me.settings.gantt_custom_popup_html;
|
||||
if(custom) {
|
||||
html = custom(item, html);
|
||||
}
|
||||
|
||||
return '<div class="details-container">'+ html +'</div>';
|
||||
}
|
||||
});
|
||||
this.render_dropdown();
|
||||
},
|
||||
|
||||
render_dropdown: function() {
|
||||
var me = this;
|
||||
var view_modes = this.gantt.config.view_modes || [];
|
||||
var dropdown = "<div class='dropdown pull-right'>" +
|
||||
"<a class='text-muted dropdown-toggle' data-toggle='dropdown'>" +
|
||||
"<span class='dropdown-text'>"+__(this.gantt_view_mode)+"</span><i class='caret'></i></a>" +
|
||||
"<ul class='dropdown-menu'></ul>" +
|
||||
"</div>";
|
||||
|
||||
// view modes (for translation) __("Day"), __("Week"), __("Month"),
|
||||
//__("Half Day"), __("Quarter Day")
|
||||
|
||||
var dropdown_list = "";
|
||||
view_modes.forEach(function(view_mode) {
|
||||
dropdown_list += "<li>" +
|
||||
"<a class='option' data-value='" + view_mode + "'>" +
|
||||
__(view_mode) + "</a></li>";
|
||||
});
|
||||
var $dropdown = $(dropdown)
|
||||
$dropdown.find(".dropdown-menu")
|
||||
.append(dropdown_list);
|
||||
me.list_view.$page.find(`.list-row-head[data-list-renderer='Gantt'] .list-row-right`).css("margin-top", 0).html($dropdown)
|
||||
$dropdown.on("click", ".option", function() {
|
||||
var mode = $(this).data('value');
|
||||
me.gantt.change_view_mode(mode);
|
||||
$dropdown.find(".dropdown-text").text(mode);
|
||||
});
|
||||
},
|
||||
|
||||
prepare_tasks: function() {
|
||||
var me = this;
|
||||
var meta = frappe.get_meta(this.doctype);
|
||||
var field_map = frappe.views.calendar[this.doctype].field_map;
|
||||
this.tasks = this.items.map(function(item) {
|
||||
// set progress
|
||||
var progress = 0;
|
||||
if(field_map.progress && $.isFunction(field_map.progress)) {
|
||||
progress = field_map.progress(item);
|
||||
} else if(field_map.progress) {
|
||||
progress = item[field_map.progress]
|
||||
}
|
||||
|
||||
// title
|
||||
if(meta.title_field) {
|
||||
var label = $.format("{0} ({1})", [item[meta.title_field], item.name]);
|
||||
} else {
|
||||
var label = item[field_map.title];
|
||||
}
|
||||
|
||||
return {
|
||||
start: item[field_map.start],
|
||||
end: item[field_map.end],
|
||||
name: label,
|
||||
id: item[field_map.id || 'name'],
|
||||
doctype: me.doctype,
|
||||
progress: progress,
|
||||
dependencies: item.depends_on_tasks || ""
|
||||
};
|
||||
});
|
||||
},
|
||||
get_item: function(name) {
|
||||
return this.items.find(function(item) {
|
||||
return item.name === name;
|
||||
});
|
||||
},
|
||||
update_gantt_task: function(task, start, end) {
|
||||
var me = this;
|
||||
if(me.gantt.updating_task) {
|
||||
setTimeout(me.update_gantt_task.bind(me, task, start, end), 200)
|
||||
return;
|
||||
}
|
||||
me.gantt.updating_task = true;
|
||||
|
||||
var field_map = frappe.views.calendar[this.doctype].field_map;
|
||||
frappe.call({
|
||||
method: 'frappe.desk.gantt.update_task',
|
||||
args: {
|
||||
args: {
|
||||
doctype: task.doctype,
|
||||
name: task.id,
|
||||
start: start.format('YYYY-MM-DD'),
|
||||
end: end.format('YYYY-MM-DD')
|
||||
},
|
||||
field_map: field_map
|
||||
},
|
||||
callback: function() {
|
||||
me.gantt.updating_task = false;
|
||||
show_alert({message:__("Saved"), indicator: 'green'}, 1);
|
||||
}
|
||||
});
|
||||
},
|
||||
get_header_html: function() {
|
||||
return frappe.render_template('list_item_row_head', { main: '', list: this });
|
||||
},
|
||||
refresh: function(values) {
|
||||
this.prepare(values);
|
||||
this.render();
|
||||
},
|
||||
can_write: function() {
|
||||
if(frappe.model.can_write(this.doctype)) {
|
||||
return true;
|
||||
} else {
|
||||
// reset gantt state
|
||||
this.gantt.change_view_mode(this.gantt_view_mode);
|
||||
show_alert({message: __("Not permitted"), indicator: 'red'}, 1);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
set_columns: function() {},
|
||||
required_libs: [
|
||||
"assets/frappe/js/lib/snap.svg-min.js",
|
||||
"assets/frappe/js/lib/frappe-gantt/frappe-gantt.js"
|
||||
]
|
||||
});
|
||||
180
frappe/public/js/frappe/views/image/image_view.js
Normal file
180
frappe/public/js/frappe/views/image/image_view.js
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/**
|
||||
* frappe.views.ImageView
|
||||
*/
|
||||
frappe.provide("frappe.views");
|
||||
|
||||
frappe.views.ImageView = frappe.views.ListRenderer.extend({
|
||||
name: 'Image',
|
||||
render_view: function (values) {
|
||||
this.items = values;
|
||||
this.render_image_view();
|
||||
this.setup_gallery();
|
||||
},
|
||||
set_defaults: function() {
|
||||
this._super();
|
||||
this.page_title = this.page_title + ' ' + __('Images');
|
||||
},
|
||||
render_image_view: function () {
|
||||
var html = this.items.map(this.render_item.bind(this)).join("");
|
||||
this.container = $('<div>')
|
||||
.addClass('image-view-container')
|
||||
.appendTo(this.wrapper);
|
||||
this.container.append(html);
|
||||
},
|
||||
render_item: function (item) {
|
||||
var image_url = this.get_image_url(item);
|
||||
var indicator = this.get_indicator_html(item);
|
||||
return frappe.render_template("image_view_item_row", {
|
||||
data: item,
|
||||
indicator: indicator,
|
||||
additional_columns: this.additional_columns,
|
||||
item_image: image_url,
|
||||
color: frappe.get_palette(item.item_name)
|
||||
});
|
||||
},
|
||||
get_image_url: function (item) {
|
||||
var url;
|
||||
url = item.image ? item.image : item[this.meta.image_field];
|
||||
|
||||
// absolute url for mobile
|
||||
if (window.cordova && !frappe.utils.is_url(url)) {
|
||||
url = frappe.base_url + url;
|
||||
}
|
||||
if (url) {
|
||||
return url
|
||||
// return "url('" + url + "')";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
get_header_html: function () {
|
||||
var main = frappe.render_template('image_view_item_main_head', {
|
||||
columns: this.columns,
|
||||
right_column: this.settings.right_column,
|
||||
_checkbox: ((frappe.model.can_delete(this.doctype) || this.settings.selectable)
|
||||
&& !this.no_delete)
|
||||
});
|
||||
return frappe.render_template('list_item_row_head', { main: main, list: this });
|
||||
},
|
||||
setup_gallery: function() {
|
||||
var me = this;
|
||||
var gallery = new frappe.views.GalleryView({
|
||||
doctype: this.doctype,
|
||||
items: this.items,
|
||||
wrapper: this.container
|
||||
});
|
||||
this.container.on('click', '.btn.zoom-view', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var name = $(this).data().name;
|
||||
gallery.show(name);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
refresh: this.render_view
|
||||
});
|
||||
|
||||
frappe.views.GalleryView = Class.extend({
|
||||
init: function(opts) {
|
||||
$.extend(this, opts);
|
||||
var me = this;
|
||||
|
||||
this.ready = false;
|
||||
this.load_lib(function() {
|
||||
me.prepare();
|
||||
me.ready = true;
|
||||
});
|
||||
},
|
||||
prepare: function() {
|
||||
// keep only one pswp dom element
|
||||
this.pswp_root = $('body > .pswp');
|
||||
if(this.pswp_root.length === 0) {
|
||||
var pswp = frappe.render_template('photoswipe_dom');
|
||||
this.pswp_root = $(pswp).appendTo('body');
|
||||
}
|
||||
},
|
||||
show: function(docname) {
|
||||
var me = this;
|
||||
if(!this.ready) {
|
||||
setTimeout(this.show.bind(this), 200);
|
||||
return;
|
||||
}
|
||||
var items = this.items.map(function(i) {
|
||||
var query = 'img[data-name="'+i.name+'"]';
|
||||
var el = me.wrapper.find(query).get(0);
|
||||
return {
|
||||
src: i.image,
|
||||
msrc: i.image,
|
||||
name: i.name,
|
||||
w: el.naturalWidth,
|
||||
h: el.naturalHeight,
|
||||
el: el
|
||||
}
|
||||
});
|
||||
|
||||
var index;
|
||||
items.map(function(item, i) {
|
||||
if(item.name === docname)
|
||||
index = i;
|
||||
});
|
||||
|
||||
var options = {
|
||||
index: index,
|
||||
getThumbBoundsFn: function(index) {
|
||||
var thumbnail = items[index].el, // find thumbnail
|
||||
pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
|
||||
rect = thumbnail.getBoundingClientRect();
|
||||
|
||||
return {x:rect.left, y:rect.top + pageYScroll, w:rect.width};
|
||||
},
|
||||
history: false,
|
||||
shareEl: false,
|
||||
}
|
||||
var pswp = new PhotoSwipe(
|
||||
this.pswp_root.get(0),
|
||||
PhotoSwipeUI_Default,
|
||||
items,
|
||||
options
|
||||
);
|
||||
pswp.init();
|
||||
},
|
||||
get_image_urls: function() {
|
||||
// not implemented yet
|
||||
return frappe.call({
|
||||
method: "frappe.client.get_list",
|
||||
args: {
|
||||
doctype: "File",
|
||||
order_by: "attached_to_name",
|
||||
fields: [
|
||||
"'image/*' as type", "ifnull(thumbnail_url, file_url) as thumbnail",
|
||||
"concat(attached_to_name, ' - ', file_name) as title", "file_url as src",
|
||||
"attached_to_name as name"
|
||||
],
|
||||
filters: [
|
||||
["File", "attached_to_doctype", "=", this.doctype],
|
||||
["File", "attached_to_name", "in", this.docnames],
|
||||
["File", "is_folder", "!=", 1]
|
||||
]
|
||||
},
|
||||
freeze: true,
|
||||
freeze_message: "Fetching Images.."
|
||||
}).then(function(r) {
|
||||
if (!r.message) {
|
||||
msgprint("No Images found")
|
||||
} else {
|
||||
// filter image files from other
|
||||
var images = r.message.filter(function(image) {
|
||||
return frappe.utils.is_image_file(image.title || image.href);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
load_lib: function(callback) {
|
||||
var asset_dir = 'assets/frappe/js/lib/photoswipe/';
|
||||
frappe.require([
|
||||
asset_dir + 'photoswipe.css',
|
||||
asset_dir + 'default-skin.css',
|
||||
asset_dir + 'photoswipe.js',
|
||||
asset_dir + 'photoswipe-ui-default.js'
|
||||
], callback);
|
||||
}
|
||||
});
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="list-value">
|
||||
{%= frappe.render_template("header_select_all_like_filter", { _checkbox: _checkbox }) %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
44
frappe/public/js/frappe/views/image/image_view_item_row.html
Normal file
44
frappe/public/js/frappe/views/image/image_view_item_row.html
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<div class="image-view-item has-checkbox ellipsis">
|
||||
<div class="image-view-header doclist-row">
|
||||
<div class="list-value">
|
||||
{{ frappe.render_template("list_item_subject", data) }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- Image -->
|
||||
<div class="image-view-body">
|
||||
<a data-name="{{ data.name }}"
|
||||
title="{{ data.name }}"
|
||||
href="#Form/{{ data.doctype }}/{{ data.name }}"
|
||||
>
|
||||
<div class="image-field"
|
||||
data-name="{{ data.name }}"
|
||||
style="
|
||||
{% if (!item_image) { %}
|
||||
background-color: {{ color }};
|
||||
{% } %}
|
||||
border: 0px;"
|
||||
>
|
||||
{% if (!item_image) { %}
|
||||
<span class="placeholder-text">
|
||||
{%= frappe.get_abbr(data._title) %}
|
||||
</span>
|
||||
{% } %}
|
||||
{% if (item_image) { %}
|
||||
<img data-name="{{ data.name }}" src="{{ item_image }}" alt="{{data.title}}">
|
||||
{% } %}
|
||||
<button class="btn btn-default zoom-view" data-name="{{data.name}}">
|
||||
<i class="fa fa-search-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="image-view-footer hide">
|
||||
<div class="row">
|
||||
<div class="col-xs-4">{%= indicator %}</div>
|
||||
<div class="col-xs-8 text-right">
|
||||
<!-- comments count and assigned to section -->
|
||||
{%= frappe.render_template("item_assigned_to_comment_count", { data: data }) %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
69
frappe/public/js/frappe/views/image/photoswipe_dom.html
Normal file
69
frappe/public/js/frappe/views/image/photoswipe_dom.html
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
|
||||
|
||||
<!-- http://photoswipe.com/documentation/getting-started.html -->
|
||||
<!-- Root element of PhotoSwipe. -->
|
||||
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
|
||||
<!-- Background of PhotoSwipe.
|
||||
It's a separate element as animating opacity is faster than rgba(). -->
|
||||
<div class="pswp__bg"></div>
|
||||
|
||||
<!-- Slides wrapper with overflow:hidden. -->
|
||||
<div class="pswp__scroll-wrap">
|
||||
|
||||
<!-- Container that holds slides.
|
||||
PhotoSwipe keeps only 3 of them in the DOM to save memory.
|
||||
Don't modify these 3 pswp__item elements, data is added later on. -->
|
||||
<div class="pswp__container">
|
||||
<div class="pswp__item"></div>
|
||||
<div class="pswp__item"></div>
|
||||
<div class="pswp__item"></div>
|
||||
</div>
|
||||
|
||||
<!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
|
||||
<div class="pswp__ui pswp__ui--hidden">
|
||||
|
||||
<div class="pswp__top-bar">
|
||||
|
||||
<!-- Controls are self-explanatory. Order can be changed. -->
|
||||
|
||||
<div class="pswp__counter"></div>
|
||||
|
||||
<button class="pswp__button pswp__button--close" title="Close (Esc)"></button>
|
||||
|
||||
<button class="pswp__button pswp__button--share" title="Share"></button>
|
||||
|
||||
<button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>
|
||||
|
||||
<button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>
|
||||
|
||||
<!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
|
||||
<!-- element will get class pswp__preloader--active when preloader is running -->
|
||||
<div class="pswp__preloader">
|
||||
<div class="pswp__preloader__icn">
|
||||
<div class="pswp__preloader__cut">
|
||||
<div class="pswp__preloader__donut"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
|
||||
<div class="pswp__share-tooltip"></div>
|
||||
</div>
|
||||
|
||||
<button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
|
||||
</button>
|
||||
|
||||
<button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
|
||||
</button>
|
||||
|
||||
<div class="pswp__caption">
|
||||
<div class="pswp__caption__center"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
1048
frappe/public/js/frappe/views/kanban/kanban_board.js
Normal file
1048
frappe/public/js/frappe/views/kanban/kanban_board.js
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -62,7 +62,7 @@ frappe.views.ReportViewPage = Class.extend({
|
|||
}
|
||||
});
|
||||
|
||||
frappe.views.ReportView = frappe.ui.Listing.extend({
|
||||
frappe.views.ReportView = frappe.ui.BaseList.extend({
|
||||
init: function(opts) {
|
||||
var me = this;
|
||||
$.extend(this, opts);
|
||||
|
|
@ -79,11 +79,11 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
|
|||
this._body = $('<div>').appendTo(this.page.main);
|
||||
this.page_title = __('Report')+ ': ' + __(this.docname ? (this.doctype + ' - ' + this.docname) : this.doctype);
|
||||
this.page.set_title(this.page_title);
|
||||
this.init_list_settings();
|
||||
this.init_user_settings();
|
||||
this.make({
|
||||
page: this.parent.page,
|
||||
method: 'frappe.desk.reportview.get',
|
||||
save_list_settings: true,
|
||||
save_user_settings: true,
|
||||
get_args: this.get_args,
|
||||
parent: this._body,
|
||||
start: 0,
|
||||
|
|
@ -139,8 +139,8 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
|
|||
// pre-select mandatory columns
|
||||
var me = this;
|
||||
var columns = [];
|
||||
if(this.list_settings.fields && !this.docname) {
|
||||
this.list_settings.fields.forEach(function(field) {
|
||||
if(this.user_settings.fields && !this.docname) {
|
||||
this.user_settings.fields.forEach(function(field) {
|
||||
var coldef = me.get_column_info_from_field(field);
|
||||
if(!in_list(['_seen', '_comments', '_user_tags', '_assign', '_liked_by', 'docstatus'], coldef[0])) {
|
||||
columns.push(coldef);
|
||||
|
|
@ -226,21 +226,21 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
|
|||
|
||||
set_route_filters: function(first_load) {
|
||||
var me = this;
|
||||
if(frappe.route_options && !this.list_settings.filters) {
|
||||
if(frappe.route_options && !this.user_settings.filters) {
|
||||
this.set_filters_from_route_options();
|
||||
return true;
|
||||
} else if(this.list_settings
|
||||
&& this.list_settings.filters
|
||||
} else if(this.user_settings
|
||||
&& this.user_settings.filters
|
||||
&& !this.docname
|
||||
&& (this.list_settings.updated_on != this.list_settings_updated_on)) {
|
||||
&& (this.user_settings.updated_on != this.user_settings_updated_on)) {
|
||||
// list settings (previous settings)
|
||||
this.filter_list.clear_filters();
|
||||
$.each(this.list_settings.filters, function(i, f) {
|
||||
$.each(this.user_settings.filters, function(i, f) {
|
||||
me.filter_list.add_filter(f[0], f[1], f[2], f[3]);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
this.list_settings_updated_on = this.list_settings.updated_on;
|
||||
this.user_settings_updated_on = this.user_settings.updated_on;
|
||||
},
|
||||
|
||||
setup_print: function() {
|
||||
|
|
@ -263,7 +263,7 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
|
|||
order_by: this.get_order_by(),
|
||||
add_total_row: this.add_total_row,
|
||||
filters: this.filter_list.get_filters(),
|
||||
save_list_settings_fields: 1,
|
||||
save_user_settings_fields: 1,
|
||||
with_childnames: 1,
|
||||
file_format_type: this.file_format_type
|
||||
}
|
||||
|
|
@ -378,7 +378,7 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
|
|||
},
|
||||
|
||||
// render data
|
||||
render_list: function() {
|
||||
render_view: function() {
|
||||
var me = this;
|
||||
var data = this.get_unique_data(this.column_info);
|
||||
|
||||
|
|
@ -598,7 +598,7 @@ frappe.views.ReportView = frappe.ui.Listing.extend({
|
|||
|
||||
this.page.add_inner_button(__('Show Totals'), function() {
|
||||
me.add_totals_row = 1 - (me.add_totals_row ? me.add_totals_row : 0);
|
||||
me.render_list();
|
||||
me.render_view();
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -887,7 +887,7 @@ _f.Frm.prototype.set_intro = function(txt, append) {
|
|||
}
|
||||
|
||||
_f.Frm.prototype.set_footnote = function(txt) {
|
||||
frappe.utils.set_footnote(this, this.body, txt);
|
||||
this.footnote_area = frappe.utils.set_footnote(this.footnote_area, this.body, txt);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,72 +0,0 @@
|
|||
@charset "UTF-8";
|
||||
/*
|
||||
* blueimp Gallery Indicator CSS
|
||||
* https://github.com/blueimp/Gallery
|
||||
*
|
||||
* Copyright 2013, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
.blueimp-gallery > .indicator {
|
||||
position: absolute;
|
||||
top: auto;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
left: 15px;
|
||||
margin: 0 40px;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
text-align: center;
|
||||
line-height: 10px;
|
||||
display: none;
|
||||
}
|
||||
.blueimp-gallery > .indicator > li {
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 6px 3px 0 3px;
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
border: 1px solid transparent;
|
||||
background: #ccc;
|
||||
background: rgba(255, 255, 255, 0.25) center no-repeat;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 0 2px #000;
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
background-size: 40px 40px;
|
||||
}
|
||||
.blueimp-gallery > .indicator > li:hover,
|
||||
.blueimp-gallery > .indicator > .active {
|
||||
background-color: #fff;
|
||||
border-color: #fff;
|
||||
opacity: 1;
|
||||
}
|
||||
.blueimp-gallery-controls > .indicator {
|
||||
display: block;
|
||||
/* Fix z-index issues (controls behind slide element) on Android: */
|
||||
-webkit-transform: translateZ(0);
|
||||
-moz-transform: translateZ(0);
|
||||
-ms-transform: translateZ(0);
|
||||
-o-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
}
|
||||
.blueimp-gallery-single > .indicator {
|
||||
display: none;
|
||||
}
|
||||
.blueimp-gallery > .indicator {
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* IE7 fixes */
|
||||
*+html .blueimp-gallery > .indicator > li {
|
||||
display: inline;
|
||||
}
|
||||
|
|
@ -1,226 +0,0 @@
|
|||
@charset "UTF-8";
|
||||
/*
|
||||
* blueimp Gallery CSS
|
||||
* https://github.com/blueimp/Gallery
|
||||
*
|
||||
* Copyright 2013, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
.blueimp-gallery,
|
||||
.blueimp-gallery > .slides > .slide > .slide-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
/* Prevent artifacts in Mozilla Firefox: */
|
||||
-moz-backface-visibility: hidden;
|
||||
}
|
||||
.blueimp-gallery > .slides > .slide > .slide-content {
|
||||
margin: auto;
|
||||
width: auto;
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
opacity: 1;
|
||||
}
|
||||
.blueimp-gallery {
|
||||
position: fixed;
|
||||
z-index: 999999;
|
||||
overflow: hidden;
|
||||
background: #000;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
opacity: 0;
|
||||
display: none;
|
||||
direction: ltr;
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.blueimp-gallery-carousel {
|
||||
position: relative;
|
||||
z-index: auto;
|
||||
margin: 1em auto;
|
||||
/* Set the carousel width/height ratio to 16/9: */
|
||||
padding-bottom: 56.25%;
|
||||
box-shadow: 0 0 10px #000;
|
||||
-ms-touch-action: pan-y;
|
||||
touch-action: pan-y;
|
||||
}
|
||||
.blueimp-gallery-display {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
.blueimp-gallery > .slides {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.blueimp-gallery-carousel > .slides {
|
||||
position: absolute;
|
||||
}
|
||||
.blueimp-gallery > .slides > .slide {
|
||||
position: relative;
|
||||
float: left;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
-webkit-transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
-moz-transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
-ms-transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
-o-transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
}
|
||||
.blueimp-gallery,
|
||||
.blueimp-gallery > .slides > .slide > .slide-content {
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
-ms-transition: opacity 0.2s linear;
|
||||
-o-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.blueimp-gallery > .slides > .slide-loading {
|
||||
background: url(../img/loading.gif) center no-repeat;
|
||||
background-size: 64px 64px;
|
||||
}
|
||||
.blueimp-gallery > .slides > .slide-loading > .slide-content {
|
||||
opacity: 0;
|
||||
}
|
||||
.blueimp-gallery > .slides > .slide-error {
|
||||
background: url(../img/error.png) center no-repeat;
|
||||
}
|
||||
.blueimp-gallery > .slides > .slide-error > .slide-content {
|
||||
display: none;
|
||||
}
|
||||
.blueimp-gallery > .prev,
|
||||
.blueimp-gallery > .next {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 15px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-top: -23px;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 60px;
|
||||
font-weight: 100;
|
||||
line-height: 30px;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 0 2px #000;
|
||||
text-align: center;
|
||||
background: #222;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
border: 3px solid #fff;
|
||||
-webkit-border-radius: 23px;
|
||||
-moz-border-radius: 23px;
|
||||
border-radius: 23px;
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
}
|
||||
.blueimp-gallery > .next {
|
||||
left: auto;
|
||||
right: 15px;
|
||||
}
|
||||
.blueimp-gallery > .close,
|
||||
.blueimp-gallery > .title {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
margin: 0 40px 0 0;
|
||||
font-size: 20px;
|
||||
line-height: 30px;
|
||||
color: #fff;
|
||||
text-shadow: 0 0 2px #000;
|
||||
opacity: 0.8;
|
||||
display: none;
|
||||
}
|
||||
.blueimp-gallery > .close {
|
||||
padding: 15px;
|
||||
right: 15px;
|
||||
left: auto;
|
||||
margin: -15px;
|
||||
font-size: 30px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.blueimp-gallery > .play-pause {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
bottom: 15px;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
background: url(../img/play-pause.png) 0 0 no-repeat;
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
display: none;
|
||||
}
|
||||
.blueimp-gallery-playing > .play-pause {
|
||||
background-position: -15px 0;
|
||||
}
|
||||
.blueimp-gallery > .prev:hover,
|
||||
.blueimp-gallery > .next:hover,
|
||||
.blueimp-gallery > .close:hover,
|
||||
.blueimp-gallery > .title:hover,
|
||||
.blueimp-gallery > .play-pause:hover {
|
||||
color: #fff;
|
||||
opacity: 1;
|
||||
}
|
||||
.blueimp-gallery-controls > .prev,
|
||||
.blueimp-gallery-controls > .next,
|
||||
.blueimp-gallery-controls > .close,
|
||||
.blueimp-gallery-controls > .title,
|
||||
.blueimp-gallery-controls > .play-pause {
|
||||
display: block;
|
||||
/* Fix z-index issues (controls behind slide element) on Android: */
|
||||
-webkit-transform: translateZ(0);
|
||||
-moz-transform: translateZ(0);
|
||||
-ms-transform: translateZ(0);
|
||||
-o-transform: translateZ(0);
|
||||
transform: translateZ(0);
|
||||
}
|
||||
.blueimp-gallery-single > .prev,
|
||||
.blueimp-gallery-left > .prev,
|
||||
.blueimp-gallery-single > .next,
|
||||
.blueimp-gallery-right > .next,
|
||||
.blueimp-gallery-single > .play-pause {
|
||||
display: none;
|
||||
}
|
||||
.blueimp-gallery > .slides > .slide > .slide-content,
|
||||
.blueimp-gallery > .prev,
|
||||
.blueimp-gallery > .next,
|
||||
.blueimp-gallery > .close,
|
||||
.blueimp-gallery > .play-pause {
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Replace PNGs with SVGs for capable browsers (excluding IE<9) */
|
||||
body:last-child .blueimp-gallery > .slides > .slide-error {
|
||||
background-image: url(../img/error.svg);
|
||||
}
|
||||
body:last-child .blueimp-gallery > .play-pause {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-size: 40px 20px;
|
||||
background-image: url(../img/play-pause.svg);
|
||||
}
|
||||
body:last-child .blueimp-gallery-playing > .play-pause {
|
||||
background-position: -20px 0;
|
||||
}
|
||||
|
||||
/* IE7 fixes */
|
||||
*+html .blueimp-gallery > .slides > .slide {
|
||||
min-height: 300px;
|
||||
}
|
||||
*+html .blueimp-gallery > .slides > .slide > .slide-content {
|
||||
position: relative;
|
||||
}
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
/*
|
||||
* blueimp Gallery Indicator JS
|
||||
* https://github.com/blueimp/Gallery
|
||||
*
|
||||
* Copyright 2013, Sebastian Tschan
|
||||
* https://blueimp.net
|
||||
*
|
||||
* Licensed under the MIT license:
|
||||
* http://www.opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* global define, window, document */
|
||||
|
||||
;(function (factory) {
|
||||
'use strict'
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// Register as an anonymous AMD module:
|
||||
define([
|
||||
'./blueimp-helper',
|
||||
'./blueimp-gallery'
|
||||
], factory)
|
||||
} else {
|
||||
// Browser globals:
|
||||
factory(
|
||||
window.blueimp.helper || window.jQuery,
|
||||
window.blueimp.Gallery
|
||||
)
|
||||
}
|
||||
}(function ($, Gallery) {
|
||||
'use strict'
|
||||
|
||||
$.extend(Gallery.prototype.options, {
|
||||
// The tag name, Id, element or querySelector of the indicator container:
|
||||
indicatorContainer: 'ol',
|
||||
// The class for the active indicator:
|
||||
activeIndicatorClass: 'active',
|
||||
// The list object property (or data attribute) with the thumbnail URL,
|
||||
// used as alternative to a thumbnail child element:
|
||||
thumbnailProperty: 'thumbnail',
|
||||
// Defines if the gallery indicators should display a thumbnail:
|
||||
thumbnailIndicators: true
|
||||
})
|
||||
|
||||
var initSlides = Gallery.prototype.initSlides
|
||||
var addSlide = Gallery.prototype.addSlide
|
||||
var resetSlides = Gallery.prototype.resetSlides
|
||||
var handleClick = Gallery.prototype.handleClick
|
||||
var handleSlide = Gallery.prototype.handleSlide
|
||||
var handleClose = Gallery.prototype.handleClose
|
||||
|
||||
$.extend(Gallery.prototype, {
|
||||
createIndicator: function (obj) {
|
||||
var indicator = this.indicatorPrototype.cloneNode(false)
|
||||
var title = this.getItemProperty(obj, this.options.titleProperty)
|
||||
var thumbnailProperty = this.options.thumbnailProperty
|
||||
var thumbnailUrl
|
||||
var thumbnail
|
||||
if (this.options.thumbnailIndicators) {
|
||||
if (thumbnailProperty) {
|
||||
thumbnailUrl = this.getItemProperty(obj, thumbnailProperty)
|
||||
}
|
||||
if (thumbnailUrl === undefined) {
|
||||
thumbnail = obj.getElementsByTagName && $(obj).find('img')[0]
|
||||
if (thumbnail) {
|
||||
thumbnailUrl = thumbnail.src
|
||||
}
|
||||
}
|
||||
if (thumbnailUrl) {
|
||||
indicator.style.backgroundImage = 'url("' + thumbnailUrl + '")'
|
||||
}
|
||||
}
|
||||
if (title) {
|
||||
indicator.title = title
|
||||
}
|
||||
return indicator
|
||||
},
|
||||
|
||||
addIndicator: function (index) {
|
||||
if (this.indicatorContainer.length) {
|
||||
var indicator = this.createIndicator(this.list[index])
|
||||
indicator.setAttribute('data-index', index)
|
||||
this.indicatorContainer[0].appendChild(indicator)
|
||||
this.indicators.push(indicator)
|
||||
}
|
||||
},
|
||||
|
||||
setActiveIndicator: function (index) {
|
||||
if (this.indicators) {
|
||||
if (this.activeIndicator) {
|
||||
this.activeIndicator
|
||||
.removeClass(this.options.activeIndicatorClass)
|
||||
}
|
||||
this.activeIndicator = $(this.indicators[index])
|
||||
this.activeIndicator
|
||||
.addClass(this.options.activeIndicatorClass)
|
||||
}
|
||||
},
|
||||
|
||||
initSlides: function (reload) {
|
||||
if (!reload) {
|
||||
this.indicatorContainer = this.container.find(
|
||||
this.options.indicatorContainer
|
||||
)
|
||||
if (this.indicatorContainer.length) {
|
||||
this.indicatorPrototype = document.createElement('li')
|
||||
this.indicators = this.indicatorContainer[0].children
|
||||
}
|
||||
}
|
||||
initSlides.call(this, reload)
|
||||
},
|
||||
|
||||
addSlide: function (index) {
|
||||
addSlide.call(this, index)
|
||||
this.addIndicator(index)
|
||||
},
|
||||
|
||||
resetSlides: function () {
|
||||
resetSlides.call(this)
|
||||
this.indicatorContainer.empty()
|
||||
this.indicators = []
|
||||
},
|
||||
|
||||
handleClick: function (event) {
|
||||
var target = event.target || event.srcElement
|
||||
var parent = target.parentNode
|
||||
if (parent === this.indicatorContainer[0]) {
|
||||
// Click on indicator element
|
||||
this.preventDefault(event)
|
||||
this.slide(this.getNodeIndex(target))
|
||||
} else if (parent.parentNode === this.indicatorContainer[0]) {
|
||||
// Click on indicator child element
|
||||
this.preventDefault(event)
|
||||
this.slide(this.getNodeIndex(parent))
|
||||
} else {
|
||||
return handleClick.call(this, event)
|
||||
}
|
||||
},
|
||||
|
||||
handleSlide: function (index) {
|
||||
handleSlide.call(this, index)
|
||||
this.setActiveIndicator(index)
|
||||
},
|
||||
|
||||
handleClose: function () {
|
||||
if (this.activeIndicator) {
|
||||
this.activeIndicator
|
||||
.removeClass(this.options.activeIndicatorClass)
|
||||
}
|
||||
handleClose.call(this)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return Gallery
|
||||
}))
|
||||
File diff suppressed because it is too large
Load diff
483
frappe/public/js/lib/photoswipe/default-skin.css
Executable file
483
frappe/public/js/lib/photoswipe/default-skin.css
Executable file
|
|
@ -0,0 +1,483 @@
|
|||
/*! PhotoSwipe Default UI CSS by Dmitry Semenov | photoswipe.com | MIT license */
|
||||
/*
|
||||
|
||||
Contents:
|
||||
|
||||
1. Buttons
|
||||
2. Share modal and links
|
||||
3. Index indicator ("1 of X" counter)
|
||||
4. Caption
|
||||
5. Loading indicator
|
||||
6. Additional styles (root element, top bar, idle state, hidden state, etc.)
|
||||
|
||||
*/
|
||||
/*
|
||||
|
||||
1. Buttons
|
||||
|
||||
*/
|
||||
/* <button> css reset */
|
||||
.pswp__button {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
position: relative;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
overflow: visible;
|
||||
-webkit-appearance: none;
|
||||
display: block;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
float: right;
|
||||
opacity: 0.75;
|
||||
-webkit-transition: opacity 0.2s;
|
||||
transition: opacity 0.2s;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none; }
|
||||
.pswp__button:focus,
|
||||
.pswp__button:hover {
|
||||
opacity: 1; }
|
||||
.pswp__button:active {
|
||||
outline: none;
|
||||
opacity: 0.9; }
|
||||
.pswp__button::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border: 0; }
|
||||
|
||||
/* pswp__ui--over-close class it added when mouse is over element that should close gallery */
|
||||
.pswp__ui--over-close .pswp__button--close {
|
||||
opacity: 1; }
|
||||
|
||||
.pswp__button,
|
||||
.pswp__button--arrow--left:before,
|
||||
.pswp__button--arrow--right:before {
|
||||
background: url(default-skin.png) 0 0 no-repeat;
|
||||
background-size: 264px 88px;
|
||||
width: 44px;
|
||||
height: 44px; }
|
||||
|
||||
@media (-webkit-min-device-pixel-ratio: 1.1), (-webkit-min-device-pixel-ratio: 1.09375), (min-resolution: 105dpi), (min-resolution: 1.1dppx) {
|
||||
/* Serve SVG sprite if browser supports SVG and resolution is more than 105dpi */
|
||||
.pswp--svg .pswp__button,
|
||||
.pswp--svg .pswp__button--arrow--left:before,
|
||||
.pswp--svg .pswp__button--arrow--right:before {
|
||||
background-image: url(default-skin.svg); }
|
||||
.pswp--svg .pswp__button--arrow--left,
|
||||
.pswp--svg .pswp__button--arrow--right {
|
||||
background: none; } }
|
||||
|
||||
.pswp__button--close {
|
||||
background-position: 0 -44px; }
|
||||
|
||||
.pswp__button--share {
|
||||
background-position: -44px -44px; }
|
||||
|
||||
.pswp__button--fs {
|
||||
display: none; }
|
||||
|
||||
.pswp--supports-fs .pswp__button--fs {
|
||||
display: block; }
|
||||
|
||||
.pswp--fs .pswp__button--fs {
|
||||
background-position: -44px 0; }
|
||||
|
||||
.pswp__button--zoom {
|
||||
display: none;
|
||||
background-position: -88px 0; }
|
||||
|
||||
.pswp--zoom-allowed .pswp__button--zoom {
|
||||
display: block; }
|
||||
|
||||
.pswp--zoomed-in .pswp__button--zoom {
|
||||
background-position: -132px 0; }
|
||||
|
||||
/* no arrows on touch screens */
|
||||
.pswp--touch .pswp__button--arrow--left,
|
||||
.pswp--touch .pswp__button--arrow--right {
|
||||
visibility: hidden; }
|
||||
|
||||
/*
|
||||
Arrow buttons hit area
|
||||
(icon is added to :before pseudo-element)
|
||||
*/
|
||||
.pswp__button--arrow--left,
|
||||
.pswp__button--arrow--right {
|
||||
background: none;
|
||||
top: 50%;
|
||||
margin-top: -50px;
|
||||
width: 70px;
|
||||
height: 100px;
|
||||
position: absolute; }
|
||||
|
||||
.pswp__button--arrow--left {
|
||||
left: 0; }
|
||||
|
||||
.pswp__button--arrow--right {
|
||||
right: 0; }
|
||||
|
||||
.pswp__button--arrow--left:before,
|
||||
.pswp__button--arrow--right:before {
|
||||
content: '';
|
||||
top: 35px;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
height: 30px;
|
||||
width: 32px;
|
||||
position: absolute; }
|
||||
|
||||
.pswp__button--arrow--left:before {
|
||||
left: 6px;
|
||||
background-position: -138px -44px; }
|
||||
|
||||
.pswp__button--arrow--right:before {
|
||||
right: 6px;
|
||||
background-position: -94px -44px; }
|
||||
|
||||
/*
|
||||
|
||||
2. Share modal/popup and links
|
||||
|
||||
*/
|
||||
.pswp__counter,
|
||||
.pswp__share-modal {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none; }
|
||||
|
||||
.pswp__share-modal {
|
||||
display: block;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
z-index: 1600;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.25s ease-out;
|
||||
transition: opacity 0.25s ease-out;
|
||||
-webkit-backface-visibility: hidden;
|
||||
will-change: opacity; }
|
||||
|
||||
.pswp__share-modal--hidden {
|
||||
display: none; }
|
||||
|
||||
.pswp__share-tooltip {
|
||||
z-index: 1620;
|
||||
position: absolute;
|
||||
background: #FFF;
|
||||
top: 56px;
|
||||
border-radius: 2px;
|
||||
display: block;
|
||||
width: auto;
|
||||
right: 44px;
|
||||
-webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25);
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25);
|
||||
-webkit-transform: translateY(6px);
|
||||
-ms-transform: translateY(6px);
|
||||
transform: translateY(6px);
|
||||
-webkit-transition: -webkit-transform 0.25s;
|
||||
transition: transform 0.25s;
|
||||
-webkit-backface-visibility: hidden;
|
||||
will-change: transform; }
|
||||
.pswp__share-tooltip a {
|
||||
display: block;
|
||||
padding: 8px 12px;
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
line-height: 18px; }
|
||||
.pswp__share-tooltip a:hover {
|
||||
text-decoration: none;
|
||||
color: #000; }
|
||||
.pswp__share-tooltip a:first-child {
|
||||
/* round corners on the first/last list item */
|
||||
border-radius: 2px 2px 0 0; }
|
||||
.pswp__share-tooltip a:last-child {
|
||||
border-radius: 0 0 2px 2px; }
|
||||
|
||||
.pswp__share-modal--fade-in {
|
||||
opacity: 1; }
|
||||
.pswp__share-modal--fade-in .pswp__share-tooltip {
|
||||
-webkit-transform: translateY(0);
|
||||
-ms-transform: translateY(0);
|
||||
transform: translateY(0); }
|
||||
|
||||
/* increase size of share links on touch devices */
|
||||
.pswp--touch .pswp__share-tooltip a {
|
||||
padding: 16px 12px; }
|
||||
|
||||
a.pswp__share--facebook:before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
right: 15px;
|
||||
border: 6px solid transparent;
|
||||
border-bottom-color: #FFF;
|
||||
-webkit-pointer-events: none;
|
||||
-moz-pointer-events: none;
|
||||
pointer-events: none; }
|
||||
|
||||
a.pswp__share--facebook:hover {
|
||||
background: #3E5C9A;
|
||||
color: #FFF; }
|
||||
a.pswp__share--facebook:hover:before {
|
||||
border-bottom-color: #3E5C9A; }
|
||||
|
||||
a.pswp__share--twitter:hover {
|
||||
background: #55ACEE;
|
||||
color: #FFF; }
|
||||
|
||||
a.pswp__share--pinterest:hover {
|
||||
background: #CCC;
|
||||
color: #CE272D; }
|
||||
|
||||
a.pswp__share--download:hover {
|
||||
background: #DDD; }
|
||||
|
||||
/*
|
||||
|
||||
3. Index indicator ("1 of X" counter)
|
||||
|
||||
*/
|
||||
.pswp__counter {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 44px;
|
||||
font-size: 13px;
|
||||
line-height: 44px;
|
||||
color: #FFF;
|
||||
opacity: 0.75;
|
||||
padding: 0 10px; }
|
||||
|
||||
/*
|
||||
|
||||
4. Caption
|
||||
|
||||
*/
|
||||
.pswp__caption {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
min-height: 44px; }
|
||||
.pswp__caption small {
|
||||
font-size: 11px;
|
||||
color: #BBB; }
|
||||
|
||||
.pswp__caption__center {
|
||||
text-align: left;
|
||||
max-width: 420px;
|
||||
margin: 0 auto;
|
||||
font-size: 13px;
|
||||
padding: 10px;
|
||||
line-height: 20px;
|
||||
color: #CCC; }
|
||||
|
||||
.pswp__caption--empty {
|
||||
display: none; }
|
||||
|
||||
/* Fake caption element, used to calculate height of next/prev image */
|
||||
.pswp__caption--fake {
|
||||
visibility: hidden; }
|
||||
|
||||
/*
|
||||
|
||||
5. Loading indicator (preloader)
|
||||
|
||||
You can play with it here - http://codepen.io/dimsemenov/pen/yyBWoR
|
||||
|
||||
*/
|
||||
.pswp__preloader {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
margin-left: -22px;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.25s ease-out;
|
||||
transition: opacity 0.25s ease-out;
|
||||
will-change: opacity;
|
||||
direction: ltr; }
|
||||
|
||||
.pswp__preloader__icn {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 12px; }
|
||||
|
||||
.pswp__preloader--active {
|
||||
opacity: 1; }
|
||||
.pswp__preloader--active .pswp__preloader__icn {
|
||||
/* We use .gif in browsers that don't support CSS animation */
|
||||
background: url(preloader.gif) 0 0 no-repeat; }
|
||||
|
||||
.pswp--css_animation .pswp__preloader--active {
|
||||
opacity: 1; }
|
||||
.pswp--css_animation .pswp__preloader--active .pswp__preloader__icn {
|
||||
-webkit-animation: clockwise 500ms linear infinite;
|
||||
animation: clockwise 500ms linear infinite; }
|
||||
.pswp--css_animation .pswp__preloader--active .pswp__preloader__donut {
|
||||
-webkit-animation: donut-rotate 1000ms cubic-bezier(0.4, 0, 0.22, 1) infinite;
|
||||
animation: donut-rotate 1000ms cubic-bezier(0.4, 0, 0.22, 1) infinite; }
|
||||
|
||||
.pswp--css_animation .pswp__preloader__icn {
|
||||
background: none;
|
||||
opacity: 0.75;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
top: 15px;
|
||||
margin: 0; }
|
||||
|
||||
.pswp--css_animation .pswp__preloader__cut {
|
||||
/*
|
||||
The idea of animating inner circle is based on Polymer ("material") loading indicator
|
||||
by Keanu Lee https://blog.keanulee.com/2014/10/20/the-tale-of-three-spinners.html
|
||||
*/
|
||||
position: relative;
|
||||
width: 7px;
|
||||
height: 14px;
|
||||
overflow: hidden; }
|
||||
|
||||
.pswp--css_animation .pswp__preloader__donut {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: 2px solid #FFF;
|
||||
border-radius: 50%;
|
||||
border-left-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: none;
|
||||
margin: 0; }
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
.pswp__preloader {
|
||||
position: relative;
|
||||
left: auto;
|
||||
top: auto;
|
||||
margin: 0;
|
||||
float: right; } }
|
||||
|
||||
@-webkit-keyframes clockwise {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg); }
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
@keyframes clockwise {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg); }
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
@-webkit-keyframes donut-rotate {
|
||||
0% {
|
||||
-webkit-transform: rotate(0);
|
||||
transform: rotate(0); }
|
||||
50% {
|
||||
-webkit-transform: rotate(-140deg);
|
||||
transform: rotate(-140deg); }
|
||||
100% {
|
||||
-webkit-transform: rotate(0);
|
||||
transform: rotate(0); } }
|
||||
|
||||
@keyframes donut-rotate {
|
||||
0% {
|
||||
-webkit-transform: rotate(0);
|
||||
transform: rotate(0); }
|
||||
50% {
|
||||
-webkit-transform: rotate(-140deg);
|
||||
transform: rotate(-140deg); }
|
||||
100% {
|
||||
-webkit-transform: rotate(0);
|
||||
transform: rotate(0); } }
|
||||
|
||||
/*
|
||||
|
||||
6. Additional styles
|
||||
|
||||
*/
|
||||
/* root element of UI */
|
||||
.pswp__ui {
|
||||
-webkit-font-smoothing: auto;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
z-index: 1550; }
|
||||
|
||||
/* top black bar with buttons and "1 of X" indicator */
|
||||
.pswp__top-bar {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 44px;
|
||||
width: 100%; }
|
||||
|
||||
.pswp__caption,
|
||||
.pswp__top-bar,
|
||||
.pswp--has_mouse .pswp__button--arrow--left,
|
||||
.pswp--has_mouse .pswp__button--arrow--right {
|
||||
-webkit-backface-visibility: hidden;
|
||||
will-change: opacity;
|
||||
-webkit-transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
|
||||
transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); }
|
||||
|
||||
/* pswp--has_mouse class is added only when two subsequent mousemove events occur */
|
||||
.pswp--has_mouse .pswp__button--arrow--left,
|
||||
.pswp--has_mouse .pswp__button--arrow--right {
|
||||
visibility: visible; }
|
||||
|
||||
.pswp__top-bar,
|
||||
.pswp__caption {
|
||||
background-color: rgba(0, 0, 0, 0.5); }
|
||||
|
||||
/* pswp__ui--fit class is added when main image "fits" between top bar and bottom bar (caption) */
|
||||
.pswp__ui--fit .pswp__top-bar,
|
||||
.pswp__ui--fit .pswp__caption {
|
||||
background-color: rgba(0, 0, 0, 0.3); }
|
||||
|
||||
/* pswp__ui--idle class is added when mouse isn't moving for several seconds (JS option timeToIdle) */
|
||||
.pswp__ui--idle .pswp__top-bar {
|
||||
opacity: 0; }
|
||||
|
||||
.pswp__ui--idle .pswp__button--arrow--left,
|
||||
.pswp__ui--idle .pswp__button--arrow--right {
|
||||
opacity: 0; }
|
||||
|
||||
/*
|
||||
pswp__ui--hidden class is added when controls are hidden
|
||||
e.g. when user taps to toggle visibility of controls
|
||||
*/
|
||||
.pswp__ui--hidden .pswp__top-bar,
|
||||
.pswp__ui--hidden .pswp__caption,
|
||||
.pswp__ui--hidden .pswp__button--arrow--left,
|
||||
.pswp__ui--hidden .pswp__button--arrow--right {
|
||||
/* Force paint & create composition layer for controls. */
|
||||
opacity: 0.001; }
|
||||
|
||||
/* pswp__ui--one-slide class is added when there is just one item in gallery */
|
||||
.pswp__ui--one-slide .pswp__button--arrow--left,
|
||||
.pswp__ui--one-slide .pswp__button--arrow--right,
|
||||
.pswp__ui--one-slide .pswp__counter {
|
||||
display: none; }
|
||||
|
||||
.pswp__element--disabled {
|
||||
display: none !important; }
|
||||
|
||||
.pswp--minimal--dark .pswp__top-bar {
|
||||
background: none; }
|
||||
861
frappe/public/js/lib/photoswipe/photoswipe-ui-default.js
Executable file
861
frappe/public/js/lib/photoswipe/photoswipe-ui-default.js
Executable file
|
|
@ -0,0 +1,861 @@
|
|||
/*! PhotoSwipe Default UI - 4.1.1 - 2015-12-24
|
||||
* http://photoswipe.com
|
||||
* Copyright (c) 2015 Dmitry Semenov; */
|
||||
/**
|
||||
*
|
||||
* UI on top of main sliding area (caption, arrows, close button, etc.).
|
||||
* Built just using public methods/properties of PhotoSwipe.
|
||||
*
|
||||
*/
|
||||
(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define(factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
module.exports = factory();
|
||||
} else {
|
||||
root.PhotoSwipeUI_Default = factory();
|
||||
}
|
||||
})(this, function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
|
||||
|
||||
var PhotoSwipeUI_Default =
|
||||
function(pswp, framework) {
|
||||
|
||||
var ui = this;
|
||||
var _overlayUIUpdated = false,
|
||||
_controlsVisible = true,
|
||||
_fullscrenAPI,
|
||||
_controls,
|
||||
_captionContainer,
|
||||
_fakeCaptionContainer,
|
||||
_indexIndicator,
|
||||
_shareButton,
|
||||
_shareModal,
|
||||
_shareModalHidden = true,
|
||||
_initalCloseOnScrollValue,
|
||||
_isIdle,
|
||||
_listen,
|
||||
|
||||
_loadingIndicator,
|
||||
_loadingIndicatorHidden,
|
||||
_loadingIndicatorTimeout,
|
||||
|
||||
_galleryHasOneSlide,
|
||||
|
||||
_options,
|
||||
_defaultUIOptions = {
|
||||
barsSize: {top:44, bottom:'auto'},
|
||||
closeElClasses: ['item', 'caption', 'zoom-wrap', 'ui', 'top-bar'],
|
||||
timeToIdle: 4000,
|
||||
timeToIdleOutside: 1000,
|
||||
loadingIndicatorDelay: 1000, // 2s
|
||||
|
||||
addCaptionHTMLFn: function(item, captionEl /*, isFake */) {
|
||||
if(!item.title) {
|
||||
captionEl.children[0].innerHTML = '';
|
||||
return false;
|
||||
}
|
||||
captionEl.children[0].innerHTML = item.title;
|
||||
return true;
|
||||
},
|
||||
|
||||
closeEl:true,
|
||||
captionEl: true,
|
||||
fullscreenEl: true,
|
||||
zoomEl: true,
|
||||
shareEl: true,
|
||||
counterEl: true,
|
||||
arrowEl: true,
|
||||
preloaderEl: true,
|
||||
|
||||
tapToClose: false,
|
||||
tapToToggleControls: true,
|
||||
|
||||
clickToCloseNonZoomable: true,
|
||||
|
||||
shareButtons: [
|
||||
{id:'facebook', label:'Share on Facebook', url:'https://www.facebook.com/sharer/sharer.php?u={{url}}'},
|
||||
{id:'twitter', label:'Tweet', url:'https://twitter.com/intent/tweet?text={{text}}&url={{url}}'},
|
||||
{id:'pinterest', label:'Pin it', url:'http://www.pinterest.com/pin/create/button/'+
|
||||
'?url={{url}}&media={{image_url}}&description={{text}}'},
|
||||
{id:'download', label:'Download image', url:'{{raw_image_url}}', download:true}
|
||||
],
|
||||
getImageURLForShare: function( /* shareButtonData */ ) {
|
||||
return pswp.currItem.src || '';
|
||||
},
|
||||
getPageURLForShare: function( /* shareButtonData */ ) {
|
||||
return window.location.href;
|
||||
},
|
||||
getTextForShare: function( /* shareButtonData */ ) {
|
||||
return pswp.currItem.title || '';
|
||||
},
|
||||
|
||||
indexIndicatorSep: ' / ',
|
||||
fitControlsWidth: 1200
|
||||
|
||||
},
|
||||
_blockControlsTap,
|
||||
_blockControlsTapTimeout;
|
||||
|
||||
|
||||
|
||||
var _onControlsTap = function(e) {
|
||||
if(_blockControlsTap) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
e = e || window.event;
|
||||
|
||||
if(_options.timeToIdle && _options.mouseUsed && !_isIdle) {
|
||||
// reset idle timer
|
||||
_onIdleMouseMove();
|
||||
}
|
||||
|
||||
|
||||
var target = e.target || e.srcElement,
|
||||
uiElement,
|
||||
clickedClass = target.getAttribute('class') || '',
|
||||
found;
|
||||
|
||||
for(var i = 0; i < _uiElements.length; i++) {
|
||||
uiElement = _uiElements[i];
|
||||
if(uiElement.onTap && clickedClass.indexOf('pswp__' + uiElement.name ) > -1 ) {
|
||||
uiElement.onTap();
|
||||
found = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(found) {
|
||||
if(e.stopPropagation) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
_blockControlsTap = true;
|
||||
|
||||
// Some versions of Android don't prevent ghost click event
|
||||
// when preventDefault() was called on touchstart and/or touchend.
|
||||
//
|
||||
// This happens on v4.3, 4.2, 4.1,
|
||||
// older versions strangely work correctly,
|
||||
// but just in case we add delay on all of them)
|
||||
var tapDelay = framework.features.isOldAndroid ? 600 : 30;
|
||||
_blockControlsTapTimeout = setTimeout(function() {
|
||||
_blockControlsTap = false;
|
||||
}, tapDelay);
|
||||
}
|
||||
|
||||
},
|
||||
_fitControlsInViewport = function() {
|
||||
return !pswp.likelyTouchDevice || _options.mouseUsed || screen.width > _options.fitControlsWidth;
|
||||
},
|
||||
_togglePswpClass = function(el, cName, add) {
|
||||
framework[ (add ? 'add' : 'remove') + 'Class' ](el, 'pswp__' + cName);
|
||||
},
|
||||
|
||||
// add class when there is just one item in the gallery
|
||||
// (by default it hides left/right arrows and 1ofX counter)
|
||||
_countNumItems = function() {
|
||||
var hasOneSlide = (_options.getNumItemsFn() === 1);
|
||||
|
||||
if(hasOneSlide !== _galleryHasOneSlide) {
|
||||
_togglePswpClass(_controls, 'ui--one-slide', hasOneSlide);
|
||||
_galleryHasOneSlide = hasOneSlide;
|
||||
}
|
||||
},
|
||||
_toggleShareModalClass = function() {
|
||||
_togglePswpClass(_shareModal, 'share-modal--hidden', _shareModalHidden);
|
||||
},
|
||||
_toggleShareModal = function() {
|
||||
|
||||
_shareModalHidden = !_shareModalHidden;
|
||||
|
||||
|
||||
if(!_shareModalHidden) {
|
||||
_toggleShareModalClass();
|
||||
setTimeout(function() {
|
||||
if(!_shareModalHidden) {
|
||||
framework.addClass(_shareModal, 'pswp__share-modal--fade-in');
|
||||
}
|
||||
}, 30);
|
||||
} else {
|
||||
framework.removeClass(_shareModal, 'pswp__share-modal--fade-in');
|
||||
setTimeout(function() {
|
||||
if(_shareModalHidden) {
|
||||
_toggleShareModalClass();
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
if(!_shareModalHidden) {
|
||||
_updateShareURLs();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_openWindowPopup = function(e) {
|
||||
e = e || window.event;
|
||||
var target = e.target || e.srcElement;
|
||||
|
||||
pswp.shout('shareLinkClick', e, target);
|
||||
|
||||
if(!target.href) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if( target.hasAttribute('download') ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
window.open(target.href, 'pswp_share', 'scrollbars=yes,resizable=yes,toolbar=no,'+
|
||||
'location=yes,width=550,height=420,top=100,left=' +
|
||||
(window.screen ? Math.round(screen.width / 2 - 275) : 100) );
|
||||
|
||||
if(!_shareModalHidden) {
|
||||
_toggleShareModal();
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
_updateShareURLs = function() {
|
||||
var shareButtonOut = '',
|
||||
shareButtonData,
|
||||
shareURL,
|
||||
image_url,
|
||||
page_url,
|
||||
share_text;
|
||||
|
||||
for(var i = 0; i < _options.shareButtons.length; i++) {
|
||||
shareButtonData = _options.shareButtons[i];
|
||||
|
||||
image_url = _options.getImageURLForShare(shareButtonData);
|
||||
page_url = _options.getPageURLForShare(shareButtonData);
|
||||
share_text = _options.getTextForShare(shareButtonData);
|
||||
|
||||
shareURL = shareButtonData.url.replace('{{url}}', encodeURIComponent(page_url) )
|
||||
.replace('{{image_url}}', encodeURIComponent(image_url) )
|
||||
.replace('{{raw_image_url}}', image_url )
|
||||
.replace('{{text}}', encodeURIComponent(share_text) );
|
||||
|
||||
shareButtonOut += '<a href="' + shareURL + '" target="_blank" '+
|
||||
'class="pswp__share--' + shareButtonData.id + '"' +
|
||||
(shareButtonData.download ? 'download' : '') + '>' +
|
||||
shareButtonData.label + '</a>';
|
||||
|
||||
if(_options.parseShareButtonOut) {
|
||||
shareButtonOut = _options.parseShareButtonOut(shareButtonData, shareButtonOut);
|
||||
}
|
||||
}
|
||||
_shareModal.children[0].innerHTML = shareButtonOut;
|
||||
_shareModal.children[0].onclick = _openWindowPopup;
|
||||
|
||||
},
|
||||
_hasCloseClass = function(target) {
|
||||
for(var i = 0; i < _options.closeElClasses.length; i++) {
|
||||
if( framework.hasClass(target, 'pswp__' + _options.closeElClasses[i]) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
},
|
||||
_idleInterval,
|
||||
_idleTimer,
|
||||
_idleIncrement = 0,
|
||||
_onIdleMouseMove = function() {
|
||||
clearTimeout(_idleTimer);
|
||||
_idleIncrement = 0;
|
||||
if(_isIdle) {
|
||||
ui.setIdle(false);
|
||||
}
|
||||
},
|
||||
_onMouseLeaveWindow = function(e) {
|
||||
e = e ? e : window.event;
|
||||
var from = e.relatedTarget || e.toElement;
|
||||
if (!from || from.nodeName === 'HTML') {
|
||||
clearTimeout(_idleTimer);
|
||||
_idleTimer = setTimeout(function() {
|
||||
ui.setIdle(true);
|
||||
}, _options.timeToIdleOutside);
|
||||
}
|
||||
},
|
||||
_setupFullscreenAPI = function() {
|
||||
if(_options.fullscreenEl && !framework.features.isOldAndroid) {
|
||||
if(!_fullscrenAPI) {
|
||||
_fullscrenAPI = ui.getFullscreenAPI();
|
||||
}
|
||||
if(_fullscrenAPI) {
|
||||
framework.bind(document, _fullscrenAPI.eventK, ui.updateFullscreen);
|
||||
ui.updateFullscreen();
|
||||
framework.addClass(pswp.template, 'pswp--supports-fs');
|
||||
} else {
|
||||
framework.removeClass(pswp.template, 'pswp--supports-fs');
|
||||
}
|
||||
}
|
||||
},
|
||||
_setupLoadingIndicator = function() {
|
||||
// Setup loading indicator
|
||||
if(_options.preloaderEl) {
|
||||
|
||||
_toggleLoadingIndicator(true);
|
||||
|
||||
_listen('beforeChange', function() {
|
||||
|
||||
clearTimeout(_loadingIndicatorTimeout);
|
||||
|
||||
// display loading indicator with delay
|
||||
_loadingIndicatorTimeout = setTimeout(function() {
|
||||
|
||||
if(pswp.currItem && pswp.currItem.loading) {
|
||||
|
||||
if( !pswp.allowProgressiveImg() || (pswp.currItem.img && !pswp.currItem.img.naturalWidth) ) {
|
||||
// show preloader if progressive loading is not enabled,
|
||||
// or image width is not defined yet (because of slow connection)
|
||||
_toggleLoadingIndicator(false);
|
||||
// items-controller.js function allowProgressiveImg
|
||||
}
|
||||
|
||||
} else {
|
||||
_toggleLoadingIndicator(true); // hide preloader
|
||||
}
|
||||
|
||||
}, _options.loadingIndicatorDelay);
|
||||
|
||||
});
|
||||
_listen('imageLoadComplete', function(index, item) {
|
||||
if(pswp.currItem === item) {
|
||||
_toggleLoadingIndicator(true);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
_toggleLoadingIndicator = function(hide) {
|
||||
if( _loadingIndicatorHidden !== hide ) {
|
||||
_togglePswpClass(_loadingIndicator, 'preloader--active', !hide);
|
||||
_loadingIndicatorHidden = hide;
|
||||
}
|
||||
},
|
||||
_applyNavBarGaps = function(item) {
|
||||
var gap = item.vGap;
|
||||
|
||||
if( _fitControlsInViewport() ) {
|
||||
|
||||
var bars = _options.barsSize;
|
||||
if(_options.captionEl && bars.bottom === 'auto') {
|
||||
if(!_fakeCaptionContainer) {
|
||||
_fakeCaptionContainer = framework.createEl('pswp__caption pswp__caption--fake');
|
||||
_fakeCaptionContainer.appendChild( framework.createEl('pswp__caption__center') );
|
||||
_controls.insertBefore(_fakeCaptionContainer, _captionContainer);
|
||||
framework.addClass(_controls, 'pswp__ui--fit');
|
||||
}
|
||||
if( _options.addCaptionHTMLFn(item, _fakeCaptionContainer, true) ) {
|
||||
|
||||
var captionSize = _fakeCaptionContainer.clientHeight;
|
||||
gap.bottom = parseInt(captionSize,10) || 44;
|
||||
} else {
|
||||
gap.bottom = bars.top; // if no caption, set size of bottom gap to size of top
|
||||
}
|
||||
} else {
|
||||
gap.bottom = bars.bottom === 'auto' ? 0 : bars.bottom;
|
||||
}
|
||||
|
||||
// height of top bar is static, no need to calculate it
|
||||
gap.top = bars.top;
|
||||
} else {
|
||||
gap.top = gap.bottom = 0;
|
||||
}
|
||||
},
|
||||
_setupIdle = function() {
|
||||
// Hide controls when mouse is used
|
||||
if(_options.timeToIdle) {
|
||||
_listen('mouseUsed', function() {
|
||||
|
||||
framework.bind(document, 'mousemove', _onIdleMouseMove);
|
||||
framework.bind(document, 'mouseout', _onMouseLeaveWindow);
|
||||
|
||||
_idleInterval = setInterval(function() {
|
||||
_idleIncrement++;
|
||||
if(_idleIncrement === 2) {
|
||||
ui.setIdle(true);
|
||||
}
|
||||
}, _options.timeToIdle / 2);
|
||||
});
|
||||
}
|
||||
},
|
||||
_setupHidingControlsDuringGestures = function() {
|
||||
|
||||
// Hide controls on vertical drag
|
||||
_listen('onVerticalDrag', function(now) {
|
||||
if(_controlsVisible && now < 0.95) {
|
||||
ui.hideControls();
|
||||
} else if(!_controlsVisible && now >= 0.95) {
|
||||
ui.showControls();
|
||||
}
|
||||
});
|
||||
|
||||
// Hide controls when pinching to close
|
||||
var pinchControlsHidden;
|
||||
_listen('onPinchClose' , function(now) {
|
||||
if(_controlsVisible && now < 0.9) {
|
||||
ui.hideControls();
|
||||
pinchControlsHidden = true;
|
||||
} else if(pinchControlsHidden && !_controlsVisible && now > 0.9) {
|
||||
ui.showControls();
|
||||
}
|
||||
});
|
||||
|
||||
_listen('zoomGestureEnded', function() {
|
||||
pinchControlsHidden = false;
|
||||
if(pinchControlsHidden && !_controlsVisible) {
|
||||
ui.showControls();
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
var _uiElements = [
|
||||
{
|
||||
name: 'caption',
|
||||
option: 'captionEl',
|
||||
onInit: function(el) {
|
||||
_captionContainer = el;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'share-modal',
|
||||
option: 'shareEl',
|
||||
onInit: function(el) {
|
||||
_shareModal = el;
|
||||
},
|
||||
onTap: function() {
|
||||
_toggleShareModal();
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'button--share',
|
||||
option: 'shareEl',
|
||||
onInit: function(el) {
|
||||
_shareButton = el;
|
||||
},
|
||||
onTap: function() {
|
||||
_toggleShareModal();
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'button--zoom',
|
||||
option: 'zoomEl',
|
||||
onTap: pswp.toggleDesktopZoom
|
||||
},
|
||||
{
|
||||
name: 'counter',
|
||||
option: 'counterEl',
|
||||
onInit: function(el) {
|
||||
_indexIndicator = el;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'button--close',
|
||||
option: 'closeEl',
|
||||
onTap: pswp.close
|
||||
},
|
||||
{
|
||||
name: 'button--arrow--left',
|
||||
option: 'arrowEl',
|
||||
onTap: pswp.prev
|
||||
},
|
||||
{
|
||||
name: 'button--arrow--right',
|
||||
option: 'arrowEl',
|
||||
onTap: pswp.next
|
||||
},
|
||||
{
|
||||
name: 'button--fs',
|
||||
option: 'fullscreenEl',
|
||||
onTap: function() {
|
||||
if(_fullscrenAPI.isFullscreen()) {
|
||||
_fullscrenAPI.exit();
|
||||
} else {
|
||||
_fullscrenAPI.enter();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'preloader',
|
||||
option: 'preloaderEl',
|
||||
onInit: function(el) {
|
||||
_loadingIndicator = el;
|
||||
}
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
var _setupUIElements = function() {
|
||||
var item,
|
||||
classAttr,
|
||||
uiElement;
|
||||
|
||||
var loopThroughChildElements = function(sChildren) {
|
||||
if(!sChildren) {
|
||||
return;
|
||||
}
|
||||
|
||||
var l = sChildren.length;
|
||||
for(var i = 0; i < l; i++) {
|
||||
item = sChildren[i];
|
||||
classAttr = item.className;
|
||||
|
||||
for(var a = 0; a < _uiElements.length; a++) {
|
||||
uiElement = _uiElements[a];
|
||||
|
||||
if(classAttr.indexOf('pswp__' + uiElement.name) > -1 ) {
|
||||
|
||||
if( _options[uiElement.option] ) { // if element is not disabled from options
|
||||
|
||||
framework.removeClass(item, 'pswp__element--disabled');
|
||||
if(uiElement.onInit) {
|
||||
uiElement.onInit(item);
|
||||
}
|
||||
|
||||
//item.style.display = 'block';
|
||||
} else {
|
||||
framework.addClass(item, 'pswp__element--disabled');
|
||||
//item.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
loopThroughChildElements(_controls.children);
|
||||
|
||||
var topBar = framework.getChildByClass(_controls, 'pswp__top-bar');
|
||||
if(topBar) {
|
||||
loopThroughChildElements( topBar.children );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
ui.init = function() {
|
||||
|
||||
// extend options
|
||||
framework.extend(pswp.options, _defaultUIOptions, true);
|
||||
|
||||
// create local link for fast access
|
||||
_options = pswp.options;
|
||||
|
||||
// find pswp__ui element
|
||||
_controls = framework.getChildByClass(pswp.scrollWrap, 'pswp__ui');
|
||||
|
||||
// create local link
|
||||
_listen = pswp.listen;
|
||||
|
||||
|
||||
_setupHidingControlsDuringGestures();
|
||||
|
||||
// update controls when slides change
|
||||
_listen('beforeChange', ui.update);
|
||||
|
||||
// toggle zoom on double-tap
|
||||
_listen('doubleTap', function(point) {
|
||||
var initialZoomLevel = pswp.currItem.initialZoomLevel;
|
||||
if(pswp.getZoomLevel() !== initialZoomLevel) {
|
||||
pswp.zoomTo(initialZoomLevel, point, 333);
|
||||
} else {
|
||||
pswp.zoomTo(_options.getDoubleTapZoom(false, pswp.currItem), point, 333);
|
||||
}
|
||||
});
|
||||
|
||||
// Allow text selection in caption
|
||||
_listen('preventDragEvent', function(e, isDown, preventObj) {
|
||||
var t = e.target || e.srcElement;
|
||||
if(
|
||||
t &&
|
||||
t.getAttribute('class') && e.type.indexOf('mouse') > -1 &&
|
||||
( t.getAttribute('class').indexOf('__caption') > 0 || (/(SMALL|STRONG|EM)/i).test(t.tagName) )
|
||||
) {
|
||||
preventObj.prevent = false;
|
||||
}
|
||||
});
|
||||
|
||||
// bind events for UI
|
||||
_listen('bindEvents', function() {
|
||||
framework.bind(_controls, 'pswpTap click', _onControlsTap);
|
||||
framework.bind(pswp.scrollWrap, 'pswpTap', ui.onGlobalTap);
|
||||
|
||||
if(!pswp.likelyTouchDevice) {
|
||||
framework.bind(pswp.scrollWrap, 'mouseover', ui.onMouseOver);
|
||||
}
|
||||
});
|
||||
|
||||
// unbind events for UI
|
||||
_listen('unbindEvents', function() {
|
||||
if(!_shareModalHidden) {
|
||||
_toggleShareModal();
|
||||
}
|
||||
|
||||
if(_idleInterval) {
|
||||
clearInterval(_idleInterval);
|
||||
}
|
||||
framework.unbind(document, 'mouseout', _onMouseLeaveWindow);
|
||||
framework.unbind(document, 'mousemove', _onIdleMouseMove);
|
||||
framework.unbind(_controls, 'pswpTap click', _onControlsTap);
|
||||
framework.unbind(pswp.scrollWrap, 'pswpTap', ui.onGlobalTap);
|
||||
framework.unbind(pswp.scrollWrap, 'mouseover', ui.onMouseOver);
|
||||
|
||||
if(_fullscrenAPI) {
|
||||
framework.unbind(document, _fullscrenAPI.eventK, ui.updateFullscreen);
|
||||
if(_fullscrenAPI.isFullscreen()) {
|
||||
_options.hideAnimationDuration = 0;
|
||||
_fullscrenAPI.exit();
|
||||
}
|
||||
_fullscrenAPI = null;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// clean up things when gallery is destroyed
|
||||
_listen('destroy', function() {
|
||||
if(_options.captionEl) {
|
||||
if(_fakeCaptionContainer) {
|
||||
_controls.removeChild(_fakeCaptionContainer);
|
||||
}
|
||||
framework.removeClass(_captionContainer, 'pswp__caption--empty');
|
||||
}
|
||||
|
||||
if(_shareModal) {
|
||||
_shareModal.children[0].onclick = null;
|
||||
}
|
||||
framework.removeClass(_controls, 'pswp__ui--over-close');
|
||||
framework.addClass( _controls, 'pswp__ui--hidden');
|
||||
ui.setIdle(false);
|
||||
});
|
||||
|
||||
|
||||
if(!_options.showAnimationDuration) {
|
||||
framework.removeClass( _controls, 'pswp__ui--hidden');
|
||||
}
|
||||
_listen('initialZoomIn', function() {
|
||||
if(_options.showAnimationDuration) {
|
||||
framework.removeClass( _controls, 'pswp__ui--hidden');
|
||||
}
|
||||
});
|
||||
_listen('initialZoomOut', function() {
|
||||
framework.addClass( _controls, 'pswp__ui--hidden');
|
||||
});
|
||||
|
||||
_listen('parseVerticalMargin', _applyNavBarGaps);
|
||||
|
||||
_setupUIElements();
|
||||
|
||||
if(_options.shareEl && _shareButton && _shareModal) {
|
||||
_shareModalHidden = true;
|
||||
}
|
||||
|
||||
_countNumItems();
|
||||
|
||||
_setupIdle();
|
||||
|
||||
_setupFullscreenAPI();
|
||||
|
||||
_setupLoadingIndicator();
|
||||
};
|
||||
|
||||
ui.setIdle = function(isIdle) {
|
||||
_isIdle = isIdle;
|
||||
_togglePswpClass(_controls, 'ui--idle', isIdle);
|
||||
};
|
||||
|
||||
ui.update = function() {
|
||||
// Don't update UI if it's hidden
|
||||
if(_controlsVisible && pswp.currItem) {
|
||||
|
||||
ui.updateIndexIndicator();
|
||||
|
||||
if(_options.captionEl) {
|
||||
_options.addCaptionHTMLFn(pswp.currItem, _captionContainer);
|
||||
|
||||
_togglePswpClass(_captionContainer, 'caption--empty', !pswp.currItem.title);
|
||||
}
|
||||
|
||||
_overlayUIUpdated = true;
|
||||
|
||||
} else {
|
||||
_overlayUIUpdated = false;
|
||||
}
|
||||
|
||||
if(!_shareModalHidden) {
|
||||
_toggleShareModal();
|
||||
}
|
||||
|
||||
_countNumItems();
|
||||
};
|
||||
|
||||
ui.updateFullscreen = function(e) {
|
||||
|
||||
if(e) {
|
||||
// some browsers change window scroll position during the fullscreen
|
||||
// so PhotoSwipe updates it just in case
|
||||
setTimeout(function() {
|
||||
pswp.setScrollOffset( 0, framework.getScrollY() );
|
||||
}, 50);
|
||||
}
|
||||
|
||||
// toogle pswp--fs class on root element
|
||||
framework[ (_fullscrenAPI.isFullscreen() ? 'add' : 'remove') + 'Class' ](pswp.template, 'pswp--fs');
|
||||
};
|
||||
|
||||
ui.updateIndexIndicator = function() {
|
||||
if(_options.counterEl) {
|
||||
_indexIndicator.innerHTML = (pswp.getCurrentIndex()+1) +
|
||||
_options.indexIndicatorSep +
|
||||
_options.getNumItemsFn();
|
||||
}
|
||||
};
|
||||
|
||||
ui.onGlobalTap = function(e) {
|
||||
e = e || window.event;
|
||||
var target = e.target || e.srcElement;
|
||||
|
||||
if(_blockControlsTap) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(e.detail && e.detail.pointerType === 'mouse') {
|
||||
|
||||
// close gallery if clicked outside of the image
|
||||
if(_hasCloseClass(target)) {
|
||||
pswp.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if(framework.hasClass(target, 'pswp__img')) {
|
||||
if(pswp.getZoomLevel() === 1 && pswp.getZoomLevel() <= pswp.currItem.fitRatio) {
|
||||
if(_options.clickToCloseNonZoomable) {
|
||||
pswp.close();
|
||||
}
|
||||
} else {
|
||||
pswp.toggleDesktopZoom(e.detail.releasePoint);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// tap anywhere (except buttons) to toggle visibility of controls
|
||||
if(_options.tapToToggleControls) {
|
||||
if(_controlsVisible) {
|
||||
ui.hideControls();
|
||||
} else {
|
||||
ui.showControls();
|
||||
}
|
||||
}
|
||||
|
||||
// tap to close gallery
|
||||
if(_options.tapToClose && (framework.hasClass(target, 'pswp__img') || _hasCloseClass(target)) ) {
|
||||
pswp.close();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
ui.onMouseOver = function(e) {
|
||||
e = e || window.event;
|
||||
var target = e.target || e.srcElement;
|
||||
|
||||
// add class when mouse is over an element that should close the gallery
|
||||
_togglePswpClass(_controls, 'ui--over-close', _hasCloseClass(target));
|
||||
};
|
||||
|
||||
ui.hideControls = function() {
|
||||
framework.addClass(_controls,'pswp__ui--hidden');
|
||||
_controlsVisible = false;
|
||||
};
|
||||
|
||||
ui.showControls = function() {
|
||||
_controlsVisible = true;
|
||||
if(!_overlayUIUpdated) {
|
||||
ui.update();
|
||||
}
|
||||
framework.removeClass(_controls,'pswp__ui--hidden');
|
||||
};
|
||||
|
||||
ui.supportsFullscreen = function() {
|
||||
var d = document;
|
||||
return !!(d.exitFullscreen || d.mozCancelFullScreen || d.webkitExitFullscreen || d.msExitFullscreen);
|
||||
};
|
||||
|
||||
ui.getFullscreenAPI = function() {
|
||||
var dE = document.documentElement,
|
||||
api,
|
||||
tF = 'fullscreenchange';
|
||||
|
||||
if (dE.requestFullscreen) {
|
||||
api = {
|
||||
enterK: 'requestFullscreen',
|
||||
exitK: 'exitFullscreen',
|
||||
elementK: 'fullscreenElement',
|
||||
eventK: tF
|
||||
};
|
||||
|
||||
} else if(dE.mozRequestFullScreen ) {
|
||||
api = {
|
||||
enterK: 'mozRequestFullScreen',
|
||||
exitK: 'mozCancelFullScreen',
|
||||
elementK: 'mozFullScreenElement',
|
||||
eventK: 'moz' + tF
|
||||
};
|
||||
|
||||
|
||||
|
||||
} else if(dE.webkitRequestFullscreen) {
|
||||
api = {
|
||||
enterK: 'webkitRequestFullscreen',
|
||||
exitK: 'webkitExitFullscreen',
|
||||
elementK: 'webkitFullscreenElement',
|
||||
eventK: 'webkit' + tF
|
||||
};
|
||||
|
||||
} else if(dE.msRequestFullscreen) {
|
||||
api = {
|
||||
enterK: 'msRequestFullscreen',
|
||||
exitK: 'msExitFullscreen',
|
||||
elementK: 'msFullscreenElement',
|
||||
eventK: 'MSFullscreenChange'
|
||||
};
|
||||
}
|
||||
|
||||
if(api) {
|
||||
api.enter = function() {
|
||||
// disable close-on-scroll in fullscreen
|
||||
_initalCloseOnScrollValue = _options.closeOnScroll;
|
||||
_options.closeOnScroll = false;
|
||||
|
||||
if(this.enterK === 'webkitRequestFullscreen') {
|
||||
pswp.template[this.enterK]( Element.ALLOW_KEYBOARD_INPUT );
|
||||
} else {
|
||||
return pswp.template[this.enterK]();
|
||||
}
|
||||
};
|
||||
api.exit = function() {
|
||||
_options.closeOnScroll = _initalCloseOnScrollValue;
|
||||
|
||||
return document[this.exitK]();
|
||||
|
||||
};
|
||||
api.isFullscreen = function() { return document[this.elementK]; };
|
||||
}
|
||||
|
||||
return api;
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
||||
return PhotoSwipeUI_Default;
|
||||
|
||||
|
||||
});
|
||||
178
frappe/public/js/lib/photoswipe/photoswipe.css
Executable file
178
frappe/public/js/lib/photoswipe/photoswipe.css
Executable file
|
|
@ -0,0 +1,178 @@
|
|||
/*! PhotoSwipe main CSS by Dmitry Semenov | photoswipe.com | MIT license */
|
||||
/*
|
||||
Styles for basic PhotoSwipe functionality (sliding area, open/close transitions)
|
||||
*/
|
||||
/* pswp = photoswipe */
|
||||
.pswp {
|
||||
display: none;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
z-index: 1500;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
/* create separate layer, to avoid paint on window.onscroll in webkit/blink */
|
||||
-webkit-backface-visibility: hidden;
|
||||
outline: none; }
|
||||
.pswp * {
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box; }
|
||||
.pswp img {
|
||||
max-width: none; }
|
||||
|
||||
/* style is added when JS option showHideOpacity is set to true */
|
||||
.pswp--animate_opacity {
|
||||
/* 0.001, because opacity:0 doesn't trigger Paint action, which causes lag at start of transition */
|
||||
opacity: 0.001;
|
||||
will-change: opacity;
|
||||
/* for open/close transition */
|
||||
-webkit-transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
|
||||
transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); }
|
||||
|
||||
.pswp--open {
|
||||
display: block; }
|
||||
|
||||
.pswp--zoom-allowed .pswp__img {
|
||||
/* autoprefixer: off */
|
||||
cursor: -webkit-zoom-in;
|
||||
cursor: -moz-zoom-in;
|
||||
cursor: zoom-in; }
|
||||
|
||||
.pswp--zoomed-in .pswp__img {
|
||||
/* autoprefixer: off */
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
cursor: grab; }
|
||||
|
||||
.pswp--dragging .pswp__img {
|
||||
/* autoprefixer: off */
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
cursor: grabbing; }
|
||||
|
||||
/*
|
||||
Background is added as a separate element.
|
||||
As animating opacity is much faster than animating rgba() background-color.
|
||||
*/
|
||||
.pswp__bg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #000;
|
||||
opacity: 0;
|
||||
transform: translateZ(0);
|
||||
-webkit-backface-visibility: hidden;
|
||||
will-change: opacity; }
|
||||
|
||||
.pswp__scroll-wrap {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden; }
|
||||
|
||||
.pswp__container,
|
||||
.pswp__zoom-wrap {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0; }
|
||||
|
||||
/* Prevent selection and tap highlights */
|
||||
.pswp__container,
|
||||
.pswp__img {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-touch-callout: none; }
|
||||
|
||||
.pswp__zoom-wrap {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
-webkit-transform-origin: left top;
|
||||
-ms-transform-origin: left top;
|
||||
transform-origin: left top;
|
||||
/* for open/close transition */
|
||||
-webkit-transition: -webkit-transform 333ms cubic-bezier(0.4, 0, 0.22, 1);
|
||||
transition: transform 333ms cubic-bezier(0.4, 0, 0.22, 1); }
|
||||
|
||||
.pswp__bg {
|
||||
will-change: opacity;
|
||||
/* for open/close transition */
|
||||
-webkit-transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
|
||||
transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1); }
|
||||
|
||||
.pswp--animated-in .pswp__bg,
|
||||
.pswp--animated-in .pswp__zoom-wrap {
|
||||
-webkit-transition: none;
|
||||
transition: none; }
|
||||
|
||||
.pswp__container,
|
||||
.pswp__zoom-wrap {
|
||||
-webkit-backface-visibility: hidden; }
|
||||
|
||||
.pswp__item {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden; }
|
||||
|
||||
.pswp__img {
|
||||
position: absolute;
|
||||
width: auto;
|
||||
height: auto;
|
||||
top: 0;
|
||||
left: 0; }
|
||||
|
||||
/*
|
||||
stretched thumbnail or div placeholder element (see below)
|
||||
style is added to avoid flickering in webkit/blink when layers overlap
|
||||
*/
|
||||
.pswp__img--placeholder {
|
||||
-webkit-backface-visibility: hidden; }
|
||||
|
||||
/*
|
||||
div element that matches size of large image
|
||||
large image loads on top of it
|
||||
*/
|
||||
.pswp__img--placeholder--blank {
|
||||
background: #222; }
|
||||
|
||||
.pswp--ie .pswp__img {
|
||||
width: 100% !important;
|
||||
height: auto !important;
|
||||
left: 0;
|
||||
top: 0; }
|
||||
|
||||
/*
|
||||
Error message appears when image is not loaded
|
||||
(JS option errorMsg controls markup)
|
||||
*/
|
||||
.pswp__error-msg {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
line-height: 16px;
|
||||
margin-top: -8px;
|
||||
color: #CCC; }
|
||||
|
||||
.pswp__error-msg a {
|
||||
color: #CCC;
|
||||
text-decoration: underline; }
|
||||
3718
frappe/public/js/lib/photoswipe/photoswipe.js
Executable file
3718
frappe/public/js/lib/photoswipe/photoswipe.js
Executable file
File diff suppressed because it is too large
Load diff
|
|
@ -768,3 +768,31 @@ textarea.form-control {
|
|||
|
||||
.c3-tooltip td.value {
|
||||
text-align: right; }
|
||||
|
||||
// custom font awesome checkbox
|
||||
input[type="checkbox"] {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
font-family: 'FontAwesome';
|
||||
content: '\f096';
|
||||
visibility: visible;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 14px;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
color: @text-extra-muted;
|
||||
.transition(150ms color);
|
||||
}
|
||||
|
||||
&:checked:before {
|
||||
content: '\f14a';
|
||||
font-size: 13px;
|
||||
color: @checkbox-color;
|
||||
}
|
||||
}
|
||||
|
|
@ -102,6 +102,7 @@
|
|||
.checkbox {
|
||||
margin: 0px;
|
||||
text-align: center;
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
|
|
|
|||
|
|
@ -141,7 +141,26 @@
|
|||
}
|
||||
|
||||
.list-value {
|
||||
display: table;
|
||||
vertical-align: middle;
|
||||
|
||||
.list-row-checkbox, .liked-by, .list-id, .list-select-all {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.list-row-checkbox, .list-select-all {
|
||||
margin: 0;
|
||||
margin-right: 7px;
|
||||
}
|
||||
|
||||
.liked-by {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.list-col-title {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.progress {
|
||||
|
|
@ -150,14 +169,14 @@
|
|||
|
||||
.doclist-row {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.likes-count {
|
||||
display: inline-block;
|
||||
width: 15px;
|
||||
margin-left: -5px;
|
||||
color: @text-muted;
|
||||
font-size: 12px;
|
||||
}
|
||||
.likes-count {
|
||||
display: inline-block;
|
||||
width: 15px;
|
||||
margin-left: -5px;
|
||||
color: @text-muted;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.doclist-row .docstatus .octicon {
|
||||
|
|
@ -210,10 +229,6 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.list-row-head .octicon-heart {
|
||||
margin-right: 13px;
|
||||
}
|
||||
|
||||
.like-action.octicon-heart {
|
||||
// color: #ffdb4c;
|
||||
color: @heart-color;
|
||||
|
|
@ -255,65 +270,6 @@
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
.image-view {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.image-view-subject {
|
||||
padding: inherit;
|
||||
}
|
||||
|
||||
.image-view-col {
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
|
||||
a {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
table.field-info {
|
||||
opacity: 0;
|
||||
bottom: -20px;
|
||||
font-size: 8pt;
|
||||
color: white;
|
||||
background-color: @text-color;
|
||||
position: absolute;
|
||||
padding-bottom: 0px !important;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
table.field-info tr td {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.zoom-view {
|
||||
top: 10px !important;
|
||||
right: 10px !important;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
opacity: 0;
|
||||
font-size: 16px;
|
||||
color: @text-color;
|
||||
position: absolute;
|
||||
padding: 0px !important;
|
||||
border-radius: 5px;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
.image-field {
|
||||
background-size: contain;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.image-field:hover .field-info {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.image-field:hover .zoom-view {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
// tags
|
||||
|
||||
.tag-row {
|
||||
|
|
@ -367,4 +323,128 @@ table.field-info tr td {
|
|||
margin-top: 3px;
|
||||
font-size: 11px;
|
||||
max-width: 100px;
|
||||
}
|
||||
|
||||
// Image view
|
||||
|
||||
.image-view-container {
|
||||
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.image-view-item {
|
||||
flex: 0 0 100%/4;
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid @light-border-color;
|
||||
border-right: 1px solid @light-border-color;
|
||||
}
|
||||
|
||||
.image-view-item:nth-child(4n) {
|
||||
border-right: none;
|
||||
}
|
||||
.image-view-item:nth-last-child(-n + 4):nth-child(4n + 1),
|
||||
.image-view-item:nth-last-child(-n + 4):nth-child(4n + 1) ~ .image-view-item {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.image-view-header {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.image-view-body {
|
||||
&:hover .zoom-view {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.image-field {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
height: 200px;
|
||||
padding: 15px;
|
||||
|
||||
img {
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.placeholder-text {
|
||||
font-size: 72px;
|
||||
color: @text-extra-muted;
|
||||
}
|
||||
|
||||
.zoom-view {
|
||||
bottom: 10px !important;
|
||||
right: 10px !important;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
opacity: 0;
|
||||
font-size: 16px;
|
||||
color: @text-color;
|
||||
position: absolute;
|
||||
|
||||
// show zoom button on mobile devices
|
||||
@media (max-width: @screen-xs) {
|
||||
opacity: 0.5
|
||||
}
|
||||
}
|
||||
|
||||
// 3 columns for small screen
|
||||
@media(max-width: @screen-sm) {
|
||||
.image-view-item {
|
||||
flex: 0 0 100%/3;
|
||||
}
|
||||
|
||||
.image-view-item:nth-child(3n) {
|
||||
border-right: none;
|
||||
}
|
||||
.image-view-item:nth-last-child(-n + 3):nth-child(3n + 1),
|
||||
.image-view-item:nth-last-child(-n + 3):nth-child(3n + 1) ~ .image-view-item {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.image-view-item:nth-child(4n) {
|
||||
border-right: 1px solid @light-border-color;
|
||||
}
|
||||
.image-view-item:nth-last-child(-n + 4):nth-child(4n + 1),
|
||||
.image-view-item:nth-last-child(-n + 4):nth-child(4n + 1) ~ .image-view-item {
|
||||
border-bottom: 1px solid @light-border-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pswp--svg .pswp__button,
|
||||
.pswp--svg .pswp__button--arrow--left:before,
|
||||
.pswp--svg .pswp__button--arrow--right:before {
|
||||
background-image: url('/assets/frappe/images/default-skin.svg') !important;
|
||||
}
|
||||
.pswp--svg .pswp__button--arrow--left,
|
||||
.pswp--svg .pswp__button--arrow--right {
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.pswp__bg {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
// gantt
|
||||
.gantt {
|
||||
.details-container {
|
||||
.heading {
|
||||
margin-bottom: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.avatar-small {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -166,6 +166,10 @@ body[data-route^="Module"] .main-menu {
|
|||
}
|
||||
}
|
||||
|
||||
.liked-by {
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
.liked-by .octicon-heart {
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue