Skip to content

Commit

Permalink
Callback API (#456)
Browse files Browse the repository at this point in the history
* Trim whitespace

* Callback for `locateFile` function and throw error if file not exists

* Add callback for create path & save
  • Loading branch information
mrmlnc authored and sergeche committed Jul 5, 2016
1 parent afafbd2 commit 65c2de6
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 78 deletions.
88 changes: 50 additions & 38 deletions lib/action/base64.js
Expand Up @@ -13,7 +13,7 @@ define(function(require, exports, module) {
var base64 = require('../utils/base64');
var actionUtils = require('../utils/action');
var editorUtils = require('../utils/editor');

/**
* Test if <code>text</code> starts with <code>token</code> at <code>pos</code>
* position. If <code>pos</code> is omitted, search from beginning of text
Expand All @@ -27,7 +27,7 @@ define(function(require, exports, module) {
pos = pos || 0;
return text.charAt(pos) == token.charAt(0) && text.substr(pos, token.length) == token;
}

/**
* Encodes image to base64
*
Expand All @@ -39,55 +39,67 @@ define(function(require, exports, module) {
function encodeToBase64(editor, imgPath, pos) {
var editorFile = editor.getFilePath();
var defaultMimeType = 'application/octet-stream';

if (editorFile === null) {
throw "You should save your file before using this action";
}

// locate real image path
var realImgPath = file.locateFile(editorFile, imgPath);
if (realImgPath === null) {
throw "Can't find " + imgPath + ' file';
}

file.read(realImgPath, function(err, content) {
if (err) {
throw 'Unable to read ' + realImgPath + ': ' + err;
}

var b64 = base64.encode(String(content));
if (!b64) {
throw "Can't encode file content to base64";
file.locateFile(editorFile, imgPath, function(realImgPath) {
if (realImgPath === null) {
throw "Can't find " + imgPath + ' file';
}

b64 = 'data:' + (actionUtils.mimeTypes[String(file.getExt(realImgPath))] || defaultMimeType) +
';base64,' + b64;

editor.replaceContent('$0' + b64, pos, pos + imgPath.length);

file.read(realImgPath, function(err, content) {
if (err) {
throw 'Unable to read ' + realImgPath + ': ' + err;
}

var b64 = base64.encode(String(content));
if (!b64) {
throw "Can't encode file content to base64";
}

b64 = 'data:' + (actionUtils.mimeTypes[String(file.getExt(realImgPath))] || defaultMimeType) +
';base64,' + b64;

editor.replaceContent('$0' + b64, pos, pos + imgPath.length);
});
});

return true;
}

/**
* Decodes base64 string back to file.
* @param {IEmmetEditor} editor
* @param {String} filePath to new image
* @param {String} data Base64-encoded file content
* @param {Number} pos Caret position where image is located in the editor
*/
function decodeFromBase64(editor, data, pos) {
function decodeFromBase64(editor, filePath, data, pos) {
// ask user to enter path to file
var filePath = String(editor.prompt('Enter path to file (absolute or relative)'));
if (!filePath)
filePath = filePath || String(editor.prompt('Enter path to file (absolute or relative)'));
if (!filePath) {
return false;

var absPath = file.createPath(editor.getFilePath(), filePath);
if (!absPath) {
throw "Can't save file";
}

file.save(absPath, base64.decode( data.replace(/^data\:.+?;.+?,/, '') ));
editor.replaceContent('$0' + filePath, pos, pos + data.length);

var editorFile = editor.getFilePath();
file.createPath(editorFile, filePath, function(err, absPath) {
if (err || !absPath) {
throw "Can't save file";
}

var content = data.replace(/^data\:.+?;.+?,/, '');
file.save(absPath, base64.decode(content), function(err) {
if (err) {
throw 'Unable to save ' + absPath + ': ' + err;
}

editor.replaceContent('$0' + filePath, pos, pos + data.length);
});
});

return true;
}

Expand All @@ -99,11 +111,11 @@ define(function(require, exports, module) {
* @param {String} profile Output profile name
* @return {Boolean}
*/
encodeDecodeDataUrlAction: function(editor) {
encodeDecodeDataUrlAction: function(editor, filepath) {
var data = String(editor.getSelection());
var caretPos = editor.getCaretPos();
var info = editorUtils.outputInfo(editor);

if (!data) {
// no selection, try to find image bounds from current caret position
var text = info.content, m;
Expand All @@ -123,15 +135,15 @@ define(function(require, exports, module) {
}
}
}

if (data) {
if (startsWith('data:', data)) {
return decodeFromBase64(editor, data, caretPos);
return decodeFromBase64(editor, filepath, data, caretPos);
} else {
return encodeToBase64(editor, data, caretPos);
}
}

return false;
}
};
Expand Down
42 changes: 22 additions & 20 deletions lib/action/updateImageSize.js
Expand Up @@ -23,7 +23,7 @@ define(function(require, exports, module) {
*/
function updateImageSizeHTML(editor) {
var offset = editor.getCaretPos();

// find tag from current caret position
var info = editorUtils.outputInfo(editor);
var xmlElem = xmlEditTree.parseFromPosition(info.content, offset, true);
Expand All @@ -33,7 +33,7 @@ define(function(require, exports, module) {
var compoundData = xmlElem.range(true);
xmlElem.value('width', size.width);
xmlElem.value('height', size.height, xmlElem.indexOf('width') + 1);

actionUtils.compoundUpdate(editor, utils.extend(compoundData, {
data: xmlElem.toString(),
caret: offset
Expand All @@ -42,14 +42,14 @@ define(function(require, exports, module) {
});
}
}

/**
* Updates image size of CSS property
* @param {IEmmetEditor} editor
*/
function updateImageSizeCSS(editor) {
var offset = editor.getCaretPos();

// find tag from current caret position
var info = editorUtils.outputInfo(editor);
var cssRule = cssEditTree.parseFromPosition(info.content, offset, true);
Expand All @@ -62,7 +62,7 @@ define(function(require, exports, module) {
var compoundData = cssRule.range(true);
cssRule.value('width', size.width + 'px');
cssRule.value('height', size.height + 'px', cssRule.indexOf('width') + 1);

actionUtils.compoundUpdate(editor, utils.extend(compoundData, {
data: cssRule.toString(),
caret: offset
Expand All @@ -72,7 +72,7 @@ define(function(require, exports, module) {
}
}
}

/**
* Returns image dimensions for source
* @param {IEmmetEditor} editor
Expand All @@ -86,23 +86,25 @@ define(function(require, exports, module) {
fileContent = base64.decode( src.replace(/^data\:.+?;.+?,/, '') );
return callback(actionUtils.getImageSize(fileContent));
}

var absPath = file.locateFile(editor.getFilePath(), src);
if (absPath === null) {
throw "Can't find " + src + ' file';
}

file.read(absPath, function(err, content) {
if (err) {
throw 'Unable to read ' + absPath + ': ' + err;

var filePath = editor.getFilePath();
file.locateFile(filePath, src, function(absPath) {
if (absPath === null) {
throw "Can't find " + src + ' file';
}

content = String(content);
callback(actionUtils.getImageSize(content));

file.read(absPath, function(err, content) {
if (err) {
throw 'Unable to read ' + absPath + ': ' + err;
}

content = String(content);
callback(actionUtils.getImageSize(content));
});
});
}
}

return {
updateImageSizeAction: function(editor) {
// this action will definitely won’t work in SASS dialect,
Expand All @@ -112,7 +114,7 @@ define(function(require, exports, module) {
} else {
updateImageSizeHTML(editor);
}

return true;
}
};
Expand Down
39 changes: 24 additions & 15 deletions lib/plugin/file.js
Expand Up @@ -31,7 +31,7 @@ define(function(require, exports, module) {
path = r('path');
_transport.http = r('http');
_transport.https = r('https');
} catch(e) {}
} catch(e) { }
}
})(require);

Expand Down Expand Up @@ -156,21 +156,22 @@ define(function(require, exports, module) {
* @param {String} fileName
* @return {String} Returns null if <code>fileName</code> cannot be located
*/
locateFile: function(editorFile, fileName) {
locateFile: function(editorFile, fileName, callback) {
if (isURL(fileName)) {
return fileName;
return callback(fileName);
}

var dirname = editorFile, f;
var dirname = editorFile
var filepath;
fileName = fileName.replace(/^\/+/, '');
while (dirname && dirname !== path.dirname(dirname)) {
dirname = path.dirname(dirname);
f = path.join(dirname, fileName);
if (fs.existsSync(f))
return f;
filepath = path.join(dirname, fileName);
if (fs.existsSync(filepath))
return callback(filepath);
}

return '';
callback(null);
},

/**
Expand All @@ -181,21 +182,29 @@ define(function(require, exports, module) {
* @return {String}
*/
createPath: function(parent, fileName, callback) {
var stat = fs.statSync(parent);
if (stat && !stat.isDirectory()) {
parent = path.dirname(parent);
}
fs.stat(parent, function(err, stat) {
if (err) {
return callback(err);
}

if (stat.isFile()) {
parent = path.dirname(parent);
}

return callback(path.resolve(parent, fileName));
var filepath = path.resolve(parent, fileName);
callback(null, filepath);
});
},

/**
* Saves <code>content</code> as <code>file</code>
* @param {String} file File's absolute path
* @param {String} content File content
*/
save: function(file, content) {
fs.writeFileSync(file, content, 'ascii');
save: function(file, content, callback) {
fs.writeFile(file, content, 'ascii', function(err) {
callback(err ? err : null);
});
},

/**
Expand Down
10 changes: 10 additions & 0 deletions test/actions/base64.js
Expand Up @@ -10,4 +10,14 @@ describe('Base64 encoder/decoder', function() {
action.encodeDecodeDataUrlAction(editor);
assert.equal(editor.getContent(), '<img src="data:image/gif;base64,R0lGODdhAQABAIAAAAAAAAAAACH5BAEAAAEALAAAAAABAAEAAAICTAEAOw==" />');
});

it('should return an error if the file does not exist', function() {
editor.replaceContent('<img src="${0}error.gif" />');

try {
action.encodeDecodeDataUrlAction(editor);
} catch (err) {
assert.equal(err, 'Can\'t find error.gif file');
}
});
});
18 changes: 13 additions & 5 deletions test/actions/updateImageSize.js
Expand Up @@ -14,31 +14,39 @@ describe('Update Image Size action', function() {
// insert attributes
run('<img${0} src="data:image/gif;base64,R0lGODlhAwACAHAAACH5BAUAAAAALAAAAAADAAIAQAIChF8AOw==" alt="" />');
assert.equal(editor.getContent(), '<img src="data:image/gif;base64,R0lGODlhAwACAHAAACH5BAUAAAAALAAAAAADAAIAQAIChF8AOw==" alt="" width="3" height="2" />');

// update existing attributes
run('<img${0} src="data:image/gif;base64,R0lGODlhAwACAHAAACH5BAUAAAAALAAAAAADAAIAQAIChF8AOw==" width="100" height="100" alt="" />');
assert.equal(editor.getContent(), '<img src="data:image/gif;base64,R0lGODlhAwACAHAAACH5BAUAAAAALAAAAAADAAIAQAIChF8AOw==" width="3" height="2" alt="" />');

// update existing attribute and insert new one
run('<img${0} src="data:image/gif;base64,R0lGODlhAwACAHAAACH5BAUAAAAALAAAAAADAAIAQAIChF8AOw==" width="100" alt="" />');
assert.equal(editor.getContent(), '<img src="data:image/gif;base64,R0lGODlhAwACAHAAACH5BAUAAAAALAAAAAADAAIAQAIChF8AOw==" width="3" height="2" alt="" />');
});

it('should work for CSS', function() {
editor.setSyntax('css');

// Added "width" and "height" properties
run('.test {\n\tbackgrou${0}nd: url(data:image/gif;base64,R0lGODlhAwACAHAAACH5BAUAAAAALAAAAAADAAIAQAIChF8AOw==);\n}');
assert.equal(editor.getContent(), '.test {\n\tbackground: url(data:image/gif;base64,R0lGODlhAwACAHAAACH5BAUAAAAALAAAAAADAAIAQAIChF8AOw==);\n\twidth: 3px;\n\theight: 2px;\n}');

// Updated "width" and "height" properties
run('.test {\n\tbackgrou${0}nd: url(data:image/gif;base64,R0lGODlhAwACAHAAACH5BAUAAAAALAAAAAADAAIAQAIChF8AOw==);\n\twidth: 100px;\n\theight: 100px;\n}');
assert.equal(editor.getContent(), '.test {\n\tbackground: url(data:image/gif;base64,R0lGODlhAwACAHAAACH5BAUAAAAALAAAAAADAAIAQAIChF8AOw==);\n\twidth: 3px;\n\theight: 2px;\n}');

// Updated "width" property and added "height"
run('.test {\n\tbackgrou${0}nd: url(data:image/gif;base64,R0lGODlhAwACAHAAACH5BAUAAAAALAAAAAADAAIAQAIChF8AOw==);\n\twidth: 100px;\n}');
assert.equal(editor.getContent(), '.test {\n\tbackground: url(data:image/gif;base64,R0lGODlhAwACAHAAACH5BAUAAAAALAAAAAADAAIAQAIChF8AOw==);\n\twidth: 3px;\n\theight: 2px;\n}');

editor.setSyntax('html');
});

it('should return an error if the file does not exist', function() {
try {
run('<img src="${0}error.gif" />');
} catch (err) {
assert.equal(err, 'Can\'t find error.gif file');
}
});
});

0 comments on commit 65c2de6

Please sign in to comment.