diff --git a/core/language/en-GB/ControlPanel.multids b/core/language/en-GB/ControlPanel.multids index 7adf4aa04..2c41f215e 100644 --- a/core/language/en-GB/ControlPanel.multids +++ b/core/language/en-GB/ControlPanel.multids @@ -175,6 +175,8 @@ Settings/NavigationPermalinkviewMode/UpdateAddressBar/Description: Update addres Settings/PerformanceInstrumentation/Caption: Performance Instrumentation Settings/PerformanceInstrumentation/Hint: Displays performance statistics in the browser developer console. Requires reload to take effect Settings/PerformanceInstrumentation/Description: Enable performance instrumentation +Settings/RecentLimit/Caption: Recent Tab Limit +Settings/RecentLimit/Hint: Maximum number of tiddlers to be displayed under the sidebar "Recent" tab Settings/ToolbarButtonStyle/Caption: Toolbar Button Style Settings/ToolbarButtonStyle/Hint: Choose the style for toolbar buttons: Settings/ToolbarButtonStyle/Styles/Borderless: Borderless diff --git a/core/modules/utils/fakedom.js b/core/modules/utils/fakedom.js index fb28465fe..66f2314e2 100755 --- a/core/modules/utils/fakedom.js +++ b/core/modules/utils/fakedom.js @@ -56,36 +56,64 @@ Object.defineProperty(TW_TextNode.prototype, "formattedTextContent", { } }); -var TW_Element = function(tag,namespace) { +var TW_Style = function(el) { + // Define the internal style object + var styleObject = { + // Method to get the entire style object + get: function() { + return el._style; + }, + // Method to set styles using a string (e.g. "color:red; background-color:blue;") + set: function(str) { + var self = this; + str = str || ""; + $tw.utils.each(str.split(";"),function(declaration) { + var parts = declaration.split(":"), + name = $tw.utils.trim(parts[0]), + value = $tw.utils.trim(parts[1]); + if(name && value) { + el._style[$tw.utils.convertStyleNameToPropertyName(name)] = value; + } + }); + }, + // Method to set a specific property without transforming the property name, such as a custom property + setProperty: function(name, value) { + el._style[name] = value; + } + }; + + // Return a Proxy to handle direct access to individual style properties + return new Proxy(styleObject, { + get: function(target, property) { + // If the property exists on styleObject, return it (get, set, setProperty methods) + if (property in target) { + return target[property]; + } + // Otherwise, return the corresponding property from _style + return el._style[$tw.utils.convertStyleNameToPropertyName(property)] || ""; + }, + set: function(target, property, value) { + // Set the property in _style + el._style[$tw.utils.convertStyleNameToPropertyName(property)] = value; + return true; + } + }); +}; + +var TW_Element = function(tag, namespace) { bumpSequenceNumber(this); this.isTiddlyWikiFakeDom = true; this.tag = tag; this.attributes = {}; this.isRaw = false; this.children = []; - this._style = {}; + this._style = {}; // Internal style object + this.style = new TW_Style(this); // Proxy for style management this.namespaceURI = namespace || "http://www.w3.org/1999/xhtml"; }; -Object.setPrototypeOf(TW_Element.prototype,TW_Node.prototype); -Object.defineProperty(TW_Element.prototype, "style", { - get: function() { - return this._style; - }, - set: function(str) { - var self = this; - str = str || ""; - $tw.utils.each(str.split(";"),function(declaration) { - var parts = declaration.split(":"), - name = $tw.utils.trim(parts[0]), - value = $tw.utils.trim(parts[1]); - if(name && value) { - self._style[$tw.utils.convertStyleNameToPropertyName(name)] = value; - } - }); - } -}); +Object.setPrototypeOf(TW_Element.prototype,TW_Node.prototype); Object.defineProperty(TW_Element.prototype, "nodeType", { get: function() { @@ -105,7 +133,7 @@ TW_Element.prototype.setAttribute = function(name,value) { throw "Cannot setAttribute on a raw TW_Element"; } if(name === "style") { - this.style = value; + this.style.set(value); } else { this.attributes[name] = value + ""; } diff --git a/core/modules/widgets/droppable.js b/core/modules/widgets/droppable.js index 0dcba1688..ba54d8860 100644 --- a/core/modules/widgets/droppable.js +++ b/core/modules/widgets/droppable.js @@ -125,11 +125,23 @@ DroppableWidget.prototype.handleDropEvent = function(event) { // Remove highlighting $tw.utils.removeClass(this.domNodes[0],"tc-dragover"); // Try to import the various data types we understand - $tw.utils.importDataTransfer(dataTransfer,null,function(fieldsArray) { - fieldsArray.forEach(function(fields) { - self.performActions(fields.title || fields.text,event); + if(this.droppableActions) { + $tw.utils.importDataTransfer(dataTransfer,null,function(fieldsArray) { + fieldsArray.forEach(function(fields) { + self.performActions(fields.title || fields.text,event); + }); }); - }); + } + // Send a TitleList to performListActions + if(this.droppableListActions) { + $tw.utils.importDataTransfer(dataTransfer,null,function(fieldsArray) { + var titleList = []; + fieldsArray.forEach(function(fields) { + titleList.push(fields.title || fields.text); + }); + self.performListActions($tw.utils.stringifyList(titleList),event); + }); + } // Tell the browser that we handled the drop event.preventDefault(); // Stop the drop ripple up to any parent handlers @@ -137,6 +149,13 @@ DroppableWidget.prototype.handleDropEvent = function(event) { return false; }; +DroppableWidget.prototype.performListActions = function(titleList,event) { + if(this.droppableListActions) { + var modifierKey = $tw.keyboardManager.getEventModifierKeyDescriptor(event); + this.invokeActionString(this.droppableListActions,this,event,{actionTiddlerList: titleList, modifier: modifierKey}); + } +}; + DroppableWidget.prototype.performActions = function(title,event) { if(this.droppableActions) { var modifierKey = $tw.keyboardManager.getEventModifierKeyDescriptor(event); @@ -149,6 +168,7 @@ Compute the internal state of the widget */ DroppableWidget.prototype.execute = function() { this.droppableActions = this.getAttribute("actions"); + this.droppableListActions = this.getAttribute("listActions"); this.droppableEffect = this.getAttribute("effect","copy"); this.droppableTag = this.getAttribute("tag"); this.droppableEnable = (this.getAttribute("enable") || "yes") === "yes"; @@ -168,7 +188,8 @@ Selectively refreshes the widget if needed. Returns true if the widget or any of */ DroppableWidget.prototype.refresh = function(changedTiddlers) { var changedAttributes = this.computeAttributes(); - if(changedAttributes.tag || changedAttributes.enable || changedAttributes.disabledClass || changedAttributes.actions || changedAttributes.effect) { + if(changedAttributes.tag || changedAttributes.enable || changedAttributes.disabledClass || + changedAttributes.actions|| changedAttributes.listActions || changedAttributes.effect) { this.refreshSelf(); return true; } else { diff --git a/core/modules/widgets/genesis.js b/core/modules/widgets/genesis.js index c8403a3d4..299be1e48 100644 --- a/core/modules/widgets/genesis.js +++ b/core/modules/widgets/genesis.js @@ -65,6 +65,16 @@ GenesisWidget.prototype.execute = function() { children: this.parseTreeNode.children || [], isNotRemappable: !this.genesisRemappable }]; + // Apply attributes in $names/$values + this.attributeNames = []; + this.attributeValues = []; + if(this.genesisNames && this.genesisValues) { + this.attributeNames = this.wiki.filterTiddlers(self.genesisNames,this); + this.attributeValues = this.wiki.filterTiddlers(self.genesisValues,this); + $tw.utils.each(this.attributeNames,function(varname,index) { + $tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],varname,self.attributeValues[index] || ""); + }); + } // Apply explicit attributes $tw.utils.each($tw.utils.getOrderedAttributesFromParseTreeNode(this.parseTreeNode),function(attribute) { var name = attribute.name; @@ -79,16 +89,6 @@ GenesisWidget.prototype.execute = function() { } $tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],$tw.utils.extend({},attribute,{name: name})); }); - // Apply attributes in $names/$values - this.attributeNames = []; - this.attributeValues = []; - if(this.genesisNames && this.genesisValues) { - this.attributeNames = this.wiki.filterTiddlers(self.genesisNames,this); - this.attributeValues = this.wiki.filterTiddlers(self.genesisValues,this); - $tw.utils.each(this.attributeNames,function(varname,index) { - $tw.utils.addAttributeToParseTreeNode(parseTreeNodes[0],varname,self.attributeValues[index] || ""); - }); - } // Construct the child widgets this.makeChildWidgets(parseTreeNodes); }; diff --git a/core/modules/widgets/widget.js b/core/modules/widgets/widget.js index b7780e069..c3dbf6df5 100755 --- a/core/modules/widgets/widget.js +++ b/core/modules/widgets/widget.js @@ -440,6 +440,11 @@ Widget.prototype.assignAttributes = function(domNode,options) { destPrefix = options.destPrefix || "", EVENT_ATTRIBUTE_PREFIX = "on"; var assignAttribute = function(name,value) { + // Process any CSS custom properties + if(name.substr(0,2) === "--" && name.length > 2) { + domNode.style.setProperty(name,value); + return; + } // Process any style attributes before considering sourcePrefix and destPrefix if(name.substr(0,6) === "style." && name.length > 6) { domNode.style[$tw.utils.unHyphenateCss(name.substr(6))] = value; diff --git a/core/ui/AdvancedSearch/Filter.tid b/core/ui/AdvancedSearch/Filter.tid index a8baf9d30..7369e4c40 100644 --- a/core/ui/AdvancedSearch/Filter.tid +++ b/core/ui/AdvancedSearch/Filter.tid @@ -2,18 +2,28 @@ title: $:/core/ui/AdvancedSearch/Filter tags: $:/tags/AdvancedSearch caption: {{$:/language/Search/Filter/Caption}} -\define lingo-base() $:/language/Search/ -\define set-next-input-tab(beforeafter:"after") -<$macrocall $name="change-input-tab" +\procedure lingo-base() $:/language/Search/ +\procedure set-next-input-tab() +<$transclude $variable="change-input-tab" stateTitle="$:/state/tab--1498284803" tag="$:/tags/AdvancedSearch" - beforeafter="$beforeafter$" + beforeafter="after" defaultState="$:/core/ui/AdvancedSearch/System" actions="<$action-setfield $tiddler='$:/state/advancedsearch/currentTab' text=<>/>" /> \end -\define cancel-search-actions() +\procedure set-previous-input-tab() +<$transclude $variable="change-input-tab" + stateTitle="$:/state/tab--1498284803" + tag="$:/tags/AdvancedSearch" + beforeafter="before" + defaultState="$:/core/ui/AdvancedSearch/System" + actions="<$action-setfield $tiddler='$:/state/advancedsearch/currentTab' text=<>/>" +/> +\end + +\procedure cancel-search-actions() \whitespace trim <$list filter="[{$:/temp/advancedsearch/input}!match{$:/temp/advancedsearch}]"> <$list-empty> @@ -24,30 +34,30 @@ caption: {{$:/language/Search/Filter/Caption}} \end -\define input-accept-actions() +\procedure input-accept-actions() \whitespace trim <$list filter="[{$:/config/Search/NavigateOnEnter/enable}match[yes]]"> <$list-empty> - <$list filter="[<__tiddler__>get[text]!is[missing]] ~[<__tiddler__>get[text]is[shadow]]"> - <$action-navigate $to={{{ [<__tiddler__>get[text]] }}}/> + <$list filter="[get[text]!is[missing]] :else[get[text]is[shadow]]"> + <$action-navigate $to={{{ [get[text]] }}}/> <$/list-empty> - <$action-navigate $to={{{ [<__tiddler__>get[text]] }}}/> + <$action-navigate $to={{{ [get[text]] }}}/> \end -\define input-accept-variant-actions() +\procedure input-accept-variant-actions() \whitespace trim <$list filter="[{$:/config/Search/NavigateOnEnter/enable}match[yes]]"> <$list-empty> - <$list filter="[<__tiddler__>get[text]!is[missing]] ~[<__tiddler__>get[text]is[shadow]]"> + <$list filter="[get[text]!is[missing]] :else[get[text]is[shadow]]"> <$list filter="[<__tiddler__>get[text]minlength[1]]"> - <$action-sendmessage $message="tm-edit-tiddler" $param={{{ [<__tiddler__>get[text]] }}}/> + <$action-sendmessage $message="tm-edit-tiddler" $param={{{ [get[text]] }}}/> - <$list filter="[<__tiddler__>get[text]minlength[1]]"> - <$action-sendmessage $message="tm-edit-tiddler" $param={{{ [<__tiddler__>get[text]] }}}/> + <$list filter="[get[text]minlength[1]]"> + <$action-sendmessage $message="tm-edit-tiddler" $param={{{ [get[text]] }}}/> \end @@ -58,8 +68,8 @@ caption: {{$:/language/Search/Filter/Caption}}