Script Name | Description | Requested by | Date of Request | Programmed by | Completed on | Link to Script |
John Zeman's "Ultimate Description Writer" | Write Clipboard Contents to Desc of single/multiple selected images. Include ability to Replace, Pre-pend or Append | DigPeter | 07.06.2017 | Jingo | |
Synopsis:With this script you can.....
Edit the current caption (description).
Actively monitor and show the total size of the current caption as you type.
Copy the current caption to the clipboard.
Replace the current caption with the text on the Windows clipboard.
Compares the captions of the selected images to see if they are identical.
Find specific text in the captions of the selected images.
Replace specific text in the captions of the selected images.
Append text to the end of existing captions of the selected images (even if the existing captions are different).
Pre-pend text to the beginning of existing captions of the selected images (even if the existing captions are different).
Making steady progress on this one.. should hopefully be done tomorrow.
Mario - quick question. If I have an idlist with 20 selected images - is there a quick way to isolate the Focused file in the group? I know I can create a 2nd idlist - but then I'm not sure how to locate the focused file in the selected idlist group by id #.
For example.. let say I have 2 files selected:
"files": [
{
"id": 34,
"name": "GF1_IMAGE_1010302.jpg",
"rating": 5,
"label": "",
"created": "2017:07:08 14:23:31",
"desc": "this is the description!",
"digitized": "2017:07:08 14:23:31",
"keywords": "",
"title": ""
},
{
"id": 35,
"name": "IMG_9123.JPG",
"rating": 3,
"label": "",
"created": "2016:05:05 18:03:02.859",
"desc": "This is an amazing image",
"digitized": "2016:05:05 18:03:02.859",
"keywords": "",
"title": ""
}
The program call of: IMatch.getFocusedFile().then(function(response) {var selid = response.id;});
gives me the id of 35 which is the focused file... but, now I want to grab the "desc" of that file and display it to the user... but I also need the idlist for all the selected files so I can update them all with the description modifications.
Thx for any ideas... Andy.
I'm not sure that I understand the question.
An idlist stores only file ids, without any contextual information. If this is what you mean.
IMatch provides an idlist with the selected files. And one with the focused file. You can call both endpoints and then do a forEach or indexOf on the idlist with the selected files with the id of the focused file to find the focused file in that idlist.
Keep in mind that, depending on how your app works, the interactive user may change the selection or focused file while your app runs.
There may be no focused file and no selection. Also: the focused file may be focused but not selected. That's uncommon but a possibility.
Quote from: Mario on July 09, 2017, 08:37:58 AM
I'm not sure that I understand the question.
An idlist stores only file ids, without any contextual information. If this is what you mean.
IMatch provides an idlist with the selected files. And one with the focused file. You can call both endpoints and then do a forEach or indexOf on the idlist with the selected files with the id of the focused file to find the focused file in that idlist.
Keep in mind that, depending on how your app works, the interactive user may change the selection or focused file while your app runs.
There may be no focused file and no selection. Also: the focused file may be focused but not selected. That's uncommon but a possibility.
Hmmm... the IndexOf sounds promising..
Basically, I am trying to gather an idlist of all selected files.. easy. Now that I have that list, I want to show the description only for the
focused file. I can easily grab that file's id but was having trouble figuring out a way to link the 2 idlists. I suppose I could take a page from my work's programming language and just create an index on the fly that links the response file # to the idlist for cross reference purposes... something like an array. But perhaps the Indexof will work... I'll check that out!
Thanks Mario!
Thx Mario... I figured it out thanks to your hint about indexOf.... used the findIndex array method (love the possibilities that Javascript presents!!!)
Setup the selected file in global variable selid:
IMatch.getFocusedFile().then(function(response) {selid = response.id;});
Now, use findIndex on the selected files idlist to locate the array entry and return the array value so I can retrieve that image description!
function findSelected(element) {
return element["id"] == selid;
}
var ientry = response.files.findIndex(findSelected);
console.log("selected id #: " + selid + " " + "index number: " + ientry);
Good. Just keep in mind that the focused file can change after you have saved it in your global variable. Maybe caused by a another app or by the user. Best not to cache this kind of data too long - unless you are certain of the conditions in which your app is used (a modal app, for example).
Thanks for that tip Mario... the app should "repaint" automatically if the file criterion is changed so that global variable should reset (I will test for this). So far, so good with this app as well!
QuoteI can easily grab that file's id but was having trouble figuring out a way to link the 2 idlists. I suppose I could take a page from my work's programming language and just create an index on the fly that links the response file # to the idlist for cross reference purposes... something like an array. But perhaps the Indexof will work... I'll check that out!
Andy, I think you could also use a
Map instead of findIndex. For example, I used somewhere the following coding.
If
response is the result of a
v1/attributes call:
// Each entry is an Object which contains the id of the file an data array of attribute records.
// Convert to a Map with the file id as key and the attribute records array as value.
let attrDates = response.result;
let myMap = attrDates && new Map(attrDates.map(el => [el.id, el.data]));
Now, you can access
myMap directly by providing the file id as key, getting the attribute records as value. For example, to access the attribute
Datum of the first attribute record, you use:
myMap.get(aFileId)[0].Datum
I know you are not talking about attributes but the principle (to convert an end point result to a Map indexed by file id) should be the same.
That's advanced juju :D
I try to avoid such constructs in my sample apps to keep them simple to follow. But in 'real' code that's one way to go.
Ok all.. this one is done!
Based loosely on John Zeman's Description Writer - the app will manipulate descriptions across single focused or multiple selected images. To use, please unzip the files to your C:\ProgramData\photools.com\imatch6\webroot\user folder and the app should appear in the app manager automatically.
(https://vgy.me/5znaP1.png) (https://vgy.me/59V5oh.png)
Lot's to cover... so here we go!
Show Results Details Button: will show/hide the Idlist for all the selected images. Useful to see how the descriptions for each image before and after manipulation. Button will toggle to Hide Details if Details are displayed.
Result Message box: Will show server-side results and clipboard success/failure messages
Focused Filename box: displays the filename of the currently focused image - this image controls the initial load of the Image Description.
Total Selected Images box: shows a count of all selected images.
Descriptions Match box: displays as "True/False" to indicate whether the description of the selected images are all the same (true) or different (false).
Image Description of Focused File box: shows the description from the Focused File. This box is read-only and cannot be edited.
Copy Description to Clipboard button: will copy the contents of the Image Description of Focused File box.
Text to append/pre-pend or overwrite File Descriptions box: textarea to enter text for manipulation of a description. All text in this box will be used to alter the description using the following buttons:
Append Focused/Append ALL Buttons: takes text from textarea and adds it to the end of the description of the focused image or ALL selected images.
Pre-pend Focused/Pre-pend ALL Buttons: takes text from textarea and adds it to the beginning of the description of the focused image or ALL selected images.
Overwrite Focused/Overwrite ALL Buttons: takes text from textarea and overwrites the description of the focused image or ALL selected images.
Clear Focused/Clear ALL Buttons: wipes the description of the focused image or ALL selected images.
Search For/Replace With textboxes: text in these boxes will be used to perform a search replace within the file description using the following buttons:
Search/Replace Focused / Search/Replace ALL Buttons: Performs a search and replace in either the focused image or ALL selected images.
Please Note: these operations are immediate and will update the IMatch database upon execution
Write-back Button: used to write updates to selected files back to the images. Only available if "background write-back" is enabled in IMatch. Otherwise, the pencil icon will display on all modified images.
I do hope this app proves useful.. if anyone has any additional requests - I'd be happy to attempt to code them. While I'm sure the app display can be tweaked to look better/save space - hopefully it will serve as a learning tool /starting place for other app creation and function as a useful addition to IMatch.
Enjoy! - Andy.
Quote from: thrinn on July 09, 2017, 08:35:34 PM
QuoteI can easily grab that file's id but was having trouble figuring out a way to link the 2 idlists. I suppose I could take a page from my work's programming language and just create an index on the fly that links the response file # to the idlist for cross reference purposes... something like an array. But perhaps the Indexof will work... I'll check that out!
Andy, I think you could also use a Map instead of findIndex. For example, I used somewhere the following coding.
If response is the result of a v1/attributes call:
// Each entry is an Object which contains the id of the file an data array of attribute records.
// Convert to a Map with the file id as key and the attribute records array as value.
let attrDates = response.result;
let myMap = attrDates && new Map(attrDates.map(el => [el.id, el.data]));
Now, you can access myMap directly by providing the file id as key, getting the attribute records as value. For example, to access the attribute Datum of the first attribute record, you use:
myMap.get(aFileId)[0].Datum
I know you are not talking about attributes but the principle (to convert an end point result to a Map indexed by file id) should be the same.
Yes! That is basically what I was originally thinking of doing.. its sort or like an index to the records. I think if I needed to access this info more than once - it would certainly be better than the findIndex method I used...
BTW: we use indexes extensively at work to map data and provide easy access points to the database records by providing various "keys". For example, in this case, I could have an index setup for:
Idlist[id]=urn (get the idlist urn quickly from the image id)
Thx for the info about Maps... learning more and more each hour! - Andy.
Thanks again Andy. This will be most useful for me.
My pleasure.. the User Interface is a bit "rough" around the edges so I may work on an enhancement but it works great! I realize I need to add in the comment counter but otherwise - it works really well!
Enjoy - Andy.
Here I have a scripting question related to this: How do I add items to an array but only if it does not already exist?
Is there an easy way? Do I have to check first if it exists and skip adding if it does?
Would using map be the way to go?
Great app: and a sure sign that some "program" is great is that someone will immediately modify it
or (like me) suggest some additions. Here I go:
A button Overwrite Focused and move focus to next file Maybe a small button with an arrow to the right of Overwrite Focused
In addition to Copy Description to Clipboard a Paste Clipboard to Text button, or, maybe more useful, a Copy Description to Text button.
(Since the latter will likely be the most common use of the clipboard text)
For a Paste Clipboard to Text button it would be good to have the clipboard text displayed.
And, while I am at it: show a thumbnail of the focused file in the top right corner.
Andy, congratulations! :)
I wonder, how long you had for this! 8)
I did not try it out, but I will of course.
First I have to buy IMatch2017 :D because the trial works not with my large DB (only read only).
Thorsten with his script for metadatas gave me the knowledge, that the stuff, what I need, is doable, hence I can change to IM17, as soon as I have the scripts. :D
Good work! Thanks for sharing.
Quote from: ubacher on July 10, 2017, 06:36:32 AM
Great app: and a sure sign that some "program" is great is that someone will immediately modify it
or (like me) suggest some additions. Here I go:
A button Overwrite Focused and move focus to next file Maybe a small button with an arrow to the right of Overwrite Focused
In addition to Copy Description to Clipboard a Paste Clipboard to Text button, or, maybe more useful, a Copy Description to Text button.
(Since the latter will likely be the most common use of the clipboard text)
For a Paste Clipboard to Text button it would be good to have the clipboard text displayed.
And, while I am at it: how a thumbnail of the focused file in the top right corner.
I think that the main purpose of the script is do batch changes to files where the descriptions differ. Changes to individual files can be made direct in the metadata panel. I might be a mistake to over-complicate the app.
Quote from: DigPeter on July 10, 2017, 12:38:51 PM
Quote from: ubacher on July 10, 2017, 06:36:32 AM
Great app: and a sure sign that some "program" is great is that someone will immediately modify it
or (like me) suggest some additions. Here I go:
A button Overwrite Focused and move focus to next file Maybe a small button with an arrow to the right of Overwrite Focused
In addition to Copy Description to Clipboard a Paste Clipboard to Text button, or, maybe more useful, a Copy Description to Text button.
(Since the latter will likely be the most common use of the clipboard text)
For a Paste Clipboard to Text button it would be good to have the clipboard text displayed.
And, while I am at it: how a thumbnail of the focused file in the top right corner.
I think that the main purpose of the script is do batch changes to files where the descriptions differ. Changes to individual files can be made direct in the metadata panel. I might be a mistake to over-complicate the app.
But you can also do "batch changes" with the metadata panel.
I think, it is another way to do changes, maybe even a more convenient way than with the metadata-panel. And you can (if you are experienced) put also the fields in that way, as you like (big, small, order in horizontal way and so on).
@Markus
If one file has description "aaaa" and another "bbbb", how can you add "cccc" to both files with through the metadata panel?
Cant. Not part of my design.
Quote from: DigPeter on July 10, 2017, 02:51:47 PM
@Markus
If one file has description "aaaa" and another "bbbb", how can you add "cccc" to both files with through the metadata panel?
DigPeter, you are completely right, sorry and thanks.
I can only change text, not add, if the text is not the same.
In such cases I must select the same description and add text.
Scripts can help us a lot.
Experienced user, whe works very often with IMatch, do very often use scripts, I guess.
Because they can a lot combine and solve specific things like here in this example.
I counted quickly my scripts, what I use/d in IMatch5:
total 16 different scripts! ;D
Where 5 are really important, the rest is simply nice to have, very personal stuff.
Quote from: DigPeter on July 10, 2017, 02:51:47 PM
@Markus
If one file has description "aaaa" and another "bbbb", how can you add "cccc" to both files with through the metadata panel?
Hence the Ultimate Description Writer App.. 8)
Quote from: sinus on July 10, 2017, 08:10:23 AM
Andy, congratulations! :)
I wonder, how long you had for this! 8)
I did not try it out, but I will of course.
First I have to buy IMatch2017 :D because the trial works not with my large DB (only read only).
Thorsten with his script for metadatas gave me the knowledge, that the stuff, what I need, is doable, hence I can change to IM17, as soon as I have the scripts. :D
Good work! Thanks for sharing.
Thx Markus - the App took me about 6 hrs of coding... I learned Javascript and the IMatch syntax this past weekend when I created this APP and the GPS Converter.
If you need additional scripts converted from IM5 - just add new request threads to this forum and I'll be sure to see what I can do next weekend (My play time). Happy to help and having concrete app requests assists me greatly by giving me focus.
Quote from: ubacher on July 10, 2017, 05:59:28 AM
Here I have a scripting question related to this: How do I add items to an array but only if it does not already exist?
Is there an easy way? Do I have to check first if it exists and skip adding if it does?
Would using map be the way to go?
Hi ubacher - you would check the array using indexOf and the push into the array if that check fails. So something like this should work:
var my_array ["item1","item2","item3"];
my_array.indexOf(new_item) === -1 ? my_array.push(new_Item) : console.log(new_item + " is already a part of the array and was not added");
Quote from: Jingo on July 10, 2017, 03:33:48 PM
Quote from: sinus on July 10, 2017, 08:10:23 AM
Andy, congratulations! :)
I wonder, how long you had for this! 8)
Thx Markus - the App took me about 6 hrs of coding... I learned Javascript and the IMatch syntax this past weekend when I created this APP and the GPS Converter.
Phew :o for such a script I would call this almost nothing.
If I could ever do this, I am sure, I would have not 6 hours, but 6 days or more.
It is really great, how some people like you or Thorsten or others are able to lern scripting so quickly. Amazing.
Quote from: Jingo on July 10, 2017, 03:33:48 PM
If you need additional scripts converted from IM5 - just add new request threads to this forum and I'll be sure to see what I can do next weekend (My play time). Happy to help and having concrete app requests assists me greatly by giving me focus.
Out of my 16 scripts are really really important for me only 2 scripts.
One I have pointed out (Calculations of Attributes), what maybe Thorsten has a look at (but I do not know) and the second is, put these Attributes - fields into a html, word or whatever makes most sense.
Hm, I will add a request for this.
Thanks anywy, for your script-effort. :)
Follow up question to Jingo re use of indexOf:
If my array is an array of objects:
var my_array= [MyObj1,MyObj2,MyObj3];
and the objects contain a (method) "name" which I want to keep unique - how would/could I code this?
the following will probably not work:
my_array[].name.indexOf(MyNewObj.name) === -1
Quote from: ubacher on July 10, 2017, 04:42:39 PM
Follow up question to Jingo re use of indexOf:
If my array is an array of objects:
var my_array= [MyObj1,MyObj2,MyObj3];
and the objects contain a (method) "name" which I want to keep unique - how would/could I code this?
the following will probably not work:
my_array[].name.indexOf(MyNewObj.name) === -1
For an array of objects - I agree this wouldn't work and you will need something a bit more complex. I found this code snippet that should work in such a case:
// check if an element exists in array using a comparer function
// comparer : function(currentElement)
Array.prototype.inArray = function(comparer) {
for(var i=0; i < this.length; i++) {
if(comparer(this[i])) return true;
}
return false;
};
// adds an element to the array if it does not already exist using a comparer
// function
Array.prototype.pushIfNotExist = function(element, comparer) {
if (!this.inArray(comparer)) {
this.push(element);
}
};
var array = [{ name: "tom", text: "tasty" }];
var element = { name: "tom", text: "tasty" };
array.pushIfNotExist(element, function(e) {
return e.name === element.name && e.text === element.text;
});
Let me know if this is helpful!
Thank you Jingo. I will try this next (suitable) script.
Have to familiarize myself with prototypes first.
@sinus:
Quote(Calculations of Attributes), what maybe Thorsten has a look at
Yes, I have. I have to learn a bit about Bootstrap forms first and how to handle the input of numbers with decimal
point and/or decimal
commas. Thought that would be coming out of the box, but it does not.
But I am working at it...
OH, suuuuper!!!
Thanks in advance ... and of course take as long time as you need!
What a cool and helpful community here! :D
I wish, I could scripting so good like you and Andy. I envy you, phew, really.
Thank you for converting my old script to this new app Andy! Because I used that script so often myself I had not upgraded to IMatch 2017 until last night.
I have two questions about your app though.
1. Is there a way I can reduce the width of the app by about 30% so I don't have to use a horizontal scrollbar to see everything in the app?
2. Can I set the default height of the description field so it's taller? Edit: Never mind this either, see my followup comment below.
Thanks again for your work on this. To be honest this old dog has very little desire to learn another new scripting language at my age so I really appreciate what you've done here.
Edit: Never mind my first question it just occurred to me that I can have that app panel separate and floating instead of being docked. But I would like to see a taller description box if that can be done.
You can also reduce the zoom for all apps under Edit > Preferences > Application: App Panel Scale.
Depending on the size of your monitor, your DPI settings and personal preferences, you can scale the App Panel contents in 16 steps!
Thanks for that Mario, I see have a lot to learn about this 2017 version.
Andy, never mind about my second question either, I was trying to use your app the way I used to use the script and I see now there are some distinct differences. For example I used to use the compare option in the script to find images with identical descriptions. Apparently that's not possible with your app but I can do the same thing with a filter, so that'll work.
I do have one comment though, the word Descriptions is misspelled as Descripions in the third row of the table. I've corrected it in my version of your app.
All in all, it looks like my nervous apprehension to upgrade to 2017 was unfounded. Yes, I no longer have my custom scripts which I relied upon heavily but I'm finding ways to do the same things in 2017 without scripting. And I've only used this new version for a few hours so far.
Quote from: JohnZeman on July 11, 2017, 07:29:37 PM
Thanks for that Mario, I see have a lot to learn about this 2017 version.
Me too, me too!
I have downloaded the new version today (licensed)
and do use now some time both version parallel, but the working version (5.8) is the real DB, where I add new images. From time to time I will copy this DB and work with it and IMatch 2017
Quote from: JohnZeman on July 11, 2017, 07:29:37 PM
All in all, it looks like my nervous apprehension to upgrade to 2017 was unfounded. Yes, I no longer have my custom scripts which I relied upon heavily but I'm finding ways to do the same things in 2017 without scripting. And I've only used this new version for a few hours so far.
Great! :)
Quote from: JohnZeman on July 11, 2017, 07:29:37 PM
Thanks for that Mario, I see have a lot to learn about this 2017 version.
Andy, never mind about my second question either, I was trying to use your app the way I used to use the script and I see now there are some distinct differences. For example I used to use the compare option in the script to find images with identical descriptions. Apparently that's not possible with your app but I can do the same thing with a filter, so that'll work.
I do have one comment though, the word Descriptions is misspelled as Descripions in the third row of the table. I've corrected it in my version of your app.
All in all, it looks like my nervous apprehension to upgrade to 2017 was unfounded. Yes, I no longer have my custom scripts which I relied upon heavily but I'm finding ways to do the same things in 2017 without scripting. And I've only used this new version for a few hours so far.
Thx John... ooops on the misspelling... I will correct and update the zip file this weekend - thanks for catching that. If there is anything else you would like to see done in the app, just let me know and I'll try to fit it in... was a great way to learn scripting for sure and I appreciate concrete examples that could help others.
Andy I've taken the liberty of editing your html code in this app. I didn't change any functionality, just the way it displays in an app panel. I've attached it in case you're interested.
Thx John... as usual - I forgot! Appreciate the upload.... Andy!
@Andy
Your app works well, but I have a few comments, particularly regarding the replace mode.
1 - In batch mode it would be helpful if the number of files altered could be displayed. This is particularly relevant when replacing words. Say 40 files are selected and I want to correct a spelling mistake (e.g. fild > field), if only 38 files are actually affected, it would be useful to know this. It is quicker when dealing with a large number of files to select them all and let the app sort out those that need changing, than individually selecting them manually. The attachment shows the message produced in John's IM5 app.
2 - Again in replace mode, when no change has been made The Result message "{ "result": "ok"}" still appears.
3 - In the above situation, your app marks all selected files as requiring write-back, including those that have not been changed. After write-back, those files which were not changed retain the pencil icon, but do not appear as pending write-back in collections.
4 - As a refinement it would be useful if a confirmation were required before a change is made. Again, the 2nd attachment shows John's message.
Quote from: DigPeter on July 24, 2017, 03:03:47 PM
@Andy
Your app works well, but I have a few comments, particularly regarding the replace mode.
1 - In batch mode it would be helpful if the number of files altered could be displayed. This is particularly relevant when replacing words. Say 40 files are selected and I want to correct a spelling mistake (e.g. fild > field), if only 38 files are actually affected, it would be useful to know this. It is quicker when dealing with a large number of files to select them all and let the app sort out those that need changing, than individually selecting them manually. The attachment shows the message produced in John's IM5 app.
2 - Again in replace mode, when no change has been made The Result message "{ "result": "ok"}" still appears.
3 - In the above situation, your app marks all selected files as requiring write-back, including those that have not been changed. After write-back, those files which were not changed retain the pencil icon, but do not appear as pending write-back in collections.
4 - As a refinement it would be useful if a confirmation were required before a change is made. Again, the 2nd attachment shows John's message.
John and Andy:
thanks, great!
Going a little off topic here for a moment...
I don't mean to infringe upon Andy's excellent work with this app for I am very grateful he has created it. But on the other hand I also wanted to adapt it for my own needs and thought I'd share a screen shot of my results in case anyone else is interested.
I went with a dark theme to blend in with the overall dark theme IMatch 2017 has on my computer.
Changed the html/CSS coding so the app scales better when the width of the app is changed.
Changed the app name, appended "2" to the folder name, and have appended my initials to the app.json ID so Andy's original app can co-exist with the one I'm modifying and showing here.
I removed some buttons that I would never use, the buttons that dealt with modifying the focused files. When I use this app (and my old script) I want to process all selected files.
And I renamed a few buttons for the same reason.
I did not modify any of the JavaScript Andy has created, hell at this point I wouldn't be able to if I tried. lol I've only altered the appearance of the app and have removed the buttons that I'd never use.
Quote from: JohnZeman on July 24, 2017, 06:06:43 PM
I did not modify any of the JavaScript Andy has created, hell at this point I wouldn't be able to if I tried. lol I've only altered the appearance of the app and have removed the buttons that I'd never use.
;D I understand you and feel with you, I am in the same boat.
I am also happy, that Andy did this. You made once, John, a great job with VB, and not Andy make also a great job, this time with JS.
Good of course for that users, who will work with that ... I will do so. :D
Hi John,
The app looks awesome. Thanks to you, and everyone else that worked on it. I also prefer the dark theme of your amended app and was wondering if you were willing to share this version as well?
Thanks,
Jamie
Thanks Jamie and I'd be happy to share it with you and anyone else who might be interested.
I've made a few more changes since my last screen shot, but they're all cosmetic. The only change I've made to Andy's JavaScript code is I added one line to reset the result message whenever the selection changes.
Otherwise the screen shots I've attached are as follows.....
The first screenshot is just an update on the way the app looks now.
The second shows how the details box pops up below the app.
The third shows an info box that pops up now if you click on the i inside the white circle icon at the top of the app.
I've zipped and attached the app to this.
And now I am heading out for the rest of the day to my #1 favorite photography shoot of the year. ;D
Quote from: JohnZeman on July 24, 2017, 06:06:43 PM
Going a little off topic here for a moment...
I don't mean to infringe upon Andy's excellent work with this app for I am very grateful he has created it. But on the other hand I also wanted to adapt it for my own needs and thought I'd share a screen shot of my results in case anyone else is interested.
I went with a dark theme to blend in with the overall dark theme IMatch 2017 has on my computer.
Changed the html/CSS coding so the app scales better when the width of the app is changed.
Changed the app name, appended "2" to the folder name, and have appended my initials to the app.json ID so Andy's original app can co-exist with the one I'm modifying and showing here.
I removed some buttons that I would never use, the buttons that dealt with modifying the focused files. When I use this app (and my old script) I want to process all selected files.
And I renamed a few buttons for the same reason.
I did not modify any of the JavaScript Andy has created, hell at this point I wouldn't be able to if I tried. lol I've only altered the appearance of the app and have removed the buttons that I'd never use.
Hi John - no worries about infringing... I'm always happy when others can take what I have done and alter and improve on it... and I love your dark theme and button look!
Quote from: DigPeter on July 24, 2017, 03:03:47 PM
@Andy
Your app works well, but I have a few comments, particularly regarding the replace mode.
1 - In batch mode it would be helpful if the number of files altered could be displayed. This is particularly relevant when replacing words. Say 40 files are selected and I want to correct a spelling mistake (e.g. fild > field), if only 38 files are actually affected, it would be useful to know this. It is quicker when dealing with a large number of files to select them all and let the app sort out those that need changing, than individually selecting them manually. The attachment shows the message produced in John's IM5 app.
2 - Again in replace mode, when no change has been made The Result message "{ "result": "ok"}" still appears.
3 - In the above situation, your app marks all selected files as requiring write-back, including those that have not been changed. After write-back, those files which were not changed retain the pencil icon, but do not appear as pending write-back in collections.
4 - As a refinement it would be useful if a confirmation were required before a change is made. Again, the 2nd attachment shows John's message.
Thx Peter - I will take a look at these and make the necessary changes... not sure how #3 slipped in but I'll review and correct. I will post the code changes so the version that John did can be altered as well - always happy to just have John's version in dark theme be the release version of this App is folks like the dark theme best - that way, there is only a single version to support moving forward.
Quote from: Jingo on July 31, 2017, 03:56:10 PM
Thx Peter - I will take a look at these and make the necessary changes... not sure how #3 slipped in but I'll review and correct. I will post the code changes so the version that John did can be altered as well - always happy to just have John's version in dark theme be the release version of this App is folks like the dark theme best - that way, there is only a single version to support moving forward.
I look forward to seeing the new version, Andy. This app is a real time saver. I too prefer the John's dark theme.
Thx Peter... I'm working on this today but it is more complicated that I originally thought because I need to do the search before I do the replace (to avoid updating files that don't need to be, getting a count, revising the selection and updating). This will require a bit of work to adjust the functionality already there... working on it though!
Great - no hurry.
I'm posting this update for anyone who may be using my dark themed version of Andy's app.
I've recently made more cosmetic changes by replacing the previous information and confirmation dialogs with much better looking bootstrap modal dialogs.
Again, no changes have been made to Andy's JavaScript.
That looks the business, John. I prefer the B&W theme. but will wait to see what Andy produces.
Boostrap is cool.
And you can apply different themes to your app by just changing one line (replacing the Boostrap theme css with the css file of the new theme).
For example, check out this link for an overview of free and very nice themes:
https://bootswatch.com/
The Bootstrap team also offers some commercial but extremely well-designed themes:
https://themes.getbootstrap.com/
On this page you'll also learn about the people behind the Bootstrap CSS framework. Very interesting.
And, of course there's Bootstraps official "Do you own themse" site:
http://getbootstrap.com/customize/
Unfortunately, this is CSS hard-code and looks a tad frightening to me :P
Thanks for those links Mario, I'm just now getting started with Bootstrap and I really like what I've been finding so far. ;D
I'll recommend you look into Bootstrap version 4 (https://v4-alpha.getbootstrap.com/) which will soon become the standard version. Much improved in all areas.
Bootstrap 3 will continue to work of course and I will include it in IMatch for the time being. I will also include Bootstrap 4 as a standard CSS so apps will have the choice.
Well.. I made adjustments to the program to make things look a bit different and to fix a few of the bugs that were found.
(https://vgy.me/ITxRlI.png)
Changes:
- New Dark Theme
- Modified Search/Replace
So, while not spending the time to go as far as John has, I did switch to a dark theme and changed a few of the other colored bits. This looks good to me so I won't be making many more changes... but the logic is there should anyone wish to go for it.
I significantly altered the Search/Replace logic to make it work more correctly. The Search will now create a sublist of files that match the search criteria and only those files will be updated when the replace is performed. I also display a count of files that match the search criteria and modified the Replace button logic to display a warning/info box before performing the code replace. This same logic has also been applied to the other modification buttons...
I also cleaned up a few bits here and there to make things a bit nicer... I have tested it and it appears to work well... look forward to hearing from others! The only file that really needs to be replaced is index.html but I included all files for completeness and updated the original link as well. Enjoy!
Enjoy - Andy.
Thanks Andy. I have downloaded the new version and will test it in a couple of days.
Quote from: DigPeter on August 06, 2017, 11:26:31 PM
Thanks Andy. I have downloaded the new version and will test it in a couple of days.
My pleasure.. look forward to your feedback.
Hi Andy. I've found one issue with your latest version.
Searching for characters like parenthesis ( or ) or square brackets [ or ] returns no result when one or more of those characters are in the descriptions. Other than that it seems to be working very well. From what I can tell your previous version did not have this issue.
Thx John - The old version was simply using the op:replace so all is handled by IMatch (rather sophisticated I would guess). The new version uses the v1/search/metadata to look for values so I might need to defer to Mario to see why the pattern passed in does not get found using this logic (shouldn't it also be sophisticated? ;-) ):
$('#btn-find').click(function(e) {
FoundFiles = '';
IMWS.get('v1/search/metadata', {
scope: 'idlist',
idlist: IMatch.idlist.fileWindowSelection,
pattern: document.getElementById('search').value,
tag: 'XMP::dc\\description\\Description\\0'
}).then(function(response) {
resultInfo.text(JSON.stringify(response, null, 2));
// loop through results and create comma seperated list of ids
response.files.forEach(function(element) {
FoundFiles = element["id"] + ',' + FoundFiles;
});
// remove trailing , and any spaces using regex
FoundFiles = FoundFiles.replace(/,\s*$/, "");
// setup variables for number of files found in search
FoundFilesNum = response.files.length;
document.getElementById('findnum').innerHTML = response.files.length;
//console.log('Found: ' + FoundFiles);
}),
function(error) {
displayError(error);
}
});
Ok thanks Andy. For the time being I'm using both the old and the new version of your app. The old for when I need to search for () or [].
I've also adapted your latest version for my needs and it works very nicely but I also would like to see what Mario has to say about this.
Thx John... I await Mario's explanation as well...
QuoteSearching for characters like parenthesis ( or ) or square brackets [ or ] returns no result when one o
pattern is a regular expression. Do you properly escape special characters like () or [] before you send the regular expression to IMatch?
In your code fragment it looks like you are handing over whatever is in the <input> tag...this won't work if somebody tries to find a ( or [ or / ...
PS.:
document.getElementById('search').value is old-school direct DOM access logic.
$('#search)'.val()would do it with jQuery (which is by default included with every IMatch app, unless you changed that).
Simpler and faster (jQuery caches a lot internally).
interesting... yeah - I am starting to get more familiar with the JQuery syntax.. though there is only so much JS one can learn in a month! Maybe next month I'll add JQuery in ;)
So.. I tried the following - but it didn't work... thoughts?
SearchVal = new RegExp(document.getElementById('search').value);
IMWS.get('v1/search/metadata', {
scope: 'idlist',
idlist: IMatch.idlist.fileWindowSelection,
pattern: SearchVal,
tag: 'XMP::dc\\description\\Description\\0'
}).then(function(response) {
SearchVal shows as a regEx but the response fails - even with text that should work such as 'desc' - SearchVal becomes '/desc/'
You are creating a RegExp object, then passing it to the get call. The GET call expects a string argument, so the RegExp is silently converted back to a string representation. But this does not escape the critical chars.
According to https://stackoverflow.com/questions/32846782/how-to-escape-special-characters-in-regular-expressions (https://stackoverflow.com/questions/32846782/how-to-escape-special-characters-in-regular-expressions), you could use a function like this to convert the input from the user to a string with escaped specials chars:
function escapeRegExp(string){
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
I woud have expected some standard function in JavaScript (or jQuery) to to this, but did not find one.
Quote from: Jingo on August 10, 2017, 12:51:08 AM
So.. I tried the following - but it didn't work... thoughts?
al shows as a regEx but the response fails - even with text that should work such as 'desc' - SearchVal becomes '/desc/'
No, wrong approach. You don't hand over a RegExp object (or the string form) to IMWS. IMWS
treats the
pattern param as a regular expression in standard IMatch (PERL) syntax. See the documentation for the /search/metadata endpoint.
This means when your search pattern contains characters with a special meaning in regular expressions, like [ or ( or you need to escape them so IMWS treats them as literals:
Searching for
beach will just work, no special characters in the search term. But to find all files starting with
(Top) you would need to supply
\(Top\).* as the pattern. ( and ) have a special meaning in regular expressions. So do [ and ] or \. You can use the function provided by thrinn above escape your pattern if you don't want it treated as a regular expression.
@Andy
Your current version works well, in particular in only operating on files that need to be changed rather than all selected files - thank you very much. I have some comments of a cosmetic nature.
The width of the dialog needs to be resized to display complete lines. Could you arrange for automatic word-wrap in the 2 description boxes?
The dialog allows for change to either the focused file or to the selected files. I believe that the mail purpose of the app is to make batch changes to files with different descriptions. A single file or a selection of files with identical descriptions can be changed more easily direct in the metadata panel. You could simplify the layout by not displaying the row of "focussed" buttons.
Would it be possible to compress the dialog vertically in its initial opening condition?
Again thanks for doing this.
Hello... thx for confirmation that the app is working appropriately now!
I'm a bit confused on the multi-line and vertical compress requests.. can you explain further and/or show an example that doesn't work?
I have my App Panel open on a 2nd monitor in full screen mode so perhaps I don't see what you are discussing.. the Image Description of Focused File does allow for multi-lines since it is a textarea...
Always happy to make changes to make the app better! - Andy.
Quote from: Jingo on August 13, 2017, 09:16:49 PM
Hello... thx for confirmation that the app is working appropriately now!
I'm a bit confused on the multi-line and vertical compress requests.. can you explain further and/or show an example that doesn't work?
I have my App Panel open on a 2nd monitor in full screen mode so perhaps I don't see what you are discussing.. the Image Description of Focused File does allow for multi-lines since it is a textarea...
Always happy to make changes to make the app better! - Andy.
My monitor is 900 pixels verically. When the app opens only about the top 2 thirds is visible. so I have to scroll down. Perhaps smaller fonts, line spacing and boxes might reduce the height of the dialog?
Quote from: DigPeter on August 13, 2017, 09:27:10 PM
Quote from: Jingo on August 13, 2017, 09:16:49 PM
Hello... thx for confirmation that the app is working appropriately now!
I'm a bit confused on the multi-line and vertical compress requests.. can you explain further and/or show an example that doesn't work?
I have my App Panel open on a 2nd monitor in full screen mode so perhaps I don't see what you are discussing.. the Image Description of Focused File does allow for multi-lines since it is a textarea...
Always happy to make changes to make the app better! - Andy.
My monitor is 900 pixels verically. When the app opens only about the top 2 thirds is visible. so I have to scroll down. Perhaps smaller fonts, line spacing and boxes might reduce the height of the dialog?
Hmm... I thought the Container-fluid DIV I'm using would do this automatically... perhaps I do not have this setup correctly? Any thoughts Mario? I didn't specific a specific size for the window but I do see that it does not resize horizontally like some of the other sample apps do..
Andy your html has 1 missing closing </tr> tag and 6 missing closing </td> tags/ which may or may not contribute to the display problem but it's not helping the display any by their not being there.
On another note regarding this app have you had any luck resolving the issue of searching for () and [] characters? I'm really happy with what you've done so far with this app but it would sure be nice if we could search for those characters too.
Edit: I looked too quickly. Instead of a closing </tr> tag you're missing an opening <tr> tag on line 77.
Missing closing </td> tags are on lines 35, 49, 53, 55, 120 and 124 (with word wrap disabled in the editor).
If tags are missing or not properly closed, the browser makes a "best guess" approach - and this may break complex or fluid layouts.
The breaking points of Bootstrap (between lg, md, sm and xs) are explained here: https://getbootstrap.com/docs/3.3/css/#responsive-utilities
Even Boostrap has its limits and sometimes some manual tricks are required to make a layout behave properly between 600 pixel and 8000 pixel ;D
QuoteMy monitor is 900 pixels verically.
This is a rather small size (Notebook or tablet, probably).
I recommend you use the
built-in scaling for App Panels (Edit > Preferences > Application: User Interface > App Panel Scale. Try something like -2 or -3 for good results.
Thanks mario - I will try that. The computer is a fairly large laptop (Aspire 7750G), which I use as my main machine.
Andy - I have scaled the app panel as suggested by Mario, which has fixed my problem with dialog scaling.
Thx Peter.. glad that worked for you but I'll correct my tags and see if that allows it to "auto-scale".. and will also fix the search criteria today... thx!
Quote from: Mario on August 10, 2017, 08:26:13 AM
Quote from: Jingo on August 10, 2017, 12:51:08 AM
So.. I tried the following - but it didn't work... thoughts?
al shows as a regEx but the response fails - even with text that should work such as 'desc' - SearchVal becomes '/desc/'
No, wrong approach. You don't hand over a RegExp object (or the string form) to IMWS. IMWS treats the pattern param as a regular expression in standard IMatch (PERL) syntax. See the documentation for the /search/metadata endpoint.
This means when your search pattern contains characters with a special meaning in regular expressions, like [ or ( or you need to escape them so IMWS treats them as literals:
Searching for beach will just work, no special characters in the search term. But to find all files starting with (Top) you would need to supply \(Top\).* as the pattern. ( and ) have a special meaning in regular expressions. So do [ and ] or \. You can use the function provided by thrinn above escape your pattern if you don't want it treated as a regular expression.
Hmm... I'm still having trouble with this.. results are not being found even though the special characters are escaped. Any thoughts on what I'm doing wrong?
Image description: Pumpkins on the table [from Dreamy Farm]
Search field entered by user: [from
Code:
function escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
// Narrow idlist from selected images to only those that contain search phrase in description - create list of ids for replacement
$('#btn-find').click(function(e) {
FoundFiles = '';
var SearchVal = escapeRegExp(document.getElementById('search').value);
console.log("Pattern: "+SearchVal);
IMWS.get('v1/search/metadata', {
scope: 'idlist',
idlist: IMatch.idlist.fileWindowSelection,
pattern: SearchVal,
tag: 'XMP::dc\\description\\Description\\0'
}).then(function(response) {
resultInfo.text(JSON.stringify(response, null, 2));
// loop through results and create comma seperated list of ids
response.files.forEach(function(element) {
FoundFiles = element["id"] + ',' + FoundFiles;
Console displays: Pattern: \[from
FoundFiles = 0
I also noticed that this now produces false positives as well... like searching for: z still returns a found file... hmmmmm
You are searching for what, exactly? In your post I cannot see the actual search term.
I tried
var pattern = '[from Dreamy Farm]';
IMWS.get('v1/search/metadata', {
scope: 'idlist',
idlist: IMatch.idlist.fileWindowSelection,
pattern: pattern,
tag: 'XMP::dc\\description\\Description\\0'
which returns the file with the description Pumpkins on the table [from Dreamy Farm]
Note: The parameter name is tags, not tag. I think you have that wrong in at least one of your posted code fragments. But this just means that IMWS will search in all tags.
But I found a bug, the pattern is treated as a contains, not as a regular expression. This is not correct, at least not according to my own documentation.
IMWS hands over the string to the search engine in IMatch. This is basically the same as when you the file window search bar, without the regular expression option. The capabilities and syntax of the search engine is documented in the IMatch help, in the Search Engine topic.
The search engine supports complex patterns like beach AND daytona or beach NOT (Hawaii or Barbados). It also supports escaped/quoted strings: "A day at the (Beach)" means that IMWS does not interpret the content enclosed in "" in any special way and that it actually searches for (Beach).
Solution to your problem would be thus (I assume) to just quote the string you send to IMWS. Just add a " and " in front and back, to force IMWS to treat the search string literally.
The /search/metadata endpoint was one of the first I've written last year. I need to check why I did not use the flag for regular expressions internally. Probably I wanted to make this an endpoint option and then forgot about it. I have made a note and I will revisit this and refactor as needed as soon as a free time slot becomes available.
Correction.
I figured it out. I forgot to list the op parameter for /search/metadata. It is listed for search/attributes so you can look there in the mean time ('between' is not supported by /search/metadata).
If no op is specified for search/metadata it uses the 'contains' search which finds all files where the specified data contains the pattern. This is all still in IMatch search engine snytax, which means that if your pattern contains ( or ) or AND or OR or NOT you need to quote it using ".
If you don't want to 'reveal' the search engine power in your app (to simplify it for users) always quote whatever the user is entering and use the op=contains mode.
I have updated automatic documentation for /search/metadata to list the op parameter and to mention that the pattern is in IMatch search engine syntax.
Thanks Mario... I thought I was going crazy over here!!
Now - it all works. I will be updating a new version shortly that corrects this issue and also corrects the issue where 'z' was found... it was because of the "tag" vs "tags" item you mentioned (oops!).
Much appreciated! - Andy.
Ok.. wanted to post an updated version with the corrected search/replace logic that now finds symbols...
Enjoy! - Andy.
Hey Andy,
Thanks, great. :D
Looks good, although I have not used it really.
But I will :D
Andy - thanks. I look forward to trying it.
Andy thanks from me also. Your app works great for me now...almost.
The only thing that fails for me now is a search for either a single ( or ).
If I search for (b or t) it finds a match but not when I search for only a ( or ).
A search for [ or ] works fine now though.
Quote from: JohnZeman on August 29, 2017, 06:52:05 PM
The only thing that fails for me now is a search for either a single ( or ).
This may be a glitch in how IMatch interprets the search query. I tried in the file window search bar, and it does not work there either.
Since both the endpoint and the search bar use the same code internally, I will have to check this.
Thanks Mario!
The problem is that ( and ) have special meaning in search expressions.
Searching only for a ( should work, if it is properly escaped. But the query parser did not handle a search pattern consisting only of a single escaped ( correctly.
Works in the next release. Since this was undiscovered so far, I doubt many people searched in IMatch 5 or 2017 for single ( ...
Thanks Mario.
Since it looks like we're getting all the problems solved now I'll go ahead and release my latest version of Andy's ultimate description writer app.
This version has Andy's latest code changes plus I've added quite a number of confirmation and nag modal dialogs to minimize the chances of user errors when using this app.
In other words you will see a confirmation modal dialog before you can actually change the descriptions in any way.
Also there are modals that will display if you have not selected any files or have not entered text in the correct place.
Append and prepend operations will display a confirmation modal giving you a preview of what the descriptions will look like after you have appended or prepended text. This allows you to verify your appending or prepending will look the way you want it to before you make any changes to the descriptions.
Looks really good John... since this was your app to begin with (as in your script from previous versions) - I'm not sure it makes sense for there to 2 be versions.. I'll keep my other version in this thread (which has the additional functionality on focused files] in case someone could use it...but will also link yours as the master version in the pinned app discussion so that is the one folks would download. If we need to tweak or expand future, then we can make those changes to your version moving forward (so long as you are ok with this).
Nice work all around!
John thanks. Works well.
Thanks guys.
Andy I'm fine with whatever you want to do with the app. :)