Menu

Skip to content
AppleScriptの穴
  • Home
  • Products
  • Books
  • 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

不可視プロセスで表示したNSAlertを最前面に表示

Posted on 1月 28, 2022 by Takaaki Naganoya

コンテクストメニューからAppleScriptを実行するツール「Service Station」を連日こづき回していろいろ試しています。

その中で、Service StationではScript実行をGUIなしの補助プログラムからosascriptコマンドを経由してAppleScriptを実行しているために、AppleScript中でNSAlertによるダイアログ表示をおこなった際に、ダイアログが最前面に表示されないという問題が生じていました。

これを見たedama2さんから、強制的にNSAlertダイアログを最前面に表示させるコードを提供していただいたので、実際にテストに用いたAppleScriptに入れたものをご紹介します。


▲そのまま普通にNSAlertダイアログを表示させたところ。Service Stationによるコンテクストメニューから実行すると、最前面に表示されないという問題があった


▲edama2さんからもたらされたコードを追加したNSAlertダイアログ。Service Stationから実行しても、問題なく最前面に表示される

コードは2行、効き目はばっちり!

--Move to frontmost (By edama2)
current application's NSApplication's sharedApplication()'s setActivationPolicy:(current application's NSApplicationActivationPolicyRegular)
current application's NSApp's activateIgnoringOtherApps:(true)

副作用として、Dockにターミナルのアイコンが表示され、最前面のアプリケーションが「osascript」になってしまいますが、気にならないところでしょう。

Program Name Name of runtime Support AppleScript document format AS Format NSAlert dialog is displayed in frontmost Can use GUI Scripting functions Can call AppleScript Libraries? Can call AS Library including Frameworks? Can call Generic Cocoa Functions? Can use Cocoa system notification functions?
Service Station osascript Script/Text Script/Applet Script/Text Script No-> Yes Yes Yes No Yes No
Script Menu osascript Script/Scriptd/Applet Script/Scriptd Yes Yes Yes No Yes Yes
Shortcuts Events MacHelper File Embedded Script Text Yes Yes Yes No Yes No
Switch Control Assistive Control File Embedded Script Script (archived) Yes Yes No No Yes No
FastScript 3 FastScripts Script Runner Script/Scriptd/Applet Script/Scriptd Yes Yes Yes No Yes

あれ? edama2さんのおかげで、Service Stationの弱点が1つなくなりましたよ。Service Stationについては、

(1)「Kind–> Script」「AppleScript」でテキストで書いた「.applescript」しかピックアップできないとかいう気の狂ったようなRulesの仕様は要・修正

(2)実行Scriptにフラットな.scptとテキストの.applescriptしか実行できないのはダメ。バンドル形式の.scptdの実行サポートは必須

(3)大量のAppleScriptをコンテクストメニューに入れると使い勝手が落ちるので、Rulesでもう少しこまかく条件付けできるとよさそう。ただし必須ではない

といったところでしょうか。

AppleScript名:Webダイアログ表示(強制最前面).scpt
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

my serviceStationDidSelect("", "", "")

on serviceStationDidSelect(targetedURL, selectedItemURLs, menuKind)
  set aList to {{label:"TEST1", value:403}, {label:"TEST2", value:301}, {label:"TEST3", value:101}, {label:"TEST4", value:65}}
  
set bList to sortRecListByLabel(aList, {"value"}, {false}) of me –降順ソート
  
  
–https://www.amcharts.com/demos/pie-chart/
  
set myStr to retHTML() of me
  
set jsonStr to array2DToJSONArray(bList) of me as string
  
set aString to current application’s NSString’s stringWithFormat_(myStr, jsonStr) as string
  
set paramObj to {myMessage:"Simple Pie Chart", mySubMessage:"This is a AMCharts test", htmlStr:aString, viewSize:{1000, 550}}
  
  
my webD’s displayWebDialog(paramObj)
end serviceStationDidSelect

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)
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList as list, aLabelStr as list, ascendF as list)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
  
set aCount to length of aLabelStr
  
set sortDescArray to current application’s NSMutableArray’s new()
  
repeat with i from 1 to aCount
    set aLabel to (item i of aLabelStr)
    
set aKey to (item i of ascendF)
    
set sortDesc to (current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabel ascending:aKey)
    (
sortDescArray’s addObject:sortDesc)
  end repeat
  
  
return (aArray’s sortedArrayUsingDescriptors:sortDescArray) as list
end sortRecListByLabel

script webD
  —
  
–  Created by: Takaaki Naganoya
  
–  Created on: 2020/06/20
  
—
  
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
  
—
  
use AppleScript
  
use framework "Foundation"
  
use framework "AppKit"
  
use framework "WebKit"
  
use scripting additions
  
property parent : AppleScript
  
  
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
  
  
  
on displayWebDialog(paramObj)
    my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true
  end displayWebDialog
  
  
on browseStrWebContents:paramObj
    set aMainMes to myMessage of paramObj as string
    
set aSubMes to mySubMessage of paramObj as string
    
set htmlString to (htmlStr of paramObj) as string
    
–set jsDelimList to (jsDelimiters of paramObj) as list
    
set webSize to (viewSize of paramObj) as list
    
    
copy webSize to {aWidth, aHeight}
    
    
–WebViewをつくる
    
set aConf to WKWebViewConfiguration’s alloc()’s init()
    
    
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)
    
    
–Move to frontmost (By edama2)
    
current application’s NSApplication’s sharedApplication()’s setActivationPolicy:(current application’s NSApplicationActivationPolicyRegular)
    
current application’s NSApp’s activateIgnoringOtherApps:(true)
    
    
— 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
    
    
if (my returnCode as number) = 1001 then error number -128
    
    
##後始末
    
aWebView’s stopLoading()
    
set js to "window.open(’about:blank’,’_self’).close();"
    
aWebView’s evaluateJavaScript:js completionHandler:(missing value)
    
set aWebView to missing value
    
  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)
    using terms from scripting additions
      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 using terms from
  end pickUpFromToStr
  
  
  
–リストを任意のデリミタ付きでテキストに
  
on retArrowText(aList, aDelim)
    using terms from scripting additions
      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 using terms from
  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)
    using terms from scripting additions
      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 using terms from
  end parseByDelim
  
end script

on retHTML()
  return "<!doctype html>
<head>
<meta charset=\"utf-8\">
<!– Styles –>
<style>
body { background-color: #000000; color: #ffffff; }
#chartdiv {
width: 100%;
height: 500px;
}

</style>
</head>
<body>

<!– Resources –>
<script src=\"https://www.amcharts.com/lib/4/core.js\"></script>
<script src=\"https://www.amcharts.com/lib/4/charts.js\"></script>
<script src=\"https://www.amcharts.com/lib/4/themes/dark.js\"></script>
<script src=\"https://www.amcharts.com/lib/4/themes/animated.js\"></script>

<!– Chart code –>
<script>
am4core.ready(function() {

// Themes begin
am4core.useTheme(am4themes_dark);
am4core.useTheme(am4themes_animated);
// Themes end

// Create chart instance
var chart = am4core.create(\"chartdiv\", am4charts.PieChart);

// Add data
chart.data = %@;

// Add and configure Series
var pieSeries = chart.series.push(new am4charts.PieSeries());
pieSeries.dataFields.value = \"value\";
pieSeries.dataFields.category = \"label\";
pieSeries.slices.template.stroke = am4core.color(\"#fff\");
pieSeries.slices.template.strokeOpacity = 1;

// This creates initial animation
pieSeries.hiddenState.properties.opacity = 1;
pieSeries.hiddenState.properties.endAngle = -90;
pieSeries.hiddenState.properties.startAngle = -90;

chart.hiddenState.properties.radius = am4core.percent(0);

}); // end am4core.ready()
</script>

<!– HTML –>
<div id=\"chartdiv\"></div>
</body>
</html>"

end retHTML

★Click Here to Open This Script 

Posted in JSON Review | Tagged 12.0savvy NSAlert NSButton NSRunningApplication NSString NSURL NSURLRequest Service Station WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

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

Posted on 7月 17, 2020 by Takaaki Naganoya

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

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

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


▲macOS 15.3上で、本Scriptの改修版を動かしたところ、クリックした箇所が見てわかるようになった

AppleScript名:アラートダイアログ上に印刷対象ページ一覧を表示して対象ページを指定 v2.scpt
— Created 2020-07-17 by Takaaki Naganoya
— Modified 2024-12-23 by Takaaki Naganoya
— 2020-2024 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 NSButtonTypeToggle : a reference to current application’s NSButtonTypeToggle
  
property NSButtonTypePushOnPushOff : a reference to current application’s NSButtonTypePushOnPushOff
  
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:(NSButtonTypeToggle))
        (
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 JSON | 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 JSON 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 JSON 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 JSON | 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 | 1 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 aWidth to 950
  
set aHeight to 650
  
  
  
set paramObj to {myMessage:"Browse World map", mySubMessage:"This is a sample SVG World map", targContents:svgCon, myWidth:(aWidth), myHeight:(aHeight)}
  
–my browseLocalWebContents:paramObj
  
my performSelectorOnMainThread:"browseLocalWebContents:" withObject:(paramObj) waitUntilDone:true
  
return aLog
end tell

on browseLocalWebContents:paramObj
  set aMainMes to (myMessage of paramObj) as string
  
set aSubMes to (mySubMessage of paramObj) as string
  
set tmpURL to (targContents of paramObj) as string –local contents
  
set aWidth to (myWidth of paramObj) as integer
  
set aHeight to (myHeight of paramObj) as integer
  
  
  
set aView to current application’s NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
  
–Ppopup Buttonをつくる
  
set a1Button to current application’s NSPopUpButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, aHeight – 26, 200, 24)) pullsDown:(false)
  
a1Button’s removeAllItems()
  
  
–Menuの中身を作る  
  
set aHTML to current application’s HTMLDocument’s documentWithString:(tmpURL)
  
set fList to (aHTML’s nodesMatchingSelector:"path")’s valueForKeyPath:"attributes.id"
  
set fList to fList’s sortedArrayUsingSelector:"compare:"
  
  
a1Button’s addItemWithTitle:"▼Select"
  
  
repeat with i in fList
    (a1Button’s addItemWithTitle:(i as string))
  end repeat
  
  
a1Button’s setTarget:(me)
  
a1Button’s setAction:("mySelector:")
  
a1Button’s setEnabled:(true)
  
  
set aWebView to makeWebViewAndLoadContents(tmpURL, aWidth, aHeight – 40) of me
  
  
aView’s addSubview:a1Button
  
aView’s addSubview:aWebView
  
  
— 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
  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 browseLocalWebContents:

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

on viewDidLoad:aNotification
  return true
end viewDidLoad:

–Popup Action Handler
on actionHandler:sender
  set aTitle to title of sender as string
end actionHandler:

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 mySelector:aSender
  set targetCountry to (aSender’s title()) as string
  
  
set aHTML to current application’s HTMLDocument’s documentWithString:(tmpURL as string)
  
  
set eList to (aHTML’s nodesMatchingSelector:"path") as list
  
set fList to (aHTML’s nodesMatchingSelector:"path")’s valueForKeyPath:"attributes.id"
  
  
–Search Target Country
  
set aRes to (fList)’s indexOfObject:(targetCountry)
  
if (aRes = current application’s NSNotFound) or (aRes > 9.99999999E+8) then
    error "Target country not found"
  end if
  
  
set aRes to aRes + 1
  
  
–Rewrite target country’s fill color on SVG
  
set tmpNode to contents of item aRes of (eList)
  (
tmpNode’s setObject:"Red" forKeyedSubscript:"fill") –Change Target Country’s fill color
  
  
set svgCon to (tmpNode’s |document|()’s serializedFragment()) as string –HTMLReaderはこういう処理ができるところが好き
  
  
aWebView’s loadHTMLString:svgCon baseURL:(missing value)
end mySelector:

on makeWebViewAndLoadContents(aContents as string, aWidth as integer, aHeight as integer)
  set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定URLのJavaScriptをFetch
  
set jsSource to my fetchJSSourceString(aContents)
  
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 setOpaque:false
  
aWebView’s setBackgroundColor:(NSColor’s clearColor())
  
–aWebView’s scrollView()’s setBackgroundColor:(NSColor’s clearColor())
  
  
aWebView’s loadHTMLString:aContents baseURL:(missing value)
  
return aWebView
end makeWebViewAndLoadContents

★Click Here to Open This Script 

Posted in dialog geolocation GUI Image SVG | Tagged 10.13savvy 10.14savvy 10.15savvy HTMLDocument NSAlert NSButton NSColor NSImage NSRunningApplication NSScreen NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上のWebViewに円グラフを表示

Posted on 11月 18, 2019 by Takaaki Naganoya

アラートダイアログ上のWebViewにSVGで作った円グラフを表示するAppleScriptです。

Objective-Cで作られたチャート表示フレームワークなどを呼び出して試していますが、スクリプトエディタ上で作成したAppleScriptから呼び出すと、アニメーションしなかったり表示が行えなかったりといろいろ環境にフィットしていません。

# 逆をいえば、Xcode上でCocoa AppleScriptアプリケーションを作成した場合には割とチャート表示部品をそのまま使えます

そこで、単純なグラフ表示を行うようにレベルを下げ、SVGをWkWebView上に表示する形式にしてみました。

本Scriptでは最低限のサンプルを表示させていますが、SVGの組み立てをもう少し強化してグラフの背景を透明にできればいい感じになるのではないでしょうか。


▲世界地図あたりだといい感じに見えるかもしれません。当該の国だけ色を変えるような処理を仕込めば何かに使えそうです。

AppleScript名:アラートダイアログ上のWebViewに円グラフを表示.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 "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 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

–set svgCon to read (choose file)
set svgCon to retSampleSVG() of me

set paramObj to {myMessage:"Browse Pie Chart", mySubMessage:"This is a sample pie chart made by SVG", targContents:svgCon}
–my browseLocalWebContents:paramObj
my performSelectorOnMainThread:"browseLocalWebContents:" withObject:(paramObj) waitUntilDone:true

on browseLocalWebContents:paramObj
  set aMainMes to (myMessage of paramObj) as string
  
set aSubMes to (mySubMessage of paramObj) as string
  
set tmpURL to (targContents of paramObj) as string –local contents
  
  
set aWidth to 330
  
set aHeight to 430
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定URLのJavaScriptをFetch
  
set jsSource to my fetchJSSourceString(tmpURL)
  
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
  
aWebView’s setOpaque:false
  
aWebView’s setBackgroundColor:(NSColor’s clearColor())
  
–aWebView’s scrollView()’s setBackgroundColor:(NSColor’s clearColor())
  
  
aWebView’s loadHTMLString:tmpURL baseURL:(missing value)
  
  
  
— 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
  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 browseLocalWebContents:

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 retSampleSVG()
  return "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"300\" height=\"300\" fill-opacity=\"0.9\">
<path d=\"M 150,0 A 150,150 0 1,1 141.8986347236027,299.7810664959306 L 150,150 Z\" fill=\"#0153d8\" stroke=\"#fff\"></path>
<text x=\"170\" y=\"150\" fill=\"#fff\" font-size=\"20\">Piyomaru</text>
<text x=\"170\" y=\"190\" fill=\"#fff\" font-size=\"40\">50.86%</text>
</svg>"
end retSampleSVG

★Click Here to Open This Script 

Posted in dialog GUI | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSColor NSImage NSRunningApplication NSScreen NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | 1 Comment

アラートダイアログ上にカレンダー1か月分を表示して選択 有効日指定あり v3a

Posted on 11月 13, 2019 by Takaaki Naganoya

アラートダイアログ上に指定月のカレンダー1か月分を表示してユーザーの日付選択(複数可)をもとめるAppleScriptです。

NSDatePickerを用いて日付選択のダイアログを作っていたら、日付がとても小さくて現代のMacの画面解像度にとても合っておらず、もっと大きめのカレンダーで選択したいと考えて作ったものです。

(1)カレンダーの表示サイズを大型化

現代のMacの画面にNSDatePickerをそのまま表示すると、とても小さくて見ていられないので、表示サイズを自由に変えられるカレンダー選択部品を作ってみました。どれか1つの日付を選択するものではなく、複数の日付を選択して、リストで結果を返してきます。

▲画面上で見やすいようにカレンダー部品を大型化

(2)選択無効日指定

あらかじめ、日付選択の対象外とする日付を指定できるようにしました。

(3)過去日付の選択無効

過去の日付を表示・選択できないようにする指定です。

▲過去日付を無効に指定すると、現在日時よりも過去の日付は選択できない

(4)曜日を現在のLocale情報から変更

曜日に用いる文字列を現在のLocale情報から取得するようにしてみました。本来であれば、日曜日はじまり「ではない」カレンダーを用いている場所もあるので(香港とかフランスとか?)、どの曜日から表示開始するかを自由選択にしたいところですが、そこまでは作り込んでいません。

▲Localeに合わせた曜日が表示される(ただし、年/月は固定フォーマット)

実用性を考えれば、Calendar.appのように日付選択とスケジュール確認が行えるものが望ましいのですが、そこまで作り込む手間をかけるほどのものでもないですし、表示対象月の移動を行おうとしてclickイベントを拾いつつカレンダー再描画に失敗した「残骸」です。見た目はいいのに完成度がいまひとつというあたりが残念です。

AppleScript名:アラートダイアログ上にカレンダー1か月分を表示して選択 有効日指定あり v3a
— Created 2019-10-15 by Takaaki Naganoya
— 2019 Piyomaru Software
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 bArray : {} –Checkbox button object array

property tYear : 0
property tMonth : 0
property theAlert : missing value
property theView : missing value

on run
  set tYear to 2019
  
set tMonth to 11
  
set ignoreP to true
  
set ndList to {2, 3, 4, 9, 10, 13, 16, 17, 23, 24, 25, 30} –選択表示させない日付
  
set paramObj to {myMessage:"", mySubMessage:"適切な日付を以下からえらんでください", targetYear:tYear, targetMonth:tMonth, nodisp:ndList, ignorePast:ignoreP}
  
  
–Detect Past Date Error
  
set curDate to current date
  
set dLimit to getMlen(tYear, tMonth) of me
  
set tmpDate to getDateInternational(tYear, tMonth, dLimit) of me
  
if (tmpDate < curDate) and (ignoreP = true) then error (("Target month is past (" & tYear as string) & "/" & tMonth as string) & "/1 is past. Today is " & date string of curDate & ")"
  
  
–my chooseItemByCheckBox:paramObj –for Debugging
  
my performSelectorOnMainThread:"chooseItemByCheckBox:" withObject:(paramObj) waitUntilDone:true
  
return my sort1DNumList:(my theResult) ascOrder:true
  
–> {1, 3, 5, 7, 9, 11}
end run

on chooseItemByCheckBox:(paramObj)
  set aMainMes to (myMessage of paramObj) as string
  
set aSubMes to (mySubMessage of paramObj) as string
  
set aMatList to (matrixTitleList of paramObj) as list
  
set tYear to (targetYear of paramObj) as integer
  
set tMonth to (targetMonth of paramObj) as integer
  
set noDispList to (nodisp of paramObj) as list
  
set ignoreP to (ignorePast of paramObj) as boolean
  
  
if aMainMes = "" then
    set aMainMes to "日付を選択してください"
  end if
  
  
set theView to makeCalendarView(tYear, tMonth, noDispList, ignoreP) of me
  
  
–Select the first radio button item
  
set my theResult to {}
  
  
— 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:theView
    
    
–for Help Button
    
–its setShowsHelp:(true)
    
its setDelegate:(me)
    
set aWin to its |window|()
  end tell
  
  
aWin’s setLevel:(current application’s NSFloatingWindowLevel)
  
  
— 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
  
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

–指定月のカレンダーを1D List(7 days x 6 weeks) で返す
on retListCalendar(tYear, tMonth)
  set mLen to getMlen(tYear, tMonth) of me
  
set aList to {}
  
  
set fDat to getDateInternational(tYear, tMonth, 1) of me
  
tell current application
    set aOffset to (weekday of fDat) as number
  end tell
  
  
–header gap
  
repeat (aOffset – 1) times
    set the end of aList to ""
  end repeat
  
  
–calendar body
  
repeat with i from 1 to mLen
    set the end of aList to (i as string)
  end repeat
  
  
–footer gap
  
repeat (42 – aOffset – mLen + 1) times
    set the end of aList to ""
  end repeat
  
  
return aList
end retListCalendar

–現在のカレンダーで指定年月の日数を返す(国際化対応版)
on getMlen(aYear as integer, aMonth as integer)
  set theNSCalendar to current application’s NSCalendar’s currentCalendar()
  
set theDate to theNSCalendar’s dateWithEra:1 |year|:aYear |month|:aMonth |day|:1 hour:0 minute:0 |second|:0 nanosecond:0
  
set theResult to theNSCalendar’s rangeOfUnit:(current application’s NSDayCalendarUnit) inUnit:(current application’s NSMonthCalendarUnit) forDate:theDate
  
return |length| of theResult
end getMlen

–現在のカレンダーで指定年月のdate objectを返す
on getDateInternational(aYear, aMonth, aDay)
  set theNSCalendar to current application’s NSCalendar’s currentCalendar()
  
set theDate to theNSCalendar’s dateWithEra:1 |year|:aYear |month|:aMonth |day|:aDay hour:0 minute:0 |second|:0 nanosecond:0
  
return theDate as date
end getDateInternational

–ローカライズされた曜日名称を返す
on getLocalizedDaynames(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s standaloneWeekdaySymbols() as list
  
return dayNames
end getLocalizedDaynames

–ローカライズされた月名称を返す
on getLocalizedMonthnames(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set monthNames to df’s standaloneMonthSymbols() as list
  
return monthNames
end getLocalizedMonthnames

–ローカライズされた曜日の名称を返す
on getLocalizedWeekdaySymbol(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s weekdaySymbols()
  
return dayNames as list
end getLocalizedWeekdaySymbol

–ローカライズされた曜日の名称(短縮版)を返す
on getLocalizedShortWeekdaySymbol(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s shortWeekdaySymbols()
  
return dayNames as list
end getLocalizedShortWeekdaySymbol

–ローカライズされた曜日の名称(短縮記号)を返す
on getLocalizedVeryShortWeekdaySymbol(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s veryShortWeekdaySymbols()
  
return dayNames as list
end getLocalizedVeryShortWeekdaySymbol

–ローカライズされた曜日の名称を返す
on getLocalizedVeryStandaloneWeekdaySymbols(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s standaloneWeekdaySymbols()
  
return dayNames as list
end getLocalizedVeryStandaloneWeekdaySymbols

–ローカライズされた曜日の名称を返す
on getLocalizedShortStandaloneWeekdaySymbols(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s shortStandaloneWeekdaySymbols()
  
return dayNames as list
end getLocalizedShortStandaloneWeekdaySymbols

–ローカライズされた曜日の名称を返す
on getLocalizedVeryShortStandaloneWeekdaySymbols(aLoc)
  set df to current application’s NSDateFormatter’s alloc()’s init()
  
df’s setLocale:(current application’s NSLocale’s localeWithLocaleIdentifier:aLoc)
  
set dayNames to df’s veryShortStandaloneWeekdaySymbols()
  
return dayNames as list
end getLocalizedVeryShortStandaloneWeekdaySymbols

–カレンダー表示ビューを作成
on makeCalendarView(tYear as integer, tMonth as integer, noDispList as list, ignoreP as boolean)
  set colNum to 7
  
set rowNum to 8
  
set aLen to (colNum * rowNum)
  
  
set aButtonCellWidth to 70 –56
  
set aButtonCellHeight to 40
  
  
set viewWidth to aButtonCellWidth * colNum
  
set viewHeight to aButtonCellHeight * rowNum
  
  
–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 30
  
set bArray to current application’s NSMutableArray’s new()
  
  
–Make Header (Month, Year)
  
set x to 1
  
set tmpB to (NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(((x – 1) * aButtonCellWidth), ((aLen – aCount) div colNum) * (aButtonCellHeight), aButtonCellWidth * 4, aButtonCellHeight)))
  (
tmpB’s setEditable:false)
  (
tmpB’s setBordered:false)
  (
tmpB’s setDrawsBackground:false)
  (
tmpB’s setAlignment:(current application’s NSLeftTextAlignment))
  (
tmpB’s setStringValue:((tYear as string) & " / " & tMonth as string))
  (
tmpB’s setFont:(NSFont’s fontWithName:"Times-Roman" |size|:40))
  (
bArray’s addObject:tmpB)
  
  
set aCount to aCount + 1
  
  
  
–Make Header (Weekday)
  
set curLocale to current application’s NSLocale’s currentLocale()
  
set aDS10 to (curLocale’s objectForKey:(current application’s NSLocaleIdentifier)) as string
  
set wdList to getLocalizedShortStandaloneWeekdaySymbols(aDS10) of me
  
set y to 2
  
  
repeat with x from 1 to 7
    set j to contents of item x of wdList
    
set tmpB to (NSTextField’s alloc()’s initWithFrame:(current application’s NSMakeRect(((x – 1) * aButtonCellWidth), ((aLen – aCount) div colNum – 1) * (aButtonCellHeight), aButtonCellWidth, aButtonCellHeight / 2)))
    (
tmpB’s setEditable:false)
    (
tmpB’s setAlignment:(current application’s NSCenterTextAlignment))
    (
tmpB’s setStringValue:(j))
    (
bArray’s addObject:tmpB)
  end repeat
  
  
set aCalList to retListCalendar(tYear, tMonth) of me
  
set aCount to 1
  
  
  
–Make Calendar (Calendar Body)
  
set curDat to current date
  
  
repeat with y from 3 to rowNum
    repeat with x from 1 to colNum
      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 – 2) * aButtonCellHeight, aButtonCellWidth, aButtonCellHeight)))
      
      
set tmpDate to getDateInternational(tYear, tMonth, j as integer) of me
      
set tmpF to (tmpDate < curDat) as boolean
      
      
if ignoreP = false then
        set dispF to true
      else if ignoreP = true and tmpF = false then
        set dispF to true
      else
        set dispF to false
      end if
      
      
if (j as integer) is not in noDispList then
        if (dispF = true) then
          (tmpB’s setTitle:(j as string))
          (
tmpB’s setFont:(NSFont’s fontWithName:"ArialMT" |size|:aFontSize))
          
–set attrTitle to makeRTFfromParameters((aCount as string), "ArialMT", 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 = ""))
          
if j is not equal to "" then
            (tmpB’s setTag:(j))
            (
bArray’s addObject:tmpB)
          end if
        end if
      end if
      
set aCount to aCount + 1
    end repeat
  end repeat
  
  (
aView’s setSubviews:bArray)
  
return aView
end makeCalendarView

★Click Here to Open This Script 

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

Post navigation

  • Older posts

電子書籍(PDF)をオンラインストアで販売中!

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • macOS 13.6.5 AS系のバグ、一切直らず
  • CotEditorで2つの書類の行単位での差分検出
  • Apple純正マウス、キーボードのバッテリー残量取得
  • macOS 15, Sequoia
  • 初心者がつまづきやすい「log」コマンド
  • ディスプレイをスリープ状態にして処理続行
  • 指定のWordファイルをPDFに書き出す
  • Adobe AcrobatをAppleScriptから操作してPDF圧縮
  • メキシカンハットの描画
  • 与えられた文字列の1D Listのすべての順列組み合わせパターン文字列を返す v3(ベンチマーク用)
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • macOS 13 TTS環境の変化について
  • 2023年に書いた価値あるAppleScript
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AdobeがInDesign v19.4からPOSIX pathを採用
  • 可変次元のベクトルに対応したコサイン類似度計算
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • Cocoa Scripting Course 続刊計画
  • NaturalLanguage.frameworkでNLEmbeddingの処理が可能な言語をチェック

Tags

10.11savvy (1102) 10.12savvy (1243) 10.13savvy (1392) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (206) 13.0savvy (163) 14.0savvy (112) 15.0savvy (89) CotEditor (64) Finder (51) iTunes (19) Keynote (115) NSAlert (61) NSArray (51) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (51) NSDictionary (27) NSFileManager (23) NSFont (19) NSImage (41) NSJSONSerialization (21) NSMutableArray (62) NSMutableDictionary (21) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (117) NSURL (97) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (71) Pages (53) Safari (44) Script Editor (26) WKUserContentController (21) WKUserScript (20) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • Beginner
  • Benchmark
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • check sum
  • Clipboard
  • Cocoa-AppleScript Applet
  • Code Sign
  • Color
  • Custom Class
  • dialog
  • diff
  • drive
  • Droplet
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • Font
  • GAME
  • geolocation
  • GUI
  • GUI Scripting
  • Hex
  • History
  • How To
  • iCloud
  • Icon
  • Image
  • Input Method
  • Internet
  • iOS App
  • JavaScript
  • JSON
  • JXA
  • Keychain
  • Keychain
  • Language
  • Library
  • list
  • Locale
  • Localize
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • parallel processing
  • PDF
  • Peripheral
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • rectangle
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • Review
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • selection
  • shell script
  • Shortcuts Workflow
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Telephony
  • Text
  • Text to Speech
  • timezone
  • Tools
  • Update
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2024年2月
  • 2024年1月
  • 2023年12月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年12月
  • 2019年11月
  • 2019年10月
  • 2019年9月
  • 2019年8月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年11月
  • 2018年10月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年5月
  • 2018年4月
  • 2018年3月
  • 2018年2月

https://piyomarusoft.booth.pm/items/301502

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org

Forum Posts

  • 人気のトピック
  • 返信がないトピック

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org
Proudly powered by WordPress
Theme: Flint by Star Verte LLC