I am using dynamic MenuContribution and get a warning that two of my referenced identifiers "cannot be found". Even though the contribution works. These warnings bug me.
I have a CompoundContributionItem implementation defined in one of my plugins. Basically it looks like this:
public class ViewerHistoryMenuItems extends CompoundContributionItem
implements IExecutableExtension {
private static final String PARAM_TYPE = "type";
private static final String PARAM_COMMAND = "command";
// some fields
public void setInitializationData(final IConfigurationElement config,
final String propertyName, final Object data) {
/* set fields */
}
protected final IContributionItem[] getContributionItems() {
/* create Items */
}
}
In other plugins I use this ContributionItem implementation by declaring the following:
<menuContribution locationURI="menu:mylocationUri">
<dynamic id="myId">
<class class="ViewerHistoryMenuItems">
<parameter
name="type"
value="someValue">
</parameter>
<parameter
name="command"
value="someCommandId">
</parameter>
</class>
</dynamic>
<command
commandId="someCommandId"
icon="anIcon.png">
</command>
</menuContribution>
When looking at the Problems-View I get two entries there (for each plug-in, which uses this contribution):
**Referenced identifier 'type' in attribute 'name' cannot be found**
**Referenced identifier 'command' in attribute 'name' cannot be found**
What am I missing here? Any ideas, why I get this warning?
PS: It doesn't help, to make the two fields PARAM_TYPE & PARAM_COMMAND public
I do not think this is related to the presence of internal fields within a class.
If you look at a similar error (not the same since it includes annotationType), the correction involved the definition of said Referenced identifier:
Referenced identifier 'com.atlassian.connector.eclipse.cruicible.ui.comment.annotation'
in attribute 'annotationType' cannot be found
Fixed with:
+ <extension
+ point="org.eclipse.ui.editors.annotationTypes">
+ <type
+ markerType="com.atlassian.connector.eclipse.crucible.ui.com.atlassian.connector.eclipse.cruicible.ui.comment.marker"
+ name="com.atlassian.connector.eclipse.cruicible.ui.comment.annotation">
+ </type>
+ </extension>
+ <extension
+ id="com.atlassian.connector.eclipse.cruicible.ui.comment.marker"
+ point="org.eclipse.core.resources.markers">
+ </extension>
Considering the extension point org.eclipse.ui.menus help page:
<!ELEMENT parameter EMPTY>
<!ATTLIST parameter
name IDREF #REQUIRED
value CDATA #REQUIRED
>
A parameter to either an executable extension or a command -- depending on where it appears in the extension.
name - The name is either the name of the parameter to pass to the executable extension, or the identifier of the parameter for the command.
value - The value to pass for this parameter.
You need to reference in the name attribute an id present somewhere else in your plugin.xml.
Sure thing, VonC. Here we go:
Within the dynamic declaration (see above) there are two parameter references
<parameter
name="type"
value="someValue">
</parameter>
<parameter
name="command"
value="someCommandId">
</parameter>
These two parameter are meant to be passed to the command itself. The command declaration is within the same plugin.xml but wasn't declaring these two commandParameters.
What I did was adding these missing commandParameters, resolving the missing reference, which was clearly stated by the warning.
<command
categoryId="aCategory"
id="someCommandId"
name="%theName">
<commandParameter
id="type"
name="type"/>
<commandParameter
id="command"
name="command">
</commandParameter>
</command>
So, you were absolutely right by saying "the correction involved the definition of said reference identifier". The question just was where and what I had to define.
I think, I wasn't thinking about the most obvious in this case.
Related
I would like to use:
<core:Icon src="{path: 'STATUS', formatter: '.formatter.getTableStatusIcon'}" />
But I get this error when I use it:
Element sap.ui.core.Icon#__icon0-__clone600: Property 'src' (value: '') should be a valid Icon URI (sap-icon://...)
Instead of an empty string, return null.
getTableStatusIcon: function(status) {
// ...
return null; // default value of the Icon src
},
Or in case of an expression binding in XML view:
<core:Icon src="{= <my condition> ? ${myIconUri} : null}" />
This won't trigger the assert message because null and undefined are used for resetting Control's property value (i.e.: no icon), which I assume you were trying to do by passing an empty string.
The message was first introduced in 1.56 in order to discourage developers from assigning the icon name only (e.g. "edit" instead of "sap-icon://edit"):
Although it is not mentioned in the API, the 'src' property also
accepted a[n] icon name of the default collection as value instead of the
documented Icon URI (IconPool.getIconURI).
This is was caused by 867c4c6 and works
again, but is still not recommended. Therefore an assertion is added. (Source)
I need to write a dynamic Attribute name instead of hardcode of Name attribute in dataweave 2.0 mulesoft 4 in anypointstudio
<?xml version="1.0" encoding="UTF-8"?>
<iGoApplicationData>
<UserData>
<Data Name="UpdateUserProfile">True</Data>
<Data Name="Action">??</Data>
</iGoApplicationData>
So in order to generate an XML like yours the DW structure will look like
{
iGoApplicationData: {
UserData: {
Data #(Name: payload.foo): "True",
Data #((var.attributeName): "Action"): "??"
}
}
}
So in this example I show how to specify a value in the attribute or a dynamic attribute name. For the dynamic attribute value just type the expression on the value side of the attribute (the part that goes after the :)
For dynamic attribute name you need to wrap the expression between parenthesis. When the name is wrapped between parenthesis it is considered dynamic. This applies to object keys and attributes names
\Templates\Snippets\Search.html
<f:form id="snippetSearchForm"
action="search"
controller="Snippets"
extensionName="snippet_highlight_syntax"
pluginName="feshs"
name="searchSnippets"
method="POST"
pageType="5513">
<f:form.textfield class="form-control" property="searchWords"/>
<f:form.submit id="searchBtn" value="Search"/>
</f:form>
SnippetsController.php
public function searchAction()
{
$arguments = $this->request->getArguments();
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($arguments);
}
ajax.js
$("#snippetSearchForm").submit(function (event) {
event.preventDefault();
var form = $(this);
var action = form.attr("action"),
method = form.attr("method"),
data = form.serialize();
$.ajax({
url: action,
type: method,
data: data,
cache: false
}).done(function (data) {
console.log(data);
}).fail(function () {
( "div.tx-feshs" ).replaceWith("errorMessage");
}).always(function () {
});
});
Request URL
index.php?id=148&type=5513&tx_snippet_highlight_syntax_feshs[action]=search&tx_snippet_highlight_syntax_feshs[controller]=Snippets&cHash=4662b6b5a3fa0dc4e590e8d5c90fa
I can't solve this problem with getArguments(). The response and console.log are (empty). Seems like I'm missing something but I can't pinpoint where :/
You have a few common errors in your code and most of them has already been mentioned here, but please allow me to sum up.
Extension key/name
First, a lot of people confuses extension name with extension key. The directory name of your extension is your extension key, in this case snippet_highlight_syntax. The extension key is used all over TYPO3 as the unique identifier of your extension. With Extbase a new convention did come along called extension name to satisfy PSR2 coding convention and is primarily used in Extbase context. The extension name is a upper camel case edition of your extension key.
ExtbaseFluidBook: CodingGuidelines - It´s a bid old but still valid
The name of the extension in UpperCamelCase. For example, if the extension-key is blog_example, then this part of the classname is BlogExample.
Extension key: snippet_highlight_syntax
Extension name: SnippetHighlightSyntax
Be aware of what the TYPO3/Extbase framework asks for, key or name - it will help you a lot.
Plugin name
You have also declared a plugin named feshs. According to the DocBlock documentation of both \TYPO3\CMS\Extbase\Utility\ExtensionUtility::(configure|register)Plugin() methods it should, as with the extension name, be in upper camel case format like Feshs. It´s not well documented and I do not think it has any negative impacted on your application jet but now you knows and has a change to future proof your application by correcting it.
/**
* ...
*
* #param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
* #param string $pluginName must be a unique id for your plugin in UpperCamelCase (the string length of the extension key added to the length of the plugin name should be less than 32!)
* #param array $controllerActions is an array of allowed combinations of controller and action stored in an array (controller name as key and a comma separated list of action names as value, the first controller and its first action is chosen as default)
* #param array $nonCacheableControllerActions is an optional array of controller name and action names which should not be cached (array as defined in $controllerActions)
* #param string $pluginType either \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_PLUGIN (default) or \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
* #throws \InvalidArgumentException
*/
public static function configurePlugin($extensionName, $pluginName, array $controllerActions, array $nonCacheableControllerActions = [], $pluginType = self::PLUGIN_TYPE_PLUGIN)
Plugin signature
Together with your extension name it will form a plugin signature called snippethighlightsyntax_feshs. This signature is the valued stored in the tt_content database table as list_type or ctype depending of the plugin configuration.
The plugin signature is further used in TypoScript and GET/POST arguments prefixed with tx_. In your case tx_snippethighlightsyntax_feshs.
Fluid & Extbase forms
In your form snippet you have declared a element <f:form:textfield /> with the property tag. The property tag is only used together with the object and objectName tags on the <f:form /> element and is used to bind values to this objects properties (autofill, validation result etc.).
See \TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper::initializeArguments.
Name of Object Property. If used in conjunction with <f:form object="...">, "name" and "value" properties will be ignored.
In your case you should properly just use name in stead of property.
Your updated form should look something like below:
<f:form id="snippetSearchForm"
action="search"
controller="Snippets"
extensionName="SnippetHighlightSyntax"
pluginName="Feshs"
method="POST"
pageType="5513">
<f:form.textfield class="form-control" name="searchWords"/>
<f:form.submit id="searchBtn" value="Search"/>
</f:form>
Controller arguments
You should declare your arguments as controller arguments.
/**
* #param string $searchWords
*/
public function searchAction(string $searchWords = null)
{
if (is_string($searchWords)) {
// TODO: Do something here...
}
}
Note how I have given the argument a default value. This should suppress the error Required argument "searchWords" is not set for... you are getting.
This was a long write up. Hopes it helps your or some others.
Happy coding
$this->request->getArguments() will only return field value arguments that are prefixed with the extensions / plugins identifier like tx_anything_pi1[anything]
Please checkout if the "name"-tag of the fields is correct. Maybe those tags are wrong because you are reffering to a "property" of an object in your textfield but there is no object bound to your f:form tag.
Since the response should at least return the HTML of an empty debug, maybe something is wrong with your action. Can you call it in the browser?
First of all use name attribute instead of property in <f:form.textfield> tag.
Then you need to register argument as follows
public function searchAction(string $searchWords)
Furthermore PHP docblock must contain the parameter as #param string $searchWords. After clearing all caches in the Install Tool you should get your arguments.
Assumed your extension-key (=foldername) is "snippet_highlight_syntax" the parameter for URLs is usually like this:
tx_snippethighlightsyntax_feshs
That means all underscores of the extension-key are removed.
Probably it's possible to make it different, but that's not standard.
Therefore $this->request->getArguments() never returns anything.
You've to adjust the parameters in the url like this:
index.php?id=148&type=5513&tx_snippethighlightsyntax_feshs[action]=search&tx_snippethighlightsyntax_feshs[controller]=Snippets&cHash=4662b6b5a3fa0dc4e590e8d5c90fa
In the TypoScript-Object-Browser you should find your plugin with that name:
plugin.tx_snippethighlightsyntax_feshs
After many tries, I've sent the extension to test on another computer and it's working.
I've cleared all the caches, disabled/enabled, and so on. Seems like my environment is at fault.
Thanks to all of you for the help !
I am trying to write an AppleScript that calls my Swift application to get a value. The method takes a string and needs to return another string.
Here is my .SDF file:
<suite name="My Suite" code="MySU" description="My AppleScript suite.">
<class name="application" code="capp" description="An application's top level scripting object.">
<cocoa class="NSApplication"/>
<element type="my types" access="r">
<cocoa key="types"/>
</element>
</class>
<command name="my command" code="MyCOMMND" description="My Command">
<parameter name="with" code="MyPR" description="my Parameter" type="text">
<cocoa key="myParameter"/>
</parameter>
<result type="text" description="the return value"/>
<cocoa method="myCommand:"/>
</command>
</suite>
The corresponding Swift code is fairly simple:
func myCommand(_ command: NSScriptCommand) -> String
{
if let myParameter = command.evaluatedArguments?["myParameter"] as? String
{
return "Hello World!"
}
else
{
return "Nothing happening here. Move on."
}
}
and finally my AppleScript is here:
tell application "MyApp"
set r to my command with "Hello"
end tell
When I execute the AppleScript it recognises my command, but it does not call the Swift code that I've tried to associate with it. Neither Xcode or AppleScript report a problem. Have I misses something out or put my code in the wrong place?
For this sort of scripting I would recommend a command-first (aka verb-first) approach rather than the object-first approach you are attempting. Your sdef would look like this (replacing "MyProject" with the name of your project, i.e. your application's Swift module name):
<dictionary xmlns:xi="http://www.w3.org/2003/XInclude">
<suite name="My Suite" code="MySU" description="My AppleScript suite.">
<command name="my command" code="MySUCMND" description="My Command">
<cocoa class="MyProject.MyCommand"/>
<parameter name="with" code="MyPR" description="my Parameter" type="text">
<cocoa key="myParameter"/>
</parameter>
<result type="text" description="the return value"/>
</command>
</suite>
</dictionary>
The MyCommand class should look like this:
class MyCommand : NSScriptCommand {
override func performDefaultImplementation() -> Any? {
if let _ = self.evaluatedArguments?["myParameter"] as? String
{
return "Hello World!"
}
else
{
return "Nothing happening here. Move on."
}
}
}
The "ModuleName.ClassName" sdef tip comes from Swift NSScriptCommand performDefaultImplementation
Goal
I am trying to make my Cocoa Application that has been written in Swift scriptable from Applescript.
What I've Done
I have created a SDEF file, configured my info.plist and created a class which I think is appropriate.
definition.sdef
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
<dictionary title="SamX">
<!-- specific suite(s) for the application follow... -->
<suite name="SamX Scripting Suite" code="Samx" description="Suite for communication with the application">
<command name="savedoc" code="corecnte" description="description">
<cocoa class="ProjectName.ScriptingSaveNotification" id="BLah"/>
<parameter name="with dname" code="WTdc" type="text" optional="no" description="description">
<cocoa key="DocumentName"/>
</parameter>
<result type="boolean" description="The result of the invocation. True if it succeeds, False if it does not"/>
</command>
</suite>
</dictionary>
info.plist
ScriptingSaveNotification.swift
import Foundation
import Cocoa
class ScriptingSaveNotification: NSScriptCommand, NSUserNotificationCenterDelegate {
override func performDefaultImplementation() -> AnyObject? {
let parms = self.evaluatedArguments
var name = ""
if let args = parms {
if let DocumentName = args["DocumentName"] as? String {
name = DocumentName
}
}
debugPrint("We were prompted to save");
return "hello world"
}
func userNotificationCenter(center: NSUserNotificationCenter, shouldPresentNotification notification: NSUserNotification) -> Bool {
debugPrint("We were prompted to save");
return true
}
}
Where I Am
I have an application that launches. The application's SDEF file appears to be reflecting in the Applescript Editor. The Applescript editors also returns a dictionary definition. However when I run the command, I always get an output of 5 (int), and none of my debug lines appears to be outputting in Xcode.
It appears to me that maybe I'm referencing my class in the SDEF improperly. But I'm not 100% sure. I've tried renaming it several times. Any help would be greatly appreciated.
Applescript Dictionary
Test Script
tell application "MyApplication"
set testString to "Hello"
set returnValue to savedoc testString
display alert returnValue
end tell
Edit:
The main issue is that you don't actually use the with dname parameter in your script. It should be:
set returnValue to savedoc with dname testString
That said, the info below is still valid for creating a proper sdef and the other suggestions/examples may be helpful.
This is a basic example of passing a string in the evaluatedArguments of the NSScriptCommand and then returning that string as the result of the script command in Swift (you could return a boolean on success/failure of the command or any other type of result; and, actually, in your sdef you say you're going to return a boolean but your command is returning a string (text in sdef definitions)). Creating your sdef can be tricky. Your command's code should start with the suite's code and you can remove the id and optional parameter (if you omit the optional parameter, the default is that the parameter is required). If you do just need a single parameter you could also just use the direct-parameter instead.
You can download a demo project:
ScriptableSwift.zip
Here are the relevant bits (aside from the plist entries that you have correct in your tests).
ScriptableSwift.sdef
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
<dictionary title="ScriptableSwift Terminology">
<suite name="ScriptableSwift Scripting Suite" code="SSss" description="Standard suite for application communication.">
<command name="save" code="SSssSave" description="Save something.">
<cocoa class="ScriptableSwift.SaveScriptCommand"/>
<parameter name="in" code="Fpat" type="text" description="The file path in which to save the document.">
<cocoa key="FilePath"/>
</parameter>
<result type="text" description="Echoes back the filepath supplied."/>
</command>
</suite>
</dictionary>
SaveScriptCommand.swift
import Foundation
import Cocoa
class SaveScriptCommand: NSScriptCommand {
override func performDefaultImplementation() -> AnyObject? {
let filePath = self.evaluatedArguments!["FilePath"] as! String
debugPrint("We were prompted to save something at: \(filePath)");
return filePath
}
}
Test AppleScript
tell application "ScriptableSwift" to save in "path/to/file"
Result:
"path/to/file"