imported>=海豚= |
imported>=海豚= |
第1行: |
第1行: |
| $(() => {
| | 基于批量上传工具 的 文 件 上传 |
| const notificationIcon = 'https://img.moegirl.org.cn/common/thumb/f/f6/%E8%93%9D%E8%90%8C%E5%AD%97.png/233px-%E8%93%9D%E8%90%8C%E5%AD%97.png'
| |
| const workerUrl = window.mw ?
| |
| '/index.php?title=User:東東君/js/notification.js&action=raw&ctype=text/javascript' :
| |
| 'notification.js'
| |
|
| |
| checkNotificationPermission()
| |
| main()
| |
|
| |
| async function main() {
| |
| const worker = await registerService()
| |
| const configListener = new WorkerDataListener(worker, 'config')
| |
| const uiController = initUI({ onSaveConfig })
| |
|
| |
| configListener.pullData()
| |
| | |
| configListener.addListener(data => {
| |
| uiController.updateConfig(data)
| |
| })
| |
|
| |
| function onSaveConfig(config) {
| |
| worker.postMessage({ type: 'saveConfig', data: { config } })
| |
| alert('配置已保存')
| |
| }
| |
| }
| |
| | |
| navigator.serviceWorker.addEventListener('message', e => {
| |
| const { type, data } = e.data
| |
| if (type === 'sendNotification') {
| |
| const [title, options] = data
| |
| const link = options.data.link
| |
| new Notification(title, options).onclick = () => window.open(link, '_blank')
| |
| }
| |
| })
| |
|
| |
| function initUI({
| |
| onSaveConfig
| |
| }) {
| |
| const template = `
| |
| <div class="widget-notification-config" style="display:none;">
| |
| <div class="body">
| |
| <fieldset>
| |
| <legend>设置</legend>
| |
| <form class="settings" action="javascript:void(0)">
| |
| <label>
| |
| <span>开启</span>
| |
| <input type="checkbox" name="enable">
| |
| </label>
| |
|
| |
| <label>
| |
| <div>排除条目:</div>
| |
| <textarea placeholder="当其中 的 条目发生变化时不会通知,使用换行分割" name="excludeList"></textarea>
| |
| </label>
| |
|
| |
| <div class="buttonGroup">
| |
| <button class="saveConfig">保存</button>
| |
| <button class="closeModal">关闭</button>
| |
| </div>
| |
| </form>
| |
| </fieldset>
| |
| </div>
| |
| </div>
| |
| `
| |
|
| |
| const cssStyle = `
| |
| <style>
| |
| .widget-notification-config {
| |
| position: fixed;
| |
| top: 0;
| |
| left: 0;
| |
| right: 0;
| |
| bottom: 0;
| |
| background-color: rgba(0, 0, 0, 0.2);
| |
| font-size: 14px;
| |
| z-index: 100;
| |
| }
| |
|
| |
| .widget-notification-config > .body {
| |
| background-color: white;
| |
| width: 300px;
| |
| box-sizing: border-box;
| |
| padding: 10px;
| |
| border-radius: 5px;
| |
| border: 2px #ccc ridge;
| |
| position: absolute;
| |
| top: 50%;
| |
| left: 50%;
| |
| transform: translate(-50%, -50%);
| |
| }
| |
|
| |
| .widget-notification-config > .body fieldset {
| |
| margin: 0;
| |
| padding-left: 15px;
| |
| padding-right: 15px;
| |
| }
| |
|
| |
| .widget-notification-config > .body .settings > label {
| |
| display: block;
| |
| }
| |
|
| |
| .widget-notification-config > .body .settings > label > * {
| |
| vertical-align: middle;
| |
| }
| |
|
| |
| .widget-notification-config > .body .settings textarea[name="excludeList"] {
| |
| width: -webkit-fill-available;
| |
| resize: none;
| |
| margin-top: 5px;
| |
| height: 100px;
| |
| border: 1px #666 solid;
| |
| }
| |
|
| |
| .widget-notification-config > .body .settings .buttonGroup {
| |
| margin: 0 auto;
| |
| margin-top: 10px;
| |
| display: table;
| |
| }
| |
|
| |
| .widget-notification-config > .body .settings .buttonGroup button {
| |
| margin: 0 5px;
| |
| }
| |
| </style>
| |
| `
| |
|
| |
| $('body').append(template).append(cssStyle)
| |
|
| |
| const rootEl = $('.widget-notification-config')
| |
| const settingsEl = rootEl.find('.settings')
| |
|
| |
| // 注入按钮
| |
| $('#p-cactions ul').append('<li id="widget-notification-showConfig"><a title="实时通知">实时通知</a></li>')
| |
|
| |
| // modal显示事件
| |
| $('#widget-notification-showConfig').on('click', () => rootEl.show())
| |
|
| |
| // modal关闭事件
| |
| rootEl.find('.closeModal').on('click', () => rootEl.hide())
| |
|
| |
| // 保存配置
| |
| rootEl.find('.saveConfig').on('click', e => {
| |
| const formValues = {
| |
| enable: settingsEl.find('[name="enable"]').prop('checked'),
| |
| listenNotification: settingsEl.find('[name="listenNotification"]').prop('checked'),
| |
| excludeList: settingsEl.find('[name="excludeList"]').val().trim().split('\n')
| |
| }
| |
|
| |
| onSaveConfig(formValues)
| |
| })
| |
|
| |
| function updateConfig({ enable, listenNotification, excludeList }) {
| |
| settingsEl.find('[name="enable"]').prop('checked', enable)
| |
| settingsEl.find('[name="listenNotification"]').prop('checked', listenNotification)
| |
| settingsEl.find('[name="excludeList"]').val(excludeList.join('\n'))
| |
| }
| |
|
| |
| return {
| |
| updateConfig
| |
| }
| |
| }
| |
|
| |
| function registerService() {
| |
| return new Promise(async (resolve, reject) => {
| |
| if (Notification === undefined || navigator.serviceWorker === undefined) {
| |
| alert('当前浏览器不支持通知插件,请从您的用户页中移除!')
| |
| return reject()
| |
| }
| |
|
| |
| if(Notification.permission === 'default') {
| |
| alert('点击确定关闭这条消息后,将弹出授予通知权限的窗口,届时请点击“允许”,以保证插件的正常运行。')
| |
| }
| |
|
| |
| await new Promise(Notification.requestPermission)
| |
| const status = Notification.permission
| |
|
| |
| if (status === 'granted') {
| |
| if (localStorage.getItem('moegirl-widget-notification-permission-granted') !== 'true') {
| |
| localStorage.setItem('moegirl-widget-notification-permission-granted', 'true')
| |
| new Notification('欢迎', {
| |
| body: '您已经成功开启实时通知功能,欢迎使用!',
| |
| icon: notificationIcon
| |
| })
| |
| }
| |
| }
| |
|
| |
| if (status === 'denied') {
| |
| alert('您未能正确授予通知权限,若要继续使用,请在url栏左侧点击小锁标志开启权限,若无法设置,请从你的用户页删去此插 件 。')
| |
| return reject()
| |
| }
| |
|
| |
| const serviceWorkerRegistration = await navigator.serviceWorker.register(workerUrl)
| |
| await navigator.serviceWorker.ready
| |
| resolve(serviceWorkerRegistration.active)
| |
| })
| |
| }
| |
| | |
| function checkNotificationPermission() {
| |
| if (localStorage.getItem('moegirl-widget-notification-permission-granted') === 'true' && Notification.permission !== 'granted') {
| |
| localStorage.removeItem('moegirl-widget-notification-permission-granted')
| |
| }
| |
| }
| |
|
| |
| class WorkerDataListener {
| |
| broadcastName = ''
| |
| worker = null
| |
| data = null
| |
| #incrementPullId = 0
| |
| | |
| get pullEventName() { return 'get-' + this.broadcastName }
| |
| get broadcastChannelName() { return 'channel-' + this.broadcastName }
| |
|
| |
| constructor(worker, broadcastName) {
| |
| this.broadcastName = broadcastName
| |
| this.worker = worker
| |
| this.broadcastChannel = new BroadcastChannel(this.broadcastChannelName)
| |
|
| |
| this.addListener(data => this.data = data)
| |
| }
| |
|
| |
| addListener(handler) {
| |
| const usingHandler = e => {
| |
| const { type, data, id } = e.data
| |
| type === 'broadcast' && handler(data, id)
| |
| }
| |
| | |
| this.broadcastChannel.addEventListener('message', usingHandler)
| |
| return () => this.broadcastChannel.removeEventListener('message', usingHandler)
| |
| }
| |
|
| |
| pullData() {
| |
| const pullId = this.#incrementPullId++
| |
| this.worker.postMessage({ type: this.pullEventName, data: { id: pullId } })
| |
| return pullId
| |
| }
| |
|
| |
| getData() {
| |
| return new Promise(resolve => {
| |
| const pullId = this.pullData()
| |
| const removeListener = this.addListener((data, id) => {
| |
| if (id !== pullId) { return }
| |
| resolve(data)
| |
| removeListener()
| |
| })
| |
| })
| |
| }
| |
| }
| |
| })
| |