Menu

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

AppleScriptの穴

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

タグ: Numbers

Numbersで選択範囲に背景色を塗られているセル数をカウント

Posted on 12月 14, 2020 by Takaaki Naganoya

Numbersでオープン中の最前面の書類の現在のシート上の選択状態にある表の選択範囲から、背景色(background color)が塗られているセルを数えるAppleScriptです。

用途は、WebGL + three.jsで作られた3Dの回転選択メニューのデータ確認のためです。Numbers上で表示範囲の表を作って、その上で背景色を塗ることで「どの位置にデータを表示するか」を指定します。そのさいに、並べるセル数が表示用のJavaScriptと合っていないと面倒なので、本Scriptで色つきセルをかぞえています。

Numbers上で背景色(background color)が塗られているセルは16ビットで色の値が返ってきますし、塗られていないセルはmissing valueが返ってきます。

AppleScript名:Numbersで選択範囲に背景色を塗られているセル数をカウント
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/12/06
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

tell application "Numbers"
  tell front document
    –現在表示中のシートを対象にする
    
tell active sheet
      –Tableを特定する
      
try
        set theTable to first table whose class of selection range is range
      on error
        display notification "Numbers: There is no selection"
        
return {}
      end try
      
      
tell theTable
        –選択範囲のデータを1D Listで取得する
        
set aRes to background color of cells of selection range
      end tell
      
      
      
–Count Background
      
set aCount to 0
      
repeat with i in aRes
        set j to contents of i
        
        
if j is not equal to missing value then
          set aCount to aCount + 1
        end if
      end repeat
      
      
return aCount
    end tell
  end tell
end tell

★Click Here to Open This Script 

同様に、着色セルの座標値(x座標, y座標)を返すものも作って使用しています。

AppleScript名:Numbersで選択中のセルのうち背景色を塗られているもののx,y座標を2D Listで返す
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/12/06
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

tell application "Numbers"
  tell front document
    –現在表示中のシートを対象にする
    
tell active sheet
      –Tableを特定する
      
try
        set theTable to first table whose class of selection range is range
      on error
        display notification "Numbers: There is no selection"
        
return {}
      end try
      
      
tell theTable
        tell selection range
          set cellRes to background color of cells
          
set aWidth to count every column
          
set aHeight to count every row
        end tell
      end tell
      
      
–Check selected cell’s background color
      
set cellL to {}
      
set adrCount to 1
      
repeat with y from 1 to aHeight
        repeat with x from 1 to aWidth
          set aTmp to contents of (item adrCount of cellRes)
          
          
if aTmp is not equal to missing value then
            set the end of cellL to {x, y}
          end if
          
          
set adrCount to adrCount + 1
        end repeat
      end repeat
      
      
return cellL
      
–> {{1, 1}, {2, 1}, {3, 1}, {6, 1}, {8, 1}, {12, 1}, {15, 1}, {16, 1}, {20, 1}, {21, 1}, {24, 1}, {27, 1}, {28, 1}, {29, 1}, {1, 2}, {4, 2}, {6, 2}, {9, 2}, {11, 2}, {14, 2}, {17, 2}, {19, 2}, {23, 2}, {25, 2}, {27, 2}, {1, 3}, {2, 3}, {3, 3}, {6, 3}, {10, 3}, {14, 3}, {17, 3}, {19, 3}, {20, 3}, {23, 3}, {25, 3}, {27, 3}, {28, 3}, {29, 3}, {1, 4}, {6, 4}, {10, 4}, {14, 4}, {17, 4}, {21, 4}, {23, 4}, {25, 4}, {27, 4}, {1, 5}, {6, 5}, {10, 5}, {15, 5}, {16, 5}, {19, 5}, {20, 5}, {21, 5}, {24, 5}, {27, 5}, {1, 7}, {5, 7}, {8, 7}, {11, 7}, {12, 7}, {15, 7}, {17, 7}, {19, 7}, {20, 7}, {21, 7}, {23, 7}, {27, 7}, {1, 8}, {2, 8}, {4, 8}, {5, 8}, {7, 8}, {9, 8}, {11, 8}, {13, 8}, {15, 8}, {17, 8}, {20, 8}, {23, 8}, {27, 8}, {1, 9}, {3, 9}, {5, 9}, {7, 9}, {8, 9}, {9, 9}, {11, 9}, {12, 9}, {15, 9}, {17, 9}, {20, 9}, {23, 9}, {25, 9}, {27, 9}, {1, 10}, {5, 10}, {7, 10}, {9, 10}, {11, 10}, {13, 10}, {15, 10}, {17, 10}, {20, 10}, {23, 10}, {24, 10}, {26, 10}, {27, 10}, {1, 11}, {5, 11}, {7, 11}, {9, 11}, {11, 11}, {13, 11}, {16, 11}, {20, 11}, {23, 11}, {27, 11}}
    end tell
  end tell
end tell

★Click Here to Open This Script 

Posted in Color list | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy Numbers | Leave a comment

Numbers選択セルの内容の&エンコーディング文字をプレーン化

Posted on 12月 7, 2020 by Takaaki Naganoya

Numbersのワークシート上で選択したセル中の文字に&エンコーディング文字が存在している場合に、その内容をプレーンテキスト化するAppleScriptです。

内容自体はよくあるものなので、説明が必要なものでもありません。Stream DeckにNumbers関連のScriptをいくつか用意して試していますが、なかなか便利です(かといって、Stream Deckの購入を決意するほどではないのですが)。ただ、実際にデータ整理が少ない手間で行えました。

Stream Deck Softwareの「システム」>「開く」のアクションにscpt形式のAppleScript書類を登録しておけば実行してくれるため、そのような利用方法を想定しています。

Numbers関連のさまざまな雑多な作業をAppleScriptで省力化し、それをStream Deckから呼び出すことで作業の負荷を減らせることを実感しています。それでもStream Deckの物理的な厚みがあるので何度もパチパチ叩いていると疲れやすいような気もします。

AppleScript名:選択セルの内容の&エンコーディング文字をプレーン化.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/12/06
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

decodeSelection() of me

–Numbersの選択範囲のデータを2D Listで返す
on decodeSelection()
  tell application "Numbers"
    tell front document
      –現在表示中のシートを対象にする
      
tell active sheet
        –Tableを特定する
        
try
          set theTable to first table whose class of selection range is range
        on error
          display notification "Numbers: There is no selection"
          
return {}
        end try
        
        
tell theTable
          –選択範囲のデータを1D Listで取得する
          
set aRes to value of cells of selection range
          
–選択範囲のセルのアドレスデータを1D Listで取得する
          
set cellList to cell of selection range
        end tell
        
        
–Percent Decode
        
set newList to {}
        
repeat with i in aRes
          set j to contents of i
          
set aRes to decodeCharacterReference(j as string) of me
          
set the end of newList to aRes
        end repeat
        
        
–Write Back to Numbers
        
repeat with i from 1 to (length of cellList)
          tell item i of cellList
            set value to item i of newList
          end tell
        end repeat
        
      end tell
    end tell
  end tell
end decodeSelection

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 decodeCharacterReference(aStr)
  set anNSString to current application’s NSString’s stringWithString:aStr
  
set theData to anNSString’s dataUsingEncoding:(current application’s NSUTF16StringEncoding)
  
set styledString to current application’s NSAttributedString’s alloc()’s initWithHTML:theData documentAttributes:(missing value)
  
set plainText to (styledString’s |string|()) as string
  
return plainText
end decodeCharacterReference

★Click Here to Open This Script 

Posted in Text | Tagged 10.14savvy 10.15savvy 11.0savvy Numbers | Leave a comment

iWork Appsのv10.2アップデートが公開される

Posted on 9月 23, 2020 by Takaaki Naganoya

AppleがKeynote/Pages/Numbersのv10.2アッップデートを公開しました。このv10.2から対象OSがmacOS 10.15以降になり、macOS 10.14では最新のKeynote v10.2を使えなくなったことになります。

Keynote v10.2のAppleScript系の機能の差分チェックを(sdefファイルベースで)行ってみたところ、iWorkアプリケーション中でKeynoteのみ機能追加されたことがわかりました。

Keynoteにムービー書き出し機能のAppleScriptオプション機能が追加される

exportコマンドのexport optionsで「movie codecs」と「movie framerates」の指定ができるように機能追加されています。

movie codecs enum
h.264 : H.264
AppleProRes422 : Apple ProRes 422
AppleProRes4444 : Apple ProRes 4444
AppleProRes422LT : Apple ProRes 422LT
AppleProRes422HQ : Apple ProRes 422HQ
AppleProRes422Proxy : Apple ProRes 422Proxy
HEVC : HEVC

movie framerates enum
FPS12 : 12 FPS
FPS2398 : 23.98 FPS
FPS24 : 24 FPS
FPS25 : 25 FPS
FPS2997 : 29.97 FPS
FPS30 : 30 FPS
FPS50 : 50 FPS
FPS5994 : 59.94 FPS
FPS60 : 60 FPS

風の噂によるとどうもARM Macはムービー書き出しが高速なようなので、そのあたりをアピールするためにもムービー書き出し系の機能の拡充は必要ということなのでしょう。

KeynoteのAppleScript用語辞書に構文確認をパスできないバグ持ち予約語が存在

同時に、「こんなんAppleScriptの処理系でコンパイル(構文確認)通るわけないやん、メーカーが何やってますのん?」という予約語がsdef内に書かれていることが一目でわかりました。

「h.264?」

この「h.264」の予約語はexportコマンドのexport optionsのmovie codecsのEnum内に書かれています。

        <enumeration name="movie codecs" code="Knmc">
            <enumerator name="h.264" code="Kmc1" description="H.264">
                <cocoa string-value="AVVideoCodecTypeH264" />
            </enumerator>

macOS 10.15.6上で確認したところ、見事に構文確認時にエラーになります。

Apple製のアプリケーションのAppleによるスクリプティング定義内容がまともに動きません。こうした事態は理解に苦しむものがあります。100%動作確認していないとしか思えません。

ここは、記号入りの予約語では言語処理系的に構文確認すらパスできないので、「h.264」ではなく記号を含まない「h264」ないし「H264」という予約語にすべきです。AppleScript系の機能を追加していただくのは前向きでよいと思いますが、メーカーとして一度も動作確認しないで機能をリリースするというのはいかがなものでしょう?

そんなところに凝っていないで、選択中のオブジェクトを取れる属性「selected objects」とか、テキストオブジェクトの縦書き制御属性「vertical」などをつけたほうが実用性があって助かります。機能追加自体はたいした作業ではありませんが、ぜひ動作確認した上でリリースしていただきたいところです。

AppleScript名:keynote movie export test
–Works with Keynote v10.2 or later
set aTagFile to ((path to desktop) as string) & "testOut.m4v"

tell application "Keynote"
  set exOpt to {compression factor:1.0, movie format:native size, class:export options}
  
–set exOpt to {compression factor:1.0, movie format:native size, movie codec:h.264, class:export options}–this cause error
  
export document 1 to file aTagFile as QuickTime movie with properties exOpt
  
end tell

★Click Here to Open This Script 

日頃からMac App Storeのレビューアーの血も涙もない(でも、ツッコミどころ満載の)リジェクトに遭っている身からすれば、こんなのリジェクト案件です。

個人的には信頼度の問題からmacOS 10.15は「パス」なので、macOS 11.0 Big SurがRelease時にコケないことを祈るのみです(メールが消えるとかいう話が一番OSの信頼度を下げる)。macOS 10.13, “Vista”という史上最悪・最低の大失敗をやらかして以来、「Release版のOSがBetaよりも低品質」という昨今のmacOS。10.13もBetaの時にはよかったのに、Release版で大崩壊を起こして見るも無残な姿に成り果てました。10.14もBetaの段階でGUI Scriptingの認証系でひどいバグがあって、「とても使えない」と判断。10.14.6まで待ってようやく手を出す気になったほど。

macOS 11.0, Big SurはBeta段階でも珍しく好印象で(GUIまわりの仕様はコロコロ変わるけど)、macOS 10.15みたいにBeta段階で「もう、これはダメ!」という話も聞きません(Relase時に紹介記事を書かなかったOSは10.15がはじめてです。10.15の崩壊度はひどかった)。macOS 11.0, Big Surには、macOS 10.13のような「Release版の大崩壊」を起こしてほしくないものです。

Posted in Bug sdef | Tagged 10.15savvy 11.0savvy Keynote Numbers Pages | Leave a comment

Numbers書類からExcel書き出し

Posted on 7月 4, 2020 by Takaaki Naganoya

Numbers書類をExcel形式(.xlsx)で書き出すAppleScriptです。

とりあえず動作確認のために作っただけだったので、動作は最低限のものです。Numbersでオープン中のNumbers書類をExcel形式に書き出します。それだけです。処理対象は1つのシートのみ含んでいる書類に限っています。Numbers書類のオープンや書き出した書類のクローズは別途作成してください。

Numbers書類でシートが複数存在しているものをExcel書類に書き出すと、各シートへのリンクが含まれたインデックスが1枚追加されます。このインデックスは非常に親切でよいのですが、割と邪魔です。あとでScript側から削除することも可能ですが、自分はNumbersから書き出す際に複数シートの書類は書き出さないようにまとめてみました。

もちろん、これはルーチンを整備して実際に使う人の考えによるものなので、別の人はNumbersの複数シートを含む書類をそのままExcel書類に変換されてもいいと考えるかもしれないですし、処理時に複数のシートを個別のNumbers書類に分割するような処理を書いてもいいでしょう。

実際にNumbersを使っていて、あまりExcel書き出しは必要にならなかったので「できる」ことは知っていながらも書かなかった処理ではあります。

AppleScript名:Numbers書類からExcel書き出し
— Created 2017-03-28 by Takaaki Naganoya
— Modified 2020-07-02 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set tmpPath to (path to desktop) as string
set aRes to exportNumbersDocToExcel(tmpPath) of me

–Numbers書類をExcel書き出し
on exportNumbersDocToExcel(targFolderPath as string)
  tell application "Numbers"
    set dCount to count every document
    
if dCount = 0 then
      return false
    end if
    
    
–複数のシートが存在していると書き出せないことはないが、リンク付きの凝ったExcelシートになる
    
tell front document
      set sCount to count every sheet
      
if sCount = 0 or sCount > 1 then
        return false
      end if
    end tell
    
    
set aPath to file of document 1
  end tell
  
  
set curPath to (current application’s NSString’s stringWithString:(POSIX path of aPath))’s lastPathComponent()’s stringByDeletingPathExtension()’s stringByAppendingString:".xlsx"
  
set outPath to (targFolderPath & curPath)
  
–このあと、安全のために重複パスの回避ルーチンを呼んでおくといいでしょう
  
  
tell application "Numbers"
    set anOpt to {class:export options, image quality:Best}
    
export document 1 to file outPath as Microsoft Excel with properties anOpt
    
return true
  end tell
end exportNumbersDocToExcel

★Click Here to Open This Script 

Posted in file | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy Numbers | Leave a comment

Finder上で「すべてのファイル名拡張子を表示」にチェックが入っているかを返す

Posted on 5月 19, 2020 by Takaaki Naganoya

Finderの環境設定で「すべてのファイル名拡張子を表示」にチェックが入っているかを確認するAppleScriptです。

iWorkアプリケーション(Keynote、Pages、Numbers)では、オープン中の書類名を返すときに、Finderの上記の環境設定の内容を反映して拡張子を含めたり、含めなかったりしつつ名称を返すという仕様。

「ファイル名単独で求めることなんてないでしょ?」と思いつつも、オープン中のドキュメントの存在確認を名称で行うため、けっこう左右されることになります。

AppleScript名:Finder上で「すべてのファイル名拡張子を表示」にチェックが入っているかを返す.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/05/19
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

set exRes to checkDisplayTheFileExtensionsInFinder() of me
–> true

on checkDisplayTheFileExtensionsInFinder()
  try
    set aRes to (do shell script "/usr/bin/defaults read NSGlobalDomain AppleShowAllExtensions") as integer
    
return aRes as boolean
  on error
    return false
  end try
end checkDisplayTheFileExtensionsInFinder

★Click Here to Open This Script 

Posted in file shell script | Tagged Finder Keynote Numbers Pages | 2 Comments

iWork Apps Update v10.0

Posted on 4月 1, 2020 by Takaaki Naganoya

Keynote、Pages、Numbersのv10.0が配信されました。Keynoteの前バージョンはv9.2、Pagesはv8.2、Numbersはv6.2.1でしたが、バージョン番号を別々に採番することがめんどくさくなったのか、内部のエンジンが一新されたのか、バージョン番号をそろえてきました。

おそらく、マーケティング的な要請やユーザーサポートの手間を省くために番号をそろえてきたのでしょう。

Pages/NumbersについてはmacOS 10.14以上が対象。KeynoteはmacOS 10.15.4が必要とのことですが、いろいろ致命的なバグの修正を含んでいるため、後日macOS 10.14.6向けのKeynoteアップデートが配信されることを期待したいところです。

# アップデートに出てこないだけで、Mac App Storeから個別にKeynote v10.0のダウンロードが(macOS 10.14.6上でも)できました。なんででしょう?

v10.0 UpdateのAppleScript的な変更の有無

■Keynote v10.0:2か所

■Pages v10.0:1か所

■Numbers v10.0:変更点なし
Numbers v6.2で「特定の行数の表を作るとエラーになる」というバグがありましたが、これはv6.2.1で修正されました。これが修正されています(記憶違いだったので、記事を修正しておきます)。

Pages v10.0の変更点

documentにfacing pagesというプロパティが新設されました。見開き表示時にページの左右(奇数ページ、偶数ページ)を考慮して2ページ表示のペアを変更するという機能のようです。

AppleScript名:Pages v10.0で追加されたfacing pagesの操作を行う
tell application "Pages"
  tell front document
    set curStat to facing pages
    
    
set facing pages to not curStat –反転
    
delay 2
    
set facing pages to curStat –元に戻す
  end tell
end tell

★Click Here to Open This Script 

全言語的に普遍的な内容ではあるのですが、日本語ユーザー的には縦書き/横書きの設定属性値を持ってくれたほうがありがたいところです。たぶん、自分は使うことはないと思います。

Keynote v10.0の変更点

Keynoteは前バージョンでかなりおかしなバグが発覚していたので、その修正が行われているかどうか、というのが見所です。

結論からいえば、バグは修正されています。macOSに関して久しぶりに前向きなニュースといえます。彼らにバグを修正する意思と能力が残されていたことについては喜びたいところです。同時に残念なニュースとして、この修正に関連して新たなバグが生まれています(このあたりがいかにもAppleらしい)。

Keynoteバグ1:表(table)作成時に行数によってはエラーになる

5行の表を作るとエラーになり、他の行数でもいろいろエラーになる組み合わせが確認されていました。テスト用のAppleScriptを書いて、行数を2〜100行で変更しつつ作成、列数を2〜30列で変更しつつ作成、行数および列数を順次ループで2〜20まで変更しつつ新規作成するなどのテストを実施。無事、修正を確認できました。

ただし、本テストは表の新規作成についてのみ確認したものであり、既存の表の行数/列数の変更を確認したものではありません。Appleの仕事に関しては、修正点の周囲に新たなバグを生む可能性が高く、修正時と修正後が一番危険な状態です。彼らに「自分の作った機能を動作確認する」という能力を期待してはいけません。信じてもいけません。つねに、疑いの目で見ることが重要です。

AppleScript名:Keynote書類上に表を作成、行数を2から100まで可変
tell application "Keynote"
  tell front document
    tell current slide
      repeat with i from 2 to 100
        set aTable to make new table with properties {header column count:0, header row count:0, row count:i, column count:3}
        
delay 1
        
delete aTable
      end repeat
    end tell
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:Keynote書類上に表を作成、列数を2から30まで可変
tell application "Keynote"
  tell front document
    tell current slide
      repeat with i from 2 to 30
        set aTable to make new table with properties {header column count:0, header row count:0, row count:5, column count:i}
        
delay 1
        
delete aTable
      end repeat
    end tell
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:Keynote書類上に表を作成、行数および列数を2から20まで可変
tell application "Keynote"
  tell front document
    tell current slide
      repeat with x from 2 to 20
        repeat with y from 2 to 20
          set aTable to make new table with properties {header column count:0, header row count:0, row count:y, column count:x}
          
delay 0.01
          
delete aTable
        end repeat
      end repeat
    end tell
  end tell
end tell

★Click Here to Open This Script 

Keynoteバグ2:書類(document)のムービーexport optionsにバグ

数値ではじまる予約語や記号を含む予約語はAppleScriptの言語処理系では宣言できません。エラーになります。それをAppleの(おそらくKeynoteの)担当者がKeynote v7.1のアップデート時に、従来の「small」「midium」「large」といったEnumによる指定から、「360p」「540p」「720p」「1080p」「2160p」という指定を行えるように変更を加えました。

より大きな解像度の書き出しに対処したことは評価できると思いますが、そもそもAppleScriptの処理系で認識できない「数字で始まる予約語」に変えたのはダメダメです(スクリプトエディタ上で構文確認を行うとエラーになる=使えない)。つまり、この担当者はsdefの改変を行なっただけで、実際にコードを書いて動作確認を行っていないことがわかります。

Appleにバグレポートを書きつつ、このような処理が必要な場合にはnative sizeで書き出して、そのあとでムービーをリサイズするような処理で回避していました(GUI Scriptingで乗り切ったScripterもいるようですが)。

Keynote v10.0では「format360p」「format540p」「format720p」「format1080p」「format2160p」と変更され、AppleScriptの構文確認時にエラーでハネられることはなくなりました。この点についてはバグ修正が行われたものと判断してよいと思われます。

ただし、従来動作していたEnum「native size」を指定するとエラーになるようになってしまいました。互換性のために残したが動作していない、といったコメントが書かれているわけでもないため、これはバグだと判断します。

■Keynote書類フォーマットとムービー書き出し時の解像度の対応表(Piyomaru Software独自調査による)

movie export formats 標準(4:3) ワイド(16:9)
format360p 480 × 360 640 × 360
format540p 720 × 540 960 × 540
format720p 960 × 720 1280 × 720
format1080p 1440 × 1080 1920 × 1080
format2160p 2880 × 2160 3840 × 2160
AppleScript名:Keynote 360p movie export test
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある
if targetFileHFSPath does not end with ".m4v" then
  set targetFileHFSPath to targetFileHFSPath & ".m4v"
end if

with timeout of 3600 seconds
  tell application "Keynote"
    export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format360p}
  end tell
end timeout

★Click Here to Open This Script 

AppleScript名:Keynote 540p movie export test
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある
if targetFileHFSPath does not end with ".m4v" then
  set targetFileHFSPath to targetFileHFSPath & ".m4v"
end if

with timeout of 3600 seconds
  tell application "Keynote"
    export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format540p}
  end tell
end timeout

★Click Here to Open This Script 

AppleScript名:Keynote 720p movie export test
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある
if targetFileHFSPath does not end with ".m4v" then
  set targetFileHFSPath to targetFileHFSPath & ".m4v"
end if

with timeout of 3600 seconds
  tell application "Keynote"
    export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format720p}
  end tell
end timeout

★Click Here to Open This Script 

AppleScript名:Keynote 1080p movie export test
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある
if targetFileHFSPath does not end with ".m4v" then
  set targetFileHFSPath to targetFileHFSPath & ".m4v"
end if

with timeout of 3600 seconds
  tell application "Keynote"
    export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format1080p}
  end tell
end timeout

★Click Here to Open This Script 

AppleScript名:Keynote 2160p movie export test
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある
if targetFileHFSPath does not end with ".m4v" then
  set targetFileHFSPath to targetFileHFSPath & ".m4v"
end if

with timeout of 3600 seconds
  tell application "Keynote"
    export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:format2160p}
  end tell
end timeout

★Click Here to Open This Script 

AppleScript名:Keynote ‌‌native size movie export test (Bug)
set targetFileHFSPath to (choose file name) as string –かならずファイル拡張子に「.m4v」を指定する必要がある
if targetFileHFSPath does not end with ".m4v" then
  set targetFileHFSPath to targetFileHFSPath & ".m4v"
end if

with timeout of 3600 seconds
  tell application "Keynote"
    –export front document to file targetFileHFSPath as QuickTime movie with properties {movie format:‌‌native size}
  end tell
end timeout

★Click Here to Open This Script 

Posted in Bug news | Tagged 10.14savvy 10.15savvy Keynote Numbers Pages | 1 Comment

Numbersで書類Aのすべてのシートの表1を、書類Bの現在のシートの表1にまとめる

Posted on 1月 21, 2020 by Takaaki Naganoya

Numbersでオープン中の複数の書類があったときに、書類Aのすべてのシートの表1を、書類Bの現在のシートの表1にまとめるAppleScriptです。

さすがに、機械的な作業すぎて手で行う気にはなれなかったので、ありもののScriptを利用して作ってみました。

こういう用途のために作っておいたライブラリ「choose multiple list」を利用しています。


▲データ取得元


▲データ集約先


▲ダイアログで「データ取得元」と「データ集約先」を選択

BridgePlus内蔵のFrameworkがmacOS 10.14/10.15に邪魔されて認識されない環境では動かせないかもしれません。このあたり、SIP解除するしかないと思わせるものがあります。

ライブラリで複雑な選択を行えるUI部品を作っておいたおかげで、これだけ込み入った動作を行うAppleScriptを書きましたが、Cocoaの機能はほぼ使っていません(getDataFromNumbersDocは作り置きしておいた、頻出ルーチンなので使いまわしています)。choose multiple listライブラリは、こういう用途のために作っておいたものであり、まさにそのぴったりな用途であったといえるでしょう。

AppleScript名:書類Aのすべてのシートの表1を、書類Bの現在のシートの表1にまとめる.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/01/20
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.7" — High Sierra (10.13) or later
use framework "Foundation"
use scripting additions
use bPlus : script "BridgePlus"
use mulList : script "choose multiple list"

script spd
  property allData : {}
end script

set (allData of spd) to {}

set {aName, bName} to getTargetDocNames() of me

–「データ取得元」のNumbers書類のすべてのシートの表1から2D Listでデータ取得
tell application "Numbers"
  tell document aName
    set sList to name of every sheet
    
repeat with i in sList
      set tmp2DDat to getDataFromNumbersDoc(aName, i) of me
      
set (allData of spd) to (allData of spd) & tmp2DDat
    end repeat
  end tell
end tell

set aHeight to length of (allData of spd)
set aWidth to length of item 1 of (allData of spd)

–「データ集約先」のNumbers書類の現在のシートの表1にまとめた2D Listを展開する(巨大すぎると時間がかかるので、CSV書き出ししてオープンするなどの別の方法を採るべき)
tell application "Numbers"
  tell document bName
    tell active sheet
      set tRes to make new table with properties {row count:aHeight + 1, column count:aWidth}
    end tell
  end tell
end tell

fillCurrentTable(bName, (allData of spd)) of me

–Numbersの書類の現在のシートを、指定の2次元配列でfillする
on fillCurrentTable(docName, aList)
  set aLen to length of aList
  
set aWidth to length of first item of aList
  
  
tell application "Numbers"
    tell document docName
      tell active sheet
        tell table 1
          repeat with i from 1 to aLen
            tell row (i + 1)
              set aRowList to contents of item i of aList
              
repeat with ii from 1 to aWidth
                tell cell ii
                  set aTmpData to contents of item ii of aRowList
                  
ignoring application responses
                    set value to aTmpData
                  end ignoring
                end tell
              end repeat
            end tell
          end repeat
        end tell
      end tell
    end tell
  end tell
end fillCurrentTable

–Numbersでオープン中の書類の名称一覧からデータ取得元とデータ集約先の書類名をダイアログで選択
on getTargetDocNames()
  tell application "Numbers"
    set nList to name of every document
  end tell
  
  
set selList to {nList, nList}
  
set tList to {"データ取得元", "データ集約先"}
  
  
set {aRes, bRes} to choose multiple list selList main message "各Numbers書類の役割を選択してください" sub message "「データ取得元」のデータを順次、「データ集約先」の表1に連結します" with title lists tList height 140 width 400 return type item contents without allow same items
  
return {aRes, bRes}
end getTargetDocNames

–Numbersでオープン中の書類の選択中のシートの表1からデータを取得して2D Listに
on getDataFromNumbersDoc(aDocName, sheetName)
  
  
load framework
  
  
tell application "Numbers"
    if (count (every document)) = 0 then return false
    
    
tell document aDocName
      if (count (every sheet)) = 0 then return false
      
      
tell sheet sheetName
        tell table 1
          set colCount to column count
          
set rowCount to row count
          
set headerCount to header row count
          
set footerCount to footer row count
          
          
set dList to value of every cell of cell range
        end tell
      end tell
      
    end tell
  end tell
  
  
–Convert 1D List to 2D List
  
set bList to (current application’s SMSForder’s subarraysFrom:dList groupedBy:colCount |error|:(missing value)) as list
  
set sItem to 1 + headerCount
  
set eItem to rowCount – footerCount
  
set cList to items sItem thru eItem of bList
  
  
return cList
  
end getDataFromNumbersDoc

★Click Here to Open This Script 

Posted in dialog GUI list | Tagged 10.13savvy 10.14savvy 10.15savvy Numbers | Leave a comment

Numbersでオープン中の最前面の書類のすべてのシートの表1の行数合計を計算する

Posted on 1月 15, 2020 by Takaaki Naganoya

Numbersでオープン中の最前面の書類のすべてのシートの表1の行数の合計を計算するAppleScriptです。

Blogアーカイブ本作成のために書いたものです。

この記事数をカウントするために使いました。

AppleScript名:Numbersでオープン中の最前面の書類のすべてのシートの表1の行数合計を計算する
set aCount to 0

tell application "Numbers"
  tell front document
    set sList to every sheet
    
repeat with i in sList
      tell i
        try
          set tmpC to count every row of table 1
          
set aCount to aCount + tmpC
        end try
      end tell
    end repeat
  end tell
end tell

return aCount

★Click Here to Open This Script 

Posted in Number | Tagged 10.13savvy 10.14savvy 10.15savvy Numbers | Leave a comment

Numbersで各シート名称を置換

Posted on 1月 15, 2020 by Takaaki Naganoya

Numbersでオープン中の最前面の書類中にあるすべてのシートの名前を置換するAppleScriptです。

内容は簡単ですが、Numbersにそうした機能が存在しないので、作っておくと便利です。アーカイブ本を作るのに、こうした(↓)資料を作る必要があるわけですが、そのためにこうしたこまごまとしたScriptをその場で作って作業の効率化を図っています。


▲上の画像あくまでは処理イメージなので、厳密に同一データの処理前・処理後の画面スナップショットではありません。各シートの名称の一部の文字列(YYYY部分)のみ置換されていることをご確認ください

AppleScript名:Numbersで各シート名称を置換
tell application "Numbers"
  tell front document
    set tList to every sheet
    
repeat with i in tList
      tell i
        set aName to name
        
set bName to replaceText(aName, "2011_", "2013_") of me
        
set name to bName
      end tell
    end repeat
  end tell
end tell

–任意のデータから特定の文字列を置換
on replaceText(origData, origText, repText)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to {origText}
  
set origData to text items of origData
  
set AppleScript’s text item delimiters to {repText}
  
set origData to origData as text
  
set AppleScript’s text item delimiters to curDelim
  
return origData
end replaceText

★Click Here to Open This Script 

Posted in Text | Tagged 10.12savvy 10.13savvy 10.14savvy 10.15savvy Numbers | Leave a comment

Safariで現在見えている表を抽出してCSV書き出しv3

Posted on 10月 8, 2019 by Takaaki Naganoya

Safariの最前面のウィンドウで表示中のページのうち、現在ウィンドウ内に表示中の表要素をCSV書き出ししてNumbersでオープンするAppleScriptの改良版です。HTMLのtable中にrowspan(複数セルを行方向に連結)とcolspan(複数セルを列方向に連結)の属性値が指定されていた場合に対応します。

–> Download table2CSV_visibleonly_v2 (Code-Signed AppleScript applet with Framework and Library in its bundle)

各DOM ElementsのWebコンテンツ中の表示座標を取得して、絞り込みを行なっています。ただし、各DOM座標はWebブラウザのスクロールにしたがって数値が変わる(相対座標)ため、少々手こずりました。また、本Scriptでは上下スクロールのみ考慮してDOM要素の抽出を行なっており、横に長いページの横方向スクロールは考慮しておりません。

このバージョンではrowspan / colspanへの対処を追加しました。

行単位で(1次元配列ベースで)表を作っていてはとても対処できなかったので、HTMLの表と同じセル数のヌル文字が入った2次元配列を作成し、そこにX座標/Y座標を指定してセルを埋めるように処理内容を変更しました。また、rowspan/colspanの属性を見つけた場合には、結合されていた複数セルを個別の(同じ値を入れた)セルに分解しています。

本バージョンでは、1つのセル(td)でrowspanとcolspanを同時に指定しないことが処理の前提条件となっています。また、一番上の行がヘッダーの場合を想定しており、一番左の列がヘッダーになっているケースには対処しておりません。

AppleScript名:Safariで現在見えている表を抽出してCSV書き出しv3.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/09/22
–  Modified on: 2019/10/07
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader
use aLib : script "arrayLib"

property NSUUID : a reference to current application’s NSUUID
property NSString : a reference to current application’s NSString
property HTMLDocument : a reference to current application’s HTMLDocument
property NSMutableArray : a reference to current application’s NSMutableArray
property NSJSONSerialization : a reference to current application’s NSJSONSerialization

set aTag to "table"

set indRes to getVisibleElementIndexList(aTag) of me
if indRes = false or indRes = {} then
  display notification "No Visible Table in Web browser"
  
return
end if

tell application "Safari"
  tell front document
    set aSource to source
  end tell
end tell

repeat with i in indRes
  set inList to filterATableAndPaseCells(aSource, i, aTag) of me
  
  
if inList = false or inList = {} then return
  
set aUUID to current application’s NSUUID’s UUID()’s UUIDString() as text
  
set aNewFile to ((path to desktop) as string) & aUUID & ".csv"
  
saveAsCSV(inList, aNewFile) of me
  
  
tell application "Numbers"
    activate
    
open (aNewFile as alias)
  end tell
end repeat

on filterATableAndPaseCells(aSource as string, targInd as integer, aTag as string)
  set aHTML to current application’s HTMLDocument’s documentWithString:(aSource as string)
  
  
–Table要素をリストアップ
  
set eList to (aHTML’s nodesMatchingSelector:aTag) as list
  
set aObj to contents of item (targInd + 1) of eList
  
  
–Count columns of Table Header (Count only)
  
set aTableHeader to (aObj’s nodesMatchingSelector:"tr")’s firstObject()
  
set hList to aTableHeader’s nodesMatchingSelector:"th"
  
set hStrList to {}
  
repeat with i1 in hList
    set hCellStr to i1’s textContent() as string
    
set the end of hStrList to (hCellStr)
  end repeat
  
set hLen to length of hStrList –count columns
  
  
  
–Acquire whole table body contents
  
set aTableBody to (aObj’s nodesMatchingSelector:"tbody")’s firstObject()
  
set bList to (aTableBody’s nodesMatchingSelector:"tr") as list
  
  
set rCount to (length of bList) –count rows
  
  
–行単位ループ
  
set yCount to 1
  
set attrList to make2DBlankArray(hLen, rCount) of aLib
  
  
repeat with i2 in bList
    set bb2List to {}
    
set i3 to (i2’s nodesMatchingSelector:"th") as list
    
if i3 = {} then
      set i3 to (i2’s nodesMatchingSelector:"td") as list
    end if
    
    
–カラム単位ループ
    
set xCount to 1
    
repeat with i4 in i3
      set anAttr to i4’s attributes()
      
set colAtr to (anAttr’s valueForKey:"colspan")
      
set rowAttr to (anAttr’s valueForKey:"rowspan")
      
set cellStr to i4’s textContent() as string
      
      
if colAtr is not equal to missing value then
        –colspan処理
        
set colNum to colAtr as integer
        
set attrList to xFill(xCount, yCount, attrList, cellStr, colNum) of aLib
        
      else if rowAttr is not equal to missing value then
        –rowspan処理
        
set rowNum to rowAttr as integer
        
set attrList to yFill(xCount, yCount, attrList, cellStr, rowNum) of aLib
        
      else if cellStr is not equal to "" then
        –通常処理
        
repeat with ii from xCount to hLen
          set aRes to getItemByXY(ii, yCount, attrList, "") of aLib
          
if aRes = "" then
            set attrList to setItemByXY(ii, yCount, attrList, cellStr) of aLib
            
exit repeat
          else
            set xCount to xCount + 1
          end if
        end repeat
        
      end if
      
      
set xCount to xCount + 1
    end repeat
    
    
set yCount to yCount + 1
  end repeat
  
  
return attrList
end filterATableAndPaseCells

–Safariのウィンドウ上で表示中のDOM Elementsを座標計算して返す
on getVisibleElementIndexList(aTag as string)
  tell application "Safari"
    set dCount to count every document
    
if dCount = 0 then return false
    
    
set jRes to do JavaScript "var winWidth = window.innerWidth,
winHeight = window.innerHeight,
winLeft = window.scrollX,
winTop = window.scrollY,
winBottom = winTop + winHeight,
winRight = winLeft + winWidth,
    elementsArray = document.body.getElementsByTagName(’" & aTag & "’),
    elemLen = elementsArray.length,
inView = [];
      
    var step;
    for (step = 0 ; step < elemLen ; step++) {
      var tmpElem = document.body.getElementsByTagName(’" & aTag & "’)[step];
      var bVar = tmpElem.getBoundingClientRect();
      if (bVar.top > 0 && bVar.top < winHeight) {
        inView.push(step);
      }
    }
    JSON.stringify(inView);"
in front document
    
    
set jList to parseJSONAsList(jRes) of me
    
return jList
    
  end tell
end getVisibleElementIndexList

on parseJSONAsList(jsRes as string)
  set jsonString to NSString’s stringWithString:jsRes
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict as list
end parseJSONAsList

–Save 2D List to CSV file
on saveAsCSV(aList as list, aPath)
  set crlfChar to (string id 13) & (string id 10)
  
set LF to (string id 10)
  
set wholeText to ""
  
  
repeat with i in aList
    set newLine to {}
    
    
–Sanitize (Double Quote)
    
repeat with ii in i
      set jj to ii as text
      
set kk to repChar(jj, string id 34, (string id 34) & (string id 34)) of me –Escape Double Quote
      
set the end of newLine to kk
    end repeat
    
    
–Change Delimiter
    
set aLineText to ""
    
set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to "\",\""
    
set aLineList to newLine as text
    
set AppleScript’s text item delimiters to curDelim
    
    
set aLineText to repChar(aLineList, return, "") of me –delete return
    
set aLineText to repChar(aLineText, LF, "") of me –delete lf
    
    
set wholeText to wholeText & "\"" & aLineText & "\"" & crlfChar –line terminator: CR+LF
  end repeat
  
  
if (aPath as string) does not end with ".csv" then
    set bPath to aPath & ".csv" as Unicode text
  else
    set bPath to aPath as Unicode text
  end if
  
  
writeToFileAsUTF8(wholeText, bPath, false) of me
  
end saveAsCSV

on writeToFileAsUTF8(this_data, target_file, append_data)
  tell current application
    try
      set the target_file to the target_file as text
      
set the open_target_file to open for access file target_file with write permission
      
if append_data is false then set eof of the open_target_file to 0
      
write this_data as «class utf8» to the open_target_file starting at eof
      
close access the open_target_file
      
return true
    on error error_message
      try
        close access file target_file
      end try
      
return error_message
    end try
  end tell
end writeToFileAsUTF8

on repChar(origText as text, targChar as text, repChar as text)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

★Click Here to Open This Script 

Posted in file JavaScript list Record Text | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSJSONSerialization NSMutableArray NSString NSUUID Numbers Safari | 4 Comments

iWork Appsがアップデート、表の新規作成時バグは未修正

Posted on 10月 2, 2019 by Takaaki Naganoya

iWork Apps(Keynote、Pages、Numbers)がアップデートし、Keynote v9.2、Pages v8.2、Numbers v6.2になりました。

KeynoteとNumbersで表の新規作成時に特定のセル数でエラーになる(ほとんどのケースでエラーになる)バグが修正されていないことを確認しました。Pagesは未確認です。

Pages v8.2で表の新規作成を試してみたところ、Pagesでは行数や桁数を指定しても問題なく作成できました。

tell application "Pages"
  tell front document
    tell page 1
      make new table at beginning with properties {row count:20, column count:5, header row count:2, header column count:2, position:{60, 80}}
    end tell
  end tell
end tell

★Click Here to Open This Script 

Numbersでimageのposition X座標による制御ができないバグはNumbers v6.2で修正されたことを確認しました。

Posted in Bug | Tagged Keynote Numbers Pages | Leave a comment

Safariで現在見えている表を抽出してCSV書き出し

Posted on 9月 24, 2019 by Takaaki Naganoya

Safariの最前面のウィンドウで表示中のページのうち、現在ウィンドウ内に表示中の表要素をCSV書き出ししてNumbersでオープンするAppleScriptです。

このところ下調べを行なっていた「Webブラウザで表示中の要素を処理する」「表示中ではない要素は処理をしない」というScriptです。

これで、「表の一部を選択しておく」とかいった操作は不要になりました。ウィンドウ内に表示されている表をWebコンテンツ内部の表示座標をもとに自動抽出します。表示エリア外に位置しているものは書き出し処理しません。

各DOM ElementsのWebコンテンツ中の表示座標を取得して、絞り込みを行なっています。ただし、各DOM座標はWebブラウザのスクロールにしたがって数値が変わる(相対座標)ため、少々手こずりました。また、本Scriptでは上下スクロールのみ考慮してDOM要素の抽出を行なっており、横に長いページの横方向スクロールは考慮しておりません。

本Scriptは大量一括処理を志向するプログラムではなく、「見えているもの」をそのまま処理してほしいという考えで作ったものでもあり、Webブラウザ(Safari)で表示中のページのソースを取得してそのまま処理しています。つまり、ユーザーが閲覧中のページのデータそのものを処理しています。

これは、ページのソースを取得するコマンドを持っていないGoogle Chromeにはできない処理です(同じURLの内容を別途curlコマンドなどで取得すればOK。Cookie値などの再現が大変でしょうけれども)。

その他、実際に作って使ってみた感想は、装飾用に使われている表データまで取り込んでしまう点に不満があるぐらいでしょうか。これら「ゴミデータ」(再利用する価値のない装飾用の表データ)を区別するために、行数が足りない場合には書き出さないといった「足切り」を行う必要性を感じます。

–> Download VisibleTableExporter(Code-signed executable applet with Framework in its bundle)

AppleScript名:Safariで現在見えている表を抽出してCSV書き出し.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/09/22
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader

property NSUUID : a reference to current application’s NSUUID
property NSString : a reference to current application’s NSString
property HTMLDocument : a reference to current application’s HTMLDocument
property NSMutableArray : a reference to current application’s NSMutableArray
property NSJSONSerialization : a reference to current application’s NSJSONSerialization

set aTag to "table"

set indRes to getVisibleElementIndexList(aTag) of me
if indRes = false or indRes = {} then
  display notification "No Visible Table in Web browser"
  
return
end if

tell application "Safari"
  tell front document
    set aSource to source
  end tell
end tell

repeat with i in indRes
  set inList to filterATableAndPaseCells(aSource, i, aTag) of me
  
if inList = false or inList = {} then return
  
set aUUID to current application’s NSUUID’s UUID()’s UUIDString() as text
  
set aNewFile to ((path to desktop) as string) & aUUID & ".csv"
  
saveAsCSV(inList, aNewFile) of me
  
  
tell application "Numbers"
    open (aNewFile as alias)
  end tell
end repeat

tell application "Numbers" to activate

on filterATableAndPaseCells(aSource as string, targInd as integer, aTag as string)
  set aHTML to current application’s HTMLDocument’s documentWithString:(aSource as string)
  
  
–Table要素をリストアップ
  
set eList to (aHTML’s nodesMatchingSelector:aTag) as list
  
set aObj to contents of item (targInd + 1) of eList
  
  
  
–Count columns of Table Header
  
set aTableHeader to (aObj’s nodesMatchingSelector:"tr")’s firstObject()
  
set hList to aTableHeader’s nodesMatchingSelector:"th"
  
set hStrList to {}
  
repeat with i1 in hList
    set the end of hStrList to i1’s textContent() as string
  end repeat
  
set hLen to length of hStrList –count columns
  
  
–Acquire whole table body contents
  
set aTableBody to (aObj’s nodesMatchingSelector:"tbody")’s firstObject()
  
set bList to aTableBody’s nodesMatchingSelector:"td"
  
set bbList to {}
  
repeat with i2 in bList
    set the end of bbList to i2’s textContent() as string
  end repeat
  
  
set tbList to makeList1DTo2D(bbList, hLen) of me
  
  
return {hStrList} & tbList
end filterATableAndPaseCells

–1D Listを2D化
on makeList1DTo2D(orig1DList as list, aMax)
  set tbList to {}
  
set tmpList to {}
  
set aCount to 1
  
  
repeat with i3 in orig1DList
    set j to contents of i3
    
set the end of tmpList to j
    
    
if aCount ≥ aMax then
      set aCount to 1
      
set the end of tbList to tmpList
      
set tmpList to {}
    else
      set aCount to aCount + 1
    end if
  end repeat
  
  
return tbList
end makeList1DTo2D

–Safariのウィンドウ上で表示中のDOM Elementsを座標計算して返す
on getVisibleElementIndexList(aTag as string)
  tell application "Safari"
    set dCount to count every document
    
if dCount = 0 then return false
    
    
set jRes to do JavaScript "var winWidth = window.innerWidth,
winHeight = window.innerHeight,
winLeft = window.scrollX
winTop = window.scrollY,
winBottom = winTop + winHeight,
winRight = winLeft + winWidth,
    elementsArray = document.body.getElementsByTagName(’" & aTag & "’),
    elemLen = elementsArray.length,
inView = [];
      
    var step;
    for (step = 0 ; step < elemLen ; step++) {
      var tmpElem = document.body.getElementsByTagName(’" & aTag & "’)[step];
      var bVar = tmpElem.getBoundingClientRect();
      if (bVar.top > 0 && bVar.top < winHeight) {
        inView.push(step);
      }
    }
    JSON.stringify(inView);"
in front document
    
    
set jList to parseJSONAsList(jRes) of me
    
return jList
    
  end tell
end getVisibleElementIndexList

on parseJSONAsList(jsRes as string)
  set jsonString to NSString’s stringWithString:jsRes
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict as list
end parseJSONAsList

–Save 2D List to CSV file
on saveAsCSV(aList as list, aPath)
  set crlfChar to (string id 13) & (string id 10)
  
set LF to (string id 10)
  
set wholeText to ""
  
  
repeat with i in aList
    set newLine to {}
    
    
–Sanitize (Double Quote)
    
repeat with ii in i
      set jj to ii as text
      
set kk to repChar(jj, string id 34, (string id 34) & (string id 34)) of me –Escape Double Quote
      
set the end of newLine to kk
    end repeat
    
    
–Change Delimiter
    
set aLineText to ""
    
set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to "\",\""
    
set aLineList to newLine as text
    
set AppleScript’s text item delimiters to curDelim
    
    
set aLineText to repChar(aLineList, return, "") of me –delete return
    
set aLineText to repChar(aLineText, LF, "") of me –delete lf
    
    
set wholeText to wholeText & "\"" & aLineText & "\"" & crlfChar –line terminator: CR+LF
  end repeat
  
  
if (aPath as string) does not end with ".csv" then
    set bPath to aPath & ".csv" as Unicode text
  else
    set bPath to aPath as Unicode text
  end if
  
  
writeToFileAsUTF8(wholeText, bPath, false) of me
  
end saveAsCSV

on writeToFileAsUTF8(this_data, target_file, append_data)
  tell current application
    try
      set the target_file to the target_file as text
      
set the open_target_file to open for access file target_file with write permission
      
if append_data is false then set eof of the open_target_file to 0
      
write this_data as «class utf8» to the open_target_file starting at eof
      
close access the open_target_file
      
return true
    on error error_message
      try
        close access file target_file
      end try
      
return error_message
    end try
  end tell
end writeToFileAsUTF8

on repChar(origText as text, targChar as text, repChar as text)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

★Click Here to Open This Script 

Posted in file JavaScript list Text | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSJSONSerialization NSMutableArray NSString NSUUID Numbers Safari | 1 Comment

tableExtractor

Posted on 9月 15, 2019 by Takaaki Naganoya

Safariで表示中のページのうち、テキストを選択中のキーワードを含む表をCSVファイルに書き出してNumbersでオープンするAppleScriptです。

–> Download tableExtractor Run-Only (Code-Signed Executable including Framework in its bundle)

–> Watch Demo movie

実行前にSafariの「開発」メニューから、「スマート検索フィールドからのJavaScriptの実行を許可」「AppleEventからのJavaScriptの実行を許可」を実行しておく必要があります(実行済みの場合には必要ありません)。


▲Safariで表示中のページのうち、CSV書き出ししたい表のテキストを選択


▲本Scriptで表をCSVに書き出してNumbersでオープン

以前に作成した「Safariで表示中のPageの選択中の文字を含む表データを取得」Scriptがいい線を行っていた(あらかじめ表中のテキストを選択しておく、という前提条件がかったるいかと思っていたのに、そうでもなかった)ので、ありもののサブルーチンを追加して、表部分のHTMLからのタグ削除やCSV書き出しなどを行えるようにしました。

本Scriptは表データをCSV書き出しする必要はどこにもないのですが、Numbers v6.1に「表を新規作成して表のセル数を指定すると多くの場合にエラーになる」というバグがあるので、Numbersを直接操作してデータ出力させることはやっていません。

処理時間もさほどかからないので、表示中のページのすべての表オブジェクトをCSV化したり、表を選択するUIを実装して、「どの表を出力するか?」という選択処理をしてもいいかもしれません。


▲漫然とMacOS日本語で書き出ししたため文字化けしたもの(左)、UTF8を指定して書き出ししたために文字化けしなくなったもの(右)

途中でCSV書き出しした表データに文字化けが発生していたのですが、これはUTF8でファイル書き出ししていなかったためでした。

本Scriptは前バージョンよりもキーワードの検出処理をていねいに行なっています。各TableのHTMLに対してタグの除去を行なったうえでWebブラウザ上で選択中の文字列を含んでいるかどうかをチェックしています。

AppleScript名:tableExtractor.scptd
— Created 2019-09-15 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader

property NSString : a reference to current application’s NSString
property HTMLDocument : a reference to current application’s HTMLDocument
property NSMutableArray : a reference to current application’s NSMutableArray

tell application "Safari"
  set dList to every document –Sometimes "count every document"causes error
  
if length of dList = 0 then return
  
  
–Get URL
  
tell front document
    set aURL to URL
  end tell
  
  
–Get Selected Text
  
set aRes to do JavaScript "var selObj = window.getSelection();
  var selStr = (selObj).getRangeAt(0);
  unescape(selStr);"
in front document
  
  
if aRes = "" then return
end tell

set aRes to filterATableAndPaseCells(aURL, aRes) of me
if aRes = false then
  display notification "I could not filter table data…"
  
return
end if

–Save 2D List to temp CSV file on desktop folder
set savePath to ((path to desktop) as string) & (do shell script "uuidgen") & ".csv"
saveAsCSV(aRes, savePath) of me

tell application "Numbers"
  activate
  
open file savePath
end tell

on filterATableAndPaseCells(aURL, aKeyword)
  set aData to (do shell script "curl " & aURL)
  
set aHTML to current application’s HTMLDocument’s documentWithString:(aData as string)
  
  
–Table要素をリストアップ
  
set eList to (aHTML’s nodesMatchingSelector:"table")
  
  
–Table要素のうちSafari上で選択中の文字列を含むものをサーチ(指定データを含むものを抽出)
  
set hitF to false
  
repeat with i in eList
    set cellList to i’s children()’s array()
    
set htmlSource to i’s serializedFragment() as string –HTML source
    
set html2 to trimStrFromTo(htmlSource, "<", ">") of me
    
set html3 to repChar(html2, return, "") of me
    
    
if html3 contains aKeyword then
      set hitF to true
      
exit repeat
    end if
  end repeat
  
if hitF = false then return false
  
  
–Count columns of Table Header
  
set aTableHeader to (i’s nodesMatchingSelector:"tr")’s firstObject()
  
set hList to aTableHeader’s nodesMatchingSelector:"th"
  
set hStrList to {}
  
repeat with i1 in hList
    set the end of hStrList to i1’s textContent() as string
  end repeat
  
set hLen to length of hStrList –count columns
  
  
–Acquire whole table body contents
  
set aTableBody to (i’s nodesMatchingSelector:"tbody")’s firstObject()
  
set bList to aTableBody’s nodesMatchingSelector:"td"
  
set bbList to {}
  
repeat with i2 in bList
    set the end of bbList to i2’s textContent() as string
  end repeat
  
  
set tbList to makeList1DTo2D(bbList, hLen) of me
  
  
return {hStrList} & tbList
end filterATableAndPaseCells

–1D Listを2D化
on makeList1DTo2D(orig1DList, aMax)
  set tbList to {}
  
set tmpList to {}
  
set aCount to 1
  
  
repeat with i3 in orig1DList
    set j to contents of i3
    
set the end of tmpList to j
    
    
if aCount ≥ aMax then
      set aCount to 1
      
set the end of tbList to tmpList
      
set tmpList to {}
    else
      set aCount to aCount + 1
    end if
  end repeat
  
  
return tbList
end makeList1DTo2D

on trimStrFromTo(aParamStr, fromStr, toStr)
  set theScanner to current application’s NSScanner’s scannerWithString:aParamStr
  
set anArray to current application’s NSMutableArray’s array()
  
  
repeat until (theScanner’s isAtEnd as boolean)
    set {theResult, theKey} to theScanner’s scanUpToString:fromStr intoString:(reference)
    
    
theScanner’s scanString:fromStr intoString:(missing value)
    
set {theResult, theValue} to theScanner’s scanUpToString:toStr intoString:(reference)
    
if theValue is missing value then set theValue to ""
    
    
theScanner’s scanString:toStr intoString:(missing value)
    
    
anArray’s addObject:theValue
  end repeat
  
  
if anArray’s |count|() = 0 then return aParamStr
  
  
copy aParamStr to curStr
  
repeat with i in (anArray as list)
    set curStr to repChar(curStr, fromStr & i & toStr, "") of me
  end repeat
  
  
return curStr
end trimStrFromTo

on repChar(aStr, targStr, repStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set bString to aString’s stringByReplacingOccurrencesOfString:targStr withString:repStr
  
set cString to bString as string
  
return cString
end repChar

–2D List to CSV file
on saveAsCSV(aList, aPath)
  –set crlfChar to (ASCII character 13) & (ASCII character 10)
  
set crlfChar to (string id 13) & (string id 10)
  
set LF to (string id 10)
  
set wholeText to ""
  
  
repeat with i in aList
    set newLine to {}
    
    
–Sanitize (Double Quote)
    
repeat with ii in i
      set jj to ii as text
      
set kk to repChar(jj, string id 34, (string id 34) & (string id 34)) of me –Escape Double Quote
      
set the end of newLine to kk
    end repeat
    
    
–Change Delimiter
    
set aLineText to ""
    
set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to "\",\""
    
set aLineList to newLine as text
    
set AppleScript’s text item delimiters to curDelim
    
    
set aLineText to repChar(aLineList, return, "") of me –delete return
    
set aLineText to repChar(aLineText, LF, "") of me –delete lf
    
    
set wholeText to wholeText & "\"" & aLineText & "\"" & crlfChar –line terminator: CR+LF
  end repeat
  
  
if (aPath as string) does not end with ".csv" then
    set bPath to aPath & ".csv" as Unicode text
  else
    set bPath to aPath as Unicode text
  end if
  
  
writeToFileUTF8(wholeText, bPath, false) of me
  
end saveAsCSV

on writeToFileUTF8(this_data, target_file, append_data)
  tell current application
    try
      set the target_file to the target_file as text
      
set the open_target_file to open for access file target_file with write permission
      
if append_data is false then set eof of the open_target_file to 0
      
write this_data as «class utf8» to the open_target_file starting at eof
      
close access the open_target_file
      
return true
    on error error_message
      try
        close access file target_file
      end try
      
return error_message
    end try
  end tell
end writeToFileUTF8

★Click Here to Open This Script 

Posted in file Internet JavaScript list Text | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSMutableArray NSString Numbers Safari | 1 Comment

Numbersにも画期的なバグ〜特定のセルサイズの表を作るとエラーに

Posted on 8月 31, 2019 by Takaaki Naganoya

Numbers v6.1に、Keynote v9.1と同様の表作成バグが存在していることを確認しました。

Numbers v6.2でも修正されていないことを確認しました。

特定行数の表の新規作成を作成するとエラーになるという、「わざとやってないと出ないエラー」です。

それとも、何か型変換のミスとかそういう程度のひくーーいバグを作ったんじゃないかと。

とりあえず、サイズを指定せずにtableを作成して、あとから行数とカラム数を変更してもエラーになるので、回避方法がほぼありません(ーー;

データをCSV書き出ししておいてCSVをNumbersでオープンして新規に作成されたドキュメント上の表をコピーしてくる、ぐらいの回避策は考えないでもありませんが、、、、、何のためにコードを書いているのかよくわからなくなります(ーー;

探してみると、r/oではない属性値のオブジェクトに数値を突っ込んでもGUI側に反映されないなど、パラメータがいまひとつ正しく解釈されていない雰囲気が濃厚です。たとえば、active sheet上にimageを配置して、AppleScript側からpositionを変更することでY座標については制御できるものの、X座標の変更が行えていません、、、、

→ imageのpositionでX座標が制御できないバグについては、Numbers v6.2で修正されたことを確認しました

tell application "Numbers"
  tell front document
    tell active sheet
      tell image 1
        set position to {0, 0}
      end tell
    end tell
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:Numbers書類上に表を新規作成.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/08/31
—
–  Copyright © 2019 jp.piyomarusoft, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set aWidth to 3
set aHeight to 10

tell application "Numbers"
  set aDoc to make new document
  
tell aDoc
    tell active sheet
      set tRes to make new table with properties {row count:aHeight, column count:aWidth}
    end tell
  end tell
end tell

★Click Here to Open This Script 

Posted in Bug | Tagged 10.13savvy 10.14savvy Numbers | 3 Comments

NumbersのColumn Adr(26進数)と10進数との相互変換

Posted on 7月 22, 2019 by Takaaki Naganoya

Numbersの表のカラムを表現するアドレス文字列(26進数)と数値の間のエンコーダーおよびデコーダーのAppleScriptです。

もともとは、Excel 2004/2008で採用されたカラムアドレス形式に対処するためのScriptでした。

Excel上のセルのアドレス(場所)を指し示す方法は、「R1C1」(行とカラムを数値指定)形式、あるいはAppleScriptの行オブジェクトとセルオブジェクトで指定する形式でした。

そこへ新たに「A1」形式……画面上で表記されている行、カラムと親和性の高い形式が採用されることになりました。当初は相互変換のための関数なども用意されていなかったと記憶しています(間違っていたらご指摘ください)。そのため、Scripterが自力でこのA1形式に対応する必要が出てきました。

そんな中、Excel書類にAppleScriptを埋め込んで実行するAppleScriptを開発。本ルーチンはそのScript開発のために作成したものです。

Excel 2008でVBAの処理系が外されてMac上のVBA的なマクロ処理はAppleSctiptに一本化されるという話になっていたため(当時の話)、これを好機ととらえ、マイクロソフトのご担当にデモして、US本社で紹介していただくということになりました。

ただ、その会議上でVBAの復活プランが発表され、自分の提案したプランは廃案に(まさか当時のREALbasicのコンパイラの開発者を引き抜いてきてVBAの処理系をスクラッチで書かせるとは思いませんでしたわー)。

その後は、Excel 2011でVBAの処理系が復活。本ルーチンも割とHDDの肥やしとして絶賛在庫状態になっておりました。ごくたまーに、このExcel 2011でVBAの処理系が復活したことを知らない方がいて、「VBAで動いているマクロをAppleScriptに移植してほしい」という問い合わせがあるのですが、「Excelの最新版を購入してください。VBAがありますよ」とお返事しています。最新のExcelが動く環境を購入する費用よりも安く仕事としてお受けすることは困難なので。

そこから年月が流れ、AppleがNumbersをリリース。そのカラム表記がExcel 2004/2008と同じ形式になっているために、しまいこんでいたルーチンをふたたび引っ張り出してきた次第です。

一応、条件つきで使えるものの、作りが古い(やっつけ仕事な)点が気になります。きっと、誰かがもっといいルーチンを作って使っているに違いありません。一応、本ルーチンでは1〜1351の範囲での動作を確認しています。

もう少し改良したいところではあります。実用上は、Numbersでそこまで大きなデータは扱わない(はず)ので、問題はあまりないものと思われます。

AppleScript名:NumbersのColumn Adr(26進数)と10進数との相互変換
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/07/21
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property NSString : a reference to current application’s NSString
property NSArray : a reference to current application’s NSArray
property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch

repeat with i from 1 to 1351
  set a to numAdrToColumnEncode(i) of me
  
set b to colAddrToNumDecode(a) of me
  
set aRes to (i = b) as boolean
  
log {i, b, a, aRes}
  
if aRes = false then display dialog i as string
end repeat

–10進数数値をExcel 2004/2008的カラム表現にエンコードするサブルーチン(エンコード範囲:1〜1351)
on numAdrToColumnEncode(origNum)
  if origNum > 1351 then
    error "エラー:Numbersのカラム表現(A1形式)への変換ルーチンにおいて、想定範囲外(1351以上)のパラメータが指定されました"
  end if
  
  
set upperDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
set lowerDigitEncTable to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "A"}
  
  
set oNum to origNum
  
set nTh to 26
  
set stringLength to 4
  
  
–数字が1桁の場合の対応
  
if origNum < 27 then
    set aRes to (item origNum of upperDigitEncTable) as string
    
return aRes
  end if
  
  
  
if origNum > 702 then
    –3桁になる場合
    
set upupNum to oNum div 676 –整数除算–上の上の桁
    
set oNum to oNum – (upupNum * 676)
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
–log {origNum, upupNum, upNum, lowNum}
    
    
–超つじつま合わせルーチン【強引】
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upupChar to (item upupNum of upperDigitEncTable) as string
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upupChar & upChar & lowChar
    
  else
    –2桁の場合
    
set upNum to oNum div 26 –整数除算–上の桁
    
set lowNum to oNum mod 26 – 1 –余剰計算–下の桁
    
    
    
–超つじつま合わせルーチン【強引】
    
if lowNum = -1 then
      set upNum to upNum – 1
      
set lowNum to 25
    end if
    
    
set upChar to (item upNum of upperDigitEncTable) as string
    
set lowChar to (item (lowNum + 1) of lowerDigitEncTable) as string
    
set resText to upChar & lowChar
    
  end if
  
  
return resText
  
end numAdrToColumnEncode

–Numbersの横方向アドレス(A〜Zの26進数)文字列を10進数に変換
on colAddrToNumDecode(origStr)
  return aNthToDecimal(origStr, {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}) of me
end colAddrToNumDecode

–n進数文字列を10進数に変換する
on aNthToDecimal(origStr, nTh)
  set resNumber to 0
  
  
set sList to reverse of (characters of origStr)
  
set aLen to length of nTh
  
set digitCount to 0
  
  
repeat with i in sList
    set j to contents of i
    
set aRes to offsetInList(j, nTh) of me
    
    
set resNumber to resNumber + (aLen ^ digitCount) * aRes
    
    
set digitCount to digitCount + 1
  end repeat
  
  
return resNumber as integer
end aNthToDecimal

on offsetInList(aChar, aList)
  set anArray to NSArray’s arrayWithArray:aList
  
set aInd to (anArray’s indexOfObject:aChar)
  
if aInd = current application’s NSNotFound or (aInd as number) > 9.99999999E+8 then
    error "Invalid Character Error"
  else
    return (aInd as integer) + 1 –0 to 1 based index conversion
  end if
end offsetInList

★Click Here to Open This Script 

Posted in list Number | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSArray NSRegularExpressionSearch NSString Numbers | Leave a comment

Keynote, Pages, Numbersがアップデート

Posted on 6月 26, 2019 by Takaaki Naganoya

macOS 10.13以上で動作するiWorkアプリケーションの最新版がアップデートしました。

Keynote v9.1、Pages v8.1、Numbers v6.1です。

AppleScript用語辞書を書き出して比較してみましたが、用語辞書に変更は一切ありません。

ただし、アプリケーション自体には大幅に機能追加が行われており、ちょっと前までの停滞しまくっていたiWorkアプリケーションとは思えないほどの強化ぶりです。

Photos.app以外でははじめて顔認識の機能が(Apple純正アプリでは)利用され、写真を配置する際に顔認識して配置するとか、ページ間リンクを張るさいにブックマークを挿入(他のアプリケーションで言うところの「アンカー」ですね)したりと、アプリケーションとしてまっとうな機能アップが行われたように感じられました。

Posted in Release | Tagged 10.13savvy 10.14savvy Keynote Numbers Pages | Leave a comment

Numbersで選択中の表のセルの範囲を背景色で頻度集計

Posted on 6月 6, 2019 by Takaaki Naganoya

Numbersでオープン中の書類の現在のシート上にある表の選択範囲のセルに対して、背景色(Background color)で登場頻度の集計を行って、どの色が何回登場しているかを色プレビューしつつ表示するAppleScriptです。

集計をRGB値で数値的に行うことは容易ですが、結局のところ色なんてRGB値で見せられてもわからず、実際に目で見える色で表示しないと判断できません。そのため、アラートダイアログを作成してその上にColorWellで表示しています。


▲Numbersの表でセルを選択


▲Numbersの表のセルに指定されている背景色の登場頻度で集計し、色プレビューと登場回数を表示(スクリプトエディタ@macOS 10.14.5上の表示、Dark Mode)


▲Numbersの表のセルに指定されている背景色の登場頻度で集計し、色プレビューと登場回数を表示(Script Debugger@macOS 10.14.5上の表示、Dark Mode)

上記サンプル表は本Blog上での説明用のために簡略化した表ですが、実際には数十行の入り組んだNumbersの表を相手にしており、かつ、手作業で色付きセルだけを数えるなんて考えたくもないレベルで頻繁に確認しなくてはならなかったために、本Scriptを作ってみました。

Numbersにかぎらず、iWorkアプリケーション(Keynote、Pages、Numbers)で共通の仕様ですが、背景色を塗らないセルから背景色を取得するとmissing valueが返ります。

本ScriptはScript Menuに入れて実行するとアラートダイアログが最前面に出てこないなど、Script書類(.scpt、.scptd)のままで実行すると問題が発生。Script Menuに入れる場合にはアプレット(.app)書き出しする必要があります。


▲スクリプトメニューにアプレット書き出しした実行ファイルを入れて呼び出し(macOS 10.14.5)。スクリプトメニューは最前面にあるGUIアプリケーションに応じて、それぞれのアプリケーション用のメニューを表示できるようになっている

AppleScript名:選択中の表のセルの範囲を背景色で頻度集計.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/06/06
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

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 NSIndexSet : a reference to current application’s NSIndexSet
property NSTextField : a reference to current application’s NSTextField
property NSColorWell : a reference to current application’s NSColorWell
property NSScrollView : a reference to current application’s NSScrollView
property NSMutableArray : a reference to current application’s NSMutableArray
property NSRunningApplication : a reference to current application’s NSRunningApplication

property theResult : 0
property returnCode : 0
property theDataSource : {}

tell application "Numbers"
  tell front document
    tell active sheet
      try
        set theTable to first table whose class of selection range is range
      on error
        return "No Selection" –何も選択されてなかった場合
      end try
      
      
tell theTable
        set bgColList to background color of every cell of selection range
        
–> {{18572, 45937, 65452}, {18572, 45937, 65452}, {3001, 24801, 44056}, {18572, 45937, 65452}, {18572, 45937, 65452}, {64899, 33134, 31509}, {64899, 33134, 31509}, {18572, 45937, 65452}, {18572, 45937, 65452}, {3001, 24801, 44056}, {18572, 45937, 65452}, {18572, 45937, 65452}, {26149, 65534, 58650}, {26149, 65534, 58650}, {26149, 65534, 58650}, {26149, 65534, 58650}, {18572, 45937, 65452}, {18572, 45937, 65452}}
      end tell
    end tell
  end tell
end tell

set bgColList to countItemsByItsAppearance(bgColList) of me
–> {{theName:{65535, 65533, 65534}, numberOfTimes:73}, {theName:{65535, 65535, 21706}, numberOfTimes:73}, {theName:missing value, numberOfTimes:27}}

set paramObj to {mainDat:bgColList, myTitle:"色別集計", mySubTitle:"Numbers上で選択したセルの背景色の頻度集計"}
–my browseColors:paramObj–for debug

my performSelectorOnMainThread:"browseColors:" withObject:(paramObj) waitUntilDone:true

on browseColors:paramObj
  set aParamList to (mainDat of (paramObj as record)) as list
  
set winTitle to (myTitle of (paramObj as record)) as string
  
set subTitle to (mySubTitle of (paramObj as record)) as string
  
  
set aLen to length of aParamList
  
  
set aHeight to 100
  
set aWidth to 300
  
  
–NSViewをつくる
  
set aNSV to NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight * 1.5))
  
aNSV’s setNeedsDisplay:true
  
  
— NSScroll Viewをつくる
  
set aScroll to NSScrollView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
aScroll’s setDocumentView:aNSV
  
  
aNSV’s enclosingScrollView()’s setHasHorizontalScroller:true
  
aNSV’s enclosingScrollView()’s setHasVerticalScroller:true
  
  
–NSColorWell+ NSTextFieldをつくる
  
set aStep to 1
  
repeat with i in aParamList
    set aColorWell to (NSColorWell’s alloc()’s initWithFrame:(current application’s NSMakeRect(10, ((aLen – aStep + 1) * 30), 60, 20)))
    
    
set myName to (theName of i)
    
set myTimes to (numberOfTimes of i)
    
    
if myName is not equal to missing value then
      copy (myName as list) to {rNum, gNum, bNum}
      
set myTimes to numberOfTimes of i
      
      
set myColor to makeNSColorFromRGBAval(rNum, gNum, bNum, 65535, 65535) of me
      (
aColorWell’s setColor:myColor)
      (
aColorWell’s setBordered:false)
      (
aNSV’s addSubview:aColorWell)
      
      
set aTF to makeNSTextField(80, ((aLen – aStep + 1) * 30), 100, 20, false, myTimes as string, true, true) of me
      (
aNSV’s addSubview:aTF)
      
      
set aStep to aStep + 1
    end if
  end repeat
  
  
–NSScrollViewを強制的にトップにスクロール
  
set aPT to current application’s NSMakePoint(0.0, aHeight)
  
aScroll’s documentView()’s scrollPoint:aPT
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:winTitle
    
its setInformativeText:subTitle
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aScroll
  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
  
end browseColors:

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

on makeNSColorFromRGBAval(redValue as integer, greenValue as integer, blueValue as integer, alphaValue as integer, aMaxVal as integer)
  set aRedCocoa to (redValue / aMaxVal) as real
  
set aGreenCocoa to (greenValue / aMaxVal) as real
  
set aBlueCocoa to (blueValue / aMaxVal) as real
  
set aAlphaCocoa to (alphaValue / aMaxVal) as real
  
set aColor to NSColor’s colorWithCalibratedRed:aRedCocoa green:aGreenCocoa blue:aBlueCocoa alpha:aAlphaCocoa
  
return aColor
end makeNSColorFromRGBAval

–1D Listを要素別に出現回数で集計
on countItemsByItsAppearance(aList as list)
  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 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

★Click Here to Open This Script 

Posted in Color dialog list Record | Tagged 10.12savvy 10.13savvy 10.14savvy NSAlert NSColor NSColorWell NSCountedSet NSDictionary NSIndexSet NSMutableArray NSRunningApplication NSScrollView NSSortDescriptor NSTextField NSView Numbers | Leave a comment

Keynoteの各slideのtitleから目次のテキストを作成してNumbersの表を作成

Posted on 5月 20, 2019 by Takaaki Naganoya

現在オープン中の最前面のKeynote書類の各スライド(ページ)のタイトルを取得して、Numbersの新規書類上にページとタイトルの一覧表を作成するAppleScriptです。

こういうのが、一番オーソドックスで誰でも「そういうのがあったら楽なのに」と思わせるような用途でしょう。

Keynoteの書類を作成してページ数が増え、タイトル一覧をながめつつ削除したりアップデートしたりする対象を探したいような場合に、このような一覧表を作成させるとわかりやすくて便利です。

本Scriptは本当にありもののルーチンをつなげて最低限の処理を行わせたものですが、さらに手の込んだ処理を行うことも可能です。たとえば、別途Keynote書類をスライド(ページ)ごとに画像書き出ししておいて、Numbersのセル上にプレビュー画像として入れておくとか。あるいは、Keynote書類の各スライドのマスターアイテム名を見て処理を変えるとか。実にいろいろあります。

作成と動作確認はmacOS 10.14.5+Keynote 9.0.2で行っていますが、macOS 10.13/10.12でも動作するはずですしました。

AppleScript名:Keynoteの各slideのtitleから目次のテキストを作成してNumbersの表を作成
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/05/20
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

–Keynoteの各slideのタイトルを取得する
tell application "Keynote"
  tell document 1
    set aList to object text of default title item of every slide
  end tell
end tell

set aLen to (length of aList) + 1 –ヘッダー行の分を+1
set bLen to 2 –data width (columns)

–2D Listを作成する (Page, Title)
set newList to {}
set pCount to 1
repeat with i in aList
  set j to contents of i
  
set the end of newList to {pCount as string, j}
  
set pCount to pCount + 1
end repeat

–Numbersの書類を新規作成して、指定サイズの表を作成する
makeNewNumbersDocumentAndTable(aLen, bLen) of me

–作成した新規書類の表1に2D Listを入れる(ただし、100行分ぐらいを上限とする。それ以上は別途CSVを書き出してオープンさせたほうが圧倒的に高速)I
fillCurrentTable(newList) of me

on fillCurrentTable(aList)
  set aLen to length of aList
  
set aWidth to length of first item of aList
  
  
tell application "Numbers"
    tell front document
      tell active sheet
        tell table 1
          repeat with i from 1 to aLen
            tell row (i + 1)
              set aRowList to contents of item i of aList
              
repeat with ii from 1 to aWidth
                tell cell ii
                  set aTmpData to contents of item ii of aRowList
                  
ignoring application responses
                    set value to aTmpData
                  end ignoring
                end tell
              end repeat
            end tell
          end repeat
        end tell
      end tell
    end tell
  end tell
end fillCurrentTable

on makeNewNumbersDocumentAndTable(aHeight, aWidth)
  tell application "Numbers"
    make new document
    
    
tell front document
      tell active sheet
        delete every table
      end tell
    end tell
    
    
tell front document
      tell active sheet
        set tRes to make new table with properties {row count:aHeight, column count:aWidth}
        
return tRes
      end tell
    end tell
  end tell
end makeNewNumbersDocumentAndTable

★Click Here to Open This Script 

Posted in list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Keynote Numbers | Leave a comment

2D Listの行列入れ替え(transpose)

Posted on 5月 16, 2019 by Takaaki Naganoya

2D List(2次元配列)の行列入れ替えを行うAppleScriptです。

本プログラムは前の(2018.1.31に消える前の)Blogに掲載していたものを動作検証を行いつつ再掲載したもので、そもそもはShane StanleyのBridgePlus AppleScript Libraryのドキュメントに掲載されているもの、ほぼそのままです。

BridgePlusの前身であるASObjCExras.frameworkのときにこの機能を見つけて、どうしてこの機能がこの仕様になっているのか、その当時は理解できていませんでした。

2次元配列の回転だけなら、単純にデータを(画像のように)回転させるだけの処理のはずですが(→ 時計まわりに90度回すサンプル)、そういうわけでもない。なんでこんな処理をShaneが書いたのか理解できず、当時は「なーんか使えないメソッドがついてんなー」ぐらいにしか思っていませんでした。

そして、出会ってしまったわけです。この機能がバリバリに必要なデータに。そして、深く理解しました。これはShaneが説明不足すぎです。そして、「致命的に必要な機能」だったので最初からついていたわけです。

ExcelでもNumbersでもGoogle Spreadsheetでも、1レコードといったら行ごとに配置されているのが普通です。プログラマーを10人集めて、2次元配列でそういうデータを表現しろと言われたら、世界中のどこのプログラマーでもだいたい10人とも行ごとにレコードを表現すると思います。

そんな中、1レコード=1行ではなく1レコード=1列とかいうデータがやってきて、途方に暮れたすえにNumbers上で「行と列を転置」機能を利用して縦横の入れ替えを行なって、ハッと気づきました。

 「これや……このためについとったんや」

調べてみたら、ビンゴ! まさに2D Listのtransposeのための機能がBridgePlusの、

SMSForder's colsToRowsIn:① |error|:②

だったわけです。

「プログラミングの身体性」ともいうべきものがあります。実体験をもとにするとデータやオブジェクトをどのように操作すべきなのかを深く理解でき、逆に実体験がともなっていないとまったく理解できないという話であり、これがまさにそれだったのでしょう(AppleScriptってプログラミングの身体性の塊のような気も、、、、一般のプログラマーが仕様だけ読んで組もうとして挫折した話をウンザリするほど聞くもので。実際にアプリケーションを動かしてみないと理解できないことが多すぎです)。

なので、こういう「息を飲むような非常識なデータ」を前に途方に暮れないかぎり、このメソッドの有用性は理解できないと思います(自分がそうだったので)。

AppleScript名:2D Listの行列入れ替え.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/05/16
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions
use script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

set aList to {{"r0", "f1", "f2"}, {"r1", "f1r1", "f2r1"}, {"r2", "f1r2", "f2r2"}, {"r3", "f1r3", "f2r3"}}
set bList to transpose2DList(aList) of me
–> {{"r0", "r1", "r2", "r3"}, {"f1", "f1r1", "f1r2", "f1r3"}, {"f2", "f2r1", "f2r2", "f2r3"}}

on transpose2DList(aList as list)
  load framework
  
return (ASify from (current application’s SMSForder’s colsToRowsIn:aList |error|:(missing value)))
end transpose2DList

★Click Here to Open This Script 

Posted in list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Excel Numbers | Leave a comment

Numbersで指定の2つの書類のデータのdiffを取る

Posted on 4月 19, 2019 by Takaaki Naganoya

指定の2つのNumbers書類(の中の現在表示中のシートのTable 1)同士のdiffを取るAppleScriptです。

# 書類内のシート内のどの表を処理するか、という階層化された対象選択を行うのにNSOutlineViewを用いたアラートダイアログを作っておきたい気持ちでいっぱいです

バージョン違いの書類間の差分を検出してレポートします。差分の評価は行単位で行なっており、同じデータでもカラムの順番を変えてあったりすると「別物」として検出します。

ただし、Numbersから2次元配列としてデータを抽出する際にすべてAppleScriptで処理するように書き換えた(macOS 10.14対策)ルーチンを使用しているので、大規模データの処理を行わせると(データ取得処理部分は)遅くなる可能性があります。

diffの計算部分はCocoaの機能に依存した(甘えまくった)処理を行なっているため、データが大きくてもそれほど遅くなりません。

612行の旧データと610行の新データをそれぞれ取得して差分を計算するのに、開発環境でだいたい3.5秒ぐらいです。同じ環境でBridgePlusを用いて1D List–> 2D List変換を行うバージョンを試してみたら、0.83秒ぐらいでした。

AppleScript名:Numbersで指定の2つの書類のデータのdiffを取る.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/04/19
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

tell application "Numbers"
  set dList to name of every document
  
set oldDoc to contents of first item of (choose from list dList with prompt "古いデータを選択してください")
  
set newDoc to contents of first item of (choose from list dList with prompt "新しいデータを選択してください")
end tell

set oldData to get2DListFromADoc(oldDoc) of me
set newData to get2DListFromADoc(newDoc) of me

–List同士のDiffを計算する
set dRes to getDiffBetweenLists(oldData, newData) of me
–> {addItems:{{"キャッツアイ恵庭", 42.87588548, 141.5834606, "北海道 恵庭市 住吉町 2-9-1"}}, minusItems:{{"セガワールド白河", 37.11931521, 140.1944139, "福島県 白河市 新高山 1-1 メガステージ白河内"}, {"プレイアイシー", 35.3721071, 139.272272, "神奈川県 秦野市 南矢名 1-15-1"}, {"駅前スタジアムIII", 33.8395736, 132.7521903, "愛媛県 松山市 大手町 2-4-1"}}}

on get2DListFromADoc(aDocName)
  tell application "Numbers"
    tell document aDocName
      tell active sheet
        set theTable to table 1
        
        
tell theTable
          set selection range to cell range
          
          
set hcCount to header column count
          
set hrCount to header row count
          
set frCount to footer row count
          
          
set cCount to column count
          
set rCount to row count
          
          
set outList to {}
          
          
repeat with i from (hrCount + 1) to rCount
            tell row i
              set tmpList to value of cells (hcCount + 1) thru cCount
              
set the end of outList to tmpList
            end tell
          end repeat
        end tell
        
        
return outList
        
      end tell
    end tell
  end tell
end get2DListFromADoc

on getDiffBetweenLists(aArray as list, bArray as list)
  set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分を削除する
  
allSet’s minusSet:duplicateSet
  
set resArray to (allSet’s allObjects()) as list
  
  
set aSet to current application’s NSMutableSet’s setWithArray:aArray
  
set bSet to current application’s NSMutableSet’s setWithArray:resArray
  
aSet’s intersectSet:bSet –積集合
  
set addRes to aSet’s allObjects() as list
  
  
set cSet to current application’s NSMutableSet’s setWithArray:bArray
  
cSet’s intersectSet:bSet –積集合
  
set minusRes to cSet’s allObjects() as list
  
  
return {addItems:minusRes, minusItems:addRes}
end getDiffBetweenLists

★Click Here to Open This Script 

Posted in list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSMutableSet NSSet Numbers | Leave a comment

Post navigation

  • Older posts

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

Google Search

Popular Posts

  • Keynoteの最前面のドキュメントの現在のスライドに指定月の日曜日はじまりカレンダーを表で作成
  • Numbersで選択範囲のセルのデータを取得して重複データを抽出
  • 配列の指定要素を検索する(テキスト)
  • 文字列のURLエンコード、URLデコード
  • 指定フォルダに指定アイコン画像をつける v3
  • リストから選択してアイテム番号を返す
  • AppleScript上でJavaScriptを実行する
  • ディスプレイの設定切り替えをAppleScriptでも行えるSwitchResX
  • Xcode 12.2betaでIntel/ARM Universal Binaryのビルドを確認
  • AppleScriptでキースキャン
  • Numbersで選択中の表のセルの範囲を背景色で頻度集計
  • SafariでURLをローディング
  • CotEditorで編集中のMarkdown書類をPDFプレビュー
  • AppleScript disassembler
  • Safariで表示中のWebページの最終更新日時を取得
  • 【基礎】AppleScriptの実行を(操作により)中断する
  • 各種GUI要素なしでSafari上に新規ウィンドウ表示
  • NSProcessInfoでプロセスの各種情報を取得
  • Safariで表示中のURLをwebarchive保存
  • Bluetoothデバイスのバッテリー残量を取得 v3

Tags

10.11savvy (1109) 10.12savvy (1249) 10.13savvy (1384) 10.14savvy (504) 10.15savvy (295) 11.0savvy (103) CotEditor (47) Finder (43) iTunes (25) Keynote (58) NSAlert (59) NSAlertSecondButtonReturn (16) NSArray (50) NSBitmapImageRep (20) NSBundle (19) NSButton (33) NSColor (48) NSDictionary (26) NSFileManager (23) NSFont (18) NSImage (40) NSJSONSerialization (20) NSMutableArray (61) NSMutableDictionary (21) NSPredicate (36) NSRunningApplication (55) NSScreen (30) NSScrollView (22) NSString (113) NSURL (93) NSURLRequest (22) NSUTF8StringEncoding (29) NSUUID (18) NSView (33) NSWindow (17) NSWorkspace (19) Numbers (42) Pages (16) Safari (34) System Events (16) WKUserContentController (20) WKUserScript (19) WKUserScriptInjectionTimeAtDocumentEnd (17) WKWebView (21) WKWebViewConfiguration (21)

カテゴリー

  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • Bluetooth
  • boolean
  • Bug
  • Calendar
  • call by reference
  • Clipboard
  • Code Sign
  • Color
  • Custom Class
  • dialog
  • drive
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • GAME
  • geolocation
  • GUI
  • GUI Scripting
  • History
  • How To
  • Icon
  • Image
  • Input Method
  • Internet
  • JavaScript
  • JXA
  • Keychain
  • Language
  • list
  • Locale
  • Machine Learning
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • OCR
  • OSA
  • PDF
  • Peripheral
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • shell script
  • 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)
  • 未分類

アーカイブ

  • 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
Proudly powered by WordPress
Theme: Flint by Star Verte LLC