Whenever a user creates a table in ckeditor 4 and presses the enter key whilst inside a table header (th) it creates a new paragraph. A paragraph inside a th is invalid HTML. Ideally I'd like to disable the enter key whenever the cursor is inside a th.
I'm aware of the enterMode config (changing it to a br or a div instead of a paragraph when enter is pressed) but that doesn't really solve the problem.
I guess I need to hook into the keypress event and then check which element type is the parent of the element in which the cursor is residing? But I'm not sure how to do that.
There is a similar question here but I'm specifically looking to disable the enter key in a particular scenario not just entirely. ckeditor turn off enter key
Any help appreciated, thanks.
I've figured this out, seems to work as I desired:
CKEDITOR.instances.editor1.on('key', function(event) {
var enterKeyPressed = event.data.keyCode === 13;
var isTH = CKEDITOR.instances.editor1.getSelection().getStartElement().$.nodeName === 'TH';
var parentisTH = CKEDITOR.instances.editor1.getSelection().getStartElement().$.parentNode.nodeName === 'TH';
if(enterKeyPressed && isTH || enterKeyPressed && parentisTH) {
event.cancel();
}
});
I would like my app to respond to the F7, F8 and F9 keyboard media control buttons.
I am aware of this lovely library but it is not working in combination with Swift: https://github.com/nevyn/SPMediaKeyTap
I actually solved this problem myself just the other day. I wrote a blog post on it, as well as a Gist
I'll embed the blog post and final code just in case the blog or Gist ever go away. Note: This is a very long post that goes into detail about how the class in constructed and what you can do to call other methods in your App's delegate. If all you want is the finished product (the MediaApplication class), head towards the bottom. It's just above the XML and the Info.plist informaton.
For starters, to get the key events from the media keys you need to create a class that extends NSApplication. This is as simple as
import Cocoa
class MediaApplication: NSApplication {
}
Next, we need to override the sendEvent() function
override func sendEvent(event: NSEvent) {
if (event.type == .SystemDefined && event.subtype.rawValue == 8) {
let keyCode = ((event.data1 & 0xFFFF0000) >> 16)
let keyFlags = (event.data1 & 0x0000FFFF)
// Get the key state. 0xA is KeyDown, OxB is KeyUp
let keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA
let keyRepeat = (keyFlags & 0x1)
mediaKeyEvent(Int32(keyCode), state: keyState, keyRepeat: Bool(keyRepeat))
}
super.sendEvent(event)
}
Now, I don't pretend to entirely understand what is going on here, but I think I have a decent idea. NSEvent objects contain several key properties: type, subtype, data1, and data2. Type and subtype are fairly self-explanatory, but data1 and data2 are extremely vague. Since the code only uses data1, that's what we'll be looking at. From what I can tell, data1 contains all of the data surrounding a key event. That means it contains the key code and any key flags. It appears that key flags contain information about the key's state (Is the key pressed down? Has the key been released?) as well as whether or not the key is being held down and repeating the signal. I'm also guessing that the key code and key flags both take up half of the data contained in data1 and the bitwise operations are separating that data out into appropriate variables. After we get the values we need, we call mediaKeyEvent() which I will get to in a moment. Regardless of what events get sent to our MediaApplication, we do want the default NSApplication to handle all events as well. To do this, we call super.sendEvent(event) at the end of the function. Now, let's take a look at mediaKeyEvent().
func mediaKeyEvent(key: Int32, state: Bool, keyRepeat: Bool) {
// Only send events on KeyDown. Without this check, these events will happen twice
if (state) {
switch(key) {
case NX_KEYTYPE_PLAY:
// Do work
break
case NX_KEYTYPE_FAST:
// Do work
break
case NX_KEYTYPE_REWIND:
// Do work
break
default:
break
}
}
}
This is where things start to get fun. First things first, we only want to check what key is being pressed if state is true, which in this case is whenever the key is pressed down. Once we get into checking the keys, we look for NX_KEYTYPE_PLAY, NX_KEYTYPE_FAST, and NX_KEYTYPE_REWIND. If their functions aren't obvious, NX_KEYTYPE_PLAY is the play/pause key, NX_KEYTYPE_FAST is the next key, and NX_KEYTYPE_REWIND is the previous key. Right now, nothing happens when any of those keys is pressed down, so lets go over some possible logic. We'll start with a simple scenario.
case NX_KEYTYPE_PLAY:
print("Play")
break
With this code in place, when your application detects that the play/pause key has been pressed you will see "Play" printed out to the console. Simple, right? Let's up the ante by calling functions in your application's NSApplicationDelegate. First we will assume that your NSApplicationDelegate has a function called printMessage. We will be modifying it as we go, so pay close attention to the changes. They will be minor, but the changes will impact how you call them from mediaEventKey.
func printMessage() {
print("Hello World")
}
This is the simplest case. When printMessage() is called, you will see "Hello World" in your console. You can call this by calling performSelector on your NSApplicationDelegate which is accessible through the MediaApplication. performSelector takes in a Selector which is just the name of the function in your NSApplicationDelegate.
case NX_KEYTYPE_PLAY:
delegate!.performSelector("printMessage")
break
Now, when your application detects that the play/pause key has been pressed, you will see "Hello World" printed to the console. Let's kick things up a notch with a new version of printMessage that takes in a parameter.
func printMessage(arg: String) {
print(arg)
}
The idea is now that if printMessage("Hello World") is called, you will see "Hello World" in your console. We can now modify the performSelector call to handle passing in a parameter.
case NX_KEYTYPE_PLAY:
delegate!.performSelector("printMessage:", withObject: "Hello World")
break
There are a few things to note about this change. First, it's important to notice the : that was added to the Selector. This separates the function name from the parameter when it gets sent to the delegate. How it works isn't too important to remember, but it's something along the lines of the delegate calling printMessage:"Hello World". I'm fairly certain that is not 100% correct as it would likely use an object ID of some sort, but I haven't done any extensive digging into the specifics. Either way, the important thing to remember is to add : when passing in a parameter.. The second thing to note is that we added a withObject parameter. withObject takes an AnyObject? as a value. In this case, we just pass in a String because that's what printMessage is looking for. When your application detects that the play/pause key has been pressed, you should still see "Hello World" in the console. Let's look at one final use-case: a version of printMessage that takes in not one, but two parameters.
func printMessage(arg: String, _ arg2: String) {
print(arg)
}
Now, if printMessage("Hello", "World") is called, you will see "Hello World" in your console. We can now modify the performSelector call to handle passing in two parameters.
case NX_KEYTYPE_PLAY:
delegate!.performSelector("printMessage::", withObject: "Hello", withObject: "World")
break
As before, there are two things to notice here. First, we now add two : to the end of the Selector. Like before, this is so that the delegate can pass information along that contains the parameters. At a very basic level, it would look something like printMessage:"Hello":"World", but again I don't know what it really looks like at a deeper level. The second thing to notice is that we have added a second withObject parameter to the performSelector call. Like before, this withObject takes an AnyObject? as a value and we're passing in a String because that's what printMessage wants. When your application detects that the play/pause key has been pressed, you should still see "Hello World" in the console.
One final thing to note is that performSelector can only accept up to two parameters. I'd really like to see Swift add concepts like splatting or varargs so that this limitation eventually goes away, but for now just avoid trying to call functions that require more than two parameters.
This is what a very simple MediaApplication class that just prints out some text would look like once you are done with everything above:
import Cocoa
class MediaApplication: NSApplication {
override func sendEvent(event: NSEvent) {
if (event.type == .SystemDefined && event.subtype.rawValue == 8) {
let keyCode = ((event.data1 & 0xFFFF0000) >> 16)
let keyFlags = (event.data1 & 0x0000FFFF)
// Get the key state. 0xA is KeyDown, OxB is KeyUp
let keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA
let keyRepeat = (keyFlags & 0x1)
mediaKeyEvent(Int32(keyCode), state: keyState, keyRepeat: Bool(keyRepeat))
}
super.sendEvent(event)
}
func mediaKeyEvent(key: Int32, state: Bool, keyRepeat: Bool) {
// Only send events on KeyDown. Without this check, these events will happen twice
if (state) {
switch(key) {
case NX_KEYTYPE_PLAY:
print("Play")
break
case NX_KEYTYPE_FAST:
print("Next")
break
case NX_KEYTYPE_REWIND:
print("Prev")
break
default:
break
}
}
}
}
Now, I should also add that, by default, your application is going to use the standard NSApplication when it runs. If you want to use the MediaApplication that this whole post is about, you'll need to go ahead and modify your application's Info.plist file. If you're in the graphical view, it will look something like this:
(source: sernprogramming.com)
Otherwise, it will look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>LSUIElement</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 Chris Rees. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
In either case, you will want to change the NSPrincipalClass property. The new value will include you project's name, so it will be something like Notify.MediaApplication. Once you make the change, run your application and use those media keys!
Question
Is it possible to remember the last item linked and have that one be selected the next time the Insert a Link dialog box is used?
Background
Our Sitecore content editors use the rich text editor (Telerik RadEditor) to edit HTML content on our website. Sometimes they need to create several links on the same page that are in similar areas (e.g. several different related articles). Currently, when they click on the Insert Link button, they are brought to the Insert a Link dialog box with the current item selected in the content tree. They browse to the item they'd like to link and click Link. Then they go to create another link, and it opens the Insert a Link dialog box to the current item again, instead of the item they just linked.
The solution which I found requires changes in Website\sitecore\shell\Controls\Rich Text Editor\RichText Commands.js file and works as long as you don't reload the page. You may easily extend it to work when some other page is edited by storing the information in a cookie instead of using the variable prevId.
First of all you need to define variable at the beginning of your file:
var prevId = null;
We will assign the last chosen item id to this variable every time we insert Sitecore link.
Second step is to extend scInsertSitecoreLink function to assign the prevId variable after the link is chosen:
function scInsertSitecoreLink(sender, returnValue) {
if (!returnValue) {
return;
}
prevId = returnValue.url.match(/id\=[a-fA-F0-9]{32}/g);
if (prevId) {
prevId = prevId[0].substr(3);
}
... rest of the scInsertSitecoreLink goes here
And the last step is to amend RadEditorCommandList["InsertSitecoreLink"] function that it uses the prevId variable value if it is set before it tries to assign scItemID which holds current item id:
RadEditorCommandList["InsertSitecoreLink"] = function(commandName, editor, args) {\
... here goes the original code of the function up to
if (!id) {
... and the code in the bracket
}
... and now we try to assign the prevId which was set after the last link was chosen
if(!id && prevId) {
id = prevId;
}
... and here goes the rest of the function
if (!id) {
id = scItemID;
}
While searching for hierarchical org chart controls, I came across a post on how to orient the nodes in d3.js, and I was wondering if there 1) was a way to edit the tree/drag children. 2) how to export the edited tree.
To answer your second question, one way is to grab the content of the parent node of your SVG (let's say your SVG is contained in a node with the id my_svg_container), and repackage it as a "true" SVG file that can be opened in an SVG-capable editor like Inkscape or Illustrator:
var rawSvg = $('#my_svg_container').outerHTML();
var result = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" version="1.1">' + rawSvg + '</svg>';
The outerHTML() function:
jQuery.fn.outerHTML = function() {
return jQuery('<div />').append(this.eq(0).clone()).html();
};
Then use a hidden web form to POST that result to a CGI script that prints it to the requesting web browser as a file. The form is triggered when a button is clicked or some other event occurs that is set to trigger the form. The browser then queries the user to save the file to the local file system.
If an example form contains the fields svg_data and svg_fn, which contain the SVG result and some filename of your choice, a very basic Perl script might look something like:
#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use CGI::Pretty qw/:standard/;
my $val = param('svg_data');
my $fn = param('svg_fn');
print "Content-Type: application/x-gzip\n";
print "Content-Disposition: attachment; filename=$fn\n";
print "Content-Description: File to download\n\n";
print $val;
You might add some data validation code to make sure you're printing an SVG file and not something else.
I have a Cocoa application. This hooks up into OSX Service Menu. I have created three ServicesMenu.strings for en.lproj, zh-Hans.lproj and hi-IN.lproj for localizing the Service Menu Title. The problem is OSX does seem to be using the localized text at all.
Info.plist (relevant portion)
<key>NSServices</key>
<array>
<dict>
<key>NSKeyEquivalent</key>
<key>NSMenuItem</key>
<dict>
<key>default</key>
<string>CreateHere</string>
</dict>
<key>NSMessage</key>
<string>createHere</string>
<key>NSPortName</key>
<string>CreateHereFilesService</string>
<key>NSRequiredContext</key>
<dict>
<key>NSApplicationIdentifier</key>
<string>com.apple.finder</string>
</dict>
<key>NSSendFileTypes</key>
<array>
<string>public.folder</string>
</array>
<key>NSUserData</key>
<string>create</string>
</dict>
</array>
ServicesMenu.strings (en.lproj)
/*
ServicesMenu.strings
*/
/* default */
"CreateHere" = "Create File Here";
On the Services Menu I can see the option CreateHere instead of Create File Here.
Update
If this helps. Here is the output of /System/Library/CoreServices/pbs -dump_pboard
{
CFPrincipalLocalizations = (
English
);
CFVendedServices = (
{
NSBundleIdentifier = "com.applegrew.apple.service.CreateHereFiles";
NSBundlePath = "/Users/applegrew/Library/Services/CreateHereFiles.app";
NSMenuItem = {
default = CreateHere;
};
NSMessage = createHere;
NSPortName = CreateHereFilesService;
NSRequiredContext = {
NSApplicationIdentifier = "com.apple.finder";
};
NSSendFileTypes = (
"public.folder"
);
NSUUID = <199fd7c0 cdd146fb 9a564a93 231b23f9>;
NSUserData = create;
}
);
CFVersion = 2;
}
Unlike for other services (not shown above) NSMenuItem does does not have any entry English. Does this have anything to do with, that I do not have any English.lproj, instead I have en.lproj?
Faced the same problem today while adding service to my application.
Everything works except the localizations.
Fixed the issue by running these commands:
/System/Library/CoreServices/pbs -flush
/System/Library/CoreServices/pbs -update
According English.lproj
Does this have anything to do with, that I do not have any
English.lproj, instead I have en.lproj?
English.lproj is obsolete, use en.lproj instead. From Apple docs:
For language designations, you can use either the ISO 639-1 or ISO 639-2 conventions. The ISO 639-1 specification uses a two-letter code to identify a language and is the preferred way to identify languages.
Look at Internationalization Programming Topics (Language and Locale Designations → Language Designations) for more info.
https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPInternational/Articles/LanguageDesignations.html#//apple_ref/doc/uid/20002144-SW1