Permalink
Browse files

Implemented interactive “Wrap With Abbreviation” and “Update Tag” act…

…ions
  • Loading branch information...
1 parent e2b2728 commit dc6f55da3336937ae8f6b543bb436f04c56931f2 @sergeche sergeche committed May 1, 2014
Showing with 213 additions and 22 deletions.
  1. +2 −0 .gitignore
  2. +23 −0 brackets-emmet.sublime-project
  3. +1 −0 editor.js
  4. +0 −14 emmet.js
  5. +175 −0 interactive.js
  6. +9 −5 main.js
  7. +3 −3 prompt.js
View
@@ -1 +1,3 @@
/node_modules/
+
+/brackets-emmet.sublime-workspace
@@ -0,0 +1,23 @@
+{
+ "folders":
+ [
+ {
+ "folder_exclude_patterns":
+ [
+ "node_modules"
+ ],
+ "follow_symlinks": true,
+ "path": "."
+ }
+ ],
+ "ternjs": {
+ "exclude": ["node_modules/**"],
+ "libs": ["browser"],
+ "plugins": {
+ "requirejs": {
+ "baseURL": "./"
+ }
+ }
+
+ }
+}
View
@@ -156,6 +156,7 @@ define(function(require, exports, module) {
this.editor.document.replaceRange(value, this._posFromIndex(start), this._posFromIndex(end));
this.createSelection(firstTabStop.start, firstTabStop.end);
+ return value;
},
getSyntax: function() {
View
Oops, something went wrong.
View
@@ -0,0 +1,175 @@
+/**
+ * Definition of interactive functions: the function
+ * that require additional dialog prompt and update
+ * editor content when user types data in prompt
+ */
+define(function(require, exports, module) {
+ var utils = require('emmet/utils/common');
+ var editorUtils = require('emmet/utils/editor');
+ var actionUtils = require('emmet/utils/action');
+
+ var range = require('emmet/assets/range');
+ var htmlMatcher = require('emmet/assets/htmlMatcher');
+ var parser = require('emmet/parser/abbreviation');
+ var updateTag = require('emmet/action/updateTag');
+
+ var prompt = require('./prompt');
+
+ /**
+ * Caches wrapping context for current selection in editor
+ * @param {IEmmetEditor} editor
+ * @param {Object} info Current editor info (content, syntax, etc.)
+ * @return {Object}
+ */
+ function selectionContext(editor, info) {
+ info = info || editorUtils.outputInfo(editor);
+ return editor.selectionList().map(function(sel, i) {
+ editor.selectionIndex = i;
+
+ var r = range(editor.getSelectionRange());
+ var tag = htmlMatcher.tag(info.content, r.start);
+ if (!r.length() && tag) {
+ // no selection, use tag pair
+ r = utils.narrowToNonSpace(info.content, tag.range);
+ }
+
+ var out = {
+ selection: r,
+ tag: tag,
+ caret: r.start,
+ syntax: info.syntax,
+ profile: info.profile || null,
+ counter: editor.selectionIndex + 1,
+ contextNode: actionUtils.captureContext(editor, r.start)
+ };
+
+ if (r.length()) {
+ out.pastedContent = utils.escapeText(r.substring(info.content));
+ }
+
+ return out;
+ });
+ }
+
+ function updateCarets(selCtx, fromIndex, delta) {
+ for (var i = fromIndex + 1, il = selCtx.length; i < il; i++) {
+ selCtx[i].caret += delta;
+ }
+ }
+
+ function resetCarets(selCtx) {
+ selCtx.forEach(function(ctx) {
+ ctx.caret = ctx.selection.start;
+ });
+ }
+
+ function restore(editor, selCtx) {
+ if (selCtx) {
+ for (var i = selCtx.length - 1; i >= 0; i--) {
+ editor.selectionIndex = i;
+ editor.setCaretPos(selCtx[i].caret);
+ }
+ }
+ editor.editor.focus();
+ }
+
+ return {
+ wrapWithAbbreviation: function(editor) {
+ // first we have to cache context for each selection
+ var selCtx = selectionContext(editor);
+
+ // show prompt dialog that will wrap each selection
+ // on user typing
+ prompt.show({
+ label: 'Enter Abbreviation',
+ editor: editor.editor,
+ update: function(abbr) {
+ var result, replaced;
+ resetCarets(selCtx);
+ for (var i = selCtx.length - 1, ctx; i >= 0; i--) {
+ ctx = selCtx[i];
+ result = '';
+ try {
+ result = parser.expand(abbr, ctx);
+ } catch (e) {
+ console.error(e);
+ }
+
+ editor.selectionIndex = i;
+ replaced = editor.replaceContent(result, ctx.selection.start, ctx.selection.end);
+ ctx.caret = editor.getCaretPos();
+ updateCarets(selCtx, i, replaced.length - ctx.selection.length());
+ }
+ },
+ confirm: function() {
+ restore(editor, selCtx);
+ },
+ cancel: function() {
+ restore(editor, selCtx);
+ }
+ });
+ },
+
+ updateTag: function(editor) {
+ var info = editorUtils.outputInfo(editor);
+ var selCtx = selectionContext(editor, info);
+
+ // show prompt dialog that will update each
+ // tag from selection
+ prompt.show({
+ label: 'Enter Abbreviation',
+ editor: editor.editor,
+ update: function(abbr) {
+ resetCarets(selCtx);
+ var tag, replaced, delta;
+ for (var i = selCtx.length - 1, ctx; i >= 0; i--) {
+ ctx = selCtx[i];
+ tag = null;
+
+ try {
+ tag = updateTag.getUpdatedTag(abbr, {match: ctx.tag}, info.content, {
+ counter: ctx.counter
+ });
+ } catch (e) {
+ console.error(e);
+ }
+
+ if (!tag) {
+ continue;
+ }
+
+ replaced = [{
+ start: ctx.tag.open.range.start,
+ end: ctx.tag.open.range.end,
+ content: tag.source
+ }];
+
+ if (tag.name() != ctx.tag.name && ctx.tag.close) {
+ replaced.unshift({
+ start: ctx.tag.close.range.start,
+ end: ctx.tag.close.range.end,
+ content: '</' + tag.name() + '>'
+ });
+ }
+
+ delta = 0;
+ editor.selectionIndex = i;
+ replaced.forEach(function(data) {
+ editor.replaceContent(data.content, data.start, data.end);
+ ctx.caret = data.start;
+ delta += data.content.length - data.end + data.start;
+ });
+
+ updateCarets(selCtx, i, delta);
+ }
+ },
+ confirm: function() {
+ restore(editor, selCtx);
+ },
+ cancel: function() {
+ restore(editor, selCtx);
+ }
+ });
+ }
+ };
+});
View
@@ -4,6 +4,7 @@ define(function(require, exports, module) {
var editor = require('./editor');
var path = require('./path');
var prompt = require('./prompt');
+ var interactive = require('./interactive');
var emmet = require('emmet/emmet');
var resources = require('emmet/assets/resources');
@@ -115,7 +116,7 @@ define(function(require, exports, module) {
function loadExtensions(callback) {
var extPath = preferences.getPreference('extPath');
if (extPath) {
- var dir = FileSystem.getDirectoryForPath(extPat);
+ var dir = FileSystem.getDirectoryForPath(extPath);
dir.exists(function(err, exists) {
if (exists) {
emmet.resetUserData();
@@ -124,6 +125,10 @@ define(function(require, exports, module) {
return callback(err);
}
+ files = files.filter(function(entry) {
+ return !entry.isDirectory;
+ });
+
var complete = function() {
emmet.loadExtensions(files);
callback();
@@ -133,7 +138,7 @@ define(function(require, exports, module) {
// if extensions path contains keymap file —
// use it as current Emmet keymap
- files.map(function(file) {
+ files = files.map(function(file) {
if (path.basename(file.fullPath) == 'keymap.json') {
waitForKeymap = true;
file.read({encoding: 'utf8'}, function(content) {
@@ -194,9 +199,8 @@ define(function(require, exports, module) {
// debug panel
CommandManager.register('Show Emmet panel', 'io.emmet.show_panel', function() {
- prompt.show({
- editor: EditorManager.getFocusedEditor()
- });
+ editor.setup(EditorManager.getFocusedEditor());
+ interactive.updateTag(editor);
});
KeyBindingManager.addBinding('io.emmet.show_panel', 'Alt-F1');
View
@@ -74,21 +74,20 @@ define(function(require, exports, module) {
$panel
.on('update.emmet', function(evt, value) {
- console.log('update', value);
updated = true;
delegate.editor.undo();
delegate.editor.document.batchOperation(function() {
update(value);
});
})
.on('confirm.emmet', function(evt, value) {
- console.log('confirm', evt);
+ method(delegate, 'confirm')();
})
.on('cancel.emmet', function(evt) {
- console.log('cancel', evt);
if (updated) {
delegate.editor.undo();
}
+ method(delegate, 'cancel')();
});
input.focus();
@@ -97,6 +96,7 @@ define(function(require, exports, module) {
if (input.val()) {
update(input.val());
+ updated = true;
}
},

0 comments on commit dc6f55d

Please sign in to comment.