├── NOTICE ├── COPYRIGHT.md ├── .gitignore ├── sly ├── toolbar │ ├── toolbar-aem-indicator.html │ ├── ToolBar.js │ └── brackets_aem_icons.svg ├── nls │ ├── strings.js │ ├── root │ │ └── strings.js │ ├── en-gb │ │ └── strings.js │ └── ro │ │ └── strings.js ├── panel │ ├── aem-sync-entry.html │ ├── aem-sync-panel.html │ └── Panel.js ├── bootstrap │ ├── extensions │ │ ├── sling.json │ │ └── cq.json │ └── default.json ├── SessionStorage.js ├── FileMTimeCache.js ├── node │ ├── Constants.js │ ├── FilterRule.js │ ├── VaultIgnore.js │ ├── Filter.js │ ├── SlyDomain.js │ └── PackMgr.js ├── styles │ └── sly.css ├── command │ └── Commands.js ├── menu │ └── Menu.js ├── preferences │ ├── project-settings-dialog.html │ └── Preferences.js ├── Highlighter.js ├── ProjectUtils.js ├── Preview.js ├── BeanManager.js ├── SightlyLanguage.js ├── SightlyCodeHint.js └── RemoteSyncManager.js ├── sly-tests ├── resources │ ├── parse-test.sly │ └── codehint-test.sly ├── BeanManagerTest.js ├── SightlyLanguageTest.js └── SightlyCodeHintTest.js ├── .jshintrc ├── strings.js ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── unittests.js ├── LICENSE_HEADER.md ├── package.json ├── PULL_REQUEST_TEMPLATE.md ├── CONTRIBUTING.md ├── main.js ├── README.md ├── CODE_OF_CONDUCT.md ├── Gruntfile.js └── LICENSE /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2014 Adobe Systems Incorporated. All rights reserved. 2 | 3 | Licensed under the Apache License 2.0. 4 | http://www.apache.org/licenses/LICENSE-2.0 -------------------------------------------------------------------------------- /COPYRIGHT.md: -------------------------------------------------------------------------------- 1 | © Copyright 2015-2018 Adobe. All rights reserved. 2 | 3 | Adobe holds the copyright for all the files found in this repository. 4 | 5 | See the LICENSE file for licensing information. 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | atlassian-ide-plugin.xml 2 | node_modules 3 | sling 4 | target 5 | .idea 6 | .classpath 7 | .project 8 | .settings 9 | .checkstyle 10 | *.iml 11 | *.ipr 12 | *.iws 13 | bin 14 | .vlt 15 | .vlt-sync-config.properties 16 | .vlt-sync.log 17 | .DS_Store 18 | *.log 19 | -------------------------------------------------------------------------------- /sly/toolbar/toolbar-aem-indicator.html: -------------------------------------------------------------------------------- 1 | {{!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 | ~ Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved. 3 | ~ 4 | ~ Licensed under the Apache License 2.0. 5 | ~ http://www.apache.org/licenses/LICENSE-2.0 6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--}} 7 | 8 | -------------------------------------------------------------------------------- /sly-tests/resources/parse-test.sly: -------------------------------------------------------------------------------- 1 | 2 |
6 | blah 7 |
8 | 9 | 10 |FilterRule represents an 'include' / 'exclude' single entry for a 'filter' tag from an Apache Jackrabbit FileVault
12 | * filter.xml file.
13 | *
14 | * @param {String} type the rule's type (see {@link FilterRule#INCLUDE_RULE}, {@link FilterRule#EXCLUDE_RULE})
15 | * @param {RegExp} pattern the rule's pattern
16 | * @constructor
17 | */
18 | function FilterRule(type, pattern) {
19 | this.type = type;
20 | this.pattern = pattern;
21 | }
22 |
23 | /**
24 | * Constant for 'include' rule type.
25 | * @type {string}
26 | */
27 | FilterRule.INCLUDE_RULE = 'include';
28 |
29 | /**
30 | * Constant for 'exclude' rule type.
31 | * @type {String}
32 | */
33 | FilterRule.EXCLUDE_RULE = 'exclude';
34 |
35 | module.exports = FilterRule;
36 | }());
--------------------------------------------------------------------------------
/sly/styles/sly.css:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
3 | *
4 | * Licensed under the Apache License 2.0.
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | ******************************************************************************/
7 | .sly table {
8 | width: 100%;
9 | }
10 |
11 | .sly .tablehead, .sly .settings-parameter {
12 | font-weight: 500;
13 | }
14 |
15 | .disabled-toolbar-button {
16 | opacity: 0.4;
17 | pointer-events: none;
18 | cursor: default;
19 | }
20 |
21 | .sly .alert {
22 | color: #DD3E3A;
23 | font-weight: 500;
24 | }
25 |
26 | #sly-status-aem {
27 | background-image: url('../toolbar/brackets_aem_icons.svg');
28 | }
29 |
30 | #sly-status-aem.sly-status-inactive {
31 | background-position: 0px 0px !important;
32 | }
33 |
34 | #sly-status-aem.sly-status-ok {
35 | background-position: 0 -24px !important;
36 | }
37 |
38 | #sly-status-aem.sly-status-warning {
39 | background-position: 0px -48px !important;
40 | }
41 |
42 | #sly-status-aem.sly-status-error {
43 | background-position: 0px -72px !important;
44 | }
45 |
46 | #sly-status-aem.sly-status-active {
47 | background-position: 0px -96px !important;
48 | }
49 |
--------------------------------------------------------------------------------
/sly/panel/aem-sync-panel.html:
--------------------------------------------------------------------------------
1 | {{!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 | ~ Copyright (c) 2015 Adobe Systems Incorporated. All rights reserved.
3 | ~
4 | ~ Licensed under the Apache License 2.0.
5 | ~ http://www.apache.org/licenses/LICENSE-2.0
6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--}}
7 | | {{Strings.SYNC_STATUS_TH_FILE}} | 20 |{{Strings.SYNC_STATUS_TH_STATUS}} | 21 |{{Strings.SYNC_STATUS_TH_TIME}} | 22 |
|---|
Filter represents a single 'filter' entry from an Apache Jackrabbit FileVault filter-vlt.xml / filter.xml file, that
19 | * describes how the content of a root path should be treated with regards to importing it into a content repository.
20 | *
21 | * @param {String} root the filter's root path
22 | * @param {FilterRule[]} rules the 'include' / 'exclude' rules
23 | * @constructor
24 | */
25 | function Filter(root, rules) {
26 | this.root = root;
27 | this.rules = rules;
28 | this._action = _getDefaultAction(rules);
29 | }
30 |
31 | /**
32 | * Checks if a path belonging to a jcr_root can be synced according to this filter or not.
33 | *
34 | * @param {String} path the path to check
35 | * @returns {Number} see {@link Constants}
36 | */
37 | Filter.prototype.getSyncStatus = function (path) {
38 | var shouldSync = Constants.sync.FILTER_IGNORED,
39 | i;
40 | if (_startsWith(path, this.root)) {
41 | var matchedRulePattern = false;
42 | for (i = 0; i < this.rules.length; i++) {
43 | var rule = this.rules[i];
44 | if (rule.pattern.test(path)) {
45 | matchedRulePattern = true;
46 | if (rule.type === FilterRule.INCLUDE_RULE) {
47 | shouldSync = Constants.sync.FILTER_INCLUDED;
48 | } else if (rule.type === FilterRule.EXCLUDE_RULE) {
49 | shouldSync = Constants.sync.FILTER_EXCLUDED;
50 | }
51 | }
52 | }
53 | if (!matchedRulePattern) {
54 | if (this._action === FilterAction.INCLUDE) {
55 | shouldSync = Constants.sync.FILTER_INCLUDED;
56 | } else if (this._action === FilterAction.EXCLUDE) {
57 | shouldSync = Constants.sync.FILTER_EXCLUDED;
58 | }
59 | }
60 | }
61 | return shouldSync;
62 | };
63 |
64 | /**
65 | * Checks if string starts with prefix.
66 | *
67 | * @param {String} string the string
68 | * @param {String} prefix the prefix
69 | * @returns {boolean} true if the string starts with prefix, false otherwise
70 | * @private
71 | */
72 | function _startsWith(string, prefix) {
73 | return string.indexOf(prefix) === 0;
74 | }
75 |
76 | /**
77 | * Analyses the filter's rules and returns its default action.
78 | *
79 | * @param {FilterRule[]} rules the filter's rules
80 | * @returns {String} the filter's action
81 | * @private
82 | */
83 | function _getDefaultAction(rules) {
84 | if (rules && rules.length && rules.length > 0) {
85 | var firstRule = rules[0];
86 | if (firstRule.type === FilterRule.INCLUDE_RULE) {
87 | return FilterAction.EXCLUDE;
88 | } else if (firstRule.type === FilterRule.EXCLUDE_RULE) {
89 | return FilterAction.INCLUDE;
90 | }
91 | }
92 | return FilterAction.INCLUDE;
93 | }
94 |
95 | module.exports = Filter;
96 | }());
--------------------------------------------------------------------------------
/sly/nls/root/strings.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
3 | *
4 | * Licensed under the Apache License 2.0.
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | ******************************************************************************/
7 | /*global define*/
8 | define({
9 | AEM_SLY_EXTENSION : 'AEM Sightly Extension',
10 |
11 | // Button labels
12 | BUTTON_OK : 'OK',
13 | BUTTON_CANCEL : 'Cancel',
14 |
15 | // Menus
16 | // -- top level
17 | MENU_PROJECT_SETTINGS : 'Project Settings...',
18 | MENU_EXPORT_CONTENT_PACKAGE : 'Export Content Package to Server',
19 | MENU_IMPORT_CONTENT_PACKAGE : 'Import Content Package from Server',
20 |
21 | // -- contextual menus
22 | CONTEXTUAL_PULL_REMOTE : 'Import from Server',
23 | CONTEXTUAL_PUSH_REMOTE : 'Export to Server',
24 | CONTEXTUAL_OPEN_REMOTE : 'Open on Server',
25 |
26 | // Project Settings dialogue
27 | PROJECT_SETTINGS : 'Project Settings',
28 | PROJECT_SETTING_SERVER_URL : 'Server URL',
29 | PROJECT_SETTING_REMOTE_USER : 'Username',
30 | PROJECT_SETTING_REMOTE_USER_PASSWORD : 'Password',
31 | PROJECT_SETTING_AUTO_SYNC : 'Automatically synchronize file-system changes to server',
32 | PROJECT_SETTING_SERVER_URL_HINT : 'http://localhost:4502',
33 | PROJECT_SETTING_REMOTE_USER_HINT : 'admin',
34 | PROJECT_SYNCHRONISATION_SETTINGS : 'Synchronization Settings',
35 | PROJECT_SETTING_SERVER_URL_ERROR_MISSING : 'Please provide a server URL.',
36 | PROJECT_SETTING_SERVER_URL_ERROR_INVALID_PROTOCOL: 'Invalid protocol used for the server URL.',
37 | PROJECT_SETTING_SERVER_URL_ERROR_UNKNOWN : 'Unknown error: server URL.',
38 | PROJECT_SETTING_SERVER_URL_ERROR_INVALID_CHAR : 'Special characters like \'{0}\' must be %-encoded.',
39 | PROJECT_SETTING_REMOTE_USER_ERROR_EMPTY : 'Please provide a username.',
40 | PROJECT_SETTING_REMOTE_USER_PASSWORD_ERROR_EMPTY : 'Please provide a password.',
41 | PROJECT_SETTING_ACCEPT_SELF_SIGNED_CERTIFICATES : 'Accept self-signed certificates for HTTPS',
42 |
43 | // Synchronisation indicator tooltip
44 | SYNC_FULL : 'All selected files were synced successfully.',
45 | SYNC_PARTIAL : 'Some of the selected files were not synced successfully.',
46 | SYNC_NONE : 'None of the selected files were synced.',
47 | SYNC_IN_PROGRESS : 'Your selected files are synchronizing.',
48 |
49 | // Synchronisation report dialogue
50 | SYNC_STATUS : 'Synchronization Status',
51 | SYNC_STATUS_TH_FILE : 'Entry',
52 | SYNC_STATUS_TH_STATUS : 'Synchronization Status',
53 | SYNC_STATUS_TH_TIME : 'Time',
54 | SYNC_STATUS_IMPORTED : 'imported',
55 | SYNC_STATUS_EXPORTED : 'exported',
56 | SYNC_STATUS_IGNORED : 'ignored by the filter configuration',
57 | SYNC_STATUS_EXCLUDED : 'excluded by the filter configuration',
58 | SYNC_STATUS_EXCLUDED_VLT : 'vlt file or file excluded by .vltignore pattern',
59 | SYNC_STATUS_DELETED_FROM_REMOTE : 'removed - the file was deleted on the server',
60 |
61 | // Synchronization panel
62 | SYNC_PANEL_CLEAR : 'Clear results'
63 |
64 | });
65 |
--------------------------------------------------------------------------------
/sly/nls/en-gb/strings.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
3 | *
4 | * Licensed under the Apache License 2.0.
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | ******************************************************************************/
7 | /*global define*/
8 | define({
9 | AEM_SLY_EXTENSION : 'AEM Sightly Extension',
10 |
11 | // Button labels
12 | BUTTON_OK : 'OK',
13 | BUTTON_CANCEL : 'Cancel',
14 |
15 | // Menus
16 | // -- top level
17 | MENU_PROJECT_SETTINGS : 'Project Settings...',
18 | MENU_EXPORT_CONTENT_PACKAGE : 'Export Content Package to Server',
19 | MENU_IMPORT_CONTENT_PACKAGE : 'Import Content Package from Server',
20 |
21 | // -- contextual menus
22 | CONTEXTUAL_PULL_REMOTE : 'Import from Server',
23 | CONTEXTUAL_PUSH_REMOTE : 'Export to Server',
24 | CONTEXTUAL_OPEN_REMOTE : 'Open on Server',
25 |
26 | // Project Settings dialogue
27 | PROJECT_SETTINGS : 'Project Settings',
28 | PROJECT_SETTING_SERVER_URL : 'Server URL',
29 | PROJECT_SETTING_REMOTE_USER : 'Username',
30 | PROJECT_SETTING_REMOTE_USER_PASSWORD : 'Password',
31 | PROJECT_SETTING_AUTO_SYNC : 'Automatically synchronise file-system changes to server',
32 | PROJECT_SETTING_SERVER_URL_HINT : 'http://localhost:4502',
33 | PROJECT_SETTING_REMOTE_USER_HINT : 'admin',
34 | PROJECT_SYNCHRONISATION_SETTINGS : 'Synchronisation Settings',
35 | PROJECT_SETTING_SERVER_URL_ERROR_MISSING : 'Please provide a server URL.',
36 | PROJECT_SETTING_SERVER_URL_ERROR_INVALID_PROTOCOL: 'Invalid protocol used for the server URL.',
37 | PROJECT_SETTING_SERVER_URL_ERROR_UNKNOWN : 'Unknown error: server URL.',
38 | PROJECT_SETTING_SERVER_URL_ERROR_INVALID_CHAR : 'Special characters like \'{0}\' must be %-encoded.',
39 | PROJECT_SETTING_REMOTE_USER_ERROR_EMPTY : 'Please provide a username.',
40 | PROJECT_SETTING_REMOTE_USER_PASSWORD_ERROR_EMPTY : 'Please provide a password.',
41 | PROJECT_SETTING_ACCEPT_SELF_SIGNED_CERTIFICATES : 'Accept self-signed certificates for HTTPS',
42 |
43 | // Synchronisation indicator tooltip
44 | SYNC_FULL : 'All selected files were synced successfully.',
45 | SYNC_PARTIAL : 'Some of the selected files were not synced successfully.',
46 | SYNC_NONE : 'None of the selected files were synced.',
47 | SYNC_IN_PROGRESS : 'Your selected files are synchronising.',
48 |
49 | // Synchronisation report dialogue
50 | SYNC_STATUS : 'Synchronisation Status',
51 | SYNC_STATUS_TH_FILE : 'Entry',
52 | SYNC_STATUS_TH_STATUS : 'Synchronisation Status',
53 | SYNC_STATUS_TH_TIME : 'Time',
54 | SYNC_STATUS_IMPORTED : 'imported',
55 | SYNC_STATUS_EXPORTED : 'exported',
56 | SYNC_STATUS_IGNORED : 'ignored by the filter configuration',
57 | SYNC_STATUS_EXCLUDED : 'excluded by the filter configuration',
58 | SYNC_STATUS_EXCLUDED_VLT : 'vlt file or file excluded by .vltignore pattern',
59 | SYNC_STATUS_DELETED_FROM_REMOTE : 'removed - the file was deleted on the server',
60 |
61 | // Synchronization panel
62 | SYNC_PANEL_CLEAR : 'Clear results'
63 |
64 | });
65 |
--------------------------------------------------------------------------------
/sly/nls/ro/strings.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
3 | *
4 | * Licensed under the Apache License 2.0.
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | ******************************************************************************/
7 | /*global define*/
8 | define({
9 | AEM_SLY_EXTENSION : 'AEM Sightly Extension',
10 |
11 | // Button labels
12 | BUTTON_OK : 'OK',
13 | BUTTON_CANCEL : 'Revocare',
14 |
15 | // Menus
16 | // -- top level
17 | MENU_PROJECT_SETTINGS : 'Setările Proiectului...',
18 | MENU_EXPORT_CONTENT_PACKAGE : 'Exportați Content Package-ul pe Server',
19 | MENU_IMPORT_CONTENT_PACKAGE : 'Importați Content Package-ul de pe Server',
20 |
21 | // -- contextual menus
22 | CONTEXTUAL_PULL_REMOTE : 'Importați de pe Server',
23 | CONTEXTUAL_PUSH_REMOTE : 'Exportați pe Server',
24 | CONTEXTUAL_OPEN_REMOTE : 'Deschideți pe Server',
25 |
26 | // Project Settings dialogue
27 | PROJECT_SETTINGS : 'Setările Proiectului',
28 | PROJECT_SETTING_SERVER_URL : 'URL Server',
29 | PROJECT_SETTING_REMOTE_USER : 'Utilizator',
30 | PROJECT_SETTING_REMOTE_USER_PASSWORD : 'Parolă',
31 | PROJECT_SETTING_AUTO_SYNC : 'Sincronizare automată a schimbărilor de pe disc către server',
32 | PROJECT_SETTING_SERVER_URL_HINT : 'http://localhost:4502',
33 | PROJECT_SETTING_REMOTE_USER_HINT : 'admin',
34 | PROJECT_SYNCHRONISATION_SETTINGS : 'Setări de Sincronizare',
35 | PROJECT_SETTING_SERVER_URL_ERROR_MISSING : 'Vă rugăm să introduceți URL-ul serverului.',
36 | PROJECT_SETTING_SERVER_URL_ERROR_INVALID_PROTOCOL: 'URL-ul serverului are un protocol invalid.',
37 | PROJECT_SETTING_SERVER_URL_ERROR_UNKNOWN : 'Eroare necunoscută: URL Server.',
38 | PROJECT_SETTING_SERVER_URL_ERROR_INVALID_CHAR : 'Caracterele speciale precum \'{0}\' trebuie să fie %-codificate.',
39 | PROJECT_SETTING_REMOTE_USER_ERROR_EMPTY : 'Vă rugăm să introduceți utilizatorul.',
40 | PROJECT_SETTING_REMOTE_USER_PASSWORD_ERROR_EMPTY : 'Vă rugăm să introduceți parola.',
41 | PROJECT_SETTING_ACCEPT_SELF_SIGNED_CERTIFICATES : 'Acceptați certificate care nu sunt semnate de CA',
42 |
43 | // Synchronisation indicator tooltip
44 | SYNC_FULL : 'Toate fișierele selectate au fost sincronizate cu succes.',
45 | SYNC_PARTIAL : 'Unele dintre fișierele selectate nu au fost sincronizate cu succes.',
46 | SYNC_NONE : 'Niciunul dintre fișierele selectate nu a fost sincronizat.',
47 | SYNC_IN_PROGRESS : 'Fișierele selectate de dumneavoastră se sincronizează.',
48 |
49 | // Synchronisation report dialogue
50 | SYNC_STATUS : 'Stare Sincronizare',
51 | SYNC_STATUS_TH_FILE : 'Fișier',
52 | SYNC_STATUS_TH_STATUS : 'Stare Sincronizare',
53 | SYNC_STATUS_TH_TIME : 'Timp',
54 | SYNC_STATUS_IMPORTED : 'importat',
55 | SYNC_STATUS_EXPORTED : 'exportat',
56 | SYNC_STATUS_IGNORED : 'ignorat de către configurarea filtrului',
57 | SYNC_STATUS_EXCLUDED : 'exclus de către configurarea filtrului',
58 | SYNC_STATUS_EXCLUDED_VLT : 'fișier vlt sau fișier exclus de către .vltignore',
59 | SYNC_STATUS_DELETED_FROM_REMOTE : 'șters - fișierul a fost șters pe server',
60 |
61 | // Synchronization panel
62 | SYNC_PANEL_CLEAR : 'Șterge rezultate'
63 |
64 | });
65 |
--------------------------------------------------------------------------------
/sly/preferences/project-settings-dialog.html:
--------------------------------------------------------------------------------
1 | {{!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 | ~ Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
3 | ~
4 | ~ Licensed under the Apache License 2.0.
5 | ~ http://www.apache.org/licenses/LICENSE-2.0
6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--}}
7 | jcr_root folder from the opened content-package project.
16 | *
17 | * @returns {promise|String} a promise resolved with the absolute path to the jcr_root folder of the project
18 | */
19 | function getJcrRoot() {
20 | var deferred = $.Deferred();
21 | getFolderContents(ProjectManager.getProjectRoot().fullPath).then(
22 | function (entries) {
23 | for (var i = 0; i < entries.length; i++) {
24 | var entry = entries[i];
25 | if (entry.name === 'jcr_root') {
26 | deferred.resolve(entry.fullPath);
27 | break;
28 | }
29 | }
30 | if (deferred.state() !== 'resolved') {
31 | deferred.reject(new Error('Cannot find a jcr_root folder for this project'));
32 | }
33 | },
34 | function (err) {
35 | deferred.reject(err);
36 | }
37 | ).done();
38 | return deferred;
39 | }
40 |
41 | /**
42 | * Retrieves the absolute path to the filter-vlt.xml or filter.xml file from the opened content-package
43 | * project.
44 | *
45 | * @returns {promise|String} a promise resolved with the absolute path to the filter.xml file; if the file cannot be found
46 | * the returned promise is rejected
47 | */
48 | function getFilterFile() {
49 | var deferred = $.Deferred();
50 | getJcrRoot().then(
51 | function (jcrRoot) {
52 | var filter = jcrRoot + '../META-INF/vault/filter-vlt.xml';
53 | FileSystem.resolve(filter, function (err, entry, stat) {
54 | if (err) {
55 | filter = jcrRoot + '../META-INF/vault/filter.xml';
56 | FileSystem.resolve(filter, function (err, entry, stat) {
57 | if (err) {
58 | deferred.reject(new Error('Cannot find a Vault filter: filter-vlt.xml, filter.xml.'));
59 | return;
60 | }
61 | if (entry.isDirectory) {
62 | deferred.reject(new Error('Entry ' + entry.fullPath + ' resolved to a folder.'));
63 | return;
64 | }
65 | deferred.resolve(entry.fullPath);
66 | });
67 | return;
68 | }
69 | if (entry.isDirectory) {
70 | deferred.reject(new Error('Entry ' + entry.fullPath + ' resolved to a folder.'));
71 | return;
72 | }
73 | deferred.resolve(entry.fullPath);
74 | });
75 | }
76 | ).done();
77 | return deferred;
78 | }
79 |
80 | /**
81 | * Generates the remote path of file from the current opened content-package project.
82 | *
83 | * @param {String} filePath the path to the local file
84 | * @returns {promise|String} a promise resolved with the remote path
85 | */
86 | function getRemotePathForFile(filePath) {
87 | var deferred = $.Deferred();
88 | getJcrRoot().then(
89 | function (root) {
90 | if (filePath.indexOf(root) === 0) {
91 | var remotePath = filePath.substring(root.length - 1);
92 | if (/^.*\.content\.xml$/.test(remotePath)) {
93 | remotePath = remotePath.substring(0, remotePath.lastIndexOf('/'));
94 | }
95 | deferred.resolve(remotePath);
96 | } else {
97 | deferred.reject(new Error('File ' + filePath + ' is outside of jcr_root folder ' + root));
98 | }
99 | }
100 | );
101 | return deferred;
102 | }
103 |
104 | /**
105 | * Gets the content of a folder. If the supplied path is a file the returned array will contain just the FileSystemEntry
106 | * for that path.
107 | *
108 | * @param {String} folder the path to a folder
109 | * @returns {promise|Array.packageFilePath to the AEM instance from serverURL.
25 | * @param {String} serverURL the server's URL (e.g. http://localhost:4502)
26 | * @param {boolean} acceptSelfSigned boolean flag to indicate if self-signed certificates should be acceppted for HTTPs connections
27 | * @param {String} user a user allowed to manage content packages
28 | * @param {String} password the user's password
29 | * @param {String} packageFilePath the path to the content package on the file system
30 | * @returns {promise|Q.promise} a promise
31 | */
32 | function uploadPackage(serverURL, acceptSelfSigned, user, password, packageFilePath) {
33 | var deferred = Q.defer(),
34 | packageStream = Fs.createReadStream(packageFilePath),
35 | uri = serverURL + URL + '?cmd=upload';
36 | var r = Request.post(
37 | uri,
38 | _createRequestOptions(user, password, acceptSelfSigned),
39 | function(err, httpResponse, body) {
40 | if (!_errorDetected(err, httpResponse, serverURL, 200, deferred)) {
41 | try {
42 | var response = JSON.parse(body);
43 | if (response.success === true) {
44 | deferred.resolve();
45 | } else {
46 | deferred.reject(new Error(response.msg));
47 | }
48 | } catch (e) {
49 | deferred.reject(new Error('Error uploading package ' + packageFilePath + ': ' + e));
50 | }
51 | }
52 | }
53 |
54 | );
55 | var form = r.form();
56 | form.append('force', 'true');
57 | form.append('package', packageStream);
58 | return deferred.promise;
59 | }
60 |
61 | /**
62 | * Installs a previously uploaded content package on the AEM instance from serverURL.
63 | * @param {String} serverURL the server's URL (e.g. http://localhost:4502)
64 | * @oaram {boolean} acceptSelfSigned boolean flag to indicate if self-signed certificates should be acceppted for HTTPs connections
65 | * @param {String} user a user allowed to manage content packages
66 | * @param {String} password the user's password
67 | * @param {String} packageName the full content package name (e.g. 'group/name-version.zip')
68 | * @returns {promise|Q.promise} a promise
69 | */
70 | function installPackage(serverURL, acceptSelfSigned, user, password, packageName) {
71 | var deferred = Q.defer(),
72 | uri = serverURL + URL + '/etc/packages/' + packageName + '?cmd=install';
73 | Request.post(
74 | uri,
75 | _createRequestOptions(user, password, acceptSelfSigned),
76 | function (err, httpResponse, body) {
77 | if (!_errorDetected(err, httpResponse, serverURL, 200, deferred)) {
78 | try {
79 | var response = JSON.parse(body);
80 | if (response.success === true) {
81 | deferred.resolve();
82 | } else {
83 | deferred.reject(new Error(response.msg));
84 | }
85 | } catch (e) {
86 | deferred.reject(new Error('Error installing package ' + packageName + ': ' + e));
87 | }
88 | }
89 | }
90 | );
91 | return deferred.promise;
92 | }
93 |
94 | /**
95 | * Builds a previously uploaded content package on the AEM instance from serverURL.
96 | * @param {String} serverURL the server's URL (e.g. http://localhost:4502)
97 | * @oaram {boolean} acceptSelfSigned boolean flag to indicate if self-signed certificates should be acceppted for HTTPs connections
98 | * @param {String} user a user allowed to manage content packages
99 | * @param {String} password the user's password
100 | * @param {String} packageName the full content package name (e.g. 'group/name-version.zip
101 | * @returns {promise|Q.promise} a promise
102 | */
103 | function buildPackage(serverURL, acceptSelfSigned, user, password, packageName) {
104 | var deferred = Q.defer(),
105 | uri = serverURL + URL + '/etc/packages/' + packageName + '?cmd=build';
106 | Request.post(
107 | uri,
108 | _createRequestOptions(user, password, acceptSelfSigned),
109 | function(err, httpResponse, body) {
110 | if (!_errorDetected(err, httpResponse, serverURL, 200, deferred)) {
111 | try {
112 | var response = JSON.parse(body);
113 | if (response.success === true) {
114 | deferred.resolve();
115 | } else {
116 | deferred.reject(new Error(response.msg));
117 | }
118 | } catch (e) {
119 | deferred.reject(new Error('Error building package' + packageName + ': ' + e));
120 | }
121 | }
122 | }
123 | );
124 | return deferred.promise;
125 | }
126 |
127 | /**
128 | * Deletes a previously uploaded content package on the AEM instance from serverURL.
129 | * @param {String} serverURL the server's URL (e.g. http://localhost:4502)
130 | * @oaram {boolean} acceptSelfSigned boolean flag to indicate if self-signed certificates should be acceppted for HTTPs connections
131 | * @param {String} user a user allowed to manage content packages
132 | * @param {String} password the user's password
133 | * @param {String} packageName the full content package name (e.g. 'group/name-version.zip)
134 | * @returns {promise|Q.promise} a promise
135 | */
136 | function deletePackage(serverURL, acceptSelfSigned, user, password, packageName) {
137 | var deferred = Q.defer(),
138 | uri = serverURL + URL + '/etc/packages/' + packageName + '?cmd=delete';
139 | Request.post(
140 | uri,
141 | _createRequestOptions(user, password, acceptSelfSigned),
142 | function(err, httpResponse, body) {
143 | if (!_errorDetected(err, httpResponse, serverURL, 200, deferred)) {
144 | try {
145 | var response = JSON.parse(body);
146 | if (response.success === true) {
147 | deferred.resolve();
148 | } else {
149 | deferred.reject(new Error(response.msg));
150 | }
151 | } catch (e) {
152 | deferred.reject(new Error('Error deleting package ' + packageName + ': ' + e));
153 | }
154 | }
155 | }
156 | );
157 | return deferred.promise;
158 | }
159 |
160 | /**
161 | * Downloads package packageName from the AEM instance available at serverURL to the outputFolder
162 | * folder.
163 | * @param {String} serverURL the server's URL (e.g. http://localhost:4502)
164 | * @oaram {boolean} acceptSelfSigned boolean flag to indicate if self-signed certificates should be acceppted for HTTPs connections
165 | * @param {String} user a user allowed to manage content packages
166 | * @param {String} password the user's password
167 | * @param {String} packageName the full content package name (e.g. 'group/name-version.zip)
168 | * @param {String} outputFolder the folder where the content package will be downloaded
169 | * @param {String} [outputFileName] the file name under which to save the downloaded package
170 | * @returns {promise|Q.promise} a promise
171 | */
172 | function downloadPackage(serverURL, acceptSelfSigned, user, password, packageName, outputFolder, outputFileName) {
173 | var deferred = Q.defer(),
174 | uri = serverURL + '/etc/packages/' + packageName,
175 | mkdirp = Q.denodeify(Fs.mkdirp);
176 | var fileName = outputFileName;
177 | if (!outputFileName) {
178 | fileName = packageName.substring(packageName.lastIndexOf('!'), packageName.length);
179 | }
180 | mkdirp(outputFolder).then(
181 | function() {
182 | var r = Request.get(
183 | uri,
184 | _createRequestOptions(user, password, acceptSelfSigned),
185 | function(err, httpResponse) {
186 | _errorDetected(err, httpResponse, serverURL, 200, deferred);
187 | }
188 | ).pipe(Fs.createWriteStream(outputFolder + Path.sep + fileName));
189 | r.on('finish', function() {
190 | deferred.resolve(outputFolder + Path.sep + fileName);
191 | });
192 | r.on('error', function() {
193 | deferred.reject(new Error('Unable to write remote file ' + uri + ' to ' + outputFolder + Path.sep + fileName));
194 | });
195 | }
196 | );
197 | return deferred.promise;
198 | }
199 |
200 | function _errorDetected(err, httpResponse, serverURL, expectedStatusCode, deferred) {
201 | if (err) {
202 | deferred.reject(new Error('Cannot establish a connection to server ' + serverURL + (err.code ? ': ' + err.code + '.' : '.')));
203 | return true;
204 | } else {
205 | if (httpResponse) {
206 | var statusCode = httpResponse.statusCode;
207 | if (statusCode !== expectedStatusCode) {
208 | switch (statusCode) {
209 | case 401:
210 | deferred.reject(new Error('Invalid user name or password for server ' + serverURL + '.'));
211 | return true;
212 | default:
213 | deferred.reject(new Error('Received status code ' + statusCode + '. Expected ' + expectedStatusCode + '.'));
214 | return true;
215 | }
216 | }
217 | }
218 | }
219 | return false;
220 | }
221 |
222 | function _createRequestOptions(user, password, acceptSelfSigned) {
223 | return {
224 | auth: {
225 | user: user,
226 | pass: password
227 | },
228 | agentOptions: {
229 | rejectUnauthorized: !acceptSelfSigned
230 | }
231 | }
232 | }
233 |
234 | exports.uploadPackage = uploadPackage;
235 | exports.installPackage = installPackage;
236 | exports.buildPackage = buildPackage;
237 | exports.deletePackage = deletePackage;
238 | exports.downloadPackage = downloadPackage;
239 | }());
240 |
--------------------------------------------------------------------------------
/sly/toolbar/brackets_aem_icons.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
143 |
--------------------------------------------------------------------------------
/sly/SightlyCodeHint.js:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
3 | *
4 | * Licensed under the Apache License 2.0.
5 | * http://www.apache.org/licenses/LICENSE-2.0
6 | ******************************************************************************/
7 |
8 | /*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
9 | /*global define, brackets, $ */
10 |
11 | define(function (require, exports, module) {
12 | "use strict";
13 | // Load dependent modules
14 | var AppInit = brackets.getModule("utils/AppInit"),
15 | CodeHintManager = brackets.getModule("editor/CodeHintManager"),
16 | HTMLUtils = brackets.getModule("language/HTMLUtils"),
17 | TokenUtils = brackets.getModule("utils/TokenUtils"),
18 | sightlyLanguage = require("sly/SightlyLanguage"),
19 | beanMgr = require("sly/BeanManager"),
20 | editorManager = brackets.getModule("editor/EditorManager"),
21 | formerDoc,
22 | slyConstants,
23 | processingChange,
24 | attributes;
25 |
26 | /**
27 | * @constructor
28 | */
29 | function SLYHints() {
30 | this.cachedHints = null;
31 | this.exclusion = "";
32 | }
33 |
34 | /**
35 | * Returns the string before current pos, ignoring "." and other potential sightly cars
36 | * 'properti'
37 | * 'properties.'
38 | * 'properties.someth'
39 | * 'data-sly-use.blah'
40 | * start limit is either space, either expression start
41 | */
42 |
43 | function _getCurrentToken(editor) {
44 | var cursor = editor.getCursorPos(),
45 | ctx = TokenUtils.getInitialContext(editor._codeMirror, cursor),
46 | char,
47 | pos,
48 | token = "";
49 | for (pos = cursor.ch - ctx.token.start - 1; slyConstants.TOKEN_START.indexOf(ctx.token.string.charAt(pos)) === -1; pos--) {
50 | token = ctx.token.string.charAt(pos) + token;
51 | }
52 | return token;
53 | }
54 |
55 | /**
56 | * Check whether the exclusion is still the same as text after the cursor.
57 | * If not, reset it to null.
58 | *
59 | * @param {boolean} attrNameOnly
60 | * true to indicate that we update the exclusion only if the cursor is inside an attribute name context.
61 | * Otherwise, we also update exclusion for attribute value context.
62 | */
63 | SLYHints.prototype.updateExclusion = function (attrNameOnly) {
64 | if (this.exclusion && this.tagInfo) {
65 | var tokenType = this.tagInfo.position.tokenType,
66 | offset = this.tagInfo.position.offset,
67 | text = _getCurrentToken(this.editor),
68 | textAfterCursor;
69 |
70 | if (tokenType === HTMLUtils.ATTR_NAME) {
71 | textAfterCursor = this.tagInfo.attr.name.substr(offset);
72 | } else if (!attrNameOnly && tokenType === HTMLUtils.ATTR_VALUE) {
73 | textAfterCursor = this.tagInfo.attr.value.substr(offset);
74 | }
75 | if (!CodeHintManager.hasValidExclusion(this.exclusion, textAfterCursor)) {
76 | this.exclusion = null;
77 | }
78 | }
79 | };
80 |
81 | /**
82 | * evaluates wether current position of cursor is within an sly expression
83 | */
84 | function _isInExpression(editor, tagInfo) {
85 | var cursor = editor.getCursorPos(),
86 | tokenType = tagInfo.position.tokenType,
87 | ctx,
88 | pos,
89 | start,
90 | end;
91 | if (tokenType === HTMLUtils.ATTR_VALUE) {
92 | return true;
93 | } else if (tokenType === "") {
94 | //@TODO: better handling, as some cases won't pass here
95 | //(like 2 expressions in the same token, and cursor being in the second)
96 | ctx = TokenUtils.getInitialContext(editor._codeMirror, cursor);
97 | start = ctx.token.string.indexOf(slyConstants.EXPR_START);
98 | if (start > -1) {
99 | pos = TokenUtils.offsetInToken(ctx);
100 | end = ctx.token.string.indexOf(slyConstants.EXPR_END);
101 | return pos > start && pos <= end;
102 | }
103 | }
104 | return false;
105 | }
106 |
107 | /**
108 | * insert a variable name corresponding to chosen declaration (passed as completion)
109 | * data-sly-use="com.blah.Blah" -> data-sly-use.blah="com.blah.Blah"
110 | * returns updated cursor position
111 | */
112 | function _insertVariableDeclaration(editor, completion) {
113 | var attributeToken = _getCurrentAttributeToken(editor),
114 | text = _getCurrentToken(editor),
115 | varName = completion.substring(completion.lastIndexOf(".")).toLowerCase(),
116 | newAttr = attributeToken.string + varName,
117 | cursor = editor.getCursorPos(),
118 | start = {line: cursor.line, ch: attributeToken.start},
119 | end = {line: cursor.line, ch: attributeToken.end},
120 | newPosition = cursor.ch + varName.length;
121 | editor.document.replaceRange(newAttr, start, end);
122 | cursor.ch = newPosition;
123 | editor.setCursorPos(cursor.line, newPosition);
124 | return cursor;
125 | }
126 |
127 | /**
128 | * this function is to be called once cursor is after the '=' in attribute position
129 | */
130 | function _completeAttributeValue(editor, pos) {
131 | var tagInfo = HTMLUtils.getTagInfo(editor, pos),
132 | a = tagInfo.attr;
133 | if (a && a.name && a.value === "") {
134 | //true only if we are in the attribute=| case
135 | var name = sightlyLanguage.extractAttributeNameInfo(a.name).name;
136 | if (attributes && attributes[name]) {
137 | var completion = slyConstants.COMPLETION[attributes[name].type];
138 | if (completion) {
139 | var completions = completion.split(slyConstants.COMPLETION_CURSOR_POS),
140 | finalText = completions[0] + completions[1],
141 | newPos = {line: pos.line, ch: pos.ch + completions[0].length};
142 | editor.document.replaceRange(finalText, pos);
143 | editor.setCursorPos(newPos);
144 | }
145 | }
146 | }
147 | }
148 |
149 |
150 | /* change event for = typing as hint manager doesn't care about them */
151 | function _onChange(event, doc, changeList) {
152 | if (!processingChange) {
153 | processingChange = true;
154 | $.each(changeList, function (index, change) {
155 | if ((change.removed.length === 1) && (change.text.length === 1) && (change.text[0] === "=")) {
156 | var editor = editorManager.getActiveEditor(),
157 | pos = { line: change.to.line, ch: change.to.ch + 1};
158 | _completeAttributeValue(editor, pos);
159 | }
160 | });
161 | processingChange = false;
162 | }
163 | }
164 |
165 | /** Handles changes to current (sly) document */
166 | function _refreshSlyDoc(event, doc) {
167 | if (!formerDoc || formerDoc !== doc) {
168 | $(doc).on("change", _onChange);
169 | if (formerDoc) {
170 | $(formerDoc).off("change", _onChange);
171 | }
172 | formerDoc = doc;
173 | }
174 | }
175 |
176 | /**
177 | * Determines whether SLY attribute hints are available in the current
178 | * editor context.
179 | *
180 | * @param {Editor} editor
181 | * A non-null editor object for the active window.
182 | *
183 | * @param {string} implicitChar
184 | * Either null, if the hinting request was explicit, or a single character
185 | * that represents the last insertion and that indicates an implicit
186 | * hinting request.
187 | *
188 | * @return {boolean}
189 | * Determines whether the current provider is able to provide hints for
190 | * the given editor context and, in case implicitChar is non-null,
191 | * whether it is appropriate to do so.
192 | */
193 | SLYHints.prototype.hasHints = function (editor, implicitChar) {
194 | var pos = editor.getCursorPos(),
195 | tokenType,
196 | sly = false;
197 |
198 | this.editor = editor;
199 | this.tagInfo = HTMLUtils.getTagInfo(editor, pos);
200 | tokenType = this.tagInfo.position.tokenType;
201 | if (tokenType === HTMLUtils.ATTR_NAME) {
202 | var name = this.tagInfo.attr.name;
203 | if (name === slyConstants.SHORTCUT) {
204 | var start = {ch: pos.ch - slyConstants.SHORTCUT.length, line: pos.line};
205 | this.editor.document.replaceRange(slyConstants.PREFIX, start, pos);
206 | this.editor.setCursorPos(start.line, pos.ch + slyConstants.PREFIX.length - slyConstants.SHORTCUT.length);
207 | return true;
208 | } else {
209 | return (name.indexOf(slyConstants.PREFIX) === 0);
210 | }
211 | } else if (_isInExpression(editor, this.tagInfo)) {
212 | return true;
213 | }
214 | return false;
215 | };
216 |
217 | /**
218 | * Returns a list of availble HTML attribute hints if possible for the
219 | * current editor context.
220 | *
221 | * @return {{hints: Array.