├── .devcontainer ├── build.ps1 ├── Dockerfile ├── run.ps1 └── docker-compose.yml ├── app ├── options │ ├── img │ │ ├── logo.png │ │ └── favicon │ │ │ ├── favicon.ico │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ └── favicon-96x96.png │ ├── controllers │ │ ├── BaseController.ts │ │ ├── OptionsController.ts │ │ ├── AboutController.ts │ │ ├── ScrollToItemController.ts │ │ ├── TreeScopeController.ts │ │ ├── DatabaseNameController.ts │ │ ├── ToggleRibbonController.ts │ │ ├── GoToDatasourceController.ts │ │ ├── TreeAutoExpandController.ts │ │ ├── TreelistFieldController.ts │ │ ├── DatabaseSelectorController.ts │ │ ├── SectionSwitchesController.ts │ │ ├── RestoreLastLocationController.ts │ │ ├── HeaderQuickInfoExtenderController.ts │ │ ├── FieldInspectorController.ts │ │ ├── FieldSearchController.ts │ │ ├── BaseOptionsController.ts │ │ ├── LinksController.ts │ │ └── GeneralOptionsController.ts │ ├── interfaces │ │ ├── ILinksStorage.ts │ │ ├── IDatabasesColorsStorage.ts │ │ └── ILinkScope.ts │ ├── package.json │ ├── models │ │ ├── LinkItem.ts │ │ └── DatabaseColorMapping.ts │ ├── bower.json │ ├── directives │ │ └── NavigationDirective.ts │ ├── views │ │ ├── modules │ │ │ ├── scrollToItem │ │ │ │ └── index.html │ │ │ ├── dbName │ │ │ │ └── index.html │ │ │ ├── treeScope │ │ │ │ └── index.html │ │ │ ├── fieldSearch │ │ │ │ └── index.html │ │ │ ├── sectionSwitches │ │ │ │ └── index.html │ │ │ ├── toggleRibbon │ │ │ │ └── index.html │ │ │ ├── treelistField │ │ │ │ └── index.html │ │ │ ├── fieldInspector │ │ │ │ └── index.html │ │ │ ├── goToDatasource │ │ │ │ └── index.html │ │ │ ├── treeAutoExpand │ │ │ │ └── index.html │ │ │ ├── databaseSelector │ │ │ │ └── index.html │ │ │ ├── restoreLastLocation │ │ │ │ └── index.html │ │ │ ├── headerQuickInfoExtender │ │ │ │ └── index.html │ │ │ └── launcher │ │ │ │ └── index.html │ │ ├── general.html │ │ ├── settings.html │ │ ├── links.html │ │ └── snippets │ │ │ └── navigation.html │ ├── services │ │ ├── LinkStorage.ts │ │ └── DatabasesColorsStorage.ts │ ├── options.html │ ├── app.ts │ ├── _all.ts │ └── providers │ │ └── OptionsProvider.ts ├── sc_ext │ ├── styles │ │ ├── treeScope.scss │ │ ├── fieldInspector.scss │ │ ├── databaseName.scss │ │ ├── treelistField.scss │ │ ├── toggleRibbon.scss │ │ ├── headerQuickInfoExtender.scss │ │ ├── fieldSearch.scss │ │ └── launcher.scss │ ├── page objects │ │ ├── _all.ts │ │ └── ContentTree.ts │ ├── modules │ │ ├── databaseName │ │ │ ├── _all.ts │ │ │ └── DatabaseNameModule.ts │ │ ├── scrollToItem │ │ │ ├── _all.ts │ │ │ └── ScrollToItemModule.ts │ │ ├── treelistField │ │ │ ├── _all.ts │ │ │ └── TreelistFieldModule.ts │ │ ├── fieldInspector │ │ │ ├── _all.ts │ │ │ └── FieldInspectorOptions.ts │ │ ├── headerQuickInfoExtender │ │ │ └── _all.ts │ │ ├── addHere │ │ │ ├── _all.ts │ │ │ ├── AddHereButton.ts │ │ │ └── AddHereModule.ts │ │ ├── treeAutoExpand │ │ │ ├── _all.ts │ │ │ ├── TreeNodeGlyph.ts │ │ │ └── TreeAutoExpandModule.ts │ │ ├── databaseColor │ │ │ ├── _all.ts │ │ │ ├── DatabaseColorOptions.ts │ │ │ └── DatabaseColorModule.ts │ │ ├── databaseSelector │ │ │ ├── _all.ts │ │ │ ├── DatabaseSelectorCommandsProvider.ts │ │ │ └── DatabaseSelectorModule.ts │ │ ├── sectionSwitches │ │ │ ├── _all.ts │ │ │ ├── SectionSwitchesCommandsProvider.ts │ │ │ └── SectionSwitchesModule.ts │ │ ├── toggleRibbon │ │ │ ├── _all.ts │ │ │ ├── Ribbon.ts │ │ │ ├── ToggleButton.ts │ │ │ └── ToggleRibbonModule.ts │ │ ├── fieldSearch │ │ │ ├── _all.ts │ │ │ ├── FieldSearchStore.ts │ │ │ └── FieldSearchOptions.ts │ │ ├── launcher │ │ │ ├── StorageType.ts │ │ │ ├── providers │ │ │ │ ├── ICommandsProvider.ts │ │ │ │ ├── BaseCommand.ts │ │ │ │ ├── BaseCommandsProvider.ts │ │ │ │ ├── NavigationCommand.ts │ │ │ │ ├── UserDefinedLinksCommandsProvider.ts │ │ │ │ ├── DynamicCommand.ts │ │ │ │ └── ShellCommandsProvider.ts │ │ │ ├── ICommand.ts │ │ │ ├── models │ │ │ │ ├── SitecoreSearchResults.ts │ │ │ │ ├── SearchResult.ts │ │ │ │ └── LauncherOptions.ts │ │ │ ├── _all.ts │ │ │ └── RecentCommandsStore.ts │ │ ├── lastLocation │ │ │ ├── _all.ts │ │ │ ├── LastLocationStore.ts │ │ │ ├── RestoreLastLocationCommandProvider.ts │ │ │ └── RestoreLastLocation.ts │ │ ├── goToDatasource │ │ │ ├── fields │ │ │ │ ├── IDatasourceField.ts │ │ │ │ ├── FieldInitializer.ts │ │ │ │ ├── DropLink.ts │ │ │ │ ├── ListField.ts │ │ │ │ └── NameLookupValueList.ts │ │ │ ├── _all.ts │ │ │ └── GoToDatasourceModule.ts │ │ ├── treeScope │ │ │ ├── PopupButtonClickCallback.ts │ │ │ ├── _all.ts │ │ │ ├── ContentEditorTree.ts │ │ │ ├── Popup.ts │ │ │ └── PopupButton.ts │ │ ├── placeholder │ │ │ ├── _all.ts │ │ │ ├── IPlaceholderCommand.ts │ │ │ ├── Rendering.ts │ │ │ ├── PlaceholderChrome.ts │ │ │ └── PlaceholderModule.ts │ │ ├── ISitecoreExtensionsModule.ts │ │ ├── shortcutsRunner │ │ │ ├── _all.ts │ │ │ ├── Token.ts │ │ │ ├── providers │ │ │ │ └── AppShortcutCommand.ts │ │ │ └── ShortcutRunner.ts │ │ └── ModuleBase.ts │ ├── http │ │ ├── Method.ts │ │ └── HttpRequest.ts │ ├── typings │ │ └── sitecore.d.ts │ ├── events │ │ ├── args │ │ │ ├── IEventArgs.ts │ │ │ ├── EventArgs.ts │ │ │ └── DatabaseChangeEventArgs.ts │ │ ├── EventsDispatcher.ts │ │ ├── _all.ts │ │ └── EventHandler.ts │ ├── status │ │ ├── IStatusProvider.ts │ │ ├── StatusType.ts │ │ ├── CommandsStatusProvider.ts │ │ ├── StatusInfoWrapper.ts │ │ └── ModulesStatusProvider.ts │ ├── enums │ │ └── Location.ts │ ├── Extensions.ts │ ├── options │ │ ├── ModuleOptions.ts │ │ ├── OptionsAutoMapper.ts │ │ ├── ExtensionsOptions.ts │ │ └── OptionsRepository.ts │ ├── types │ │ ├── IDictionary.ts │ │ └── Dictionary.ts │ ├── IdParser.ts │ ├── storage │ │ └── GlobalStorage.ts │ ├── ExtensionsManager.ts │ ├── Notification.ts │ ├── libraries │ │ └── Fuzzy.ts │ └── _all.ts ├── chrome │ ├── images │ │ ├── icon-128.png │ │ ├── icon-16.png │ │ ├── icon-19.png │ │ ├── icon-38.png │ │ ├── icon-48.png │ │ ├── icon-disabled-16.png │ │ └── icon-disabled-128.png │ ├── popup │ │ ├── fonts │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ ├── fontawesome-webfont.woff2 │ │ │ └── fontawesome-webfont.svg │ │ ├── popup-new-version.html │ │ ├── scripts │ │ │ └── popup-new-version.ts │ │ ├── popup.html │ │ └── styles │ │ │ └── main.scss │ └── background.ts ├── common │ ├── communication │ │ ├── message │ │ │ ├── request │ │ │ │ ├── GetOptionsRequestMessage.ts │ │ │ │ ├── GetGlobalStorageRequestMessage.ts │ │ │ │ ├── GetModuleOptionsRequestMessage.ts │ │ │ │ ├── SetGlobalStorageRequestMessage.ts │ │ │ │ ├── SetOptionsRequestMessage.ts │ │ │ │ └── SetModuleOptionsRequestMessage.ts │ │ │ ├── response │ │ │ │ ├── GetGlobalStorageResponseMessage.ts │ │ │ │ ├── GetOptionsResponseMessage.ts │ │ │ │ └── GetModuleOptionsResponseMessage.ts │ │ │ └── MessageBase.ts │ │ ├── DataParser.ts │ │ └── ObjectDeserializer.ts │ ├── _all.ts │ └── GlobalStorage.ts ├── _locales │ └── en │ │ └── messages.json └── manifest.json ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── CONTRIBUTING.md ├── .gitignore ├── ci └── azure.yml ├── .vscode └── settings.json ├── package.json ├── LICENSE ├── PRIVACY_POLICY.md └── tslint.json /.devcontainer/build.ps1: -------------------------------------------------------------------------------- 1 | docker build -t alpl/sc_ext . -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8.2.1 2 | USER node 3 | WORKDIR /data/app/ 4 | ENTRYPOINT /bin/bash -------------------------------------------------------------------------------- /.devcontainer/run.ps1: -------------------------------------------------------------------------------- 1 | Push-Location $PSScriptRoot 2 | docker-compose run --rm localdev 3 | Pop-Location -------------------------------------------------------------------------------- /app/options/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/options/img/logo.png -------------------------------------------------------------------------------- /app/sc_ext/styles/treeScope.scss: -------------------------------------------------------------------------------- 1 | .sc-ext-treescope-hidden-container { 2 | display: none !important; 3 | } -------------------------------------------------------------------------------- /app/chrome/images/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/chrome/images/icon-128.png -------------------------------------------------------------------------------- /app/chrome/images/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/chrome/images/icon-16.png -------------------------------------------------------------------------------- /app/chrome/images/icon-19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/chrome/images/icon-19.png -------------------------------------------------------------------------------- /app/chrome/images/icon-38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/chrome/images/icon-38.png -------------------------------------------------------------------------------- /app/chrome/images/icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/chrome/images/icon-48.png -------------------------------------------------------------------------------- /app/sc_ext/page objects/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// -------------------------------------------------------------------------------- /app/options/img/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/options/img/favicon/favicon.ico -------------------------------------------------------------------------------- /app/chrome/images/icon-disabled-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/chrome/images/icon-disabled-16.png -------------------------------------------------------------------------------- /app/chrome/images/icon-disabled-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/chrome/images/icon-disabled-128.png -------------------------------------------------------------------------------- /app/sc_ext/modules/databaseName/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// -------------------------------------------------------------------------------- /app/sc_ext/modules/scrollToItem/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// -------------------------------------------------------------------------------- /app/sc_ext/modules/treelistField/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// -------------------------------------------------------------------------------- /app/options/img/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/options/img/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /app/options/img/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/options/img/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /app/options/img/favicon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/options/img/favicon/favicon-96x96.png -------------------------------------------------------------------------------- /app/sc_ext/modules/fieldInspector/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Issue Fixed # 2 | 3 | ## Proposed Changes 4 | 5 | - 6 | - 7 | - 8 | 9 | @alan-null 10 | -------------------------------------------------------------------------------- /app/sc_ext/http/Method.ts: -------------------------------------------------------------------------------- 1 | namespace SitecoreExtensions.Http { 2 | export enum Method { 3 | POST, 4 | GET 5 | } 6 | } -------------------------------------------------------------------------------- /app/chrome/popup/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/chrome/popup/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /app/chrome/popup/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/chrome/popup/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /app/chrome/popup/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/chrome/popup/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /app/chrome/popup/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alan-null/sc_ext/HEAD/app/chrome/popup/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /app/sc_ext/modules/headerQuickInfoExtender/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | temp 3 | .tmp 4 | dist 5 | .sass-cache 6 | package 7 | *.js 8 | *.css 9 | *.js.map 10 | !app/options/libs/* 11 | -------------------------------------------------------------------------------- /app/sc_ext/typings/sitecore.d.ts: -------------------------------------------------------------------------------- 1 | declare var scForm: any; 2 | declare var scSitecore: any; 3 | declare var Sitecore: any; 4 | declare var scContentEditor: any; -------------------------------------------------------------------------------- /app/sc_ext/styles/fieldInspector.scss: -------------------------------------------------------------------------------- 1 | .sc-ext-contentButton:after { 2 | content: "]" 3 | } 4 | 5 | .sc-ext-contentButton:before { 6 | content: "[" 7 | } -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | localdev: 4 | image: alpl/sc_ext 5 | build: . 6 | volumes: 7 | - ./../:/data/app 8 | -------------------------------------------------------------------------------- /app/chrome/popup/popup-new-version.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/sc_ext/modules/addHere/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// -------------------------------------------------------------------------------- /app/sc_ext/modules/treeAutoExpand/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// -------------------------------------------------------------------------------- /app/sc_ext/modules/databaseColor/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// -------------------------------------------------------------------------------- /app/sc_ext/events/args/IEventArgs.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Events { 4 | export interface IEventArgs { 5 | eventName: string; 6 | } 7 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/databaseSelector/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// -------------------------------------------------------------------------------- /app/sc_ext/modules/sectionSwitches/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// -------------------------------------------------------------------------------- /app/sc_ext/modules/toggleRibbon/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// 5 | /// -------------------------------------------------------------------------------- /app/sc_ext/status/IStatusProvider.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Status { 4 | export interface IStatusProvider { 5 | getStatus(): string; 6 | } 7 | } -------------------------------------------------------------------------------- /app/sc_ext/styles/databaseName.scss: -------------------------------------------------------------------------------- 1 | $break-medium: 1000px; 2 | $break-small: 550px; 3 | $break-tiny: 390px; 4 | 5 | .sc-ext-dbName { 6 | position: fixed; 7 | width: 100%; 8 | text-align: center; 9 | } -------------------------------------------------------------------------------- /app/sc_ext/events/args/EventArgs.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Events { 4 | export class EventArgs implements IEventArgs { 5 | eventName: string; 6 | } 7 | } -------------------------------------------------------------------------------- /app/sc_ext/status/StatusType.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Status { 4 | export enum StatusType { 5 | ModulesCount, 6 | AvailableCommandsCount 7 | } 8 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/fieldSearch/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// 5 | /// -------------------------------------------------------------------------------- /app/sc_ext/enums/Location.ts: -------------------------------------------------------------------------------- 1 | namespace SitecoreExtensions.Enums { 2 | export enum Location { 3 | ContentEditor, 4 | ExperienceEditor, 5 | Launchpad, 6 | Desktop, 7 | Unknown 8 | } 9 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/StorageType.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Launcher { 4 | export enum StorageType { 5 | LocalStorage, 6 | GlobalStorage 7 | } 8 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/lastLocation/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// 5 | /// -------------------------------------------------------------------------------- /app/options/controllers/BaseController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | 6 | export class BaseController { 7 | public static $inject = ['$scope']; 8 | } 9 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Steps to Reproduce the Problem 2 | 1. 3 | 1. 4 | 1. 5 | 6 | ### Expected Behavior 7 | ... 8 | 9 | ### Actual Behavior 10 | ... 11 | 12 | ### Specifications 13 | Sitecore version: X.X (revision YYYYY) 14 | -------------------------------------------------------------------------------- /app/sc_ext/Extensions.ts: -------------------------------------------------------------------------------- 1 | declare interface MouseEvent { 2 | getSrcElement(): Element; 3 | } 4 | 5 | namespace SitecoreExtensions { 6 | MouseEvent.prototype['getSrcElement'] = function (): Element { 7 | return this.target; 8 | }; 9 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/goToDatasource/fields/IDatasourceField.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.GoToDatasource.Fields { 4 | export interface IDatasourceField { 5 | initialize(); 6 | } 7 | } -------------------------------------------------------------------------------- /app/sc_ext/options/ModuleOptions.ts: -------------------------------------------------------------------------------- 1 | namespace SitecoreExtensions.Options { 2 | export class ModuleOptions { 3 | enabled: boolean; 4 | constructor() { 5 | this.enabled = true; 6 | } 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /app/options/interfaces/ILinksStorage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | export interface ILinksStorage { 5 | get(coldStorageCb?: any): LinkItem[]; 6 | put(links: LinkItem[]); 7 | } 8 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/treeScope/PopupButtonClickCallback.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.TreeScope { 4 | export interface PopupButtonClickCallback { 5 | (activeNodeID: string): void; 6 | } 7 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/providers/ICommandsProvider.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Launcher.Providers { 4 | export interface ICommandsProvider { 5 | getCommands(): ICommand[]; 6 | } 7 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/placeholder/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// 5 | /// 6 | /// -------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/ICommand.ts: -------------------------------------------------------------------------------- 1 | namespace SitecoreExtensions.Modules.Launcher { 2 | export interface ICommand { 3 | id: number; 4 | name: string; 5 | description: string; 6 | execute: Function; 7 | canExecute: Function; 8 | } 9 | } -------------------------------------------------------------------------------- /app/sc_ext/events/EventsDispatcher.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Events { 4 | export class EventsDispatcher { 5 | public static Dispatch(args: IEventArgs) { 6 | window.postMessage(args, '*'); 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/ISitecoreExtensionsModule.ts: -------------------------------------------------------------------------------- 1 | namespace SitecoreExtensions.Modules { 2 | export interface ISitecoreExtensionsModule { 3 | moduleName: string; 4 | description: string; 5 | 6 | canExecute(): boolean; 7 | initialize(): void; 8 | } 9 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/goToDatasource/fields/FieldInitializer.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.GoToDatasource.Fields { 4 | export interface FieldInitializer { 5 | (select: HTMLSelectElement): IDatasourceField; 6 | } 7 | } -------------------------------------------------------------------------------- /app/options/interfaces/IDatabasesColorsStorage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | export interface IDatabasesColorsStorage { 5 | get(coldStorageCb?: any): DatabaseColorMapping[]; 6 | put(links: DatabaseColorMapping[]); 7 | } 8 | } -------------------------------------------------------------------------------- /app/options/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sc_ext_options", 3 | "description": "Sitecore Extensions Options", 4 | "private": true, 5 | "scripts": { 6 | "compile": "tsc --sourcemap --out app.js _all.ts" 7 | }, 8 | "dependencies": { 9 | "angular": "^1.3.13" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/sc_ext/events/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// -------------------------------------------------------------------------------- /app/sc_ext/modules/treeScope/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// -------------------------------------------------------------------------------- /app/common/communication/message/request/GetOptionsRequestMessage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Common.Communication { 4 | export class GetOptionsRequestMessage extends MessageBase { 5 | constructor() { 6 | super(); 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /app/options/models/LinkItem.ts: -------------------------------------------------------------------------------- 1 | module SitecoreExtensions.Options { 2 | export class LinkItem { 3 | constructor( 4 | public name: string, 5 | public url: string, 6 | public mode: string, 7 | public order: number 8 | ) { } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /app/sc_ext/types/IDictionary.ts: -------------------------------------------------------------------------------- 1 | namespace SitecoreExtensions.Types { 2 | export interface IDictionary { 3 | add(key: string, value: any): void; 4 | remove(key: string): void; 5 | containsKey(key: string): boolean; 6 | getKeys(): string[]; 7 | getValues(): any[]; 8 | } 9 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Describe the new feature 11 | 12 | ### How does this help you? 13 | 14 | ### If we couldn't add this feature, is there a compromise you can think of? -------------------------------------------------------------------------------- /app/sc_ext/modules/shortcutsRunner/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// -------------------------------------------------------------------------------- /app/options/models/DatabaseColorMapping.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | export class DatabaseColorMapping { 5 | constructor( 6 | public name: string, 7 | public color: string, 8 | public order: number 9 | ) { } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/sc_ext/styles/treelistField.scss: -------------------------------------------------------------------------------- 1 | .scContentControl.scTreelistEx.sc-ext-treelist { 2 | .sc-ext-treelist-path { 3 | margin-left: 5px; 4 | color: #808080; 5 | 6 | } 7 | .sc-ext-treelist-path:after { 8 | content: "]" 9 | } 10 | .sc-ext-treelist-path:before { 11 | content: "[" 12 | } 13 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/models/SitecoreSearchResults.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Launcher.Models { 4 | export class SitecoreSearchResults { 5 | path: string; 6 | id: string; 7 | category: string; 8 | title: string; 9 | img: string; 10 | } 11 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/shortcutsRunner/Token.ts: -------------------------------------------------------------------------------- 1 | namespace SitecoreExtensions.Modules.ShortcutsRunner { 2 | export class Token { 3 | __CSRFTOKEN: string; 4 | __VIEWSTATE: string; 5 | constructor(csrftoken, viewstate) { 6 | this.__CSRFTOKEN = csrftoken; 7 | this.__VIEWSTATE = viewstate; 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /app/common/communication/message/response/GetGlobalStorageResponseMessage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | 4 | namespace SitecoreExtensions.Common.Communication { 5 | export class GetGlobalStorageResponseMessage extends MessageBase { 6 | value: any = null; 7 | constructor() { 8 | super(); 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /app/sc_ext/styles/toggleRibbon.scss: -------------------------------------------------------------------------------- 1 | 2 | .sc-ext-toggleRibon-hidden { 3 | display: none !important; 4 | } 5 | 6 | #sc-ext-toggleRibon-button { 7 | position: fixed; 8 | top: 0; 9 | right: 0; 10 | z-index: 9999; 11 | background: url('/sitecore/shell/Themes/Standard/images/hamburgermenu_default.png'); 12 | width: 63px; 13 | height: 31px; 14 | } -------------------------------------------------------------------------------- /app/options/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sc_ext_options", 3 | "description": "Sitecore Extensions Options Libraries", 4 | "dependencies": { 5 | "angular": "1.4.7", 6 | "angular-formly": "8.2.1", 7 | "angular-formly-templates-bootstrap": "latest", 8 | "api-check": "7.5.5", 9 | "bootstrap": "3.3.5", 10 | "jquery": "1.11.2" 11 | }, 12 | "private": true 13 | } -------------------------------------------------------------------------------- /app/options/directives/NavigationDirective.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | export function NavigationDirective(): ng.IDirective { 6 | return { 7 | restrict: 'E', 8 | scope: false, 9 | templateUrl: 'views/snippets/navigation.html' 10 | }; 11 | } 12 | } -------------------------------------------------------------------------------- /app/common/communication/message/response/GetOptionsResponseMessage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Common.Communication { 4 | export class GetOptionsResponseMessage extends MessageBase { 5 | optionsWrapper: SitecoreExtensions.Options.OptionsWrapper = null; 6 | constructor() { 7 | super(); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /app/common/communication/message/request/GetGlobalStorageRequestMessage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | 4 | namespace SitecoreExtensions.Common.Communication { 5 | export class GetGlobalStorageRequestMessage extends MessageBase { 6 | key: string; 7 | constructor(key: string) { 8 | super(); 9 | this.key = key; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /app/sc_ext/events/args/DatabaseChangeEventArgs.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Events { 4 | export class DatabaseChangeEventArgs extends EventArgs { 5 | constructor(public databaseName: string) { 6 | super(); 7 | this.eventName = "onDatabaseChange"; 8 | this.databaseName = databaseName; 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: 'bug' 6 | assignees: 'alan-null' 7 | 8 | --- 9 | 10 | ### Steps to Reproduce the Problem 11 | 1. 12 | 1. 13 | 1. 14 | 15 | ### Expected Behavior 16 | ... 17 | 18 | ### Actual Behavior 19 | ... 20 | 21 | ### Specifications 22 | Sitecore version: X.X (revision YYYYY) 23 | -------------------------------------------------------------------------------- /app/common/communication/message/response/GetModuleOptionsResponseMessage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Common.Communication { 4 | export class GetModuleOptionsResponseMessage extends MessageBase { 5 | moduleOptions: SitecoreExtensions.Options.IModuleOptions = null; 6 | constructor() { 7 | super(); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/placeholder/IPlaceholderCommand.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Placeholder { 4 | export interface IPlaceholderCommand { 5 | click: string; 6 | header: string; 7 | icon: string; 8 | disabledIcon: string; 9 | isDivider: boolean; 10 | tooltip: string; 11 | type: string; 12 | } 13 | } -------------------------------------------------------------------------------- /app/common/communication/message/request/GetModuleOptionsRequestMessage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Common.Communication { 4 | export class GetModuleOptionsRequestMessage extends MessageBase { 5 | moduleName: string; 6 | constructor(moduleName: string) { 7 | super(); 8 | this.moduleName = moduleName; 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /app/options/controllers/OptionsController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | 6 | export class OptionsController extends BaseController { 7 | model: any; 8 | constructor(private $scope: any) { 9 | super(); 10 | $scope.vm = this; 11 | $scope.vm.content = "views/general.html"; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/goToDatasource/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// 8 | /// 9 | /// -------------------------------------------------------------------------------- /app/options/interfaces/ILinkScope.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | export interface ILinkScope extends ng.IScope { 5 | links: LinkItem[]; 6 | name: string; 7 | url: string; 8 | mode: string; 9 | order: number; 10 | editedLink: LinkItem; 11 | originalLink: LinkItem; 12 | reverted: boolean; 13 | vm: LinksController; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "Sitecore Extensions", 4 | "description": "The name of the application" 5 | }, 6 | "appShortName": { 7 | "message": "sc_ext", 8 | "description": "The short name of the application" 9 | }, 10 | "appDescription": { 11 | "message": "Small improvements which will make your work with Sitecore much easier.", 12 | "description": "The description of the application" 13 | } 14 | } -------------------------------------------------------------------------------- /app/options/controllers/AboutController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | declare var chrome; 6 | export class AboutController extends BaseController { 7 | model: any; 8 | constructor(private $scope: any) { 9 | super(); 10 | $scope.vm = this; 11 | $scope.vm.version = chrome.runtime.getManifest().version; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /app/common/communication/message/request/SetGlobalStorageRequestMessage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | 4 | namespace SitecoreExtensions.Common.Communication { 5 | export class SetGlobalStorageRequestMessage extends MessageBase { 6 | key: string; 7 | value: any; 8 | constructor(key: string, value: any) { 9 | super(); 10 | this.key = key; 11 | this.value = value; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /ci/azure.yml: -------------------------------------------------------------------------------- 1 | pool: 2 | name: Azure Pipelines 3 | steps: 4 | - task: NodeTool@0 5 | displayName: "Use Node 8.2.1" 6 | inputs: 7 | versionSpec: 8.2.1 8 | 9 | - powershell: | 10 | npm install 11 | npm -g install gulp-cli@2.3.0 12 | gulp package 13 | displayName: Main 14 | 15 | - task: PublishBuildArtifacts@1 16 | displayName: "Publish artifacts" 17 | inputs: 18 | PathtoPublish: package 19 | ArtifactName: package 20 | -------------------------------------------------------------------------------- /app/common/communication/message/MessageBase.ts: -------------------------------------------------------------------------------- 1 | namespace SitecoreExtensions.Common.Communication { 2 | export class MessageBase { 3 | public readonly applicationID: string = "SitecoreExtensions"; 4 | protected classNameString: string; 5 | 6 | constructor() { 7 | this.assignClassName(); 8 | } 9 | 10 | protected assignClassName() { 11 | this.classNameString = (this as any).constructor.name; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /app/common/communication/message/request/SetOptionsRequestMessage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import OptionsWrapper = SitecoreExtensions.Options.OptionsWrapper; 4 | 5 | namespace SitecoreExtensions.Common.Communication { 6 | export class SetOptionsRequestMessage extends MessageBase { 7 | options: IModuleOptions[] = null; 8 | constructor(options: IModuleOptions[]) { 9 | super(); 10 | this.options = options; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /app/common/communication/message/request/SetModuleOptionsRequestMessage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import IModuleOptions = SitecoreExtensions.Options.IModuleOptions; 4 | namespace SitecoreExtensions.Common.Communication { 5 | export class SetModuleOptionsRequestMessage extends MessageBase { 6 | moduleOptions: IModuleOptions = null; 7 | 8 | constructor(moduleOptions: IModuleOptions) { 9 | super(); 10 | this.moduleOptions = moduleOptions; 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/databaseColor/DatabaseColorOptions.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.DatabaseColor { 4 | export class DatabaseColorOptions extends Options.ModuleOptions { 5 | colors: Options.DatabaseColorMapping[] = new Array(); 6 | constructor() { 7 | super(); 8 | let defaultcolor = new Options.DatabaseColorMapping("WEB", "DC291E", 0); 9 | this.colors.push(defaultcolor); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/lastLocation/LastLocationStore.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.LastLocation { 4 | export class LastLocationStore { 5 | private static localStorageKey: string = "sc_ext::last_item"; 6 | 7 | public static saveLastItemId(id: string): void { 8 | localStorage.setItem(this.localStorageKey, id); 9 | } 10 | 11 | public static loadLastItemId(): string { 12 | return localStorage.getItem(this.localStorageKey); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/sc_ext/modules/fieldSearch/FieldSearchStore.ts: -------------------------------------------------------------------------------- 1 | namespace SitecoreExtensions.Modules.FieldSearch { 2 | export class FieldSearchStore { 3 | public static key: string = "sc_ext::fieldSearch"; 4 | 5 | public static getInputValue(): string { 6 | return localStorage.getItem(this.key); 7 | } 8 | 9 | public static storeInputValue(str: string): void { 10 | return localStorage.setItem(this.key, str); 11 | } 12 | 13 | public static clear(): void { 14 | localStorage.setItem(this.key, ""); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/placeholder/Rendering.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Placeholder { 4 | export class Rendering { 5 | public placeholder: string; 6 | public uniqueId: string; 7 | constructor(rendering: any) { 8 | this.placeholder = rendering["@ph"]; 9 | this.uniqueId = rendering["@uid"]; 10 | } 11 | 12 | public remove(): void { 13 | let controlId = this.uniqueId.replace(/[-{}]/g, ""); 14 | Sitecore.LayoutDefinition.remove(controlId); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /app/options/views/modules/scrollToItem/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
-------------------------------------------------------------------------------- /app/sc_ext/events/EventHandler.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Events { 4 | declare type EventCallback = (arg: EventArgs) => void; 5 | 6 | export class EventHandler { 7 | constructor(private eventName: string, callback: EventCallback) { 8 | window.addEventListener('message', (event) => { 9 | let args = event.data as EventArgs; 10 | if (args && args.eventName && args.eventName == this.eventName) { 11 | callback(args); 12 | } 13 | }); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /app/common/communication/DataParser.ts: -------------------------------------------------------------------------------- 1 | namespace SitecoreExtensions.Common.Communication { 2 | export class DataParser { 3 | public tryParse(data: any): T { 4 | if (this.validate(data)) { 5 | let deserializer = new SitecoreExtensions.Common.Communication.ObjectDeserializer(); 6 | let instance = deserializer.deserialize(data); 7 | return instance; 8 | } 9 | } 10 | private validate(data: any): boolean { 11 | return data != null && data.applicationID && data.applicationID == "SitecoreExtensions"; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /app/options/views/general.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /app/sc_ext/IdParser.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | namespace SitecoreExtensions { 3 | export class IdParser { 4 | idPattern: string = "{[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}}"; 5 | 6 | constructor() { } 7 | 8 | public extractID(params: string) { 9 | var results = params.match(this.idPattern); 10 | if (results != null && results.length > 0) { 11 | return results[0]; 12 | } 13 | } 14 | 15 | public match(id: string): RegExpMatchArray { 16 | return id.match(this.idPattern); 17 | } 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /app/options/views/modules/dbName/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
-------------------------------------------------------------------------------- /app/options/views/modules/treeScope/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /app/options/views/modules/fieldSearch/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /app/options/views/modules/sectionSwitches/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
-------------------------------------------------------------------------------- /app/options/views/modules/toggleRibbon/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /app/options/views/modules/treelistField/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
-------------------------------------------------------------------------------- /app/options/views/modules/fieldInspector/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /app/options/views/modules/goToDatasource/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /app/options/views/modules/treeAutoExpand/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /app/sc_ext/modules/fieldInspector/FieldInspectorOptions.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.FieldInspector { 4 | export class FieldInspectorOptions extends SitecoreExtensions.Options.ModuleOptions { 5 | fieldName: { 6 | highlightText: boolean 7 | } = { highlightText: true}; 8 | 9 | constructor(wrapper: any) { 10 | super(); 11 | if (wrapper != null) { 12 | this.enabled = wrapper.model.enabled; 13 | this.fieldName.highlightText = wrapper.model.fieldName.highlightText; 14 | }; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/sc_ext/modules/fieldSearch/FieldSearchOptions.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.FieldSearch { 4 | export class FieldSearchOptions extends SitecoreExtensions.Options.ModuleOptions { 5 | inputbox: { 6 | rememberValue: boolean 7 | } = { rememberValue: true}; 8 | 9 | constructor(wrapper: any) { 10 | super(); 11 | if (wrapper != null) { 12 | this.enabled = wrapper.model.enabled; 13 | this.inputbox.rememberValue = wrapper.model.inputbox.rememberValue == "remmeber"; 14 | }; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/sc_ext/options/OptionsAutoMapper.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Options { 4 | export interface IOptionsMapper { 5 | mapOptions(rawOptions: ModuleOptionsBase, otpions: T): T; 6 | } 7 | 8 | export class OptionsAutoMapper implements IOptionsMapper { 9 | mapOptions(rawOptions: ModuleOptionsBase, options: T): T { 10 | for (var f in rawOptions.model) { 11 | if (options.hasOwnProperty(f)) { 12 | options[f] = rawOptions.model[f]; 13 | } 14 | } 15 | return options; 16 | } 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /app/chrome/popup/scripts/popup-new-version.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | 5 | 6 | 'use strict'; 7 | 8 | chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) { 9 | var activeTab = tabs[0]; 10 | chrome.tabs.sendMessage(activeTab.id, { 11 | sc_ext_setVersion_request: true, 12 | version: chrome.runtime.getManifest().version 13 | }, () => { 14 | chrome.tabs.create({ url: "https://alan-null.github.io/redirect/sc-ext-update" }); 15 | }); 16 | }); -------------------------------------------------------------------------------- /app/options/views/modules/databaseSelector/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /app/options/views/modules/restoreLastLocation/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
-------------------------------------------------------------------------------- /app/sc_ext/modules/goToDatasource/fields/DropLink.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.GoToDatasource.Fields { 4 | 5 | export class DropLink extends DatasourceField implements IDatasourceField { 6 | constructor(selectElement: HTMLSelectElement) { 7 | super(selectElement); 8 | } 9 | 10 | public initialize() { 11 | this.innerElement.classList.add(this.className); 12 | this.innerElement.addEventListener("change", (e) => { 13 | this.refreshButton(); 14 | }); 15 | this.refreshButton(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/options/views/modules/headerQuickInfoExtender/index.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |
6 | 7 | 8 | 9 |
10 |
11 |
12 |
-------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/providers/BaseCommand.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Launcher.Providers { 4 | export abstract class BaseCommand implements ICommand { 5 | id: number; 6 | name: string; 7 | description: string; 8 | url: string; 9 | 10 | constructor(name: string, description: string, url: string) { 11 | this.id = 0; 12 | this.name = name; 13 | this.description = description; 14 | this.url = url; 15 | } 16 | 17 | abstract canExecute(); 18 | 19 | abstract execute(evt: UserActionEvent); 20 | } 21 | } -------------------------------------------------------------------------------- /app/common/communication/ObjectDeserializer.ts: -------------------------------------------------------------------------------- 1 | namespace SitecoreExtensions.Common.Communication { 2 | export class ObjectDeserializer { 3 | public deserialize(data: any): T { 4 | let instance = new SitecoreExtensions.Common.Communication[data.classNameString](); 5 | instance = this.mapOptions(data, instance); 6 | return instance as T; 7 | } 8 | 9 | mapOptions(rawOptions: any, options: T): T { 10 | for (var f in rawOptions) { 11 | if (options.hasOwnProperty(f)) { 12 | options[f] = rawOptions[f]; 13 | } 14 | } 15 | return options; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/*.js.map": { 4 | "when": "$(basename)" 5 | }, 6 | "**/*.js": { 7 | "when": "$(basename).ts" 8 | }, 9 | "**/*.css": { 10 | "when": "$(basename).scss" 11 | }, 12 | "app/common/*.js": true, 13 | "app/common/*.js.map": true, 14 | "app/sc_ext/libraries/*.js": true, 15 | "app/sc_ext/libraries/*.css": true, 16 | }, 17 | "files.trimTrailingWhitespace": true, 18 | "search.exclude": { 19 | "**/dist": true 20 | }, 21 | "files.defaultLanguage": "typescript", 22 | "files.associations": { 23 | "**/ci/*.yml": "azure-pipelines" 24 | }, 25 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/models/SearchResult.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Launcher.Models { 4 | export class SearchResult { 5 | command: ICommand; 6 | score: number; 7 | term: string; 8 | highlightedTerm: string; 9 | 10 | public static Cast(command: ICommand): SearchResult { 11 | if (command != null) { 12 | var sr = { 13 | command: command, 14 | score: 200, 15 | term: command.name, 16 | highlightedTerm: command.name, 17 | }; 18 | return sr; 19 | } 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /app/sc_ext/styles/headerQuickInfoExtender.scss: -------------------------------------------------------------------------------- 1 | .sc-ext-quickInfoExtender { 2 | position: relative; 3 | display: inline-block; 4 | width: 250px !important; 5 | 6 | input { 7 | padding-right: 0 !important; 8 | box-sizing: content-box !important; 9 | } 10 | 11 | span { 12 | cursor: pointer; 13 | margin-left: 5px; 14 | } 15 | 16 | .sc-ext-quickInfoExtender-svg-icon { 17 | width: 15px; 18 | height: 100%; 19 | margin-bottom: -3px; 20 | color: #515151; 21 | } 22 | } 23 | 24 | // Override default Sitecore button inline style 25 | .sc-ext-quickInfoExtender[data-item-id] { 26 | input.scEditorHeaderQuickInfoInput, 27 | input.scEditorHeaderQuickInfoInputID { 28 | width: 16rem !important; 29 | } 30 | } -------------------------------------------------------------------------------- /app/options/controllers/ScrollToItemController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | export class ScrollToItemController extends BaseOptionsController { 6 | constructor($scope: any, formlyVersion: string) { 7 | super($scope, formlyVersion, 'Scroll To Item'); 8 | $scope.vm.title = 'Scroll To Item module'; 9 | } 10 | 11 | getFields() { 12 | return [ 13 | { 14 | key: 'enabled', 15 | type: 'checkbox', 16 | defaultValue: true, 17 | templateOptions: { 18 | label: 'Enabled' 19 | } 20 | }, 21 | ]; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /app/options/controllers/TreeScopeController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | export class TreeScopeController extends BaseOptionsController { 6 | constructor($scope: any, formlyVersion: string) { 7 | super($scope, formlyVersion, 'Tree Scope'); 8 | $scope.vm.title = 'Tree Scope module'; 9 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki/Tree-Scope'; 10 | } 11 | 12 | getFields() { 13 | return [ 14 | { 15 | key: 'enabled', 16 | type: 'checkbox', 17 | defaultValue: true, 18 | templateOptions: { 19 | label: 'Enabled' 20 | } 21 | }, 22 | ]; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sc-ext", 3 | "private": true, 4 | "engines": { 5 | "node": ">=v8.2.1" 6 | }, 7 | "scripts": { 8 | "watch": "gulp watch", 9 | "build": "gulp build", 10 | "package": "gulp package" 11 | }, 12 | "devDependencies": { 13 | "del": "^2.2.0", 14 | "gulp": "^3.9.1", 15 | "gulp-clean-css": "^2.0.3", 16 | "gulp-if": "^2.0.0", 17 | "gulp-htmlmin": "^1.3.0", 18 | "gulp-size": "^2.1.0", 19 | "gulp-sourcemaps": "^1.6.0", 20 | "gulp-uglify": "^1.5.3", 21 | "gulp-zip": "^3.2.0", 22 | "gulp-tslint": "7.1.0", 23 | "run-sequence": "^1.1.5", 24 | "typescript": "2.2.1", 25 | "tslint": "4.5.1", 26 | "gulp-typescript": "3.1.6", 27 | "gulp-sass": "3.1.0", 28 | "gulp-concat": "2.6.0", 29 | "gulp-string-replace": "0.4.0", 30 | "sass-lint": "1.11.1", 31 | "izitoast": "1.4.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/options/controllers/DatabaseNameController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | export class DatabaseNameController extends BaseOptionsController { 6 | constructor($scope: any, formlyVersion: string) { 7 | super($scope, formlyVersion, 'Database Name'); 8 | $scope.vm.title = 'Database Name module'; 9 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki/Database-Name'; 10 | } 11 | 12 | getFields() { 13 | return [ 14 | { 15 | key: 'enabled', 16 | type: 'checkbox', 17 | defaultValue: true, 18 | templateOptions: { 19 | label: 'Enabled' 20 | } 21 | }, 22 | ]; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/options/controllers/ToggleRibbonController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | export class ToggleRibbonController extends BaseOptionsController { 6 | constructor($scope: any, formlyVersion: string) { 7 | super($scope, formlyVersion, 'Toggle Ribbon'); 8 | $scope.vm.title = 'Toggle Ribbon module'; 9 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki/Toggle-Ribbon'; 10 | } 11 | 12 | getFields() { 13 | return [ 14 | { 15 | key: 'enabled', 16 | type: 'checkbox', 17 | defaultValue: true, 18 | templateOptions: { 19 | label: 'Enabled' 20 | } 21 | }, 22 | ]; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/shortcutsRunner/providers/AppShortcutCommand.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.ShortcutsRunner.Providers { 4 | import ICommand = Launcher.ICommand; 5 | 6 | export class AppShortcutCommand extends Launcher.Providers.BaseCommand implements ICommand { 7 | runner: ShortcutRunner; 8 | shortcutID: string; 9 | 10 | constructor(name: string, description: string, runner: ShortcutRunner, shortcutID: string) { 11 | super(name, description, ""); 12 | this.shortcutID = shortcutID; 13 | this.runner = runner; 14 | } 15 | 16 | public canExecute(): boolean { 17 | return true; 18 | } 19 | 20 | public execute(evt?: KeyboardEvent): void { 21 | this.runner.runShortcutCommand(this.shortcutID, evt); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /app/options/controllers/GoToDatasourceController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | export class GoToDatasourceController extends BaseOptionsController { 6 | constructor($scope: any, formlyVersion: string) { 7 | super($scope, formlyVersion, 'Go To Datasource'); 8 | $scope.vm.title = 'Go To Datasource module'; 9 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki/Go-To-Datasource'; 10 | } 11 | 12 | getFields() { 13 | return [ 14 | { 15 | key: 'enabled', 16 | type: 'checkbox', 17 | defaultValue: true, 18 | templateOptions: { 19 | label: 'Enabled' 20 | } 21 | }, 22 | ]; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/options/controllers/TreeAutoExpandController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | export class TreeAutoExpandController extends BaseOptionsController { 6 | constructor($scope: any, formlyVersion: string) { 7 | super($scope, formlyVersion, 'Tree Auto Expand'); 8 | $scope.vm.title = 'Tree Auto Expand module'; 9 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki/Tree-Auto-Expand'; 10 | } 11 | 12 | getFields() { 13 | return [ 14 | { 15 | key: 'enabled', 16 | type: 'checkbox', 17 | defaultValue: true, 18 | templateOptions: { 19 | label: 'Enabled' 20 | } 21 | }, 22 | ]; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/options/controllers/TreelistFieldController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | 6 | export class TreelistFieldController extends BaseOptionsController { 7 | constructor($scope: any, formlyVersion: string) { 8 | super($scope, formlyVersion, 'Treelist Field'); 9 | $scope.vm.title = 'Treelist Field module'; 10 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki/Treelist-Field'; 11 | } 12 | 13 | getFields() { 14 | return [ 15 | { 16 | key: 'enabled', 17 | type: 'checkbox', 18 | defaultValue: true, 19 | templateOptions: { 20 | label: 'Enabled' 21 | } 22 | }, 23 | ]; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/options/controllers/DatabaseSelectorController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | export class DatabaseSelectorController extends BaseOptionsController { 6 | constructor($scope: any, formlyVersion: string) { 7 | super($scope, formlyVersion, 'Database Selector'); 8 | $scope.vm.title = 'Database Selector module'; 9 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki/Database-Selector'; 10 | } 11 | 12 | getFields() { 13 | return [ 14 | { 15 | key: 'enabled', 16 | type: 'checkbox', 17 | defaultValue: true, 18 | templateOptions: { 19 | label: 'Enabled' 20 | } 21 | }, 22 | ]; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/options/controllers/SectionSwitchesController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | 6 | export class SectionSwitchesController extends BaseOptionsController { 7 | constructor($scope: any, formlyVersion: string) { 8 | super($scope, formlyVersion, 'Section Switches'); 9 | $scope.vm.title = 'Section Switches module'; 10 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki/Section-Switches'; 11 | } 12 | 13 | getFields() { 14 | return [ 15 | { 16 | key: 'enabled', 17 | type: 'checkbox', 18 | defaultValue: true, 19 | templateOptions: { 20 | label: 'Enabled' 21 | } 22 | }, 23 | ]; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/sc_ext/options/ExtensionsOptions.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Options { 4 | export class ExtensionsOptions extends ModuleOptions { 5 | badge: { 6 | enabled: boolean, 7 | statusType: Status.StatusType 8 | } = { enabled: true, statusType: Status.StatusType.ModulesCount }; 9 | 10 | statusInfo: { 11 | enabled: boolean, 12 | } = { enabled: false }; 13 | 14 | constructor(wrapper: any) { 15 | super(); 16 | if (wrapper != null) { 17 | this.enabled = wrapper.model.enabled; 18 | this.badge.enabled = wrapper.model.badge.enabled; 19 | this.badge.statusType = Status.StatusType[wrapper.model.badge.statusType as string]; 20 | this.statusInfo.enabled = wrapper.model.statusInfo.enabled; 21 | }; 22 | } 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /app/options/controllers/RestoreLastLocationController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | 6 | export class RestoreLastLocationController extends BaseOptionsController { 7 | constructor($scope: any, formlyVersion: string) { 8 | super($scope, formlyVersion, 'Restore Last Location'); 9 | $scope.vm.title = 'Restore Last Location module'; 10 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki/Restore-Last-Location'; 11 | } 12 | 13 | getFields() { 14 | return [ 15 | { 16 | key: 'enabled', 17 | type: 'checkbox', 18 | defaultValue: true, 19 | templateOptions: { 20 | label: 'Enabled' 21 | } 22 | }, 23 | ]; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/options/controllers/HeaderQuickInfoExtenderController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | export class HeaderQuickInfoExtenderController extends BaseOptionsController { 6 | constructor($scope: any, formlyVersion: string) { 7 | super($scope, formlyVersion, 'Header QuickInfo Extender'); 8 | $scope.vm.title = 'Header QuickInfo Extender module'; 9 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki/Header-QuickInfo-Extender'; 10 | } 11 | 12 | getFields() { 13 | return [ 14 | { 15 | key: 'enabled', 16 | type: 'checkbox', 17 | defaultValue: true, 18 | templateOptions: { 19 | label: 'Enabled' 20 | } 21 | }, 22 | ]; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /app/options/views/settings.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

{{::vm.title}}

5 |

Reset settings to default:

6 | 7 |
8 | After you click reset button, all your personal settings will be changed to default. 9 |
10 |
11 | 12 |

Export settings:

13 | 14 |

Import settings:

15 | 16 | 17 |
18 |
19 |
-------------------------------------------------------------------------------- /app/options/views/modules/launcher/index.html: -------------------------------------------------------------------------------- 1 |
2 | 12 |
13 |
14 | To obtain key codes use Sitecore Keyboard Map or 15 | this site. 16 |
17 |
18 |

{{::vm.title}}

19 |
20 | 21 |
22 | 23 |
24 |
25 |
26 |
27 |
28 |
-------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/providers/BaseCommandsProvider.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Launcher.Providers { 4 | export abstract class BaseCommandsProvider implements ICommandsProvider { 5 | commands: ICommand[]; 6 | 7 | constructor() { 8 | this.commands = Array(); 9 | this.createCommands(); 10 | } 11 | getCommands(): ICommand[] { 12 | return this.commands; 13 | } 14 | 15 | abstract createCommands(); 16 | 17 | addInvokeCommand(name: string, description: string, command: string, canExecute: Function): void { 18 | var cmd: ICommand = { 19 | id: 0, 20 | name: name, 21 | description: description, 22 | execute: () => { scForm.invoke(command); }, 23 | canExecute: canExecute 24 | }; 25 | this.commands.push(cmd); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/treeScope/ContentEditorTree.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.TreeScope { 4 | export class ContentEditorTree { 5 | private classHiddenContainer: string = "sc-ext-treescope-hidden-container"; 6 | private firstElement: HTMLDivElement; 7 | private nodesContainer: HTMLDivElement; 8 | 9 | constructor() { 10 | this.nodesContainer = document.querySelector("#ContentTreeActualSize") as HTMLDivElement; 11 | this.firstElement = (this.nodesContainer.childNodes[0]) as HTMLDivElement; 12 | } 13 | 14 | hide(): void { 15 | this.firstElement.classList.add(this.classHiddenContainer); 16 | } 17 | 18 | show(): void { 19 | this.firstElement.classList.remove(this.classHiddenContainer); 20 | } 21 | 22 | addTreeNode(nodeClode: HTMLDivElement): void { 23 | this.nodesContainer.appendChild(nodeClode); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/addHere/AddHereButton.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.AddHere { 4 | export class AddHereButton { 5 | classButtonInitialized: string = "sc-ext-addHere-button-initialized"; 6 | innerElement: HTMLDivElement; 7 | textElement: HTMLSpanElement; 8 | placeholderName: string; 9 | constructor(innerElement: HTMLDivElement) { 10 | this.innerElement = innerElement; 11 | this.textElement = this.innerElement.nextElementSibling.firstChild as HTMLSpanElement; 12 | this.placeholderName = this.innerElement.parentElement.title.match(/'.*'/)[0].replace(/'/g, ""); 13 | this.innerElement.classList.add(this.classButtonInitialized); 14 | } 15 | 16 | public setText(text: string) { 17 | this.textElement.innerText = text; 18 | } 19 | 20 | public getText(): string { 21 | return this.textElement.innerText; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /app/common/_all.ts: -------------------------------------------------------------------------------- 1 | // Directives 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// 8 | /// 9 | /// 10 | /// 11 | /// 12 | /// 13 | /// 14 | /// 15 | -------------------------------------------------------------------------------- /app/sc_ext/status/CommandsStatusProvider.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Status { 4 | import ISitecoreExtensionsModule = Modules.ISitecoreExtensionsModule; 5 | import LauncherModule = Modules.Launcher.LauncherModule; 6 | 7 | export class CommandsStatusProvider implements IStatusProvider { 8 | public getStatus(): string { 9 | return this.getAvailableCommandsCount().toString(); 10 | } 11 | 12 | private getAvailableCommandsCount(): number { 13 | let allCommands = this.getAllCommands(); 14 | let availableCommands = allCommands.filter((m) => { return m.canExecute(); }); 15 | return availableCommands.length; 16 | } 17 | 18 | private getAllCommands(): Modules.Launcher.ICommand[] { 19 | return this.getLauncherModule().commands; 20 | } 21 | 22 | private getLauncherModule(): LauncherModule { 23 | return SitecoreExtensions.scExtManager.getModule(LauncherModule) as LauncherModule; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/lastLocation/RestoreLastLocationCommandProvider.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.LastLocation { 4 | import ICommand = Launcher.ICommand; 5 | 6 | export class RestoreLastLocationCommandProvider implements Launcher.Providers.ICommandsProvider { 7 | getCommands(): ICommand[] { 8 | var cmd: ICommand = { 9 | id: 0, 10 | name: "Restore Last Opened Item", 11 | description: "Restores last opened item in Content Editor", 12 | execute: () => { 13 | var lastItem = LastLocationStore.loadLastItemId(); 14 | if (lastItem) { 15 | let contentTree = new PageObjects.ContentTree(); 16 | contentTree.loadItem(lastItem); 17 | } 18 | }, 19 | canExecute: () => { return Context.Location() == Enums.Location.ContentEditor; } 20 | }; 21 | return [ 22 | cmd 23 | ]; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/_all.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// 8 | /// 9 | /// 10 | /// 11 | /// 12 | /// 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | /// 19 | /// 20 | /// -------------------------------------------------------------------------------- /app/sc_ext/modules/scrollToItem/ScrollToItemModule.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.ScrollToItem { 4 | export class ScrollToItemModule extends ModuleBase implements ISitecoreExtensionsModule { 5 | 6 | constructor(name: string, description: string, rawOptions: Options.ModuleOptionsBase) { 7 | super(name, description, rawOptions); 8 | } 9 | 10 | canExecute(): boolean { 11 | return this.options.enabled && Context.Location() == Enums.Location.ContentEditor; 12 | } 13 | 14 | initialize(): void { 15 | HTMLHelpers.addProxy(scSitecore, 'postEvent', () => { this.scrollToActiveItemAfterChange(); }); 16 | HTMLHelpers.addProxy(scForm, 'invoke', () => { this.scrollToActiveItemAfterChange(); }); 17 | } 18 | 19 | private scrollToActiveItemAfterChange() { 20 | let contentTree = new PageObjects.ContentTree(); 21 | contentTree.onActiveTreeNodeChanged(_ => { 22 | contentTree.scrollToActiveNode(); 23 | }); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Alan Płócieniak 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /app/sc_ext/modules/placeholder/PlaceholderChrome.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Placeholder { 4 | export class PlaceholderChrome { 5 | chrome: any; 6 | 7 | constructor(phChrome: any) { 8 | this.chrome = phChrome; 9 | } 10 | 11 | public addCommand(cmd: IPlaceholderCommand) { 12 | return this.chrome.data.commands.push(cmd); 13 | } 14 | 15 | public getPlaceholderId(): string { 16 | const el = this.chrome._originalDOMElement; 17 | let key: string | undefined = ''; 18 | if (!el) { 19 | return key; 20 | } 21 | if (el.length === 1 && el[0].attributes && el[0].attributes.key && el[0].attributes.key.value) { 22 | key = el[0].attributes.key.value; 23 | } 24 | else if (el.context && el.context.attributes && el.context.attributes.key && el.context.attributes.key.value) { 25 | key = el.context.attributes.key.value; 26 | } 27 | return typeof key === 'string' ? key : ''; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /app/options/services/LinkStorage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | 6 | export class LinkStorage implements ILinksStorage { 7 | STORAGE_ID = 'Links'; 8 | optionsProvider: OptionsProvider; 9 | 10 | constructor() { 11 | this.optionsProvider = new OptionsProvider(); 12 | } 13 | 14 | get(coldStorageCb?: any): LinkItem[] { 15 | this.optionsProvider.getModuleOptions(this.STORAGE_ID, (options: IModuleOptions) => { 16 | if (options && options.model) { 17 | if (coldStorageCb) { 18 | coldStorageCb(options.model); 19 | } 20 | } 21 | }); 22 | return JSON.parse(localStorage.getItem(this.STORAGE_ID) || '[]'); 23 | } 24 | 25 | put(links: LinkItem[]) { 26 | localStorage.setItem(this.STORAGE_ID, JSON.stringify(links)); 27 | var moduleOptions = new ModuleOptionsBase(this.STORAGE_ID, links as any); 28 | this.optionsProvider.setModuleOptions(moduleOptions); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/toggleRibbon/Ribbon.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.ToggleRibbon { 4 | export class Ribbon { 5 | private nodeRibbon: HTMLDivElement; 6 | private classHidden: string = "sc-ext-toggleRibon-hidden"; 7 | 8 | constructor() { 9 | this.nodeRibbon = top.window.document.querySelector("#scWebEditRibbon") as HTMLDivElement; 10 | } 11 | public isInitialized(): boolean { 12 | return this.getContainerNode() != null; 13 | } 14 | 15 | public show() { 16 | let nodeContainer = this.getContainerNode(); 17 | nodeContainer.classList.remove(this.classHidden); 18 | this.nodeRibbon.classList.remove(this.classHidden); 19 | } 20 | 21 | public hide() { 22 | let nodeContainer = this.getContainerNode(); 23 | nodeContainer.classList.add(this.classHidden); 24 | this.nodeRibbon.classList.add(this.classHidden); 25 | } 26 | 27 | private getContainerNode(): HTMLDivElement { 28 | return (top.window.document.querySelector("#scCrossPiece") as HTMLDivElement); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /app/options/controllers/FieldInspectorController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | export class FieldInspectorController extends BaseOptionsController { 6 | constructor($scope: any, formlyVersion: string) { 7 | super($scope, formlyVersion, 'Field Inspector'); 8 | $scope.vm.title = 'Field Inspector module'; 9 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki/Field-Inspector'; 10 | } 11 | 12 | getFields() { 13 | return [ 14 | { 15 | key: 'enabled', 16 | type: 'checkbox', 17 | defaultValue: true, 18 | templateOptions: { 19 | label: 'Enabled' 20 | } 21 | }, 22 | { 23 | key: 'fieldName.highlightText', 24 | type: 'checkbox', 25 | defaultValue: true, 26 | templateOptions: { 27 | label: 'Highlight field name' 28 | } 29 | }, 30 | ]; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/ModuleBase.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules { 4 | import ModuleOptions = Options.ModuleOptions; 5 | import ModuleOptionsBase = Options.ModuleOptionsBase; 6 | 7 | export class ModuleBase { 8 | moduleName: string; 9 | description: string; 10 | options: ModuleOptions; 11 | optionsMapper: SitecoreExtensions.Options.IOptionsMapper; 12 | constructor(name: string, description: string, rawOptions?: ModuleOptionsBase) { 13 | this.moduleName = name; 14 | this.description = description; 15 | this.options = new ModuleOptions(); 16 | if (rawOptions != null) { 17 | this.mapOptions(rawOptions); 18 | } 19 | } 20 | 21 | getOptionsMapper(): SitecoreExtensions.Options.IOptionsMapper { 22 | return new SitecoreExtensions.Options.OptionsAutoMapper(); 23 | } 24 | 25 | mapOptions(rawOptions: ModuleOptionsBase) { 26 | if (rawOptions != null) { 27 | this.options = this.getOptionsMapper().mapOptions(rawOptions, this.options); 28 | } 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/providers/NavigationCommand.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Launcher.Providers { 4 | export interface UserActionEvent { 5 | altKey: boolean; 6 | ctrlKey: boolean; 7 | } 8 | 9 | export class NavigationCommand extends BaseCommand implements ICommand { 10 | constructor(name: string, description: string, url: string) { 11 | super(name, description, url); 12 | } 13 | 14 | canExecute(): boolean { 15 | return true; 16 | } 17 | 18 | execute(evt: UserActionEvent): void { 19 | if (evt && evt.ctrlKey) { 20 | this.openInNewTab(); 21 | } else { 22 | this.openInCurrentTab(); 23 | } 24 | } 25 | 26 | private openInCurrentTab(): void { 27 | window.top.document.location.href = this.url; 28 | } 29 | 30 | private openInNewTab(): void { 31 | var virtualLink = HTMLHelpers.createElement("a", { 32 | target: "_blank", 33 | href: this.url 34 | }) as HTMLLinkElement; 35 | virtualLink.click(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/toggleRibbon/ToggleButton.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.ToggleRibbon { 4 | export class ToggleButton { 5 | innerElement: HTMLDivElement; 6 | private classHidden: string = "sc-ext-toggleRibon-hidden"; 7 | 8 | constructor(toggleHandler: any) { 9 | this.innerElement = HTMLHelpers.createElement("div", { id: "sc-ext-toggleRibon-button" }) as HTMLDivElement; 10 | this.innerElement.onclick = () => { toggleHandler(); }; 11 | document.body.appendChild(this.innerElement); 12 | } 13 | 14 | public updatePosition(isVisible: boolean): void { 15 | if (isVisible) { 16 | this.innerElement.style.right = '50px'; 17 | this.innerElement.style.top = '58px'; 18 | } else { 19 | this.innerElement.style.right = '0'; 20 | this.innerElement.style.top = '0'; 21 | } 22 | } 23 | 24 | public show() { 25 | this.innerElement.classList.remove(this.classHidden); 26 | } 27 | 28 | public hide() { 29 | this.innerElement.classList.add(this.classHidden); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /app/sc_ext/storage/GlobalStorage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Storage { 4 | export class GlobalStorage { 5 | public static set(key: string, value: any): void { 6 | let message = new Communication.SetGlobalStorageRequestMessage(key, value); 7 | window.postMessage(message, '*'); 8 | } 9 | 10 | public static async get(key: string): Promise { 11 | return new Promise(returnValue => { 12 | window.addEventListener('message', function (event) { 13 | let validator = new Communication.DataParser(); 14 | let instance = validator.tryParse(event.data); 15 | if (instance instanceof Communication.GetGlobalStorageResponseMessage) { 16 | if (instance.value) { 17 | returnValue(instance.value); 18 | } else { 19 | returnValue(null); 20 | } 21 | } 22 | }); 23 | let message = new Communication.GetGlobalStorageRequestMessage(key); 24 | window.postMessage(message, '*'); 25 | }); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /app/sc_ext/http/HttpRequest.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Http { 4 | export class HttpRequest { 5 | private url: string; 6 | private method: Method; 7 | private callback: any; 8 | 9 | constructor(url: string, method: Method, callback) { 10 | this.url = url; 11 | this.method = method; 12 | this.callback = callback; 13 | } 14 | 15 | public execute(postData?: any) { 16 | var method = this.getMethodValue(this.method); 17 | var async = true; 18 | var request = new XMLHttpRequest(); 19 | request.onload = this.callback; 20 | request.open(method, this.url, async); 21 | request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 22 | if (postData) { 23 | request.send(postData); 24 | } else { 25 | request.send(); 26 | } 27 | } 28 | 29 | private getMethodValue(method: Method): string { 30 | switch (method) { 31 | case Method.POST: 32 | return "POST"; 33 | case Method.GET: 34 | return "GET"; 35 | } 36 | return "GET"; 37 | } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /app/sc_ext/modules/goToDatasource/fields/ListField.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.GoToDatasource.Fields { 4 | export class ListField extends DatasourceField implements IDatasourceField { 5 | constructor(selectElement: HTMLSelectElement) { 6 | super(selectElement); 7 | } 8 | 9 | public initialize() { 10 | this.innerElement.classList.add(this.className); 11 | 12 | this.innerElement.addEventListener("change", (e) => { 13 | this.refreshButton(); 14 | }); 15 | 16 | let options = this.getOptions(); 17 | for (let k = 0; k < options.length; k++) { 18 | options[k].addEventListener("dblclick", () => { 19 | let oldVal = this.getSelectedValue(); 20 | HTMLHelpers.postponeAction(() => { 21 | return this.getSelectedValue() != oldVal; 22 | }, () => { 23 | this.refreshButton(); 24 | }, 10, 10); 25 | }); 26 | } 27 | 28 | this.destination.parentElement.querySelectorAll(".scNavButton")[1].addEventListener("click", () => { 29 | this.refreshButton(); 30 | }); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/sc_ext/styles/fieldSearch.scss: -------------------------------------------------------------------------------- 1 | .scEditorTabControls { 2 | input[type="text"].sc-ext-fieldSearch { 3 | display: inline !important; 4 | margin-right: 10px; 5 | height: 26px; 6 | min-height: 26px; 7 | width: 130px !important; 8 | } 9 | } 10 | 11 | .sc-ext-hiddenElement { 12 | display: none; 13 | } 14 | 15 | .sc-ext-forceExpandedElement { 16 | display: table !important; 17 | } 18 | 19 | span.sc-ext-searchFieldContainer { 20 | position: relative; 21 | span.sc-ext-fieldSearchClear { 22 | position: absolute; 23 | display: block; 24 | border-top: 6px solid white; 25 | border-bottom: 6px solid white; 26 | border-right: 6px solid white; 27 | top: -3px; 28 | right: 11px; 29 | width: 10px; 30 | height: 10px; 31 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAQAAABKfvVzAAAAAmJLR0QAAKqNIzIAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgBR4PNzAfNMlbAAAA1klEQVQ4y+WTKxKDMBCGlz4U+KZoBAfoPdoroAgaTwYRU1ofPDM9QHuB+poydfELChdNBcNQIDD1/CrJ/N8+sgnAsvW+cIlseIqMyzzp9qtu+ThWjqB9BJkIKud+0gJeZpaK/CLIRKB2VuFlE0Uhi4qwjooGQRaVYc2wn9MYIoIqYpZUADTR/dSOZ4AOAUNn1wBt5QA6e6/p/7TWx7eKrVL73L1Z1+cs0Nr99PDKXUXGyEZvt2MABEEVERRh3Ano770/l5G4HI+pQbjUAnky9fg+54X/yy88t4P7PozvzAAAAABJRU5ErkJggg==') 17px 17px; 32 | cursor: pointer; 33 | } 34 | input { 35 | padding-right: 16px; 36 | } 37 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/treeAutoExpand/TreeNodeGlyph.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.TreeAutoExpand { 4 | export class TreeNodeGlyph { 5 | private iconExpanded: string = "/sitecore/shell/themes/standard/images/treemenu_expanded.png"; 6 | private iconNonExpand: string = "/sitecore/shell/themes/standard/images/noexpand15x15.gif"; 7 | private iconCollapsed: string = "sitecore/shell/themes/standard/images/treemenu_collapsed.png"; 8 | private treeNodeGlyphElement: HTMLImageElement; 9 | 10 | constructor(elementId: string) { 11 | this.treeNodeGlyphElement = document.getElementById(elementId) as HTMLImageElement; 12 | } 13 | 14 | isExpanded(): boolean { 15 | let isExpanded = this.treeNodeGlyphElement.src.endsWith(this.iconExpanded); 16 | return isExpanded; 17 | } 18 | 19 | isExpandable(): boolean { 20 | if (this.treeNodeGlyphElement && this.treeNodeGlyphElement.src) { 21 | return !this.treeNodeGlyphElement.src.endsWith(this.iconNonExpand) && !this.treeNodeGlyphElement.src.endsWith(this.iconCollapsed); 22 | } else { 23 | return false; 24 | } 25 | } 26 | 27 | getChildren() { 28 | return this.treeNodeGlyphElement.parentElement.querySelectorAll(".scContentTreeNode"); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /app/options/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Sitecore Extensions Options 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 28 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 | 37 | 38 |
39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /app/sc_ext/types/Dictionary.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Types { 4 | export class Dictionary implements IDictionary { 5 | keys: string[] = new Array(); 6 | values: any[] = new Array(); 7 | 8 | constructor(init: { key: string; value: any; }[]) { 9 | for (var x = 0; x < init.length; x++) { 10 | this[init[x].key] = init[x].value; 11 | this.keys.push(init[x].key); 12 | this.values.push(init[x].value); 13 | } 14 | } 15 | 16 | add(key: string, value: any) { 17 | this[key] = value; 18 | this.keys.push(key); 19 | this.values.push(value); 20 | } 21 | 22 | remove(key: string) { 23 | var index = this.keys.indexOf(key, 0); 24 | this.keys.splice(index, 1); 25 | this.values.splice(index, 1); 26 | 27 | delete this[key]; 28 | } 29 | 30 | getKeys(): string[] { 31 | return this.keys; 32 | } 33 | 34 | getValues(): any[] { 35 | return this.values; 36 | } 37 | 38 | containsKey(key: string) { 39 | if (typeof this[key] === "undefined") { 40 | return false; 41 | } 42 | return true; 43 | } 44 | 45 | toLookup(): IDictionary { 46 | return this; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /PRIVACY_POLICY.md: -------------------------------------------------------------------------------- 1 | # Privacy Policy for *Sitecore Extensions* 2 | 3 | **Effective date:** April 16, 2016 4 | 5 | ***Sitecore Extensions*** respects your privacy. This extension does **not** collect, store, transmit, or share any personal data with anyone. 6 | 7 | 8 | ## Data Collection and Usage 9 | 10 | This extension does not collect any personally identifiable information (PII). 11 | 12 | All user preferences and settings are stored **locally on your device** using the browser’s built-in storage mechanisms (such as `chrome.storage.local` or local files). No information leaves your device. 13 | 14 | 15 | ## Data Sharing 16 | 17 | This extension does not use any third-party analytics, advertising, or tracking services. 18 | No data is transmitted to external servers or shared with third parties. 19 | 20 | 21 | ## User Access and Control 22 | 23 | Because no data is collected or transmitted, there are no user controls required for managing data sharing or deletion. 24 | 25 | You can remove all locally stored data at any time by uninstalling the extension from your browser. 26 | 27 | 28 | ## Changes to This Policy 29 | 30 | If future updates introduce new features that involve data handling, this privacy policy will be updated to reflect those changes. 31 | 32 | 33 | ## Contact 34 | 35 | If you have any questions or concerns about this privacy policy, you can contact us at: [📧](mailto:SitecoreExtensions@duck.com?subject=Sitecore%20Extensions%20Privacy%20Policy%20Inquiry) -------------------------------------------------------------------------------- /app/chrome/popup/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 33 |
34 | 35 |
36 |
37 | Modules: 38 | [sc_ext_modules_count] 39 |
40 |
41 | Commands: 42 | [sc_ext_commands_count] 43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /app/sc_ext/modules/sectionSwitches/SectionSwitchesCommandsProvider.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.SectionSwitches { 4 | import ICommand = SitecoreExtensions.Modules.Launcher.ICommand; 5 | 6 | export class SectionSwitchesCommandsProvider implements Launcher.Providers.ICommandsProvider { 7 | commands: ICommand[]; 8 | constructor() { 9 | this.commands = new Array(); 10 | this.initCommands(); 11 | } 12 | 13 | initCommands(): void { 14 | var cmd1: ICommand = { 15 | id: 0, 16 | name: 'Open sections', 17 | description: 'Open all closed sections', 18 | execute: SectionSwitches.SectionSwitchesModule.prototype.openClosedSections, 19 | canExecute: () => { return Context.Location() == Enums.Location.ContentEditor; } 20 | }; 21 | var cmd2: ICommand = { 22 | id: 0, 23 | name: 'Close sections', 24 | description: 'Close all opened sections', 25 | execute: SectionSwitches.SectionSwitchesModule.prototype.closeOpenedSections, 26 | canExecute: () => { return Context.Location() == Enums.Location.ContentEditor; } 27 | }; 28 | this.commands.push(cmd1); 29 | this.commands.push(cmd2); 30 | } 31 | 32 | getCommands(): ICommand[] { 33 | return this.commands; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/chrome/background.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | 'use strict'; 5 | 6 | chrome.runtime.onInstalled.addListener(details => { 7 | console.log('previousVersion', details.previousVersion); 8 | console.log('currentVersion', chrome.runtime.getManifest().version); 9 | }); 10 | 11 | chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { 12 | if (sender.tab == null) { 13 | console.log("Tab cannot be null"); 14 | return; 15 | } 16 | if (request.sc_ext_setBadgeText_request) { 17 | chrome.action.setBadgeText({ tabId: sender.tab.id, text: request.modulesCount }); 18 | } 19 | if (request.sc_ext_setIcon_request) { 20 | chrome.action.setIcon({ 21 | path: chrome.runtime.getURL(request.newIconPath), 22 | tabId: sender.tab.id 23 | }); 24 | } 25 | chrome.action.setPopup({ 26 | tabId: sender.tab.id, 27 | popup: 'chrome/popup/popup.html' 28 | }); 29 | chrome.action.setBadgeBackgroundColor({ color: '#666' }); 30 | 31 | if (request.sc_ext_checkVersion_request) { 32 | console.log(chrome.runtime.getManifest().version); 33 | console.log(request.version); 34 | 35 | if (request.version == null || request.version != chrome.runtime.getManifest().version) { 36 | chrome.action.setBadgeText({ tabId: sender.tab.id, text: "NEW", }); 37 | chrome.action.setPopup({ 38 | tabId: sender.tab.id, 39 | popup: 'chrome/popup/popup-new-version.html' 40 | }); 41 | } 42 | } 43 | }); -------------------------------------------------------------------------------- /app/common/GlobalStorage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | namespace SitecoreExtensions.Common { 5 | export class GlobalStorage { 6 | public static async get(key: string): Promise { 7 | return new Promise(returnValue => { 8 | chrome.storage.local.get({ 9 | sc_ext_globalStorage: null, 10 | }, function (items: any) { 11 | if (items.sc_ext_globalStorage) { 12 | returnValue(items.sc_ext_globalStorage[key]); 13 | } 14 | returnValue(null); 15 | }); 16 | }); 17 | } 18 | 19 | 20 | public static async set(key: string, value: any): Promise { 21 | let storage = await this.getStorage(); 22 | storage[key] = value; 23 | chrome.storage.local.set({ 24 | sc_ext_globalStorage: storage, 25 | }, () => { }); 26 | } 27 | private static async getStorage(): Promise { 28 | return new Promise(returnValue => { 29 | chrome.storage.local.get({ 30 | sc_ext_globalStorage: null, 31 | }, function (items: any) { 32 | if (items.sc_ext_globalStorage) { 33 | returnValue(items.sc_ext_globalStorage); 34 | } 35 | returnValue({}); 36 | }); 37 | }); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/providers/UserDefinedLinksCommandsProvider.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Launcher.Providers { 4 | class UserDefinedLink extends NavigationCommand implements ICommand { 5 | constructor(name: string, description: string, url: string) { 6 | if (!url.startsWith('http')) { 7 | let connector = url.startsWith('/') ? "" : '/'; 8 | url = window.top.location.origin + connector + url; 9 | } 10 | super(name, description, url); 11 | } 12 | } 13 | 14 | export class UserDefinedLinksCommandsProvider implements ICommandsProvider { 15 | commands: ICommand[]; 16 | links: SitecoreExtensions.Options.LinkItem[]; 17 | 18 | constructor(rawOptions: Options.ModuleOptionsBase) { 19 | this.commands = Array(); 20 | if (rawOptions) { 21 | this.links = rawOptions.model; 22 | this.createCommands(); 23 | } 24 | } 25 | 26 | createCommands(): void { 27 | for (var index = 0; index < this.links.length; index++) { 28 | var link = this.links[index]; 29 | this.addCommand(link.name, link.url, link.url); 30 | } 31 | } 32 | 33 | addCommand(name: string, description: string, url: string): void { 34 | this.commands.push(new UserDefinedLink(name, description, url)); 35 | } 36 | 37 | getCommands(): ICommand[] { 38 | return this.commands; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to Contribute to This Project 2 | 3 | #### **Did You Find a Bug?** 4 | 5 | * **Ensure the bug was not already reported** by searching on GitHub under [issues][issues]. 6 | * If you're unable to find an open issue addressing the problem, [open a new one][new-issue]. Be sure to include a **title and clear description**, as much relevant information as possible. 7 | 8 | #### **Did You Write a Patch That Fixes a Bug?** 9 | 10 | * Open a new GitHub pull request with the patch. 11 | 1. Fork this project 12 | 1. Create your feature branch: `git checkout -b my-new-feature` 13 | 1. Commit your changes: `git commit -am '$MESSAGE'` (read more in **Naming** section) 14 | 1. Push to the branch: `git push origin my-new-feature` 15 | 1. Submit a pull request 16 | * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. 17 | 18 | #### Naming 19 | * **Commit message**. 20 | * Please use following commit message scheme: `#ISSUE_NUMBER | ISSUE DESCRIPTION`, 21 | * Example: `#1 | Launcher does not initialize when navigating from desktop` 22 | 23 | #### **Do You Intend to Add a New Feature or Change an Existing One?** 24 | 25 | * Suggest your change as a new [issue][new-issue] using the appropriate labels **BEFORE** you start writing code. 26 | 27 | Thanks for contributing! 28 | 29 | 30 | 31 | [//]: # 32 | 33 | [issues]: //github.com/alan-null/sc-ext/issues 34 | [new-issue]: //github.com/alan-null/sc-ext/issues/new 35 | [![Analytics](https://ga-beacon.appspot.com/UA-74179201-4/sc_ext/CONTRIBUTING.md?pixel)](https://github.com/igrigorik/ga-beacon) -------------------------------------------------------------------------------- /app/options/controllers/FieldSearchController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | 6 | export class FieldSearchController extends BaseOptionsController { 7 | constructor($scope: any, formlyVersion: string) { 8 | super($scope, formlyVersion, 'Field Search'); 9 | $scope.vm.title = 'Field Search module'; 10 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki/Field-Search'; 11 | } 12 | 13 | getFields() { 14 | return [ 15 | { 16 | key: 'enabled', 17 | type: 'checkbox', 18 | defaultValue: true, 19 | templateOptions: { 20 | label: 'Enabled' 21 | } 22 | }, 23 | { template: '

Input box behaviour

', noFormControl: true }, 24 | { 25 | key: "inputbox.rememberValue", 26 | type: "radio", 27 | defaultValue: "remmeber", 28 | templateOptions: { 29 | label: "When changing item or refreshing a page:", 30 | options: [ 31 | { 32 | name: "Remember input box value", 33 | value: "remmeber" 34 | }, 35 | { 36 | name: "Clear input box value", 37 | value: "clear" 38 | }, 39 | ] 40 | } 41 | } 42 | ]; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/options/controllers/BaseOptionsController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | 6 | export abstract class BaseOptionsController extends BaseController { 7 | name: string; 8 | model: any; 9 | optionsProvider: OptionsProvider; 10 | constructor(public $scope: any, formlyVersion: string, name: string) { 11 | super(); 12 | this.name = name; 13 | this.optionsProvider = new OptionsProvider(); 14 | $scope.vm = this; 15 | $scope.vm.fields = this.getFields(); 16 | 17 | $scope.vm.env = { 18 | angularVersion: angular.version.full, 19 | formlyVersion: formlyVersion 20 | }; 21 | 22 | this.optionsProvider.getModuleOptions(name, (settings: IModuleOptions) => { 23 | $scope.$apply(function () { 24 | if (settings != null) { 25 | for (var f in settings.model) { 26 | if ($scope.vm.model.hasOwnProperty(f)) { 27 | $scope.vm.model[f] = settings.model[f]; 28 | } 29 | } 30 | } 31 | }); 32 | }); 33 | 34 | $scope.vm.onSubmit = this.saveSettings; 35 | } 36 | 37 | abstract getFields(): any[]; 38 | 39 | buildModuleOptions(): ModuleOptionsBase { 40 | return new ModuleOptionsBase(this.name, this.model); 41 | } 42 | 43 | saveSettings() { 44 | var moduleOptions = this.buildModuleOptions(); 45 | this.optionsProvider.setModuleOptions(moduleOptions); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/sc_ext/ExtensionsManager.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions { 4 | import ISitecoreExtensionsModule = Modules.ISitecoreExtensionsModule; 5 | 6 | export class ExtensionsManager { 7 | modules: ISitecoreExtensionsModule[]; 8 | modulesOptions: Options.IModuleOptions[]; 9 | constructor() { 10 | this.modules = new Array(); 11 | } 12 | 13 | addModule(module: ISitecoreExtensionsModule): void { 14 | this.modules.push(module); 15 | } 16 | 17 | initModules(): void { 18 | this.modules 19 | .filter(m => { return m.canExecute(); }) 20 | .forEach(m => { this.initModule(m); }); 21 | } 22 | 23 | getModule(type: any): ISitecoreExtensionsModule { 24 | for (var index = 0; index < this.modules.length; index++) { 25 | var m = this.modules[index]; 26 | if (m.constructor === type) { 27 | return m; 28 | } 29 | } 30 | return null; 31 | } 32 | 33 | getModuleByName(name: string): ISitecoreExtensionsModule { 34 | for (var index = 0; index < this.modules.length; index++) { 35 | var m = this.modules[index]; 36 | if (m.moduleName === name) { 37 | return m; 38 | } 39 | } 40 | return null; 41 | } 42 | 43 | private initModule(m: ISitecoreExtensionsModule) { 44 | try { 45 | m.initialize(); 46 | } catch (e) { 47 | console.log('Cannot initialize module: ' + m.moduleName); 48 | console.log(e); 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app/options/app.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | var app = angular.module('sc_ext', ['formly', 'formlyBootstrap']) 6 | .controller('OptionsController', OptionsController) 7 | .controller('GeneralOptionsController', GeneralOptionsController) 8 | .controller('AboutController', AboutController) 9 | .controller('LauncherController', LauncherController) 10 | .controller('DatabaseColorController', DatabaseColorController) 11 | .controller('DatabaseNameController', DatabaseNameController) 12 | .controller('SectionSwitchesController', SectionSwitchesController) 13 | .controller('FieldSearchController', FieldSearchController) 14 | .controller('RestoreLastLocationController', RestoreLastLocationController) 15 | .controller('TreelistFieldController', TreelistFieldController) 16 | .controller('SettingsController', SettingsController) 17 | .controller('TreeScopeController', TreeScopeController) 18 | .controller('DatabaseSelectorController', DatabaseSelectorController) 19 | .controller('FieldInspectorController', FieldInspectorController) 20 | .controller('GoToDatasourceController', GoToDatasourceController) 21 | .controller('ToggleRibbonController', ToggleRibbonController) 22 | .controller('TreeAutoExpandController', TreeAutoExpandController) 23 | .controller('ScrollToItemController', ScrollToItemController) 24 | .controller('HeaderQuickInfoExtenderController', HeaderQuickInfoExtenderController) 25 | .directive('navigation', NavigationDirective) 26 | .controller('LinksController', LinksController) 27 | .service('linkStorage', LinkStorage) 28 | .service('databaseColorsStorage', DatabasesColorsStorage); 29 | } 30 | -------------------------------------------------------------------------------- /app/sc_ext/modules/goToDatasource/fields/NameLookupValueList.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.GoToDatasource.Fields { 4 | export class NameLookupValueList extends DatasourceField implements IDatasourceField { 5 | previous: any; 6 | 7 | constructor(selectElement: HTMLSelectElement) { 8 | super(selectElement); 9 | } 10 | 11 | public initialize() { 12 | this.innerElement.classList.add(this.className); 13 | this.innerElement.addEventListener("change", (e) => { 14 | this.refreshButton(); 15 | }); 16 | this.refreshButton(); 17 | } 18 | 19 | protected removeButton() { 20 | this.previous = this.getButton().nextSibling; 21 | super.removeButton(); 22 | } 23 | 24 | protected getButtonClasses(): string[] { 25 | return [this.classButton, "scContentButton", this.innerElement.id]; 26 | } 27 | 28 | protected generateButton(): HTMLSpanElement { 29 | let spanGoToDatasource = HTMLHelpers.createElement("a", { 30 | class: this.getButtonClasses().join(' '), 31 | }) as HTMLSpanElement; 32 | spanGoToDatasource.innerText = "Go to '" + this.getSelectedOption().innerText + "'"; 33 | spanGoToDatasource.dataset['index'] = this.innerElement.selectedIndex.toString(); 34 | return spanGoToDatasource; 35 | } 36 | 37 | protected insertButton(spanGoToDatasource: HTMLSpanElement) { 38 | if (this.previous) { 39 | this.destination.insertBefore(spanGoToDatasource, this.previous); 40 | } else { 41 | this.destination.appendChild(spanGoToDatasource); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/sc_ext/modules/databaseName/DatabaseNameModule.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.DatabaseName { 4 | import DatabaseChangeEventArgs = Events.DatabaseChangeEventArgs; 5 | 6 | export class DatabaseNameModule extends ModuleBase implements ISitecoreExtensionsModule { 7 | constructor(name: string, description: string, rawOptions: Options.ModuleOptionsBase) { 8 | super(name, description, rawOptions); 9 | } 10 | 11 | canExecute(): boolean { 12 | return this.options.enabled && Context.Database() != null && document.querySelector('.sc-globalHeader-loginInfo') != null; 13 | } 14 | 15 | initialize(): void { 16 | var dbName = Context.Database(); 17 | if (dbName != null) { 18 | this.addDbNameToHeader(dbName.toUpperCase()); 19 | } 20 | 21 | new Events.EventHandler("onDatabaseChange", (args: DatabaseChangeEventArgs) => { this.onDatabaseChange(args); }); 22 | } 23 | 24 | onDatabaseChange(args: DatabaseChangeEventArgs) { 25 | this.removeDbNameFromHeader(); 26 | this.addDbNameToHeader(args.databaseName.toUpperCase()); 27 | } 28 | 29 | addDbNameToHeader(dbName: string): void { 30 | var dbnameDiv = HTMLHelpers.createElement('div', { class: 'sc-ext-dbName' }); 31 | dbnameDiv.innerText = dbName; 32 | 33 | let destination = document.querySelector('.sc-globalHeader'); 34 | destination.insertBefore(dbnameDiv, destination.firstChild); 35 | } 36 | 37 | removeDbNameFromHeader(): void { 38 | let element = document.querySelector('.sc-ext-dbName'); 39 | if (element) { 40 | element.remove(); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/providers/DynamicCommand.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Launcher.Providers { 4 | export class DynamicCommand extends BaseCommand implements ICommand { 5 | executeCallback: CommandExecuteCallback; 6 | canExecuteCallback: CommandCanExecuteCallback; 7 | descriptionGetter: CommandDescriptionCallback; 8 | staticDescription: string; 9 | 10 | get description(): string { 11 | if (this.descriptionGetter == null) { 12 | return this.staticDescription; 13 | } else { 14 | return this.descriptionGetter(this); 15 | } 16 | } 17 | constructor(name: string, description: string, url: string) { 18 | super(name, description, url); 19 | this.staticDescription = description; 20 | } 21 | canExecute(): boolean { 22 | if (this.canExecuteCallback) { 23 | return this.canExecuteCallback(); 24 | } 25 | return false; 26 | } 27 | 28 | execute(evt: UserActionEvent): void { 29 | if (this.executeCallback) { 30 | this.executeCallback(this, evt); 31 | } 32 | } 33 | 34 | get ItemId(): string { 35 | return Context.ItemID(); 36 | } 37 | 38 | get Database(): string { 39 | return Context.Database(); 40 | } 41 | 42 | 43 | public get Lang(): string { 44 | return Context.Language(); 45 | } 46 | } 47 | 48 | export interface CommandExecuteCallback { 49 | (cmd: DynamicCommand, evt: UserActionEvent): void; 50 | } 51 | 52 | export interface CommandDescriptionCallback { 53 | (cmd: DynamicCommand): string; 54 | } 55 | 56 | export interface CommandCanExecuteCallback { 57 | (): boolean; 58 | } 59 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/addHere/AddHereModule.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.AddHere { 4 | export class AddHereModule extends ModuleBase implements ISitecoreExtensionsModule { 5 | constructor(name: string, description: string, rawOptions: Options.ModuleOptionsBase) { 6 | super(name, description, rawOptions); 7 | } 8 | 9 | canExecute(): boolean { 10 | return this.options.enabled && Context.Location() == Enums.Location.ExperienceEditor; 11 | } 12 | 13 | initialize(): void { 14 | if (window["Sitecore"] != null && Sitecore.PageModes != null) { 15 | HTMLHelpers.addProxy((Sitecore.PageModes.DesignManager as any), 'insertionStart', () => { this.refreshControls(); }); 16 | } 17 | } 18 | 19 | getAddHereButtons(): Array { 20 | var elements = document.querySelectorAll('.scInsertionHandleLeft.scAddToHere:not(.sc-ext-addHere-button-initialized)') as NodeListOf; 21 | return Array.from(Array.prototype.slice.call(elements) as Array, e => new AddHereButton(e)); 22 | } 23 | 24 | refreshControls(): void { 25 | var addHereButtons = this.getAddHereButtons(); 26 | if (addHereButtons.length === 0) { 27 | return; 28 | } 29 | 30 | addHereButtons.forEach(button => { 31 | let buttons = addHereButtons.filter(function (b) { return b.placeholderName == button.placeholderName; }); 32 | let txt = button.getText() + " | " + button.placeholderName; 33 | if (buttons.length > 1) { 34 | let index = buttons.indexOf(button) + 1; 35 | txt = txt + "(" + index + ")"; 36 | } 37 | button.setText(txt); 38 | }); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/sc_ext/page objects/ContentTree.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.PageObjects { 4 | 5 | export class ContentTree { 6 | private element: HTMLElement; 7 | 8 | constructor() { 9 | this.element = document.getElementById("ContentTreeInnerPanel"); 10 | } 11 | 12 | public getActiveTreeNode(): HTMLElement { 13 | return document.querySelector(".scContentTreeNodeActive") as HTMLElement; 14 | } 15 | 16 | public loadItem(id: string): void { 17 | scForm.postRequest("", "", "", "LoadItem(\"" + id + "\")"); 18 | 19 | let currentlySelectedElementId = this.getActiveTreeNode().id; 20 | HTMLHelpers.postponeAction(_ => { 21 | let active = this.getActiveTreeNode().id; 22 | return active.length > 0 && active !== currentlySelectedElementId; 23 | }, _ => { 24 | this.scrollToActiveNode(); 25 | this.getActiveTreeNode().click(); 26 | }, 100, 10); 27 | } 28 | 29 | public scrollToActiveNode(): void { 30 | let element = this.getActiveTreeNode(); 31 | HTMLHelpers.scrollToElement(element, this.element); 32 | } 33 | 34 | public onActiveTreeNodeChanged(callback: Function) { 35 | let activeNode = this.getActiveTreeNode(); 36 | if (activeNode == null) { 37 | return; 38 | } 39 | let previousId = activeNode.id; 40 | HTMLHelpers.postponeAction(_ => { 41 | let activeTreeNode = this.getActiveTreeNode(); 42 | if (activeTreeNode && activeTreeNode.id) { 43 | let currentId = activeTreeNode.id; 44 | return currentId.length > 0 && currentId !== previousId; 45 | } 46 | return false; 47 | }, _ => { 48 | callback(); 49 | }, 100, 20); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/treeAutoExpand/TreeAutoExpandModule.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.TreeAutoExpand { 4 | export class TreeAutoExpandModule extends ModuleBase implements ISitecoreExtensionsModule { 5 | 6 | constructor(name: string, description: string, rawOptions: Options.ModuleOptionsBase) { 7 | super(name, description, rawOptions); 8 | } 9 | 10 | canExecute(): boolean { 11 | return this.options.enabled && Context.Location() == Enums.Location.ContentEditor; 12 | } 13 | 14 | initialize(): void { 15 | this.addTreeNodeHandlers('scContentTree'); 16 | } 17 | 18 | addTreeNodeHandlers(className: string): void { 19 | var nodes = document.getElementsByClassName(className); 20 | for (var i = 0; i < nodes.length; i++) { 21 | nodes[i].addEventListener('click', (evt: MouseEvent) => { 22 | setTimeout(() => { 23 | this.expandSubTree(evt); 24 | }, 10); 25 | }); 26 | } 27 | } 28 | 29 | expandSubTree(evt: MouseEvent): void { 30 | let glyphId = evt.getSrcElement().id; 31 | let icon = new TreeNodeGlyph(glyphId); 32 | 33 | if (icon.isExpandable()) { 34 | HTMLHelpers.postponeAction(_ => { return this.predicate(glyphId); }, _ => { this.action(glyphId); }, 100, 10); 35 | } 36 | } 37 | 38 | private predicate(glyphId: string): boolean { 39 | return new TreeNodeGlyph(glyphId).isExpanded(); 40 | } 41 | 42 | private action(glyphId: string): void { 43 | let icon = new TreeNodeGlyph(glyphId); 44 | let childNodeds = icon.getChildren(); 45 | if (childNodeds.length == 1) { 46 | (childNodeds[0].querySelector(".scContentTreeNodeGlyph") as HTMLImageElement).click(); 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /app/sc_ext/status/StatusInfoWrapper.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions { 4 | export class StatusInfoWrapper { 5 | private static instance: StatusInfoWrapper; 6 | private moduleStatusProviderInstance: Status.ModulesStatusProvider | null = null; 7 | private commandStatusProviderInstance: Status.CommandsStatusProvider | null = null; 8 | 9 | private constructor() { } 10 | 11 | public static getInstance(): StatusInfoWrapper { 12 | if (!StatusInfoWrapper.instance) { 13 | StatusInfoWrapper.instance = new StatusInfoWrapper(); 14 | } 15 | return StatusInfoWrapper.instance; 16 | } 17 | 18 | public clear(): void { 19 | this.status = null; 20 | } 21 | 22 | public update(): void { 23 | this.status = { 24 | modules_count: this.moduleStatusProvider.getStatus(), 25 | commands_count: this.commandStatusProvider.getStatus() 26 | }; 27 | } 28 | 29 | public get moduleStatusProvider(): Status.ModulesStatusProvider { 30 | if (!this.moduleStatusProviderInstance) { 31 | this.moduleStatusProviderInstance = new Status.ModulesStatusProvider(); 32 | } 33 | return this.moduleStatusProviderInstance; 34 | } 35 | 36 | public get commandStatusProvider(): Status.CommandsStatusProvider { 37 | if (!this.commandStatusProviderInstance) { 38 | this.commandStatusProviderInstance = new Status.CommandsStatusProvider(); 39 | } 40 | return this.commandStatusProviderInstance; 41 | } 42 | 43 | get status(): any { // Replace `any` with the actual type of statusInfo 44 | return (window.top as any).SitecoreExtensions.statusInfo; 45 | } 46 | 47 | set status(value: any) { 48 | (window.top as any).SitecoreExtensions.statusInfo = value; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/models/LauncherOptions.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Launcher.Models { 4 | export class LauncherOptions extends Options.ModuleOptions { 5 | keyBindings: { 6 | show: number, 7 | hide: number, 8 | selectNextResult: number, 9 | selectPrevResult: number, 10 | executeCommand: number, 11 | selectFirstResult: number, 12 | selectLastResult: number, 13 | } = { 14 | show: 32, 15 | hide: 27, 16 | selectNextResult: 40, 17 | selectPrevResult: 38, 18 | executeCommand: 13, 19 | selectFirstResult: 33, 20 | selectLastResult: 34 21 | }; 22 | 23 | searchResultsCount: number = 8; 24 | storageType: StorageType = StorageType.LocalStorage; 25 | autocomplete: boolean = false; 26 | constructor(wrapper: any) { 27 | super(); 28 | if (wrapper != null) { 29 | this.enabled = wrapper.model.enabled; 30 | this.autocomplete = wrapper.model.autocomplete; 31 | this.keyBindings.show = wrapper.model.keyBindings.show; 32 | this.keyBindings.hide = wrapper.model.keyBindings.hide; 33 | this.keyBindings.selectNextResult = wrapper.model.keyBindings.selectNextResult; 34 | this.keyBindings.selectPrevResult = wrapper.model.keyBindings.selectPrevResult; 35 | this.keyBindings.executeCommand = wrapper.model.keyBindings.executeCommand; 36 | this.keyBindings.selectFirstResult = wrapper.model.keyBindings.selectFirstResult; 37 | this.keyBindings.selectLastResult = wrapper.model.keyBindings.selectLastResult; 38 | this.searchResultsCount = wrapper.model.searchResultsCount; 39 | this.storageType = StorageType[wrapper.model.storageType as string]; 40 | }; 41 | } 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /app/options/services/DatabasesColorsStorage.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | 6 | export class DatabasesColorsStorage implements IDatabasesColorsStorage { 7 | STORAGE_ID = 'Database Colour'; 8 | optionsProvider: OptionsProvider; 9 | 10 | constructor() { 11 | this.optionsProvider = new OptionsProvider(); 12 | } 13 | 14 | get(coldStorageCb?: any): DatabaseColorMapping[] { 15 | this.optionsProvider.getModuleOptions(this.STORAGE_ID, (options: IModuleOptions) => { 16 | if (options && options.model) { 17 | if (coldStorageCb) { 18 | coldStorageCb(options.model); 19 | } 20 | } 21 | }); 22 | 23 | if (localStorage.getItem(this.STORAGE_ID) == null) { 24 | let defaultColorsMapping = this.getDefaultStorageValue(); 25 | localStorage.setItem(this.STORAGE_ID, JSON.stringify(defaultColorsMapping)); 26 | var moduleOptions = new ModuleOptionsBase(this.STORAGE_ID, { 27 | enabled: true, 28 | colors: defaultColorsMapping 29 | }); 30 | this.optionsProvider.setModuleOptions(moduleOptions); 31 | return defaultColorsMapping; 32 | } else { 33 | return JSON.parse(localStorage.getItem(this.STORAGE_ID) || '[]'); 34 | } 35 | 36 | } 37 | 38 | getDefaultStorageValue(): DatabaseColorMapping[] { 39 | let links = []; 40 | links.push(new DatabaseColorMapping("WEB", "DC291E", 0)); 41 | return links; 42 | } 43 | 44 | put(links: DatabaseColorMapping[]) { 45 | localStorage.setItem(this.STORAGE_ID, JSON.stringify(links)); 46 | this.get((model) => { 47 | model.colors = links; 48 | var moduleOptions = new ModuleOptionsBase(this.STORAGE_ID, model); 49 | this.optionsProvider.setModuleOptions(moduleOptions); 50 | }); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/databaseColor/DatabaseColorModule.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.DatabaseColor { 4 | import DatabaseChangeEventArgs = Events.DatabaseChangeEventArgs; 5 | 6 | export class DatabaseColorModule extends ModuleBase implements ISitecoreExtensionsModule { 7 | coloursMapping: Types.IDictionary; 8 | options: DatabaseColorOptions; 9 | 10 | constructor(name: string, description: string, rawOptions: Options.ModuleOptionsBase) { 11 | super(name, description); 12 | this.options = new DatabaseColorOptions(); 13 | this.mapOptions(rawOptions); 14 | this.coloursMapping = new Types.Dictionary([]); 15 | 16 | this.options.colors.forEach((dc: Options.DatabaseColorMapping) => { 17 | let name = dc.name.toUpperCase(); 18 | let color = dc.color; 19 | if (!color.startsWith("#")) { 20 | color = '#' + color; 21 | } 22 | this.coloursMapping.add(name, color); 23 | }); 24 | } 25 | 26 | canExecute(): boolean { 27 | return this.options.enabled && Context.Database() != null && document.querySelector('.sc-globalHeader-content') != null; 28 | } 29 | 30 | initialize(): void { 31 | var dbName = Context.Database(); 32 | if (dbName != null) { 33 | this.changeheaderColor(dbName.toUpperCase()); 34 | } 35 | 36 | new Events.EventHandler("onDatabaseChange", (args: DatabaseChangeEventArgs) => { this.onDatabaseChange(args); }); 37 | } 38 | 39 | onDatabaseChange(args: DatabaseChangeEventArgs) { 40 | this.changeheaderColor(args.databaseName.toUpperCase()); 41 | } 42 | 43 | changeheaderColor(dbName: string): void { 44 | let header = document.getElementsByClassName('sc-globalHeader-content')[0]; 45 | if (this.coloursMapping.containsKey(dbName)) { 46 | header.setAttribute("style", "background-color: " + this.coloursMapping[dbName] + ";"); 47 | } else { 48 | header.removeAttribute("style"); 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/toggleRibbon/ToggleRibbonModule.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.ToggleRibbon { 4 | 5 | 6 | export class ToggleRibbonModule extends ModuleBase implements ISitecoreExtensionsModule { 7 | ribbon: Ribbon; 8 | toggleButton: ToggleButton; 9 | 10 | constructor(name: string, description: string, rawOptions: Options.ModuleOptionsBase) { 11 | super(name, description, rawOptions); 12 | } 13 | 14 | canExecute(): boolean { 15 | return this.options.enabled 16 | && Context.Location() == Enums.Location.ExperienceEditor 17 | && document.querySelector('#scWebEditRibbon') != null; 18 | } 19 | 20 | initialize(): void { 21 | this.ribbon = new Ribbon(); 22 | this.toggleButton = new ToggleButton(() => { 23 | this.toggle(); 24 | }); 25 | this.toggleButton.hide(); 26 | 27 | SitecoreExtensions.HTMLHelpers.postponeAction(() => { 28 | return this.ribbon.isInitialized(); 29 | }, () => { 30 | this.refresh(); 31 | this.toggleButton.show(); 32 | }, 200, 30); 33 | } 34 | 35 | private isVisible() { 36 | var scRibbon = top.window.document.cookie.replace(/(?:(?:^|.*;\s*)scRibbon\s*\=\s*([^;]*).*$)|^.*$/, "$" + "1"); 37 | return scRibbon === '1' || scRibbon.length == 0; 38 | } 39 | 40 | private hide() { 41 | this.ribbon.hide(); 42 | this.saveRibbonState(0); 43 | this.toggleButton.updatePosition(this.isVisible()); 44 | } 45 | 46 | private show() { 47 | this.ribbon.show(); 48 | this.saveRibbonState(1); 49 | this.toggleButton.updatePosition(this.isVisible()); 50 | } 51 | 52 | private toggle() { 53 | this.isVisible() ? this.hide() : this.show(); 54 | } 55 | 56 | private refresh() { 57 | this.isVisible() ? this.show() : this.hide(); 58 | } 59 | 60 | private saveRibbonState(value: number) { 61 | top.window.document.cookie = 'scRibbon=' + value; 62 | } 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/options/_all.ts: -------------------------------------------------------------------------------- 1 | // Libraries 2 | /// 3 | /// 4 | /// 5 | 6 | // Providers 7 | /// 8 | 9 | // Controllers 10 | /// 11 | /// 12 | /// 13 | /// 14 | /// 15 | /// 16 | /// 17 | /// 18 | /// 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | /// 25 | /// 26 | /// 27 | /// 28 | /// 29 | /// 30 | /// 31 | 32 | // Directives 33 | /// 34 | 35 | // Interfaces 36 | /// 37 | /// 38 | /// 39 | 40 | // Models 41 | /// 42 | /// 43 | 44 | // Models 45 | /// 46 | /// 47 | /// 48 | 49 | 50 | -------------------------------------------------------------------------------- /app/chrome/popup/fonts/fontawesome-webfont.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2016 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /app/sc_ext/modules/treeScope/Popup.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.TreeScope { 4 | export class Popup { 5 | popupElement: HTMLDivElement; 6 | constructor(innerElement: HTMLDivElement) { 7 | this.popupElement = innerElement; 8 | } 9 | 10 | appendPopupButton(button: PopupButton, index: number = 0) { 11 | var tbody = this.popupElement.querySelector("table>tbody"); 12 | let newTr = (tbody.parentNode as HTMLTableElement).insertRow(index); 13 | newTr.parentNode.replaceChild(button.renderButton(), newTr); 14 | this.relocatePopup(1); 15 | } 16 | 17 | getIndexOfElement(elementId: string): number { 18 | let refreshTreeButton = this.popupElement.querySelector("table>tbody #" + elementId) as HTMLTableRowElement; 19 | return refreshTreeButton.rowIndex; 20 | } 21 | 22 | hide(): void { 23 | this.popupElement.remove(); 24 | } 25 | 26 | private relocatePopup(count: number = 1): void { 27 | let numberOfExistingButtons = this.getNumberOfExistingButtons(); 28 | let buttonHeight = this.popupElement.clientHeight / numberOfExistingButtons; 29 | 30 | let value = buttonHeight * count; 31 | this.popupElement.style.maxHeight = (this.parseStyleInt(this.popupElement.style.maxHeight) + value) + "px"; 32 | 33 | let bottomOffset = this.popupElement.offsetParent.clientHeight - (this.popupElement.offsetHeight + this.popupElement.offsetTop); 34 | if (bottomOffset < 0) { 35 | this.popupElement.style.top = (this.parseStyleInt(this.popupElement.style.top) + bottomOffset) + "px"; 36 | } 37 | } 38 | 39 | private getNumberOfExistingButtons(): number { 40 | var tbody = this.popupElement.querySelector("table>tbody"); 41 | let numberOfExistingButtons = 0; 42 | [].forEach.call(tbody.childNodes, (e) => { 43 | if (e.id != null && e.id.length > 0) { 44 | numberOfExistingButtons++; 45 | } 46 | }); 47 | return numberOfExistingButtons; 48 | } 49 | 50 | private parseStyleInt(intWannaBe: string) { 51 | return parseInt(intWannaBe.replace("px", "")); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /app/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "__MSG_appName__", 3 | "short_name": "__MSG_appShortName__", 4 | "version": "4.1.0", 5 | "manifest_version": 3, 6 | "description": "__MSG_appDescription__", 7 | "icons": { 8 | "16": "chrome/images/icon-16.png", 9 | "48": "chrome/images/icon-48.png", 10 | "128": "chrome/images/icon-128.png" 11 | }, 12 | "default_locale": "en", 13 | "background": { 14 | "service_worker": "chrome/background.js" 15 | }, 16 | "permissions": [ 17 | "activeTab", 18 | "storage" 19 | ], 20 | "host_permissions": [ 21 | "http://*/*", 22 | "https://*/*" 23 | ], 24 | "content_scripts": [ 25 | { 26 | "matches": [ 27 | "http://*/*", 28 | "https://*/*" 29 | ], 30 | "js": [ 31 | "chrome/contentscript.js", 32 | "common/optionsProvider.js" 33 | ], 34 | "css": [ 35 | "sc_ext/styles/launcher.css", 36 | "sc_ext/styles/databaseName.css", 37 | "sc_ext/styles/headerQuickInfoExtender.css", 38 | "sc_ext/styles/fieldSearch.css", 39 | "sc_ext/styles/treelistField.css", 40 | "sc_ext/styles/fieldInspector.css", 41 | "sc_ext/styles/toggleRibbon.css", 42 | "sc_ext/styles/treeScope.css", 43 | "sc_ext/libraries/iziToast.css" 44 | ], 45 | "run_at": "document_end", 46 | "all_frames": true 47 | } 48 | ], 49 | "action": { 50 | "default_icon": { 51 | "19": "chrome/images/icon-disabled-128.png", 52 | "38": "chrome/images/icon-disabled-128.png" 53 | }, 54 | "default_popup": "chrome/popup/popup.html" 55 | }, 56 | "options_ui": { 57 | "page": "options/options.html" 58 | }, 59 | "web_accessible_resources": [ 60 | { 61 | "resources": [ 62 | "common/optionsProvider.js", 63 | "sc_ext/Application.js", 64 | "sc_ext/libraries/iziToast.js" 65 | ], 66 | "matches": [ 67 | "https://*/*" 68 | ], 69 | "extension_ids": [ 70 | "aoclhcccfdkjddgpaaajldgljhllhgmd" 71 | ] 72 | } 73 | ] 74 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/treeScope/PopupButton.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.TreeScope { 4 | export class PopupButton { 5 | activeNodeID: string; 6 | buttonClass: string; 7 | 8 | iconImage: string; 9 | captionText: string; 10 | hotkeyImage: string; 11 | 12 | clickCallback: PopupButtonClickCallback; 13 | 14 | constructor(activeNodeID: string, clickCallback: PopupButtonClickCallback) { 15 | this.activeNodeID = activeNodeID; 16 | 17 | this.iconImage = "/sitecore/images/blank.gif"; 18 | this.captionText = ""; 19 | this.iconImage = "/sitecore/images/blank.gif"; 20 | 21 | this.clickCallback = clickCallback; 22 | } 23 | 24 | renderButton(): HTMLTableRowElement { 25 | let defaultEvent = "javascript:return scForm.rollOver(this,event)"; 26 | let tr = HTMLHelpers.createElement("tr", { 27 | onmouseover: defaultEvent, 28 | onfocus: defaultEvent, 29 | onmouseout: defaultEvent, 30 | onblur: defaultEvent, 31 | class: this.buttonClass 32 | }) as HTMLTableRowElement; 33 | 34 | tr.onclick = () => { 35 | this.clickCallback(this.activeNodeID); 36 | }; 37 | 38 | let tdIcon = HTMLHelpers.createElement("td", { class: "scMenuItemIcon" }) as HTMLTableDataCellElement; 39 | let tdIconImg = HTMLHelpers.createElement("img", { src: this.iconImage, width: "16", height: "16", align: "middle", class: "", alt: "", border: "0" }) as HTMLImageElement; 40 | tdIcon.appendChild(tdIconImg); 41 | 42 | let tdCaption = HTMLHelpers.createElement("td", { class: "scMenuItemCaption" }) as HTMLTableDataCellElement; 43 | tdCaption.textContent = this.captionText; 44 | 45 | let tdHotkey = HTMLHelpers.createElement("td", { class: "scMenuItemHotkey" }) as HTMLTableDataCellElement; 46 | let tdHotkeyImg = HTMLHelpers.createElement("img", { src: this.hotkeyImage, width: "1", height: "1", class: "scSpacer", alt: "", border: "0" }) as HTMLImageElement; 47 | tdHotkey.appendChild(tdHotkeyImg); 48 | 49 | tr.appendChild(tdIcon); 50 | tr.appendChild(tdCaption); 51 | tr.appendChild(tdHotkey); 52 | 53 | return tr; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /app/options/controllers/LinksController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | 6 | export class LinksController { 7 | public static $inject = ['$scope', 'linkStorage']; 8 | 9 | private links: LinkItem[]; 10 | 11 | constructor(private $scope: ILinkScope, private linksStorage: ILinksStorage) { 12 | this.links = $scope.links = linksStorage.get((links) => { 13 | this.links = $scope.links = links; 14 | }); 15 | 16 | $scope.name = ''; 17 | $scope.url = ''; 18 | $scope.mode = 'newtab'; 19 | $scope.editedLink = null; 20 | $scope.order = 0; 21 | 22 | $scope.vm = this; 23 | 24 | $scope.$watch('links', () => this.onLinks(), true); 25 | 26 | } 27 | 28 | onLinks() { 29 | this.linksStorage.put(this.links); 30 | } 31 | 32 | addLink() { 33 | var name: string = this.$scope.name.trim(); 34 | if (!name.length) { 35 | return; 36 | } 37 | 38 | var url: string = this.$scope.url.trim(); 39 | if (!url.length) { 40 | return; 41 | } 42 | 43 | var mode: string = this.$scope.mode.trim(); 44 | if (!mode.length) { 45 | return; 46 | } 47 | 48 | this.links.push(new LinkItem(name, url, mode, 0)); 49 | 50 | this.$scope.name = ''; 51 | this.$scope.url = ''; 52 | this.$scope.mode = 'currenttab'; 53 | this.$scope.order = 0; 54 | } 55 | 56 | editLink(linkItem: LinkItem) { 57 | this.$scope.editedLink = linkItem; 58 | this.$scope.originalLink = angular.extend({}, linkItem); 59 | } 60 | 61 | doneEditing(linkItem: LinkItem) { 62 | this.$scope.editedLink = null; 63 | this.$scope.originalLink = null; 64 | if (this.$scope.reverted) { 65 | this.$scope.reverted = null; 66 | return; 67 | } 68 | linkItem.name = linkItem.name.trim(); 69 | if (!linkItem.name) { 70 | this.removeLink(linkItem); 71 | } 72 | } 73 | 74 | removeLink(linkItem: LinkItem) { 75 | this.links.splice(this.links.indexOf(linkItem), 1); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/sc_ext/modules/lastLocation/RestoreLastLocation.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.LastLocation { 4 | export class RestoreLastLocation extends ModuleBase implements ISitecoreExtensionsModule { 5 | 6 | constructor(name: string, description: string, rawOptions: Options.ModuleOptionsBase) { 7 | super(name, description, rawOptions); 8 | } 9 | 10 | canExecute(): boolean { 11 | return this.options.enabled && Context.Location() == Enums.Location.ContentEditor; 12 | } 13 | 14 | initialize(): void { 15 | this.addTreeNodeHandlers('scContentTree'); 16 | HTMLHelpers.addProxy(scSitecore, 'postEvent', () => { this.saveCurrentLocationAfterChange(); }); 17 | HTMLHelpers.addProxy(scForm, 'invoke', () => { this.saveCurrentLocationAfterChange(); }); 18 | } 19 | 20 | private getElement(args: any): Element { 21 | if (args["element"] != null) { 22 | return args.element(); 23 | } 24 | } 25 | 26 | private updateLastLocation(parent: Element): void { 27 | if ((parent as HTMLDivElement).classList.contains("scContentTreeNode")) { 28 | parent = parent.querySelector("a"); 29 | } else { 30 | parent = HTMLHelpers.getElement(parent, (n) => { 31 | return n.tagName.toLowerCase() === "a"; 32 | }); 33 | } 34 | 35 | if (parent) { 36 | let id = parent.id; 37 | id = id.substring(id.lastIndexOf("_") + 1); 38 | LastLocationStore.saveLastItemId(id); 39 | } 40 | } 41 | 42 | private addTreeNodeHandlers(className: string): void { 43 | var nodes = document.getElementsByClassName(className); 44 | for (var i = 0; i < nodes.length; i++) { 45 | nodes[i].addEventListener('click', (evt) => { 46 | let element = this.getElement(evt); 47 | this.updateLastLocation(element); 48 | }); 49 | } 50 | } 51 | 52 | private saveCurrentLocationAfterChange() { 53 | let contentTree = new PageObjects.ContentTree(); 54 | contentTree.onActiveTreeNodeChanged(_ => { 55 | this.updateLastLocation(document.querySelector(".scContentTreeNodeActive")); 56 | }); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/sc_ext/modules/shortcutsRunner/ShortcutRunner.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.ShortcutsRunner { 4 | import HttpRequest = Http.HttpRequest; 5 | import Method = Http.Method; 6 | 7 | export class ShortcutRunner { 8 | private tokenService: TokenService; 9 | private cacheKey: string = 'sc_ext::request_token'; 10 | private baseUrl: string = window.top.location.origin + "/sitecore/shell/default.aspx"; 11 | 12 | constructor() { 13 | this.tokenService = new TokenService(); 14 | } 15 | 16 | public runShortcutCommand(shortcutId: string, evt?: KeyboardEvent): void { 17 | this.getShortcutUrl((e) => { 18 | if (e.currentTarget.status == 500) { 19 | this.handleErrorAndRetry(shortcutId); 20 | } else { 21 | var data = JSON.parse(e.currentTarget.responseText); 22 | this.invokeCommand(data, evt); 23 | } 24 | }, shortcutId); 25 | } 26 | 27 | private invokeCommand(data, evt?: KeyboardEvent): void { 28 | var lastCommandIndex = data.commands.length - 1; 29 | var iFrame = data.commands[lastCommandIndex].value; 30 | var urls = iFrame.match(/\/sitecore\/shell(.)*png/); 31 | if (urls) { 32 | var url = window.top.location.origin + urls[0]; 33 | var command = new Launcher.Providers.NavigationCommand(null, null, url); 34 | command.execute(evt); 35 | } 36 | } 37 | 38 | private handleErrorAndRetry(shortcutId: string): void { 39 | this.tokenService.invalidateToken().then((token) => { 40 | this.runShortcutCommand(shortcutId); 41 | }); 42 | } 43 | 44 | private getShortcutUrl(callback: Function, shortcutId: string): void { 45 | var req = new HttpRequest(this.baseUrl, Method.POST, callback); 46 | let token = this.tokenService.getToken().then((token: ShortcutsRunner.Token) => { 47 | if (token) { 48 | var postData = "&__PARAMETERS=" + "RunShortcut%28%26quot%3B%7B" + shortcutId + "%7D%26quot%3B%29" 49 | + "&__ISEVENT=" + "1" 50 | + "&__CSRFTOKEN=" + token.__CSRFTOKEN 51 | + "&__VIEWSTATE=" + token.__VIEWSTATE; 52 | } 53 | req.execute(postData); 54 | }); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/treelistField/TreelistFieldModule.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.TreelistField { 4 | export class TreelistFieldModule extends ModuleBase implements ISitecoreExtensionsModule { 5 | className: string = "sc-ext-treelist"; 6 | 7 | constructor(name: string, description: string, rawOptions: Options.ModuleOptionsBase) { 8 | super(name, description, rawOptions); 9 | } 10 | 11 | canExecute(): boolean { 12 | return this.options.enabled && Context.Location() == Enums.Location.ContentEditor; 13 | } 14 | 15 | initialize(): void { 16 | window.addEventListener('load', () => this.addPathToTreelistField()); 17 | this.addTreeNodeHandlers('scContentTree'); 18 | HTMLHelpers.addProxy(scSitecore, 'postEvent', () => this.addPathToTreelistField()); 19 | HTMLHelpers.addProxy(scForm, 'invoke', () => this.addPathToTreelistField()); 20 | HTMLHelpers.addProxy(scForm, 'resume', () => this.addPathToTreelistField()); 21 | } 22 | 23 | addPathToTreelistField(): void { 24 | let treeListFields = document.querySelectorAll(".scContentControl.scTreelistEx:not(." + this.className + ")"); 25 | for (var i = 0; i < treeListFields.length; i++) { 26 | var field = treeListFields[i]; 27 | field.classList.add(this.className); 28 | if (field.childNodes.length > 0) { 29 | for (var j = 0; j < field.childNodes.length; j++) { 30 | var itemRow = field.childNodes[j] as HTMLDivElement; 31 | let pathSpan = HTMLHelpers.createElement("span", { class: "sc-ext-treelist-path" }) as HTMLSpanElement; 32 | pathSpan.innerText = itemRow.title; 33 | pathSpan.onclick = () => { HTMLHelpers.selectNodeContent(pathSpan); }; 34 | 35 | itemRow.appendChild(pathSpan); 36 | } 37 | } 38 | } 39 | } 40 | 41 | addTreeNodeHandlers(className: string): void { 42 | var nodes = document.getElementsByClassName(className); 43 | for (var i = 0; i < nodes.length; i++) { 44 | nodes[i].addEventListener('click', (evt) => { 45 | setTimeout(() => { 46 | this.addPathToTreelistField(); 47 | }, 10); 48 | }); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/options/controllers/GeneralOptionsController.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | module SitecoreExtensions.Options { 4 | 'use strict'; 5 | 6 | export class GeneralOptionsController extends BaseOptionsController { 7 | constructor($scope: any, formlyVersion: string) { 8 | super($scope, formlyVersion, 'General'); 9 | $scope.vm.title = 'Sitecore Extensions general options'; 10 | $scope.vm.link = 'https://github.com/alan-null/sc_ext/wiki'; 11 | } 12 | 13 | getFields() { 14 | return [ 15 | { template: '

General

', noFormControl: true }, 16 | { 17 | key: 'enabled', 18 | type: 'checkbox', 19 | defaultValue: true, 20 | templateOptions: { 21 | label: 'Enabled' 22 | }, 23 | }, 24 | { template: '

Extension status icon

', noFormControl: true }, 25 | { 26 | key: 'badge.enabled', 27 | type: 'checkbox', 28 | defaultValue: true, 29 | templateOptions: { 30 | label: 'Enabled' 31 | }, 32 | }, 33 | { 34 | key: "badge.statusType", 35 | type: "radio", 36 | defaultValue: "ModulesCount", 37 | templateOptions: { 38 | label: "Status type:", 39 | options: [ 40 | { 41 | name: "Modules Count", 42 | value: "ModulesCount" 43 | }, 44 | { 45 | name: "Available Commands Count", 46 | value: "AvailableCommandsCount" 47 | }, 48 | ] 49 | }, 50 | hideExpression: '!model.badge.enabled' 51 | }, 52 | { template: '

Extension status information

', noFormControl: true }, 53 | { 54 | key: 'statusInfo.enabled', 55 | type: 'checkbox', 56 | defaultValue: false, 57 | templateOptions: { 58 | label: 'Enabled' 59 | }, 60 | }, 61 | ]; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/sc_ext/options/OptionsRepository.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import Communication = SitecoreExtensions.Common.Communication; 4 | 5 | namespace SitecoreExtensions.Options { 6 | export class OptionsRepository { 7 | constructor(getOptionsCallback?: any) { 8 | } 9 | 10 | async getOptions(): Promise { 11 | return new Promise(returnValue => { 12 | window.addEventListener('message', function (event) { 13 | let validator = new Communication.DataParser(); 14 | let instance = validator.tryParse(event.data); 15 | if (instance instanceof Communication.GetOptionsResponseMessage) { 16 | if (instance.optionsWrapper && instance.optionsWrapper.options) { 17 | returnValue(instance.optionsWrapper); 18 | } else { 19 | returnValue(new OptionsWrapper([])); 20 | } 21 | } 22 | }); 23 | let message = new Communication.GetOptionsRequestMessage(); 24 | window.postMessage(message, '*'); 25 | }); 26 | } 27 | 28 | async getModuleOptions(moduleName: string): Promise { 29 | return new Promise(returnValue => { 30 | window.addEventListener('message', function (event) { 31 | let validator = new Communication.DataParser(); 32 | let instance = validator.tryParse(event.data); 33 | if (instance instanceof Communication.GetModuleOptionsResponseMessage) { 34 | returnValue(instance.moduleOptions); 35 | } 36 | }); 37 | let message = new Communication.GetModuleOptionsRequestMessage(moduleName); 38 | window.postMessage(message, '*'); 39 | }); 40 | } 41 | 42 | 43 | setOptions(modulesOptions: IModuleOptions[]): void { 44 | let message = new Communication.SetOptionsRequestMessage(modulesOptions); 45 | window.postMessage(message, '*'); 46 | } 47 | 48 | setModuleOptions(moduleOptions: IModuleOptions): void { 49 | let message = new Communication.SetModuleOptionsRequestMessage(moduleOptions); 50 | window.postMessage(message, '*'); 51 | } 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name": true, 4 | "no-conditional-assignment": true, 5 | "comment-format": [ 6 | true, 7 | "check-space" 8 | ], 9 | "semicolon": [ 10 | true, 11 | "always" 12 | ], 13 | "member-ordering": [ 14 | true, 15 | { 16 | "order": [ 17 | "public-static-field", 18 | "protected-static-field", 19 | "private-static-field", 20 | "public-instance-field", 21 | "protected-instance-field", 22 | "private-instance-field", 23 | "constructor", 24 | "public-static-method", 25 | "protected-static-method", 26 | "private-static-method", 27 | "public-instance-method", 28 | "protected-instance-method", 29 | "private-instance-method" 30 | ] 31 | } 32 | ], 33 | "no-eval": true, 34 | "indent": [ 35 | true, 36 | "spaces" 37 | ], 38 | "no-trailing-whitespace": true, 39 | "one-line": [ 40 | true, 41 | "check-catch", 42 | "check-finally", 43 | "check-else", 44 | "check-open-brace", 45 | "check-whitespace" 46 | ], 47 | "typedef-whitespace": [ 48 | true, 49 | { 50 | "call-signature": "nospace", 51 | "index-signature": "nospace", 52 | "parameter": "nospace", 53 | "property-declaration": "nospace", 54 | "variable-declaration": "nospace" 55 | }, 56 | { 57 | "call-signature": "onespace", 58 | "index-signature": "onespace", 59 | "parameter": "onespace", 60 | "property-declaration": "onespace", 61 | "variable-declaration": "onespace" 62 | } 63 | ], 64 | "variable-name": [ 65 | true, 66 | "ban-keywords", 67 | "check-format" 68 | ], 69 | "whitespace": [ 70 | true, 71 | "check-branch", 72 | "check-decl", 73 | "check-operator", 74 | "check-module", 75 | "check-separator", 76 | "check-type" 77 | ], 78 | "no-duplicate-variable": true 79 | } 80 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/databaseSelector/DatabaseSelectorCommandsProvider.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.DatabaseSelector { 4 | import ICommand = Launcher.ICommand; 5 | 6 | export class DatabaseNamesStore { 7 | private static localStorageKey: string = "sc_ext::db_names"; 8 | 9 | public static saveDatabases(dbs: Array): void { 10 | localStorage.setItem(this.localStorageKey, dbs.join(',')); 11 | } 12 | 13 | public static getDatabases(): Array { 14 | let raw = localStorage.getItem(this.localStorageKey); 15 | if (raw) { 16 | return raw.split(','); 17 | } 18 | return new Array(); 19 | } 20 | } 21 | 22 | export class DatabaseSelectorCommandsProvider implements Launcher.Providers.ICommandsProvider { 23 | private commands: ICommand[]; 24 | 25 | constructor() { 26 | this.commands = Array(); 27 | this.createCommands(); 28 | } 29 | 30 | public getCommands(): ICommand[] { 31 | return this.commands; 32 | 33 | } 34 | 35 | private createCommands() { 36 | let dbs = DatabaseNamesStore.getDatabases(); 37 | if (dbs) { 38 | for (let index = 0; index < dbs.length; index++) { 39 | var databaseName = dbs[index]; 40 | var cmd: ICommand = { 41 | id: 0, 42 | name: 'Change database: ' + databaseName, 43 | description: 'Change current database to ' + databaseName, 44 | execute: (e: KeyboardEvent) => { 45 | let url = window.top.location.origin + "/sitecore/shell/default.aspx?sc_content=" + dbs[index]; 46 | new Http.HttpRequest(url, Http.Method.GET, null).execute(); 47 | if (e.ctrlKey) { 48 | let location = window.top.location; 49 | new Launcher.Providers.NavigationCommand(null, null, location.href).execute(e); 50 | } 51 | 52 | let args = new Events.DatabaseChangeEventArgs(dbs[index]); 53 | Events.EventsDispatcher.Dispatch(args); 54 | }, 55 | canExecute: () => { return true; } 56 | }; 57 | this.commands.push(cmd); 58 | } 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/goToDatasource/GoToDatasourceModule.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.GoToDatasource { 4 | export class GoToDatasourceModule extends ModuleBase implements ISitecoreExtensionsModule { 5 | className: string = "sc-ext-goToDatasource"; 6 | 7 | constructor(name: string, description: string, rawOptions: Options.ModuleOptionsBase) { 8 | super(name, description, rawOptions); 9 | } 10 | 11 | canExecute(): boolean { 12 | return this.options.enabled && Context.Location() == Enums.Location.ContentEditor; 13 | } 14 | 15 | initialize(): void { 16 | window.addEventListener('load', () => this.refreshFields()); 17 | this.addTreeNodeHandlers('scContentTree'); 18 | HTMLHelpers.addProxy(scSitecore, 'postEvent', () => { this.refreshFields(); }); 19 | HTMLHelpers.addProxy(scForm, 'invoke', () => this.refreshFields()); 20 | HTMLHelpers.addProxy(scForm, 'resume', () => this.refreshFields()); 21 | } 22 | 23 | private getFields(fieldSelector: string, objectInitializer: Fields.FieldInitializer) { 24 | let fields = document.querySelectorAll(fieldSelector); 25 | for (let i = 0; i < fields.length; i++) { 26 | var rawField = fields[i] as HTMLSelectElement; 27 | if (!rawField.classList.contains(this.className)) { 28 | let field = objectInitializer(rawField) as Fields.IDatasourceField; 29 | field.initialize(); 30 | } 31 | } 32 | } 33 | 34 | private refreshFields(): void { 35 | this.getFields(".scContentControlMultilistBox", (field) => { 36 | return new Fields.ListField(field); 37 | }); 38 | this.getFields(".scContentControl.scCombobox", (field) => { 39 | return new Fields.DropLink(field); 40 | }); 41 | this.getFields(".scCombobox select.scCombobox", (field) => { 42 | return new Fields.NameLookupValueList(field); 43 | }); 44 | } 45 | 46 | private addTreeNodeHandlers(className: string): void { 47 | var nodes = document.getElementsByClassName(className); 48 | for (var i = 0; i < nodes.length; i++) { 49 | nodes[i].addEventListener('click', (evt) => { 50 | setTimeout(() => { 51 | this.refreshFields(); 52 | }, 10); 53 | }); 54 | } 55 | } 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/sc_ext/Notification.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions { 4 | interface IziToastFunction { 5 | (settings: IziToastSettings): void; 6 | } 7 | 8 | export class Notification { 9 | private static instance: Notification; 10 | 11 | public warning(settings: IziToastSettings): void { 12 | this.invokeLibFun((s) => { iziToast.warning(s); }, settings); 13 | } 14 | 15 | public show(settings: IziToastSettings): void | boolean { 16 | this.invokeLibFun((s) => { iziToast.show(s); }, settings); 17 | } 18 | 19 | public info(settings: IziToastSettings): void { 20 | this.invokeLibFun((s) => { iziToast.info(s); }, settings); 21 | } 22 | 23 | public error(settings: IziToastSettings): void { 24 | this.invokeLibFun((s) => { iziToast.error(s); }, settings); 25 | } 26 | 27 | public success(settings: IziToastSettings): void { 28 | this.invokeLibFun((s) => { iziToast.success(s); }, settings); 29 | } 30 | 31 | public question(settings: IziToastSettings): void { 32 | this.invokeLibFun((s) => { iziToast.question(s); }, settings); 33 | } 34 | 35 | public settings(settings: IziToastSettings): void { 36 | this.invokeLibFun((s) => { iziToast.settings(s); }, settings); 37 | } 38 | 39 | public progress(settings: IziToastSettings, toast: HTMLDivElement, callback?: () => void): IziToastProgress { return null; } 40 | 41 | public hide(settings: IziToastSettings, toast: HTMLDivElement | string, closedBy?: string): void { } 42 | 43 | public destroy(): void { 44 | this.invokeLibFun((s) => { iziToast.destroy(); }, null); 45 | } 46 | 47 | protected invokeLibFun(fun: IziToastFunction, settings: IziToastSettings): void { 48 | if (window["iziToast"] != undefined) { fun(settings); } else { 49 | this.loadLibrary(); 50 | HTMLHelpers.postponeAction(() => { 51 | return window["iziToast"] != undefined; 52 | }, () => { fun(settings); }, 200, 10); 53 | } 54 | } 55 | 56 | protected loadLibrary() { 57 | window.postMessage({ 58 | sc_ext_enabled: true, 59 | sc_ext_load_lib_request: true, 60 | sc_ext_lib: "/sc_ext/libraries/iziToast.js" 61 | }, '*'); 62 | } 63 | 64 | public static get Instance(): IziToast { 65 | return this.instance || (this.instance = new this()); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /app/sc_ext/status/ModulesStatusProvider.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Status { 4 | import ISitecoreExtensionsModule = Modules.ISitecoreExtensionsModule; 5 | import LauncherModule = Modules.Launcher.LauncherModule; 6 | 7 | export class ModulesStatusProvider implements IStatusProvider { 8 | private globalModulesKey: string = "scExtManagerGlobalContextModules"; 9 | private globalModulesNames: string[] = ["Database Name", "Database Colour"]; 10 | 11 | constructor() { 12 | this.saveState(); 13 | } 14 | 15 | public saveState() { 16 | var globalModules = window.top[this.globalModulesKey] || new Array(); 17 | for (let i = 0; i < this.globalModulesNames.length; i++) { 18 | let m = SitecoreExtensions.scExtManager.getModuleByName(this.globalModulesNames[i]); 19 | if (m != null && m.canExecute()) { 20 | globalModules.push(m); 21 | } 22 | } 23 | window.top[this.globalModulesKey] = globalModules; 24 | } 25 | 26 | public getStatus(): string { 27 | return this.getModulesCount().toString(); 28 | } 29 | 30 | private getAvailableCommandsCount(): string { 31 | var launcher = SitecoreExtensions.scExtManager.getModule(LauncherModule) as LauncherModule; 32 | var availableCommands = launcher.commands.filter((m) => { return m.canExecute(); }); 33 | return availableCommands.length.toString(); 34 | } 35 | 36 | private getModulesCount(): number { 37 | return this.getActiveModules().length; 38 | } 39 | 40 | private getActiveModules(): ISitecoreExtensionsModule[] { 41 | var activeModules = SitecoreExtensions.scExtManager.modules.filter(m => { return m.canExecute(); }); 42 | var globalModules = window.top[this.globalModulesKey] || new Array(); 43 | for (var index = 0; index < globalModules.length; index++) { 44 | activeModules.push(globalModules[index]); 45 | } 46 | return this.getUniqueModules(activeModules); 47 | } 48 | 49 | private getUniqueModules(modules: ISitecoreExtensionsModule[]) { 50 | var result = new Array(); 51 | for (var i = 0, l = modules.length; i < l; i++) 52 | if (result.filter(m => { return m.moduleName == modules[i].moduleName; }).length == 0) 53 | result.push(modules[i]); 54 | return result; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /app/options/views/links.html: -------------------------------------------------------------------------------- 1 |
2 | 11 |
12 |
13 |
14 |

Add new Links

15 | 24 |
25 | 26 |
27 |

Edit Links:

28 |
29 |
30 |

Order

31 |
32 |
33 |

Name

34 |
35 |
36 |

Url

37 |
38 |
39 |

Type

40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | 53 |
54 |
55 | 56 |
57 |
58 |
59 |
60 |
61 |
62 |
-------------------------------------------------------------------------------- /app/sc_ext/libraries/Fuzzy.ts: -------------------------------------------------------------------------------- 1 | module SitecoreExtensions.Libraries { 2 | export class Fuzzy { 3 | analyzeSubTerms = false; 4 | analyzeSubTermDepth = 10; 5 | highlighting = { 6 | before: '', 7 | after: '' 8 | }; 9 | 10 | matchComparator = (m1, m2) => { 11 | return (m2.score - m1.score != 0) ? m2.score - m1.score : m1.term.length - m2.term.length; 12 | } 13 | 14 | getScore(term, query) { 15 | var max = this.calcFuzzyScore(term, query); 16 | var termLength = term.length; 17 | 18 | if (this.analyzeSubTerms) { 19 | 20 | for (var i = 1; i < termLength && i < this.analyzeSubTermDepth; i++) { 21 | var subTerm = term.substring(i); 22 | var score = this.calcFuzzyScore(subTerm, query); 23 | if (score.score > max.score) { 24 | score.term = term; 25 | score.highlightedTerm = term.substring(0, i) + score.highlightedTerm; 26 | max = score; 27 | } 28 | } 29 | } 30 | return max; 31 | }; 32 | 33 | private calcFuzzyScore(term, query) { 34 | var score = 0; 35 | var termLength = term.length; 36 | var queryLength = query.length; 37 | var highlighting = ''; 38 | var ti = 0; 39 | var previousMatchingCharacter = -2; 40 | 41 | for (var qi = 0; qi < queryLength && ti < termLength; qi++) { 42 | var qc = query.charAt(qi); 43 | var lowerQc = qc.toLowerCase(); 44 | 45 | for (; ti < termLength; ti++) { 46 | var tc = term.charAt(ti); 47 | 48 | if (lowerQc === tc.toLowerCase()) { 49 | score++; 50 | 51 | if ((previousMatchingCharacter + 1) === ti) { 52 | score += 2; 53 | } 54 | 55 | highlighting += this.highlighting.before + 56 | tc + 57 | this.highlighting.after; 58 | previousMatchingCharacter = ti; 59 | ti++; 60 | break; 61 | } else { 62 | highlighting += tc; 63 | } 64 | } 65 | } 66 | 67 | highlighting += term.substring(ti, term.length); 68 | 69 | return { 70 | score: score, 71 | term: term, 72 | query: query, 73 | highlightedTerm: highlighting 74 | }; 75 | }; 76 | } 77 | } -------------------------------------------------------------------------------- /app/chrome/popup/styles/main.scss: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | 5 | @font-face { 6 | font-family: 'fontawesome-webfont'; 7 | src: url('../fonts/fontawesome-webfont.eot?22561381'); 8 | src: url('../fonts/fontawesome-webfont.eot?22561381#iefix') 9 | format('embedded-opentype'), 10 | url('../fonts/fontawesome-webfont.woff?22561381') 11 | format('woff'), url('../fonts/fontawesome-webfont.ttf?22561381') 12 | format('truetype'), 13 | url('../fonts/fontawesome-webfont.svg?22561381#fontawesome-webfont') format('svg'); 14 | font-weight: normal; 15 | font-style: normal; 16 | } 17 | 18 | .fa { 19 | font-family: "fontawesome-webfont"; 20 | font-style: normal; 21 | font-weight: normal; 22 | display: inline-block; 23 | text-decoration: inherit; 24 | width: 1em; 25 | text-align: center; 26 | font-variant: normal; 27 | text-transform: none; 28 | -webkit-font-smoothing: antialiased; 29 | -moz-osx-font-smoothing: grayscale; 30 | text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); 31 | padding-right: 5px; 32 | } 33 | 34 | li.logo { 35 | float: right !important; 36 | margin-right: 10px; 37 | padding-top: 2px; 38 | } 39 | 40 | ul.link-list { 41 | list-style-type: none; 42 | margin: 0; 43 | padding: 0; 44 | width: 350px; 45 | background-color: #f1f1f1; 46 | li a { 47 | display: block; 48 | color: #000; 49 | padding: 8px 16px; 50 | text-decoration: none; 51 | } 52 | li a:hover { 53 | background-color: #555; 54 | color: white; 55 | } 56 | } 57 | 58 | ul.header-navigation { 59 | list-style-type: none; 60 | margin: 0; 61 | padding: 0; 62 | overflow: hidden; 63 | background-color: #333; 64 | li { 65 | float: left; 66 | } 67 | li a { 68 | display: block; 69 | color: white; 70 | text-align: center; 71 | padding: 14px 14px; 72 | text-decoration: none; 73 | } 74 | li a:hover { 75 | background-color: #111; 76 | } 77 | li.active { 78 | background-color: #111; 79 | } 80 | } 81 | 82 | .wrapper{ 83 | max-height: 350px; 84 | overflow-x: hidden; 85 | overflow-y: auto; 86 | } 87 | 88 | 89 | ::-webkit-scrollbar { 90 | width: 12px; 91 | } 92 | 93 | ::-webkit-scrollbar-thumb { 94 | background: rgba(136,136,136,0.8); 95 | -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5); 96 | box-shadow: #000; 97 | } 98 | 99 | .info-section { 100 | background-color: #2b2b2b; 101 | color: white; 102 | padding: 5px 15px 1px 15px; 103 | font-family: Arial, sans-serif; 104 | } 105 | 106 | .no-data { 107 | display: none; 108 | } 109 | 110 | .info-item { 111 | display: flex; 112 | justify-content: space-between; 113 | padding: 5px 0; 114 | } 115 | 116 | .label { 117 | font-weight: bold; 118 | } -------------------------------------------------------------------------------- /app/sc_ext/_all.ts: -------------------------------------------------------------------------------- 1 | // Typings 2 | /// 3 | /// 4 | /// 5 | 6 | // Options Page 7 | /// 8 | /// 9 | /// 10 | 11 | // Options 12 | /// 13 | /// 14 | /// 15 | /// 16 | 17 | // Common 18 | /// 19 | 20 | // Storage 21 | /// 22 | 23 | // Page Objects 24 | /// 25 | 26 | // Other 27 | /// 28 | /// 29 | /// 30 | /// 31 | /// 32 | /// 33 | /// 34 | /// 35 | 36 | ///Events 37 | /// 38 | 39 | // Http 40 | /// 41 | /// 42 | // Libraries 43 | /// 44 | 45 | // Modules 46 | /// 47 | /// 48 | 49 | /// 50 | /// 51 | /// 52 | /// 53 | /// 54 | /// 55 | /// 56 | /// 57 | /// 58 | /// 59 | /// 60 | /// 61 | /// 62 | /// 63 | /// 64 | /// 65 | /// 66 | /// 67 | 68 | 69 | // Status 70 | /// 71 | /// 72 | /// 73 | /// 74 | /// -------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/RecentCommandsStore.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Launcher { 4 | import GlobalStorage = SitecoreExtensions.Storage.GlobalStorage; 5 | export class RecentCommandsStore { 6 | array: Array; 7 | recentCommandsKey: string = "sc_ext::recent_commands"; 8 | private storageType: StorageType; 9 | 10 | constructor(historyCount: number, storageType: StorageType) { 11 | this.array = this.getArrayWithLimitedLength(historyCount); 12 | this.storageType = storageType; 13 | } 14 | 15 | add(command: ICommand): void { 16 | this.array = this.array.filter((name) => { return name != command.name; }); 17 | this.array.push(command.name); 18 | 19 | let storageValue = this.array.slice(-50).join('|'); 20 | if (this.storageType == StorageType.GlobalStorage) { 21 | let options = new Options.ModuleOptionsBase(this.recentCommandsKey, { 22 | value: storageValue 23 | }); 24 | GlobalStorage.set(this.recentCommandsKey, storageValue); 25 | } else { 26 | localStorage.setItem(this.recentCommandsKey, storageValue); 27 | } 28 | } 29 | 30 | async getRecentCommands(commands: ICommand[]) { 31 | if (this.array.length == 0) { 32 | if (this.storageType == StorageType.GlobalStorage) { 33 | let options = await GlobalStorage.get(this.recentCommandsKey); 34 | if (options) { 35 | this.array = options.split('|').filter((x) => { return x.length > 0; }); 36 | } 37 | } else { 38 | var recentCommands = localStorage.getItem(this.recentCommandsKey); 39 | await (async () => { 40 | if (recentCommands) { 41 | this.array = recentCommands.split('|').filter((x) => { return x.length > 0; }); 42 | } 43 | })(); 44 | } 45 | } 46 | 47 | let result = new Array(); 48 | this.array.forEach(commandName => { 49 | let command = commands.filter(c => c.name == commandName && c.canExecute())[0]; 50 | if (command) { 51 | result.push(command); 52 | } 53 | }); 54 | 55 | return [].concat(result).reverse(); 56 | } 57 | 58 | private getArrayWithLimitedLength(length): Array { 59 | var array = new Array(); 60 | array.push = function () { 61 | if (this.length >= length) { 62 | this.shift(); 63 | } 64 | return Array.prototype.push.apply(this, arguments); 65 | }; 66 | return array; 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /app/sc_ext/styles/launcher.scss: -------------------------------------------------------------------------------- 1 | $font: "Arvo", "Helvetica Neue", Helvetica, arial, sans-serif; 2 | 3 | 4 | #sc-ext-modal.launcher-modal { 5 | display: none; 6 | position: fixed; 7 | z-index: 20001; 8 | padding-top: 250px; 9 | left: 0; 10 | top: 0; 11 | width: 100%; 12 | height: 100%; 13 | overflow: auto; 14 | background-color: rgb(0, 0, 0); 15 | background-color: rgba(0, 0, 0, 0.4); 16 | .launcher-modal-content { 17 | margin: auto; 18 | top: 20px; 19 | position: relative; 20 | width: 50%; 21 | .border { 22 | -moz-border-radius: 3px; 23 | -webkit-border-radius: 3px; 24 | border-radius: 3px; 25 | } 26 | .search-field { 27 | @extend .border; 28 | display: block; 29 | width: 100% !important; 30 | margin: 1em auto 0; 31 | padding: 0.5em 0px !important; 32 | text-indent: 10px; 33 | border: 1px solid #999; 34 | font-size: 140% !important; 35 | font-family: $font !important; 36 | font-weight: 400 !important; 37 | color: #A2A2A2 !important; 38 | background-color: #3A3A3A !important; 39 | } 40 | .search-field.sc-ext-search-progress { 41 | background: url('/sitecore/shell/Applications/Buckets/images/sc-spinner32.gif'); 42 | background-repeat: no-repeat; 43 | background-size: 24px; 44 | background-position: right 10px center; 45 | background-blend-mode: luminosity; 46 | } 47 | .term-list { 48 | @extend .border; 49 | list-style: none inside; 50 | margin: 0 auto 2em; 51 | padding: 0px; 52 | text-align: left; 53 | color: #A2A2A2; 54 | background: #464646; 55 | li { 56 | padding: 0.5em 0; 57 | border-bottom: 1px solid 464646; 58 | font-family: $font !important; 59 | font-size: 120% !important; 60 | } 61 | li.sc-ext-selected-term { 62 | color: white; 63 | background-color: #006ED7 64 | } 65 | strong { 66 | color: #444; 67 | font-weight: 700; 68 | } 69 | } 70 | .term-list.hidden { 71 | display: none; 72 | } 73 | span.command-description { 74 | float: right; 75 | padding-right: 10px; 76 | font-size: 90%; 77 | line-height: 100%; 78 | width: 60%; 79 | padding-top: -6px; 80 | text-align: right; 81 | } 82 | @media only screen and (max-width: 1250px) { 83 | .command-description { 84 | display: none; 85 | } 86 | } 87 | span.command-name { 88 | padding-left: 10px; 89 | .term { 90 | color: white; 91 | } 92 | } 93 | img.command-img { 94 | padding-left: 10px; 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /app/options/providers/OptionsProvider.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | module SitecoreExtensions.Options { 5 | 'use strict'; 6 | 7 | export interface IModuleOptions { 8 | name: string; 9 | model: any; 10 | } 11 | 12 | export class ModuleOptionsBase implements IModuleOptions { 13 | name: string; 14 | model: any; 15 | constructor(name: string, model: any) { 16 | this.name = name; 17 | this.model = model; 18 | } 19 | } 20 | 21 | export class OptionsWrapper { 22 | options: IModuleOptions[]; 23 | 24 | constructor(options: IModuleOptions[]) { 25 | this.options = options; 26 | } 27 | 28 | static create(optionsWrapper: OptionsWrapper): OptionsWrapper { 29 | return new OptionsWrapper(optionsWrapper.options); 30 | } 31 | 32 | getModuleOptions(moduleName: string): IModuleOptions { 33 | if (this.options != null) { 34 | return this.options.find(m => { return m.name == moduleName; }); 35 | } 36 | } 37 | 38 | setModuleOptions(options: IModuleOptions): void { 39 | var moduleOptions = this.getModuleOptions(options.name); 40 | var index = this.options.indexOf(moduleOptions); 41 | if (index !== -1) { 42 | this.options[index] = options; 43 | } else { 44 | this.options.push(options); 45 | } 46 | } 47 | } 48 | 49 | declare type GetOptionsCallback = (arg: OptionsWrapper) => void; 50 | 51 | export class OptionsProvider { 52 | getOptions(done: GetOptionsCallback): void { 53 | chrome.storage.local.get({ 54 | sc_ext_options: null, 55 | }, function (items: any) { 56 | done(items.sc_ext_options); 57 | }); 58 | } 59 | 60 | setOptions(moduleOptions: IModuleOptions[], done: any): void { 61 | chrome.storage.local.set({ 62 | sc_ext_options: new OptionsWrapper(moduleOptions), 63 | }, done); 64 | } 65 | 66 | getModuleOptions(name: string, done: any): void { 67 | this.getOptions((optionsWrapper) => { 68 | if (optionsWrapper != null) { 69 | done(OptionsWrapper.create(optionsWrapper).getModuleOptions(name)); 70 | } 71 | }); 72 | } 73 | 74 | setModuleOptions(options: IModuleOptions): void { 75 | this.getOptions((optionsWrapper) => { 76 | if (optionsWrapper != null) { 77 | (OptionsWrapper.create(optionsWrapper)).setModuleOptions(options); 78 | } else { 79 | var array = new Array(); 80 | array.push(options); 81 | optionsWrapper = new OptionsWrapper(array); 82 | } 83 | chrome.storage.local.set({ sc_ext_options: optionsWrapper }); 84 | }); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/databaseSelector/DatabaseSelectorModule.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.DatabaseSelector { 4 | import HttpRequest = Http.HttpRequest; 5 | import Method = Http.Method; 6 | import TokenService = SitecoreExtensions.Modules.ShortcutsRunner.TokenService; 7 | import Token = SitecoreExtensions.Modules.ShortcutsRunner.Token; 8 | 9 | 10 | export class DatabaseSelectorModule extends ModuleBase implements ISitecoreExtensionsModule { 11 | private retryCount: number = 3; 12 | private tokenService: TokenService; 13 | 14 | constructor(name: string, description: string, rawOptions: Options.ModuleOptionsBase) { 15 | super(name, description, rawOptions); 16 | this.tokenService = new TokenService(); 17 | } 18 | 19 | canExecute(): boolean { 20 | return this.options.enabled; 21 | } 22 | 23 | initialize(): void { 24 | if (DatabaseNamesStore.getDatabases().length == 0) { 25 | this.init(); 26 | } 27 | } 28 | 29 | private getSelectDatabaseDialogResponse(callback) { 30 | let url = window.top.location.origin + "/sitecore/shell/default.aspx"; 31 | this.tokenService.getToken().then((token) => { 32 | if (token) { 33 | var postData = "&__PARAMETERS=" + "ShowDatabases" 34 | + "&__ISEVENT=" + "1" 35 | + "&__CSRFTOKEN=" + token.__CSRFTOKEN 36 | + "&__VIEWSTATE=" + token.__VIEWSTATE; 37 | } 38 | new Http.HttpRequest(url, Http.Method.POST, callback).execute(postData); 39 | }); 40 | } 41 | 42 | private handleErrorAndRetry(): void { 43 | if (this.retryCount-- < 0) { 44 | return; 45 | } 46 | this.tokenService.invalidateToken().then(() => { 47 | this.init(); 48 | }); 49 | } 50 | 51 | private init() { 52 | this.getSelectDatabaseDialogResponse((e) => { 53 | if (e.currentTarget.status == 500) { 54 | this.handleErrorAndRetry(); 55 | } else { 56 | var data = e.currentTarget.responseText; 57 | var parser = new DOMParser(); 58 | var doc = parser.parseFromString(data, "text/html"); 59 | 60 | let trs = doc.querySelectorAll('body>table>tbody>tr'); 61 | let dbNames = new Array(); 62 | 63 | for (var index = trs.length - 1; index >= 0; index--) { 64 | var dbRow = trs[index] as HTMLTableRowElement; 65 | if (dbRow.innerText.length > 0) { 66 | dbNames.push(dbRow.innerText); 67 | } else { 68 | break; 69 | } 70 | } 71 | if (dbNames.length > 0) { 72 | DatabaseNamesStore.saveDatabases(dbNames); 73 | } 74 | } 75 | }); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /app/sc_ext/modules/placeholder/PlaceholderModule.ts: -------------------------------------------------------------------------------- 1 | 2 | namespace SitecoreExtensions.Modules.Placeholder { 3 | export class PlaceholderModule extends ModuleBase implements ISitecoreExtensionsModule { 4 | private readonly initKey: string = 'sc_ext_initialized'; 5 | constructor(name: string, description: string, rawOptions: Options.ModuleOptionsBase) { 6 | super(name, description, rawOptions); 7 | } 8 | 9 | public static removeRenderings(placeholderID: string) { 10 | let phChrome = [].find.call(Sitecore.PageModes.DesignManager.placeholders(), function (chrome) { 11 | return chrome.isEnabled() && new PlaceholderChrome(chrome).getPlaceholderId() == placeholderID; 12 | }); 13 | [].forEach.call(phChrome.getChildChromes(), (renderingChrome) => { phChrome.type.deleteControl(renderingChrome); }); 14 | [].forEach.call(this.getStaleRenderings(placeholderID), (r: Rendering) => { r.remove(); }); 15 | } 16 | 17 | private static getStaleRenderings(placeholderID: string): Array { 18 | return [].filter.call(this.getAllRenderings(), (r: Rendering) => { 19 | return r.placeholder.match(new RegExp(placeholderID, "g")) != null; 20 | }); 21 | } 22 | 23 | private static getAllRenderings(): Array { 24 | return [].map.call(Sitecore.LayoutDefinition.getRenderings(), (r: any) => { return new Rendering(r); }) as Array; 25 | } 26 | 27 | canExecute(): boolean { 28 | return this.options.enabled && Context.Location() == Enums.Location.ExperienceEditor && Sitecore.PageModes != null; 29 | } 30 | 31 | initialize(): void { 32 | HTMLHelpers.addProxy(Sitecore.PageModes.ChromeManager, "resetChromes", () => { 33 | this.getPlaceholders().forEach((placeholder: PlaceholderChrome) => { 34 | let placeholderID = placeholder.getPlaceholderId(); 35 | 36 | let removeCommand = this.buildRemoveCommand(placeholderID); 37 | placeholder.addCommand(removeCommand); 38 | placeholder.chrome.data[this.initKey] = true; 39 | }); 40 | }); 41 | } 42 | 43 | protected getPlaceholders(): Array { 44 | let allPlaceholders = Sitecore.PageModes.DesignManager.placeholders(); 45 | let placeholders = [].filter.call(allPlaceholders, (chrome: any) => { return chrome.data[this.initKey] == null; }); 46 | return [].map.call(placeholders, (p: any) => { return new PlaceholderChrome(p); }) as Array; 47 | } 48 | 49 | protected buildRemoveCommand(placeholderID: string): IPlaceholderCommand { 50 | const removeCommand: IPlaceholderCommand = { 51 | click: `SitecoreExtensions.Modules.Placeholder.PlaceholderModule.removeRenderings('${placeholderID}')`, 52 | header: 'Remove', 53 | icon: '/temp/iconcache/office/16x16/delete.png', 54 | disabledIcon: '/temp/add_disabled16x16.png', 55 | isDivider: false, 56 | tooltip: `Remove all renderings from the '${placeholderID}' placeholder.`, 57 | type: "" 58 | }; 59 | return removeCommand; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/sc_ext/modules/sectionSwitches/SectionSwitchesModule.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.SectionSwitches { 4 | export class SectionSwitchesModule extends ModuleBase implements ISitecoreExtensionsModule { 5 | sectionSwitchButtonClassName: string; 6 | 7 | constructor(name: string, description: string, rawOptions: Options.ModuleOptionsBase) { 8 | super(name, description, rawOptions); 9 | this.sectionSwitchButtonClassName = 'scEButton'; 10 | } 11 | 12 | canExecute(): boolean { 13 | return this.options.enabled && Context.Location() == Enums.Location.ContentEditor; 14 | } 15 | 16 | initialize(): void { 17 | window.addEventListener('load', () => this.refreshButtons()); 18 | this.addTreeNodeHandlers('scContentTree'); 19 | HTMLHelpers.addProxy(scSitecore, 'postEvent', () => { this.refreshButtons(); }); 20 | HTMLHelpers.addProxy(scForm, 'invoke', () => { this.refreshButtons(); }); 21 | HTMLHelpers.addProxy(scForm, 'resume', () => { this.refreshButtons(); }); 22 | } 23 | 24 | closeOpenedSections() { 25 | HTMLHelpers.triggerEventOnSelector('.scEditorSectionCaptionExpanded .scEditorSectionCaptionGlyph', 'click'); 26 | }; 27 | 28 | openClosedSections() { 29 | HTMLHelpers.triggerEventOnSelector('.scEditorSectionCaptionCollapsed .scEditorSectionCaptionGlyph', 'click'); 30 | }; 31 | 32 | createTabControlButton(text: string, callback: { (e: MouseEvent): any }): HTMLAnchorElement { 33 | var span = HTMLHelpers.createElement('span', {}); 34 | span.innerText = text; 35 | var link = HTMLHelpers.createElement('a', { 36 | href: '#', 37 | class: 'scEditorHeaderNavigator scEditorHeaderButton scButton ' + this.sectionSwitchButtonClassName 38 | }); 39 | link.onclick = callback; 40 | link.appendChild(span); 41 | return link; 42 | } 43 | 44 | buttonsExists(): boolean { 45 | return document.getElementsByClassName(this.sectionSwitchButtonClassName).length > 0; 46 | } 47 | 48 | refreshButtons(): void { 49 | if (!this.buttonsExists()) { 50 | this.insertButtons(); 51 | } 52 | } 53 | 54 | addTreeNodeHandlers(className: string): void { 55 | var nodes = document.getElementsByClassName(className); 56 | for (var i = 0; i < nodes.length; i++) { 57 | nodes[i].addEventListener('click', (evt) => { 58 | setTimeout(() => { 59 | this.refreshButtons(); 60 | }, 10); 61 | }); 62 | } 63 | } 64 | 65 | private insertButtons(): void { 66 | var btnCollapse = this.createTabControlButton('Collapse', this.closeOpenedSections); 67 | var btnExpand = this.createTabControlButton('Expand', this.openClosedSections); 68 | 69 | var controlsTab = document.querySelector('.scEditorTabControlsTab5'); 70 | controlsTab.insertBefore(btnCollapse, controlsTab.firstChild); 71 | controlsTab.insertBefore(btnExpand, controlsTab.firstChild); 72 | }; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/sc_ext/modules/launcher/providers/ShellCommandsProvider.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | namespace SitecoreExtensions.Modules.Launcher.Providers { 4 | export class ShellCommandsProvider extends BaseCommandsProvider { 5 | constructor() { 6 | super(); 7 | } 8 | 9 | createCommands(): void { 10 | var canExecute = () => { return Context.Location() == Enums.Location.ContentEditor || Context.Location() == Enums.Location.Desktop; }; 11 | 12 | this.addInvokeCommand('Analytics - Reports', 'Experience Analytics reports', 'analytics:reports', canExecute); 13 | this.addInvokeCommand('Analytics - Status Information', 'An overview of your servers and their current status.', 'analytics:status', canExecute); 14 | this.addInvokeCommand('Export Languages', 'Select the languages that you want to export.', 'globalization:exportlanguage', canExecute); 15 | this.addInvokeCommand('Import Languages', 'Enter the language file name of the language that you want to import', 'globalization:importlanguage', canExecute); 16 | this.addInvokeCommand('Scan for Untranslated Fields', 'Select the languages that you want to scan for untranslated fields.', 'globalization:untranslatedfields', canExecute); 17 | this.addInvokeCommand('Change Region and Language Options', 'Select your preferred number and date format and the application language', 'preferences:changeregionalsettings', canExecute); 18 | this.addInvokeCommand('Change personal/user Information', 'Change your personal information', 'preferences:changeuserinformation', canExecute); 19 | this.addInvokeCommand('Change wallpaper', 'Select a desktop background.', 'preferences:changewallpaper', canExecute); 20 | this.addInvokeCommand('Content Carousel', 'Presents content items as a carousel', 'carousel:home', canExecute); 21 | this.addInvokeCommand('Customize My Toolbar', 'Add or remove commands from My Toolbar.', 'ribbon:customize', canExecute); 22 | this.addInvokeCommand('User Options', 'Application Options', 'shell:useroptions', canExecute); 23 | 24 | this.addInvokeCommand('Add a new language', 'Choose a predefined language code or enter a language identifier and a country/region code for the new language.', 'system:addlanguage', canExecute); 25 | this.addInvokeCommand('Delete a Language', 'Select the languages that you want to delete.', 'system:deletelanguage', canExecute); 26 | this.addInvokeCommand('Database Usage', 'Database usage stastistics', 'system:databaseusage', canExecute); 27 | this.addInvokeCommand('Rebuild Link Databases', 'Rebuild Link Databases', 'system:rebuildlinkdatabase', canExecute); 28 | this.addInvokeCommand('License Details', 'Show license details window', 'system:showabout', canExecute); 29 | this.addInvokeCommand('Licenses', 'Show installed licenses', 'system:showlicenses', canExecute); 30 | 31 | this.addInvokeCommand('Indexing Manager (rebuild serach index)', 'Select the search indexes that you want to rebuild.', 'indexing:runmanager', canExecute); 32 | this.addInvokeCommand('Generate the Solr schema', 'Generate the Solr Schema.xml file', 'indexing:generatesolrschema', canExecute); 33 | 34 | this.addInvokeCommand('Deploy marketing definitions', 'Deploy marketing definitions', 'marketing:opendeploydefinitionsdialog', canExecute); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /app/options/views/snippets/navigation.html: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------