Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functions #135

Merged
merged 2 commits into from
Mar 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 35 additions & 19 deletions web/sheet/engine/SheetRemoteEngine.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,43 @@
'use strict';

var oo = require('substance/util/oo');
var RemoteEngine = require('../../RemoteEngine');

function SheetRemoteEngine() {
SheetRemoteEngine.super.apply(this, arguments);

window._engine = this;
}

SheetRemoteEngine.Prototype = function() {

/**
* A list of function names currently available in the
* the sheet's context
*/
this._functionList = null;
Gets the list of available functions.
*/
this.getFunctionList = function() {
return this._functionList;
};

/**
A list of function names currently available in the
the sheet's context

TODO: remove hard-coded entries once updateFunction list
strategy is in place.
*/
this._functionList = ['sum', 'mean'];

/**
* A dictionary of functions definitions used as
* a cache
*/
this._functionSpecs = {}
A dictionary of functions definitions used as
a cache
*/
this._functionSpecs = {};

/**
* Get a list of function names
*/
this.functions = function(cb) {
Updates the cache of available functions

TODO: this should be run on app start and when new packages are
imported that expose more functions.
*/
this.updateFunctionList = function(cb) {
if(this._functionList) {
cb(this._functionList);
} else {
Expand All @@ -38,19 +49,24 @@ SheetRemoteEngine.Prototype = function() {
};

/**
* Get a function definition
*/
Get a function definition
*/
this.function = function(name, cb) {
if(this._functionSpecs[name]){
return this._functionSpecs[name];
var cachedFunction = this._functionSpecs[name];
if (cachedFunction) {
cb(null, cachedFunction);
} else {
this._request('PUT', 'function', {name:name}, function(err, result) {
if (err) return cb(err);
this._functionSpecs[name] = result;
cb(result);
cb(null, result);
}.bind(this));
}
};


/*
Updates given cells
*/
this.update = function(cells, cb) {
this._request('PUT', 'update', cells, function(err, result) {
if (err) return cb(err);
Expand Down
28 changes: 14 additions & 14 deletions web/sheet/sheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,17 @@ window.Stencila = {};
window.isEditable = true;

function launch() {
Raven
.config(
'https://6329017160394100b21be92165555d72@app.getsentry.com/37250',{
ignoreUrls: [
// Ignore errors generated during development or on local sessions
/localhost/,
/127\.0\.0\.1/,
]
})
.install();
try {
// Raven
// .config(
// 'https://6329017160394100b21be92165555d72@app.getsentry.com/37250',{
// ignoreUrls: [
// // Ignore errors generated during development or on local sessions
// /localhost/,
// /127\.0\.0\.1/,
// ]
// })
// .install();
// try {
var doc = loadDocument();
if (window.isEditable) {
renderStaticReadonlyVersion(doc);
Expand All @@ -80,9 +80,9 @@ function launch() {
} else {
renderInteractiveVersion(doc, 'read');
}
} catch(e) {
Raven.captureException(e)
}
// } catch(e) {
// Raven.captureException(e)
// }
}

window.activate = function() {
Expand Down
1 change: 1 addition & 0 deletions web/sheet/sheet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ $default-cell-padding: 1px 3px;
@import './styles/_primitive-expression';
@import './styles/_image-expression';
@import './styles/_function';
@import './styles/_select-function';
@import './styles/_cell-teaser';
@import './styles/_save-tool';
@import './styles/_sheet-editor';
Expand Down
10 changes: 10 additions & 0 deletions web/sheet/styles/_select-function.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.sc-select-function {
position: absolute;
min-width: 300px;
z-index: 2;
background: #FFFFFF;
top: 30px;
font-size: 12px;
box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.50);
text-align: left;
}
12 changes: 6 additions & 6 deletions web/sheet/testFunction.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
var testSnippet = {
var testFunction = {
"name": "sum",
"summary": "Returns the sum of values.",
"title": "Returns the sum of values.",
"notes": [
"If only a single number for `values` is supplied, `sum` returns `values`"
],
"parameters": [
{
"name": "value1",
"descr": "The first number or range to sum up."
"description": "The first number or range to sum up."
},
{
"shape": ["one", "block"],
"name": "value2",
"descr": "Additional numbers or ranges to add to value1",
"description": "Additional numbers or ranges to add to value1",
"variadic": true,
"optional": true
}
Expand All @@ -31,7 +31,7 @@ var testSnippet = {
"r",
"py"
]
}
};


module.exports = testSnippet;
module.exports = testFunction;
71 changes: 55 additions & 16 deletions web/sheet/ui/CellEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
var Component = require('substance/ui/Component');
var $$ = Component.$$;
var FunctionComponent = require('./FunctionComponent');
var SelectFunction = require('./SelectFunction');

/*
The CellEditor is different to a regular TextPropertyEditor
Expand All @@ -26,13 +27,16 @@ CellEditor.Prototype = function() {
.on('input', this.onChange)
.ref('editor')
);
if (this.state.func) {
window._engine.function(this.state.func, function(func){
el.append($$(FunctionComponent, {
func: func,
paramIndex: this.state.paramIndex
}));
}.bind(this));
if (this.state.funcName) {
el.append($$(FunctionComponent, {
funcName: this.state.funcName,
paramIndex: this.state.paramIndex
}).ref('function')); // ref is needed so the component is not wiped on each keystroke
} else if (this.state.suggestedFunctions) {
// Render function name suggestor
el.append($$(SelectFunction, {
entries: this.state.suggestedFunctions
}).ref('selectFunction'));
}
return el;
};
Expand Down Expand Up @@ -94,39 +98,74 @@ CellEditor.Prototype = function() {
this._detectFunction();
};

/*
Iterates over available function names and matches the current input string

var _FUNCTIONS = ['sum', 'mean'];
var _FUNCTION_RE_STR = '\\b(' + _FUNCTIONS.join('|') + ')[(]';
TODO: @nokome: the _matcher needs to be improved! Also you may want to
limit the number of suggested function names
*/
this._matchFunctionNames = function(str) {
if (!str) return []; // don't match anything for an empty string
var _matcher = new RegExp('\^'+str, 'gi');

var matches = [];
var funcs = this._getAvailableFunctions();

funcs.forEach(function(funcName) {
if (_matcher.exec('='+funcName)) {
matches.push(funcName);
}
});
return matches;
};

this._getAvailableFunctions = function() {
var engine = this.context.engine;
return engine.getFunctionList();
};

this._detectFunction = function() {
var _availableFuncs = this._getAvailableFunctions();
var _function_re_str = '\\b(' + _availableFuncs.join('|') + ')[(]';

setTimeout(function() {
var el = this._getTextArea();
var source = el.value;
var pos = el.selectionStart;
// only if collapsed
if (pos === el.selectionEnd) {
source = source.slice(0, pos);
var re = new RegExp(_FUNCTION_RE_STR, 'gi');
var re = new RegExp(_function_re_str, 'gi');
var lastMatch, match;
while ( (match = re.exec(source)) ) {
lastMatch = match;
}

if (lastMatch) {
// console.log('DETECTED FUNCTION', lastMatch[1], lastMatch);
var func = lastMatch[1];
var funcName = lastMatch[1];
var startPos = lastMatch.index+1;
var argsPos = startPos + lastMatch[0].length;
var currentArg = this._detectCurrentArg(source.slice(argsPos));
var newState = {
func: func,
funcName: funcName,
paramIndex: currentArg.argIdx
};
// console.log('DETECTED FUNCTION', newState);
this.setState(newState);
} else if (this.state.func) {
this.extendState({
func: false
});
} else {
// Check if any available function name matches partly so we can suggest it
var suggestedFunctions = this._matchFunctionNames(source);

if (suggestedFunctions.length > 0) {
this.setState({
suggestedFunctions: suggestedFunctions
});
} else {
this.setState({
funcName: false
});
}
}
}
}.bind(this));
Expand Down