【ブックマークレット】画面をスリープさせない

# ページを見ている時にスリープされないようにする
レシピを見ている時に画面がスリープされること、ありませんか？
そんなときに役立つブックマークレットのご紹介です！

実行するとこのようになり、スイッチがオンになっているときには画面がスリープしないようになります。

![IMG_7211.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764553/d366a246-424c-1a2d-772f-bd03d1e73055.jpeg)


元々、クラシルのサイトでは料理モードという名前でスリープしない機能がありました。
それをすべてのサイトで使えるようにしたいと思い作成しました。

![IMG_7208.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1764553/73f3f53a-8910-8403-c755-0a7fd9084988.jpeg)

仕組みとしてはScreen Wake Lock APIを使用しています。
仕様でタブがアクティブでなくなった時にはロックは解除されるようになっているのですが、再びロックを取ることはせず、オフのままにしています。

https://developer.mozilla.org/ja/docs/Web/API/Screen_Wake_Lock_API


# コード
以下のコードをコピーしてブックマークに登録してください。
登録の仕方は「ブックマークレット」で検索すると出てくるかと思います。
```js
javascript:(function(){let wakeLock=null;const root=document.createElement('div');const shadowRoot=root.attachShadow({mode:"open"});shadowRoot.innerHTML='<div class="button"><div class="switch"><input type="checkbox"><span class="slider"></span></div></div>';const button=shadowRoot.querySelector('div.button');const checkbox=shadowRoot.querySelector('input[type="checkbox"]');async function requestWakeLock(){try{wakeLock=await navigator.wakeLock.request('screen');checkbox.checked=true;wakeLock.addEventListener('release',()=>{checkbox.checked=false;});}catch(err){button.style.background='rgba(255,0,0,0.7)';console.error(`${err.name},${err.message}`);}}function releaseWakeLock(){if(wakeLock!==null){wakeLock.release();}}button.addEventListener('click',(e)=>{if(wakeLock!==null&&!wakeLock.released){releaseWakeLock();}else{requestWakeLock();}});requestWakeLock();const style=document.createElement('style');style.innerHTML='.button{display:flex;align-items:center;justify-content:center;position:fixed;padding:7.5px;bottom:20px;right:20px;z-index:1000;border-radius:10px;background:rgba(128,128,128,0.7);color:white;font-size:24px;cursor:pointer;}.switch{position:relative;width:45px;height:25.5px;}.switch input{opacity:0;width:0;height:0;}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;transition:.4s;border-radius:25.5px;}.slider:before{position:absolute;content:"";height:19.5px;width:19.5px;left:3px;bottom:3px;background-color:white;transition:.4s;border-radius:50%;}input:checked+.slider{background-color:#2196F3;}input:checked+.slider:before{transform:translateX(19.5px);}';shadowRoot.appendChild(style);document.body.appendChild(root);})();
```

min化する前のコード
```js
javascript: (function() {
  let wakeLock = null;

  const root = document.createElement('div');
  const shadowRoot = root.attachShadow({ mode: "open" });
  shadowRoot.innerHTML = `
    <div class="button">
        <div class="switch">
            <input type="checkbox">
            <span class="slider round"></span>
        </div>
    </div>`;

  const button = shadowRoot.querySelector('div.button');
  const checkbox = shadowRoot.querySelector('input[type="checkbox"]');

  async function requestWakeLock() {
    try {
      wakeLock = await navigator.wakeLock.request('screen');
      checkbox.checked = true;
      wakeLock.addEventListener('release', () => {
        checkbox.checked = false;
      });
    } catch (err) {
      button.style.background = 'rgba(255, 0, 0, 0.7)';
      console.error(`${err.name}, ${err.message}`);
    }
  }

  function releaseWakeLock() {
    if (wakeLock !== null) {
      wakeLock.release();
    }
  }

  button.addEventListener('click', (e) => {
    if (wakeLock!==null&&!wakeLock.released) {
      releaseWakeLock();
    } else {
      requestWakeLock();
    }
  });

  requestWakeLock();

  const style = document.createElement('style');
  style.innerHTML = `
    .button{
        display: flex;
        align-items: center;
        justify-content: center;
        position: fixed;
        padding: 7.5px;
        bottom: 20px;
        right: 20px;
        z-index: 1000;
        border-radius: 10px;
        background: rgba(128, 128, 128, 0.7);
        color: white;
        font-size: 24px;
        cursor: pointer;
    }
    .switch {
      position: relative;
      width: 45px;
      height: 25.5px;
    }
    .switch input {
      opacity: 0;
      width: 0;
      height: 0;
    }
    .slider {
      position: absolute;
      cursor: pointer;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: #ccc;
      transition: .4s;
      border-radius: 25.5px;
    }
    .slider:before {
      position: absolute;
      content: "";
      height: 19.5px;
      width: 19.5px;
      left: 3px;
      bottom: 3px;
      background-color: white;
      transition: .4s;
      border-radius: 50%;
    }
    input:checked + .slider {
      background-color: #2196F3;
    }
    input:checked + .slider:before {
      transform: translateX(19.5px);
    }
  `;
  shadowRoot.appendChild(style);
  document.body.appendChild(root);
})();
```

# コメント

UIはChatGPTに「フローティングのトグルスイッチを表示し、Wake Lock APIを使用して画面がロックされるのを防ぐブックマークレットを作って」とお願いして、追加で注文して直してもらったものそのままです。

Shadow DOMを使うようにする、divの代わりにlabelで囲っていたせいでclickイベントが二重に発生しておかしくなっているなどロジックの一部は自分で修正しました。


それでも出力速度が爆速かつ修正も対応してくれるので一から作るよりよい開発体験でした。