How to show and hide standard InDesign panels through scripting? - adobe-indesign

I’m able to get a reference to, for instance, the “Scripts” panel; but it doesn’t seem to have the show and hide methods like panels created through scripting (see code below). How can I get it to show or hide programmatically, without invoking the corresponding menu item?
function findPanelByName(name) { // String → Panel|null
for (var iPanel = 0; iPanel < app.panels.length; iPanel++) {
var panel = app.panels[iPanel];
if (panel.name == name) {
return panel;
}
}
return null;
}
var scriptsPanel = findPanelByName('Scripts');
scriptsPanel.show(); // → “scriptsPanel.show is not a function”

A few things: Your method to get the right panel is unneccessarily complicated. You could just get the panel by using the panel collection's item method like so:
var scriptsPanel = app.panels.item('Scripts');
Then, you don't need to use show() to show the panel (as that method does not exist), but you can just show the panel, by settings its visible property to true:
scriptsPanel.visible = true;
And lastly, in case anybody else is supposed to use the script, you should make sure, that it works with international versions of InDesign as well. In my German version, the above panel for example would not exist, as it is named Skripte instead of Scripts. To avoid that you can use the language independent key of InDesign:
var scriptsPanel = app.panels.item('$ID/Scripting');
So, in conclusion, the entire script could be shortened up to this one-liner
app.panels.item('$ID/Scripting').visible = true;

Related

Showing more than one line of the notification description in the notification tray using an extension

I am currently designing an extension to make the notifications in the notification section of the calendar expendable. The goal is to make the noficiation expand like the initial notification on the desktop does. I have changed the type of notification added to the noficiation tray to class NotificationBanner from class NotificationMessage. I am currently using a work-around to make this work, this is what my expand function looks like:
expand(animate) {
this.expanded = true;
this._actionBin.visible = this._actionBin.get_n_children() > 0;
if (this._bodyStack.get_n_children() < 2) {
this._expandedLabel = new MessageList.URLHighlighter(this._bodyText,
true, this._useBodyMarkup);
this.setExpandedBody(this._expandedLabel);
}
if (animate) {
if (!this.clickedByButton && !this.forceExpansion) {
// This is the usual way notifications are expanded, using the layout manager
this._bodyStack.ease_property('#layout.expansion', 1, {
progress_mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: MessageTray.ANIMATION_TIME,
});
}
else if (this.forceExpansion || this.clickedByButton) {
// When auto expanding or clicked by button, change height of body
oldHeight = this.bodyLabel.get_height();
const lines = Math.ceil(this._bodyText.length / 54);
this.bodyLabel.set_height(lines * this.bodyLabel.get_height());
}
this._actionBin.scale_y = 0;
this._actionBin.ease({
scale_y: 1,
duration: MessageTray.ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
} else {
this._bodyStack.layout_manager.expansion = 1;
this._actionBin.scale_y = 1;
}
this.emit('expanded');
}
As you can see, I have 2 options for this extension: Force expand all notifications or make the user use a button to expand. The current solution is not elegant, it simply changes the height of the notification label which manages the body. Furhermore, the notification body still shows the three dots, implying that the body is still not expanded. I believe this to be an issue with the layout manager, since the proper way to expand is to set message._bodyStack.layout_manager.expansion to 1. That does not work in the case of expanding a message in the notification tray. Is anyone familiar with the layout manager or can help me find a different solution? Here is an image of what my current solution looks like:
Image of an automatically expanded notification in the notification tray due to the extension (note the three dots at the end of the first line being still there)
Okay I have found a solution, it is not related to the layout manager. The value of the message message.bodyLabel.clutter_text.ellipsize is set to 3, which is the main cause of the dots appearing on the notification. Setting this value to 0 solves this problem. I would have still loved to find a more elegant approach to displaying the body, but this will do.

How to get the entire Visual Studio active document... with formatting

I know how to use VS Extensibility to get the entire active document's text. Unfortunately, that only gets me the text and doesn't give me the formatting, and I want that too.
I can, for example, get an IWpfTextView but once I get it, I'm not sure what to do with it. Are there examples of actually getting all the formatting from it? I'm only really interested in text foreground/background color, that's it.
Note: I need the formatted text on every edit, so unfortunately doing cut-and-paste using the clipboard is not an option.
Possibly the simplest method is to select all of the text and copy it to the clipboard. VS puts the rich text into the clipboard, so when you paste, elsewhere, you'll get the colors (assuming you handle rich text in your destination).
Here's my not-the-simplest solution. TL;DR: you can jump to the code at https://github.com/jimmylewis/GetVSTextViewFormattedTextSample.
The VS editor uses "classifications" to show segments of text which have special meaning. These classifications can then be formatted differently according to the language and user settings.
There's an API for getting the classifications in a document, but it didn't work for me. Or other people, apparently. But we can still get the classifications through an ITagAggregator<IClassificationTag>, as described in the preceding link, or right here:
[Import]
IViewTagAggregatorFactoryService tagAggregatorFactory = null;
// in some method...
var classificationAggregator = tagAggregatorFactory.CreateTagAggregator<IClassificationTag>(textView);
var wholeBufferSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, 0, textBuffer.CurrentSnapshot.Length);
var tags = classificationAggregator.GetTags(wholeBufferSpan);
Armed with these, we can rebuild the document. It's important to note that some text is not classified, so you have to piece everything together in chunks.
It's also notable that at this point, we have no idea how any of these tags are formatted - i.e. the colors used during rendering. If you want to, you can define your own mapping from IClassificationType to a color of your choice. Or, we can ask VS for what it would do using an IClassificationFormatMap. Again, remember, this is affected by user settings, Light vs. Dark theme, etc.
Either way, it could look something like this:
// Magic sauce pt1: See the example repo for an RTFStringBuilder I threw together.
RTFStringBuilder sb = new RTFStringBuilder();
var wholeBufferSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, 0, textBuffer.CurrentSnapshot.Length);
// Magic sauce pt2: see the example repo, but it's basically just
// mapping the spans from the snippet above with the formatting settings
// from the IClassificationFormatMap.
var textSpans = GetTextSpansWithFormatting(textBuffer);
int currentPos = 0;
var formattedSpanEnumerator = textSpans.GetEnumerator();
while (currentPos < wholeBufferSpan.Length && formattedSpanEnumerator.MoveNext())
{
var spanToFormat = formattedSpanEnumerator.Current;
if (currentPos < spanToFormat.Span.Start)
{
int unformattedLength = spanToFormat.Span.Start - currentPos;
SnapshotSpan unformattedSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, currentPos, unformattedLength);
sb.AppendText(unformattedSpan.GetText(), System.Drawing.Color.Black);
}
System.Drawing.Color textColor = GetTextColor(spanToFormat.Formatting.ForegroundBrush);
sb.AppendText(spanToFormat.Span.GetText(), textColor);
currentPos = spanToFormat.Span.End;
}
if (currentPos < wholeBufferSpan.Length)
{
// append any remaining unformatted text
SnapshotSpan unformattedSpan = new SnapshotSpan(textBuffer.CurrentSnapshot, currentPos, wholeBufferSpan.Length - currentPos);
sb.AppendText(unformattedSpan.GetText(), System.Drawing.Color.Black);
}
return sb.ToString();
Hope this helps with whatever you're doing. The example repo will ask if you you want the formatted text in the clipboard after each edit, but that was just a dirty way that I could test and see that it worked. It's annoying, but it was just a PoC.

passing control indexer by reference to method to change its property

i have made a program, which include a lot of controls. The controls would be showed and hided according to the choice of the user. That means that controls overlapped on each other at design time. now i want to change the forecolor and backcolor of all controls at design time. but i founded so hard to accomplish this task, because all the control overlapping each other. so I decided to make a for loop method to iterate the controls in the form and then check each control in turn whether it has controls. when the control has also controls in it, I call the same method and pass the control to it to change the properties for the subcontrols too. The method like so:
void setColor(ref Control con)
{
con.BackColor= System.Drawing.Color.Black;
con.ForeColor=System.Drawing.Color.Yellow;
if (con.Controls.Count > 0) { setColor(ref con); }
}
so my Form include tabControl with multiple tabPages. I iterate the tabPages and wanted to pass it to this method, but I become error "Indexer may not be passed as an out or ref parameter"
I pass it so: setColor(ref tabControl1.Controls[i]);
can you please help me to solve this problem?
I have resolved the problem.
I have removed the "ref" from method and wrote the method simply like the following:
void SetColor(Control con)
{
con.BackColor = System.Drawing.Color.Black;
con.ForeColor = System.Drawing.Color.Yellow;
if (con.Controls.Count > 0)
{
for (int i=0; i<con.Controls.Count;i++)
SetColor(con.Controls[i]);
}
}
and call it so: setColor(this.Controls[i]);

How to indent the first line of a paragraph in CKEditor

I'm using CKEditor and I want to indent just the first line of the paragraph. What I've done before is click "Source" and edit the <p> style to include text-indent:12.7mm;, but when I click "Source" again to go back to the normal editor, my changes are gone and I have no idea why.
My preference would be to create a custom toolbar button, but I'm not sure how to do so or where to edit so that clicking a custom button would edit the <p> with the style attribute I want it to have.
Depending on which version of CKE you use, your changes most likely disappear because ether the style attribute or the text-indent style is not allowed in the content. This is due to the Allowed Content Filter feature of CKEditor, read more here: http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter
Like Ervald said in the comments, you can also use CSS to do this without adding the code manually - however, your targeting options are limited. Either you have to target all paragraphs or add an id or class property to your paragraph(s) and target that. Or if you use a selector like :first-child you are restricted to always having the first element indented only (which might be what you want, I don't know :D).
To use CSS like that, you have to add the relevant code to contents.css, which is the CSS file used in the Editor contents and also you have to include it wherever you output the Editor contents.
In my opinion the best solution would indeed be making a plugin that places an icon on the toolbar and that button, when clicked, would add or remove a class like "indentMePlease" to the currently active paragraph. Developing said plugin is quite simple and well documented, see the excellent example at http://docs.ckeditor.com/#!/guide/plugin_sdk_sample_1 - if you need more info or have questions about that, ask in the comments :)
If you do do that, you again need to add the "indentMePlease" style implementation in contents.css and the output page.
I've got a way to indent the first line without using style, because I'm using iReport to generate automatic reports. Jasper does not understand styles. So I assign by jQuery an onkeydown method to the main iframe of CKEditor 4.6 and I check the TAB and Shift key to do and undo the first line indentation.
// TAB
$(document).ready(function(){
startTab();
});
function startTab() {
setTimeout(function(){
var $iframe_document;
var $iframe;
$iframe_document = $('.cke_wysiwyg_frame').contents();
$iframe = $iframe_document.find('body');
$iframe.keydown(function(e){
event_onkeydown(e);
});
},300);
}
function event_onkeydown(event){
if(event.keyCode===9) { // key tab
event.preventDefault();
setTimeout(function(){
var editor = CKEDITOR.instances['editor1'], //get your CKEDITOR instance here
range = editor.getSelection().getRanges()[0],
startNode = range.startContainer,
element = startNode.$,
parent;
if(element.parentNode.tagName != 'BODY') // If you take an inner element of the paragraph, get the parentNode (P)
parent = element.parentNode;
else // If it takes BODY as parentNode, it updates the inner element
parent = element;
if(event.shiftKey) { // reverse tab
var res = parent.innerHTML.toString().split(' ');
var aux = [];
var count_space = 0;
for(var i=0;i<res.length;i++) {
// console.log(res[i]);
if(res[i] == "")
count_space++;
if(count_space > 8 || res[i] != "") {
if(!count_space > 8)
count_space = 9;
aux.push(res[i]);
}
}
parent.innerHTML = aux.join(' ');
}
else { // tab
var spaces = " ";
parent.innerHTML = spaces + parent.innerHTML;
}
},200);
}
}

Close only a specific tab with firefox extension

i'm developing a firefox extension and i want to be able to close a specific tab. For example if there are many open tabs in the browser o want to close only the tab with a specific url.
I know that i can use gBrowser.removeTab(tab) but i don't know how to get tab object.
On the other hand i can get the browser that corresponds to the url but the param of the removeTab() function must be a "tab object". How cat i get the tab object.
Any ideas?
tabbrowser.getBrowserForTab() method is actually the easiest way of associating browsers with tabs. So you would do something like this:
var tabs = gBrowser.tabs;
for (var i = tabs.length - 1; i >= 0; i--)
{
var tab = tabs[i];
var browser = gBrowser.getBrowserForTab(tab);
if (browser.currentURI && browser.currentURI.spec == "...")
gBrowser.removeTab(tab);
}
I think you can use this method: gBrowser.removeCurrentTab(); this example closes the currently selected tab.
For more code, please refers this link: https://developer.mozilla.org/en/Code_snippets/Tabbed_browser

Resources