From 6d02c442fd92e6dfc003787dafa1c62bd3621c6e Mon Sep 17 00:00:00 2001 From: FelisCatus Date: Fri, 19 Dec 2014 23:37:47 +0800 Subject: [PATCH] Add context menu for inspecting elements. Fix #11. --- omega-i18n/en/messages.json | 21 ++++++ omega-i18n/zh_CN/messages.json | 21 ++++++ omega-i18n/zh_HK/messages.json | 21 ++++++ omega-i18n/zh_TW/messages.json | 21 ++++++ .../background.coffee | 50 +++++++++++-- omega-target-chromium-extension/index.coffee | 1 + .../omega_target_web.coffee | 19 ++++- .../overlay/manifest.json | 2 + .../src/inspect.coffee | 70 +++++++++++++++++++ .../src/tabs.coffee | 14 ++++ 10 files changed, 230 insertions(+), 10 deletions(-) create mode 100644 omega-target-chromium-extension/src/inspect.coffee diff --git a/omega-i18n/en/messages.json b/omega-i18n/en/messages.json index c56aed0..d1d57ba 100644 --- a/omega-i18n/en/messages.json +++ b/omega-i18n/en/messages.json @@ -807,6 +807,15 @@ "browserAction_titleExternalProxy": { "message": "Note: The proxy settings are currently controlled by other app(s)." }, + "browserAction_titleInspect": { + "message": "[Inspect] $URL$", + "placeholders": { + "url": { + "content": "$1", + "example": "example.com/image.png" + } + } + }, "browserAction_defaultRuleDetails": { "message": "(default)", "description": "Representation of the default profile being selected on browserAction title." @@ -822,5 +831,17 @@ "browserAction_tempRulePrefix": { "message": "(TEMP) ", "description": "The prefix to indicate a temp rule on browserAction title. Should be very short." + }, + "contextMenu_inspectPage": { + "message": "Inspect proxy used for this page" + }, + "contextMenu_inspectFrame": { + "message": "Inspect proxy used for this Frame" + }, + "contextMenu_inspectLink": { + "message": "Inspect proxy to be used if this Link is opened" + }, + "contextMenu_inspectElement": { + "message": "Inspect proxy used for this Element" } } diff --git a/omega-i18n/zh_CN/messages.json b/omega-i18n/zh_CN/messages.json index 814e209..7cae9a4 100644 --- a/omega-i18n/zh_CN/messages.json +++ b/omega-i18n/zh_CN/messages.json @@ -807,6 +807,15 @@ "browserAction_titleExternalProxy": { "message": "注意:其他应用正在控制当前代理设置。" }, + "browserAction_titleInspect": { + "message": "[检查] $URL$", + "placeholders": { + "url": { + "content": "$1", + "example": "example.com/image.png" + } + } + }, "browserAction_defaultRuleDetails": { "message": "(默认)", "description": "在图标悬停提示上表示选择了默认情景模式作为结果的文字。" @@ -822,5 +831,17 @@ "browserAction_tempRulePrefix": { "message": "(临时) ", "description": "在图标悬停提示上显示临时规则的前缀。文字应该非常短。" + }, + "contextMenu_inspectPage": { + "message": "检查此页面使用的代理" + }, + "contextMenu_inspectFrame": { + "message": "检查此[框架页面]使用的代理" + }, + "contextMenu_inspectLink": { + "message": "检查此[链接目标]将会使用的代理" + }, + "contextMenu_inspectElement": { + "message": "检查此[元素]使用的代理" } } diff --git a/omega-i18n/zh_HK/messages.json b/omega-i18n/zh_HK/messages.json index a1b0cf7..04871ec 100644 --- a/omega-i18n/zh_HK/messages.json +++ b/omega-i18n/zh_HK/messages.json @@ -807,6 +807,15 @@ "browserAction_titleExternalProxy": { "message": "注意:其他程式正在控制當前代理設置。" }, + "browserAction_titleInspect": { + "message": "[檢查] $URL$", + "placeholders": { + "url": { + "content": "$1", + "example": "example.com/image.png" + } + } + }, "browserAction_defaultRuleDetails": { "message": "(默認)", "description": "在圖標懸停提示上表示選擇了默認情景模式作爲結果的文字。" @@ -822,5 +831,17 @@ "browserAction_tempRulePrefix": { "message": "(臨時) ", "description": "在圖標懸停提示上顯示臨時規則的前綴。文字應該非常短。" + }, + "contextMenu_inspectPage": { + "message": "檢查此頁面使用的代理" + }, + "contextMenu_inspectFrame": { + "message": "檢查此[框架頁面]使用的代理" + }, + "contextMenu_inspectLink": { + "message": "檢查此[連結目標]將會使用的代理" + }, + "contextMenu_inspectElement": { + "message": "檢查此[元素]使用的代理" } } diff --git a/omega-i18n/zh_TW/messages.json b/omega-i18n/zh_TW/messages.json index b7f888e..895506a 100644 --- a/omega-i18n/zh_TW/messages.json +++ b/omega-i18n/zh_TW/messages.json @@ -807,6 +807,15 @@ "browserAction_titleExternalProxy": { "message": "注意:其他應用正在控制當前代理設定。" }, + "browserAction_titleInspect": { + "message": "[檢查] $URL$", + "placeholders": { + "url": { + "content": "$1", + "example": "example.com/image.png" + } + } + }, "browserAction_defaultRuleDetails": { "message": "(默認)", "description": "在圖示懸停提示上表示選擇了默認情景模式作為結果的文字。" @@ -822,5 +831,17 @@ "browserAction_tempRulePrefix": { "message": "(臨時) ", "description": "在圖示懸停提示上顯示臨時規則的字首。文字應該非常短。" + }, + "contextMenu_inspectPage": { + "message": "檢查此頁面使用的代理" + }, + "contextMenu_inspectFrame": { + "message": "檢查此[框架頁面]使用的代理" + }, + "contextMenu_inspectLink": { + "message": "檢查此[連結目標]將會使用的代理" + }, + "contextMenu_inspectElement": { + "message": "檢查此[元素]使用的代理" } } diff --git a/omega-target-chromium-extension/background.coffee b/omega-target-chromium-extension/background.coffee index cfa489a..f4e1f46 100644 --- a/omega-target-chromium-extension/background.coffee +++ b/omega-target-chromium-extension/background.coffee @@ -102,14 +102,22 @@ actionForUrl = (url) -> if not details details = options.printProfile(current) - icon = - if profile.name == current.name and options.isCurrentProfileStatic() - if direct - drawIcon(options.profile('direct').color, profile.color) - else - drawIcon(profile.color) + resultColor = profile.color + profileColor = current.color + + icon = null + if profile.name == current.name and options.isCurrentProfileStatic() + if direct + resultColor = options.profile('direct').color + profileColor = profile.color else - drawIcon(profile.color, current.color) + resultColor = profileColor = profile.color + icon = drawIcon(profile.color) + else + resultColor = profile.color + profileColor = current.color + + icon ?= drawIcon(resultColor, profileColor) return { title: chrome.i18n.getMessage('browserAction_titleWithResult', [ currentName @@ -117,6 +125,8 @@ actionForUrl = (url) -> details ]) icon: icon + resultColor: resultColor + profileColor: profileColor } @@ -133,6 +143,32 @@ if chrome.runtime.id != OmegaTargetCurrent.SwitchySharp.extId tabs = new OmegaTargetCurrent.ChromeTabs(actionForUrl) tabs.watch() +inspect = new OmegaTargetCurrent.Inspect (url, tab) -> + if url == tab.url + options.clearBadge() + tabs.processTab(tab) + state.remove('inspectUrl') + return + + state.set({inspectUrl: url}) + + actionForUrl(url).then (action) -> + parsedUrl = OmegaTargetCurrent.Url.parse(url) + if parsedUrl.hostname == OmegaTargetCurrent.Url.parse(tab.url).hostname + urlDisp = parsedUrl.path + else + urlDisp = parsedUrl.hostname + + title = chrome.i18n.getMessage('browserAction_titleInspect', urlDisp) + '\n' + title += action.title + chrome.browserAction.setTitle(title: title, tabId: tab.id) + tabs.setTabBadge(tab, { + text: '#' + color: action.resultColor + }) + +inspect.register() + options.setProxyNotControllable(null) timeout = null diff --git a/omega-target-chromium-extension/index.coffee b/omega-target-chromium-extension/index.coffee index 89f1e86..31e0dec 100644 --- a/omega-target-chromium-extension/index.coffee +++ b/omega-target-chromium-extension/index.coffee @@ -4,6 +4,7 @@ module.exports = ChromeTabs: require('./src/tabs') SwitchySharp: require('./src/switchysharp') ExternalApi: require('./src/external_api.coffee') + Inspect: require('./src/inspect') Url: require('url') for name, value of require('omega-target') diff --git a/omega-target-chromium-extension/omega_target_web.coffee b/omega-target-chromium-extension/omega_target_web.coffee index a1a4e08..eb59cb2 100644 --- a/omega-target-chromium-extension/omega_target_web.coffee +++ b/omega-target-chromium-extension/omega_target_web.coffee @@ -101,12 +101,25 @@ angular.module('omegaTarget', []).factory 'omegaTarget', ($q) -> setDefaultProfile: (profileName, defaultProfileName) -> callBackground('setDefaultProfile', profileName, defaultProfileName) getActivePageInfo: -> - # First, try to clear badges on opening the popup. - callBackground('clearBadge') + clearBadge = true d = $q['defer']() chrome.tabs.query {active: true, lastFocusedWindow: true}, (tabs) -> - d.resolve(tabs[0]?.url) + if not tabs[0]?.url + d.resolve(undefined) + return + getBadge = $q['defer']() + chrome.browserAction.getBadgeText {tabId: tabs[0]?.id}, (result) -> + getBadge.resolve(result) + $q.all([getBadge.promise, omegaTarget.state('inspectUrl') + ]).then ([badge, url]) -> + if badge != '#' || not url + d.resolve(tabs[0]?.url) + else + clearBadge = false + d.resolve(url) return d.promise.then (url) -> + # First, try to clear badges on opening the popup. + callBackground('clearBadge') if clearBadge return null if not url or isChromeUrl(url) urlParser.href = url domain = urlParser.hostname diff --git a/omega-target-chromium-extension/overlay/manifest.json b/omega-target-chromium-extension/overlay/manifest.json index 6afdc29..57c2a64 100644 --- a/omega-target-chromium-extension/overlay/manifest.json +++ b/omega-target-chromium-extension/overlay/manifest.json @@ -29,6 +29,8 @@ "storage", "webRequest", "webRequestBlocking", + "contextMenus", + "http://*/*", "https://*/*", "ftp://*/*", diff --git a/omega-target-chromium-extension/src/inspect.coffee b/omega-target-chromium-extension/src/inspect.coffee new file mode 100644 index 0000000..9bc5af9 --- /dev/null +++ b/omega-target-chromium-extension/src/inspect.coffee @@ -0,0 +1,70 @@ +OmegaTarget = require('omega-target') +OmegaPac = OmegaTarget.OmegaPac +Promise = OmegaTarget.Promise + +module.exports = class Inspect + constructor: (@onInspect) -> + + register: -> + # We don't need this API. However its presence indicates that Chrome >= 35, + # which provides the menuItemId we need in contextMenu callback. + # https://developer.chrome.com/extensions/contextMenus + return unless chrome.i18n.getUILanguage? + + + webResource = [ + "http://*/*" + "https://*/*" + "ftp://*/*" + ] + + chrome.contextMenus.create({ + id: 'inspectPage' + title: chrome.i18n.getMessage('contextMenu_inspectPage') + contexts: ['page'] + onclick: @inspect.bind(this) + documentUrlPatterns: webResource + }) + + chrome.contextMenus.create({ + id: 'inspectFrame' + title: chrome.i18n.getMessage('contextMenu_inspectFrame') + contexts: ['frame'] + onclick: @inspect.bind(this) + documentUrlPatterns: webResource + }) + + chrome.contextMenus.create({ + id: 'inspectLink' + title: chrome.i18n.getMessage('contextMenu_inspectLink') + contexts: ['link'] + onclick: @inspect.bind(this) + targetUrlPatterns: webResource + }) + + chrome.contextMenus.create({ + id: 'inspectElement' + title: chrome.i18n.getMessage('contextMenu_inspectElement') + contexts: [ + 'image' + 'video' + 'audio' + ] + onclick: @inspect.bind(this) + targetUrlPatterns: webResource + }) + + propForMenuItem: + 'inspectPage': 'pageUrl' + 'inspectFrame': 'frameUrl' + 'inspectLink': 'linkUrl' + 'inspectElement': 'srcUrl' + + inspect: (info, tab) -> + return unless info.menuItemId + url = info[@propForMenuItem[info.menuItemId]] + if not url and info.menuItemId == 'inspectPage' + url = tab.url + return unless url + + @onInspect(url, tab) diff --git a/omega-target-chromium-extension/src/tabs.coffee b/omega-target-chromium-extension/src/tabs.coffee index 2325aac..59ea6cd 100644 --- a/omega-target-chromium-extension/src/tabs.coffee +++ b/omega-target-chromium-extension/src/tabs.coffee @@ -1,6 +1,7 @@ class ChromeTabs _dirtyTabs: {} _defaultAction: null + _badgeTab: null constructor: (@actionForUrl) -> return @@ -34,6 +35,10 @@ class ChromeTabs @processTab(tab, changeInfo) processTab: (tab, changeInfo) -> + if @_badgeTab + for own id of @_badgeTab + try chrome.browserAction.setBadgeText(text: '', tabId: id) + @_badgeTab = null if not tab.url? or tab.url.indexOf("chrome") == 0 chrome.browserAction.setTitle(title: @_defaultAction.title, tabId: tab.id) @clearIcon tab.id @@ -42,6 +47,15 @@ class ChromeTabs @setIcon(action.icon, tab.id) chrome.browserAction.setTitle(title: action.title, tabId: tab.id) + setTabBadge: (tab, badge) -> + @_badgeTab ?= {} + @_badgeTab[tab.id] = true + chrome.browserAction.setBadgeText(text: badge.text, tabId: tab.id) + chrome.browserAction.setBadgeBackgroundColor( + color: badge.color + tabId: tab.id + ) + setIcon: (icon, tabId) -> if tabId? chrome.browserAction.setIcon({