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

カテゴリー: JavaScript

アラートダイアログ上にWebViewで3Dコンテンツを表示(WebGL+three.js)v3

Posted on 3月 7 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを作成して、さまざまなグラフや3Dアニメーションを表示してきた「箱庭ダイアログ」の1つの到達点、「periodictable」(元素周期表)選択UIの表示デモAppleScriptです。

このデモ、macOS 10.14あたりまでは動いていたのですが、その後のmacOSのアップデートにより、表示されなくなっておりました。

いろいろ調べたところ、macOSの開発者もiOSの開発者も揃いも揃って「表示できない」と言っているのを見て、逆に何か解決策がありそうな気がしてきました。

ローカルに保存しておいた1枚ものの表示用HTML(2020/05に作成したもの)は、当時のSafariで表示できており、WkWebViewでも表示できていました。

現在、この1枚もののHTMLはSafariでもWkWebViewでも表示できないようになっています。
その一方で、three.jsのWebサイトに掲載されているperiodictableのサンプルは現行のSafariで表示でき、操作も行えます。

当初は、これを「SafariとWkWebViewの差」だと思って、WkWebViewをカスタマイズしまくらないとSafariと同等の表示が行えないのではないか? と考えていました。ただ、探しても探しても答えが見つからず、この方向で情報収集を行っても「無駄」に思えてきました。

そこでにわかに浮上してきたのが、「periodictable」や「three.js」自体がアップデートされている説、です。

WebKit(WkWebView)側のアップデート、およびCDN上のJavaScriptのライブラリのアップデートの相互作用によって表示できなくなったのではないかと、調査の方向を変えてみました。

当時のサンプルHTMLと現在のサンプルHTMLのdiffをとって、読み込むCDN上のライブラリを変更したり、追加することで現行OS上のWkWebView上でも動作するようになりました。

つまり、文字列として与えているHTMLの部分のみ変更しただけで、AppleScript部分とかWkWebViewまわりは一切手をつけていません。わかってしまえば、「なーんだ」という内容ですが、これにはなかなか対応できませんでした。

あとは、クリックした項目のURLイベントをAppleScript側で受信できればなおよいのですが、、、アプリケーションとして独立したものに変更して、AppleScript用語辞書を介して「display periodictable」みたいなコマンドでAppleScript側と値をやりとりするのがよいのかもしれません。

AppleScript名:アラートダイアログ上にWebViewで3Dコンテンツを表示(WebGL+three.js)v3.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/06/13
–  Modified on: 2023/03/07
—
–  Copyright © 2020-2023 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.7"
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

–https://www.cresco.co.jp/blog/entry/7427/
— By sgi-chang @ UX Design Center
set myStr to "<!DOCTYPE html>
<html>

<head>
<title>three.js css3d – cresco xmas inspired by periodic table</title>
<meta charset=\"utf-8\">
<meta name=\"viewport\" content=\"width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0\">
<link type=\"text/css\" rel=\"stylesheet\" href=\"https://threejs.org/examples/main.css\">
<style>
a {
color: #8ff;
}

#menu {
position: absolute;
bottom: 20px;
width: 100%;
text-align: center;
}

.element {
width: 120px;
height: 160px;
box-shadow: 0px 0px 12px rgba(0, 255, 255, 0.5);
border: 1px solid rgba(127, 255, 255, 0.25);
font-family: Helvetica, sans-serif;
text-align: center;
line-height: normal;
cursor: default;
}

.element:hover {
box-shadow: 0px 0px 12px rgba(0, 255, 255, 0.75);
border: 1px solid rgba(127, 255, 255, 0.75);
}

.element .number {
position: absolute;
top: 20px;
right: 20px;
font-size: 12px;
color: rgba(127, 255, 255, 0.75);
}

.element .symbol {
position: absolute;
top: 40px;
left: 0px;
right: 0px;
font-size: 60px;
font-weight: bold;
color: rgba(255, 255, 255, 0.75);
text-shadow: 0 0 10px rgba(0, 255, 255, 0.95);
}

.element .details {
position: absolute;
bottom: 15px;
left: 0px;
right: 0px;
font-size: 12px;
color: rgba(127, 255, 255, 0.75);
}

button {
color: rgba(127, 255, 255, 0.75);
background: transparent;
outline: 1px solid rgba(127, 255, 255, 0.75);
border: 0px;
padding: 5px 10px;
cursor: pointer;
}

button:hover {
background-color: rgba(0, 255, 255, 0.5);
}

button:active {
color: #000000;
background-color: rgba(0, 255, 255, 0.75);
}
</style>
</head>

<body>
<script src=\"https://threejs.org/examples/jsm/libs/tween.module.min.js\"></script>
<script src=\"https://threejs.org/examples/jsm/controls/TrackballControls.js\"></script>
<script src=\"https://threejs.org/examples/jsm/renderers/CSS3DRenderer.js\"></script>

<div id=\"info\"><a href=\"http://piyocast.com/as\" target=\"_blank\">AppleScript 3D UI Demonstration</a> By Piyomaru Software</div>
<div id=\"container\"></div>
<div id=\"menu\">
<button id=\"table\">TABLE</button>
<button id=\"sphere\">SPHERE</button>
<button id=\"helix\">HELIX</button>
<button id=\"grid\">GRID</button>
</div>

    <!– Import maps polyfill –>
    <!– Remove this when import maps will be widely supported –>
    <script async src=\"https://unpkg.com/es-module-shims@1.5.8/dist/es-module-shims.js\"></script>

    <script type=\"importmap\">
      {
        \"imports\": {
          \"three\": \"https://unpkg.com/three@0.142.0/build/three.module.js\",
          \"OrbitControls\": \"https://unpkg.com/three@0.142.0/examples/jsm/controls/OrbitControls.js\"
        }
      }
    </script>
    
<script type=\"module\">
import * as THREE from ’https://threejs.org/build/three.module.js’;
import { TWEEN } from ’https://threejs.org/examples/jsm/libs/tween.module.min.js’;
import { TrackballControls } from ’https://threejs.org/examples/jsm/controls/TrackballControls.js’;
import { CSS3DRenderer, CSS3DObject } from ’https://threejs.org/examples/jsm/renderers/CSS3DRenderer.js’;
    
var table = [
\"1\", \"Hydrogen\", \"1.00794\", 1, 1,
\"2\", \"Helium\", \"4.002602\", 1, 2,
\"3\", \"Lithium\", \"6.941\", 1, 3,
\"4\", \"Beryllium\", \"9.012182\", 1, 4,
\"5\", \"Boron\", \"10.811\", 1, 5,
\"6\", \"Carbon\", \"12.0107\", 2, 1,
\"7\", \"Nitrogen\", \"14.0067\", 2, 3,
\"8\", \"Oxygen\", \"15.9994\", 3, 1,
\"9\", \"Fluorine\", \"18.9984032\", 3, 3,
\"101\", \"Saturday\", \"July\", 4, 2,
\"I\", \"Moscovium\", \"(290)\", 6, 1,
\"I\", \"Livermorium\", \"(293)\", 6, 2,
\"I\", \"Tennessine\", \"(294)\", 6, 3,
\"I\", \"Titanium\", \"47.867\", 6, 4,
\"I\", \"Vanadium\", \"50.9415\", 6, 5,
\"Y\", \"Chromium\", \"51.9961\", 8, 1,
\"Y\", \"Manganese\", \"54.938045\", 9, 2,
\"Y\", \"Iron\", \"55.845\", 10, 3,
\"Y\", \"Cobalt\", \"58.933195\", 10, 4,
\"Y\", \"Nickel\", \"58.6934\", 10, 5,
\"Y\", \"Copper\", \"63.546\", 11, 2,
\"Y\", \"Zinc\", \"65.38\", 12, 1,
\"O\", \"Gallium\", \"69.723\", 14, 1,
\"O\", \"Copernicium\", \"(285)\", 14, 2,
\"O\", \"Nihonium\", \"(286)\", 14, 3,
\"O\", \"Oganesson\", \"(294)\", 14, 4,
\"O\", \"Neon\", \"20.1797\", 14, 5,
\"O\", \"Sodium\", \"22.98976…\", 15, 1,
\"O\", \"Magnesium\", \"24.305\", 15, 5,
\"O\", \"Aluminium\", \"26.9815386\", 16, 1,
\"O\", \"Silicon\", \"28.0855\", 16, 5,
\"O\", \"Phosphorus\", \"30.973762\", 17, 1,
\"O\", \"Sulfur\", \"32.065\", 17, 2,
\"O\", \"Chlorine\", \"35.453\", 17, 3,
\"O\", \"Argon\", \"39.948\", 17, 4,
\"O\", \"Potassium\", \"39.948\", 17, 5,
\"M\", \"Calcium\", \"40.078\", 1, 7,
\"M\", \"Scandium\", \"44.955912\", 1, 8,
\"M\", \"Roentgenium\", \"(280)\", 1, 9,
\"M\", \"Germanium\", \"72.63\", 1, 10,
\"M\", \"Lead\", \"207.2\", 1, 11,      
\"M\", \"Arsenic\", \"74.9216\", 2, 8,
\"M\", \"Selenium\", \"78.96\", 3, 9,
\"M\", \"Bromine\", \"79.904\", 3, 10,
\"M\", \"Krypton\", \"83.798\", 4, 8,
\"M\", \"Rubidium\", \"85.4678\", 5, 7,
\"M\", \"Strontium\", \"87.62\", 5, 8,
\"M\", \"Yttrium\", \"88.90585\", 5, 9,
\"M\", \"Zirconium\", \"91.224\", 5, 10,
\"M\", \"Niobium\", \"92.90628\", 5, 11,
\"A\", \"Molybdenum\", \"95.96\", 7,8,
\"A\", \"Technetium\", \"(98)\", 7, 9,
\"A\", \"Ruthenium\", \"101.07\", 7, 10,
\"A\", \"Rhodium\", \"102.9055\",7, 11,
\"A\", \"Palladium\", \"106.42\", 8, 7,
\"A\", \"Silver\", \"107.8682\", 8,9,
\"A\", \"Cadmium\", \"112.411\", 9, 7,
\"A\", \"Indium\", \"114.818\", 9, 9,
\"A\", \"Tin\", \"118.71\", 10, 8,
\"A\", \"Antimony\", \"121.76\", 10, 9,
\"A\", \"Gadolinium\", \"157.25\", 10, 10,
\"A\", \"Terbium\", \"158.92535\", 10, 11,
\"R\", \"Dysprosium\", \"162.5\", 12, 7,
\"R\", \"Holmium\", \"164.93032\", 12, 8,
\"R\", \"Erbium\", \"167.259\", 12, 9,
\"R\", \"Thulium\", \"168.93421\", 12, 10,
\"R\", \"Ytterbium\", \"173.054\", 12, 11,
\"R\", \"Lutetium\", \"174.9668\", 13, 7,
\"R\", \"Hafnium\", \"178.49\", 13, 9,
\"R\", \"Samarium\", \"150.36\", 14, 7,
\"R\", \"Europium\", \"151.964\", 14, 9,
\"R\", \"Tantalum\", \"180.94788\", 15, 8,
\"R\", \"Tungsten\", \"183.84\", 15, 10,
\"R\", \"Rhenium\", \"186.207\", 15, 11,
\"U\", \"Osmium\", \"190.23\", 17, 7,
\"U\", \"Iridium\", \"192.217\", 17,8,
\"U\", \"Platinum\", \"195.084\", 17, 9,
\"U\", \"Gold\", \"196.966569\", 17, 10,
\"U\", \"Mercury\", \"200.59\", 18, 11,
\"U\", \"Thallium\", \"204.3833\", 19, 11,
\"U\", \"Bismuth\", \"208.9804\", 20, 7,
\"U\", \"Polonium\", \"(209)\", 20, 8,
\"U\", \"Astatine\", \"(210)\", 20, 9,
\"U\", \"Francium\", \"(223)\", 20, 10,
\"U\", \"Radium\", \"(226)\", 22, 9,
\"U\", \"Actinium\", \"(227)\", 22, 10,
\"U\", \"Thorium\", \"232.03806\", 22, 11,
\"A\", \"Protactinium\", \"231.0588\", 22, 7,
\"A\", \"Uranium\", \"238.02891\", 23, 9,
\"A\", \"Neptunium\", \"(237)\", 23, 8,
\"A\", \"Plutonium\", \"(244)\", 23, 9,
\"A\", \"Americium\", \"(243)\", 23, 10,
\"A\", \"Curium\", \"(247)\", 23, 11,
\"S\", \"Berkelium\", \"(247)\", 24, 7,
\"S\", \"Californium\", \"(251)\", 24, 8,
\"S\", \"Einstenium\", \"(252)\", 24, 9,
\"S\", \"Fermium\", \"(257)\", 24, 11,
\"S\", \"Mendelevium\", \"(258)\", 25, 7,
\"S\", \"Nobelium\", \"(259)\", 25, 9,
\"S\", \"Lawrencium\", \"(262)\", 25, 11,
\"S\", \"Rutherfordium\", \"(267)\", 26, 7,
\"S\", \"Dubnium\", \"(268)\", 26, 9,
\"S\", \"Seaborgium\", \"(271)\", 26, 10,
\"S\", \"Bohrium\", \"(272)\", 26, 11,
\"A\", \"Hassium\", \"(270)\", 27, 8,
\"B\", \"Meitnerium\", \"(276)\", 27, 9,
\"C\", \"Darmstadium\", \"(281)\", 27, 8,
\"D\", \"Tellurium\", \"127.6\", 27, 9,
\"E\", \"Iodine\", \"126.90447\", 27, 10,
\"F\", \"Xenon\", \"131.293\", 28, 9,
\"G\", \"Caesium\", \"132.9054\", 28, 10,
\"H\", \"Barium\", \"132.9054\", 28, 11,
\"I\", \"Lanthanum\", \"138.90547\", 29, 8,
\"J\", \"Cerium\", \"140.116\", 29, 9,
\"K\", \"Praseodymium\", \"140.90765\", 29, 10,
\"L\", \"Neodymium\", \"144.242\", 29, 8,
\"M\", \"Promethium\", \"(145)\", 29, 9,
  \"PS\", \"Piyomaru Software\", \"(PiyoPiyo)\", 29, 10,  
  \"AS\", \"AppleScript\", \"(osalang)\", 29, 11,  
];

var camera, scene, renderer;
var controls;
var objects = [];
var targets = { table: [], sphere: [], helix: [], grid: [] };
init();
animate();
    
function init() {
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 3000;
scene = new THREE.Scene();
      
// table
for (var i = 0; i < table.length; i += 5) {
      
var element = document.createElement(’div’);
element.className = ’element’;

     //element.style.backgroundColor = ’rgba(128,0,64,’ + ( Math.random() * 0.5 + 0.25 ) + ’)’;
    //element.style.backgroundColor = ’rgba(64,0,128,’ + ( Math.random() * 0.5 + 0.25 ) + ’)’;
//element.style.backgroundColor = ’rgba(0,0,0,’ + ( Math.random() * 0.5 + 0.25 ) + ’)’;
element.style.backgroundColor = ’rgba(0,127,127,’ + ( Math.random() * 0.5 + 0.25 ) + ’)’;
//element.style.backgroundColor = ’rgba(18,77,174,’ + (Math.random() * 0.5 + 0.25) + ’)’;

var number = document.createElement(’div’);
number.className = ’number’;
number.textContent = (i / 5) + 1;
element.appendChild(number);
var symbol = document.createElement(’div’);
symbol.className = ’symbol’;
symbol.textContent = table[i];
element.appendChild(symbol);
var details = document.createElement(’div’);
details.className = ’details’;
details.innerHTML = table[i + 1] + ’<br>’ + table[i + 2];
element.appendChild(details);
var object = new CSS3DObject(element);
object.position.x = Math.random() * 4000 – 2000;
object.position.y = Math.random() * 4000 – 2000;
object.position.z = Math.random() * 4000 – 2000;
scene.add(object);
objects.push(object);
//
var object = new THREE.Object3D();
object.position.x = (table[i + 3] * 140) – 1330;
object.position.y = – (table[i + 4] * 180) + 990;
targets.table.push(object);
}
      
// sphere
var vector = new THREE.Vector3();
for (var i = 0, l = objects.length; i < l; i++) {
var phi = Math.acos(- 1 + (2 * i) / l);
var theta = Math.sqrt(l * Math.PI) * phi;
var object = new THREE.Object3D();
object.position.setFromSphericalCoords(800, phi, theta);
vector.copy(object.position).multiplyScalar(2);
object.lookAt(vector);
targets.sphere.push(object);
}
      
// helix
var vector = new THREE.Vector3();
for (var i = 0, l = objects.length; i < l; i++) {
var theta = i * 0.175 + Math.PI;
var y = – (i * 8) + 450;
var object = new THREE.Object3D();
object.position.setFromCylindricalCoords(900, theta, y);
vector.x = object.position.x * 2;
vector.y = object.position.y;
vector.z = object.position.z * 2;
object.lookAt(vector);
targets.helix.push(object);
}
      
// grid
for (var i = 0; i < objects.length; i++) {
var object = new THREE.Object3D();
object.position.x = ((i % 5) * 400) – 800;
object.position.y = (- (Math.floor(i / 5) % 5) * 400) + 800;
object.position.z = (Math.floor(i / 25)) * 1000 – 2000;
targets.grid.push(object);
}
      
//
renderer = new CSS3DRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.getElementById(’container’).appendChild(renderer.domElement);
      
//
controls = new TrackballControls(camera, renderer.domElement);
controls.minDistance = 500;
controls.maxDistance = 6000;
controls.addEventListener(’change’, render);
      
var button = document.getElementById(’table’);
button.addEventListener(’click’, function () {
transform(targets.table, 2000);
}, false);
      
var button = document.getElementById(’sphere’);
button.addEventListener(’click’, function () {
transform(targets.sphere, 2000);
}, false);
      
var button = document.getElementById(’helix’);
button.addEventListener(’click’, function () {
transform(targets.helix, 2000);
}, false);
      
var button = document.getElementById(’grid’);
button.addEventListener(’click’, function () {
transform(targets.grid, 2000);
}, false);
      
transform(targets.table, 2000);
//
window.addEventListener(’resize’, onWindowResize, false);
}
    
function transform(targets, duration) {
TWEEN.removeAll();
for (var i = 0; i < objects.length; i++) {
var object = objects[i];
var target = targets[i];
new TWEEN.Tween(object.position)
.to({ x: target.position.x, y: target.position.y, z: target.position.z }, Math.random() * duration + duration)
.easing(TWEEN.Easing.Exponential.InOut)
.start();
new TWEEN.Tween(object.rotation)
.to({ x: target.rotation.x, y: target.rotation.y, z: target.rotation.z }, Math.random() * duration + duration)
.easing(TWEEN.Easing.Exponential.InOut)
.start();
}
new TWEEN.Tween(this)
.to({}, duration * 2)
.onUpdate(render)
.start();
}
    
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
render();
}
    
function animate() {
requestAnimationFrame(animate);
TWEEN.update();
controls.update();
}
    
function render() {
renderer.render(scene, camera);
}
</script>
</body>

</html>"

set paramObj to {myMessage:"WebGL & three.js Test", mySubMessage:"This is a WebGL UI using three.js", 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 1600
  
set aHeight to 900
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script src", "</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 

(Visited 60 times, 2 visits today)
Posted in 3D dialog JavaScript | Tagged 12.0savvy 13.0savvy WKWebView | 1 Comment

LAN上の別のMacでYouTubeムービー再生をハンズオーバー v2

Posted on 10月 8, 2020 by Takaaki Naganoya

Safariの最前面のウィンドウで再生中のYouTubeムービーの情報を取得し、LAN上の別のMacで再生を引き継ぐ(ハンズオーバーする)AppleScriptです。

macOS 10.13以降、リモートAppleEvents経由でGUIアプリケーションを直接操作する機能が復活しました(Mac OS X 10.7〜10.12ぐらいまでAppleScriptアプレット間のみリモート通信が許可されていた状態)。

メインマシンで再生中のYouTubeムービーを、LAN上の他のマシンに引き継がせてみました。再生を引き継がれる方のマシンでは、システム環境設定の「共有」で「リモートApple Events」の項目をオンにしています(自分のマシンではすべてこの項目をオンにしています)。

(1)リモートマシン上のユーザーのパスワード

AppleScript書類のコメント(Finderコメント)にパスワードを書いておくと、それを読み取って使用するようにしてみました。

(2)リモートマシン上のSafariの起動

リモートマシン上のアプリケーションの操作は、ただリモートマシン上のアプリケーションを指定すればOKなのですが、操作対象のアプリケーションが起動していない場合にはエラーになります。これは、とても困る仕様です。

そこで、リモートマシンのFinder経由でアプリケーションファイルをオープンすることで、リモートマシン上でSafariを起動します。オープン対象をapplication file “Safari”と指定するとエラーになりますが、application file id “com.apple.Safari”と指定するとエラーになりません。

(3)YouTubeで再生中の情報取得

以前調査しておいた内容をそのまま使っています。再生中ならPauseし、再生中の位置(時間)情報を取得し、文字列で指定するために加工してYouTubeのURLに追加しています。URLの加工部分は少々手抜きをしています。

とくに問題なく、メインマシンから他のマシン(macOS 10.15.7/macOS 11.0beta9)にLAN経由で再生をハンズオーバーできました。

実際に、コントロール先のマシン名(Bonjour名)をremoteMachineNameに、ユーザー名をremoteUserNameに、パスワードを実行するAppleScript書類のFinderコメントに書き込んで実行してください。スクリプトエディタ上でもスクリプトメニューからでも問題なく実行できています。

あとは、Safari上のYouTube再生をフルスクリーンで行えるとよいのですが、少し試した範囲ではできなかったので、また地道に調べておく感じでしょうか。

AppleScript名:LAN上の別のMacでYouTubeムービー再生をハンズオーバー v2.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/10/08
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

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

property |NSURL| : a reference to current application’s |NSURL|
property NSMetadataItem : a reference to current application’s NSMetadataItem

set remoteMachineName to "MacMini2014.local"
set remoteUserName to "maro"

–ScriptのCommentに書いておいたパスワードを拾って使う
set mePath to (path to me)

–FinderからCommentは拾えるが、メタデータ経由で取得する処理も試してみた
set remoteUserPass to getFinderComment(POSIX path of mePath) of me

tell application "Safari"
  if running then
    tell front document
      set aURL to URL
      
–最前面のウィンドウがYouTubeの場合のみ処理
      
if aURL does not start with "https://www.youtube.com/" then
        display notification "エラー: YouTubeを再生していないため、ハンズオーバーしませんでした"
        
return
      end if
      
      
–再生中のポジションを取得
      
set tRes to (do JavaScript "document.querySelector(’#movie_player video’).currentTime;")
      
      
–再生状況を取得
      
set pRes to (do JavaScript "document.querySelector(’#movie_player video’).paused;")
      
      
if pRes = false then
        –再生中であればPauseする
        
set aRes to (do JavaScript "document.querySelector(’#movie_player .ytp-play-button’).click();")
      end if
      
      
openYouTubeOnRemoteMachine(remoteUserName, remoteUserPass, remoteMachineName, tRes, aURL) of me
    end tell
  end if
end tell

–指定のリモートマシン上のSafariでYouTubeの指定ムービーの指定箇所からの再生を行う
on openYouTubeOnRemoteMachine(remoteUser, remotePass, remoteMachineLocal, newDuration, newURL)
  set remoteMachineName to "eppc://" & remoteUser & ":" & remotePass & "@" & remoteMachineLocal
  
  
–URLの加工。ちょっと手抜きをした
  
if newDuration is not 0 then
    set tText to retTimeText(newDuration) of me
    
if newURL contains "&" then
      set sepChar to "?"
    else
      set sepChar to "&"
    end if
    
    
set newURL to newURL & sepChar & "t=" & tText
  end if
  
  
using terms from application "Safari"
    tell application "Safari" of machine remoteMachineName
      if not running then
        –起動していなかったらあらためてSafariを起動
        
launchRemoteSafari(remoteMachineName) of me
      end if
      
      
try
        close every document
      end try
      
      
set aWin to make new document
      
      
tell aWin
        set URL to newURL
        
–フルスクリーン再生をためしてみたが、こういう書き方ではなかった模様(URLオープンを待つ必要もある)
        
–set aRes to (do JavaScript "document.querySelector(’#movie_player playFullscreen’).click();")
      end tell
      
    end tell
  end using terms from
end openYouTubeOnRemoteMachine

–リモートマシン上でSafariを起動する
on launchRemoteSafari(aMachine)
  using terms from application "Finder"
    tell application "Finder" of machine aMachine
      open application file id "com.apple.Safari"
    end tell
  end using terms from
end launchRemoteSafari

–数値を「h」「m」「s」でフォーマットして返す
on retTimeText(aTime)
  set aHour to aTime div 3600
  
set aMinute to (aTime – (aHour * 3600)) div 60
  
set aSeconds to (aTime mod 60)
  
  
set aString to ""
  
  
if aHour > 0 then
    set aString to aHour & "h"
  end if
  
  
if aMinute > 0 then
    set aString to aString & (aMinute as integer) & "m"
  end if
  
  
if aSeconds > 0 then
    set aString to aString & (aSeconds as integer as string) & "s"
  end if
  
  
return (aString as string)
end retTimeText

–Finderコメントをメタデータ経由で取得
on getFinderComment(aPOSIX)
  set aURL to |NSURL|’s fileURLWithPath:aPOSIX
  
set aMetaInfo to NSMetadataItem’s alloc()’s initWithURL:aURL
  
set metaDict to (aMetaInfo’s valuesForAttributes:{"kMDItemFinderComment"}) as record
  
if metaDict = {} then return ""
  
set aComment to kMDItemFinderComment of (metaDict)
  
return aComment
end getFinderComment

★Click Here to Open This Script 

(Visited 103 times, 1 visits today)
Posted in Internet JavaScript Remote Control | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy Finder NSMetadataItem NSURL Safari | 14 Comments

アラートダイアログでMarkdownをプレビュー v2

Posted on 8月 8, 2020 by Takaaki Naganoya

edama2さんから投稿していただいた、Markdown書類をダイアログ上でプレビューするScriptの第二弾です。

–> Download Script Bundle

WKWebViewではなくNSAttributedStringを使ってMarkdownを表示しています。
NSAttributedStringでhtmlが表示できるとわかってWKWebViewの代わりになるかな?と思ったんですが、javascriptは使えないので自前で実行し、NSAttributedStringに<hr>に相当するものがないのとWKWebViewとは描画結果が違うので、プレビューとして使うのはイマイチです。作っておいてなんですが…😢

本Scriptの見どころは2点。「Scriptバンドル内にJavaScriptのライブラリを突っ込んで呼び出しているところ」と、「Markdownを(HTML経由で)NSAttributedStringに変換してプレビューしている」ところです。

ひかえめな説明文とは裏腹に、ずいぶんと攻めているというか、野心的な実装です。

JavaScriptのライブラリをローカルに置く案についてはいろいろedama2さんと意見交換をしていたんですが、割とさらっと書いているところにショックを受けます。これだけでも、相当に試行錯誤が必要な内容なんですが、このレベルに追いつくためには相当の苦労が、、、

AppleScript名:アラートダイアログでMarkdownをプレビュー v2
use AppleScript
use framework "Foundation"
use scripting additions

on run
  my main()
end run

on main()
  set mes to "Markdownファイルを選択してください。"
  
set chooseItems to choose file of type {"net.daringfireball.markdown"} with prompt mes
  
  
#
  
set aScreen to current application’s NSScreen’s mainScreen()
  
set screenFrame to aScreen’s frame()
  
set aHeight to current application’s NSHeight(screenFrame)
  
set aWidth to current application’s NSWidth(screenFrame)
  
set aHeight to aHeight * 0.845
  
set aWidth to aWidth * 0.94 / 2
  
  
set paramObj to {}
  
set paramObj to paramObj & {myMessage:"Markdown preview"}
  
set paramObj to paramObj & {mySubMessage:"file : " & chooseItems’s POSIX path}
  
set paramObj to paramObj & {mdFile:chooseItems}
  
set paramObj to paramObj & {viewWidth:aWidth}
  
set paramObj to paramObj & {viewHeight:aHeight}
  
  
my performSelectorOnMainThread:"displayMarkdownPreview:" withObject:(paramObj) waitUntilDone:true
end main

# Markdownをダイアログで表示
on displayMarkdownPreview:paramObj
  set mesText to myMessage of paramObj as text
  
set infoText to mySubMessage of paramObj as text
  
set mdFile to (mdFile of paramObj) as alias
  
set viewWidth to (viewWidth of paramObj) as integer
  
set viewHeight to (viewHeight of paramObj) as integer
  
  
## MDを読み込む
  
set mdStr to (read mdFile as «class utf8») as text
  
  
## javascriptを読み込む
  
set mePath to path to me
  
set resPath to (mePath & "Contents:Resources:marked.min.js") as text
  
set jsStr to (read (resPath as alias) as «class utf8») as text
  
  
## javascriptでMarkdownをhtmlに変換
  
tell current application’s JSContext’s new()
    evaluateScript_(jsStr)
    
tell objectForKeyedSubscript_("marked")
      tell callWithArguments_({mdStr})
        set resultStr to toString()
      end tell
    end tell
  end tell
  
  
## HTMLを読み込む
  
set mePath to path to me
  
set resPath to (mePath & "Contents:Resources:index.html") as text
  
set htmlStr to (read (resPath as alias) as «class utf8») as text
  
  
## html内の文字を置き換え
  
set aString to current application’s NSString’s stringWithFormat_(htmlStr, resultStr) as text
  
log result
  
  
  
## NSAttributedString
  
set aString to current application’s NSString’s stringWithString:aString
  
set stringData to aString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
  
set aValue to {current application’s NSHTMLTextDocumentType, current application’s NSUTF8StringEncoding}
  
set aKey to {current application’s NSDocumentTypeDocumentAttribute, current application’s NSCharacterEncodingDocumentAttribute}
  
set aOption to current application’s NSDictionary’s dictionaryWithObjects:aValue forKeys:aKey
  
  
tell current application’s NSAttributedString’s alloc()
    tell initWithHTML_options_documentAttributes_(stringData, aOption, missing value)
      set attributedString to it
    end tell
  end tell
  
log result
  
  
# Create a TextView with Scroll View
  
set frameSize to current application’s NSMakeRect(0, 0, viewWidth, viewHeight)
  
tell current application’s NSTextView’s alloc()
    tell initWithFrame_(frameSize)
      setEditable_(false)
      
tell textStorage()
        appendAttributedString_(attributedString)
      end tell
      
set aView to it
    end tell
  end tell
  
tell current application’s NSScrollView’s alloc()
    tell initWithFrame_(frameSize)
      setDocumentView_(aView)
      
set theView to it
    end tell
  end tell
  
  
  
## アイコンの指定
  
set aImage to current application’s NSWorkspace’s sharedWorkspace()’s iconForFileType:"net.daringfireball.markdown"
  
  
## set up alert
  
tell current application’s NSAlert’s new()
    addButtonWithTitle_("Close")
    
setAccessoryView_(theView)
    
setIcon_(aImage)
    
setInformativeText_(infoText)
    
setMessageText_(mesText)
    
tell |window|()
      setInitialFirstResponder_(theView)
    end tell
    
### show alert in modal loop
    
if runModal() is (current application’s NSAlertSecondButtonReturn) then return
  end tell
end displayMarkdownPreview:

★Click Here to Open This Script 

そして、本Scriptをよくよく見回してみると、NSAttributedStringになっているのでPDFに変換するのがとても簡単でした。WkWebView上に表示したWebコンテンツをPDF化しようと試みているものの、うまくできていません。Blocks構文を必要とする機能であるため(なんでこんなものまでBlocks(非同期実行)必要なんだろ?)、AppleScriptからの呼び出しができないためです。Xcode上で他の言語をまじえて組めば不可能ではない気もしますが……

CSSがWeb表示用のものなので、PDF出力時には割とゆったり目で密度の低いレイアウトになってしまうものの、このCSS指定を別のものにできればけっこうMarkdown→PDFの変換を行う部品として使えるレベルになってくるのではないでしょうか。それはそれで、Scriptバンドル内に入れたCSSを指定するとか、Web上のどこかに印刷用のCSSをホスティングしておくなどの方法が必要になることでしょう。

(Visited 80 times, 1 visits today)
Posted in dialog JavaScript Markdown | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy JSContext NSAlert NSAlertSecondButtonReturn NSAttributedString NSCharacterEncodingDocumentAttribute NSDictionary NSDocumentTypeDocumentAttribute NSScreen NSScrollView NSString NSTextView NSUTF8StringEncoding NSWorkspace | Leave a comment

アラートダイアログでMarkdownをプレビュー

Posted on 7月 29, 2020 by Takaaki Naganoya

edama2さんからの投稿です。実際に動かして「こんな素朴な記述でMarkdownのプレビューができるのか?!」とぶっ飛びましたが、箱庭グラフ表示シリーズ(JavaScriptのライブラリに描画丸投げ)と同様、外部のJavaScriptライブラリを呼んで表示しています。

→ Download archive

タイトルは「アラートダイアログでMarkdownをプレビュー」
アラートダイアログ上でMarkdownのプレビュー表示をします
中身はhtml内のjavascriptで変換してWkWebViewで表示しているだけなので今更目新しいこともありません
一応うまく動いていると思いますが、いろんなパターンを試したわけじゃないのでちょっと不安です

技術的に見所が多すぎて困るぐらいの内容です。ちょろっと流せるぐらいの規模ではありません。

JavaScriptのライブラリでMarkdownのプレビューが行えるというのは、割と盲点でした。グラフやらアニメーションやらはさんざんJavaScriptを呼び出して表示させていましたが、Markdownのプレビューまで行えるとは。

主に、Markdownのレンダリング系のフレームワークとか、AppleがXcodeに添付したMarkdownのプレビュー機能あたりが活用できないか調べていたことはありましたが、CDN上のJavaScriptを呼び出してプレビューというのはなかなか強力です。

さらに、本Scriptはblocks構文が必要なAPIに対してパラメータにmissing valueを指定することで呼び出せています。

blocks構文のパラメータにヌル文字やmissing valueを指定することで誤魔化せるケースがあることはedama2さんと話して知っていましたが、実例として提示されたのはこれがはじめてでしょう(macscripter.netでも見かけない)。

また、箱庭WebViewダイアログ系のプログラムが「スクリプトエディタ上から実行すると、実行後にウィンドウのオブジェクトがメモリ上に残ったままになる」という問題を抱えていた点を解決……はできていないですね。Appletで動かせば解決できるのと、親プロセス(スクリプトエディタやScript Debugger)が終了するとまとめて消えるので、その方向でなんとか対処を。


▲添付のサンプルMarkdown書類をプレビューしたところ。表のレンダリングができている点に驚き


▲実際に書籍用にメンテナンスしているMarkdown書類をプレビュー。applescript://のURLリンクも有効。インラインHTMLの類いも使える


▲箱庭Webダイアログの負の遺産、実行するたびにたまるゴミプロセス。これで解消なるか?!→それは無理でした

ちなみに、CotEditorのスクリプトメニューに組み込んで実行してみましたが、ネットワークへのアクセスが必要なためCotEditor側のセキュリティポリシーと合わずに実行できませんでした。 → できました。WebKitをuseし忘れていただけのようです(CDN上のライブラリで円グラフ表示できているので、逆にできないのがおかしいと気づきました)。

macOS標準装備のスクリプトメニュー内から、Applet形式に書き出したAppleScriptを呼び出すスタイルにしたら実行できました。

AppleScript名:アラートダイアログでMarkdownをプレビュー
use AppleScript
use framework “Foundation”
use scripting additions

on run
  my main()
end run


on main()
  set mes to “Markdownファイルを選択してください。”
set chooseItems to choose file of type {“net.daringfireball.markdown”} with prompt mes


  #
set aScreen to current application’s NSScreen’s mainScreen()
set screenFrame to aScreen’s frame()
set aHeight to current application’s NSHeight(screenFrame)
set aWidth to current application’s NSWidth(screenFrame)
set aHeight to aHeight * 0.845
set aWidth to aWidth * 0.94 / 2


  set paramObj to {}
set paramObj to paramObj & {myMessage:“Markdown preview”}
set paramObj to paramObj & {mySubMessage:“file : “ & chooseItems’s POSIX path}
set paramObj to paramObj & {mdFile:chooseItems}
set paramObj to paramObj & {viewWidth:aWidth}
set paramObj to paramObj & {viewHeight:aHeight}


  my performSelectorOnMainThread:“displayMarkdownPreview:” withObject:(paramObj) waitUntilDone:true
end main


# Markdownをダイアログで表示
on displayMarkdownPreview:paramObj
  set mesText to myMessage of paramObj as text
set infoText to mySubMessage of paramObj as text
set mdFile to (mdFile of paramObj) as alias
set viewWidth to (viewWidth of paramObj) as integer
set viewHeight to (viewHeight of paramObj) as integer


  ## HTMLを読み込む
set mePath to path to me
set resPath to (mePath & “Contents:Resources:index.html”) as text
set htmlStr to (read (resPath as alias) as «class utf8») as text


  ## MDを読み込む
set mdStr to (read mdFile as «class utf8») as text


  ## MD内に改行があるとうまく読み込まれないので改行を置き換え
set mdStr to current application’s NSString’s stringWithString:mdStr
set mdStr to mdStr’s stringByReplacingOccurrencesOfString:(linefeed) withString:“\\n”
set mdStr to mdStr’s stringByReplacingOccurrencesOfString:“’” withString:“\\’”


  ## html内の文字を置き換え
set aString to current application’s NSString’s stringWithFormat_(htmlStr, mdStr) as text
log result


  ## baseURL
set aPath to mdFile’s POSIX path
set baseURL to current application’s NSURL’s fileURLWithPath:aPath
set baseURL to baseURL’s URLByDeletingLastPathComponent()


  ##
set aConf to current application’s WKWebViewConfiguration’s new()
tell current application’s WKUserContentController’s new()
    aConf’s setUserContentController:it
  end tell


  ## WebViewを作成&読み込み
set frameSize to current application’s NSMakeRect(0, 0, viewWidth, viewHeight)
tell current application’s WKWebView’s alloc()
    tell initWithFrame_configuration_(frameSize, aConf)
      setNavigationDelegate_(me)
setUIDelegate_(me)
loadHTMLString_baseURL_(aString, baseURL)
set theView to it
    end tell
  end tell


  ## アイコンの指定
set aImage to current application’s NSWorkspace’s sharedWorkspace()’s iconForFileType:“net.daringfireball.markdown”


  ## set up alert
tell current application’s NSAlert’s new()
    addButtonWithTitle_(“Close”)
setAccessoryView_(theView)
setIcon_(aImage)
setInformativeText_(infoText)
setMessageText_(mesText)
tell |window|()
      setInitialFirstResponder_(theView)
    end tell
### show alert in modal loop
if runModal() is (current application’s NSAlertSecondButtonReturn) then return
  end tell


  ##後始末
theView’s stopLoading()
set js to “window.open(’about:blank’,’_self’).close();”
theView’s evaluateJavaScript:js completionHandler:(missing value)
set theView to missing value
end displayMarkdownPreview:

★Click Here to Open This Script 
(Visited 66 times, 1 visits today)
Posted in dialog JavaScript Markdown | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy | Leave a comment

Vis.jsでGraphvizをダイアログ上に表示 v2

Posted on 6月 23, 2020 by Takaaki Naganoya

アラートダイアログ上にWkWebViewを配置し、その上にvis.jsによるDOT言語をGraphViz同様に表示するAppleScriptです。


▲本Scriptの実行画面。改行が効いていませんね

GraphVizは、知る人ぞ知るフロー図やマインドマップ風の図を比較的わかりやすい記述言語(DOT)で行ったものをレンダリング表示するフリーのソフトウェアです。もともと、IC上の部品配置を最適化するためのアルゴリズムが活用されているのだとか。

ノード間を線でつないだ図(マインドマップみたいなもの)を、ノードの関連情報を記述するだけでレンダリングできるため、いろいろ便利に使ってきました。MindjetMindManagerなどのアプリケーションをAppleScriptからコントロールして表示してきたものを、GraphVizに置き換えています(MindjetMindManagerが高価な割に不甲斐ないので)。AppleScript書類内のルーチンの呼び出し関係をマインドマップで表示するAppleScriptなども使っており、こちらはまだGraphViz版を作っていませんが、いろいろ便利に使えるだろうかといったところです。


▲同じデータをGraphVizでレンダリング&表示させた実行画面

–> Download gviz_data(Script bundle with AppleScript Libraries & DOT Data)

DOTファイルをレンダリングして表示するのに、GraphvizのObjective-C版をひろってきて、その内容を適宜呼び出すようなことも検討していたのですが、これでいいじゃないですか。

GraphvizのObjective-C版をAppleScriptObjC版のアプリケーションに組み込むのが大変(プログラムがFrameworkになっているとか、表示用のビューをWindowに乗せればそれでおしまい、という風にはなっていない)。

WkWebViewを1枚ウィンドウ上に貼り付けて、JavaScriptを実行。PDFに書き出すことさえ考えなければ、これで問題ないでしょう。そう、PDF出力することを考えなければ…………。あとは、Mac App Storeに出すときにこうした構造のアプリケーションで大丈夫なのかが疑問です。ただ、iOSでこうしたWebView+JavaScriptの「ガワアプリ」と言われるものが多数存在するという状況を鑑みますと、そんなにうるさいことを言われないのでは? という気もします。

本Scriptについては、あとはマウスのスクロールで拡大縮小するように改良できるとよいでしょう。

AppleScript名:DOT.jsでGraphvizをダイアログ上に表示 v2.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 scripting additions
use webD : script "webDialogLib"

property NSString : a reference to current application’s NSString

set aDot to choose file of type {"com.omnigroup.foreign-types.graphviz-dot"}
set aData to read aDot as «class utf8»

–https://visjs.github.io/vis-graph3d/docs/graph3d/index.html
set myStr to "<!DOCTYPE html>
<html lang=\"ja\">
<head>
<meta charset=\"utf-8\">
<title>Vue.js-Viz.js</title>
<script src=\"https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js\"></script>
<script type=\"text/javascript\" src=\"https://unpkg.com/viz.js@1.8.0\"></script>
<style>
</style>
</head>
<body>
<div class=\"container\">
<div id=\"graph\">
<div class=\"write\">
</div>
<div class=\"out\">
<div class=\"graph\" v-html=\"svg\"></div>
</div>
</div>
</div>
</body>
<script>
new Vue({
el: ’#graph’,
data: {
input: `%@`,
},
computed: {
svg: function() {
return Viz(this.input, {
format: ’svg’
});
},
},
});
</script>
</html>"

set aString to current application’s NSString’s stringWithFormat_(myStr, aData) as string
set paramObj to {myMessage:"viz.js Test", mySubMessage:"This is a viz.js test", htmlStr:aString, jsDelimiters:{"<script>", "</script>"}, viewSize:{1700, 400}}

webD’s displayWebDialog(paramObj)

★Click Here to Open This Script 

(Visited 383 times, 1 visits today)
Posted in dialog JavaScript | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy | Leave a comment

アラートダイアログ上にWebViewでvis.jsを用いて3Dグラフを表示

Posted on 6月 22, 2020 by Takaaki Naganoya

アラートダイアログ上に作成したWkWebViewでvis.jsのGraph3dを用いて3Dグラフを表示するAppleScriptです。

本Scriptは単に三角関数の計算値をプロットするものなので、そのまま実用レベルというわけではありませんが、vis.jsがこのように利用できることを示す実証コードにはなっていると思います。

実行すると、グラフの表示タイプを聞いてくるので、

選択すると、グラフを表示します。ドラッグで回転、マウスのスクロールホイールでズーム制御を行います。

まいどまいど、代わり映えしないWkWebViewの表示コードを掲載するのもどうかと思い、その部分はライブラリとしてまとめておきました。きちんとAppleScript側のオブジェクトでパラメータを指定できるレベルまで落とし込めば、JavaScript部分もライブラリに押し込んで「display chart」のようなsdefつきライブラリに仕立ててもいいのかもしれません。

–> Download 3dGraphDialog.zip (Script Bundle with AppleScript Libraries)

AppleScript名:アラートダイアログ上にWebViewでvis.jsを用いて3Dグラフを表示.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 scripting additions
use webD : script "webDialogLib"

property NSString : a reference to current application’s NSString

set aSel to choose from list {"bar", "bar-color", "bar-size", "dot", "dot-line", "dot-color", "dot-size", "grid", "line", "surface"}
if aSel = false then return

set aaSel to contents of first item of aSel

–https://visjs.github.io/vis-graph3d/docs/graph3d/index.html
set myStr to "<!DOCTYPE HTML>
<html>
<head>
<title>Graph 3D demo</title>

<style>
body {font: 16pt arial;}
</style>

<script type=\"text/javascript\" src=\"https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.js\"></script>

<script type=\"text/javascript\">
var data = null;
var graph = null;

function custom(x, y) {
return (Math.sin(x/50) * Math.cos(y/50) * 50 + 50);
}

// Called when the Visualization API is loaded.
function drawVisualization() {

// Create and populate a data table.
var data = new vis.DataSet();
  
// create some nice looking data with sin/cos
var steps = 30; // number of datapoints will be steps*steps
var axisMax = 314;
var axisStep = axisMax / steps;
for (var x = 0; x < axisMax; x+=axisStep) {
for (var y = 0; y < axisMax; y+=axisStep) {
var value = custom(x, y);
data.add({
x: x,
y: y,
z: value,
style: value
});
}
}

// specify options
var options = {
width: ’900px’,
height: ’600px’,
style: ’%@’,
showPerspective: true,
showGrid: true,
showShadow: false,
keepAspectRatio: true,
verticalRatio: 0.6
};

// create a graph3d
var container = document.getElementById(’mygraph’);
graph3d = new vis.Graph3d(container, data, options);
}
</script>
</head>

<body onload=\"drawVisualization();\">
<div id=\"mygraph\"></div>
</body>
</html>"

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

set paramObj to {myMessage:"Vis.js Test", mySubMessage:"This is a Vis.js test", htmlStr:aString, jsDelimiters:{"<script type=", "</script>"}, viewSize:{920, 620}}

webD’s displayWebDialog(paramObj)

★Click Here to Open This Script 

(Visited 372 times, 2 visits today)
Posted in dialog JavaScript | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy | 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 

(Visited 215 times, 1 visits today)
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で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 

(Visited 157 times, 1 visits today)
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

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

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 

(Visited 47 times, 1 visits today)
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 

(Visited 76 times, 1 visits today)
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

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 

(Visited 141 times, 1 visits today)
Posted in file JavaScript JSON list Record Text | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSJSONSerialization NSMutableArray NSString NSUUID Numbers Safari | 4 Comments

Google Chromeで最前面のWindowで表示中のページのHTMLソースを取得する

Posted on 9月 30, 2019 by Takaaki Naganoya

Google Chromeの最前面のウィンドウで表示中のページのHTMLソースを取得するAppleScriptです。

ChromeをMacの自動処理の部品として使おうとはまったく考えませんが、命令が存在しないぐらいで「できない」というのも何なので、JavaScript経由でソースを取得できないか調べてみたら、できました。

あらかじめ、Google Chromeの「表示」>「開発/管理」>「Apple EventsからのJavaScriptを許可」を実行しておく必要があります。

AppleScript名:最前面のウィンドウのHTMLソースを取得する
tell application "Google Chrome"
  tell window 1
    tell active tab
      set htmlRes to (execute javascript "document.getElementsByTagName(’html’)[0].innerHTML")
    end tell
  end tell
end tell

★Click Here to Open This Script 

com.google.Chrome

(Visited 376 times, 4 visits today)
Posted in Internet JavaScript | Tagged 10.12savvy 10.13savvy 10.14savvy Google Chrome | 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 

(Visited 147 times, 4 visits today)
Posted in file JavaScript JSON list Text | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSJSONSerialization NSMutableArray NSString NSUUID Numbers Safari | 1 Comment

Safariで指定のDOM Elementの情報を取得する

Posted on 9月 22, 2019 by Takaaki Naganoya

Safariで表示中の最前面のDocument内の指定Tag、指定Index(出現順、0はじまり)のDOM Elementの詳細なプロパティ値を取得するAppleScriptです。

複数のTableが存在しているページのそれぞれのプロパティ値を取得してdiffを取るための調査用Scriptです。

AppleScript名:Safariで指定のDOM Elementの情報を取得する
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

tell application "Safari"
  set jsStr to "var elementsArray = document.body.getElementsByTagName(’table’);
    aVar = window.getComputedStyle(elementsArray[1]);
  JSON.stringify(aVar);"
  
  
set aHeight to do JavaScript jsStr in front document
  
set cRes to parseJSONAsRecord(aHeight) of me
end tell

–> {|95|:"font-style", |50|:"caret-color", |96|:"font-synthesis", |51|:"clear", |97|:"font-variant", webkitMaskPosition:"0% 0%", |52|:"clip", |98|:"font-variant-alternates", webkitHyphens:"manual", |right|:"auto", |53|:"clip-path", |99|:"font-variant-caps", |54|:"clip-rule", backgroundAttachment:"scroll", willChange:"auto", |55|:"color", margin:"0px 0px 20px", marginTop:"0px", |10|:"animation-name", |56|:"color-interpolation", webkitColumnBreakBefore:"auto", baselineShift:"baseline", webkitLineSnap:"none", |11|:"animation-play-state", |57|:"color-interpolation-filters", scrollSnapMargin:"0px", transform:"none", |12|:"animation-timing-function", |58|:"color-rendering", |13|:"background-attachment", |59|:"color-scheme", fontVariantPosition:"normal", gridAutoFlow:"row", |14|:"background-blend-mode", position:"static", |15|:"background-clip", |16|:"background-color", |17|:"background-image", webkitMaskComposite:"source-over", |18|:"background-origin", justifyItems:"normal", |19|:"background-position", colorRendering:"auto", |color|:"rgb(51, 51, 51)", listStyleImage:"none", borderBottom:"0px none rgb(128, 128, 128)", backgroundOrigin:"padding-box", counterIncrement:"none", webkitMaskRepeatY:"", writingMode:"horizontal-tb", borderInlineEndStyle:"none", columnGap:"normal", textDecorationLine:"none", scrollSnapMarginBottom:"0px", strokeColor:"rgba(0, 0, 0, 0)", webkitBoxOrdinalGroup:"1", alignItems:"normal", caretColor:"rgb(51, 51, 51)", webkitMarginBottomCollapse:"collapse", paddingLeft:"0px", fontWeight:"normal", padding:"0px", scrollPaddingTop:"0px", flexGrow:"0", boxSizing:"border-box", webkitBackgroundSize:"auto", marginBottom:"20px", gridTemplateRows:"none", background:"rgba(0, 0, 0, 0) none repeat scroll 0% 0% / auto padding-box border-box", fontDisplay:"", speakAs:"normal", |left|:"auto", webkitBoxDecorationBreak:"slice", scrollSnapAlign:"none none", backgroundPosition:"0% 0%", gridRowStart:"auto", borderBlockStartWidth:"0px", borderTopLeftRadius:"0px", webkitUserDrag:"auto", borderRightColor:"rgb(128, 128, 128)", fontVariantAlternates:"normal", breakInside:"auto", webkitTextZoom:"normal", marker:"", webkitClipPath:"none", strokeLinejoin:"miter", webkitMarquee:"", breakAfter:"auto", webkitMaskPositionX:"0%", whiteSpace:"normal", backgroundColor:"rgba(0, 0, 0, 0)", flexDirection:"row", columns:"auto auto", transformOriginX:"", clip:"auto", emptyCells:"show", transformOrigin:"413.75px 309.4021911621094px", borderLeftColor:"rgb(128, 128, 128)", flex:"0 1 auto", webkitTextStroke:"", clipRule:"nonzero", grid:"none / none / none / row / auto / auto", listStyleType:"disc", maxWidth:"none", borderInlineStartStyle:"none", webkitTextOrientation:"mixed", clipPath:"none", justifySelf:"auto", clear:"none", transformOriginY:"", overflowWrap:"break-word", webkitHyphenateLimitAfter:"auto", tabSize:"8", marginBlockStart:"0px", |120|:"image-rendering", unicodeRange:"", gridColumnEnd:"auto", webkitRubyPosition:"before", |220|:"text-rendering", animationDirection:"normal", webkitMaskOrigin:"border-box", |121|:"isolation", fontStyle:"normal", |320|:"-webkit-text-emphasis-position", |221|:"text-shadow", webkitTextFillColor:"rgb(51, 51, 51)", |122|:"justify-content", borderBottomLeftRadius:"0px", |321|:"-webkit-text-emphasis-style", |80|:"fill-rule", |222|:"text-transform", |123|:"justify-items", |81|:"filter", |322|:"-webkit-text-fill-color", transformOriginZ:"", borderRightWidth:"0px", |82|:"flex-basis", |223|:"text-underline-position", |124|:"justify-self", webkitTextSizeAdjust:"auto", |83|:"flex-direction", |323|:"-webkit-text-orientation", |224|:"top", |84|:"flex-flow", |125|:"kerning", |150|:"opacity", |85|:"flex-grow", |324|:"-webkit-text-security", borderBlockStartStyle:"none", |225|:"touch-action", |40|:"border-top-color", |86|:"flex-shrink", |126|:"left", |250|:"-apple-color-filter", |151|:"order", |41|:"border-top-left-radius", |87|:"flex-wrap", |325|:"-webkit-text-size-adjust", |226|:"transform", border:"0px none rgb(128, 128, 128)", |42|:"border-top-right-radius", |88|:"float", |127|:"letter-spacing", |152|:"orphans", |251|:"-webkit-appearance", |43|:"border-top-style", |89|:"flood-color", |227|:"transform-box", |326|:"-webkit-text-stroke-color", |252|:"-webkit-backdrop-filter", |44|:"border-top-width", |128|:"lighting-color", |153|:"outline-color", |327|:"-webkit-text-stroke-width", borderBlockEndColor:"rgb(128, 128, 128)", |45|:"bottom", |228|:"transform-origin", borderInlineEnd:"0px none rgb(128, 128, 128)", |253|:"-webkit-backface-visibility", |129|:"line-break", |46|:"box-shadow", |154|:"outline-offset", |328|:"-webkit-text-zoom", alignContent:"normal", borderLeftStyle:"none", |47|:"box-sizing", |229|:"transform-style", |254|:"-webkit-background-clip", colorScheme:"auto", shapeOutside:"none", |48|:"buffered-rendering", |155|:"outline-style", |180|:"ry", |329|:"-webkit-transform-style", minBlockSize:"0px", |49|:"caption-side", |255|:"-webkit-background-composite", inlineSize:"827.5px", |280|:"-webkit-font-kerning", |156|:"outline-width", textDecorationColor:"rgb(51, 51, 51)", |181|:"scroll-padding", transitionProperty:"all", webkitBoxDirection:"normal", webkitInitialLetter:"normal", |256|:"-webkit-background-origin", gridColumn:"auto / auto", |281|:"-webkit-font-smoothing", |157|:"overflow-wrap", listStyle:"disc outside none", |182|:"scroll-padding-bottom", webkitMaskBoxImage:"none", floodColor:"rgb(0, 0, 0)", webkitTextEmphasisPosition:"over right", |257|:"-webkit-background-size", scrollSnapMarginRight:"0px", |282|:"-webkit-hyphenate-character", |158|:"overflow-x", webkitTextSecurity:"none", |183|:"scroll-padding-left", columnRule:"0px none rgb(51, 51, 51)", |258|:"-webkit-border-fit", gridColumnStart:"auto", |283|:"-webkit-hyphenate-limit-after", |159|:"overflow-y", touchAction:"auto", |184|:"scroll-padding-right", webkitFontSizeDelta:"", webkitLocale:"ja", |259|:"-webkit-border-horizontal-spacing", |284|:"-webkit-hyphenate-limit-before", colorInterpolation:"sRGB", borderTopColor:"rgb(128, 128, 128)", |185|:"scroll-padding-top", |285|:"-webkit-hyphenate-limit-lines", hangingPunctuation:"none", |186|:"scroll-snap-align", mask:"none", borderRight:"0px none rgb(128, 128, 128)", paddingInlineStart:"0px", webkitBackgroundOrigin:"padding-box", |286|:"-webkit-hyphens", |187|:"scroll-snap-margin", pageBreakAfter:"auto", colorProfile:"", textAnchor:"start", |287|:"-webkit-initial-letter", webkitMaskSize:"auto", |188|:"scroll-snap-margin-bottom", overflowX:"visible", |288|:"-webkit-line-align", strokeLinecap:"butt", |189|:"scroll-snap-margin-left", |289|:"-webkit-line-box-contain", borderBottomColor:"rgb(128, 128, 128)", paddingRight:"0px", fontOpticalSizing:"auto", borderImage:"none", floodOpacity:"1", webkitAspectRatio:"auto", webkitColumnProgression:"normal", alignSelf:"auto", display:"table", borderRadius:"0px", maxInlineSize:"none", minHeight:"0px", strokeMiterlimit:"4", webkitBorderVerticalSpacing:"0px", webkitMaskClip:"border-box", webkitBorderHorizontalSpacing:"0px", objectPosition:"50% 50%", kerning:"0", borderStyle:"none", visibility:"visible", textShadow:"none", borderLeftWidth:"0px", shapeImageThreshold:"0", scrollSnapMarginTop:"0px", markerMid:"none", scrollPadding:"0px", markerEnd:"none", webkitFontKerning:"auto", borderBottomWidth:"0px", float:"none", placeSelf:"auto auto", webkitBackgroundComposite:"source-over", borderTop:"0px none rgb(128, 128, 128)", backgroundRepeat:"repeat", webkitMarqueeDirection:"auto", animationIterationCount:"1", backgroundPositionX:"0%", content:"", transformStyle:"flat", borderInlineEndColor:"rgb(128, 128, 128)", borderBlockStart:"0px none rgb(128, 128, 128)", overflow:"visible", webkitMaskPositionY:"0%", perspective:"none", strokeDashoffset:"0px", outlineColor:"rgb(51, 51, 51)", webkitMarqueeSpeed:"", webkitTextEmphasisStyle:"none", isolation:"auto", borderInlineStartColor:"rgb(128, 128, 128)", textDecorationSkip:"auto", outlineOffset:"0px", objectFit:"fill", textUnderlineOffset:"auto", webkitAppearance:"none", webkitMaskBoxImageWidth:"auto", animationTimingFunction:"ease", borderWidth:"0px", borderSpacing:"0px 0px", captionSide:"top", columnWidth:"auto", rowGap:"normal", webkitMaskBoxImageSource:"none", webkitRtlOrdering:"logical", |70|:"counter-reset", paddingInlineEnd:"0px", |71|:"cursor", |72|:"cx", fontSize:"14.000000953674316px", |73|:"cy", vectorEffect:"none", |74|:"direction", justifyContent:"normal", fillRule:"nonzero", |75|:"display", fontSynthesis:"style weight small-caps", |30|:"border-image-repeat", |76|:"dominant-baseline", |31|:"border-image-slice", |77|:"empty-cells", pageBreakBefore:"auto", |32|:"border-image-source", |78|:"fill", cx:"0px", webkitMaskBoxImageRepeat:"stretch", borderImageSource:"none", |33|:"border-image-width", |79|:"fill-opacity", cy:"0px", outlineStyle:"none", webkitBoxFlex:"0", |34|:"border-left-color", width:"827.5px", webkitMarginBeforeCollapse:"collapse", |35|:"border-left-style", borderRightStyle:"none", |36|:"border-left-width", |0|:"align-content", |37|:"border-right-color", |1|:"align-items", paddingBlockStart:"0px", |size|:"", |2|:"align-self", |38|:"border-right-style", |3|:"alignment-baseline", |4|:"alt", |39|:"border-right-width", webkitFontSmoothing:"auto", |5|:"animation-delay", borderTopWidth:"0px", |6|:"animation-direction", |100|:"font-variant-east-asian", |7|:"animation-duration", |8|:"animation-fill-mode", |200|:"stroke", |9|:"animation-iteration-count", webkitTransformStyle:"flat", |101|:"font-variant-ligatures", counterReset:"none", |300|:"-webkit-mask-box-image", maskType:"luminance", webkitBoxShadow:"none", |201|:"stroke-color", borderBlockEndStyle:"none", |102|:"font-variant-numeric", fontStretch:"normal", textDecorationStyle:"solid", |301|:"-webkit-mask-box-image-outset", cursor:"auto", |202|:"stroke-dasharray", webkitMarqueeStyle:"scroll", |103|:"font-variant-position", animationFillMode:"none", glyphOrientationVertical:"auto", |302|:"-webkit-mask-box-image-repeat", |203|:"stroke-dashoffset", textRendering:"auto", |104|:"font-variation-settings", borderImageRepeat:"stretch", |303|:"-webkit-mask-box-image-slice", |204|:"stroke-linecap", height:"618.8043823242188px", |105|:"font-weight", all:"", |130|:"line-height", |304|:"-webkit-mask-box-image-source", pointerEvents:"auto", textTransform:"none", |205|:"stroke-linejoin", dominantBaseline:"auto", |230|:"transition-delay", |106|:"glyph-orientation-horizontal", filter:"none", |131|:"list-style-image", |305|:"-webkit-mask-box-image-width", |330|:"-webkit-user-drag", |206|:"stroke-miterlimit", paintOrder:"normal", |231|:"transition-duration", |107|:"glyph-orientation-vertical", placeItems:"normal normal", |132|:"list-style-position", |306|:"-webkit-mask-clip", borderInlineStart:"0px none rgb(128, 128, 128)", |331|:"-webkit-user-modify", |207|:"stroke-opacity", textOverflow:"clip", |232|:"transition-property", |108|:"grid-auto-columns", webkitBackdropFilter:"none", |133|:"list-style-type", |307|:"-webkit-mask-composite", webkitMaskRepeat:"repeat", |332|:"-webkit-user-select", |208|:"stroke-width", webkitBoxReflect:"none", |233|:"transition-timing-function", |109|:"grid-auto-flow", |134|:"margin-bottom", |308|:"-webkit-mask-image", |333|:"fullscreen-inset-bottom", |209|:"tab-size", |234|:"unicode-bidi", flexWrap:"nowrap", wordSpacing:"0px", |135|:"margin-left", |309|:"-webkit-mask-origin", |160|:"padding-bottom", |334|:"safe-area-inset-bottom", flexFlow:"row nowrap", |235|:"vector-effect", |260|:"-webkit-border-image", |136|:"margin-right", |161|:"padding-left", |335|:"safe-area-inset-left", transition:"all 0s ease 0s", |236|:"vertical-align", columnFill:"balance", |261|:"-webkit-border-vertical-spacing", |137|:"margin-top", |162|:"padding-right", |336|:"fullscreen-inset-left", maxHeight:"none", |237|:"visibility", alt:"\"\"", |262|:"-webkit-box-align", |138|:"marker-end", marginInlineEnd:"0px", |163|:"padding-top", |337|:"fullscreen-inset-right", webkitMarginTopCollapse:"collapse", |238|:"white-space", gridRowEnd:"auto", |263|:"-webkit-box-decoration-break", |139|:"marker-mid", |164|:"page-break-after", |338|:"fullscreen-auto-hide-duration", fillOpacity:"1", |239|:"widows", |264|:"-webkit-box-direction", overflowY:"visible", |165|:"page-break-before", |339|:"safe-area-inset-right", |190|:"scroll-snap-margin-right", |265|:"-webkit-box-flex", animationDuration:"0s", |290|:"-webkit-line-clamp", |166|:"page-break-inside", marginRight:"0px", |191|:"scroll-snap-margin-top", |266|:"-webkit-box-flex-group", borderInlineStartWidth:"0px", |291|:"-webkit-line-grid", |167|:"paint-order", webkitNbspMode:"normal", |192|:"scroll-snap-type", |267|:"-webkit-box-lines", mixBlendMode:"normal", |292|:"-webkit-line-snap", |168|:"perspective", paddingBlockEnd:"0px", |193|:"shape-image-threshold", src:"", webkitBoxAlign:"stretch", |268|:"-webkit-box-ordinal-group", paddingTop:"0px", |293|:"-webkit-locale", |169|:"perspective-origin", borderBlockEnd:"0px none rgb(128, 128, 128)", |194|:"shape-margin", r:"0px", textAlign:"start", |269|:"-webkit-box-orient", webkitMaskBoxImageOutset:"0px", |294|:"-webkit-margin-after-collapse", webkitTextEmphasis:"", webkitTextStrokeColor:"rgb(51, 51, 51)", |195|:"shape-outside", breakBefore:"auto", wordWrap:"break-word", |295|:"-webkit-margin-before-collapse", minInlineSize:"0px", |196|:"shape-rendering", borderInlineEndWidth:"0px", webkitLineAlign:"none", webkitMaskBoxImageSlice:"0 fill", widows:"auto", perspectiveOrigin:"413.75px 309.4021911621094px", |296|:"-webkit-marquee-direction", x:"0px", y:"0px", |197|:"speak-as", perspectiveOriginX:"", |297|:"-webkit-marquee-increment", |198|:"stop-color", fontFamily:"-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen-Sans, Ubuntu, Cantarell, \"Helvetica Neue\", sans-serif", |298|:"-webkit-marquee-repetition", |199|:"stop-opacity", animationPlayState:"running", webkitHyphenateLimitBefore:"auto", |299|:"-webkit-marquee-style", webkitBoxOrient:"horizontal", order:"0", webkitMaskSourceType:"alpha", fontVariantNumeric:"normal", webkitColumnBreakAfter:"auto", webkitColumnBreakInside:"auto", shapeMargin:"0px", webkitMaskImage:"none", top:"auto", backgroundBlendMode:"normal", listStylePosition:"outside", bottom:"auto", gridTemplateColumns:"none", strokeWidth:"0.8695652484893799px", borderTopRightRadius:"0px", direction:"ltr", webkitBackfaceVisibility:"visible", backgroundPositionY:"0%", rx:"0px", webkitHyphenateLimitLines:"no-limit", ry:"0px", lineBreak:"auto", bufferedRendering:"auto", quotes:"", gridRow:"auto / auto", webkitBorderFit:"border", borderBottomRightRadius:"0px", alignmentBaseline:"auto", textIndent:"0px", paddingBottom:"0px", columnRuleColor:"rgb(51, 51, 51)", fontVariantCaps:"normal", backgroundSize:"auto", |60|:"column-count", columnCount:"auto", |61|:"column-fill", webkitBoxLines:"single", webkitBoxFlexGroup:"1", backgroundRepeatX:"", |62|:"column-gap", glyphOrientationHorizontal:"0deg", lineHeight:"20px", |63|:"column-rule-color", borderBlockEndWidth:"0px", opacity:"1", webkitBackgroundClip:"border-box", webkitBoxPack:"start", |64|:"column-rule-style", |65|:"column-rule-width", borderImageWidth:"1", fontVariantLigatures:"normal", |20|:"background-repeat", |66|:"column-span", |21|:"background-size", |67|:"column-width", gridTemplateAreas:"none", tableLayout:"auto", |22|:"baseline-shift", |68|:"content", webkitBorderImage:"none", |23|:"border-bottom-color", |69|:"counter-increment", animationName:"none", letterSpacing:"normal", |24|:"border-bottom-left-radius", |25|:"border-bottom-right-radius", backgroundClip:"border-box", transitionDelay:"0s", |26|:"border-bottom-style", |27|:"border-bottom-width", webkitCursorVisibility:"auto", |28|:"border-collapse", webkitTextDecorationsInEffect:"none", |29|:"border-image-outset", fill:"rgb(0, 0, 0)", webkitHyphenateCharacter:"auto", animation:"", pageBreakInside:"auto", lightingColor:"rgb(255, 255, 255)", webkitLineClamp:"none", perspectiveOriginY:"", textDecorationThickness:"auto", marginInlineStart:"0px", borderTopStyle:"none", placeContent:"normal normal", backgroundRepeatY:"", textUnderlinePosition:"auto", wordBreak:"normal", columnRuleStyle:"none", webkitUserModify:"read-only", columnSpan:"none", strokeOpacity:"1", webkitMarqueeRepetition:"infinite", webkitMarginCollapse:"", flexBasis:"auto", colorInterpolationFilters:"linearRGB", gap:"normal normal", webkitMask:"", gridArea:"auto / auto / auto / auto", gridTemplate:"none / none / none", resize:"none", borderColor:"rgb(128, 128, 128)", zIndex:"auto", webkitTextCombine:"none", webkitTextStrokeWidth:"0px", borderBottomStyle:"none", fontVariant:"normal", scrollSnapType:"none", textDecoration:"none", webkitTextEmphasisColor:"rgb(51, 51, 51)", orphans:"auto", scrollPaddingRight:"0px", borderImageOutset:"0px", webkitTextDecoration:"none solid rgb(51, 51, 51)", |110|:"grid-auto-rows", marginLeft:"0px", transitionTimingFunction:"ease", |210|:"table-layout", stroke:"none", stopOpacity:"1", |111|:"grid-column-end", |310|:"-webkit-mask-position", stopColor:"rgb(0, 0, 0)", webkitPrintColorAdjust:"economy", |211|:"text-align", unicodeBidi:"normal", |112|:"grid-column-start", |311|:"-webkit-mask-repeat", page:"", |212|:"text-anchor", |113|:"grid-row-end", |312|:"-webkit-mask-size", fontFeatureSettings:"normal", |213|:"text-decoration", |114|:"grid-row-start", webkitMarqueeIncrement:"6px", webkitUserSelect:"text", |313|:"-webkit-mask-source-type", gridAutoRows:"auto", |214|:"text-decoration-color", |115|:"grid-template-areas", |140|:"marker-start", |314|:"-webkit-nbsp-mode", scrollPaddingBottom:"0px", |215|:"text-decoration-line", |240|:"width", |116|:"grid-template-columns", |141|:"mask", |315|:"-webkit-print-color-adjust", borderBlockStartColor:"rgb(128, 128, 128)", |340|:"fullscreen-inset-top", |216|:"text-decoration-skip", fontVariantEastAsian:"normal", |241|:"will-change", |117|:"grid-template-rows", fontVariationSettings:"normal", |142|:"mask-type", |316|:"-webkit-rtl-ordering", marginBlockEnd:"20px", |341|:"safe-area-inset-top", |217|:"text-decoration-style", minWidth:"0px", |242|:"word-break", |118|:"hanging-punctuation", zoom:"1", |143|:"max-height", |317|:"-webkit-text-combine", |218|:"text-indent", gridAutoColumns:"auto", |243|:"word-spacing", |119|:"height", verticalAlign:"baseline", |144|:"max-width", |318|:"-webkit-text-decorations-in-effect", imageRendering:"auto", maxBlockSize:"none", |219|:"text-overflow", outlineWidth:"0px", |244|:"word-wrap", shapeRendering:"auto", webkitLineGrid:"none", |145|:"min-height", |319|:"-webkit-text-emphasis-color", |170|:"place-content", enableBackground:"", |245|:"writing-mode", |270|:"-webkit-box-pack", |146|:"min-width", animationDelay:"0s", |171|:"place-items", boxShadow:"none", scrollSnapMarginLeft:"0px", webkitBorderRadius:"", |246|:"x", |271|:"-webkit-box-reflect", |147|:"mix-blend-mode", |172|:"place-self", |247|:"y", blockSize:"618.8043823242188px", |272|:"-webkit-box-shadow", |148|:"object-fit", columnRuleWidth:"0px", |173|:"pointer-events", backgroundImage:"none", |248|:"z-index", |273|:"-webkit-clip-path", |149|:"object-position", transitionDuration:"0s", |174|:"position", |249|:"zoom", |274|:"-webkit-column-axis", webkitColumnAxis:"auto", |175|:"r", borderImageSlice:"100%", |275|:"-webkit-column-break-after", borderCollapse:"collapse", |176|:"resize", |276|:"-webkit-column-break-before", webkitLineBoxContain:"block inline replaced", |177|:"right", |277|:"-webkit-column-break-inside", |178|:"row-gap", borderLeft:"0px none rgb(128, 128, 128)", |font|:"normal normal normal normal 14.000000953674316px/20px -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen-Sans, Ubuntu, Cantarell, \"Helvetica Neue\", sans-serif", webkitMarginAfterCollapse:"collapse", |278|:"-webkit-column-progression", |outline|:"rgb(51, 51, 51) none 0px", scrollPaddingLeft:"0px", |90|:"flood-opacity", |179|:"rx", markerStart:"none", strokeDasharray:"none", |91|:"font-family", |279|:"-webkit-cursor-visibility", flexShrink:"1", webkitMaskRepeatX:"", |92|:"font-optical-sizing", transformBox:"border-box", |93|:"font-size", |94|:"font-stretch"}

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

★Click Here to Open This Script 

(Visited 176 times, 2 visits today)
Posted in Internet JavaScript JSON | Tagged 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSString Safari | 1 Comment

Safariのdo JavaScriptから結果をJSONで返してASの各種オブジェクトに変換

Posted on 9月 22, 2019 by Takaaki Naganoya

Safariのdo JavaScriptコマンドから各種結果を取得してAppleScriptの各種オブジェクトに変換するAppleScriptです。

真剣にSafari上でdo JavaScriptコマンド経由で値の受け渡しをするときに、さまざまな型のデータをJavaScript側からAppleScript側に渡したいことがあります。

ただ、JavaScript側からのデータの受け渡しはそんなにまじめにやっていなかったので、あらためて方法を調べておきました。

AppleScript名:Safariのdo javascriptから結果をJSONで返してASの各種オブジェクトに変換
—
–  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"

tell application "Safari"
  if (count every document) = 0 then return
  
  
–String List (1D)
  
set jsRes1 to do JavaScript "var tempVar = [’1’,’2’];
  JSON.stringify(tempVar);"
in front document
  
set aRes to parseJSONAsList(jsRes1) of me
  
–> {"1", "2"}
  
  
–Number List (1D)  
  
set jsRes2 to do JavaScript "var tempVar = [1,2];
  JSON.stringify(tempVar);"
in front document
  
set bRes to parseJSONAsList(jsRes2) of me
  
–> {1, 2}
  
  
–Record  
  
set jsRes3 to do JavaScript "var tempVar2 = { name:’Steve Jobs’, age:32, tel:’080-1234-5678’ };
  JSON.stringify(tempVar2);"
in front document
  
set cRes to parseJSONAsRecord(jsRes3) of me
  
–> {|name|:"Steve Jobs", age:32, tel:"080-1234-5678"}
  
  
–Records in List
  
set jsRes4 to do JavaScript "var tempVar2 = [{ name:’Steve Jobs’, age:32, tel:’080-1234-5678’ },{ name:’Tim Coo’, age:55, tel:’090-1234-5678’ }] ;
  JSON.stringify(tempVar2);"
in front document
  
set dRes to parseJSONAsList(jsRes4) of me
  
–> {{|name|:"Steve Jobs", age:32, tel:"080-1234-5678"}, {|name|:"Tim Coo", age:55, tel:"090-1234-5678"}}
  
  
–Number List (2D)  
  
set jsRes5 to do JavaScript "var tempVar = [[1,2], [3,4], [5,6]];
  JSON.stringify(tempVar);"
in front document
  
set eRes to parseJSONAsList(jsRes5) of me
  
–> {{1, 2}, {3, 4}, {5, 6}}
end tell

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

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

★Click Here to Open This Script 

AppleScript名:Safariのdo javascriptから結果をJSONで返してASの各種オブジェクトに変換 2
—
–  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"

tell application "Safari"
  if (count every document) = 0 then return
  
  
–String
  
set jsRes1 to do JavaScript "var tempVar = ’1’;
  tempVar;"
in front document
  
–> "1"
  
  
–Number
  
set jsRes2 to do JavaScript "var tempVar = 1;
  tempVar;"
in front document
  
–> 1.0
  
end tell

★Click Here to Open This Script 

(Visited 82 times, 1 visits today)
Posted in JavaScript JSON Tag | Tagged 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSString Safari | 1 Comment

コンテンツ中の表示中のエリア座標を取得する

Posted on 9月 18, 2019 by Takaaki Naganoya

Safariで表示中のWebコンテンツの表示範囲の座標を取得するAppleScriptです。

Webブラウザに対するAppleScriptの処理といえば、

 (1)表示中のURLを取得して処理
 (2)表示中のコンテンツにJavaScriptを実行したりGUI Scripting経由で操作(特定要素をカウントしたりFormに値を入れたりボタンを押したり)
 (3)表示中のHTMLソースを取得して処理
 (4)Webブラウザそのものの環境情報(Bookmarkや履歴など)にアクセスして処理
 (5)選択中のテキストを取得して処理
 (6)テキストを選択しておいて、その内容が該当する要素を抽出

といった操作を行ってきました。

(1)は、Webブラウザで表示中のURLを他のプログラムで処理する場合などに便利な、基礎的な処理です。
(2)は、ロボット的なScriptにありがちな、メニューの奥深く(URLで一発オープンが無理なログインを要求される構造のWebサイトとか)にあるデータを定期的に取得するような処理によく使います。
(3)は、(1)の延長線上にあるもので、HTMLReaderなどのHTMLそのものを解釈して処理できる高機能フレームワークと組み合わせてWebスクレイピングを行うものです
(4)は、書いてあるとおりブックマークや履歴などにアクセスして統計処理を行なったりしています。
(5)は、ちょっとした調べ物や翻訳などを行いたい場合に使っています。
(6)は、(3)の処理を行いたいが、処理対象の要素(表など)が複数あるので、どの要素なのか特定するための補助情報としてテキスト選択を要求するものです。

このうち、(6)に該当する処理が現状だといまひとつです。Webブラウザ上でテキストを選択しておく必要があるというのでは使い勝手がよくありません。

Webコンテンツのうち、Webブラウザ上で表示中の要素を取得するようなやり方であれば、その方が使い勝手がよいことでしょう。Wikipedia上の表データを使いまわしたいが、対象ページ上に表が複数あるので、いま現在Webブラウザのウィンドウ上で見えている範囲内に存在する表を取り出すようにすれば、より気の利いた処理になることでしょう。

AppleScript名:コンテンツ中の表示中のエリア座標を取得する
–https://stackoverflow.com/questions/9271747/can-i-detect-the-user-viewable-area-on-the-browser
tell application "Safari"
  set dCount to count every document
  
if dCount = 0 then return
  
  
set aHeight to do JavaScript "window.innerHeight;" in front document
  
set sHeight to do JavaScript "window.scrollY;" in front document
  
  
set aWidth to do JavaScript "window.innerWidth;" in front document
  
set sWidth to do JavaScript "window.scrollX;" in front document
  
  
return {myWidth:aWidth, scrollX:sWidth, myHeight:aHeight, scrollY:sHeight}
end tell

★Click Here to Open This Script 

(Visited 51 times, 1 visits today)
Posted in JavaScript Web Contents Control | Tagged 10.12savvy 10.13savvy 10.14savvy Safari | Leave a 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 

(Visited 70 times, 1 visits today)
Posted in file Internet JavaScript list Text | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSMutableArray NSString Numbers Safari | 1 Comment

指定URLのMS名を取得する v2b

Posted on 9月 4, 2019 by Takaaki Naganoya

edama2さんから投稿していただいた、指定URLの初出の指定タグ要素を抽出するAppleScriptです。

戦場の絆Wiki上の指定ページ上の指定タグでマークされたテキストを取得します。

ブログを見ていて思いつき、前に作りかけていたのを清書して送ります。

名前は「指定URLのMS名を取得するv2b」です。
内容はWKWebviewでページを読み込んで、javascriptで要素を取得しています。
前の二つよりスマートではありませんが、こんなやり方もあるってことで...

色々書き換えているうちに元がないですが、元ネタはapplescriptの穴からです。

プログラムも短いわけではなく、処理速度も速いわけでもなく(自分の環境で9秒ぐらい)、ただ見ただけだと「????」という内容ですが、本プログラムの価値は処理対象ではなく、

AppleScriptからWkWebViewに対して任意のJavaScriptを実行して処理しているサンプルである

という1点に尽きます。これはー、セキュリティ上のしばりがきつくて、けっこう大変なんですよ(遠い目)。

以前、WKWebView上にYouTubeの指定URLのムービーを表示するというScriptを掲載したことがありますが、本当はこの上でJavaScriptを実行して指定の再生ポジションに再生位置をジャンプさせるといった処理を行いたかったのですが、WKWebView相手に(任意の)JavaScriptを実行させられず、時間切れで諦めたことがありました(そして絶賛放置中)。なるほど、こう書くんですねー。

あとは、

tell AppleScript

ってなんなんでしょう(^ー^;; 初めて見かける記述のオンパレードがけっこうショッキングです。

自分は「癖のないプログラムを読みやすく書く派」を自称していますが、日本国内にも割と海外のScripterに紹介したい(変わった)人たちがいて、edama2さんとMacLab.さんはその中に必ず入ってくる人たちでしょう。

AppleScript名:指定URLのMS名を取得する v2b.scpt
—
–  Created by: edama2
–  Created on: 2019/09/04
—
use AppleScript
use scripting additions
use framework "Foundation"
use framework "WebKit"

property _js_result : ""

on run
  my main()
end run

on main()
  set my _js_result to ""
  
  
set aURL to "https://w.atwiki.jp/senjounokizuna/pages/1650.html"
  
set myJs to "var result = document.getElementsByTagName(’h3’)[0].innerHTML;
  webkit.messageHandlers.oreore.postMessage(result);"
–>返信用に必要
  
set paramObj to {targetURL:aURL, javascript:myJs}
  
  
my performSelectorOnMainThread:"makeWebContents:" withObject:(paramObj) waitUntilDone:true
  
  
return my _js_result as text
end main

on makeWebContents:paramObj
  
  
set {targetURL:aURL, javascript:myJs} to paramObj
  
  
# 下準備
  
set thisURL to current application’s |NSURL|’s URLWithString:aURL
  
set theRequest to current application’s NSURLRequest’s requestWithURL:thisURL
  
set aConf to current application’s WKWebViewConfiguration’s new()
  
  
#javascriptからname を取り出す
  
set myJs to myJs as text
  
tell AppleScript
    set tmp to text item delimiters
    
set text item delimiters to "webkit.messageHandlers."
    
set stringList to myJs’s text items
    
set aText2 to stringList’s item 2
    
set text item delimiters to ".postMessage("
    
set stringList2 to aText2’s text items
    
set scriptName to stringList2’s item 1
    
set text item delimiters to tmp
  end tell
  
  
#ページ読み込み後に実行するjavascriptの仕込み
  
set userScript to current application’s WKUserScript’s alloc()’s initWithSource:myJs injectionTime:(current application’s WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
tell current application’s WKUserContentController’s new()
    addUserScript_(userScript)
    
addScriptMessageHandler_name_(me, scriptName)
    
aConf’s setUserContentController:it
  end tell
  
  
#WebViewを作成&読み込み
  
tell (current application’s WKWebView’s alloc()’s initWithFrame:(current application’s CGRectZero) configuration:aConf)
    setNavigationDelegate_(me)
    
loadRequest_(theRequest)
    
    
set hitF to false
    
repeat (minutes * 1000) times
      set isLoading to isLoading() as boolean
      
if not isLoading then
        set hitF to true
        
exit repeat
      end if
      
delay "0.001" as real
    end repeat
    
  end tell
  
  
return hitF
end makeWebContents:

#javascriptの結果を受信
on userContentController:myUserContentController didReceiveScriptMessage:aMessage
  set my _js_result to aMessage’s body() as text
  
return my _js_result
end userContentController:didReceiveScriptMessage:

★Click Here to Open This Script 

(Visited 61 times, 1 visits today)
Posted in JavaScript URL | Tagged 10.12savvy 10.13savvy 10.14savvy NSURL NSURLRequest WKUserContentController WKUserScript WKWebView WKWebViewConfiguration | Leave a comment

Safariで表示中のPageの選択中の文字を含む表データを取得

Posted on 9月 3, 2019 by Takaaki Naganoya

Safari上で一部のテキストを選択した「表」のデータをHTMLReaderフレームワークを利用してparseし、2D Listとして取得するAppleScriptです。

Web上の表データをそのまま利用したいケースが多々あります。こんな小さなデータではなく、数百個にわたる表データをインポートして使いたいというケースです。

そのときに作った部品を転用して、より一般的な用途に使えるようにしたのが本Scriptです。ただし、さまざまな用途に使って鍛えたというものでもなく、AppleのWebドキュメントやWikiの内容の抽出など、割と「規則性の高そうなコンテンツ」で利用してみました。

本来は、複数ページの特定の表を指定してデータを取得する用途に用いているものなので、本Scriptのように「選択中の文字列を含む表」といった、のどかな使い方はしません。動作内容がわかりやすいように作り変えたためにこのような仕様になっています。

どこぞのオンラインストアの諸元をまとめた表をWeb上からくすねてくる、とかいう用途だと、割と表が込み入って(JavaScriptを仕込んでソートし直せるようにしてあるとか)いるケースがあるので、どのページのどの表にでもあまねく利用できるという種類のものではありません。

–> Download HTMLReader.framework(To ~/Library/Frameworks)

HTMLReader.frameworkを利用するためには、macOS 10.14以降だとSIPを解除するかScript Debugger上で動かすか、AppleScriptアプレット内に組み込んで実行することになります。

AppleScript名:Safariで表示中のPageの選択中の文字を含む表データを取得.scptd
— Created 2019-09-02 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
–> {{"Objective-C and AppleScript class", "Attributes (script term, if different)", "Relationships"}, {"NSObjectImplements the item AppleScript class. For any scriptable Objective-C class that inherits from NSObject, the AppleScript class it implements inherits from the item class (and inherits the class property and the properties property).", "class name (class), properties", ""}, {"NSApplicationImplements the application AppleScript class.", "name, active flag (frontMost), version", "documents, windows (both accessible as ordered relationship)"}, {"NSDocumentImplements the document AppleScript class.", "location of the document’s on-disk representation (path); last component of filename (name); edited flag (modified)", ""}, {"NSWindowImplements the window AppleScript class.", "title (name); various binary-state attributes: closeable, floating, miniaturized, modal, resizable, titled, visible, zoomable", "document"}}

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
    
    
if htmlSource 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

★Click Here to Open This Script 

(Visited 68 times, 1 visits today)
Posted in JavaScript Text URL | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSMutableArray NSString Safari | 1 Comment

各種GUI要素なしでSafari上に新規ウィンドウ表示

Posted on 4月 29, 2019 by Takaaki Naganoya

Safari上で操作ボタンなどのGUI要素を表示しないで新規ウィンドウ表示するAppleScriptです。

1つのウィンドウを表示するのはすぐにできましたが、複数表示が大変でした(ーー; 結局、適宜delayコマンドで時間待ちをする必要があったのでした。やれやれー。

現時点で用途はまったく不明なのですが、いつか必要になることもあるでしょう(そういうの多いな!)。「resizable=no」という指定をしているのに、ウィンドウがリサイズできるあたりはご愛嬌。

ちなみに、Safariのdocumentが1つ以上存在することを前提条件としていますが、そこは省略して明示していません(初心者がひっかかりがちな「不明確な前提条件」なのですが本説明をもってかえさせていただきます)。

Twitter上でロシアのMacユーザーが「だれかAppleScriptについて教えてくれー」と言っていたので、「Google翻訳の範囲でなら(込み入った話でなければ)いいぞ」と返信したら、マンツーマンでやりとり。

初のロシア人とのチャットです。

本ScriptのおおもとになったAppleScriptをAlfred.appを使ってキーボードショートカットで呼び出していたそうで、1アクションから1つのサイトをオープンするだけなのが不満で、複数のサイト(URL)をオープンするように変更したかったとのこと。

Google翻訳を使ってコミュニケーションしてみて、いろいろ理解しました。

(1)ロシア人、とっても普通

(2)話した相手がプログラミングわからない人だったので、いろいろ追加で話をされたが、プログラマーが一番嫌がる内容(最初からゴール地点が設定されていない)になってきたので「ここから先は仕事としてならやるが、ギャラなしだったらやらない」と明言して打ち切り

(3)Google翻訳を通じて「ロシア語に翻訳できない表現」がいろいろあって焦る。おそらく、英語ほどには日本語との間の翻訳の用例が多く蓄積されておらず、翻訳できなかったものと想像。一応、日本語→ロシア語に翻訳してから、その文章を再度日本語に再翻訳してチェック。トンでもない表現に翻訳されて驚愕するも、何例か日本語の表現を変えてリトライ

あとから振り返って考えると、「日本語からロシア語に翻訳するより、英語からロシア語に翻訳した方がよかった」、「ダスビダーニャ(До свидания)って挨拶は知っていたのに使えなかったよ、ハラショー」といったところでしょうか。

あとは、固定でプログラム中にURLのデータを入れておかないで、外部ファイル……たとえばNumbers書類上のデータであるとか、DragThingのURLランチャーに登録してある現在選択中のタブからURLを取得してオープンするとかいった処理が考えられると「お、頑張ったね」というレベルでしょうか。

AppleScript名:各種GUI要素なしでSafari上に新規ウィンドウ表示
set aURLstr to "http://piyocast.com/as"

tell application "Safari"
  tell front document
    set jsStr to "open(’" & aURLstr & "’, ’test’,’scrollbars=no,resizable=no,status=no,location=no," & "toolbar=no,menubar=no,width=1024,height=720,left=0,top=0’);"
    
do JavaScript jsStr
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:各種GUI要素なしでSafari上に新規ウィンドウを複数表示
set aURLarray to {"http://piyocast.com/as", "http://www.apple.com", "http://www.microsoft.com"}

repeat with i in aURLarray
  set j to contents of i
  
openNewWindowWithoutGUIElements(j) of me
  
delay 3
end repeat

on openNewWindowWithoutGUIElements(aURLstr)
  set aNum to random number from 1 to 999
  
tell application "Safari"
    tell front document
      set jsStr to ("open(’" & aURLstr & "’, ’test" & aNum as string) & "’,’scrollbars=no,resizable=no,status=no,location=no," & "toolbar=no,menubar=no,width=1024,height=720,left=0,top=0’);"
      
do JavaScript jsStr
    end tell
  end tell
end openNewWindowWithoutGUIElements

★Click Here to Open This Script 

(Visited 138 times, 1 visits today)
Posted in JavaScript list URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Safari | Leave a comment

Post navigation

  • Older posts

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

Google Search

Popular posts

  • AppleScriptによるWebブラウザ自動操縦ガイド
  • macOS 13, Ventura(継続更新)
  • ドラッグ&ドロップ機能の未来?
  • macOS 12.x上のAppleScriptのトラブルまとめ
  • PFiddlesoft UI Browserが製品終了に
  • macOS 12.3 beta 5、ASの障害が解消される(?)
  • SF Symbolsを名称で指定してPNG画像化
  • 新刊発売:AppleScriptによるWebブラウザ自動操縦ガイド
  • macOS 12.3 beta4、まだ直らないASまわりの障害
  • macOS 12.3上でFinder上で選択中のファイルをそのままオープンできない件
  • Safariで表示中のYouTubeムービーのサムネイル画像を取得
  • macOS 12のスクリプトエディタで、Context Menu機能にバグ
  • Pixelmator Pro v2.4.1で新機能追加+AppleScriptコマンド追加
  • 人類史上初、魔導書の観点から書かれたAppleScript入門書「7つの宝珠」シリーズ開始?!
  • CotEditor v4.1.2でAppleScript系の機能を追加
  • macOS 12.5(21G72)がリリースされた!
  • UI Browserがgithub上でソース公開され、オープンソースに
  • Pages v12に謎のバグ。書類上に11枚しか画像を配置できない→解決
  • 新発売:AppleScriptからSiriを呼び出そう!
  • iWork 12.2がリリースされた

Tags

10.11savvy (1102) 10.12savvy (1243) 10.13savvy (1391) 10.14savvy (586) 10.15savvy (434) 11.0savvy (274) 12.0savvy (174) 13.0savvy (34) CotEditor (60) Finder (47) iTunes (19) Keynote (97) NSAlert (60) NSArray (51) NSBezierPath (18) NSBitmapImageRep (21) NSBundle (20) NSButton (34) NSColor (51) NSDictionary (27) NSFileManager (23) NSFont (18) NSImage (42) NSJSONSerialization (21) NSMutableArray (62) NSMutableDictionary (21) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (118) NSURL (97) NSURLRequest (23) NSUTF8StringEncoding (30) NSUUID (18) NSView (33) NSWorkspace (20) Numbers (55) Pages (36) Safari (41) Script Editor (20) WKUserContentController (21) WKUserScript (20) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • Clipboard
  • Code Sign
  • Color
  • Custom Class
  • dialog
  • drive
  • 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
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • 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
  • 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)
  • 未分類

アーカイブ

  • 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