locked
ブラウザがEdgeの場合、選択したアイテムのタイトルコピーに失敗する RRS feed

  • 質問

  • SharePoint Onlineでリストビューにスクリプトエディターでボタンを追加し、チェックされたアイテムのタイトルコピーをする処理を作りましたが、

    Chromeではだいたい成功し、Edgeでは一回も成功しません。

    別の処理でURLをコピーする場合はうまくいくためコピー部分に問題はなさそうで、

    クエリーを実行する部分が非同期処理になるため、それが原因だと思うのですが

    Edgeで1回も成功しない原因がわかりません。

    async,awaitは比較的新しいブラウザでしか使えないようですが、

    ブラウザのバージョンは対応済みのものでした。

    何か対応策はありますでしょうか?

    スクリプトエディターのコードは以下です。

    <html>
    <head>
    <script language='javaScript' type='text/javascript'>
    var getSelectedItems = function(){
        return new Promise(function (resolve,reject){
            JSRequest.EnsureSetup();
            var context = SP.ClientContext.get_current();
            var listId= SP.ListOperation.Selection.getSelectedList();
            var selectedItemIds = SP.ListOperation.Selection.getSelectedItems(context);

            var list= context.get_web().get_lists().getById(listId);
            var currentItem = list.getItemById(parseInt(selectedItemIds[0].id));
            context.load(currentItem);
            context.executeQueryAsync(
                function(){
                    resolve(currentItem);
                },
                function(){
                    reject(args.get_message());
                }
            );
        })
    }

    async function exec(){
        await getSelectedItems().then(function (items){
             var copyFrom = document.createElement('textarea');
            copyFrom.value = items.get_item('Title');
            document.body.appendChild(copyFrom);
            copyFrom.focus();
            copyFrom.select();
            var retVal=document.execCommand('copy');
            if(retVal){
                alert('コピーできました');
            } else{
                alert('コピーできませんでした');
            }
            copyFrom.parentElement.removeChild(copyFrom);
        }).catch(function(error){
            alert(error);
        });
    }
    </script>
    </head>

    <body>
    <input type="button" value="タイトルコピー" onclick="exec();" />
    </body>
    </html>


    • 編集済み mmami 2019年2月23日 1:03
    2019年2月23日 1:03

すべての返信

  • 自己解決です。

    Promise,async,awaitを使わずにコールバックを使用したらEdgeでも動きました。

    <html>

    <head>

    <script language='javaScript' type='text/javascript'>
    function exec(callback){
    JSRequest.EnsureSetup();
    var context = SP.ClientContext.get_current();
    var listId= SP.ListOperation.Selection.getSelectedList();
    var selectedItemIds = SP.ListOperation.Selection.getSelectedItems(context);
    var list= context.get_web().get_lists().getById(listId);
    var currentItem = list.getItemById(parseInt(selectedItemIds[0].id));
    context.load(currentItem,'Title');
    context.executeQueryAsync(null,null);
    callback(currentItem);
    }
    var copyItem = function (item){
    var copyFrom = document.createElement('textarea');
    copyFrom.value = item.get_item('Title');
    document.body.appendChild(copyFrom);
    copyFrom.focus();
    copyFrom.select();
    var retVal=document.execCommand('copy');
    if(retVal){
    alert('コピーできました');
    } else{
    alert('コピーできませんでした');
    }
    copyFrom.parentElement.removeChild(copyFrom);
    }
    </script>
    </head>
    <body>
    <input type="button" value="タイトルコピー" onclick="exec(copyItem);" />
    </body>
    </html>
    • 回答としてマーク mmami 2019年2月24日 5:50
    • 回答としてマークされていない mmami 2019年3月2日 6:17
    2019年2月24日 5:49
  • 上記のコードでも1回目は

    context.executeQueryAsync(null,null);

    の後の

    callback(currentItem);

    で以下のエラーが表示されるのですが、2回目以降のクリックは成功します。

    (promiseやasync,awaitを使った時と同じエラー)

    「プロパティまたはフィールドが初期化されていません。初期化が要求されていないか、その要求が実行されていません。これは、明示的に要求する必要があります。」

    currentItemが取得できておらず、タイトルをexecuteQueryAsyncの非同期処理で取得するのが根本原因だと思いますので

    setTimeOutで間を置くか、非同期処理を使わずにタイトルが取得できればいいのですが、

    何か妙案ある方がいましたらご教示いただきたいです。


    • 編集済み mmami 2019年3月2日 9:42
    2019年3月2日 6:24
  • 要件が分からないのですが、executeQueryAsync のコールバックに直接処理を書くのはダメなんでしょうか?

    context.executeQueryAsync(
         ()=>{alert(currentItem.get_item('Title'))}
    );
    2019年3月4日 7:54
  • ご返信ありがとうございます。

    executeQueryAsyncのコールバックに直接書きますと、

    クリップボードにコピーするducument.execCommand('copy')の戻り値がfalseとなり、

    コピーできません。

    同じような処理の書き方でexecuteQueryAsyncを使わずに取得できるURLのコピーは成功しています。

    (開発者ツールで変数の中身を確認しながら実行したのですが、成功しているときと失敗しているときの違いがないです)

    そこで非同期処理に問題があるのかと思ってPromiseを使ったりcallbackを使って書いているのですが、

    なかなかうまく動作しないといったところです。

    非同期処理を使わずにタイトルを取得できる方法があればうまくいくのかもしれませんが。。

    ※過去、Edgeではdocument.execCommand('copy')が常にfalseを返すという事象も

    あったようですが、既に修正されているようですし、URLはコピーできているので違いそうです。

    https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/14080262/

    • 編集済み mmami 2019年3月5日 15:06 追記
    2019年3月5日 14:55
  • いろいろと試してみているのですが、Microsoft Edge の場合、document.execCommand('copy') はユーザーのアクション以外では false になってしまうんですね…、また、Chrome はそのへんの制限が緩いみたいですが…。セキュリティ上の理由だとは思うのですが、なかなか実現が難しそうですね。

    どこかテキストボックスに値を入れておき、ユーザー操作でそのテキストボックスにフォーカスした時などのトリガーで document.execCommand('copy') を実行するのがシンプルそうですね。

    2019年3月7日 0:47