mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
feat: Apply frontend interpreter to paragraph
This commit is contained in:
parent
a163044d61
commit
5810bf1de5
10 changed files with 257 additions and 135 deletions
|
|
@ -40,7 +40,7 @@ export default class TranslatorInterpreter extends AbstractFrontendInterpreter {
|
|||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer YOUR_ACCESS_KEY_HERE',
|
||||
'Authorization': 'Bearer YOUR_ACCESS_KEY',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
'q': text,
|
||||
|
|
@ -48,16 +48,16 @@ export default class TranslatorInterpreter extends AbstractFrontendInterpreter {
|
|||
'target': 'ko',
|
||||
'format': 'text'
|
||||
})
|
||||
}).then((response) => {
|
||||
}).then(response => {
|
||||
if (response.status === 200) {
|
||||
return response.json()
|
||||
}
|
||||
throw new Error(`https://translation.googleapis.com/language/translate/v2 ${response.status} (${response.statusText})`);
|
||||
}).then((json) => {
|
||||
const extracted = json.data.translations.map(t => {
|
||||
return t.translatedText;
|
||||
});
|
||||
return extracted.join('\n');
|
||||
const extracted = json.data.translations.map(t => {
|
||||
return t.translatedText;
|
||||
});
|
||||
return extracted.join('\n');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export class AbstractFrontendInterpreter {
|
|||
* Currently, `display` only allows DefaultDisplayType
|
||||
* as a type of result to avoid to recursive evaluation of display results.
|
||||
*
|
||||
* @param paragraphText {string}
|
||||
* @param paragraphText {string} which doesn't include magic
|
||||
* @return {FrontendInterpreterResult}
|
||||
*/
|
||||
display(paragraphText) {
|
||||
|
|
|
|||
|
|
@ -28,12 +28,14 @@ NotebookCtrl.$inject = [
|
|||
'ngToast',
|
||||
'noteActionSrv',
|
||||
'noteVarShareService',
|
||||
'TRASH_FOLDER_ID'
|
||||
'TRASH_FOLDER_ID',
|
||||
'heliumService',
|
||||
];
|
||||
|
||||
function NotebookCtrl($scope, $route, $routeParams, $location, $rootScope,
|
||||
$http, websocketMsgSrv, baseUrlSrv, $timeout, saveAsService,
|
||||
ngToast, noteActionSrv, noteVarShareService, TRASH_FOLDER_ID) {
|
||||
ngToast, noteActionSrv, noteVarShareService, TRASH_FOLDER_ID,
|
||||
heliumService) {
|
||||
|
||||
ngToast.dismiss();
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ limitations under the License.
|
|||
<!-- Run / Cancel button -->
|
||||
<span ng-if="!revisionView">
|
||||
<span class="icon-control-play" style="cursor:pointer;color:#3071A9" tooltip-placement="top" tooltip="Run this paragraph (Shift+Enter)"
|
||||
ng-click="runParagraph(getEditorValue())"
|
||||
ng-click="runParagraphFromButton(getEditorValue())"
|
||||
ng-show="paragraph.status!='RUNNING' && paragraph.status!='PENDING' && paragraph.config.enabled"></span>
|
||||
<span class="icon-control-pause" style="cursor:pointer;color:#CD5C5C" tooltip-placement="top"
|
||||
tooltip="Cancel (Ctrl+{{ (isMac ? 'Option' : 'Alt') }}+c)"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AbstractFrontendInterpreter } from '../../frontend-interpreter'
|
||||
|
||||
angular.module('zeppelinWebApp').controller('ParagraphCtrl', ParagraphCtrl);
|
||||
|
||||
ParagraphCtrl.$inject = [
|
||||
|
|
@ -29,15 +31,19 @@ ParagraphCtrl.$inject = [
|
|||
'baseUrlSrv',
|
||||
'ngToast',
|
||||
'saveAsService',
|
||||
'noteVarShareService'
|
||||
'noteVarShareService',
|
||||
'heliumService'
|
||||
];
|
||||
|
||||
function ParagraphCtrl($scope, $rootScope, $route, $window, $routeParams, $location,
|
||||
$timeout, $compile, $http, $q, websocketMsgSrv,
|
||||
baseUrlSrv, ngToast, saveAsService, noteVarShareService) {
|
||||
baseUrlSrv, ngToast, saveAsService, noteVarShareService,
|
||||
heliumService) {
|
||||
var ANGULAR_FUNCTION_OBJECT_NAME_PREFIX = '_Z_ANGULAR_FUNC_';
|
||||
$scope.parentNote = null;
|
||||
$scope.paragraph = null;
|
||||
$scope.paragraph = {};
|
||||
$scope.paragraph.results = {};
|
||||
$scope.paragraph.results.msg = [];
|
||||
$scope.originalText = '';
|
||||
$scope.editor = null;
|
||||
|
||||
|
|
@ -219,21 +225,30 @@ function ParagraphCtrl($scope, $rootScope, $route, $window, $routeParams, $locat
|
|||
websocketMsgSrv.cancelParagraphRun(paragraph.id);
|
||||
};
|
||||
|
||||
$scope.runParagraph = function(data) {
|
||||
websocketMsgSrv.runParagraph($scope.paragraph.id, $scope.paragraph.title,
|
||||
data, $scope.paragraph.config, $scope.paragraph.settings.params);
|
||||
$scope.originalText = angular.copy(data);
|
||||
$scope.dirtyText = undefined;
|
||||
$scope.runParagraphUsingFrontendInterpreter = function(intp, paragraphText, magic) {
|
||||
// clear results which is watched by `ng-repeat`. without this,
|
||||
// frontend interpreter results cannot be rendered in view twice more
|
||||
$scope.paragraph.results = {};
|
||||
$scope.$digest();
|
||||
|
||||
if ($scope.paragraph.config.editorSetting.editOnDblClick) {
|
||||
closeEditorAndOpenTable($scope.paragraph);
|
||||
} else if (editorSetting.isOutputHidden &&
|
||||
!$scope.paragraph.config.editorSetting.editOnDblClick) {
|
||||
// %md/%angular repl make output to be hidden by default after running
|
||||
// so should open output if repl changed from %md/%angular to another
|
||||
openEditorAndOpenTable($scope.paragraph);
|
||||
try {
|
||||
// remove magic from paragraphText
|
||||
const splited = paragraphText.split(magic);
|
||||
const textWithoutMagic = splited[1];
|
||||
$scope.paragraph.status = 'FINISHED';
|
||||
$scope.paragraph.results.msg = intp.interpret(textWithoutMagic);
|
||||
$scope.paragraph.config.tableHide = false;
|
||||
// TODO(1ambda): broadcast to other clients
|
||||
} catch (error) {
|
||||
$scope.paragraph.status = 'ERROR';
|
||||
$scope.paragraph.errorMessage = error.stack;
|
||||
console.error('Failed to execute FrontendInterpreter.interpret\n', error);
|
||||
}
|
||||
editorSetting.isOutputHidden = $scope.paragraph.config.editorSetting.editOnDblClick;
|
||||
};
|
||||
|
||||
$scope.runParagraphUsingBackendInterpreter = function(paragraphText) {
|
||||
websocketMsgSrv.runParagraph($scope.paragraph.id, $scope.paragraph.title,
|
||||
paragraphText, $scope.paragraph.config, $scope.paragraph.settings.params);
|
||||
};
|
||||
|
||||
$scope.saveParagraph = function(paragraph) {
|
||||
|
|
@ -251,10 +266,43 @@ function ParagraphCtrl($scope, $rootScope, $route, $window, $routeParams, $locat
|
|||
commitParagraph(paragraph);
|
||||
};
|
||||
|
||||
$scope.run = function(paragraph, editorValue) {
|
||||
if (editorValue && !$scope.isRunning(paragraph)) {
|
||||
$scope.runParagraph(editorValue);
|
||||
$scope.runParagraph = function(paragraphText) {
|
||||
if (!paragraphText || $scope.isRunning($scope.paragraph)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const magic = AbstractFrontendInterpreter.extractMagic(paragraphText);
|
||||
const frontendIntp = heliumService.getFrontendInterpreterUsingMagic(magic);
|
||||
|
||||
if (frontendIntp) {
|
||||
$scope.runParagraphUsingFrontendInterpreter(frontendIntp, paragraphText, magic);
|
||||
} else {
|
||||
$scope.runParagraphUsingBackendInterpreter(paragraphText);
|
||||
}
|
||||
|
||||
$scope.originalText = angular.copy(paragraphText);
|
||||
$scope.dirtyText = undefined;
|
||||
|
||||
if ($scope.paragraph.config.editorSetting.editOnDblClick) {
|
||||
closeEditorAndOpenTable($scope.paragraph);
|
||||
} else if (editorSetting.isOutputHidden &&
|
||||
!$scope.paragraph.config.editorSetting.editOnDblClick) {
|
||||
// %md/%angular repl make output to be hidden by default after running
|
||||
// so should open output if repl changed from %md/%angular to another
|
||||
openEditorAndOpenTable($scope.paragraph);
|
||||
}
|
||||
editorSetting.isOutputHidden = $scope.paragraph.config.editorSetting.editOnDblClick;
|
||||
};
|
||||
|
||||
$scope.runParagraphFromShortcut = function(paragraphText) {
|
||||
// we need to call `$digest()` to update view immediately
|
||||
$scope.runParagraph(paragraphText);
|
||||
$scope.$digest();
|
||||
};
|
||||
|
||||
$scope.runParagraphFromButton = function(paragraphText) {
|
||||
// we come here from `$scope.on`, so we don't need to call `$digest()`
|
||||
$scope.runParagraph(paragraphText)
|
||||
};
|
||||
|
||||
$scope.moveUp = function(paragraph) {
|
||||
|
|
@ -452,6 +500,10 @@ function ParagraphCtrl($scope, $rootScope, $route, $window, $routeParams, $locat
|
|||
}
|
||||
};
|
||||
|
||||
// $scope.text = asdasd
|
||||
// dirtyText =
|
||||
|
||||
// originalText
|
||||
$scope.aceChanged = function(_, editor) {
|
||||
var session = editor.getSession();
|
||||
var dirtyText = session.getValue();
|
||||
|
|
@ -807,15 +859,6 @@ function ParagraphCtrl($scope, $rootScope, $route, $window, $routeParams, $locat
|
|||
editor.navigateFileEnd();
|
||||
};
|
||||
|
||||
$scope.getResultType = function(paragraph) {
|
||||
var pdata = (paragraph) ? paragraph : $scope.paragraph;
|
||||
if (pdata.results && pdata.results.type) {
|
||||
return pdata.results.type;
|
||||
} else {
|
||||
return 'TEXT';
|
||||
}
|
||||
};
|
||||
|
||||
$scope.parseTableCell = function(cell) {
|
||||
if (!isNaN(cell)) {
|
||||
if (cell.length === 0 || Number(cell) > Number.MAX_SAFE_INTEGER || Number(cell) < Number.MIN_SAFE_INTEGER) {
|
||||
|
|
@ -1092,7 +1135,7 @@ function ParagraphCtrl($scope, $rootScope, $route, $window, $routeParams, $locat
|
|||
// move focus to next paragraph
|
||||
$scope.$emit('moveFocusToNextParagraph', paragraphId);
|
||||
} else if (keyEvent.shiftKey && keyCode === 13) { // Shift + Enter
|
||||
$scope.run($scope.paragraph, $scope.getEditorValue());
|
||||
$scope.runParagraphFromShortcut($scope.getEditorValue());
|
||||
} else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 67) { // Ctrl + Alt + c
|
||||
$scope.cancelParagraph($scope.paragraph);
|
||||
} else if (keyEvent.ctrlKey && keyEvent.altKey && keyCode === 68) { // Ctrl + Alt + d
|
||||
|
|
|
|||
|
|
@ -58,9 +58,7 @@ limitations under the License.
|
|||
ng-init="init(result, paragraph.config.results[$index], paragraph, $index)"
|
||||
ng-include src="'app/notebook/paragraph/result/result.html'">
|
||||
</div>
|
||||
<div id="{{paragraph.id}}_error"
|
||||
class="error text"
|
||||
ng-if="paragraph.status == 'ERROR'"
|
||||
<div id="{{paragraph.id}}_error" class="error text"
|
||||
ng-bind="paragraph.errorMessage">
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ import PiechartVisualization from '../../../visualization/builtins/visualization
|
|||
import AreachartVisualization from '../../../visualization/builtins/visualization-areachart';
|
||||
import LinechartVisualization from '../../../visualization/builtins/visualization-linechart';
|
||||
import ScatterchartVisualization from '../../../visualization/builtins/visualization-scatterchart';
|
||||
import {
|
||||
DefaultDisplayType,
|
||||
FrontendInterpreterResult,
|
||||
} from '../../../frontend-interpreter'
|
||||
|
||||
angular.module('zeppelinWebApp').controller('ResultCtrl', ResultCtrl);
|
||||
|
||||
|
|
@ -149,14 +153,12 @@ function ResultCtrl($scope, $rootScope, $route, $window, $routeParams, $location
|
|||
|
||||
// image data
|
||||
$scope.imageData;
|
||||
$scope.textRendererInitialized = false;
|
||||
|
||||
$scope.init = function(result, config, paragraph, index) {
|
||||
console.log('result controller init %o %o %o', result, config, index);
|
||||
|
||||
// register helium plugin vis
|
||||
var heliumVis = heliumService.get();
|
||||
console.log('Helium visualizations %o', heliumVis);
|
||||
heliumVis.forEach(function(vis) {
|
||||
var visBundles = heliumService.getVisualizationBundles();
|
||||
visBundles.forEach(function(vis) {
|
||||
$scope.builtInTableDataVisualizationList.push({
|
||||
id: vis.id,
|
||||
name: vis.name,
|
||||
|
|
@ -166,7 +168,7 @@ function ResultCtrl($scope, $rootScope, $route, $window, $routeParams, $location
|
|||
class: vis.class
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
updateData(result, config, paragraph, index);
|
||||
renderResult($scope.type);
|
||||
};
|
||||
|
|
@ -259,92 +261,170 @@ function ResultCtrl($scope, $rootScope, $route, $window, $routeParams, $location
|
|||
}
|
||||
|
||||
if (activeApp) {
|
||||
var app = _.find($scope.apps, {id: activeApp});
|
||||
renderApp(app);
|
||||
const app = _.find($scope.apps, {id: activeApp});
|
||||
renderApp(app, `p${appState.id}`);
|
||||
} else {
|
||||
if (type === 'TABLE') {
|
||||
|
||||
/**
|
||||
* find proper interpreter which can handle the non-default display type
|
||||
* the displayed type which is generated from `display()`
|
||||
* should be one of the default interpreter type
|
||||
*/
|
||||
// const isDefaultDisplayType = DefaultDisplayType[type];
|
||||
// if (!isDefaultDisplayType) {
|
||||
// const intp = heliumService.getFrontendInterpreterWithDisplayType(type);
|
||||
//
|
||||
// if (intp) {
|
||||
// // currently display only accepts `Object` data not
|
||||
// // doesn't support function and promise
|
||||
// const result = intp.display(data);
|
||||
// type = result.getType();
|
||||
// data = result.getData();
|
||||
// }
|
||||
// }
|
||||
|
||||
if (type === DefaultDisplayType.TABLE) {
|
||||
$scope.renderGraph($scope.graphMode, refresh);
|
||||
} else if (type === 'HTML') {
|
||||
renderHtml();
|
||||
} else if (type === 'ANGULAR') {
|
||||
renderAngular();
|
||||
} else if (type === 'TEXT') {
|
||||
renderText();
|
||||
} else if (type === DefaultDisplayType.HTML) {
|
||||
renderHtml(`p${$scope.id}_html`, data);
|
||||
} else if (type === DefaultDisplayType.ANGULAR) {
|
||||
renderAngular(`p${$scope.id}_angular`, data);
|
||||
} else if (type === DefaultDisplayType.TEXT) {
|
||||
renderText(`p${$scope.id}_text`, data);
|
||||
} else if (type === DefaultDisplayType.ELEMENT) {
|
||||
renderElem(`p${$scope.id}_elem`, data);
|
||||
} else {
|
||||
console.error(`Unknown Display Type: ${type}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var renderHtml = function() {
|
||||
var retryRenderer = function() {
|
||||
var htmlEl = angular.element('#p' + $scope.id + '_html');
|
||||
if (htmlEl.length) {
|
||||
try {
|
||||
htmlEl.html(data);
|
||||
/**
|
||||
* generates actually object which will be consumed from `data` property
|
||||
* feed it to the success callback.
|
||||
* if error occurs, the error is passed to the failure callback
|
||||
*
|
||||
* @param generator {Object or Promise or Function}
|
||||
* @param type {string} Display Type
|
||||
* @param successCallback
|
||||
* @param failureCallback
|
||||
*/
|
||||
const generateData = function(generator, type, successCallback, failureCallback) {
|
||||
if (FrontendInterpreterResult.isFunctionGenerator(generator)) {
|
||||
try {
|
||||
successCallback(generator());
|
||||
} catch (error) {
|
||||
failureCallback(error);
|
||||
console.error(`Failed to handle ${type} type, function generator\n`, error);
|
||||
}
|
||||
} else if (FrontendInterpreterResult.isPromiseGenerator(generator)) {
|
||||
generator
|
||||
.then((generated) => { successCallback(generated); })
|
||||
.catch((error) => {
|
||||
failureCallback(error);
|
||||
console.error(`Failed to handle ${type} type, promise generator\n`, error);
|
||||
});
|
||||
} else if (FrontendInterpreterResult.isObjectGenerator(generator)) {
|
||||
try {
|
||||
successCallback(generator);
|
||||
} catch (error) {
|
||||
console.error(`Failed to handle ${type} type, object generator\n`, error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
htmlEl.find('pre code').each(function(i, e) {
|
||||
const renderElem = function(targetElemId, generator) {
|
||||
function retryRenderer() {
|
||||
const elem = angular.element(`#${targetElemId}`);
|
||||
if (!elem.length) {
|
||||
$timeout(retryRenderer, 10);
|
||||
return;
|
||||
}
|
||||
|
||||
generateData(() => { generator(targetElemId) }, DefaultDisplayType.ELEMENT,
|
||||
() => {}, /** HTML element will be filled in generator . thus pass empty success callback */
|
||||
(error) => { elem.html(`${error.stack}`); }
|
||||
);
|
||||
}
|
||||
|
||||
$timeout(retryRenderer);
|
||||
};
|
||||
|
||||
const renderHtml = function(targetElemId, generator) {
|
||||
function retryRenderer() {
|
||||
const elem = angular.element(`#${targetElemId}`);
|
||||
if (!elem.length) {
|
||||
$timeout(retryRenderer, 10);
|
||||
return;
|
||||
}
|
||||
|
||||
generateData(generator, DefaultDisplayType.HTML,
|
||||
(generated) => {
|
||||
elem.html(generated);
|
||||
elem.find('pre code').each(function(i, e) {
|
||||
hljs.highlightBlock(e);
|
||||
});
|
||||
/*eslint new-cap: [2, {"capIsNewExceptions": ["MathJax.Hub.Queue"]}]*/
|
||||
MathJax.Hub.Queue(['Typeset', MathJax.Hub, htmlEl[0]]);
|
||||
} catch (err) {
|
||||
console.log('HTML rendering error %o', err);
|
||||
}
|
||||
} else {
|
||||
$timeout(retryRenderer, 10);
|
||||
}
|
||||
};
|
||||
MathJax.Hub.Queue(['Typeset', MathJax.Hub, elem[0]]);
|
||||
},
|
||||
(error) => { elem.html(`${error.stack}`); }
|
||||
);
|
||||
}
|
||||
|
||||
$timeout(retryRenderer);
|
||||
};
|
||||
|
||||
var renderAngular = function() {
|
||||
var retryRenderer = function() {
|
||||
if (angular.element('#p' + $scope.id + '_angular').length) {
|
||||
try {
|
||||
angular.element('#p' + $scope.id + '_angular').html(data);
|
||||
|
||||
var paragraphScope = noteVarShareService.get(paragraph.id + '_paragraphScope');
|
||||
$compile(angular.element('#p' + $scope.id + '_angular').contents())(paragraphScope);
|
||||
} catch (err) {
|
||||
console.log('ANGULAR rendering error %o', err);
|
||||
}
|
||||
} else {
|
||||
const renderAngular = function(targetElemId, generator) {
|
||||
function retryRenderer() {
|
||||
const elem = angular.element(`#${targetElemId}`);
|
||||
if (!elem.length) {
|
||||
$timeout(retryRenderer, 10);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const paragraphScope = noteVarShareService.get(`${paragraph.id}_paragraphScope`);
|
||||
generateData(generator, DefaultDisplayType.ANGULAR,
|
||||
(generated) => {
|
||||
elem.html(generated);
|
||||
$compile(elem.contents())(paragraphScope);
|
||||
},
|
||||
(error) => { elem.html(`${error.stack}`); }
|
||||
);
|
||||
}
|
||||
|
||||
$timeout(retryRenderer);
|
||||
};
|
||||
|
||||
var getTextEl = function (paragraphId) {
|
||||
return angular.element('#p' + $scope.id + '_text');
|
||||
const getTextResultElem = function (resultId) {
|
||||
return angular.element('#p' + resultId + '_text');
|
||||
};
|
||||
|
||||
const renderText = function(targetElemId, generator) {
|
||||
function retryRenderer() {
|
||||
const elem = angular.element(`#${targetElemId}`);
|
||||
if (!elem.length) {
|
||||
$timeout(retryRenderer, 10);
|
||||
return;
|
||||
}
|
||||
|
||||
generateData(generator, DefaultDisplayType.TEXT,
|
||||
(generated) => {
|
||||
// clear all lines before render
|
||||
clearTextOutput();
|
||||
$scope.textRendererInitialized = true;
|
||||
if (generated) { appendTextOutput(generated); }
|
||||
else { flushAppendQueue(); }
|
||||
elem.bind('mousewheel', (e) => { $scope.keepScrollDown = false; });
|
||||
},
|
||||
(error) => { elem.html(`${error.stack}`); }
|
||||
);
|
||||
}
|
||||
|
||||
$timeout(retryRenderer);
|
||||
}
|
||||
|
||||
var textRendererInitialized = false;
|
||||
var renderText = function() {
|
||||
var retryRenderer = function() {
|
||||
var textEl = getTextEl($scope.id);
|
||||
if (textEl.length) {
|
||||
// clear all lines before render
|
||||
clearTextOutput();
|
||||
textRendererInitialized = true;
|
||||
|
||||
if (data) {
|
||||
appendTextOutput(data);
|
||||
} else {
|
||||
flushAppendQueue();
|
||||
}
|
||||
|
||||
getTextEl($scope.id).bind('mousewheel', function(e) {
|
||||
$scope.keepScrollDown = false;
|
||||
});
|
||||
} else {
|
||||
$timeout(retryRenderer, 10);
|
||||
}
|
||||
};
|
||||
$timeout(retryRenderer);
|
||||
};
|
||||
|
||||
var clearTextOutput = function() {
|
||||
var textEl = getTextEl($scope.id);
|
||||
var textEl = getTextResultElem($scope.id);
|
||||
if (textEl.length) {
|
||||
textEl.children().remove();
|
||||
}
|
||||
|
|
@ -359,11 +439,11 @@ function ResultCtrl($scope, $rootScope, $route, $window, $routeParams, $location
|
|||
};
|
||||
|
||||
var appendTextOutput = function(msg) {
|
||||
if (!textRendererInitialized) {
|
||||
if (!$scope.textRendererInitialized) {
|
||||
textAppendQueueBeforeInitialize.push(msg);
|
||||
} else {
|
||||
flushAppendQueue();
|
||||
var textEl = getTextEl($scope.id);
|
||||
var textEl = getTextResultElem($scope.id);
|
||||
if (textEl.length) {
|
||||
var lines = msg.split('\n');
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
|
|
@ -371,7 +451,7 @@ function ResultCtrl($scope, $rootScope, $route, $window, $routeParams, $location
|
|||
}
|
||||
}
|
||||
if ($scope.keepScrollDown) {
|
||||
var doc = getTextEl($scope.id);
|
||||
var doc = getTextResultElem($scope.id);
|
||||
doc[0].scrollTop = doc[0].scrollHeight;
|
||||
}
|
||||
}
|
||||
|
|
@ -725,22 +805,23 @@ function ResultCtrl($scope, $rootScope, $route, $window, $routeParams, $location
|
|||
});
|
||||
};
|
||||
|
||||
var renderApp = function(appState) {
|
||||
var retryRenderer = function() {
|
||||
var targetEl = angular.element(document.getElementById('p' + appState.id));
|
||||
console.log('retry renderApp %o', targetEl);
|
||||
if (targetEl.length) {
|
||||
const renderApp = function(targetElemId, appState) {
|
||||
function retryRenderer() {
|
||||
var elem = angular.element(document.getElementById(elememId));
|
||||
console.log('retry renderApp %o', elem);
|
||||
if (!elem.length) {
|
||||
$timeout(retryRenderer, 1000);
|
||||
} else {
|
||||
try {
|
||||
console.log('renderApp %o', appState);
|
||||
targetEl.html(appState.output);
|
||||
$compile(targetEl.contents())(getAppScope(appState));
|
||||
elem.html(appState.output);
|
||||
$compile(elem.contents())(getAppScope(appState));
|
||||
} catch (err) {
|
||||
console.log('App rendering error %o', err);
|
||||
}
|
||||
} else {
|
||||
$timeout(retryRenderer, 1000);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
$timeout(retryRenderer);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -67,13 +67,15 @@ limitations under the License.
|
|||
tooltip="Scroll Top"></div>
|
||||
</div>
|
||||
|
||||
<div id="p{{id}}_html"
|
||||
class="resultContained"
|
||||
<div id="p{{id}}_elem" class="resultContained"
|
||||
ng-if="type == 'ELEMENT'">
|
||||
</div>
|
||||
|
||||
<div id="p{{id}}_html" class="resultContained"
|
||||
ng-if="type == 'HTML'">
|
||||
</div>
|
||||
|
||||
<div id="p{{id}}_angular"
|
||||
class="resultContained"
|
||||
<div id="p{{id}}_angular" class="resultContained"
|
||||
ng-if="type == 'ANGULAR'">
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -108,5 +108,5 @@ import {
|
|||
this.disable = function(name) {
|
||||
return $http.post(baseUrlSrv.getRestApiBase() + '/helium/disable/' + name);
|
||||
};
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -41,10 +41,6 @@ describe('Controller: ParagraphCtrl', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should return "TEXT" by default when getResultType() is called with no parameter', function() {
|
||||
expect(scope.getResultType()).toEqual('TEXT');
|
||||
});
|
||||
|
||||
it('should have this array of values for "colWidthOption"', function() {
|
||||
expect(scope.colWidthOption).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue