diff --git a/api/etemplate.php b/api/etemplate.php index 4d14a87848..9e3dfd4b20 100644 --- a/api/etemplate.php +++ b/api/etemplate.php @@ -270,7 +270,7 @@ function send_template() $str = preg_replace('#]+)(/|>#', '', $str); // fix <(button|buttononly|timestamper).../> --> - $str = preg_replace_callback('#<(button|buttononly|timestamper|button-timestamp)\s(.*?)(/|>#s', function ($matches) use ($name) + $str = preg_replace_callback('#<(button|buttononly|timestamper|button-timestamp|dropdown_button)\s(.*?)(/|>#s', function ($matches) use ($name) { $tag = 'et2-button'; $attrs = parseAttrs($matches[2]); @@ -284,6 +284,9 @@ function send_template() $tag .= '-timestamp'; $attrs['background_image'] = 'true'; break; + case 'dropdown_button': + $tag = 'et2-dropdown-button'; + break; } // novalidation --> noValidation if (!empty($attrs['novalidation']) && in_array($attrs['novalidation'], ['true', '1'], true)) diff --git a/api/js/etemplate/et2_widget_dropdown_button.ts b/api/js/etemplate/et2_widget_dropdown_button.ts deleted file mode 100644 index d38a67e271..0000000000 --- a/api/js/etemplate/et2_widget_dropdown_button.ts +++ /dev/null @@ -1,439 +0,0 @@ -/** - * EGroupware eTemplate2 - JS Dropdown Button object - * - * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License - * @package etemplate - * @subpackage api - * @link https://www.egroupware.org - * @author Nathan Gray - * @copyright Nathan Gray 2013 - */ - -/*egw:uses - /vendor/bower-asset/jquery/dist/jquery.js; - et2_baseWidget; -*/ - -import {et2_inputWidget} from './et2_core_inputWidget'; -import {WidgetConfig, et2_register_widget} from "./et2_core_widget"; -import {ClassWithAttributes} from "./et2_core_inheritance"; -import {et2_no_init} from "./et2_core_common"; -import {egw} from "../jsapi/egw_global"; - -/** - * A split button - a button with a dropdown list - * - * There are several parts to the button UI: - * - Container: This is what is percieved as the dropdown button, the whole package together - * - Button: The part on the left that can be clicked - * - Arrow: The button to display the choices - * - Menu: The list of choices - * - * Menu options are passed via the select_options. They are normally ID => Title pairs, - * as for a select box, but the title can also be full HTML if needed. - * - * @augments et2_inputWidget - */ -export class et2_dropdown_button extends et2_inputWidget -{ - static readonly attributes : any = { - "label": { - "name": "caption", - "type": "string", - "description": "Label of the button", - "translate": true, - "default": "Select..." - }, - "label_updates": { - "name": "Label updates", - "type": "boolean", - "description": "Button label updates when an option is selected from the menu", - "default": true - }, - "image": { - "name": "Icon", - "type": "string", - "description": "Add an icon" - }, - "ro_image": { - "name": "Read-only Icon", - "type": "string", - "description": "Use this icon instead of hiding for read-only" - }, - "onclick": { - "description": "JS code which gets executed when the button is clicked" - }, - "select_options": { - "type": "any", - "name": "Select options", - "default": {}, - "description": "Select options for dropdown. Can be a simple key => value list, or value can be full HTML", - // Skip normal initialization for this one - "ignore": true - }, - "accesskey": { - "name": "Access Key", - "type": "string", - "default": et2_no_init, - "description": "Alt + activates widget" - }, - "tabindex": { - "name": "Tab index", - "type": "integer", - "default": et2_no_init, - "description": "Specifies the tab order of a widget when the 'tab' button is used for navigating." - }, - // No such thing as a required button - "required": { - "ignore": true - } - }; - - internal_ids : any = { - div: "", - button: "", - menu: "" - }; - - div : JQuery = null; - buttons : JQuery = null; - button : JQuery = null; - arrow : JQuery = null; - menu : JQuery = null; - image : JQuery = null; - clicked : boolean = false; - label_updates : boolean = true; - value : any = null; - /** - * Default menu, so there is something for the widget browser / editor to show - */ - readonly default_menu : string = ''; - - /** - * Constructor - * - * @memberOf et2_dropdown_button - */ - constructor(_parent?, _attrs? : WidgetConfig, _child? : object) { - super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_dropdown_button._attributes, _child || {})); - - this.clicked = false; - - let self = this; - - // Create the individual UI elements - - // Menu is a UL - this.menu = jQuery(this.default_menu).attr("id",this.internal_ids.menu) - .hide() - .menu({ - select: function(event,ui) { - self.onselect.call(self,event,ui.item); - } - }); - - this.buttons = jQuery(document.createElement("div")) - .addClass("et2_dropdown"); - - // Main "wrapper" div - this.div = jQuery(document.createElement("div")) - .attr("id", this.internal_ids.div) - .append(this.buttons) - .append(this.menu); - - // Left side - activates click action - this.button = jQuery(document.createElement("button")) - .attr("id", this.internal_ids.button) - .attr("type", "button") - .addClass("ui-widget ui-corner-left").removeClass("ui-corner-all") - .appendTo(this.buttons); - - // Right side - shows dropdown - this.arrow = jQuery(document.createElement("button")) - .addClass("ui-widget ui-corner-right").removeClass("ui-corner-all") - .attr("type", "button") - .click(function() { - // ignore click on readonly button - if (self.options.readonly) return false; - // Clicking it again hides menu - if(self.menu.is(":visible")) - { - self.menu.hide(); - return false; - } - // Show menu dropdown - var menu = self.menu.show().position({ - my: "left top", - at: "left bottom", - of: self.buttons - }); - // Hide menu if clicked elsewhere - jQuery( document ).one( "click", function() { - menu.hide(); - }); - return false; - }) - // This is the actual down arrow icon - .append("
") - .appendTo(this.buttons); - - // Common button UI - this.buttons.children("button") - .addClass("ui-state-default") - .hover( - function() {jQuery(this).addClass("ui-state-hover");}, - function() {jQuery(this).removeClass("ui-state-hover");} - ); - - // Icon - this.image = jQuery(document.createElement("img")); - - this.setDOMNode(this.div[0]); - } - - destroy() { - // Destroy widget - if(this.menu && this.menu.data('ui-menu')) this.menu.menu("destroy"); - - // Null children - this.image = null; - this.button = null; - this.arrow = null; - this.buttons = null; - this.menu = null; - - // Remove - this.div.empty().remove(); - } - - set_id(_id) { - super.set_id(_id); - - // Update internal IDs - not really needed since we refer by internal - // javascript reference, but good to keep up to date - this.internal_ids = { - div: this.dom_id + "_wrapper", - button: this.dom_id, - menu: this.dom_id + "_menu" - }; - for(let key in this.internal_ids) - { - if(this[key] == null) continue; - this[key].attr("id", this.internal_ids[key]); - } - } - - /** - * Set if the button label changes to match the selected option - * - * @param updates boolean Turn updating on or off - */ - set_label_updates(updates) - { - this.label_updates = updates; - } - - set_accesskey(key) - { - jQuery(this.node).attr("accesskey", key); - } - - set_ro_image(_image) - { - if(this.options.readonly) - { - this.set_image(_image); - } - } - - set_image(_image) - { - if(!this.isInTree() || this.image == null) return; - if(!_image.trim()) - { - this.image.hide(); - } - else - { - this.image.show(); - } - - let src = this.egw().image(_image); - if(src) - { - this.image.attr("src", src); - } - // allow url's too - else if (_image[0] == '/' || _image.substr(0,4) == 'http') - { - this.image.attr('src', _image); - } - else - { - this.image.hide(); - } - } - - /** - * Overwritten to maintain an internal clicked attribute - * - * @param _ev - * @returns {Boolean} - */ - click(_ev) - { - // ignore click on readonly button - if (this.options.readonly) return false; - - this.clicked = true; - - if (!super.click(_ev)) - { - this.clicked = false; - return false; - } - this.clicked = false; - return true; - } - - onselect(event, selected_node) - { - this.set_value(selected_node.attr("data-id")); - this.change(selected_node); - } - - attachToDOM() - { - let res = super.attachToDOM(); - - // Move the parent's handler to the button, or we can't tell the difference between the clicks - jQuery(this.node).unbind("click.et2_baseWidget"); - this.button.off().bind("click.et2_baseWidget", this, function(e) { - return e.data.click.call(e.data, this); - }); - return res; - } - - set_label(_value) - { - if (this.button) - { - this.label = _value; - - this.button.text(_value) - .prepend(this.image); - } - } - - /** - * Set the options for the dropdown - * - * @param options Object ID => Label pairs - */ - set_select_options(options) { - this.menu.first().empty(); - - // Allow more complicated content, if passed - if(typeof options == "string") - { - this.menu.append(options); - } - else - { - let add_complex = function(node, options) - { - for(let key in options) - { - let item; - if(typeof options[key] == "string") - { - item = jQuery("
  • "+options[key]+"
  • "); - } - else if (options[key]["label"]) - { - item =jQuery("
  • "+options[key]["label"]+"
  • "); - } - // Optgroup - else - { - item = jQuery("
  • "+key+"
  • "); - add_complex(node.append("
      "), options[key]); - } - node.append(item); - if(item && options[key].icon) - { - // we supply a applicable class for item images - jQuery('a',item).prepend(''); - } - } - } - add_complex(this.menu.first(), options); - } - this.menu.menu("refresh"); - } - - /** - * Set tab index - */ - set_tabindex(index) - { - jQuery(this.button).attr("tabindex", index); - } - - set_value(new_value) - { - let menu_item = jQuery("[data-id='"+new_value+"']",this.menu); - if(menu_item.length) - { - this.value = new_value; - if(this.label_updates) - { - this.set_label(menu_item.text()); - } - } - else - { - this.value = null; - if(this.label_updates) - { - this.set_label(this.options.label); - } - } - } - - getValue() - { - return this.value; - } - - /** - * Set options.readonly - * - * @param {boolean} _ro - */ - set_readonly(_ro : boolean) - { - if (_ro != this.options.readonly) - { - this.options.readonly = _ro; - - // don't make readonly dropdown buttons clickable - if (this.buttons) - { - this.buttons.find('button') - .toggleClass('et2_clickable', !_ro) - .toggleClass('et2_button_ro', _ro) - .css('cursor', _ro ? 'default' : 'pointer'); - } - } - } -} -et2_register_widget(et2_dropdown_button, ["dropdown_button"]); \ No newline at end of file diff --git a/api/js/etemplate/et2_widget_favorites.ts b/api/js/etemplate/et2_widget_favorites.ts deleted file mode 100644 index 5f61e3c785..0000000000 --- a/api/js/etemplate/et2_widget_favorites.ts +++ /dev/null @@ -1,433 +0,0 @@ -/** - * EGroupware eTemplate2 - JS Favorite widget - * - * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License - * @package etemplate - * @subpackage api - * @link https://www.egroupware.org - * @author Nathan Gray - * @copyright Nathan Gray 2013 - */ - -/*egw:uses - et2_dropdown_button; - et2_extension_nextmatch; -*/ - -import {WidgetConfig} from "./et2_core_widget"; -import {et2_INextmatchHeader} from "./et2_extension_nextmatch"; -import {et2_dropdown_button} from "./et2_widget_dropdown_button"; -import {ClassWithAttributes} from "./et2_core_inheritance"; -import {egw, egw_getFramework} from "../jsapi/egw_global"; -import Sortable from 'sortablejs/modular/sortable.complete.esm.js'; - -/** - * Favorites widget, designed for use with a nextmatch widget - * - * The primary control is a split/dropdown button. Clicking on the left side of the button filters the - * nextmatch list by the user's default filter. The right side of the button gives a list of - * saved filters, pulled from preferences. Clicking a filter from the dropdown list sets the - * filters as saved. - * - * Favorites can also automatically be shown in the sidebox, using the special ID favorite_sidebox. - * Use the following code to generate the sidebox section: - * display_sidebox($appname,lang('Favorites'),array( - * array( - * 'no_lang' => true, - * 'text'=>'', - * 'link'=>false, - * 'icon' => false - * ) - * )); - * This sidebox list will be automatically generated and kept up to date. - * - * - * Favorites are implemented by saving the values for [column] filters. Filters are stored - * in preferences, with the name favorite_. The favorite favorite used for clicking on - * the filter button is stored in nextmatch--favorite. - * - * @augments et2_dropdown_button - */ -export class et2_favorites extends et2_dropdown_button implements et2_INextmatchHeader -{ - static readonly _attributes : any = { - "default_pref": { - "name": "Default preference key", - "type": "string", - "description": "The preference key where default favorite is stored (not the value)" - }, - "sidebox_target": { - "name": "Sidebox target", - "type": "string", - "description": "ID of element to insert favorite list into", - "default": "favorite_sidebox" - }, - "app": { - "name": "Application", - "type": "string", - "description": "Application to show favorites for" - }, - "filters": { - "name": "Extra filters", - "type": "any", - "description": "Array of extra filters to include in the saved favorite" - }, - - // These are particular to favorites - id: {"default": "favorite"}, - label: {"default": ""}, - label_updates: { "default": false}, - image: {"default": egw().image('fav_filter')}, - statustext: {"default": "Favorite queries", "type": "string"} - }; - - // Some convenient variables, used in closures / event handlers - header = null; - nextmatch = null; - public static readonly PREFIX = "favorite_"; - private stored_filters: {}; - private favSortedList : any = null; - private sidebox_target : JQuery = null; - private preferred; - static is_admin : boolean; - private filters : any; - - // If filter was set server side, we need to remember it until nm is created - nm_filter = false; - - /** - * Constructor - * - * @memberOf et2_favorites - */ - constructor(_parent?, _attrs? : WidgetConfig, _child? : object) - { - super(_parent, _attrs, ClassWithAttributes.extendAttributes(et2_favorites._attributes, _child || {})); - this.sidebox_target = jQuery("#"+this.options.sidebox_target); - if(this.sidebox_target.length == 0 && egw_getFramework() != null) - { - let egw_fw = egw_getFramework(); - this.sidebox_target = jQuery("#"+this.options.sidebox_target,egw_fw.sidemenuDiv); - } - // Store array of sorted items - this.favSortedList = ['blank']; - - let apps = egw().user('apps'); - et2_favorites.is_admin = (typeof apps['admin'] != "undefined"); - - // Make sure we have an app - if(!this.options.app) - { - this.options.app = this.getInstanceManager().app; - } - - this.stored_filters = this.load_favorites(this.options.app); - - this.preferred = egw.preference(this.options.default_pref,this.options.app); - if(!this.preferred || typeof this.stored_filters[this.preferred] == "undefined") - { - this.preferred = "blank"; - } - - // It helps to have the ID properly set before we get too far - this.set_id(this.id); - - this.init_filters(this); - - this.menu.addClass("favorites"); - - // Set the default (button) value - this.set_value(this.preferred,true); - - let self = this; - - // Add a listener on the radio buttons to set default filter - jQuery(this.menu).on("click","input:radio", function(event){ - // Don't do the menu - event.stopImmediatePropagation(); - - // Save as default favorite - used when you click the button - self.egw().set_preference(self.options.app,self.options.default_pref,jQuery(this).val()); - self.preferred = jQuery(this).val(); - - // Update sidebox, if there - if(self.sidebox_target.length) - { - jQuery("div.ui-icon-heart", self.sidebox_target) - .replaceWith("
      "); - jQuery("li[data-id='"+self.preferred+"'] div.sideboxstar",self.sidebox_target) - .replaceWith("
      "); - } - - // Close the menu - self.menu.hide(); - - // Some user feedback - self.button.addClass("ui-state-active", 500,"swing",function(){ - self.button.removeClass("ui-state-active",2000); - }); - }); - - //Sort DomNodes of sidebox fav. menu - let sideBoxDOMNodeSort = function (_favSList) { - let favS = jQuery.isArray(_favSList)?_favSList.slice(0).reverse():[]; - - for (let i=0; i < favS.length;i++) - { - self.sidebox_target.children().find('[data-id$="' + favS[i] + '"]').prependTo(self.sidebox_target.children()); - } - }; - - /** - * todo (@todo-jquery-ui): the sorting does not work at the moment becuase of jquery-ui menu being used in order to create dropdown - * buttons menu. Once we replace the et2_widget_dropdown_button with web component this should be adapted - * and working again. - **/ - let sortablejs = Sortable.create(this.menu[0], { - ghostClass: 'ui-fav-sortable-placeholder', - draggable: 'li:not([data-id$="add"])', - delay: 25, - dataIdAttr:'data-id', - onSort: function(event){ - self.favSortedList = sortablejs.toArray(); - self.egw.set_preference(self.options.app,'fav_sort_pref', self.favSortedList ); - sideBoxDOMNodeSort(self.favSortedList); - } - }); - - // Add a listener on the delete to remove - this.menu.on("click","div.ui-icon-trash", app[self.options.app], function() { - // App instance might not be ready yet, so don't bind directly - app[self.options.app].delete_favorite.apply(this,arguments); - }) - // Wrap and unwrap because jQueryUI styles use a parent, and we don't want to change the state of the menu item - // Wrap in a span instead of a div because div gets a border - .on("mouseenter","div.ui-icon-trash", function() {jQuery(this).wrap("");}) - .on("mouseleave","div.ui-icon-trash", function() {jQuery(this).unwrap();}); - - // Trigger refresh of menu options now that events are registered - // to update sidebox - if(this.sidebox_target.length > 0) - { - this.init_filters(this); - } - } - - /** - * Load favorites from preferences - * - * @param app String Load favorites from this application - */ - load_favorites(app) - { - - // Default blank filter - let stored_filters : any = { - 'blank': { - name: this.egw().lang("No filters"), - state: {} - } - }; - - // Load saved favorites - let preferences : any = egw.preference("*",app); - for(let pref_name in preferences) - { - if(pref_name.indexOf(et2_favorites.PREFIX) == 0 && typeof preferences[pref_name] == 'object') - { - let name = pref_name.substr(et2_favorites.PREFIX.length); - stored_filters[name] = preferences[pref_name]; - // Keep older favorites working - they used to store nm filters in 'filters',not state - if(preferences[pref_name]["filters"]) - { - stored_filters[pref_name]["state"] = preferences[pref_name]["filters"]; - } - } - if (pref_name == 'fav_sort_pref') - { - this.favSortedList = preferences[pref_name]; - //Make sure sorted list is always an array, seems some old fav are not array - if (!jQuery.isArray(this.favSortedList)) this.favSortedList = this.favSortedList.split(','); - } - } - if(typeof stored_filters == "undefined" || !stored_filters) - { - stored_filters = {}; - } - else - { - for(let name in stored_filters) - { - if (this.favSortedList.indexOf(name) < 0) - { - this.favSortedList.push(name); - } - } - this.egw().set_preference (this.options.app,'fav_sort_pref',this.favSortedList); - if (this.favSortedList.length > 0) - { - let sortedListObj = {}; - - for (let i=0; i < this.favSortedList.length; i++) - { - if (typeof stored_filters[this.favSortedList[i]] != 'undefined') - { - sortedListObj[this.favSortedList[i]] = stored_filters[this.favSortedList[i]]; - } - else - { - this.favSortedList.splice(i,1); - this.egw().set_preference (this.options.app,'fav_sort_pref',this.favSortedList); - } - } - stored_filters = jQuery.extend(sortedListObj,stored_filters); - } - } - return stored_filters; - } - - // Create & set filter options for dropdown menu - init_filters(widget, filters?) - { - if(typeof filters == "undefined") - { - filters = this.stored_filters; - } - - let options = {}; - for(let name in filters) - { - options[name] = ""+ - (filters[name].name != undefined ? filters[name].name : name) + - (filters[name].group != false && !et2_favorites.is_admin || name == 'blank' ? "" : - "
      "); - } - - // Only add 'Add current' if we have a nextmatch - if(this.nextmatch) - { - options["add"] = ""+this.egw().lang('Add current'); - } - widget.set_select_options.call(widget,options); - - // Set radio to current value - jQuery("input[value='"+ this.preferred +"']:radio", this.menu).attr("checked",1); - } - - set_nm_filters(filters) - { - if(this.nextmatch) - { - this.nextmatch.applyFilters(filters); - } - else - { - console.log(filters); - } - } - - onclick(node) - { - // Apply preferred filter - make sure it's an object, and not a reference - if(this.preferred && this.stored_filters[this.preferred]) - { - // use app[appname].setState if available to allow app to overwrite it (eg. change to non-listview in calendar) - if (typeof app[this.options.app] != 'undefined') - { - app[this.options.app].setState(this.stored_filters[this.preferred]); - } - else - { - this.set_nm_filters(jQuery.extend({},this.stored_filters[this.preferred].state)); - } - } - else - { - alert(this.egw().lang("No default set")); - } - } - - // Apply the favorite when you pick from the list - change(selected_node) - { - this.value = jQuery(selected_node).attr("data-id"); - if(this.value == "add" && this.nextmatch) - { - // Get current filters - let current_filters = jQuery.extend({},this.nextmatch.activeFilters); - - // Add in extras - for(let extra in this.options.filters) - { - // Don't overwrite what nm has, chances are nm has more up-to-date value - if(typeof current_filters == 'undefined') - { - current_filters[extra] = this.nextmatch.options.settings[extra]; - } - } - - // Skip columns for now - delete current_filters.selcolumns; - - // Add in application's settings - if(this.filters != true) - { - for(let i = 0; i < this.filters.length; i++) - { - current_filters[this.options.filters[i]] = this.nextmatch.options.settings[this.options.filters[i]]; - } - } - - // Call framework - app[this.options.app].add_favorite(current_filters); - - // Reset value - this.set_value(this.preferred,true); - } - else if (this.value == 'blank') - { - // Reset filters when select no filters - this.set_nm_filters({}); - } - } - - set_value(filter_name, parent? : boolean) : void | boolean - { - if(parent) - { - return super.set_value(filter_name); - } - - if(filter_name == 'add') return false; - - app[this.options.app].setState(this.stored_filters[filter_name]); - return false; - } - - getValue() - { - return null; - } - - /** - * Set the nextmatch to filter - * From et2_INextmatchHeader interface - * - * @param {et2_nextmatch} nextmatch - */ - setNextmatch(nextmatch) - { - this.nextmatch = nextmatch; - - if(this.nm_filter) - { - this.set_value(this.nm_filter); - this.nm_filter = false; - } - - // Re-generate filter list so we can add 'Add current' - this.init_filters(this); - } -} - diff --git a/api/js/etemplate/etemplate2.ts b/api/js/etemplate/etemplate2.ts index 2082e0bea7..3f79328276 100644 --- a/api/js/etemplate/etemplate2.ts +++ b/api/js/etemplate/etemplate2.ts @@ -112,9 +112,7 @@ import './et2_widget_radiobox'; import './et2_widget_date'; import './et2_widget_dialog'; import './et2_widget_diff'; -import './et2_widget_dropdown_button'; import './et2_widget_styles'; -import './et2_widget_favorites'; import './et2_widget_html'; import './et2_widget_htmlarea'; import './et2_widget_taglist'; diff --git a/api/js/jsapi/app_base.js b/api/js/jsapi/app_base.js index cf53a281dd..b411ae8415 100644 --- a/api/js/jsapi/app_base.js +++ b/api/js/jsapi/app_base.js @@ -8,19 +8,15 @@ * @author Nathan Gray */ -/*egw:uses - egw_inheritance; - /api/js/es6-promise.min.js; -*/ import {EgwApp} from "./egw_app"; import './egw_inheritance.js'; import {etemplate2} from "../etemplate/etemplate2"; import {et2_createWidget} from "../etemplate/et2_core_widget"; import {Et2Dialog} from "../etemplate/Et2Dialog/Et2Dialog"; import {et2_nextmatch} from "../etemplate/et2_extension_nextmatch"; -import {et2_favorites} from "../etemplate/et2_widget_favorites"; import {EGW_KEY_ENTER} from "../egw_action/egw_action_constants"; import "sortablejs/Sortable.min.js"; +import {Et2Favorites} from "../etemplate/Et2Favorites/Et2Favorites"; /** * Common base class for application javascript @@ -736,7 +732,7 @@ export const AppJS = (function(){ "use strict"; return Class.extend( et2[i].widgetContainer.iterateOver(function(_widget) { _widget.stored_filters = _widget.load_favorites(self.appname); _widget.init_filters(_widget); - }, self, et2_favorites); + }, self, Et2Favorites); } } else diff --git a/api/js/jsapi/egw_app.ts b/api/js/jsapi/egw_app.ts index f61563e57c..4184bdbb23 100644 --- a/api/js/jsapi/egw_app.ts +++ b/api/js/jsapi/egw_app.ts @@ -14,13 +14,13 @@ import {etemplate2} from "../etemplate/etemplate2"; import type {et2_container} from "../etemplate/et2_core_baseWidget"; import {et2_nextmatch} from "../etemplate/et2_extension_nextmatch"; import {et2_createWidget} from "../etemplate/et2_core_widget"; -import {et2_favorites} from "../etemplate/et2_widget_favorites"; import type {IegwAppLocal} from "./egw_global"; import Sortable from 'sortablejs/modular/sortable.complete.esm.js'; import {et2_valueWidget} from "../etemplate/et2_core_valueWidget"; import {nm_action} from "../etemplate/et2_extension_nextmatch_actions"; import {Et2Dialog} from "../etemplate/Et2Dialog/Et2Dialog"; import {EGW_KEY_ENTER} from "../egw_action/egw_action_constants"; +import {Et2Favorites} from "../etemplate/Et2Favorites/Et2Favorites"; /** * Type for push-message @@ -973,7 +973,7 @@ export abstract class EgwApp { _widget.stored_filters = _widget.load_favorites(self.appname); _widget.init_filters(_widget); - }, self, et2_favorites); + }, self, Et2Favorites); } } else diff --git a/filemanager/templates/default/index.xet b/filemanager/templates/default/index.xet index a74acde798..d066dc588b 100644 --- a/filemanager/templates/default/index.xet +++ b/filemanager/templates/default/index.xet @@ -57,7 +57,7 @@