From b019038f5701b67d475a36275fcbe69ac5d6ee04 Mon Sep 17 00:00:00 2001 From: Jason Barnabe Date: Sun, 15 Apr 2012 20:56:12 -0500 Subject: [PATCH] initial commit --- 128.png | Bin 0 -> 4936 bytes 16.png | Bin 0 -> 661 bytes 19.png | Bin 0 -> 825 bytes 48.png | Bin 0 -> 2346 bytes _locales/de/messages.json | 151 +++++++++++++++ _locales/en/messages.json | 226 +++++++++++++++++++++ _locales/es/messages.json | 148 ++++++++++++++ _locales/te/messages.json | 55 ++++++ _locales/zh/messages.json | 175 +++++++++++++++++ _locales/zh_CN/messages.json | 175 +++++++++++++++++ apply.js | 113 +++++++++++ background.html | 5 + background.js | 78 ++++++++ edit.html | 108 +++++++++++ edit.js | 277 ++++++++++++++++++++++++++ help.png | Bin 0 -> 786 bytes install.js | 50 +++++ localization.js | 19 ++ manage.html | 102 ++++++++++ manage.js | 281 +++++++++++++++++++++++++++ manifest.json | 37 ++++ messaging.js | 21 ++ popup.html | 117 +++++++++++ storage.js | 366 +++++++++++++++++++++++++++++++++++ world_go.png | Bin 0 -> 944 bytes 25 files changed, 2504 insertions(+) create mode 100644 128.png create mode 100644 16.png create mode 100644 19.png create mode 100644 48.png create mode 100644 _locales/de/messages.json create mode 100644 _locales/en/messages.json create mode 100644 _locales/es/messages.json create mode 100644 _locales/te/messages.json create mode 100644 _locales/zh/messages.json create mode 100644 _locales/zh_CN/messages.json create mode 100644 apply.js create mode 100644 background.html create mode 100644 background.js create mode 100644 edit.html create mode 100644 edit.js create mode 100644 help.png create mode 100644 install.js create mode 100644 localization.js create mode 100644 manage.html create mode 100644 manage.js create mode 100644 manifest.json create mode 100644 messaging.js create mode 100644 popup.html create mode 100644 storage.js create mode 100644 world_go.png diff --git a/128.png b/128.png new file mode 100644 index 0000000000000000000000000000000000000000..b79792face65dc78241bf6a80ba02609e8cf3d3a GIT binary patch literal 4936 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 E4=6;6>Hq)$ literal 0 HcmV?d00001 diff --git a/16.png b/16.png new file mode 100644 index 0000000000000000000000000000000000000000..ca39cc8250c328fdb13c4e171a9a4b3be4ed9a34 GIT binary patch literal 661 zcmV;G0&4wPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01m+b01m+cxRGn^00007bV*G`2ipk| z0x>9|^l#w+00I?BL_t(I%cYY~Xp(UlfS+$T*AgO8aiEZqWFQ?(9F-teb4EptBo?zE z>JS96ON(x%*n-wo3YMdT)hT19qb(X%ofdGj_f^xYGfJURi>-7?g#Ykl`-2OD*Trjt| zj3|njbr-mLMaS9R!-T_OL{S8wtE&rn$FAmrbAyjC8jTFzm2r2ja-%=TiWDIdiLB@7 z_4?*hP^;CHN+puXB;(`bJV=z#YPE#J)lF3tg&*ZL=7*kDAMCf(3uIZQy}g}aFi0>M zY*^iRJkG(M^UW)`cE*F#>BR5%<8V0W=;%NY1Qr$+NN2{_X6vN0`($&$DfeDN4~LkZ v{6O)&g7{5A5TLJbjgfbA8(yQZ*>nB}2YR^_r(H~800000NkvXXu0mjfob4;s literal 0 HcmV?d00001 diff --git a/19.png b/19.png new file mode 100644 index 0000000000000000000000000000000000000000..6f180610c33139e89ce4168a59ec3d39f6c781a2 GIT binary patch literal 825 zcmV-91IGM`P)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01m+b01m+cxRGn^00007bV*G`2ipk| z0y81%9<|2+00Oy5L_t(I%dM1MNRx3C#(#g6p))PZ6y4kq%@?y67BldxP*97^5fNcj zAcz-+LJ|hyMP+!Q(S^{3g+g@G2d`J6&?jPSflN~yX^7hr!&uk7?I8>d(sPbb2a|SCW^PM@&o%Uayyli3zM$EB#I< z-#<)qagRPUSsiL2HM)%P!t6r1a7w* zhr@wJqd}4+bUGbTQBfNj{6X0I!24wpv)Qc1cDtR@@*Mg{Zc$uZj9#xNH`PE#M+Yg| z$l#Nm%Zy_|v(02vt>SR77pI77=UEG(qEyPH{0Dor;6lvMc1FYyDAkdUC(x!rEA-jnIH zIq9@HgOh1A8Y~tIlarHpJRW*`dy!=sm&-+VcD5?@;o~Qy?K==!W_)Zk;8Tr{kB_IU ztZc&vAp|`=Jy;rAHeZcQV3f0 z3;X}o&_-&QnwsKv^E8U`Ouc6jJ5~Wye}X}5<)!@v^A!*myp3+R00000NkvXXu0mjf Dao1(r literal 0 HcmV?d00001 diff --git a/48.png b/48.png new file mode 100644 index 0000000000000000000000000000000000000000..7338c4d1afd1718df4781f03578977f8d3d63000 GIT binary patch literal 2346 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 QBme*a07*qoM6N<$f+kaXlmGw# literal 0 HcmV?d00001 diff --git a/_locales/de/messages.json b/_locales/de/messages.json new file mode 100644 index 00000000..c528f592 --- /dev/null +++ b/_locales/de/messages.json @@ -0,0 +1,151 @@ +{ + "addStyleTitle": { + "message": "Neuer Stil" + }, + "appliesAdd": { + "message": "Hinzufügen" + }, + "appliesDisplay": { + "message": "Wird angewendet auf: $applies$", + "placeholders": { + "applies": { + "content": "$1" + } + } + }, + "appliesDisplayTruncatedSuffix": { + "message": "und mehr" + }, + "appliesDomainOption": { + "message": "URLs auf der Domäne" + }, + "appliesHelp": { + "message": "Nutzen Sie \"Anwenden auf\" um festzulegen, auf welche URLs der Code in diesem Abschnitt angewendet wird." + }, + "appliesLabel": { + "message": "Anwenden auf" + }, + "appliesRemove": { + "message": "Entfernen" + }, + "appliesSpecify": { + "message": "Genauer..." + }, + "appliesToEverything": { + "message": "Alles" + }, + "appliesUrlOption": { + "message": "URL" + }, + "appliesUrlPrefixOption": { + "message": "URLs beginnend mit" + }, + "checkForUpdate": { + "message": "Nach Update suchen" + }, + "checkingForUpdate": { + "message": "Suche..." + }, + "deleteStyleLabel": { + "message": "Entfernen" + }, + "deleteStyleConfirm": { + "message": "Möchten Sie diesen Stil wirklich entfernen?" + }, + "disableStyleLabel": { + "message": "Deaktivieren" + }, + "editStyleHeading": { + "message": "Stil bearbeiten" + }, + "editStyleLabel": { + "message": "Bearbeiten" + }, + "editStyleTitle": { + "message": "\"$stylename$\" bearbeiten", + "placeholders": { + "stylename": { + "content": "$1" + } + } + }, + "enableStyleLabel": { + "message": "Aktivieren" + }, + "findStylesForSite": { + "message": "Stile für diese Seite suchen" + }, + "helpAlt": { + "message": "Hilfe" + }, + "installUpdate": { + "message": "Update installieren" + }, + "manageHeading": { + "message": "Installierte Stile" + }, + "manageTitle": { + "message": "Stylish" + }, + "noStylesForSite": { + "message": "Für diese Seite wurden keine Stile installiert." + }, + "sectionAdd": { + "message": "Neuen Abschnitt hinzufügen" + }, + "sectionCode": { + "message": "Code" + }, + "sectionHelp": { + "message": "Abschnitte unterteilen den Code eines Stils in verschiedene Teile, die auf verschiedene URLs angewendet werden. So könnte z.B. ein Stil die Startseite einer Website anders gestalten als den Rest der Website." + }, + "sectionRemove": { + "message": "Abschnitt löschen" + }, + "styleCancelEditLabel": { + "message": "Zurück zur Übersicht" + }, + "styleChangesNotSaved": { + "message": "Sie haben Änderungen an diesem Stil noch nicht gespeichert." + }, + "styleEnabledLabel": { + "message": "Aktiviert" + }, + "styleInstall": { + "message": "Möchten Sie \"$stylename$\" mit Stylish installieren?", + "placeholders": { + "stylename": { + "content": "$1" + } + } + }, + "styleMissingName": { + "message": "Geben Sie einen Namen ein." + }, + "styleNameLabel": { + "message": "Name" + }, + "styleSaveLabel": { + "message": "Speichern" + }, + "styleSectionsTitle": { + "message": "Abschnitte" + }, + "updateCheckFailBadResponseCode": { + "message": "Update gescheitert - Server meldet Code $code$.", + "placeholders": { + "code": { + "content": "$1" + } + } + }, + "updateCheckFailServerUnreachable": { + "message": "Update gescheitert - Server nicht erreichbar." + }, + "updateCheckSucceededNoUpdate": { + "message": "Stil ist aktuell." + }, + "updateCompleted": { + "message": "Update fertiggestellt." + } +} \ No newline at end of file diff --git a/_locales/en/messages.json b/_locales/en/messages.json new file mode 100644 index 00000000..64e407be --- /dev/null +++ b/_locales/en/messages.json @@ -0,0 +1,226 @@ +{ + "addStyleLabel": { + "message": "Write new style", + "description": "Label for the button to go to the add style page" + }, + "addStyleTitle": { + "message": "Add Style", + "description": "Title of the page for adding styles" + }, + "appliesAdd": { + "message": "Add", + "description": "Label for the button to add an 'applies' entry" + }, + "appliesDisplay": { + "message": "Applies to: $applies$", + "description": "Text on the manage screen to describe what the style applies to", + "placeholders": { + "applies": { + "content": "$1" + } + } + }, + "appliesDisplayTruncatedSuffix": { + "message": "and more", + "description": "Text added to appliesDisplay when there are more sites for the style than are displayed" + }, + "appliesDomainOption": { + "message": "URLs on the domain", + "description": "Option to make the style apply to the entered string as a domain" + }, + "appliesHelp": { + "message": "Use the 'Applies to' controls to limit what URLs the code in this section applies to.", + "description": "Help text for 'applies to' section" + }, + "appliesLabel": { + "message": "Applies to", + "description": "Label for 'applies to' fields on the edit\/add screen" + }, + "appliesRegexpOption": { + "message": "URLs matching the regexp", + "description": "Option to make the style apply to the entered string as a regular expression" + }, + "appliesRemove": { + "message": "Remove", + "description": "Label for the button to remove an 'applies' entry" + }, + "appliesSpecify": { + "message": "Specify", + "description": "Label for the button to make a style apply only to specific sites" + }, + "appliesToEverything": { + "message": "Everything", + "description": "Text displayed for styles that apply to all sites" + }, + "appliesUrlOption": { + "message": "URL", + "description": "Option to make the style apply to the entered string as a URL" + }, + "appliesUrlPrefixOption": { + "message": "URLs starting with", + "description": "Option to make the style apply to the entered string as a URL prefix" + }, + "checkAllUpdates": { + "message": "Check all styles for updates", + "description": "Label for the button to check all styles for updates" + }, + "checkForUpdate": { + "message": "Check for update", + "description": "Label for the button to check a single style for an update" + }, + "checkingForUpdate": { + "message": "Checking...", + "description": "Text to display when checking a style for an update" + }, + "deleteStyleLabel": { + "message": "Delete", + "description": "Label for the button to delete a style" + }, + "deleteStyleConfirm": { + "message": "Are you sure you want to delete this style?", + "description": "Confirmation before deleting a style" + }, + "description": { + "message": "Restyle the web with Stylish, a user styles manager. Stylish lets you easily install themes and skins for Google, Facebook, YouTube, Orkut, and many, many other sites.", + "description": "Extension description" + }, + "disableStyleLabel": { + "message": "Disable", + "description": "Label for the button to disable a style" + }, + "editStyleHeading": { + "message": "Edit Style", + "description": "Title of the page for editing styles" + }, + "editStyleLabel": { + "message": "Edit", + "description": "Label for the button to go to the edit style page" + }, + "editStyleTitle": { + "message": "Edit Style $stylename$", + "description": "Title of the page for editing styles", + "placeholders": { + "stylename": { + "content": "$1" + } + } + }, + "enableStyleLabel": { + "message": "Enable", + "description": "Label for the button to enable a style" + }, + "findStylesForSite": { + "message": "Find more styles for this site.", + "description": "Text for a link that gets a list of styles for the current site" + }, + "helpAlt": { + "message": "Help", + "description": "Alternate text for help buttons" + }, + "installUpdate": { + "message": "Install update", + "description": "Label for the button to install an update for a single style" + }, + "manageHeading": { + "message": "Installed Styles", + "description": "Heading for the manage page" + }, + "manageText": { + "message": "Visit userstyles.org<\/a> for pre-made styles. Ask in the forum<\/a> if you need help.", + "description": "Help text on the manage page" + }, + "manageTitle": { + "message": "Stylish", + "description": "Title for the manage page" + }, + "noStylesForSite": { + "message": "No styles installed for this site.", + "description": "Text displayed when no styles are installed for the current site" + }, + "openManage": { + "message": "Manage installed styles.", + "description": "Link to open the manage page." + }, + "sectionAdd": { + "message": "Add another section", + "description": "Label for the button to add a section" + }, + "sectionCode": { + "message": "Code", + "description": "Label for the code for a section" + }, + "sectionHelp": { + "message": "Sections let you define different pieces of code to apply to different sets of URLs in the same style. For example, a single style could change the homepage of a site one way, while changing the rest of a site another way.", + "description": "Help text for sections" + }, + "sectionRemove": { + "message": "Remove section", + "description": "Label for the button to remove a section" + }, + "styleCancelEditLabel": { + "message": "Back to manage", + "description": "Label for cancel button for style editing" + }, + "styleChangesNotSaved": { + "message": "You've made changes to this style without saving.", + "description": "Text for the prompt when changes are made to a style and the user tries to leave without saving" + }, + "styleEnabledLabel": { + "message": "Enabled", + "description": "Label for the enabled state of styles" + }, + "styleInstall": { + "message": "Install '$stylename$' into Stylish?", + "description": "Confirmation when installing a style", + "placeholders": { + "stylename": { + "content": "$1" + } + } + }, + "styleMissingName": { + "message": "Enter a name.", + "description": "Error displayed when user saves without providing a name" + }, + "styleNameLabel": { + "message": "Name", + "description": "Label for the name of styles" + }, + "styleSaveLabel": { + "message": "Save", + "description": "Label for save button for style editing" + }, + "styleSectionsTitle": { + "message": "Sections", + "description": "Title for the style sections section" + }, + "styleToMozillaFormat": { + "message": "To Mozilla format", + "description": "Label for the button that converts the code to Mozilla format" + }, + "styleToMozillaFormatHelp": { + "message": "The Mozilla format of the code can be used with Stylish for Firefox and can be submitted to userstyles.org.", + "description": "Help info for the button that converts the code to Mozilla format" + }, + "updateCheckFailBadResponseCode": { + "message": "Update failed - server responded with code $code$.", + "description": "Text that displays when an update check failed because the response code indicates an error", + "placeholders": { + "code": { + "content": "$1" + } + } + }, + "updateCheckFailServerUnreachable": { + "message": "Update failed - server unreachable.", + "description": "Text that displays when an update check failed because the update server is unreachable" + }, + "updateCheckSucceededNoUpdate": { + "message": "Style is up to date.", + "description": "Text that displays when an update check completed and no update is available" + }, + "updateCompleted": { + "message": "Update completed.", + "description": "Text that displays when an update completed" + } +} \ No newline at end of file diff --git a/_locales/es/messages.json b/_locales/es/messages.json new file mode 100644 index 00000000..74cd784b --- /dev/null +++ b/_locales/es/messages.json @@ -0,0 +1,148 @@ +{ + "addStyleTitle": { + "message": "Añadir Estilo" + }, + "appliesAdd": { + "message": "Añadir" + }, + "appliesDisplay": { + "message": "Aplica para: $applies$", + "placeholders": { + "applies": { + "content": "$1" + } + } + }, + "appliesDisplayTruncatedSuffix": { + "message": "y más" + }, + "appliesDomainOption": { + "message": "URL en el dominio" + }, + "appliesHelp": { + "message": "Use los controles de \"Aplicar a\" para limitar a cuales URL aplica el código en esta sección." + }, + "appliesLabel": { + "message": "Aplica a" + }, + "appliesRemove": { + "message": "Eliminar" + }, + "appliesSpecify": { + "message": "Especificar" + }, + "appliesToEverything": { + "message": "Todo" + }, + "appliesUrlOption": { + "message": "URL" + }, + "appliesUrlPrefixOption": { + "message": "URL comenzando con" + }, + "checkForUpdate": { + "message": "Revisar actualizaciones" + }, + "checkingForUpdate": { + "message": "Verificando..." + }, + "deleteStyleLabel": { + "message": "Borrar" + }, + "deleteStyleConfirm": { + "message": "¿Estás seguro de que quieres eliminar este estilo?" + }, + "disableStyleLabel": { + "message": "Desactivar" + }, + "editStyleHeading": { + "message": "Editar Estilo" + }, + "editStyleLabel": { + "message": "Editar" + }, + "editStyleTitle": { + "message": "Editar Estilo $stylename$", + "placeholders": { + "stylename": { + "content": "$1" + } + } + }, + "enableStyleLabel": { + "message": "Activar" + }, + "findStylesForSite": { + "message": "Encontrar más estilos para este sitio." + }, + "helpAlt": { + "message": "Ayuda" + }, + "installUpdate": { + "message": "Instalar actualización" + }, + "manageHeading": { + "message": "Estilos Instalados" + }, + "manageTitle": { + "message": "Stylish" + }, + "noStylesForSite": { + "message": "No hay estilos instalados para este sitio." + }, + "sectionAdd": { + "message": "Añadir otra sección" + }, + "sectionHelp": { + "message": "Las secciones te permiten definir diferentes trozos de código a ser aplicados a diferentes juegos de URL en el mismo estilo. Por ejemplo, un estilo particular puede cambiar la página de inicio de un sitio de una forma, mientras cambia el resto del sitio de otra." + }, + "sectionRemove": { + "message": "Eliminar sección" + }, + "styleCancelEditLabel": { + "message": "Atrás para manejar" + }, + "styleChangesNotSaved": { + "message": "Has realizado cambios a este estilo sin guardar." + }, + "styleEnabledLabel": { + "message": "Activado" + }, + "styleInstall": { + "message": "¿Instalar \"$stylename$\" en Stylish?", + "placeholders": { + "stylename": { + "content": "$1" + } + } + }, + "styleMissingName": { + "message": "Ingrese un nombre." + }, + "styleNameLabel": { + "message": "Nombre" + }, + "styleSaveLabel": { + "message": "Guardar" + }, + "styleSectionsTitle": { + "message": "Secciones" + }, + "updateCheckFailBadResponseCode": { + "message": "Actualización fallida - el servidor respondió con el código $code$.", + "placeholders": { + "code": { + "content": "$1" + } + } + }, + "updateCheckFailServerUnreachable": { + "message": "Actualización fallida - no se encuentra el servidor." + }, + "updateCheckSucceededNoUpdate": { + "message": "El estilo se actualizó." + }, + "updateCompleted": { + "message": "Actualización completa." + } +} \ No newline at end of file diff --git a/_locales/te/messages.json b/_locales/te/messages.json new file mode 100644 index 00000000..a97a620a --- /dev/null +++ b/_locales/te/messages.json @@ -0,0 +1,55 @@ +{ + "appliesAdd": { + "message": "చేర్చు" + }, + "appliesDisplay": { + "message": "వేటికి వర్తిస్తుంది; $applies$", + "placeholders": { + "applies": { + "content": "$1" + } + } + }, + "appliesDisplayTruncatedSuffix": { + "message": "ఇంకా మరిన్ని" + }, + "appliesRemove": { + "message": "తొలగించు" + }, + "appliesToEverything": { + "message": "అన్నిటికీ" + }, + "deleteStyleLabel": { + "message": "తొలగించు" + }, + "deleteStyleConfirm": { + "message": "మీరు నజంగానే ఈ శైలిని తొలగించాలనుకుంటున్నారా?" + }, + "disableStyleLabel": { + "message": "అచేతనించు" + }, + "editStyleLabel": { + "message": "మార్చు" + }, + "enableStyleLabel": { + "message": "చేతనించు" + }, + "helpAlt": { + "message": "సహాయం" + }, + "manageHeading": { + "message": "స్థాపిత శైలులు" + }, + "manageTitle": { + "message": "స్టైలిష్" + }, + "styleNameLabel": { + "message": "పేరు" + }, + "styleSaveLabel": { + "message": "భద్రపరచు" + }, + "styleSectionsTitle": { + "message": "విభాగాలు" + } +} \ No newline at end of file diff --git a/_locales/zh/messages.json b/_locales/zh/messages.json new file mode 100644 index 00000000..b9982f4b --- /dev/null +++ b/_locales/zh/messages.json @@ -0,0 +1,175 @@ +{ + "addStyleLabel": { + "message": "编写新的样式" + }, + "addStyleTitle": { + "message": "添加样式" + }, + "appliesAdd": { + "message": "添加" + }, + "appliesDisplay": { + "message": "应用到: $applies$", + "placeholders": { + "applies": { + "content": "$1" + } + } + }, + "appliesDisplayTruncatedSuffix": { + "message": "以及更多" + }, + "appliesDomainOption": { + "message": "指定域上的URL" + }, + "appliesHelp": { + "message": "使用“应用到”来控制这个样式应用到哪些地址上。" + }, + "appliesLabel": { + "message": "应用到" + }, + "appliesRegexpOption": { + "message": "匹配正则的URL" + }, + "appliesRemove": { + "message": "移除" + }, + "appliesSpecify": { + "message": "指定站点" + }, + "appliesToEverything": { + "message": "所有站点" + }, + "appliesUrlOption": { + "message": "地址" + }, + "appliesUrlPrefixOption": { + "message": "以指定地址开始" + }, + "checkAllUpdates": { + "message": "检查所有样式的更新" + }, + "checkForUpdate": { + "message": "检查更新" + }, + "checkingForUpdate": { + "message": "检查中..." + }, + "deleteStyleLabel": { + "message": "删除" + }, + "deleteStyleConfirm": { + "message": "确定要删除这个样式吗?" + }, + "description": { + "message": "Stylish,一个用户样式管理器,帮助您重新定义网页样式。Stylish易于为Google,Facebook,Youtube,Orkut以及其它各类型网站安装样式和主题。" + }, + "disableStyleLabel": { + "message": "禁用" + }, + "editStyleHeading": { + "message": "编辑样式" + }, + "editStyleLabel": { + "message": "编辑" + }, + "editStyleTitle": { + "message": "编辑样式 $stylename$", + "placeholders": { + "stylename": { + "content": "$1" + } + } + }, + "enableStyleLabel": { + "message": "启用" + }, + "findStylesForSite": { + "message": "查找更多适合此站点的样式" + }, + "helpAlt": { + "message": "帮助" + }, + "installUpdate": { + "message": "安装更新" + }, + "manageHeading": { + "message": "已安装的样式" + }, + "manageText": { + "message": "访问 userstyles.org<\/a> 查找预定义的样式. 如果您需要帮助,请访问 论坛<\/a>." + }, + "manageTitle": { + "message": "Stylish" + }, + "noStylesForSite": { + "message": "当前站点上没有已安装的样式" + }, + "openManage": { + "message": "管理已安装样式" + }, + "sectionAdd": { + "message": "添加新节" + }, + "sectionCode": { + "message": "代码" + }, + "sectionHelp": { + "message": "样式节允许你定义多个样式段落并将它们应用于不同的站点匹配规则上。例如,一个样式可以更改使用一个方式来更改主页,而此时其它的样式段可以更改站点的其它部分。" + }, + "sectionRemove": { + "message": "移除节" + }, + "styleCancelEditLabel": { + "message": "返回到管理" + }, + "styleChangesNotSaved": { + "message": "您已经修改了此样式,但尚未保存" + }, + "styleEnabledLabel": { + "message": "已启用" + }, + "styleInstall": { + "message": "安装 '$stylename$' 到 Stylish?", + "placeholders": { + "stylename": { + "content": "$1" + } + } + }, + "styleMissingName": { + "message": "请输入名称." + }, + "styleNameLabel": { + "message": "名称" + }, + "styleSaveLabel": { + "message": "保存" + }, + "styleSectionsTitle": { + "message": "样式节" + }, + "styleToMozillaFormat": { + "message": "转换为Mozilla格式" + }, + "styleToMozillaFormatHelp": { + "message": "用于Firefox上的Stylish的Mozilla格式样式代码可以在 userstyles.org 上提交" + }, + "updateCheckFailBadResponseCode": { + "message": "更新失败 - 服务器了返回代码 $code$.", + "placeholders": { + "code": { + "content": "$1" + } + } + }, + "updateCheckFailServerUnreachable": { + "message": "更新失败 - 服务器无法访问." + }, + "updateCheckSucceededNoUpdate": { + "message": "已经是最新的." + }, + "updateCompleted": { + "message": "更新完成." + } +} \ No newline at end of file diff --git a/_locales/zh_CN/messages.json b/_locales/zh_CN/messages.json new file mode 100644 index 00000000..b9982f4b --- /dev/null +++ b/_locales/zh_CN/messages.json @@ -0,0 +1,175 @@ +{ + "addStyleLabel": { + "message": "编写新的样式" + }, + "addStyleTitle": { + "message": "添加样式" + }, + "appliesAdd": { + "message": "添加" + }, + "appliesDisplay": { + "message": "应用到: $applies$", + "placeholders": { + "applies": { + "content": "$1" + } + } + }, + "appliesDisplayTruncatedSuffix": { + "message": "以及更多" + }, + "appliesDomainOption": { + "message": "指定域上的URL" + }, + "appliesHelp": { + "message": "使用“应用到”来控制这个样式应用到哪些地址上。" + }, + "appliesLabel": { + "message": "应用到" + }, + "appliesRegexpOption": { + "message": "匹配正则的URL" + }, + "appliesRemove": { + "message": "移除" + }, + "appliesSpecify": { + "message": "指定站点" + }, + "appliesToEverything": { + "message": "所有站点" + }, + "appliesUrlOption": { + "message": "地址" + }, + "appliesUrlPrefixOption": { + "message": "以指定地址开始" + }, + "checkAllUpdates": { + "message": "检查所有样式的更新" + }, + "checkForUpdate": { + "message": "检查更新" + }, + "checkingForUpdate": { + "message": "检查中..." + }, + "deleteStyleLabel": { + "message": "删除" + }, + "deleteStyleConfirm": { + "message": "确定要删除这个样式吗?" + }, + "description": { + "message": "Stylish,一个用户样式管理器,帮助您重新定义网页样式。Stylish易于为Google,Facebook,Youtube,Orkut以及其它各类型网站安装样式和主题。" + }, + "disableStyleLabel": { + "message": "禁用" + }, + "editStyleHeading": { + "message": "编辑样式" + }, + "editStyleLabel": { + "message": "编辑" + }, + "editStyleTitle": { + "message": "编辑样式 $stylename$", + "placeholders": { + "stylename": { + "content": "$1" + } + } + }, + "enableStyleLabel": { + "message": "启用" + }, + "findStylesForSite": { + "message": "查找更多适合此站点的样式" + }, + "helpAlt": { + "message": "帮助" + }, + "installUpdate": { + "message": "安装更新" + }, + "manageHeading": { + "message": "已安装的样式" + }, + "manageText": { + "message": "访问 userstyles.org<\/a> 查找预定义的样式. 如果您需要帮助,请访问 论坛<\/a>." + }, + "manageTitle": { + "message": "Stylish" + }, + "noStylesForSite": { + "message": "当前站点上没有已安装的样式" + }, + "openManage": { + "message": "管理已安装样式" + }, + "sectionAdd": { + "message": "添加新节" + }, + "sectionCode": { + "message": "代码" + }, + "sectionHelp": { + "message": "样式节允许你定义多个样式段落并将它们应用于不同的站点匹配规则上。例如,一个样式可以更改使用一个方式来更改主页,而此时其它的样式段可以更改站点的其它部分。" + }, + "sectionRemove": { + "message": "移除节" + }, + "styleCancelEditLabel": { + "message": "返回到管理" + }, + "styleChangesNotSaved": { + "message": "您已经修改了此样式,但尚未保存" + }, + "styleEnabledLabel": { + "message": "已启用" + }, + "styleInstall": { + "message": "安装 '$stylename$' 到 Stylish?", + "placeholders": { + "stylename": { + "content": "$1" + } + } + }, + "styleMissingName": { + "message": "请输入名称." + }, + "styleNameLabel": { + "message": "名称" + }, + "styleSaveLabel": { + "message": "保存" + }, + "styleSectionsTitle": { + "message": "样式节" + }, + "styleToMozillaFormat": { + "message": "转换为Mozilla格式" + }, + "styleToMozillaFormatHelp": { + "message": "用于Firefox上的Stylish的Mozilla格式样式代码可以在 userstyles.org 上提交" + }, + "updateCheckFailBadResponseCode": { + "message": "更新失败 - 服务器了返回代码 $code$.", + "placeholders": { + "code": { + "content": "$1" + } + } + }, + "updateCheckFailServerUnreachable": { + "message": "更新失败 - 服务器无法访问." + }, + "updateCheckSucceededNoUpdate": { + "message": "已经是最新的." + }, + "updateCompleted": { + "message": "更新完成." + } +} \ No newline at end of file diff --git a/apply.js b/apply.js new file mode 100644 index 00000000..5fcefc6d --- /dev/null +++ b/apply.js @@ -0,0 +1,113 @@ +chrome.extension.sendRequest({name:"getStylesToApply"}, function(response) { + response.forEach(applyStyle); +}); + +chrome.extension.onRequest.addListener(function(request, sender, sendResponse) { + switch(request.name) { + case "styleDeleted": + removeStyle(request.id); + sendResponse({}); + break; + case "styleUpdated": + removeStyle(request.style.id); + //fallthrough + case "styleAdded": + if (request.style.enabled == "true") { + chrome.extension.sendRequest({name: "getStyleApplies", style: request.style, url: location.href}, function(response) { + if (response) { + applyStyle(response); + } + }); + } + sendResponse({}); + } +}); + +function removeStyle(id) { + var e = document.getElementById("stylish-" + id); + if (e) { + e.parentNode.removeChild(e); + } +} + +function applyStyle(s) { + var style = document.createElement("style"); + style.setAttribute("id", "stylish-" + s.id); + style.setAttribute("class", "stylish"); + style.setAttribute("type", "text/css"); + style.appendChild(document.createTextNode(s.sections.filter(filterSection).map(function(section) { + return section.code; + }).join("\n"))); + if (document.head) { + document.head.appendChild(style); + } else { + document.documentElement.appendChild(style); + } +} + +function filterSection(section) { + // global + if (!section.urls && !section.urlPrefixes && !section.domains && !section.regexps) { + return true; + } + if (section.urls) { + var found = false; + section.urls.forEach(function(url) { + if (url == location.href) { + found = true; + return; + } + }); + if (found) { + return true; + } + } + if (section.urlPrefixes) { + var found = false; + section.urlPrefixes.forEach(function(urlPrefix) { + if (location.href.indexOf(urlPrefix) == 0) { + found = true; + return; + } + }); + if (found) { + return true; + } + } + if (section.domains) { + var found = false; + var currentDomains = getDomains(location.href); + section.domains.forEach(function(domain) { + if (currentDomains.indexOf(domain) >= 0) { + found = true; + return; + } + }); + if (found) { + return true; + } + } + if (section.regexps) { + var found = false; + section.regexps.forEach(function(regexp) { + if ((new RegExp(regexp)).test(location.href)) { + found = true; + return; + } + }); + if (found) { + return true; + } + } + return false; +} + +function getDomains(url) { + var d = /.*?:\/*([^\/]+)/.exec(url)[1]; + var domains = [d]; + while (d.indexOf(".") != -1) { + d = d.substring(d.indexOf(".") + 1); + domains.push(d); + } + return domains; +} diff --git a/background.html b/background.html new file mode 100644 index 00000000..d05d55da --- /dev/null +++ b/background.html @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/background.js b/background.js new file mode 100644 index 00000000..f57e8271 --- /dev/null +++ b/background.js @@ -0,0 +1,78 @@ +chrome.extension.onRequest.addListener(function(request, sender, sendResponse) { + switch (request.name) { + case "getStylesToApply": + getStyles({matchUrl: sender.tab.url, enabled: true}, function(r) { + chrome.browserAction.setBadgeText({text: getBadgeText(r), tabId: sender.tab.id}); + sendResponse(r); + }); + break; + case "getStylesForUrl": + getStyles({url: request.url}, sendResponse); + break; + case "getStyleApplies": + sendResponse(styleAppliesToUrl(request.style, request.url)); + break; + case "saveFromJSON": + saveFromJSON(request.json); + sendResponse({}); + break; + case "styleChanged": + cachedGlobalStyleIds = null; + cachedStyles = []; + sendResponse({}); + break; + case "getCachedStyles": + sendResponse(cachedStyles); + break; + case "cacheStyles": + request.styles.forEach(function(style) { + cachedStyles[style.id] = style; + }); + break; + } +}); + +function styleAppliesToUrl(style, url) { + style.sections = style.sections.filter(function(section) { + return sectionAppliesToUrl(section, url); + }); + if (style.sections.size == 0) { + return null; + } + return style; +} + +function sectionAppliesToUrl(section, url) { + if (!section.urls && !section.domains && !section.urlPrefixes && !section.regexps) { + console.log(section + " is global"); + return true; + } + if (section.urls && section.urls.indexOf(url) != -1) { + console.log(section + " applies to " + url + " due to URL rules"); + return true; + } + if (section.urlPrefixes && section.urlPrefixes.some(function(prefix) { + return url.indexOf(prefix) == 0; + })) { + console.log(section + " applies to " + url + " due to URL prefix rules"); + return true; + } + if (section.domains && getDomains(url).some(function(domain) { + return section.domains.indexOf(domain) != -1; + })) { + console.log(section + " applies due to " + url + " due to domain rules"); + return true; + } + if (section.regexps && section.regexps.some(function(regexp) { + return (new RegExp(regexp)).test(url); + })) { + console.log(section + " applies to " + url + " due to regexp rules"); + return true; + } + console.log(section + " does not apply due to " + url); + return false; +} + +var cachedGlobalStyleIds = null; +var cachedStyles = []; +var background = true; diff --git a/edit.html b/edit.html new file mode 100644 index 00000000..496fe8c8 --- /dev/null +++ b/edit.html @@ -0,0 +1,108 @@ + + + + + + + + + + +
+

+
+ + diff --git a/edit.js b/edit.js new file mode 100644 index 00000000..9675c349 --- /dev/null +++ b/edit.js @@ -0,0 +1,277 @@ +var styleId = null; +var dirty = false; + +var appliesToTemplate = document.createElement("li"); +appliesToTemplate.innerHTML = ''; + +var appliesToEverythingTemplate = document.createElement("li"); +appliesToEverythingTemplate.className = "applies-to-everything"; +appliesToEverythingTemplate.innerHTML = t("appliesToEverything") + ' ' + +var sectionTemplate = document.createElement("div"); +sectionTemplate.innerHTML = '
    '; + +function makeDirty() { + dirty = true; +} + +window.onbeforeunload = function() { + return dirty ? t('styleChangesNotSaved') : null; +} + +function addAppliesTo(list, name, value) { + var showingEverything = list.querySelector(".applies-to-everything") != null; + // blow away "Everything" if it's there + if (showingEverything) { + list.removeChild(list.firstChild); + } + var e; + if (name && value) { + e = appliesToTemplate.cloneNode(true); + e.querySelector("[name=applies-type]").value = name; + e.querySelector("[name=applies-value]").value = value; + } else if (showingEverything || list.hasChildNodes()) { + e = appliesToTemplate.cloneNode(true); + if (list.hasChildNodes()) { + e.querySelector("[name=applies-type]").value = list.querySelector("li:last-child [name='applies-type']").value; + } + } else { + e = appliesToEverythingTemplate.cloneNode(true); + } + list.appendChild(e); +} + +function addSection(section) { + var div = sectionTemplate.cloneNode(true); + var appliesTo = div.querySelector(".applies-to-list"); + + if (section) { + div.querySelector(".code").value = section.code; + if (section.urls) { + section.urls.forEach(function(url) { + addAppliesTo(appliesTo, "url", url); + }); + } + if (section.urlPrefixes) { + section.urlPrefixes.forEach(function(url) { + addAppliesTo(appliesTo, "url-prefix", url); + }); + } + if (section.domains) { + section.domains.forEach(function(d) { + addAppliesTo(appliesTo, "domain", d); + }); + } + if (section.regexps) { + section.regexps.forEach(function(d) { + addAppliesTo(appliesTo, "regexp", d); + }); + } + if (!section.urls && !section.urlPrefixes && !section.domains && !section.regexps) { + addAppliesTo(appliesTo); + } + } else { + addAppliesTo(appliesTo); + } + + var sections = document.getElementById("sections"); + sections.appendChild(div); +} + +function removeAppliesTo(event) { + var appliesToList = event.target.parentNode.parentNode; + appliesToList.removeChild(event.target.parentNode); + if (!appliesToList.hasChildNodes()) { + appliesToList.appendChild(appliesToEverythingTemplate); + } + makeDirty(); +} + +function removeSection(event) { + event.target.parentNode.parentNode.removeChild(event.target.parentNode); + makeDirty(); +} + +window.addEventListener("load", init, false); + +function init() { + tE("sections-help", "helpAlt", "alt"); + var idMatch = /[&\?]id=([0-9]+)/.exec(location.href) + if (idMatch == null || idMatch.length != 2) { // match should be 2 - one for the whole thing, one for the parentheses + // This is an add + addSection(); + document.title = t("addStyleTitle"); + tE("heading", "addStyleTitle"); + return; + } + // This is an edit + var id = idMatch[1]; + getStyles({id: id}, function(styles) { + var style = styles[0]; + styleId = style.id; + initWithStyle(style); + }); +} + +function initWithStyle(style) { + document.getElementById("name").value = style.name; + document.getElementById("enabled").checked = style.enabled == "true"; + document.getElementById("heading").innerHTML = t("editStyleHeading"); + initTitle(style); + // if this was done in response to an update, we need to clear existing sections + Array.prototype.forEach.call(document.querySelectorAll("#sections > div"), function(div) { + div.parentNode.removeChild(div); + }); + style.sections.forEach(addSection); +} + +function initTitle(style) { + document.title = t('editStyleTitle', [style.name]); +} + +function validate() { + var name = document.getElementById("name").value; + if (name == "") { + return t("styleMissingName"); + } + return null; +} + +function save() { + var error = validate(); + if (error) { + alert(error); + return; + } + var name = document.getElementById("name").value; + var enabled = document.getElementById("enabled").checked; + getDatabase(function(db) { + db.transaction(function (t) { + var sections = getSections(); + if (styleId == null) { + t.executeSql('INSERT INTO styles (name, enabled) VALUES (?, ?);', [name, enabled]); + sections.forEach(function(s) { + t.executeSql("INSERT INTO sections (style_id, code) SELECT id, ? FROM styles ORDER BY id DESC LIMIT 1;", [s.code]); + s.meta.forEach(function(m) { + t.executeSql("INSERT INTO section_meta (section_id, name, value) SELECT id, ?, ? FROM sections ORDER BY id DESC LIMIT 1;", [m[0], m[1]]); + }); + }); + } else { + t.executeSql('UPDATE styles SET name = ?, enabled = ? WHERE id = ?;', [name, enabled, styleId]); + t.executeSql('DELETE FROM section_meta WHERE section_id IN (SELECT id FROM sections WHERE style_id = ?);', [styleId]); + t.executeSql('DELETE FROM sections WHERE style_id = ?;', [styleId]); + sections.forEach(function(s) { + t.executeSql("INSERT INTO sections (style_id, code) VALUES (?, ?);", [styleId, s.code]); + s.meta.forEach(function(m) { + t.executeSql("INSERT INTO section_meta (section_id, name, value) SELECT id, ?, ? FROM sections ORDER BY id DESC LIMIT 1;", [m[0], m[1]]); + }); + }); + } + dirty = false; + }, reportError, saveComplete); + }, reportError); +} + +function getSections() { + var sections = []; + Array.prototype.forEach.call(document.querySelectorAll("#sections > div"), function(div) { + var code = div.querySelector(".code").value; + if (/^\s*$/.test(code)) { + return; + } + sections.push({code: code, meta: getMeta(div)}); + }); + return sections; +} + +function getMeta(e) { + var meta = []; + Array.prototype.forEach.call(e.querySelector(".applies-to-list").childNodes, function(li) { + if (li.className == appliesToEverythingTemplate.className) { + return; + } + var a = li.querySelector("[name=applies-type]").value; + var b = li.querySelector("[name=applies-value]").value; + if (a && b) { + meta.push([a, b]); + } + }); + return meta; +} + +function saveComplete() { + if (styleId == null) { + // Load the style id + getDatabase(function(db) { + db.readTransaction(function (t) { + t.executeSql('SELECT id FROM styles ORDER BY id DESC LIMIT 1', [], function(t, r) { + styleId = r.rows.item(0).id; + notifySave(true); + }, reportError) + }, reportError) + }); + return; + } + notifySave(false); +} + +function showMozillaFormat() { + var w = window.open("data:text/plain," + encodeURIComponent(toMozillaFormat())); +} + +function toMozillaFormat() { + return getSections().map(function(section) { + if (section.meta.length == 0) { + return section.code; + } + var mf = "@-moz-document "; + mf += section.meta.map(function(meta) { + return meta[0] + "(\"" + meta[1].replace("\\", "\\\\") + "\")"; + }).join(", "); + return mf + " {\n" + section.code + "\n}"; + }).join("\n\n"); +} + +function notifySave(newStyle) { + chrome.extension.sendRequest({name: "styleChanged"}); + getStyles({id: styleId}, function(styles) { + if (newStyle) { + notifyAllTabs({name:"styleAdded", style: styles[0]}); + // give the code above a moment before we kill the page + setTimeout(function() {location.href = "edit.html?id=" + styleId;}, 200); + } else { + initTitle(styles[0]); + notifyAllTabs({name:"styleUpdated", style: styles[0]}); + } + }); +} + +function showSectionHelp() { + showHelp(t("sectionHelp")); +} + +function showAppliesToHelp() { + showHelp(t("appliesHelp")); +} + +function showToMozillaHelp() { + showHelp(t("styleToMozillaFormatHelp")); +} + +function showHelp(text) { + alert(text); +} + +chrome.extension.onRequest.addListener(function(request, sender, sendResponse) { + var installed = document.getElementById("installed"); + switch(request.name) { + case "styleUpdated": + initWithStyle(request.style); + break; + case "styleDeleted": + if (styleId == request.id) { + window.close(); + break; + } + } +}); diff --git a/help.png b/help.png new file mode 100644 index 0000000000000000000000000000000000000000..5c870176d4dea68aab9e51166cc3d7a582f326d6 GIT binary patch literal 786 zcmV+t1MU2YP)$XgYMs^AIOw1Qr{*Wn)N-{9ma}x2(<~`9Go1=*>YR!KZvrBS zCd!u}@M0og%Ev@_;Z?Kk>Wwv=%h_57zmt2<_1msz_niYE=YRNPpd%02TK9oK1z z>ooPno}v^sikz_|1XHFx_L%~;ljh7i(jiay5F0x*+(9aXXFCl?AdQj5XlQ65%sEv+ ztfe?|YcjPN*@yYtE~ImQh{l|#A6Z8iu>pf43Rj52CzU_dMQm|S2xR62YjQOn+z8WH zaK=!}ggOZi{4pB7SQ=xC0n|vXP_Bkx_a)FeNd}w8U97BNbSWxa^QW-li9BZ#M1!_xE*?wzt^GcoeoL*JGLSe_+l-JT2#2tz!z&^ z_s5anq&^nBklIMwRvcoP3%qs%%Ea?1c{_*V*Xj&~uLu-2Dp1fUN4<0zMo$EH>*U83 zm_9;Vt%-bE{_J_!If!1y=c+`QVZ>0_BPy z+%^pgnv`f8H)Z%0&Tp8&u*MCIC4igNW5MeWM_DHpDNi)Zxz|9XboOnitwFq$ETN=X zj-tkCJnz**Y4k#6_Ty^B=hWo~L!47r`HoP=x&3T1)JLr2t2+#fH + + + + + + + + + + +
    + + diff --git a/manage.js b/manage.js new file mode 100644 index 00000000..8ec02c83 --- /dev/null +++ b/manage.js @@ -0,0 +1,281 @@ + +var styleTemplate = document.createElement("div"); +styleTemplate.innerHTML = "

    "; + +var appliesToExtraTemplate = document.createElement("span"); +appliesToExtraTemplate.className = "applies-to-extra"; +appliesToExtraTemplate.innerHTML = t('appliesDisplayTruncatedSuffix'); + +getStyles({}, showStyles); + +function showStyles(styles) { + var installed = document.getElementById("installed"); + styles.map(createStyleElement).forEach(function(e) { + installed.appendChild(e); + }); +} + +function createStyleElement(style) { + var e = styleTemplate.cloneNode(true); + e.setAttribute("class", style.enabled == "true" ? "enabled" : "disabled"); + e.setAttribute("style-id", style.id); + if (style.updateUrl) { + e.setAttribute("style-update-url", style.updateUrl); + } + + var styleName = e.querySelector(".style-name"); + styleName.appendChild(document.createTextNode(style.name)); + if (style.url) { + var homepage = document.createElement("a"); + homepage.setAttribute("href", style.url); + homepage.setAttribute("target", "_blank"); + var homepageImg = document.createElement("img"); + homepageImg.src = "world_go.png"; + homepageImg.alt = "*"; + homepage.appendChild(homepageImg); + styleName.appendChild(document.createTextNode(" " )); + styleName.appendChild(homepage); + } + var domains = []; + var urls = []; + var urlPrefixes = []; + var regexps = []; + function add(array, property) { + style.sections.forEach(function(section) { + if (section[property]) { + section[property].filter(function(value) { + return array.indexOf(value) == -1; + }).forEach(function(value) { + array.push(value); + });; + } + }); + } + add(domains, 'domains'); + add(urls, 'urls'); + add(urlPrefixes, 'urlPrefixes'); + add(regexps, 'regexps'); + var appliesToToShow = []; + if (domains) + appliesToToShow = appliesToToShow.concat(domains); + if (urls) + appliesToToShow = appliesToToShow.concat(urls); + if (urlPrefixes) + appliesToToShow = appliesToToShow.concat(urlPrefixes.map(function(u) { return u + "*"; })); + if (regexps) + appliesToToShow = appliesToToShow.concat(regexps.map(function(u) { return "/" + u + "/"; })); + var appliesToString = ""; + var showAppliesToExtra = false; + if (appliesToToShow.length == "") + appliesToString = t('appliesToEverything'); + else if (appliesToToShow.length <= 10) + appliesToString = appliesToToShow.join(", "); + else { + appliesToString = appliesToToShow.slice(0, 10).join(", "); + showAppliesToExtra = true; + } + e.querySelector(".applies-to").appendChild(document.createTextNode(t('appliesDisplay', [appliesToString]))); + if (showAppliesToExtra) { + e.querySelector(".applies-to").appendChild(appliesToExtraTemplate.cloneNode(true)); + } + var editLink = e.querySelector(".style-edit-link"); + editLink.setAttribute("href", editLink.getAttribute("href") + style.id); + return e; +} + +function enable(event, enabled) { + var id = getId(event); + enableStyle(id, enabled); +} + +function doDelete() { + if (!confirm(t('deleteStyleConfirm'))) { + return; + } + var id = getId(event); + deleteStyle(id); +} + +function getId(event) { + return getStyleElement(event).getAttribute("style-id"); +} + +function getStyleElement(event) { + var e = event.target; + while (e) { + if (e.hasAttribute("style-id")) { + return e; + } + e = e.parentNode; + } + return null; +} + +chrome.extension.onRequest.addListener(function(request, sender, sendResponse) { + switch(request.name) { + case "styleUpdated": + handleUpdate(request.style); + sendResponse({}); + break; + case "styleAdded": + installed.appendChild(createStyleElement(request.style)); + sendResponse({}); + break; + case "styleDeleted": + handleDelete(request.id); + sendResponse({}); + break; + } +}); + +function handleUpdate(style) { + var installed = document.getElementById("installed"); + installed.replaceChild(createStyleElement(style), installed.querySelector("[style-id='" + style.id + "']")); +} + +function handleDelete(id) { + var installed = document.getElementById("installed"); + installed.removeChild(installed.querySelector("[style-id='" + id + "']")); +} + +function doCheckUpdate(event) { + checkUpdate(getStyleElement(event)); +} + +function checkUpdateAll() { + Array.prototype.forEach.call(document.querySelectorAll("[style-update-url]"), checkUpdate); +} + +function checkUpdate(element) { + element.querySelector(".update-note").innerHTML = t('checkingForUpdate'); + element.className = element.className.replace("checking-update", "").replace("no-update", "").replace("can-update", "") + " checking-update"; + var id = element.getAttribute("style-id"); + var url = element.getAttribute("style-update-url"); + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, true); + xhr.onreadystatechange = function (aEvt) { + if (xhr.readyState == 4) { + if (xhr.status == 200) { + checkNeedsUpdate(id, JSON.parse(xhr.responseText)); + } else if (xhr.status == 0) { + handleNeedsUpdate(t('updateCheckFailServerUnreachable'), id, null); + } else { + handleNeedsUpdate(t('updateCheckFailBadResponseCode', [xhr.status]), id, null); + } + } + }; + xhr.send(null); +} + +function checkNeedsUpdate(id, serverJson) { + getStyles({id: id}, function(styles) { + var style = styles[0]; + if (codeIsEqual(style.sections, serverJson.sections)) { + handleNeedsUpdate("no", id, serverJson); + } else { + handleNeedsUpdate("yes", id, serverJson); + } + }); +} + +function handleNeedsUpdate(needsUpdate, id, serverJson) { + var e = document.querySelector("[style-id='" + id + "']"); + e.className = e.className.replace("checking-update", ""); + switch (needsUpdate) { + case "yes": + e.className += " can-update"; + e.updatedCode = serverJson; + e.querySelector(".update-note").innerHTML = ''; + break; + case "no": + e.className += " no-update"; + e.querySelector(".update-note").innerHTML = t('updateCheckSucceededNoUpdate'); + break; + default: + e.className += " no-update"; + e.querySelector(".update-note").innerHTML = needsUpdate; + } +} + +function doUpdate(event) { + var element = getStyleElement(event); + var o = {}; + o.id = element.getAttribute('style-id'); + o.sections = element.updatedCode.sections; + saveFromJSON(o, function() { + element.updatedCode = ""; + element.className = element.className.replace("can-update", "update-done"); + element.querySelector(".update-note").innerHTML = t('updateCompleted'); + }); +} + +function codeIsEqual(a, b) { + if (a.length != b.length) { + return false; + } + var properties = ["code", "urlPrefixes", "urls", "domains", "regexps"]; + for (var i = 0; i < a.length; i++) { + var found = false; + for (var j = 0; j < b.length; j++) { + var allEquals = properties.every(function(property) { + return jsonEquals(a[i], b[j], property); + }); + if (allEquals) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; +} + +function jsonEquals(a, b, property) { + var type = getType(a[property]); + var typeB = getType(b[property]); + if (type != typeB) { + // consider empty arrays equivalent to lack of property + if ((type == "undefined" || (type == "array" && a[property].length == 0)) && (typeB == "undefined" || (typeB == "array" && b[property].length == 0))) { + return true; + } + return false; + } + if (type == "undefined") { + return true; + } + if (type == "array") { + if (a[property].length != b[property].length) { + return false; + } + for (var i = 0; i < a.length; i++) { + var found = false; + for (var j = 0; j < b.length; j++) { + if (a[i] == b[j]) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; + } + if (type == "string") { + return a[property] == b[property]; + } +} + +function getType(o) { + if (typeof o == "undefined" || typeof o == "string") { + return typeof o; + } + if (o instanceof Array) { + return "array"; + } + throw "Not supported - " + o; +} + +document.title = t("manageTitle"); diff --git a/manifest.json b/manifest.json new file mode 100644 index 00000000..b8351f4e --- /dev/null +++ b/manifest.json @@ -0,0 +1,37 @@ +{ + "name": "Stylish", + "version": "0.9", + "description": "__MSG_description__", + "icons": { + "16": "16.png", + "48": "48.png", + "128": "128.png" + }, + "permissions": [ + "tabs", + "http://userstyles.org/", + "http://userstyles.local/" + ], + "background_page": "background.html", + "content_scripts": [ + { + "matches": ["http://*/*", "https://*/*"], + "run_at": "document_start", + "all_frames": true, + "js": ["apply.js"] + }, + { + "matches": ["http://userstyles.org/*", "http://userstyles.local/*"], + "run_at": "document_end", + "all_frames": false, + "js": ["install.js"] + } + ], + "options_page": "manage.html", + "browser_action": { + "default_icon": "19.png", + "default_title": "Stylish", + "default_popup": "popup.html" + }, + "default_locale": "en" +} diff --git a/messaging.js b/messaging.js new file mode 100644 index 00000000..1fb4206f --- /dev/null +++ b/messaging.js @@ -0,0 +1,21 @@ +function notifyAllTabs(request) { + chrome.windows.getAll({populate: true}, function(windows) { + windows.forEach(function(win) { + win.tabs.forEach(function(tab) { + chrome.tabs.sendRequest(tab.id, request); + updateBadgeText(tab); + }); + }); + }); +} + +function updateBadgeText(tab) { + getStyles({matchUrl: tab.url}, function(styles) { + chrome.browserAction.setBadgeText({text: getBadgeText(styles), tabId: tab.id}); + }); +} + +function getBadgeText(styles) { + var e = styles.filter(function(style) { return style.enabled == "true"; }); + return e.length == 0 ? "" : ("" + e.length); +} diff --git a/popup.html b/popup.html new file mode 100644 index 00000000..fd9c97dc --- /dev/null +++ b/popup.html @@ -0,0 +1,117 @@ + + + + + + + + +
    + + + diff --git a/storage.js b/storage.js new file mode 100644 index 00000000..102d2935 --- /dev/null +++ b/storage.js @@ -0,0 +1,366 @@ +var namespacePattern = /^\s*@namespace\s+([a-zA-Z]+\s+)?url\(\"?http:\/\/www.w3.org\/1999\/xhtml\"?\);?\s*$/; + +var stylishDb = null; +function getDatabase(ready, error) { + if (stylishDb != null) { + ready(stylishDb); + return; + } + stylishDb = openDatabase('stylish', '', 'Stylish Styles', 5*1024*1024); + if (stylishDb.version == "1.0" || stylishDb.version == "") { + dbV11(stylishDb, error, ready); + } else if (stylishDb.version == "1.1") { + dbV12(stylishDb, error, ready); + } else if (stylishDb.version == "1.2") { + dbV13(stylishDb, error, ready); + } else { + ready(stylishDb); + } +} + +function dbV11(d, error, done) { + d.changeVersion(d.version, '1.1', function (t) { + t.executeSql('CREATE TABLE styles (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, url TEXT, updateUrl TEXT, md5Url TEXT, name TEXT NOT NULL, code TEXT NOT NULL, enabled INTEGER NOT NULL, originalCode TEXT NULL);'); + t.executeSql('CREATE TABLE style_meta (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, style_id INTEGER NOT NULL, name TEXT NOT NULL, value TEXT NOT NULL);'); + t.executeSql('CREATE INDEX style_meta_style_id ON style_meta (style_id);'); + }, error, function() {dbV12(d, error, done)}); +} + +function dbV12(d, error, done) { + d.changeVersion(d.version, '1.2', function (t) { + // add section table + t.executeSql('CREATE TABLE sections (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, style_id INTEGER NOT NULL, code TEXT NOT NULL);'); + t.executeSql('INSERT INTO sections (style_id, code) SELECT id, code FROM styles;'); + // switch meta to sections + t.executeSql('DROP INDEX style_meta_style_id;'); + t.executeSql('CREATE TABLE section_meta (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, section_id INTEGER NOT NULL, name TEXT NOT NULL, value TEXT NOT NULL);'); + t.executeSql('INSERT INTO section_meta (section_id, name, value) SELECT s.id, sm.name, sm.value FROM sections s INNER JOIN style_meta sm ON sm.style_id = s.style_id;'); + t.executeSql('CREATE INDEX section_meta_section_id ON section_meta (section_id);'); + t.executeSql('DROP TABLE style_meta;'); + // drop extra fields from styles table + t.executeSql('CREATE TABLE newstyles (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, url TEXT, updateUrl TEXT, md5Url TEXT, name TEXT NOT NULL, enabled INTEGER NOT NULL);'); + t.executeSql('INSERT INTO newstyles (id, url, updateUrl, md5Url, name, enabled) SELECT id, url, updateUrl, md5Url, name, enabled FROM styles;'); + t.executeSql('DROP TABLE styles;'); + t.executeSql('ALTER TABLE newstyles RENAME TO styles;'); + }, error, function() {dbV13(d, error, done)}); +} + +function dbV13(d, error, done) { + d.changeVersion(d.version, '1.3', function (t) { + // clear out orphans + t.executeSql('DELETE FROM section_meta WHERE section_id IN (SELECT sections.id FROM sections LEFT JOIN styles ON styles.id = sections.style_id WHERE styles.id IS NULL);'); + t.executeSql('DELETE FROM sections WHERE id IN (SELECT sections.id FROM sections LEFT JOIN styles ON styles.id = sections.style_id WHERE styles.id IS NULL);'); + }, error, function() { done(d)}); +} + +function getStyles(options, callback) { + getDatabase(function(db) { + db.readTransaction(function (t) { + if ("matchUrl" in options) { + // get a list of style ids that apply to the url. we need to do this separately because we need all the metas for the styles, not just the matching ones + // find site-specific ones + var sql = "SELECT DISTINCT s.style_id FROM sections s INNER JOIN section_meta sm ON sm.section_id = s.id WHERE (sm.name = 'url' and sm.value = ?) OR (sm.name = 'url-prefix' AND ? LIKE (sm.value || '%')) OR (sm.name = 'regexp' AND ? REGEXP sm.value)"; + var matchParams = []; + var domains = getDomains(options.matchUrl); + matchParams = matchParams.concat([options.matchUrl, options.matchUrl, options.matchUrl]).concat(domains); + var domainClause = ""; + if (domains.length == 1) { + sql += " OR (sm.name = 'domain' AND sm.value = ?)"; + } else if (domains.length > 1) { + sql += " OR (sm.name = 'domain' AND sm.value IN ("; + sql += domains.map(function(d) { return "?";}).join(","); + sql += '))'; + } + t.executeSql(sql, matchParams, function (t, r) { + var style_ids = []; + if (options.id) { + style_ids.push(options.id); + } + for (var i = 0; i < r.rows.length; i++) { + var values = r.rows.item(i); + style_ids.push(values.style_id); + } + // now add in global ones + getGlobalStyleIds(function(ids) { + style_ids = style_ids.concat(ids); + loadStyles(style_ids, options.enabled, options.url, callback); + }); + }); + } else { + loadStyles(options.id ? [options.id] : null, options.enabled, options.url, callback); + } + }, reportError); + }, reportError); +} + +function getCache(callback) { + if (isBackground()) { + callback(cachedStyles); + return; + } + chrome.extension.sendRequest({name: "getCachedStyles"}, callback); +} + +function fixBoolean(b) { + if (typeof b != "undefined") { + return b != "false"; + } + return null; +} + +function loadStyles(styleIds, enabled, url, callback) { + // clean up the parameters + enabled = fixBoolean(enabled); + if (typeof url == "undefined") { + url = null; + } + // grab what we can from the cache + if (styleIds) { + getCache(function(cache) { + var styles = []; + var styleIdsNeeded = []; + styleIds.forEach(function(id) { + if (cache[id]) { + if (checkStyle(cache[id], enabled, url)) { + styles.push(cache[id]); + } + } else { + styleIdsNeeded.push(id); + } + }); + styleIds = styleIdsNeeded; + // do we have everything we need? + if (styleIds.length == 0) { + callback(styles); + return; + } + loadStylesFromDB(styles, styleIds, enabled, url, callback); + }); + return; + } + loadStylesFromDB([], styleIds, enabled, url, callback); +} + +function checkStyle(style, enabled, url) { + return (enabled == null || enabled == fixBoolean(style.enabled)) && (url == null || url == style.url); +} + +function loadStylesFromDB(styles, styleIds, enabled, url, callback) { + // load from the db for the rest + getDatabase(function(db) { + db.readTransaction(function (t) { + var where = ""; + var params = []; + if (styleIds) { + if (styleIds.size == 0) { + callback([]); + return; + } + + where += " AND s.id IN (" + var firstStyleId = true; + styleIds.forEach(function(styleId) { + where += firstStyleId ? "?" : ",?"; + firstStyleId = false; + params.push(styleId); + }); + where += ")"; + } + /*if (enabled != null) { + where += ' AND enabled = ?'; + params.push(enabled); + } + if (url != null) { + where += ' AND s.url = ?'; + params.push(url); + }*/ + t.executeSql('SELECT DISTINCT s.*, se.id section_id, se.code, sm.name metaName, sm.value metaValue FROM styles s LEFT JOIN sections se ON se.style_id = s.id LEFT JOIN section_meta sm ON sm.section_id = se.id WHERE 1' + where + ' ORDER BY s.id, se.id, sm.id', params, function (t, r) { + var currentStyle = null; + var currentSection = null; + for (var i = 0; i < r.rows.length; i++) { + var values = r.rows.item(i); + var metaName = null; + switch (values.metaName) { + case null: + break; + case "url": + metaName = "urls"; + break; + case "url-prefix": + metaName = "urlPrefixes"; + break; + case "domain": + var metaName = "domains"; + break; + case "regexps": + var metaName = "regexps"; + break; + default: + var metaName = values.metaName + "s"; + } + var metaValue = values.metaValue; + if (currentStyle == null || currentStyle.id != values.id) { + currentStyle = {id: values.id, url: values.url, updateUrl: values.updateUrl, md5Url: values.md5Url, name: values.name, enabled: values.enabled, sections: []}; + styles.push(currentStyle); + } + if (currentSection == null || currentSection.id != values.section_id) { + currentSection = {id: values.section_id, code: values.code}; + currentStyle.sections.push(currentSection); + } + if (metaName && metaValue) { + if (currentSection[metaName]) { + currentSection[metaName].push(metaValue); + } else { + currentSection[metaName] = [metaValue]; + } + } + } + if (isBackground()) { + styles.forEach(function(style) { + cachedStyles[style.id] = style; + + }); + } else { + chrome.extension.sendRequest({name: "cacheStyles", styles: styles}); + } + callback(styles.filter(function(style) { + return checkStyle(style, enabled, url); + })); + }, reportError); + }, reportError); + }, reportError); +} + +function getGlobalStyleIds(callback) { + if (isBackground() && cachedGlobalStyleIds != null) { + callback(cachedGlobalStyleIds); + return; + } + getDatabase(function(db) { + db.readTransaction(function (t) { + t.executeSql("SELECT DISTINCT s.style_id, s.code FROM sections s LEFT JOIN section_meta sm ON sm.section_id = s.id INNER JOIN styles st ON st.id = s.style_id GROUP BY s.id HAVING COUNT(sm.id) = 0", [], function (t, r) { + var style_ids = []; + for (var i = 0; i < r.rows.length; i++) { + var values = r.rows.item(i); + // ignore namespace only sections + if (!namespacePattern.test(values.code) && style_ids.indexOf(values.style_id) == -1) { + style_ids.push(values.style_id); + } + } + if (isBackground()) { + cachedGlobalStyleIds = style_ids; + } + callback(style_ids); + }, reportError); + }, reportError); + }, reportError); +} + + +function saveFromJSON(o, callback) { + getDatabase(function(db) { + db.transaction(function (t) { + if (o.id) { + t.executeSql('DELETE FROM section_meta WHERE section_id IN (SELECT id FROM sections WHERE style_id = ?);', [o.id]); + t.executeSql('DELETE FROM sections WHERE style_id = ?;', [o.id]); + } else { + t.executeSql('INSERT INTO styles (name, enabled, url, updateUrl) VALUES (?, ?, ?, ?);', [o.name, true, o.url, o.updateUrl]); + } + o.sections.forEach(function(section) { + if (o.id) { + t.executeSql('INSERT INTO sections (style_id, code) VALUES (?, ?);', [o.id, section.code]); + } else { + t.executeSql('INSERT INTO sections (style_id, code) SELECT id, ? FROM styles ORDER BY id DESC LIMIT 1;', [section.code]); + } + section.urls.forEach(function(u) { + t.executeSql("INSERT INTO section_meta (section_id, name, value) SELECT id, 'url', ? FROM sections ORDER BY id DESC LIMIT 1;", [u]); + }); + section.urlPrefixes.forEach(function(u) { + t.executeSql("INSERT INTO section_meta (section_id, name, value) SELECT id, 'url-prefix', ? FROM sections ORDER BY id DESC LIMIT 1;", [u]); + }); + section.domains.forEach(function(u) { + t.executeSql("INSERT INTO section_meta (section_id, name, value) SELECT id, 'domain', ? FROM sections ORDER BY id DESC LIMIT 1;", [u]); + }); + section.regexps.forEach(function(u) { + t.executeSql("INSERT INTO section_meta (section_id, name, value) SELECT id, 'regexp', ? FROM sections ORDER BY id DESC LIMIT 1;", [u]); + }); + }); + }, reportError, function() {saveFromJSONComplete(o.id, callback)}); + }, reportError); +} + +function saveFromJSONComplete(id, callback) { + chrome.extension.sendRequest({name: "styleChanged"}); + if (id) { + notifyAllTabs({name:"styleUpdated", style: id}); + if (callback) { + callback(id); + } + return; + } + // Load the style id + getDatabase(function(db) { + db.readTransaction(function (t) { + t.executeSql('SELECT id FROM styles ORDER BY id DESC LIMIT 1', [], function(t, r) { + var styleId = r.rows.item(0).id; + getStyles({id: styleId}, function(styles) { + notifyAllTabs({name:"styleAdded", style: styles[0]}); + }); + if (callback) { + callback(styleId); + } + }, reportError) + }, reportError) + }); +} + +function reportError() { + for (i in arguments) { + if ("message" in arguments[i]) { + //alert(arguments[i].message); + console.log(arguments[i].message); + } + } +} + +function isBackground() { + return typeof background != "undefined" && background; +} + +function getDomains(url) { + var d = /.*?:\/*([^\/]+)/.exec(url)[1]; + var domains = [d]; + while (d.indexOf(".") != -1) { + d = d.substring(d.indexOf(".") + 1); + domains.push(d); + } + return domains; +} + +function enableStyle(id, enabled) { + getDatabase(function(db) { + db.transaction(function (t) { + t.executeSql("UPDATE styles SET enabled = ? WHERE id = ?;", [enabled, id]); + }, reportError, function() { + chrome.extension.sendRequest({name: "styleChanged"}); + getStyles({id: id}, function(styles) { + handleUpdate(styles[0]); + notifyAllTabs({name:"styleUpdated", style: styles[0]}); + }); + }); + }); +} + +function deleteStyle(id) { + getDatabase(function(db) { + db.transaction(function (t) { + t.executeSql('DELETE FROM section_meta WHERE section_id IN (SELECT id FROM sections WHERE style_id = ?);', [id]); + t.executeSql('DELETE FROM sections WHERE style_id = ?;', [id]); + t.executeSql("DELETE FROM styles WHERE id = ?;", [id]); + }, reportError, function() { + chrome.extension.sendRequest({name: "styleChanged"}); + handleDelete(id); + notifyAllTabs({name:"styleDeleted", id: id}); + }); + }); +} diff --git a/world_go.png b/world_go.png new file mode 100644 index 0000000000000000000000000000000000000000..aee9c97f8232fd21bdd23804c83eb721ff597a96 GIT binary patch literal 944 zcmV;h15f;kP)Vt{;GNX|PV@wQxfRAQ-FeWBO z_okAVsCzMc+6+1!88|n0#f5DY;>y+0w55ffp3Cpz=VNHC0RRA)nx7m4J_e2fEr1D> zf$Li7b6<{q_X_|3fT6VpU}}ES1g3#EU(cKfCPFP#tOhI>gtQSn;qulcA%*-^2>JFm zr+(T4FtpZ8%})k^KL(S1BPTO2QL%$KxGYx;>U5BTrO?79gvFL~m7AM47lbE{|M1p@ zvJU{5KHA(pGTJssQM!0O10j6WL>(4&6rCX3c8K+IfcD4>45pqv>^k0$0RGbW>L~Ep z>F(G3_hpqWYSffq&yG-Z0#t0sZtPO7RtY8w81XE_$%9;8ywUmn_33;5p~)j(OtcLh zGW;R7d;;`7T4jV=PyEzuAB!7%sQMDYjz>7LEO}MJEJ+SEXMDFFKWs9AW0_c*yVfT8 zdLO<111JQ!Z5P|F5l?92}SW-(dg4!8-@ngsi3V^Oiyy@FAt+W#MZLO z+G>n8Cxq}c`;$Ecm+#=&HP9L%gkegdiWRq#ZuU14t$&X7yov1vXjLB(4@;a4kKLRg z-PA=-YKUFC%EJ2Z6sr?Rp~|N4#O=q$)pS=l!*Bo1(-`ie&YwXjm+`*$kXj*?M4{O% zuhGAMggv*$Cl@{hx*zyFSA6yJ!&%W0X~DEMC>Q=Dk#Mkui`0r-AY6 ziYp9c#&{<6JiCE=qrPunJwM|*-o=^4Szb&J5cfBbh$w7fBc$M|SUag$2d(i=0{##! z(KNT$=DD_V!?IjrCV=O7?_9~=opWmL;fW*1d9-cvk8qg2_BpO{v4zWlWG};=C;2-! z$Cag7CoJ20md|EuhSnN@SH6BZDm-yscyj#Rk@rnx3a!H!K7(Yu!lxHc)7Lu8)up-J z2HoDfaAs*8z|dL)001y@X6Owm