Menu

Skip to content
AppleScriptの穴
  • Home
  • Products
  • Docs
  • Events
  • Forum
  • About This Blog
  • License
  • 仕事依頼

AppleScriptの穴

Useful & Practical AppleScript archive. Click '★Click Here to Open This Script' Link to download each AppleScript

タグ: NSButton

アラートダイアログ上に印刷対象ページ一覧を表示して対象ページを指定

Posted on 7月 17, 2020 by Takaaki Naganoya

アラートダイアログ上にボタンタイプのチェックボックスを並べて、選択したボタンのタイトルを選択するAppleScriptです。

書類の印刷対象を、こまかくページ指定するために作成した部品です。

ヘルプボタンにより、全ボタンの選択/非選択状態を作り出せます。


▲Beta2でAlert Dialogのタイトルまわりが変更されたようですが、、、、うーーん。あと、選択状態をボタンの見かけから知ることができないですわー

AppleScript名:アラートダイアログ上に印刷対象ページ一覧を表示して対象ページを指定
— Created 2020-07-17 by Takaaki Naganoya
— 2020 Piyomaru Software

set aRes to selectByCheckbox("Select each printout page", "Selected pages are the target", 64, "Helvetica") of chooseSeqNum

script chooseSeqNum
  
  
use AppleScript version "2.5"
  
use scripting additions
  
use framework "Foundation"
  
use framework "AppKit"
  
  
property NSFont : a reference to current application’s NSFont
  
property NSView : a reference to current application’s NSView
  
property NSAlert : a reference to current application’s NSAlert
  
property NSColor : a reference to current application’s NSColor
  
property NSButton : a reference to current application’s NSButton
  
property NSOnState : a reference to current application’s NSOnState
  
property NSOffState : a reference to current application’s NSOffState
  
property NSTextField : a reference to current application’s NSTextField
  
property NSMutableArray : a reference to current application’s NSMutableArray
  
property NSButtonTypeOnOff : a reference to current application’s NSButtonTypeOnOff
  
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
  
property NSRunningApplication : a reference to current application’s NSRunningApplication
  
property NSFontAttributeName : a reference to current application’s NSFontAttributeName
  
property NSKernAttributeName : a reference to current application’s NSKernAttributeName
  
property NSMutableParagraphStyle : a reference to current application’s NSMutableParagraphStyle
  
property NSLigatureAttributeName : a reference to current application’s NSLigatureAttributeName
  
property NSMutableAttributedString : a reference to current application’s NSMutableAttributedString
  
property NSUnderlineStyleAttributeName : a reference to current application’s NSUnderlineStyleAttributeName
  
property NSParagraphStyleAttributeName : a reference to current application’s NSParagraphStyleAttributeName
  
property NSForegroundColorAttributeName : a reference to current application’s NSForegroundColorAttributeName
  
  
property theResult : 0
  
property returnCode : 0
  
property cList : {} –Checkbox button object array
  
property bArray : {}
  
  
  
on selectByCheckbox(aMainMessage, aSubMessage, aMaxPage, myFont)
    set paramObj to {myMessage:aMainMessage, mySubMessage:aSubMessage, maxPage:aMaxPage, fontName:myFont}
    
–my chooseItemByCheckBox:paramObj –for Debugging
    
my performSelectorOnMainThread:"chooseItemByCheckBox:" withObject:(paramObj) waitUntilDone:true
    
–> {1, 3, 5, 7, 9, 11}
    
return cList
  end selectByCheckbox
  
  
on chooseItemByCheckBox:(paramObj)
    set aMainMes to (myMessage of paramObj) as string
    
set aSubMes to (mySubMessage of paramObj) as string
    
set aMaxPage to (maxPage of paramObj) as integer
    
set aFontName to (fontName of paramObj) as string
    
    
set cList to {}
    
    
set colNum to 10
    
set rowNum to (aMaxPage div 10) + 1
    
set aLen to (colNum * rowNum)
    
    
set aButtonCellWidth to 56
    
set aButtonCellHeight to 40
    
    
set viewWidth to aButtonCellWidth * colNum
    
set viewHeight to aButtonCellHeight * (rowNum + 1)
    
    
–define the matrix size where you’ll put the radio buttons
    
set matrixRect to current application’s NSMakeRect(0.0, 0.0, viewWidth, viewHeight)
    
set aView to NSView’s alloc()’s initWithFrame:(matrixRect)
    
    
set aCount to 1
    
set aFontSize to 24
    
set bArray to current application’s NSMutableArray’s new()
    
    
–Make Header (Month, Year)
    
set aCalList to makeSeqNumList(1, aMaxPage) of me
    
set aCount to 1
    
    
    
–Make Calendar (Calendar Body)
    
repeat with y from 1 to rowNum
      repeat with x from 1 to colNum
        –try
        
set j to (contents of item aCount of aCalList)
        
set tmpB to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(((x – 1) * aButtonCellWidth), ((aLen – aCount) div colNum) * aButtonCellHeight, aButtonCellWidth, aButtonCellHeight)))
        
        (
tmpB’s setTitle:(j as string))
        (
tmpB’s setFont:(NSFont’s fontWithName:aFontName |size|:aFontSize))
        
–set attrTitle to makeRTFfromParameters((aCount as string), aFontName, aFontSize, 0, (aFontSize * 1.2)) of me
        
–(tmpB’s setAttributedTitle:(attrTitle))
        (
tmpB’s setShowsBorderOnlyWhileMouseInside:true)
        (
tmpB’s setAlignment:(current application’s NSCenterTextAlignment))
        (
tmpB’s setEnabled:(j ≠ ""))
        (
tmpB’s setTarget:me)
        (
tmpB’s setAction:("clicked:"))
        (
tmpB’s setButtonType:(NSButtonTypeOnOff))
        (
tmpB’s setHidden:(j = ""))
        
        (
tmpB’s setTag:(j))
        (
bArray’s addObject:tmpB)
        
        
set aCount to aCount + 1
        
if aCount > aMaxPage then exit repeat
        
–end try
      end repeat
      
if aCount > aMaxPage then exit repeat
    end repeat
    
    
–Select the first radio button item
    
–(tmpArray’s objectAtIndex:0)’s setState:(current application’s NSOnState)
    
set my theResult to {}
    
    (
aView’s setSubviews:bArray)
    
    
— set up alert  
    
set theAlert to NSAlert’s alloc()’s init()
    
tell theAlert
      its setMessageText:aMainMes
      
its setInformativeText:aSubMes
      
its addButtonWithTitle:"OK"
      
its addButtonWithTitle:"Cancel"
      
its setAccessoryView:aView
      
      
–for Help Button
      
its setShowsHelp:(true)
      
its setDelegate:(me)
      
    end tell
    
    
— show alert in modal loop
    
NSRunningApplication’s currentApplication()’s activateWithOptions:0
    
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
    
if (my returnCode as number) = 1001 then error number -128
    
    
set bNumList to (bArray’s valueForKeyPath:"state") as list
    
–set cList to {}
    
repeat with i from 1 to aMaxPage
      set aFlag to (contents of item i of bNumList) as boolean
      
if aFlag = true then
        set the end of cList to contents of i
      end if
    end repeat
    
    
copy cList to bArray
  end chooseItemByCheckBox:
  
  
  
on doModal:aParam
    set (my returnCode) to aParam’s runModal()
  end doModal:
  
  
  
  
on clicked:aParam
    set aTag to (tag of aParam) as integer
    
–clicked
    
if aTag is not in (my theResult) then
      set the end of (my theResult) to aTag
    else
      set theResult to my deleteItem:aTag fromList:theResult
    end if
  end clicked:
  
  
  
  
on deleteItem:anItem fromList:theList
    set theArray to NSMutableArray’s arrayWithArray:theList
    
theArray’s removeObject:anItem
    
return theArray as list
  end deleteItem:fromList:
  
  
  
  
–1D List(数値)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
  
on sort1DNumList:theList ascOrder:aBool
    tell current application’s NSSet to set theSet to setWithArray_(theList)
    
tell current application’s NSSortDescriptor to set theDescriptor to sortDescriptorWithKey_ascending_(missing value, true)
    
set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor}
    
return (sortedList) as list
  end sort1DNumList:ascOrder:
  
  
  
–Help Button Clicked Event Handler
  
on alertShowHelp:aNotification
    set aRes to display dialog "Do you change all checkbox state?" buttons {"All Off", "All On", "Cancel"} default button 3 with icon 1
    
set bRes to (button returned of aRes) as string
    
    
if bRes = "All Off" then
      set bLen to bArray’s |count|()
      
set theResult to {}
      
repeat with i from 0 to bLen
        ((bArray’s objectAtIndex:i)’s setState:(current application’s NSOffState))
      end repeat
      
    else if bRes = "All On" then
      set bLen to bArray’s |count|()
      
set theResult to {}
      
repeat with i from 0 to bLen
        ((bArray’s objectAtIndex:i)’s setState:(current application’s NSOnState))
        
set the end of theResult to i + 1
      end repeat
    end if
    
    
return false –trueを返すと親ウィンドウ(アラートダイアログ)がクローズする
  end alertShowHelp:
  
  
  
  
–書式つきテキストを組み立てる
  
on makeRTFfromParameters(aStr as string, fontName as string, aFontSize as real, aKerning as real, aLineSpacing as real)
    set aVal1 to NSFont’s fontWithName:fontName |size|:aFontSize
    
set aKey1 to (NSFontAttributeName)
    
    
set aVal2 to NSColor’s blackColor()
    
set aKey2 to (NSForegroundColorAttributeName)
    
    
set aVal3 to aKerning
    
set akey3 to (NSKernAttributeName)
    
    
set aVal4 to 0
    
set akey4 to (NSUnderlineStyleAttributeName)
    
    
set aVal5 to 2 –all ligature ON
    
set akey5 to (NSLigatureAttributeName)
    
    
set aParagraphStyle to NSMutableParagraphStyle’s alloc()’s init()
    
aParagraphStyle’s setMinimumLineHeight:(aLineSpacing)
    
aParagraphStyle’s setMaximumLineHeight:(aLineSpacing)
    
set akey7 to (NSParagraphStyleAttributeName)
    
    
set keyList to {aKey1, aKey2, akey3, akey4, akey5, akey7}
    
set valList to {aVal1, aVal2, aVal3, aVal4, aVal5, aParagraphStyle}
    
set attrsDictionary to NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
    
    
set attrStr to NSMutableAttributedString’s alloc()’s initWithString:aStr attributes:attrsDictionary
    
return attrStr
  end makeRTFfromParameters
  
  
  
on makeNSTextField(xPos as integer, yPos as integer, myWidth as integer, myHeight as integer, editableF as boolean, setVal as string, backgroundF as boolean, borderedF as boolean)
    set aNSString to NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(xPos, yPos, myWidth, myHeight))
    
aNSString’s setEditable:(editableF)
    
aNSString’s setStringValue:(setVal)
    
aNSString’s setDrawsBackground:(backgroundF)
    
aNSString’s setBordered:(borderedF)
    
return aNSString
  end makeNSTextField
  
  
  
  
on makeSeqNumList(fromNum as integer, toNum as integer)
    script spd
      property aList : {}
    end script
    
    
set aList of spd to {}
    
    
repeat with i from fromNum to toNum
      set the end of (aList of spd) to i
    end repeat
    
    
return (aList of spd)
  end makeSeqNumList
  
  
end script

★Click Here to Open This Script 

Posted in dialog | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy NSAlert NSButton NSButtonTypeOnOff NSColor NSFont NSFontAttributeName NSForegroundColorAttributeName NSKernAttributeName NSLigatureAttributeName NSMutableArray NSMutableAttributedString NSMutableDictionary NSMutableParagraphStyle NSOffState NSOnState NSParagraphStyleAttributeName NSRunningApplication NSTextField NSUnderlineStyleAttributeName NSView | Leave a comment

アラートダイアログ上にWebViewでCesiumを用いて地球儀上に地図を表示

Posted on 6月 21, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを敷いて、Cesiumを呼び出して地球儀上に地図を表示するAppleScriptです。

もともとのコードは国土地理院のサイトで見つけたものなのですが、地球儀上の地図表示が行えるようです。地球儀以外にも、メルカトル図法などの地図っぽい表示も可能。

右上のメニューから、地図の種類を選択して指定できます。マウスホイールでズームします。

白黒で表示された地図がなかなか面白いところです。

AppleScript名:アラートダイアログ上にWebViewでCesiumを用いて地球儀上に地図を表示.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/06/20
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0

–set aRecArray to {{5, 20}, {25, 67}, {85, 21}, {100, 33}, {220, 88}, {250, 50}, {330, 95}, {410, 12}, {475, 44}, {480, 90}}
–set jsonStr to array2DToJSONArray(aRecArray) of me

–https://github.com/gsi-cyberjapan/gsitiles-cesium/blob/gh-pages/index.html
set myStr to "<!DOCTYPE html>
<html>
<head>
<meta charset=\"UTF-8\">
<title>GSI Tiles on Cesium</title>
<script src=\"https://cesium.com/downloads/cesiumjs/releases/1.63.1/Build/Cesium/Cesium.js\"></script>
<link href=\"https://cesium.com/downloads/cesiumjs/releases/1.63.1/Build/Cesium/Widgets/widgets.css\" rel=\"stylesheet\">
<style>
#cesiumContainer {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
margin: 0;
overflow: hidden;
padding: 0;
font-family: sans-serif;
}
html {
height: 100%;
}
body {
padding: 0;
margin: 0;
overflow: hidden;
height: 100%;
}
</style>
</head>

<body>
<div id=\"cesiumContainer\"></div>
<script>
var viewer = new Cesium.Viewer(’cesiumContainer’, {
imageryProvider: new Cesium.createOpenStreetMapImageryProvider({
url: ’https://cyberjapandata.gsi.go.jp/xyz/std/’,
credit: new Cesium.Credit(’地理院タイル’, ’’, ’https://maps.gsi.go.jp/development/ichiran.html’)
}),
baseLayerPicker: true,
geocoder: false,
homeButton: false
});

viewer.camera.setView({
destination : Cesium.Cartesian3.fromDegrees(140.00, 36.14, 20000000.0)
});
</script>
</body>
</html>"

–set aString to current application’s NSString’s stringWithFormat_(myStr, jsonStr) as string

set paramObj to {myMessage:"Cesium Test", mySubMessage:"This is a Cesium test", htmlStr:myStr}
–my browseStrWebContents:paramObj–for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 1220
  
set aHeight to 720
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script>", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
using terms from scripting additions
    set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  end using terms from
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

★Click Here to Open This Script 

Posted in dialog JavaScript | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上のWebViewでGio.jsを用いて地球儀+データアニメーション表示 v2a

Posted on 6月 20, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを配置し、その上にGio.jsによる地球儀+グラフデータ(アニメーション)を表示するAppleScriptです。

Gio.jsは国際間の貿易収支、Webトラフィックなどの可視化を行うさいに利用するライブラリのようです。さまざまな可視化サンプルをかき集めて、実際にWkWebViewで表示できたもののうち、再利用しやすく利用価値の高そうなものということで、このGio.jsを選んでみました。

派手なビジュアライズの部品はいろいろ見て回りましたが、割とすぐ慣れるというか、飽きるというべきなのか、派手に見せたところで実用性はさほど高まらないといった悟りを得るに至った次第です。

本ScriptはAppleScript側のオブジェクトで与えたデータをもとに表示内容を変更するところまでは作り込んでいませんが、一応、Gio.jsをCDN上のものを呼び出すように書き換えておきました。

AppleScript名:アラートダイアログ上にWebViewでGio.jsを用いて地球儀上にデータアニメーションを表示 v2a.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/06/20
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0

–set aRecArray to {{5, 20}, {25, 67}, {85, 21}, {100, 33}, {220, 88}, {250, 50}, {330, 95}, {410, 12}, {475, 44}, {480, 90}}
–set jsonStr to array2DToJSONArray(aRecArray) of me

–https://github.com/webhacck/gio-js-sample/blob/master/sample2.html
set myStr to "<!DOCTYPE html>
<html>
<head>
<title>Gio.js sample</title>
<meta charset=\"utf-8\">
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
</head>
<body>

<div id=\"globalArea\" style=\"width:1000px;height:700px\"></div>

  <script src=\"https://threejs.org/build/three.min.js\"></script>
  <script src=\"https://cdn.jsdelivr.net/npm/giojs@2.2.1/build/gio.min.js\"></script>
  <script>

var container = document.getElementById( \"globalArea\" );

//config用のオプション設定
var config = {
\"control\": {
\"stats\": false,
\"disableUnmentioned\": false,
\"lightenMentioned\": true,
\"inOnly\": false,
\"outOnly\": false,
\"initCountry\": \"JP\",
\"halo\": true
},
\"color\": {
\"surface\": 1744048,
\"selected\": 2141154,
\"in\": 16765762,
\"out\": 5366382,
\"halo\": 2141154,
\"background\": 0
},
\"brightness\": {
\"ocean\": 0.95,
\"mentioned\": 0.28,
\"related\": 0.74
}
};


//dataset
var data= [
{ e: \"JP\", i: \"CN\", v: 8000000 },
{ e: \"JP\", i: \"TH\", v: 3000000 },
{ e: \"JP\", i: \"ID\", v: 1000000 },
{ e: \"US\", i: \"JP\", v: 8000000 },
{ e: \"RU\", i: \"JP\", v: 3000000 },
{ e: \"IN\", i: \"JP\", v: 1000000 }]

//第2引数にconfigを設定する
var controller = new GIO.Controller( container, config );

controller.addData( data );
controller.init();

</script>

</body>
</html>"

–set aString to current application’s NSString’s stringWithFormat_(myStr, jsonStr) as string

set paramObj to {myMessage:"Gio.js Test", mySubMessage:"This is a Gio.js test", htmlStr:myStr}
–my browseStrWebContents:paramObj–for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 1020
  
set aHeight to 720
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script>", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
using terms from scripting additions
    set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  end using terms from
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

★Click Here to Open This Script 

Posted in dialog | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上にWebViewでChart.jsを表示(Pie Chart) v2

Posted on 6月 15, 2020 by Takaaki Naganoya

Chart.jsを用いてアラートダイアログ上に円グラフを表示するAppleScriptです。

サンプルの円グラフの色使いがいまひとつだったので、Keynoteのグラフの色設定を読み取って利用しています。

ネットワーク接続チェックなど、必要な処理はひととおり行なっている、実戦レベルに近いものです。

さまざまなJavaScript系のグラフ表示のプログラムを試してみましたが、Chart.jsはとてもいい感じです。

AppleScript名:アラートダイアログ上にWebViewでChart.jsを表示(Pie Chart) v2.scptd
set aList to {"field1", "field2", "field3", "field4", "field5"}
set cList to {38, 31, 21, 10, 1}
set dMes1 to "Pie chart Test"
set dMes2 to "This is a simple Donut chart using charts.js"

displayPieChart(aList, cList, dMes1, dMes2) of pieChartLib

script pieChartLib
  —
  
–  Created by: Takaaki Naganoya
  
–  Created on: 2020/06/12
  
—
  
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
  
—
  
use AppleScript version "2.4" — Yosemite (10.10) or later
  
use framework "Foundation"
  
use framework "AppKit"
  
use framework "WebKit"
  
use scripting additions
  
  
property |NSURL| : a reference to current application’s |NSURL|
  
property NSAlert : a reference to current application’s NSAlert
  
property NSString : a reference to current application’s NSString
  
property NSButton : a reference to current application’s NSButton
  
property WKWebView : a reference to current application’s WKWebView
  
property WKUserScript : a reference to current application’s WKUserScript
  
property NSURLRequest : a reference to current application’s NSURLRequest
  
property NSMutableArray : a reference to current application’s NSMutableArray
  
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
  
property NSRunningApplication : a reference to current application’s NSRunningApplication
  
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
  
property WKUserContentController : a reference to current application’s WKUserContentController
  
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
  
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd
  
  
property returnCode : 0
  
property parent : AppleScript
  
  
  
on displayPieChart(aList, cList, dMes1, dMes2)
    –Error Check
    
if length of aList is not equal to length of cList then error "Wrong Parameter items"
    
if length of aList > 18 then error "Too much items"
    
    
set aRes to hasInternetConnection("https://cdnjs.cloudflare.com") of me
    
if aRes = false then error "Internet connection lost"
    
    
–Data convert to JSON strings
    
set aJsonStr to array2DToJSONArray(aList) of me
    
set cJsonStr to array2DToJSONArray(cList) of me
    
    
–Pie Chart Template HTML
    
set myStr to "<!DOCTYPE html>
<html lang=\"ja\">
<head>
<meta charset=\"utf-8\">
 <title>Graph</title>
</head>
<body>
<canvas id=\"myPieChart\"></canvas>
<script src=\"https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js\"></script>

<script>
var ctx = document.getElementById(\"myPieChart\");
var myPieChart = new Chart(ctx, {
type: ’pie’,
data: {
labels: %@,
datasets: [{
backgroundColor: %@,
data: %@
}]
},
options: {
title: {
display: false,
text: \"\"
}
}
});
</script>
</body>
</html>"

    –Color Table From Apple Keynote
    
set bList to {"#118EFE", "#53D529", "#F5AD10", "#FC0007", "#8B2659", "#2A2A2A", "#118EFE", "#53D529", "#F5AD10", "#FC0007", "#8B2659", "#2A2A2A", "#118EFE", "#53D529", "#F5AD10", "#FC0007", "#8B2659", "#2A2A2A"}
    
set bJsonStr to array2DToJSONArray(bList) of me
    
    
set aString to NSString’s stringWithFormat_(myStr, aJsonStr, bJsonStr, cJsonStr) as string
    
    
set paramObj to {myMessage:dMes1, mySubMessage:dMes2, htmlStr:aString}
    
–my browseStrWebContents:paramObj–for debug
    
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true
  end displayPieChart
  
  
on browseStrWebContents:paramObj
    set aMainMes to myMessage of paramObj
    
set aSubMes to mySubMessage of paramObj
    
set htmlString to (htmlStr of paramObj)
    
    
set aWidth to 920
    
set aHeight to 500
    
    
–WebViewをつくる
    
set aConf to WKWebViewConfiguration’s alloc()’s init()
    
    
–指定HTML内のJavaScriptをFetch
    
set jsSource to pickUpFromToStr(htmlString, "<script>", "</script>") of me
    
    
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
    
set userContentController to WKUserContentController’s alloc()’s init()
    
userContentController’s addUserScript:(userScript)
    
aConf’s setUserContentController:userContentController
    
    
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) configuration:aConf
    
aWebView’s setNavigationDelegate:me
    
aWebView’s setUIDelegate:me
    
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
    
using terms from scripting additions
      set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
    end using terms from
    
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
    
    
— set up alert  
    
set theAlert to NSAlert’s alloc()’s init()
    
tell theAlert
      its setMessageText:aMainMes
      
its setInformativeText:aSubMes
      
its addButtonWithTitle:"OK"
      
–its addButtonWithTitle:"Cancel"
      
its setAccessoryView:aWebView
      
      
set myWindow to its |window|
    end tell
    
    
— show alert in modal loop
    
NSRunningApplication’s currentApplication()’s activateWithOptions:0
    
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
    
    
–Stop Web View Action
    
set bURL to |NSURL|’s URLWithString:"about:blank"
    
set bReq to NSURLRequest’s requestWithURL:bURL
    
aWebView’s loadRequest:bReq
    
    
if (my returnCode as number) = 1001 then error number -128
  end browseStrWebContents:
  
  
  
on doModal:aParam
    set (my returnCode) to (aParam’s runModal()) as number
  end doModal:
  
  
  
on viewDidLoad:aNotification
    return true
  end viewDidLoad:
  
  
  
on fetchJSSourceString(aURL)
    set jsURL to |NSURL|’s URLWithString:aURL
    
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
    
return jsSourceString
  end fetchJSSourceString
  
  
  
on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
    set a1Offset to offset of s1Str in aStr
    
if a1Offset = 0 then return false
    
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
    
set a2Offset to offset of s2Str in bStr
    
if a2Offset = 0 then return false
    
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
    
return cStr as string
  end pickUpFromToStr
  
  
  
on array2DToJSONArray(aList)
    set anArray to NSMutableArray’s arrayWithArray:aList
    
set jsonData to NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
    
set resString to NSString’s alloc()’s initWithData:jsonData encoding:(NSUTF8StringEncoding)
    
return resString
  end array2DToJSONArray
  
  
  
on parseByDelim(aData, aDelim)
    set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to aDelim
    
set dList to text items of aData
    
set AppleScript’s text item delimiters to curDelim
    
return dList
  end parseByDelim
  
  
on hasInternetConnection(aURL)
    set aURL to current application’s |NSURL|’s alloc()’s initWithString:aURL
    
set aReq to current application’s NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:5.0
    
set urlRes to (current application’s NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
    
if urlRes = missing value then
      return false
    else
      return true
    end if
  end hasInternetConnection
end script

★Click Here to Open This Script 

Posted in dialog Internet JavaScript URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSJSONSerialization NSMutableArray NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上にd3-cloudを用いてワードクラウドを表示

Posted on 6月 14, 2020 by Takaaki Naganoya

d3-cloudを用いてワードクラウドを表示するAppleScriptです。

本AppleScriptでは、

 {|word|:"NSString", |count|:97}

のように、登場単語、登場回数のように集計ずみのデータをJSONに変換してワードクラウド表示させています。この(AppleScriptの予約語にかぶりまくりな)属性ラベルはd3-cloud側の仕様です。

以前に作った「Tag CloudっぽいRTFの作成」のデータを用いて(属性ラベルを置換して)表示させたものがこちら(↑)。

Tag/Word Cloud関連のJavaScriptについては前から気になって調べてはいたのですが、「ローカルにデータを持つスクリプトが多い」「d3-cloud自体をローカルにインストールさせる例が多い」(実行速度などの問題で?)という状況で、ありもののスクリプトをこのアラートダイアログ上にはりつけたWkWebViewの「箱庭環境」で追加スクリプトのインストールなしで動くように書き換えるのに少々手間取りました。

CDNにホスティングされているd3-cloudを呼び出すことで、ローカルにd3-cloudをインストールせずに実行していますが、将来的にこれが変更・廃止された場合には別のWeb上のどこかにホスティングされているd3-cloudを呼び出すことになります。

ローカルにあるテキストコンテンツ(CotEditorで編集中の文章とか、Pagesで作成中のワープロ文章とか、Keynoteで作成中のプレゼン資料の内容とか)を分析して頻出単語を取り出し、タグクラウドといいますかワードクラウドで表示して全体の見通しをつけるというScriptは作りたいと思っていました。

AppleScript名:アラートダイアログ上にd3-cloudを用いてワードクラウドを表示.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/06/13
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSMutableArray : a reference to current application’s NSMutableArray
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0

set aRecArray to {{|word|:"NSString", |count|:97}, {|word|:"NSURL", |count|:78}, {|word|:"Keynote", |count|:52}, {|word|:"NSMutableArray", |count|:51}, {|word|:"NSAlert", |count|:50}, {|word|:"NSRunningApplication", |count|:49}, {|word|:"NSArray", |count|:48}, {|word|:"CotEditor", |count|:44}, {|word|:"NSColor", |count|:44}, {|word|:"Finder", |count|:41}, {|word|:"NSImage", |count|:39}, {|word|:"Numbers", |count|:38}, {|word|:"NSPredicate", |count|:34}, {|word|:"NSView", |count|:32}, {|word|:"NSButton", |count|:28}, {|word|:"Safari", |count|:28}, {|word|:"NSScreen", |count|:27}, {|word|:"iTunes", |count|:25}, {|word|:"NSUTF8StringEncoding", |count|:24}, {|word|:"NSDictionary", |count|:22}, {|word|:"NSScrollView", |count|:21}, {|word|:"NSBitmapImageRep", |count|:20}, {|word|:"NSFileManager", |count|:20}, {|word|:"NSMutableDictionary", |count|:19}, {|word|:"NSURLRequest", |count|:18}, {|word|:"NSUUID", |count|:18}, {|word|:"NSWindow", |count|:17}, {|word|:"NSBezierPath", |count|:16}, {|word|:"NSFont", |count|:16}, {|word|:"WKWebView", |count|:16}, {|word|:"WKWebViewConfiguration", |count|:16}, {|word|:"NSWorkspace", |count|:15}, {|word|:"Pages", |count|:15}, {|word|:"Script Editor", |count|:15}, {|word|:"System Events", |count|:15}, {|word|:"WKUserContentController", |count|:15}, {|word|:"WKUserScript", |count|:15}, {|word|:"NSAlertSecondButtonReturn", |count|:14}, {|word|:"NSJSONSerialization", |count|:14}, {|word|:"NSSortDescriptor", |count|:14}}
set jsonStr to array2DToJSONArray(aRecArray) of me

–https://qiita.com/january108/items/5388799531c1ace8324e
set myStr to "<!DOCTYPE HTML>
<html lang=\"en\">
<head>
<meta charset=\"UTF-8\">
<title>D3 Word Clouds</title>
<meta name=\"author\" content=\"d4i\"/>
</head>
<body>
<script src=\"http://d3js.org/d3.v3.min.js\" charset=\"utf-8\"></script>
<script src=\"https://cdnjs.cloudflare.com/ajax/libs/d3-cloud/1.2.5/d3.layout.cloud.min.js\"></script>

<script>
  var data = %@;
var width = 600,
height = 400,
fill = d3.scale.category20(),
maxcount = d3.max(data, function(d){ return d.count; } ),
wordcount = data.map(function(d) { return {text: d.word, size: d.count / maxcount * 100}; });

d3.layout.cloud().size([width, height])
.words(wordcount)
.padding(5)
.rotate(function() { return ~~(Math.random() * 2) * 90; })
.font(\"Impact\")
.fontSize(function(d) { return d.size; })
.on(\"end\", draw)
.start();

function draw(words) {
d3.select(\"body\").append(\"svg\")
.attr({
\"width\": width,
\"height\": height
})
.append(\"g\")
.attr(\"transform\", \"translate(\" + [ width >> 1, height >> 1 ] + \")\")
.selectAll(\"text\")
.data(words)
.enter()
.append(\"text\")
.style({
\"font-size\": function(d) { return d.size + \"px\"; },
\"font-family\": \"Impact\",
\"fill\": function(d, i) { return fill(i); }
})
.attr({
\"text-anchor\": \"middle\",
\"transform\": function(d) { return \"translate(\" + [d.x, d.y] + \")rotate(\" + d.rotate + \")\"; }
})
.text(function(d) { return d.text; });
}
</script>
</body>
</html>"

set aString to current application’s NSString’s stringWithFormat_(myStr, jsonStr) as string

set paramObj to {myMessage:"D3 Test", mySubMessage:"This is a d3-cloud word cloud test", htmlStr:aString}
–my browseStrWebContents:paramObj–for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 620
  
set aHeight to 420
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script>", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
using terms from scripting additions
    set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  end using terms from
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to NSMutableArray’s arrayWithArray:aList
  
set jsonData to NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

★Click Here to Open This Script 

Posted in dialog Tag | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSJSONSerialization NSMutableArray NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上にWebViewでGoogle Chartを表示(Column Chart)

Posted on 6月 3, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを配置し、Google Chartsを用いてカラムチャート(縦棒グラフ)を表示するAppleScriptです。

大枠はAppleScriptで、Cocoaの機能を活用してWkWebViewを動的に生成し、その中にJavaScript入りのHTMLを文字列で作って表示させ、WkWebView上でマウスカーソルの挙動に合わせて表示させる(このあたりはGoogle Chartsの機能)という、3階建ぐらいの構造のScriptです。

AppleScriptの配列変数(リスト型変数)をJavaScriptで扱えるJSON形式に変換して、HTML+JavaScriptのテンプレートにはめこんで、WkWebViewに表示させてグラフ描画実行を行なっています。表示データをAppleScriptのデータ(リスト型変数)で与えられる点がチャームポイントです。

AppleScript名:アラートダイアログ上にWebViewでGoogle Chartを表示(Column Chart).scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/05/30
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0

set aList to {{"Year", "Sales", "Expenses", "Profit"}, ¬
  {"2014", 1000, 400, 200}, ¬
  {
"2015", 1170, 460, 250}, ¬
  {
"2016", 660, 1120, 300}, ¬
  {
"2017", 1030, 540, 350}}

set aJsonArrayStr to array2DToJSONArray(aList) of me

–Pie Chart Template HTML
set myStr to "<!DOCTYPE html>
<html lang=\"UTF-8\">
<head>
<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>

<script type=\"text/javascript\">
// Load google charts
google.charts.load(’current’, {’packages’:[’bar’]});
google.charts.setOnLoadCallback(drawChart);

// Draw the chart and set the chart values
function drawChart() {
var data =google.visualization.arrayToDataTable(%@);

// Optional; add a title and set the width and height of the chart
var options = {
chart: {
title: ’Company Performance’,
subtitle: ’Sales, Expenses, and Profit: 2014-2017’,
}
};

// Display the chart inside the <div> element with id=\"columnchart_values\"
var chart = new google.charts.Bar(document.getElementById(\"columnchart_material\"));
chart.draw(data, google.charts.Bar.convertOptions(options));
}
</script>
<body>
<div id=\"columnchart_material\" style=\"width: 800px; height: 200;\"></div>
</body>
</html>"

set aString to current application’s NSString’s stringWithFormat_(myStr, aJsonArrayStr) as string

set paramObj to {myMessage:"Column Chart Test", mySubMessage:"This is a simple Column chart using google charts", htmlStr:aString}
–my browseStrWebContents:paramObj–for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 820
  
set aHeight to 220
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script type=\"text/javascript\">", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
using terms from scripting additions
    set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  end using terms from
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

★Click Here to Open This Script 

Posted in dialog | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上にWebViewでGoogle Chartを表示(Bubble Chart)

Posted on 6月 1, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを配置し、Google Chartsを用いてバブルチャートを表示するAppleScriptです。

バブルチャートというのは、3軸の数値の組みわせデータをX軸とY軸に加え、バブル(円)のサイズでもう1軸表現したもののようです。

サンプルでは、X軸に平均寿命、Y軸に出生率、Z軸に人口をとっています。データ件数がそんなに多くなくて、データが散らばっている場合にはその傾向がよく把握できそうです(本グラフのように)。

自動処理のワークフローにおいて本Scriptがどの程度役立つかについては、いろいろ考えてみたものの「多分、Blogに掲載するぐらいしか使い道がないよね!」というところでしょうか。やはり、オーソドックスな円グラフや棒グラフのほうが使い手がよさそうです。あとは、デモンストレーションぐらいでしょうか。Google Chartsを用いたダイアログ部品自体が、デモ向けのそれほど意味のなさそうな内容であります。

AppleScript名:アラートダイアログ上にWebViewでGoogle Chartを表示(Bubble Chart).scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/05/30
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions
–https://developers.google.com/chart/interactive/docs/gallery/bubblechart

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0

set aList to {{"ID", "平均寿命", "出生率", "地域", "人口"}, ¬
  {"CAN", 80.66, 1.67, "北米", 33739900}, ¬
  {
"DEU", 79.84, 1.36, "欧州", 81902307}, ¬
  {
"DNK", 78.6, 1.84, "欧州", 5523095}, ¬
  {
"EGY", 72.73, 2.78, "中東", 79716203}, ¬
  {
"GBR", 80.05, 2, "欧州", 61801570}, ¬
  {
"IRN", 72.49, 1.7, "中東", 73137148}, ¬
  {
"IRQ", 68.09, 4.77, "中東", 31090763}, ¬
  {
"ISR", 81.55, 2.96, "中東", 7485600}, ¬
  {
"RUS", 68.6, 1.54, "欧州", 141850000}, ¬
  {
"USA", 78.09, 2.05, "北米", 307007000}}

set aJsonArrayStr to array2DToJSONArray(aList) of me

–Pie Chart Template HTML
set myStr to "<!DOCTYPE html>
<html lang=\"UTF-8\">
<head>
<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>
<script type=\"text/javascript\">
// Load google charts
google.charts.load(’current’, {’packages’:[’corechart’]});
google.charts.setOnLoadCallback(drawSeriesChart);

// Draw the chart and set the chart values
function drawSeriesChart() {
var data =google.visualization.arrayToDataTable(%@);

// Optional; add a title and set the width and height of the chart
var options = {
title: ’Correlation between life expectancy, fertility rate ’ + ’and population of some world countries (2010)’,
hAxis: {title: ’平均寿命’},
vAxis: {title: ’出生率’},
bubble: {textStyle: {fontSize: 11}} };

// Display the chart inside the <div> element with id=\"barchart\"
var chart = new google.visualization.BubbleChart(document.getElementById(’series_chart_div’));
chart.draw(data, options);
}
</script>
<body>
<div id=\"series_chart_div\" style=\"width: 800px; height: 200;\"></div>
</body>
</html>"

set aString to current application’s NSString’s stringWithFormat_(myStr, aJsonArrayStr) as string

set paramObj to {myMessage:"Bubble Chart Test", mySubMessage:"This is a simple Bubble Chart using google charts", htmlStr:aString}
–my browseStrWebContents:paramObj–for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 820
  
set aHeight to 220
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script type=\"text/javascript\">", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
using terms from scripting additions
    set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  end using terms from
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

★Click Here to Open This Script 

Posted in dialog | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上にWebViewでGoogle Chartを表示(Gantt Chart)

Posted on 6月 1, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを配置し、Google Chartsを用いてガントチャートを表示するAppleScriptです。

ガントチャートの表示が行えるのは、なかなか便利そうです。ガントチャート系でAppleScriptから操作が行えるのは、Omni Planぐらいなので、ガントチャート表示用部品が増えるのはいいことです。

# ただ、ガントチャートのデータをもとに自動処理したことはありません。人間との間で行う対話処理が重要なので、自動処理で「あとはよろしくぅ!」というワークフローがそんなに思いつきません(予定が変わった担当者に自動で連絡しておくぐらい?)

何らかのデータ処理を行なった末にガントチャートで結果を表示する……という流れになるとは思うのですが、結果に納得できない場合にデータ修正できるようになっていないと、「なんですかそれは?」という話になりかねません。

なので、表UIでデータを入力し、その内容を反映させたガントチャートを表示。表UIとガントチャートの間で自由に行き来できる必要があります。Google Chartsではこのように複数のグラフUIを組み合わせる(並べて表示、再描画を連動)こともできるため、そういう組み合わせで利用するための「下調べ」といったところでしょう。

AppleScript名:アラートダイアログ上にWebViewでGoogle Chartを表示(Gantt Chart).scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/05/27
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property NSBundle : a reference to current application’s NSBundle
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0
property aBrowserAgentRes : ""

–Sample Data
–set aJsonArrayStr to array2DToJSONArray(aList) of me

–Map Template HTML
set myStr to "<!DOCTYPE html>
<html lang=\"UTF-8\">
<head>
<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>

<script type=\"text/javascript\">
google.charts.load(’current’, {’packages’:[’gantt’]});
google.charts.setOnLoadCallback(drawChart);

function daysToMilliseconds(days) {
return days * 24 * 60 * 60 * 1000;
}

function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn(’string’, ’Task ID’);
data.addColumn(’string’, ’Task Name’);
data.addColumn(’date’, ’Start Date’);
data.addColumn(’date’, ’End Date’);
data.addColumn(’number’, ’Duration’);
data.addColumn(’number’, ’Percent Complete’);
data.addColumn(’string’, ’Dependencies’);

data.addRows([
[’Research’, ’Find sources’,
new Date(2015, 0, 1), new Date(2015, 0, 5), null, 100, null],
[’Write’, ’Write paper’,
null, new Date(2015, 0, 9), daysToMilliseconds(3), 25, ’Research,Outline’],
[’Cite’, ’Create bibliography’,
null, new Date(2015, 0, 7), daysToMilliseconds(1), 20, ’Research’],
[’Complete’, ’Hand in paper’,
null, new Date(2015, 0, 10), daysToMilliseconds(1), 0, ’Cite,Write’],
[’Outline’, ’Outline paper’,
null, new Date(2015, 0, 6), daysToMilliseconds(1), 100, ’Research’]
]);

var options = {
height: 275
};

var chart = new google.visualization.Gantt(document.getElementById(’chart_div’));

chart.draw(data, options);
}
</script>
</head>
<body>
  <div id=\"chart_div\"></div>
</body>
</html>"

–set aString to NSString’s stringWithFormat_(myStr, aJsonArrayStr) as string

set paramObj to {myMessage:"Google Gantt Chart Test", mySubMessage:"This is a simple Gantt Chart using google charts", htmlStr:myStr}
–my browseStrWebContents:paramObj –for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 1000
  
set aHeight to 300
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script type=\"text/javascript\">", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
  
set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to NSString’s alloc()’s initWithData:jsonData encoding:(NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

★Click Here to Open This Script 

Posted in dialog | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSArray NSBundle NSButton NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上にWebViewでGoogle Chartを表示(Bar Chart)

Posted on 5月 30, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを配置し、Google Chartsを用いてbarChartを表示するAppleScriptです。

Googleのオンラインドキュメント品質が一定になっておらず、一番簡単なはずの棒グラフを書かせるのに手間取ってしまいました。

Cocoa Scriptingを始めた当初は、このJavaScriptを含んだHTMLコンテンツをダイアログ上に表示してインタラクティブな表示を行わせるなど、夢のまた夢という感じでしたが、いまでは見慣れた光景になってしまいました。

箱庭ダイアログ系AppleScriptも、YouTubeの動画表示ができるようになった頃から、進化にはずみがついた気がします。

ひととおりGoogle Chartsを表示できるようになったので、チャート表示のScript Libraryにまとめ、sdef(AppleScript用語辞書)をかぶせてカプセル化するといい感じでしょうか。Google Charts Scripting Libとかいって、display google chartコマンドを実行するのでしょうか。そこまで作り込むと、無料公開は勘弁して欲しいところですけれども。

AppleScript名:アラートダイアログ上にWebViewでGoogle Chartを表示(Bar Chart)v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/03/02
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0

set aList to {{"City", "2010 Population", "2000 Population"}, ¬
  {"New York City, NY", 8175000, 8008000}, ¬
  {
"Los Angeles, CA", 3792000, 3694000}, ¬
  {
"Chicago, IL", 2695000, 2896000}, ¬
  {
"Houston, TX", 2099000, 1953000}, ¬
  {
"Philadelphia, PA", 1526000, 1517000}}

set aJsonArrayStr to array2DToJSONArray(aList) of me

–Pie Chart Template HTML
set myStr to "<!DOCTYPE html>
<html lang=\"UTF-8\">
<head>
<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>

<script type=\"text/javascript\">
// Load google charts
google.charts.load(’current’, {’packages’:[’corechart’, ’bar’]});
google.charts.setOnLoadCallback(drawChart);

// Draw the chart and set the chart values
function drawChart() {
var data =google.visualization.arrayToDataTable(%@);

// Optional; add a title and set the width and height of the chart
var options = {
  title: ’Population’,
  chartArea: {width: ’400’},
  isStacked: true,
  hAxis: {
   title: ’Total Population’,
   minValue: 0,
  },
  vAxis: {
   title: ’City’
  }
};

// Display the chart inside the <div> element with id=\"barchart\"
var chart = new google.visualization.BarChart(document.getElementById(\"barchart_values\"));
chart.draw(data, options);
}
</script>
<body>
<div id=\"barchart_values\" style=\"width: 800px; height: 200;\"></div>
</body>
</html>"

set aString to current application’s NSString’s stringWithFormat_(myStr, aJsonArrayStr) as string

set paramObj to {myMessage:"Bar Chart Test", mySubMessage:"This is a simple bar chart using google charts", htmlStr:aString}
–my browseStrWebContents:paramObj–for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 820
  
set aHeight to 220
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script type=\"text/javascript\">", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
using terms from scripting additions
    set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  end using terms from
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

★Click Here to Open This Script 

Posted in dialog URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上にWebViewでGoogle Chartを表示(WordTree)

Posted on 5月 29, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを配置し、Google Chartsを用いてWordTreeを表示するAppleScriptです。

Mindmap風の図を表示するので、純粋にMindmapの表示部品として使えるとよさそうですが、そういうわけでもないようです。図を表示するだけです。

また、Wordtree中の途中のノードを選択するとツリーが閉じたりしますが、どのノードを選択したかといった情報を(現状では)取得できるわけでもないため、超多項目の選択User Interfaceに使いたい場合に「使えそうで使えない」という浮世離れした部品になっています。

一応、JavaScript内ではノードのクリックイベントを拾うことができましたが、selectionで得られる属性値が「word」「color」「weight」といった、個別にノードを特定できる値ではないものばかりなので(idぐらい取れてもいいんやで)、選択UIとして使うのはつらそうです。さらに、WkWebView内のJavaScriptからその「外側の外側」にいるAppleScriptにイベントや値を渡す方法がさっぱり見つかりません。JavaScript側からローカルのファイル……に書けそうな気配はないので、cookie経由で値を受け渡すぐらいでしょうか。


▲Appleのサンプルコード「TreeView」(Written in Objective-C)。これがもっと使いまわしやすい部品として書きこなれていればいいのですが、、、、

# Mindmap風の選択UIは、なかなか手を加えてすぐに使いまわしやすい部品になっていなくて、、

プログラム自体は他のScriptとの共有部品ばかりで、新規に起こしたものはほとんどありません。


▲選択肢をツリーで描画してクリック選択でき、選択した内容をもとに処理できるという意味ではGraphViz+Dot言語が難易度低くていい感じ?(実際に使っています)


▲これもゆくゆくは多項目表示の部品として利用? 制約条件(不自由さ)を設けることで発想につなげようというコンセプトなので、自由なデータ表現の部品にはならないという見方も

AppleScript名:アラートダイアログ上にWebViewでGoogle Chartを表示(WordTree1).scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/05/27
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property NSBundle : a reference to current application’s NSBundle
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0
property aBrowserAgentRes : ""

–Sample Data
set aList to {{"Phrases"}, ¬
  {"cats are better than dogs"}, ¬
  {
"cats eat kibble"}, ¬
  {
"cats are better than hamsters"}, ¬
  {
"cats are awesome"}, ¬
  {
"cats are people too"}, ¬
  {
"cats eat mice"}, ¬
  {
"cats meowing"}, ¬
  {
"cats in the cradle"}, ¬
  {
"cats eat mice"}, ¬
  {
"cats in the cradle lyrics"}, ¬
  {
"cats eat kibble"}, ¬
  {
"cats for adoption"}, ¬
  {
"cats are family"}, ¬
  {
"cats eat mice"}, ¬
  {
"cats are better than kittens"}, ¬
  {
"cats are evil"}, ¬
  {
"cats are weir"}, ¬
  {
"cats eat mice"}}

set aJsonArrayStr to array2DToJSONArray(aList) of me

–Map Template HTML
set myStr to "<!DOCTYPE html>
<html lang=\"UTF-8\">
<head>
<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>

<script type=\"text/javascript\">
google.charts.load(’current’, {’packages’:[’wordtree’]});
google.charts.setOnLoadCallback(drawChart);

function drawChart() {
var data = google.visualization.arrayToDataTable(%@);

var options = {
wordtree: {
format: ’implicit’,
word: ’cats’
}
};

  var chart = new google.visualization.WordTree(document.getElementById(’wordtree’));
chart.draw(data, options);
}
</script>
</head>
<body>
  <div id=\"wordtree\" style=\"width: 900px; height: 500px;\"></div>
</body>
</html>"

set aString to NSString’s stringWithFormat_(myStr, aJsonArrayStr) as string

set paramObj to {myMessage:"Google Word Tree Test", mySubMessage:"This is a simple Word Tree using google charts", htmlStr:aString}
–my browseStrWebContents:paramObj –for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 920
  
set aHeight to 540
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script type=\"text/javascript\">", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
  
set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to NSString’s alloc()’s initWithData:jsonData encoding:(NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

★Click Here to Open This Script 

Posted in dialog | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSArray NSBundle NSButton NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上にWebViewでGoogle Chartsを表示(Geo Chart 1)

Posted on 5月 24, 2020 by Takaaki Naganoya

NSAlertのアラートダイアログ上にGoogleChartsを用いたGeoChartを表示するAppleScriptです。

Geo Chartに表示されている地図の上でマウスカーソルを移動させると、Chartが反応してデータ表示を行います。

本Scriptに掲載しているAPI KeyはGoogleに掲載されているサンプル用のものであり、サンプルデータの表示以外には使用できません。Google開発者アカウントを取得し、API Keyを取得して記入しておく必要があります。

AppleScript名:アラートダイアログ上にWebViewでGoogle Chartを表示(Geo Chart 1).scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/03/02
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property NSBundle : a reference to current application’s NSBundle
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0
property aBrowserAgentRes : ""

set mapsAPIKey to "AIzaSyD-9tSrke72PouQMnMX-a7eZSW0jkFMBWY" –for demonstration only

my performSelectorOnMainThread:"getSafariUserAgentString:" withObject:(missing value) waitUntilDone:true

–Sample Data
set aList to {{"Country", "Popularity"}, ¬
  {"Germany", 200}, ¬
  {
"United States", 300}, ¬
  {
"Brazil", 400}, ¬
  {
"Canada", 500}, ¬
  {
"France", 600}, ¬
  {
"RU", 700}}

set aJsonArrayStr to array2DToJSONArray(aList) of me

–Map Template HTML
set myStr to "<!DOCTYPE html>
<html lang=\"UTF-8\">
<head>
<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>

<script type=\"text/javascript\">
google.charts.load(’current’, {’packages’:[’geochart’], ’mapsApiKey’: ’%@’});
google.charts.setOnLoadCallback(drawRegionsMap);

function drawRegionsMap() {
var data = google.visualization.arrayToDataTable(%@);

var options = {};

var chart = new google.visualization.GeoChart(document.getElementById(’regions_div’));
chart.draw(data, options);
};
</script>
</head>
<body>
  <div id=\"regions_div\" style=\"width: 900px; height: 500px;\"></div>
</body>
</html>"

set aString to NSString’s stringWithFormat_(myStr, mapsAPIKey, aJsonArrayStr) as string

set paramObj to {myMessage:"Google GeoChart Test", mySubMessage:"This is a simple GeoChart using google charts", htmlStr:aString}
–my browseStrWebContents:paramObj –for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 920
  
set aHeight to 520
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script type=\"text/javascript\">", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
aWebView’s setCustomUserAgent:(my aBrowserAgentRes)
  
  
set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to NSString’s alloc()’s initWithData:jsonData encoding:(NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

–Safariと同じUser Agentの文字列を取得する
on getSafariUserAgentString:anObject
  set aBundle to NSBundle’s bundleWithIdentifier:"com.apple.Safari"
  
set aVer to (aBundle’s infoDictionary()’s objectForKey:"CFBundleShortVersionString") as text
  
–>  "9.0.2"
  
  
set aBuildNo to (aBundle’s infoDictionary()’s objectForKey:"CFBundleVersion") as text
  
–>  "11601.3.6"
  
  
set {v1, v2, v3} to parseVersionNumber(aBuildNo) of me
  
set aV1 to NSString’s stringWithString:v1
  
set bV1 to aV1’s substringFromIndex:2 –3 characters from tail –?????
  
–> "601"
  
  
set bStr to retStrFromArrayWithDelimiter({bV1, v2, v3}, ".") of me
  
  
set aWebView to WebView’s alloc()’s init()
  
set aRes to (aWebView’s stringByEvaluatingJavaScriptFromString:"navigator.userAgent") as text
  
–>  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.6 (KHTML, like Gecko)"
  
  
set aBrowserAgentRes to (aRes & " Version/" & aVer & " Safari/" & bStr)
end getSafariUserAgentString:

–バージョン番号文字列からメジャーバージョンを取り出し数値として返す
on parseVersionNumber(a)
  set aStr to current application’s NSString’s stringWithString:a
  
set aRes to (aStr’s componentsSeparatedByString:".")
  
set bRes to aRes’s allObjects()
  
return bRes as list
end parseVersionNumber

–リストを指定デリミタをはさんでテキスト化
on retStrFromArrayWithDelimiter(aList, aDelim)
  set anArray to NSArray’s arrayWithArray:aList
  
set aRes to anArray’s componentsJoinedByString:aDelim
  
return aRes as text
end retStrFromArrayWithDelimiter

★Click Here to Open This Script 

Posted in dialog | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSArray NSBundle NSButton NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

ダブルクリックとコンテクストメニュー表示をサポートするボタン

Posted on 5月 22, 2020 by Takaaki Naganoya

Xcode上で作成するAppleScriptアプリケーションで、ダブルクリックとコンテクストメニュー表示を受け入れるボタンのプロジェクトの試作品です。

–> Download Xcode Projext (doubleClick v2)

ボタンでシングルクリックを受け付けるのは簡単ですが、ダブルクリックを受信するためには、少し手間がかかります。まして、コンテクストメニュー表示は、、、、、

この試作品では、クリックされたボタンを識別できていません。ダブルクリックされたボタンのTagとか、コンテクストメニュー表示させたボタンのTagを取得できるように改変したいところです。

こうした(↑)テーマセレクタで、ダブルクリックでそのままテーマ選択を行えるように対処したいところです。テーマセレクタとか環境設定なんて、アプリケーション開発の最後のほうでやっつけ的に行うので、それほど気合いを入れて作っているものではありません(個人の見解です)。

当初はもっと仕様的に「盛った」ものを作ろうとデザインしたのですが、いざ作ってみたら技術的に難しすぎたので、技術的な難易度を大幅に下げて実装してみました(ここで妥協ができないとモノが仕上がりません)。

自分はRadio Buttonに画像を載せて「選択状態だけとれればいい」と割り切って実装しましたが、たしかにダブルクリックぐらいは受け付けたほうがよいでしょう。Keynoteのテーマセレクタのように。

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— doubleClick
—
— Created by Takaaki Naganoya on 2020/01/29.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script AppDelegate
  
  
property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
property theView : missing value
  
property DCButton : missing value
  
property aConMenu : missing value
  
  
on applicationWillFinishLaunching:aNotification
    —
  end applicationWillFinishLaunching:
  
  
on applicationShouldTerminate:sender
    return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
on clicked:aSender
    display dialog "Clicked"
  end clicked:
  
  
on dispContextual:aEvent
    current application’s NSMenu’s popUpContextMenu:(aConMenu) withEvent:(aEvent) forView:(theView)
  end dispContextual:
  
  
on action:aSender
    display dialog (tag of aSender) as string
  end action:
  
end script

★Click Here to Open This Script 

AppleScript名:DCButton.applescript
—
— DCButton.applescript
— Kamenoko
—
— Created by Takaaki Naganoya on 2020/05/18.
— Copyright © 2020 Takaaki Naganoya. All rights reserved.
—

script DCButton
  property parent : class "NSButton"
  
  
on mouseDown:aEvent
    set buttonNum to aEvent’s buttonNumber()
    
set aEtype to aEvent’s type()
    
set aCount to aEvent’s clickCount()
    
    
if aCount = 3 then –Triple Click
      display dialog "Triple Click"
      
    else if aCount = 2 then –Double Click
      display dialog "Double Click"
      
    end if
  end mouseDown:
  
  
on mouseMoved:theEvent
    log {"mouseMoved", aEvent}
  end mouseMoved:
  
  
on mouseUp:aEvent
    log {"mouseUp", aEvent}
  end mouseUp:
  
  
on mouseDragged:aEvent
    log "mouseDragged"
  end mouseDragged:
  
  
on rightMouseDown:aEvent
    –Display Contextual Menu
    
current application’s NSApp’s delegate()’s performSelector:"dispContextual:" withObject:(aEvent)
  end rightMouseDown:
  
  
on rightMouseUp:aEvent
    log {"rightMouseUp", aEvent}
  end rightMouseUp:
  
  
on clicked:aSender
    continue clicked:(missing value)
  end clicked:
  
  
(*
  on mouseEntered:theEvent
    log {"mouseEntered", theEvent}
  end mouseEntered:

  on mouseExited:theEvent
    log {"mouseExited", theEvent}
  end mouseExited:
*)
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode | Tagged 10.13savvy 10.14savvy 10.15savvy NSButton NSMenu | Leave a comment

クリップボード内の文字種別を集計して円グラフ表示

Posted on 5月 16, 2020 by Takaaki Naganoya

クリップボード内に文字列が入っていれば、いいかえれば「文字列をコピーした状態であれば」、クリップボード内容をテキストとして取り出して文字種別ごとに集計して構成比を円グラフで表示するAppleScriptです。

# CAUTION: This script process Japanese characters. So, this script make no sense for other language users

グラフ表示部分は手抜きでGoogle Chartsを呼び出しているだけなので、Macがネットワークに接続されていない場合には表示できません。

macOS標準装備のScript Menuに入れて使っています。複数の円グラフを表示させることも可能なので、典型的な例文(新聞、論文、なろう系、技術系文章、文学作品)のグラフを一覧表示して、どの例文の使用比率に近いかといったことを見てわかるようにできそうです(やらないけど)。

ありものをただ引っ張り出してきて、Script文でつないだだけなので、オリジナルで記述した部分はほとんどありません。

とはいえ、技術的にはいろいろなハードルを乗り越えまくって動かしているものでもあります。

・メインスレッドでしか動かせないWkWebView、NSAlertをScriptから呼び出している(実行環境に左右されずに実行)
・Cocoa Scriptingを行うAppleScriptObjCをscript文でscript object化して(カプセル化して)呼び出し、再利用
・WkWebViewをdialog内に表示して、マウスオーバーでデータ内容が見えるようなインタラクティブなグラフを表示

といった、いろいろ無茶なことをやっているScriptです。ただ、すでに見慣れた光景になりつつありますけれども。

AppleScript名:クリップボード内の文字種別を集計して円グラフ表示.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/05/14
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property NSScreenSaverWindowLevel : a reference to current application’s NSScreenSaverWindowLevel
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0

–Calc Clipboard
set aRes to clipAnaliticsMain() of clipboardInfoKit
if aRes = false then return —クリップボードが空だった(文字列的に)

set totalC to totalC of aRes

set aList to {{"文字種別", "構成比"}} & rating of aRes

set aJsonArrayStr to array2DToJSONArray(aList) of me

–Pie Chart Template HTML
set myStr to "<!DOCTYPE html>
<html lang=\"UTF-8\">
<body>
<div id=\"piechart\"></div>

<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>

<script type=\"text/javascript\">
// Load google charts
google.charts.load(’current’, {’packages’:[’corechart’]});
google.charts.setOnLoadCallback(drawChart);

// Draw the chart and set the chart values
function drawChart() {
var data = google.visualization.arrayToDataTable(%@);

// Optional; add a title and set the width and height of the chart
var options = {
is3D: true,
   ’width’:600, ’height’:400
};

// Display the chart inside the <div> element with id=\"piechart\"
var chart = new google.visualization.PieChart(document.getElementById(’piechart’));
chart.draw(data, options);
}
</script>

</body>
</html>"

set aString to current application’s NSString’s stringWithFormat_(myStr, aJsonArrayStr) as string

set paramObj to {myMessage:"文字種別構成比", mySubMessage:"クリップボードの内容を集計。文字数は" & (totalC as string) & "文字", htmlStr:aString}
–my browseStrWebContents:paramObj–for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 600
  
set aHeight to 450
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script type=\"text/javascript\">", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight – 100)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
  
set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
myWindow’s setLevel:(NSScreenSaverWindowLevel)
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

script clipboardInfoKit
  use scripting additions
  
use framework "Foundation"
  
property parent : AppleScript
  
  
property NSString : a reference to current application’s NSString
  
property NSNumber : a reference to current application’s NSNumber
  
property NSDictionary : a reference to current application’s NSDictionary
  
property NSCountedSet : a reference to current application’s NSCountedSet
  
property NSCharacterSet : a reference to current application’s NSCharacterSet
  
property NSMutableArray : a reference to current application’s NSMutableArray
  
property NSNumberFormatter : a reference to current application’s NSNumberFormatter
  
property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch
  
property NSNumberFormatterRoundUp : a reference to current application’s NSNumberFormatterRoundUp
  
property NSNumberFormatterRoundDown : a reference to current application’s NSNumberFormatterRoundDown
  
  
  
on clipAnaliticsMain()
    set cCount to 0
    
set hCount to 0
    
set kCount to 0
    
set oCount to 0
    
set tCount to 0
    
    
using terms from scripting additions
      set aStr to (the clipboard as «class utf8»)
      
if aStr = "" then
        display dialog "No text data in clipboard" buttons {"OK"} default button 1
        
return false
      end if
    end using terms from
    
    
set aRec to detectCharKindRating(aStr) of me
    
    
set cCount to cCount + (kanjiNum of aRec)
    
set hCount to hCount + (hiraganaNum of aRec)
    
set kCount to kCount + (katakanaNum of aRec)
    
set oCount to oCount + (otherNum of aRec)
    
set tCount to tCount + (totalCount of aRec)
    
    
return {rating:{{"漢字", cCount}, {"ひらがな", hCount}, {"カタカナ", kCount}, {"その他", oCount}}, totalC:tCount}
  end clipAnaliticsMain
  
  
  
  
on detectCharKindRating(aStr as string)
    set aList to NSMutableArray’s arrayWithArray:(characters of aStr)
    
set theCountedSet to NSCountedSet’s alloc()’s initWithArray:aList
    
set theEnumerator to theCountedSet’s objectEnumerator()
    
    
set cCount to 0
    
set hCount to 0
    
set kCount to 0
    
set oCount to 0
    
set totalC to length of aStr
    
    
repeat
      set aValue to theEnumerator’s nextObject()
      
if aValue is missing value then exit repeat
      
      
set aStr to aValue as string
      
set tmpCount to (theCountedSet’s countForObject:aValue)
      
      
set s1Res to chkKanji(aStr) of me
      
set s2Res to chkKatakana(aStr) of me
      
set s3Res to chkHiragana(aStr) of me
      
      
if s1Res = true then
        set cCount to cCount + tmpCount
      else if s2Res = true then
        set kCount to kCount + tmpCount
      else if s3Res = true then
        set hCount to hCount + tmpCount
      else
        set oCount to oCount + tmpCount
      end if
    end repeat
    
    
set ckRes to roundingUp((cCount / totalC) * 100, 1) of me
    
set kkRes to roundingUp((kCount / totalC) * 100, 1) of me
    
set hgRes to roundingUp((hCount / totalC) * 100, 1) of me
    
set otRes to roundingUp((oCount / totalC) * 100, 1) of me
    
    
return {kanjiNum:cCount, kanjiRating:ckRes, hiraganaNum:hCount, hiraganaRating:hgRes, katakanaNum:kCount, katakanaRating:kkRes, otherNum:oCount, otherRating:otRes, totalCount:totalC}
  end detectCharKindRating
  
  
  
on chkKanji(aChar)
    return detectCharKind(aChar, "[一-龠]") of me
  end chkKanji
  
  
on chkHiragana(aChar)
    return detectCharKind(aChar, "[ぁ-ん]") of me
  end chkHiragana
  
  
on chkKatakana(aChar)
    return detectCharKind(aChar, "[ァ-ヶ]") of me
  end chkKatakana
  
  
on detectCharKind(aChar, aPattern)
    set aChar to NSString’s stringWithString:aChar
    
set searchStr to NSString’s stringWithString:aPattern
    
set matchRes to aChar’s rangeOfString:searchStr options:(NSRegularExpressionSearch)
    
if matchRes’s location() = (current application’s NSNotFound) or (matchRes’s location() as number) > 9.99999999E+8 then
      return false
    else
      return true
    end if
  end detectCharKind
  
  
on roundingUp(aNum, aDigit as integer)
    set a to aNum as real
    
set aFormatter to NSNumberFormatter’s alloc()’s init()
    
aFormatter’s setMaximumFractionDigits:aDigit
    
aFormatter’s setRoundingMode:(NSNumberFormatterRoundUp)
    
set aStr to aFormatter’s stringFromNumber:(NSNumber’s numberWithFloat:a)
    
return (aStr as text) as real
  end roundingUp
end script

★Click Here to Open This Script 

Posted in dialog Internet JavaScript Text | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSCharacterSet NSCountedSet NSDictionary NSMutableArray NSNumber NSNumberFormatter NSNumberFormatterRoundDown NSNumberFormatterRoundUp NSRegularExpressionSearch NSRunningApplication NSScreenSaverWindowLevel NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上にWebViewでGoogle Chartsを表示(Calendar Chart)

Posted on 5月 7, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを配置し、Google Chartsを用いてCalendar Chartを表示するAppleScriptです。

自分の開発環境(MacBook Pro Retina 2012, Core i7 2.6GHz)で100日間のアクセス履歴を処理して7秒強ぐらいで描画が終了します。

調子に乗って300日分のアクセス履歴を処理したところ、表示まで1分ほどかかりました。あまり長い期間の描画を行わせるのは(このプログラムの書き方だと)向いていないと感じます。いまのところテストしただけで実用性は考えていませんが、この程度のグラフなら自前でNSImage上にボックスを描画して表示しても大した手間にはならないでしょう。


▲スクリプトエディタ上で実行したところ


▲Script Debugger上で実行したところ


▲スクリプトメニュー上で実行したところ

Safariのアクセス履歴は例によってsqliteのDatabaseにアクセスして取得していますが、AppleScriptのランタイム環境によっては、アクセス権限がないというメッセージが出てアクセスできないことがあります。ASObjC Explorer 4上では実行できませんでしたし、Switch Control上でも実行できません。

# 管理者権限つきで実行しても(with administrator privileges)実行できません → Switch Controlでも実行できるようになりました

最初に掲載したバージョンでは、グラフ化したときに表示月が1か月ズレるという問題がありました。

Google Chartsのドキュメントを確認したところ、

Note: JavaScript counts months starting at zero: January is 0, February is 1, and December is 11. If your calendar chart seems off by a month, this is why.

JavaScriptでMonthはJanuaryが0らしく、monthを-1する必要があるとdocumentに書かれていました。うわ、なにその仕様?(ーー;;;

AppleScript名:アラートダイアログ上にWebViewでGoogle Chartを表示(Calendar Charts)v1a.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/05/07
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0

script spd
  property aRes : {}
  
property bRes : {}
end script

–Calculate Safari access frequency for (parameter days)
set (aRes of spd) to calcMain(100) of safariHistLib

set (bRes of spd) to ""
repeat with i in (aRes of spd)
  set {item1, item2, item3} to parseByDelim(theName of (contents of i), "-") of me
  
set newLine to " [ new Date(" & (item1 as string) & ", " & ((item2 – 1) as string) & ", " & (item3 as string) & "), " & (numberOfTimes of i) & "]," & (string id 10)
  
set (bRes of spd) to (bRes of spd) & newLine
end repeat

set (bRes of spd) to text 1 thru -3 of (bRes of spd)

–Pie Chart Template HTML
set myStr to "<!DOCTYPE html>
<html lang=\"UTF-8\">
<head>
<div id=\"calendarchart\"></div>

<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>

<script type=\"text/javascript\">
// Load google charts
google.charts.load(’current’, {’packages’:[’calendar’]});
google.charts.setOnLoadCallback(drawChart);

// Draw the chart and set the chart values
function drawChart() {
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: ’date’, id: ’Date’ });
dataTable.addColumn({ type: ’number’, id: ’Web Access’ });
dataTable.addRows([
  %@
]);

var chart = new google.visualization.Calendar(document.getElementById(’calendar_basic’));

var options = {
title: \"Web Activity\",
height: 350,
};

chart.draw(dataTable, options);
}
</script>
</head>
<body>
  <div id=\"calendar_basic\" style=\"width: 1000px; height: 350px;\"></div>
</body>
</html>"

set aString to current application’s NSString’s stringWithFormat_(myStr, (bRes of spd)) as string

set paramObj to {myMessage:"Calendar Chart Test", mySubMessage:"This is a simple calendar chart using google charts", htmlStr:aString}
–my browseStrWebContents:paramObj–for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 1000
  
set aHeight to 300
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script type=\"text/javascript\">", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight – 100)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
  
set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

script safariHistLib
  property parent : AppleScript
  
use scripting additions
  
use framework "Foundation"
  
  
property |NSURL| : a reference to current application’s |NSURL|
  
  
script spd
    property sList : {}
    
property nList : {}
    
property sRes : {}
    
property dRes1 : {}
    
property dRes2 : {}
  end script
  
  
  
on calcMain(daysNum)
    set (dRes1 of spd) to dumpSafariHistoryFromDaysBefore(daysNum) of me
    
    
set (dRes2 of spd) to {}
    
repeat with i in (dRes1 of spd)
      copy (first item of i) as string to dStr
      
set convDstr to first item of (parseByDelim(dStr, {" "}) of me)
      
set the end of (dRes2 of spd) to convDstr
    end repeat
    
    
–日付ごとに登場頻度集計
    
set cRes to countItemsByItsAppearance2((dRes2 of spd)) of me
    
return cRes as list
  end calcMain
  
  
  
–NSArrayに入れたレコードを、指定の属性ラベルの値でソート
  
on sortRecListByLabel(aArray, aLabelStr as string, ascendF as boolean)
    –ソート
    
set sortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF
    
set sortDescArray to current application’s NSArray’s arrayWithObjects:sortDesc
    
set sortedArray to aArray’s sortedArrayUsingDescriptors:sortDescArray
    
    
–NSArrayからListに型変換して返す
    
set bList to (sortedArray) as list
    
return bList
  end sortRecListByLabel
  
  
  
on dumpSafariHistoryFromDaysBefore(daysBefore)
    –現在日時のn日前を求める
    
using terms from scripting additions
      set origDate to (current date) – (daysBefore * days)
    end using terms from
    
    
set dStr to convDateObjToStrWithFormat(origDate, "yyyy-MM-dd hh:mm:ss") of me
    
    
set aDBpath to "~/Library/Safari/History.db"
    
set pathString to current application’s NSString’s stringWithString:aDBpath
    
set newPath to pathString’s stringByExpandingTildeInPath()
    
    
set aText to "/usr/bin/sqlite3 " & newPath & " ’SELECT datetime(history_visits.visit_time+978307200, \"unixepoch\", \"localtime\"), history_visits.title || \" @ \" || substr(history_items.URL,1,max(length(history_items.URL)*(instr(history_items.URL,\" & \")=0),instr(history_items.URL,\" & \"))) as Info FROM history_visits INNER JOIN history_items ON history_items.id = history_visits.history_item where history_visits.visit_time>(julianday(\"" & dStr & "\")*86400-211845068000) ORDER BY visit_time ASC LIMIT 999999;’"
    
    
using terms from scripting additions
      set (sRes of spd) to do shell script aText
    end using terms from
    
    
set (sList of spd) to (paragraphs of (sRes of spd))
    
    
repeat with i in (sList of spd)
      set j to contents of i
      
      
–Parse each field
      
set j2 to parseByDelim(j, {"|", "@ "}) of me
      
      
set the end of (nList of spd) to j2
    end repeat
    
    
return (nList of spd)
  end dumpSafariHistoryFromDaysBefore
  
  
  
  
on parseByDelim(aData, aDelim)
    set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to aDelim
    
set dList to text items of aData
    
set AppleScript’s text item delimiters to curDelim
    
return dList
  end parseByDelim
  
  
  
–出現回数で集計
  
on countItemsByItsAppearance2(aList)
    set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
    
set bArray to current application’s NSMutableArray’s array()
    
set theEnumerator to aSet’s objectEnumerator()
    
    
repeat
      set aValue to theEnumerator’s nextObject()
      
if aValue is missing value then exit repeat
      
bArray’s addObject:(current application’s NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{"theName", "numberOfTimes"})
    end repeat
    
    
–出現回数(numberOfTimes)で降順ソート
    
set theDesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:"theName" ascending:true
    
bArray’s sortUsingDescriptors:{theDesc}
    
    
return bArray
  end countItemsByItsAppearance2
  
  
  
on convDateObjToStrWithFormat(aDateO as date, aFormatStr as string)
    set aDF to current application’s NSDateFormatter’s alloc()’s init()
    
    
set aLoc to current application’s NSLocale’s currentLocale()
    
set aLocStr to (aLoc’s localeIdentifier()) as string
    
    
aDF’s setLocale:(current application’s NSLocale’s alloc()’s initWithLocaleIdentifier:aLocStr)
    
aDF’s setDateFormat:aFormatStr
    
set dRes to (aDF’s stringFromDate:aDateO) as string
    
return dRes
  end convDateObjToStrWithFormat
  
end script

★Click Here to Open This Script 

Posted in JavaScript shell script Sort | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding Safari WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上にWkWebViewでGoogle Chartsを表示 v2

Posted on 4月 29, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを配置し、Google Chartsを用いてPie Chartを表示するAppleScriptです。

自分の開発環境(MacBook Pro Retina 2012, Core i7 2.6GHz)で10日間のアクセス履歴を処理して1.38秒程度でダイアログ表示してグラフ描画に入ります。3秒強ぐらいで描画が終了します。

WkWebViewに対して、文字列で組み立てたHTMLを読み込んでグラフ表示しています。Pie Chart上にマウスカーソルを乗せると反応します。一応表示できているぐらいで、デザイン的には余計な余白ができたままで、いまひとつな感じです。せめて、WkWebViewの背景を透明化できると大味な表示をいくらか緩和できるかと思っているのですが、WkWebViewの透明背景にはNSColorではなく(AppleScriptから作成できない)CGColorでclearColor(透明色)を指定する必要があるようで、、、、

サンプル表示データは、Safariの10日間のアクセス履歴からドメイン単位で計算したヒストグラムを、その場で計算したものを使っています。

本Scriptは、①NSAlertのダイアログ表示の経験 ②WkWebView上へのコンテンツ表示の経験 ③グラフ表示用FrameworkやSVGベースのグラフ作成の経験 を経て、2・3年越しで完成したものです。とくに、WkWebViewについてはサンプル数がそれほど多くなく、用途の方向性がObjective-CやSwiftと若干異なるために、参考にできるサンプルの数が多くない状況。必然的に、いろいろ試しては失敗を重ねてきました。急に出来上がってきたものではありません。

Safariの履歴集計ScriptをScriptオブジェクトの中に放り込んだら、scripting additionsの用語をusing terms from句で囲っておく必要がありました。何回か経験していますが、知らないと対処に困る現象です。

現状(macOS 10.14以降)では、Scripting AdditionはmacOS標準搭載のStandard Additionsしか存在していないし認識も行われないため、エラー内容がいまひとつわかりにくく、不正確であるように思えます。Apple純正のStandard Additionsしか存在していないんだから自分で判断しろやコラ、と言いたくなります。

AppleScript名:アラートダイアログ上にWebViewでGoogle Chartを表示 v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/03/02
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0

–Calc Safari access domain from history
set aRes to calcSafariHistoryBest10Domain(10) of safariHistoryLib

set aList to {{"Domain", "Access"}}
repeat with i in aRes
  set aDom to theName of i
  
set accessNum to numberOfTimes of i
  
set the end of aList to {aDom, accessNum}
end repeat

–set aList to {{"Task", "Hours per Day"}, {"Work", 8}, {"Eat", 2}, {"TV", 4}, {"Gym", 2}, {"Sleep", 8}}

set aJsonArrayStr to array2DToJSONArray(aList) of me

–Pie Chart Template HTML
set myStr to "<!DOCTYPE html>
<html lang=\"UTF-8\">
<body>
<div id=\"piechart\"></div>

<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>

<script type=\"text/javascript\">
// Load google charts
google.charts.load(’current’, {’packages’:[’corechart’]});
google.charts.setOnLoadCallback(drawChart);

// Draw the chart and set the chart values
function drawChart() {
var data = google.visualization.arrayToDataTable(%@);

// Optional; add a title and set the width and height of the chart
var options = {’title’:’’, ’width’:600, ’height’:400};

// Display the chart inside the <div> element with id=\"piechart\"
var chart = new google.visualization.PieChart(document.getElementById(’piechart’));
chart.draw(data, options);
}
</script>

</body>
</html>"

set aString to current application’s NSString’s stringWithFormat_(myStr, aJsonArrayStr) as string

set paramObj to {myMessage:"Pie Chart Test", mySubMessage:"This is a simple pie chart using google charts", htmlStr:aString}
–my browseStrWebContents:paramObj–for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 600
  
set aHeight to 450
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script type=\"text/javascript\">", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight – 100)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
  
set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

–Safariのn日前からの履歴をドメイン別に集計してソート
script safariHistoryLib
  use scripting additions
  
use framework "Foundation"
  
property parent : AppleScript
  
  
property |NSURL| : a reference to current application’s |NSURL|
  
  
script spd
    property sList : {}
    
property nList : {}
    
property sRes : {}
  end script
  
  
  
on calcSafariHistoryBest10Domain(daysBefore)
    –現在日時のn日前を求める
    
using terms from scripting additions
      set origDate to (current date) – (daysBefore * days)
    end using terms from
    
set dStr to convDateObjToStrWithFormat(origDate, "yyyy-MM-dd hh:mm:ss") of me
    
    
set aDBpath to "~/Library/Safari/History.db"
    
set pathString to current application’s NSString’s stringWithString:aDBpath
    
set newPath to pathString’s stringByExpandingTildeInPath()
    
    
set aText to "sqlite3 " & newPath & " ’SELECT datetime(history_visits.visit_time+978307200, \"unixepoch\", \"localtime\"), history_visits.title || \" @ \" || substr(history_items.URL,1,max(length(history_items.URL)*(instr(history_items.URL,\" & \")=0),instr(history_items.URL,\" & \"))) as Info FROM history_visits INNER JOIN history_items ON history_items.id = history_visits.history_item where history_visits.visit_time>(julianday(\"" & dStr & "\")*86400-211845068000) ORDER BY visit_time ASC LIMIT 999999;’"
    
    
using terms from scripting additions
      set (sRes of spd) to do shell script aText
    end using terms from
    
    
set (sList of spd) to (paragraphs of (sRes of spd))
    
    
set (nList of spd) to {}
    
    
repeat with i in (sList of spd)
      set j to contents of i
      
      
–Parse each field
      
set j2 to parseByDelim(j, {"|", "@ "}) of me
      
      
–Calculate URL’s domain only
      
set j3 to contents of last item of j2
      
set aURL to (|NSURL|’s URLWithString:j3)
      
      
if aURL = missing value then
        set j4 to ""
      else
        set j4 to (aURL’s |host|()) as string
      end if
      
      
set the end of (nList of spd) to j4
    end repeat
    
    
–登場頻度でURLを集計
    
set aList to countItemsByItsAppearance((nList of spd)) of me
    
    
    
–Best 10の計算のために10位以下をまとめる
    
set best9 to items 1 thru 9 of aList
    
set best10 to items 10 thru -1 of aList
    
    
set otherTimes to 0
    
repeat with i in best10
      set otherTimes to otherTimes + (numberOfTimes of i)
    end repeat
    
    
set the end of best9 to {theName:"Other", numberOfTimes:otherTimes}
    
return best9
  end calcSafariHistoryBest10Domain
  
  
  
  
on parseByDelim(aData, aDelim)
    set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to aDelim
    
set dList to text items of aData
    
set AppleScript’s text item delimiters to curDelim
    
return dList
  end parseByDelim
  
  
  
–出現回数で集計
  
on countItemsByItsAppearance(aList)
    set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
    
set bArray to current application’s NSMutableArray’s array()
    
set theEnumerator to aSet’s objectEnumerator()
    
    
repeat
      set aValue to theEnumerator’s nextObject()
      
if aValue is missing value then exit repeat
      
bArray’s addObject:(current application’s NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{"theName", "numberOfTimes"})
    end repeat
    
    
–出現回数(numberOfTimes)で降順ソート
    
set theDesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:"numberOfTimes" ascending:false
    
bArray’s sortUsingDescriptors:{theDesc}
    
    
return bArray as list
  end countItemsByItsAppearance
  
  
  
on convDateObjToStrWithFormat(aDateO as date, aFormatStr as string)
    set aDF to current application’s NSDateFormatter’s alloc()’s init()
    
    
set aLoc to current application’s NSLocale’s currentLocale()
    
set aLocStr to (aLoc’s localeIdentifier()) as string
    
    
aDF’s setLocale:(current application’s NSLocale’s alloc()’s initWithLocaleIdentifier:aLocStr)
    
aDF’s setDateFormat:aFormatStr
    
set dRes to (aDF’s stringFromDate:aDateO) as string
    
return dRes
  end convDateObjToStrWithFormat
  
end script

★Click Here to Open This Script 

Posted in dialog Web Contents Control | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding Safari WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

AppleScriptでキースキャン

Posted on 2月 26, 2020 by Takaaki Naganoya

Xcode上で作成するAppleScript Cocoa Applicationで、キースキャンを試してみました。

ふだん作っているものだと、各種パラメータをGUI上で設定する程度のもので、キースキャンを行う必要などこれっぽっちもないのですが、いま作っているアプリケーションでキースキャンが必要になってしまったので、昔作ったものを引っ張り出してきました。

AppleScriptのプログラムでキースキャンを行うといえば、AppleScript Appletの起動時に何らかのModifier Keys(ShiftとかOptionとかCommandとかControlとか)が押されていることを検出して動作を変更するといった処理が一般的です。ループ処理中でも、これらのキー入力を定期的に監視することはよく行なっています(処理中に停止したいという要求はあるので)。

–> Watch Demo Movie

–> Download Xcode Project Archive

本プログラムでは、Modifier Keysにかぎらずキーボード入力全般を受け付けています。ただし、キースキャン可能なのは本プログラムが最前面にある場合のみです。

掲載しているコードからではわかりませんが、キー入力の受け付けをNSWindowで行なっています。FirstResponderまわりを一切いじくらずにほぼプログラミングなしでキー受け付けを行おうとした結果NSWindowで行うことになったというわけで、これがベストとも思いません。

とりあえず「こうすればできた」というレベルをおさえておいて、そこから自分の好きな方向に機能を変更していけばよいと思います。

AppleScript名:AppDelegate.applescript
—
— AppDelegate.applescript
— keyEvents
—
— Created by Takaaki Naganoya on 2014/05/09.
— Copyright (c) 2014年 Takaaki Naganoya. All rights reserved.
—

script AppDelegate
  property parent : class "NSObject"
  
  
— IBOutlets
  
property theWindow : missing value
  
property aButton : missing value
  
  
property xMax : 500
  
property yMax : 500
  
  
property aStep : 50
  
  
on applicationWillFinishLaunching:aNotification
    —
  end applicationWillFinishLaunching:
  
  
on applicationShouldTerminate:sender
    return current application’s NSTerminateNow
  end applicationShouldTerminate:
  
  
  
on buttonMove:(aCode as integer)
    set curFrame to aButton’s frame()
    
copy curFrame to {{x, y}, {xWidth, yHeight}}
    
    
if aCode = 123 then
      –Left
      
if x > 0 then
        set x to x – aStep
      end if
    else if aCode = 124 then
      –Right
      
if x < xMax then
        set x to x + aStep
      end if
      
    else if aCode = 126 then
      –Up
      
if y < yMax then
        set y to y + aStep
      end if
      
    else if aCode = 125 then
      –Down
      
if y > 10 then
        set y to y – aStep
      end if
    else if aCode = 125 then
      
    end if
    
    
set newRect to {{x, y}, {xWidth, yHeight}}
    
aButton’s setFrame:newRect
    
aButton’s setNeedsDisplay()
  end buttonMove:
end script

★Click Here to Open This Script 

AppleScript名:keyEventWin.applescript
script keyEvWin
  
  
property parent : class "NSWindow"
  
  
property aButton : missing value
  
  
  
on canBecomeKeyWindow:sender
    return true
  end canBecomeKeyWindow:
  
  
on canBecomeMainWindow:sender
    return true
  end canBecomeMainWindow:
  
  
  
on keyDown:theEvent
    set aCode to (theEvent’s keyCode) as integer
    
    
if aCode = 123 then
      –左
      
current application’s NSApp’s delegate()’s performSelector:"buttonMove:" withObject:(aCode)
      
    else if aCode = 124 then
      –右
      
current application’s NSApp’s delegate()’s performSelector:"buttonMove:" withObject:(aCode)
      
    else if aCode = 126 then
      –上
      
current application’s NSApp’s delegate()’s performSelector:"buttonMove:" withObject:(aCode)
      
    else if aCode = 125 then
      –下
      
current application’s NSApp’s delegate()’s performSelector:"buttonMove:" withObject:(aCode)
      
    end if
    
    
  end keyDown:
  
end script

★Click Here to Open This Script 

Posted in AppleScript Application on Xcode GUI | Tagged 10.13savvy 10.14savvy 10.15savvy NSButton NSEvent NSWindow | Leave a comment

アラートダイアログ上のWebViewに世界地図を表示 v2b

Posted on 11月 20, 2019 by Takaaki Naganoya

世界地図のSVGをHTMLReader.frameworkでparseして、目的のノードに塗り色の指定を行い、WkWebView上で表示するAppleScriptです。

–> Download selectCountry2(Code-signed AppleScript executable applet)

昨日のものがあくまでSVGのParseと表示が目的の試作品であったのに対し、本Scriptは連続してポップアップメニューから対象を選んで表示するというものです。

同様にmacOS 10.15.1上で作成しましたが、このバージョンのOS環境ではAppleScriptアプレットにFrameworkを入れてAppleScript内から呼び出すことが標準のランタイム(Script Editorから書き出した場合)では行えないようになっており、Script Debuggerから「Application(Enhanced)」で書き出さないと呼び出せないようです(これはちょっとひどいかも、、、、)。

世界地図はWikipediaから拾ってきたもので、ISO国コードではなく名称でIDが振ってあり、日本もJapanではなくHokkaido、Honshu、Shikoku、Kyushuuに分けて登録されています。


▲Script Editor上でサードパーティFramework呼び出しの動作ができているのは、この実行環境でSIPを解除してあるからです

AppleScript名:アラートダイアログ上のWebViewに世界地図を表示 v2b.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/11/18
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property HTMLDocument : a reference to current application’s HTMLDocument
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property theResult : 0
property returnCode : 0
property aWebView : missing value
property aLog : missing value
property tmpURL : ""

tell current application
  set mePath to ((path to me) as string) & "Contents:Resources:World_map_-_low_resolution.svg"
  
set svgCon to read (mePath as alias)
  
  
set