",
+ options: {
+ disabled: false,
+
+ // callbacks
+ create: null
+ },
+ _createWidget: function( options, element ) {
+ element = $( element || this.defaultElement || this )[ 0 ];
+ this.element = $( element );
+ this.uuid = widget_uuid++;
+ this.eventNamespace = "." + this.widgetName + this.uuid;
+
+ this.bindings = $();
+ this.hoverable = $();
+ this.focusable = $();
+
+ if ( element !== this ) {
+ $.data( element, this.widgetFullName, this );
+ this._on( true, this.element, {
+ remove: function( event ) {
+ if ( event.target === element ) {
+ this.destroy();
+ }
+ }
+ });
+ this.document = $( element.style ?
+ // element within the document
+ element.ownerDocument :
+ // element is window or document
+ element.document || element );
+ this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
+ }
+
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ this._create();
+ this._trigger( "create", null, this._getCreateEventData() );
+ this._init();
+ },
+ _getCreateOptions: $.noop,
+ _getCreateEventData: $.noop,
+ _create: $.noop,
+ _init: $.noop,
+
+ destroy: function() {
+ this._destroy();
+ // we can probably remove the unbind calls in 2.0
+ // all event bindings should go through this._on()
+ this.element
+ .unbind( this.eventNamespace )
+ .removeData( this.widgetFullName )
+ // support: jquery <1.6.3
+ // http://bugs.jquery.com/ticket/9413
+ .removeData( $.camelCase( this.widgetFullName ) );
+ this.widget()
+ .unbind( this.eventNamespace )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetFullName + "-disabled " +
+ "ui-state-disabled" );
+
+ // clean up events and states
+ this.bindings.unbind( this.eventNamespace );
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ },
+ _destroy: $.noop,
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key,
+ parts,
+ curOption,
+ i;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.widget.extend( {}, this.options );
+ }
+
+ if ( typeof key === "string" ) {
+ // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+ options = {};
+ parts = key.split( "." );
+ key = parts.shift();
+ if ( parts.length ) {
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+ for ( i = 0; i < parts.length - 1; i++ ) {
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+ curOption = curOption[ parts[ i ] ];
+ }
+ key = parts.pop();
+ if ( arguments.length === 1 ) {
+ return curOption[ key ] === undefined ? null : curOption[ key ];
+ }
+ curOption[ key ] = value;
+ } else {
+ if ( arguments.length === 1 ) {
+ return this.options[ key ] === undefined ? null : this.options[ key ];
+ }
+ options[ key ] = value;
+ }
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var key;
+
+ for ( key in options ) {
+ this._setOption( key, options[ key ] );
+ }
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ .toggleClass( this.widgetFullName + "-disabled", !!value );
+
+ // If the widget is becoming disabled, then nothing is interactive
+ if ( value ) {
+ this.hoverable.removeClass( "ui-state-hover" );
+ this.focusable.removeClass( "ui-state-focus" );
+ }
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOptions({ disabled: false });
+ },
+ disable: function() {
+ return this._setOptions({ disabled: true });
+ },
+
+ _on: function( suppressDisabledCheck, element, handlers ) {
+ var delegateElement,
+ instance = this;
+
+ // no suppressDisabledCheck flag, shuffle arguments
+ if ( typeof suppressDisabledCheck !== "boolean" ) {
+ handlers = element;
+ element = suppressDisabledCheck;
+ suppressDisabledCheck = false;
+ }
+
+ // no element argument, shuffle and use this.element
+ if ( !handlers ) {
+ handlers = element;
+ element = this.element;
+ delegateElement = this.widget();
+ } else {
+ element = delegateElement = $( element );
+ this.bindings = this.bindings.add( element );
+ }
+
+ $.each( handlers, function( event, handler ) {
+ function handlerProxy() {
+ // allow widgets to customize the disabled handling
+ // - disabled as an array instead of boolean
+ // - disabled class as method for disabling individual parts
+ if ( !suppressDisabledCheck &&
+ ( instance.options.disabled === true ||
+ $( this ).hasClass( "ui-state-disabled" ) ) ) {
+ return;
+ }
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+
+ // copy the guid so direct unbinding works
+ if ( typeof handler !== "string" ) {
+ handlerProxy.guid = handler.guid =
+ handler.guid || handlerProxy.guid || $.guid++;
+ }
+
+ var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
+ eventName = match[1] + instance.eventNamespace,
+ selector = match[2];
+ if ( selector ) {
+ delegateElement.delegate( selector, eventName, handlerProxy );
+ } else {
+ element.bind( eventName, handlerProxy );
+ }
+ });
+ },
+
+ _off: function( element, eventName ) {
+ eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
+ this.eventNamespace;
+ element.unbind( eventName ).undelegate( eventName );
+
+ // Clear the stack to avoid memory leaks (#10056)
+ this.bindings = $( this.bindings.not( element ).get() );
+ this.focusable = $( this.focusable.not( element ).get() );
+ this.hoverable = $( this.hoverable.not( element ).get() );
+ },
+
+ _delay: function( handler, delay ) {
+ function handlerProxy() {
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+ var instance = this;
+ return setTimeout( handlerProxy, delay || 0 );
+ },
+
+ _hoverable: function( element ) {
+ this.hoverable = this.hoverable.add( element );
+ this._on( element, {
+ mouseenter: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-hover" );
+ },
+ mouseleave: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-hover" );
+ }
+ });
+ },
+
+ _focusable: function( element ) {
+ this.focusable = this.focusable.add( element );
+ this._on( element, {
+ focusin: function( event ) {
+ $( event.currentTarget ).addClass( "ui-state-focus" );
+ },
+ focusout: function( event ) {
+ $( event.currentTarget ).removeClass( "ui-state-focus" );
+ }
+ });
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig,
+ callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ // the original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+ return !( $.isFunction( callback ) &&
+ callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ if ( typeof options === "string" ) {
+ options = { effect: options };
+ }
+ var hasOptions,
+ effectName = !options ?
+ method :
+ options === true || typeof options === "number" ?
+ defaultEffect :
+ options.effect || defaultEffect;
+ options = options || {};
+ if ( typeof options === "number" ) {
+ options = { duration: options };
+ }
+ hasOptions = !$.isEmptyObject( options );
+ options.complete = callback;
+ if ( options.delay ) {
+ element.delay( options.delay );
+ }
+ if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue(function( next ) {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ next();
+ });
+ }
+ };
+});
+
+var widget = $.widget;
+
+
+
+}));
diff --git a/view/js/external-libs/js.cookie.js b/view/js/external-libs/js.cookie.js
new file mode 100644
index 0000000..e808108
--- /dev/null
+++ b/view/js/external-libs/js.cookie.js
@@ -0,0 +1,145 @@
+/*!
+ * JavaScript Cookie v2.0.4
+ * https://github.com/js-cookie/js-cookie
+ *
+ * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
+ * Released under the MIT license
+ */
+(function(factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(factory);
+ } else if (typeof exports === 'object') {
+ module.exports = factory();
+ } else {
+ var _OldCookies = window.Cookies;
+ var api = window.Cookies = factory();
+ api.noConflict = function() {
+ window.Cookies = _OldCookies;
+ return api;
+ };
+ }
+}(function() {
+ function extend() {
+ var i = 0;
+ var result = {};
+ for (; i < arguments.length; i++) {
+ var attributes = arguments[ i ];
+ for (var key in attributes) {
+ result[key] = attributes[key];
+ }
+ }
+ return result;
+ }
+
+ function init(converter) {
+ function api(key, value, attributes) {
+ var result;
+
+ // Write
+
+ if (arguments.length > 1) {
+ attributes = extend({
+ path: '/'
+ }, api.defaults, attributes);
+
+ if (typeof attributes.expires === 'number') {
+ var expires = new Date();
+ expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
+ attributes.expires = expires;
+ }
+
+ try {
+ result = JSON.stringify(value);
+ if (/^[\{\[]/.test(result)) {
+ value = result;
+ }
+ } catch (e) {}
+
+ if (!converter.write) {
+ value = encodeURIComponent(String(value))
+ .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
+ } else {
+ value = converter.write(value, key);
+ }
+
+ key = encodeURIComponent(String(key));
+ key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
+ key = key.replace(/[\(\)]/g, escape);
+
+ return (document.cookie = [
+ key, '=', value,
+ attributes.expires && '; expires=' + attributes.expires.toUTCString(), // use expires attribute, max-age is not supported by IE
+ attributes.path && '; path=' + attributes.path,
+ attributes.domain && '; domain=' + attributes.domain,
+ attributes.secure ? '; secure' : ''
+ ].join(''));
+ }
+
+ // Read
+
+ if (!key) {
+ result = {};
+ }
+
+ // To prevent the for loop in the first place assign an empty array
+ // in case there are no cookies at all. Also prevents odd result when
+ // calling "get()"
+ var cookies = document.cookie ? document.cookie.split('; ') : [];
+ var rdecode = /(%[0-9A-Z]{2})+/g;
+ var i = 0;
+
+ for (; i < cookies.length; i++) {
+ var parts = cookies[i].split('=');
+ var name = parts[0].replace(rdecode, decodeURIComponent);
+ var cookie = parts.slice(1).join('=');
+
+ if (cookie.charAt(0) === '"') {
+ cookie = cookie.slice(1, -1);
+ }
+
+ try {
+ cookie = converter.read ?
+ converter.read(cookie, name) : converter(cookie, name) ||
+ cookie.replace(rdecode, decodeURIComponent);
+
+ if (this.json) {
+ try {
+ cookie = JSON.parse(cookie);
+ } catch (e) {}
+ }
+
+ if (key === name) {
+ result = cookie;
+ break;
+ }
+
+ if (!key) {
+ result[name] = cookie;
+ }
+ } catch (e) {}
+ }
+
+ return result;
+ }
+
+ api.get = api.set = api;
+ api.getJSON = function() {
+ return api.apply({
+ json: true
+ }, [].slice.call(arguments));
+ };
+ api.defaults = {};
+
+ api.remove = function(key, attributes) {
+ api(key, '', extend(attributes, {
+ expires: -1
+ }));
+ };
+
+ api.withConverter = init;
+
+ return api;
+ }
+
+ return init(function() {});
+}));
diff --git a/view/js/helpers/icon-helper.js b/view/js/helpers/icon-helper.js
new file mode 100644
index 0000000..9cc0f4f
--- /dev/null
+++ b/view/js/helpers/icon-helper.js
@@ -0,0 +1,85 @@
+(function(iconHelper, $, undefined) {
+
+ var baseUrl = '';
+
+ function _changeImage(img, url) {
+ img.attr('src', url);
+ }
+
+ function _enableIconHover(container, isHover) {
+ var img = $(container).find('img').first();
+ var hover_img_url = baseUrl + '/img/' + $(container).attr('name');
+ if (isHover) {
+ hover_img_url += '-icon-hover.png';
+ } else {
+ hover_img_url += '-icon.png';
+ }
+ _changeImage(img, hover_img_url);
+ }
+
+ function _enableIconCheck(container, isCheck) {
+ var img = $(container).find('img').first();
+ var check_img_url = baseUrl + '/img/' + $(container).attr('name');
+ if (isCheck) {
+ check_img_url += '-icon-check.png';
+ } else {
+ check_img_url += '-icon.png';
+ }
+ _changeImage(img, check_img_url);
+ }
+
+ function _selectIcon(iconName, isSelect, panel) {
+ panel = typeof panel == 'undefined' ? '' : '[panel=' + panel + ']';
+ var icon_id = '.icon_container[name=' + iconName + ']' + panel;
+ _enableIconHover(icon_id, isSelect);
+ $(icon_id).attr('select', isSelect);
+ }
+
+ function _deselectIcon(iconName, parent) {
+ _selectIcon(iconName, false, parent);
+ }
+
+ function _setupCheckIcon(option, isCheck, panel) {
+ panel = typeof panel == 'undefined' ? '' : '[panel=' + panel + ']';
+ var icon_id = '.icon_container[name=' + option + ']' + panel;
+ iconHelper.enableIconCheck(icon_id, isCheck);
+ $('.icon_container[name=' + option + ']' + panel).attr('complete',
+ isCheck);
+ }
+
+ function _canHover(el) {
+ var incompleteConfig = typeof $(el).attr('complete') == 'undefined'
+ || $(el).attr('complete') == 'false';
+ return (!configurationScreen.isMenuSelected() && incompleteConfig)
+ || (typeof $(el).attr('select') == 'undefined' && incompleteConfig);
+ }
+
+ iconHelper.enableIconHover = function(container, isHover) {
+ _enableIconHover(container, isHover);
+ }
+
+ iconHelper.enableIconCheck = function(container, isCheck) {
+ _enableIconCheck(container, isCheck);
+ }
+
+ iconHelper.setupCheckIcon = function(option, isCheck, panel) {
+ _setupCheckIcon(option, isCheck, panel);
+ }
+
+ iconHelper.selectIcon = function(iconName, isSelect, panel) {
+ _selectIcon(iconName, isSelect, panel);
+ }
+
+ iconHelper.deselectIcon = function(iconName, parent) {
+ _deselectIcon(iconName, parent);
+ }
+
+ iconHelper.canHover = function(el) {
+ return _canHover(el);
+ }
+
+ iconHelper.setup = function(url) {
+ baseUrl = url;
+ };
+
+}(window.iconHelper = window.iconHelper || {}, jQuery));
diff --git a/view/js/helpers/load-html-helper.js b/view/js/helpers/load-html-helper.js
new file mode 100644
index 0000000..ea3aef1
--- /dev/null
+++ b/view/js/helpers/load-html-helper.js
@@ -0,0 +1,106 @@
+(function(loadHtmlHelper, $, undefined) {
+
+ var baseUrl = '';
+ var templatesUrl = '';
+
+ _preprocessHtml = function(data) {
+ var matchSubConfig = data.match(/sub(?:C|c)onfig="(.*?)"/);
+ var currentMainConfig = dynworkflow.getMainConfig(); // right-hand or left-hand
+ var goodData = data;
+
+ var isRightHand = function(hand) {
+ return hand === 'right-hand';
+ };
+
+ var replaceConfigurationTag = function(data, mainConfig) {
+ if (isRightHand(mainConfig)) {
+ return data.replace(/{{ configuracao }}/g, 'cmd');
+ } else {
+ return data.replace(/{{ configuracao }}/g, 'cme');
+ }
+ };
+
+ var replaceOrientationTag = function(data, mainConfig) {
+ if (isRightHand(mainConfig)) {
+ return data.replace(/{{ orientacao }}/g, 'ord');
+ } else {
+ return data.replace(/{{ orientacao }}/g, 'ore');
+ }
+ };
+
+ var replaceHandFolderTag = function(data, mainConfig) {
+ if (isRightHand(mainConfig)) {
+ return data.replace(/{{ hand-folder }}/g, 'md');
+ } else {
+ return data.replace(/{{ hand-folder }}/g, 'me');
+ }
+ };
+
+ var replaceMovementNameTag = function(data, mainConfig) {
+ var selectedMovement = movement
+ .getPreviousSelectedMovement(mainConfig);
+ if (typeof selectedMovement != "undefined") {
+ return data.replace(/{{ movement-name }}/g, selectedMovement);
+ }
+ return data;
+ };
+
+ if (matchSubConfig) { // case defined
+ // There is no specific(right or left hand dependent) assets for: articulacao, duracao, expressao, movimento, transicao
+ // Specific configurations: configuracao, orientacao
+ // possible values on the side as comment
+ var subConfig = matchSubConfig[1]; // articulacao | configuracao | duracao | expressao | movimento | orientacao | transicao
+
+ // possible subconfigs that need changing
+ switch (subConfig) {
+ case 'configuracao':
+ goodData = replaceConfigurationTag(data, currentMainConfig);
+ break;
+ case 'configuracao-retilineo':
+ goodData = replaceConfigurationTag(data, currentMainConfig);
+ break;
+ case 'orientacao':
+ goodData = replaceOrientationTag(data, currentMainConfig);
+ break;
+ case 'orientacao-retilineo':
+ goodData = replaceOrientationTag(data, currentMainConfig);
+ break;
+ }
+ }
+ goodData = replaceHandFolderTag(goodData, currentMainConfig);
+ goodData = replaceMovementNameTag(goodData, currentMainConfig);
+ goodData = goodData.replace(/{{ hand }}/g, currentMainConfig);
+ return goodData.replace(/{{ server }}/g, baseUrl);
+ };
+
+ function _getHtml(templatePath, target, toReplace, toPrepend, callback) {
+ var url = templatesUrl + templatePath;
+ $.get(url, function(data) {
+ var processedHtml = _preprocessHtml(data);
+
+ if (toReplace) {
+ $(target).html(processedHtml);
+ } else if (toPrepend) {
+ $(target).prepend(processedHtml);
+ } else {
+ $(target).append(processedHtml);
+ }
+ }).done(function() {
+ callback && callback(); // call if defined
+ });
+ }
+
+ loadHtmlHelper.append = function(templatePath, target, toPrepend, callback) {
+ _getHtml(templatePath, target, false, toPrepend, callback);
+ };
+
+ loadHtmlHelper.load = function(templatePath, target, callback) {
+ _getHtml(templatePath, target, true, false, callback);
+ };
+
+ loadHtmlHelper.setup = function(url) {
+ baseUrl = url;
+ templatesUrl = baseUrl + "/templates";
+ };
+
+}(window.loadHtmlHelper = window.loadHtmlHelper || {}, jQuery));
diff --git a/view/js/helpers/pybossa-api-helper.js b/view/js/helpers/pybossa-api-helper.js
new file mode 100644
index 0000000..8a79e28
--- /dev/null
+++ b/view/js/helpers/pybossa-api-helper.js
@@ -0,0 +1,44 @@
+(function(pybossaApiHelper, $, undefined) {
+
+ var pybossaEndpoint = '';
+ var projectName = '';
+
+ function _getProjectId() {
+ return $.ajax({
+ url : pybossaEndpoint + '/api/project?short_name=' + projectName
+ });
+ }
+
+ function _getUserProgress() {
+ return $.ajax({
+ url : pybossaEndpoint + '/api/project/' + projectName + '/userprogress',
+ cache : false,
+ dataType : 'json'
+ });
+ }
+
+ function _getAnswers(projectId, userId) {
+ return $.ajax({
+ url : pybossaEndpoint + '/api/taskrun?project_id=' + projectId
+ + '&user_id=' + userId
+ });
+ }
+
+ pybossaApiHelper.setup = function(endpoint, name) {
+ pybossaEndpoint = endpoint;
+ projectName = name;
+ }
+
+ pybossaApiHelper.getProjectId = function() {
+ return _getProjectId();
+ }
+
+ pybossaApiHelper.getUserProgress = function() {
+ return _getUserProgress();
+ }
+
+ pybossaApiHelper.getAnswers = function(projectId, userId) {
+ return _getAnswers(projectId, userId);
+ }
+
+}(window.pybossaApiHelper = window.pybossaApiHelper || {}, jQuery));
diff --git a/view/js/helpers/tmpJSONParser.js b/view/js/helpers/tmpJSONParser.js
new file mode 100644
index 0000000..0c0dc60
--- /dev/null
+++ b/view/js/helpers/tmpJSONParser.js
@@ -0,0 +1,124 @@
+(function(tmpJSONParser, $, undefined) {
+
+ var base_parameter_json = {};
+ var movement_parameter_json = {};
+
+ function _setupBaseParameterJSON(tmpJSON) {
+ base_parameter_json['userId'] = tmpJSON['userId'];
+ base_parameter_json['sinal'] = tmpJSON['sinal'];
+ base_parameter_json['interpolacao'] = 'normal';
+ base_parameter_json['movimentos'] = [];
+ movement_parameter_json = {
+ 'facial': {},
+ 'mao_direita': {},
+ 'mao_esquerda': {}
+ };
+ base_parameter_json['movimentos'].push(movement_parameter_json);
+ }
+
+ function _parseParameterValue(value) {
+ if (typeof value == 'string' && value.toLowerCase() == 'true') {
+ return true;
+ } else if (typeof value == 'string' && value.toLowerCase() == 'false') {
+ return false;
+ } else {
+ return !isNaN(value) ? parseInt(value) : value;
+ }
+ }
+
+ function _parseTempFacialParameterJSON(tmpJSON) {
+ var attrs = dynworkflow.getFacialParameters();
+ for (var i in attrs) {
+ var attr = attrs[i];
+ parameterValue = tmpJSON['facial'][attr][0];
+ movement_parameter_json['facial'][attr] = _parseParameterValue(parameterValue);
+ }
+ }
+
+ function _parseHand(hand) {
+ var parsedHand = hand == 'right-hand' ? 'mao_direita' : hand;
+ parsedHand = hand == 'left-hand' ? 'mao_esquerda' : parsedHand;
+ return parsedHand;
+ }
+
+ // Default parser
+ function _defaultMovementParser(tmpJSON, movementName, hand) {
+ var attrs = dynworkflow.getMovementParameters(movementName);
+ var parsedHand = _parseHand(hand);
+
+ for (var i in attrs) {
+ var attr = attrs[i];
+ var parameterValue = '';
+ if (typeof tmpJSON[hand][attr] == "undefined") {
+ continue;
+ }
+ if (attr == 'configuracao') {
+ parameterValue = tmpJSON[hand][attr][1];
+ } else if (attr == 'articulacao') {
+ parameterValue = articulation.processValue(hand, tmpJSON[hand][attr]);
+ } else {
+ parameterValue = tmpJSON[hand][attr][0];
+ }
+ movement_parameter_json[parsedHand][movementName][attr] =
+ _parseParameterValue(parameterValue);
+ }
+ }
+
+ function _retilinearMovementParser(tmpJSON, movementName, hand) {
+ var attrs = dynworkflow.getMovementParameters(movementName);
+ var parsedHand = _parseHand(hand);
+
+ for (var i in attrs) {
+ var attr = attrs[i];
+ var initParameterValue = '';
+ var endParameterValue = '';
+ if (attr == 'configuracao-retilineo') {
+ initParameterValue = tmpJSON[hand][attr][1];
+ endParameterValue = tmpJSON[hand][attr][3];
+ } else if (attr == 'articulacao-retilineo') {
+ initSlice = tmpJSON[hand][attr].slice(0, 2);
+ endSlice = tmpJSON[hand][attr].slice(2, 4);
+ initParameterValue = articulation.processValue(hand, initSlice);
+ endParameterValue = articulation.processValue(hand, endSlice);
+ } else {
+ initParameterValue = tmpJSON[hand][attr][0];
+ endParameterValue = tmpJSON[hand][attr][1];
+ }
+ attr = attr.replace('-retilineo', '');
+ var initAttr = attr + '_inicial';
+ var endAttr = attr + '_final';
+ movement_parameter_json[parsedHand][movementName][initAttr] =
+ _parseParameterValue(initParameterValue);
+ movement_parameter_json[parsedHand][movementName][endAttr] =
+ _parseParameterValue(endParameterValue);
+ }
+ }
+
+ function _parseTempMovementParameterJSON(tmpJSON, hand) {
+ var movimentConfig = tmpJSON[hand]['movimento'];
+ if (typeof movimentConfig == 'undefined') return;
+
+ var movementName = movimentConfig[0];
+ var parsedHand = _parseHand(hand);
+ movement_parameter_json[parsedHand][movementName] = {};
+
+ if (movementName == 'retilineo') {
+ _retilinearMovementParser(tmpJSON, movementName, hand);
+ } else {
+ _defaultMovementParser(tmpJSON, movementName, hand);
+ }
+ }
+
+ tmpJSONParser.parse = function(tmpJSON, rightHand, leftHand) {
+ _setupBaseParameterJSON(tmpJSON);
+ _parseTempFacialParameterJSON(tmpJSON);
+ if (rightHand) {
+ _parseTempMovementParameterJSON(tmpJSON, 'right-hand');
+ }
+ if (leftHand) {
+ _parseTempMovementParameterJSON(tmpJSON, 'left-hand');
+ }
+ return base_parameter_json;
+ };
+
+}(window.tmpJSONParser = window.tmpJSONParser || {}, jQuery));
diff --git a/view/js/helpers/video-helper.js b/view/js/helpers/video-helper.js
new file mode 100644
index 0000000..00e31ce
--- /dev/null
+++ b/view/js/helpers/video-helper.js
@@ -0,0 +1,23 @@
+(function(videoHelper, $, undefined) {
+
+ function _controlVideo(elId, toPlay) {
+ var videoSrc = $(elId).attr("src");
+ if (typeof videoSrc == "undefined" ||
+ (typeof videoSrc != "undefined" && videoSrc === ""))
+ return;
+ if (toPlay) {
+ $(elId).get(0).play();
+ } else {
+ $(elId).get(0).pause();
+ }
+ }
+
+ videoHelper.play = function(elId) {
+ _controlVideo(elId, true);
+ }
+
+ videoHelper.pause = function(elId) {
+ _controlVideo(elId, false);
+ }
+
+}(window.videoHelper = window.videoHelper || {}, jQuery));
diff --git a/view/js/ranking.js b/view/js/ranking.js
new file mode 100644
index 0000000..50bb0d0
--- /dev/null
+++ b/view/js/ranking.js
@@ -0,0 +1,138 @@
+(function(ranking, $, undefined) {
+
+ var NUMBER_OF_TOP_USERS = 10;
+ var STARS_MAP = ['', 'gold', 'silver', 'bronze'];
+ var baseUrl = '';
+ var pybossaEndpoint = '';
+ var projectName = '';
+ var loggedUser = {};
+ var totalTasks = 0;
+ var doneTasks = 0;
+
+ function _getRankingData(callback) {
+ $.ajax({
+ url : pybossaEndpoint + '/api/leaderboard?limit='
+ + NUMBER_OF_TOP_USERS,
+ success : function(response) {
+ callback(typeof response == 'object' ? response[projectName]
+ : '');
+ },
+ error : function(xhr, textStatus, error) {
+ alert(xhr.responseText);
+ }
+ });
+ }
+
+ function _processRankingRow(rowData) {
+ var rank = rowData.rank;
+ if (rank < 0) {
+ return '';
+ }
+ var starHTML = '';
+ if (rank > 0 && rank < 4) {
+ starHTML = '
';
+ }
+ var trHTML = '
';
+ if (rowData.name === loggedUser.name) {
+ trHTML = ' ';
+ loggedUser.rank = rowData.rank;
+ }
+ rank = rank == 0 ? '-' : rank + '.';
+ return trHTML + '' + starHTML + ' ' + rank
+ + ' ' + rowData.fullname + ' '
+ + rowData.score + ' ';
+ }
+
+ function _updateRanking() {
+ _getRankingData(function(data) {
+ if (data === '')
+ return;
+
+ var rowsHTML = '';
+ for (var i = 0; i < data.length; i++) {
+ rowsHTML += _processRankingRow(data[i]);
+ }
+ $('#leaderboard-container tbody').html(rowsHTML);
+ $('#ranking-info-container .rank-position').html(loggedUser.rank);
+ $('#ranking-info-container .username').html(loggedUser.fullName);
+ if (loggedUser.avatarUrl != '') {
+ $('#ranking-info-container .avatar-container img').attr('src',
+ loggedUser.avatarUrl);
+ $('#ranking-info-container .avatar-placeholder').hide();
+ $('#ranking-info-container .avatar-container').show();
+ }
+ if (loggedUser.rank === 0) {
+ $('#ranking-info-container .rank-position-container').hide();
+ }
+ _updateProgress();
+ });
+ }
+
+ function _getUserData() {
+ return $.ajax({
+ url : pybossaEndpoint + '/api/user?name=' + loggedUser.name
+ });
+ }
+
+ function _getAvatarUrl(data) {
+ return !data || typeof data.avatar === 'undefined' || typeof data.container === 'undefined' ?
+ '' : pybossaEndpoint + '/uploads/' + data.container + '/' + data.avatar;
+ }
+
+ function _updateProgress() {
+ pybossaApiHelper
+ .getUserProgress()
+ .done(
+ function(response) {
+ totalTasks = response.total;
+ doneTasks = response.done;
+ var percentage = (doneTasks / totalTasks) * 100;
+ $('#ranking-info-container .progress-bar').attr(
+ 'aria-valuenow', percentage).css('width',
+ percentage + '%');
+ $('#ranking-container [data-toggle="tooltip"]')
+ .tooltip(
+ {
+ title : '
'
+ + doneTasks
+ + ' / '
+ + totalTasks
+ + ' sinais ensinados.',
+ placement : 'bottom',
+ trigger : 'manual'
+ });
+ });
+ }
+
+ function _loadRankingData() {
+ _getUserData().done(function(response) {
+ if (typeof response == 'undefined' || response.length < 1) {
+ return;
+ }
+ loggedUser.fullName = response[0].fullname;
+ loggedUser.avatarUrl = _getAvatarUrl(response[0].info);
+ _updateRanking();
+ });
+ }
+
+ ranking.show = function() {
+ $('.sub-main-container').hide();
+ $('#ranking-container').show();
+
+ if (doneTasks > 0) {
+ $('#ranking-container [data-toggle="tooltip"]').tooltip('show');
+ }
+ }
+
+ ranking.setup = function(serverUrl, endpoint, name, user) {
+ baseUrl = serverUrl;
+ pybossaEndpoint = endpoint;
+ projectName = name;
+ loggedUser.name = user;
+ loadHtmlHelper.load('/ranking/ranking.html', '#ranking-container',
+ _loadRankingData);
+ };
+
+}(window.ranking = window.ranking || {}, jQuery));
\ No newline at end of file
diff --git a/view/js/render-sign.js b/view/js/render-sign.js
new file mode 100644
index 0000000..7ffa0c0
--- /dev/null
+++ b/view/js/render-sign.js
@@ -0,0 +1,83 @@
+(function(renderSign, $, undefined) {
+
+ var api_url = '';
+
+ function _submitParameterJSON(parsedParameterJSON, callback) {
+ console.log(parsedParameterJSON);
+ $.ajax({
+ type : 'POST',
+ url : api_url + '/sign',
+ data : JSON.stringify(parsedParameterJSON),
+ contentType : 'application/json',
+ success : function(response) {
+ console.log(response);
+ callback(parsedParameterJSON);
+ },
+ error : function(xhr, textStatus, error) {
+ alert(xhr.responseText);
+ }
+ });
+ }
+
+ function _showRenderedAvatar(parameterJSON) {
+ var userId = parameterJSON['userId'];
+ var signName = parameterJSON['sinal'];
+ $("#render-avatar video").attr("src",
+ _getRenderedAvatarUrl(userId, signName));
+ $("#render-avatar").fadeIn(300);
+ }
+
+ function _showRenderScreen(toShow) {
+ if (toShow) {
+ $("#render-screen").fadeIn(300);
+ videoHelper.play("#render-ref video");
+ videoHelper.play("#render-avatar video");
+ } else {
+ $("#render-screen").hide();
+ videoHelper.pause("#render-ref video");
+ videoHelper.pause("#render-avatar video");
+ }
+ }
+
+ function _getRenderedAvatarUrl(userId, signName) {
+ return api_url + '/public/' + userId + '/' + signName + ".webm";
+ }
+
+ renderSign.showRenderedAvatar = function(parameterJSON) {
+ _showRenderedAvatar(parameterJSON);
+ _showRenderScreen(true);
+ }
+
+ renderSign.showRenderScreen = function(toShow) {
+ _showRenderScreen(toShow);
+ }
+
+ renderSign.getRenderedAvatarUrl = function(userId, signName) {
+ return _getRenderedAvatarUrl(userId, signName);
+ }
+
+ renderSign.submit = function(parsedParameterJSON) {
+ configurationScreen.show(false);
+ _showRenderScreen(true);
+ $("#render-avatar").hide();
+ $("#render-loading").fadeIn(300);
+ $("#render-button-container .btn").hide();
+ $("#finish-button").addClass("disabled");
+ $("#finish-button").show();
+
+ _submitParameterJSON(parsedParameterJSON, function(parsedParameterJSON) {
+ $("#render-loading").fadeOut(300);
+ $("#finish-button").removeClass("disabled");
+ _showRenderedAvatar(parsedParameterJSON);
+ });
+ };
+
+ renderSign.setup = function(apiUrl) {
+ api_url = apiUrl;
+ $("#render-edit").off("click").on("click", function() {
+ _showRenderScreen(false);
+ configurationScreen.show(true);
+ });
+ }
+
+}(window.renderSign = window.renderSign || {}, jQuery));
diff --git a/view/js/selection-panel/articulation.js b/view/js/selection-panel/articulation.js
new file mode 100644
index 0000000..cdefabd
--- /dev/null
+++ b/view/js/selection-panel/articulation.js
@@ -0,0 +1,143 @@
+(function(articulation, $, undefined) {
+
+ var server_host = '';
+ var MAX_COLUMNS = 14;
+
+ function _updateASelector(container, ballSelector, step) {
+ var pointSelector = parseInt(step) == 2 ? 'A' : 'B';
+ $(container + ' .ball-selector.active').each(function() {
+ $(this).removeClass('active');
+ $(this).find('.point-selector').remove();
+ });
+ ballSelector.addClass('active');
+ ballSelector.append('
');
+ $(container + ' .selection-panel-option[select=true]').attr('select',
+ false);
+ $(ballSelector).attr('select', true);
+ }
+
+ function _getSelectedY(hand, subConfig, step) {
+ step = parseInt(step) - 1;
+ var previousStepId = '.selection-panel-body[mainConfig=' + hand
+ + '][subConfig=' + subConfig + '][step=' + step
+ + '] .module-x-y';
+ return $(previousStepId).attr('data-y');
+ }
+
+ function _setupModuleZ(hand, subConfig, step, selectedY) {
+ if (typeof selectedY == 'undefined' || selectedY == '')
+ return;
+
+ var base_id = '.selection-panel-body[mainConfig=' + hand
+ + '][subConfig=' + subConfig + '][step=' + step + ']';
+ var articulation_z = base_id + ' .module-z';
+ $(articulation_z + ' .ball-selector').hide();
+ $(articulation_z + ' .row-number-' + selectedY + ' .ball-selector')
+ .show();
+
+ var z = $(articulation_z).attr('data-z');
+ if (typeof z != 'undefined') {
+ var ball_selector = $(articulation_z + ' .row-number-' + selectedY
+ + ' .ball-' + z);
+ _updateASelector(articulation_z, ball_selector, step);
+ }
+ }
+
+ function _setupBallSelectorXY(hand, subConfig, step) {
+ var base_id = '.selection-panel-body[mainConfig=' + hand
+ + '][subConfig=' + subConfig + '][step=' + step + ']';
+ var articulation_x_y = base_id + ' .module-x-y';
+ $(articulation_x_y + ' .ball-selector')
+ .off('click')
+ .on(
+ 'click',
+ function(a) {
+ var b = $(a.target);
+ if (!b.hasClass('ball-selector')) {
+ dynworkflow.userSelectedAnOption();
+ return;
+ }
+ var c = b.parent('.grid-row'), d = $(articulation_x_y), f = b
+ .attr('data-x'), g = c.attr('data-y');
+ d.attr('data-x', f), d.attr('data-y', g);
+
+ var nextStep = parseInt(step) + 1;
+ _updateASelector(articulation_x_y, b, nextStep);
+ _setupModuleZ(hand, subConfig, nextStep, g);
+
+ wikilibras.updateTempParameterJSON(hand, subConfig,
+ step, f + ';' + g);
+ dynworkflow.userSelectedAnOption();
+ });
+ }
+
+ function _setupBallSelectorZ(hand, subConfig, step) {
+ var base_id = '.selection-panel-body[mainConfig=' + hand
+ + '][subConfig=' + subConfig + '][step=' + step + ']';
+ var articulation_z = base_id + ' .module-z';
+ $(articulation_z + ' .ball-selector').off('click').on(
+ 'click',
+ function(a) {
+ var b = $(a.target);
+ if (!b.hasClass('ball-selector')) {
+ dynworkflow.userSelectedAnOption();
+ return;
+ }
+ var c = b.parent('.grid-row'), e = $(articulation_z), h = b
+ .attr('data-z');
+ b.attr('data-z') && e.attr('data-z', h), _updateASelector(
+ articulation_z, b, step);
+
+ wikilibras
+ .updateTempParameterJSON(hand, subConfig, step, h);
+ dynworkflow.userSelectedAnOption();
+ });
+ }
+
+ function _calculateArticulationPointIndex(hand, xValue, yValue, zValue) {
+ var x = xValue;
+ var y = yValue;
+ var z = zValue;
+ if (hand == 'left-hand') {
+ x = MAX_COLUMNS - x + 1;
+ }
+
+ var value = (z - 1) * MAX_COLUMNS + x + 3 * MAX_COLUMNS * (y - 1);
+ //console.log(value);
+ return value;
+ }
+
+ articulation.processValue = function(hand, selectionArray) {
+ var xyValueSplit = selectionArray[0].split(';');
+ var xValue = parseInt(xyValueSplit[0]);
+ var yValue = parseInt(xyValueSplit[1]);
+ var zValue = parseInt(selectionArray[1]);
+ return _calculateArticulationPointIndex(hand, xValue, yValue, zValue);
+ };
+
+ articulation.setupModuleXY = function(serverhost, hand, subConfig, step) {
+ server_host = serverhost;
+ _setupBallSelectorXY(hand, subConfig, step);
+ };
+
+ articulation.setupModuleZ = function(serverhost, hand, subConfig, step) {
+ server_host = serverhost;
+ _setupBallSelectorZ(hand, subConfig, step);
+
+ var selectedY = _getSelectedY(hand, subConfig, step);
+ _setupModuleZ(hand, subConfig, step, selectedY);
+ };
+
+ articulation.clean = function() {
+ $('.ball-selector.active').each(function() {
+ $(this).removeClass('active');
+ $(this).find('.point-selector').remove();
+ });
+ $('.module-x-y').attr('data-x', '');
+ $('.module-x-y').attr('data-y', '');
+ $('.module-z').attr('data-z', '');
+ }
+
+}(window.articulation = window.articulation || {}, jQuery));
diff --git a/view/js/selection-panel/configuration.js b/view/js/selection-panel/configuration.js
new file mode 100644
index 0000000..8e0e3d0
--- /dev/null
+++ b/view/js/selection-panel/configuration.js
@@ -0,0 +1,43 @@
+(function(configuration, $, undefined) {
+
+ configuration.setupFingersGroup = function(hand, subConfig, step) {
+ var baseId = '.selection-panel-body[mainConfig=' + hand + '][subConfig=' +
+ subConfig + '][step=' + step + ']';
+ $(baseId + ' .selection-panel-option'
+ ).off('click').on('click', function() {
+ selectionPanel.selectAnOption(baseId, this);
+ _setupFingersToShow(hand, subConfig, step);
+
+ dynworkflow.userSelectedAnOption();
+ });
+ };
+
+ function _setupFingersToShow(hand, subConfig, step) {
+ var stepOneBaseId = '.selection-panel-body[mainConfig=' + hand + '][subConfig=' +
+ subConfig + '][step=' + step + ']';
+ var nextStep = parseInt(step) + 1;
+ var stepTwoBaseId = '.selection-panel-body[mainConfig=' + hand + '][subConfig=' +
+ subConfig + '][step=' + nextStep + ']';
+
+ var finger_group = $(stepOneBaseId + ' .selection-panel-option[select=true]').attr('value');
+ finger_group = typeof finger_group == 'undefined' ? '0' : finger_group;
+
+ // clean next step
+ dynworkflow.cleanStep(hand, subConfig, nextStep);
+ $(stepTwoBaseId + ' .finger-group').hide();
+ $(stepTwoBaseId + ' .finger-group[group=' + finger_group + ']').show();
+ }
+
+ configuration.setupFingersPosition = function(hand, subConfig, step) {
+ var stepTwoBaseId = '.selection-panel-body[mainConfig=' + hand + '][subConfig=' +
+ subConfig + '][step=' + step + ']';
+ $(stepTwoBaseId + ' .selection-panel-option').off('click').on(
+ 'click', function() {
+ selectionPanel.selectAnOption(stepTwoBaseId, this);
+ dynworkflow.userSelectedAnOption();
+ });
+ var previousStep = parseInt(step) - 1;
+ _setupFingersToShow(hand, subConfig, previousStep);
+ };
+
+}(window.configuration = window.configuration || {}, jQuery));
diff --git a/view/js/selection-panel/default-configuration-handler.js b/view/js/selection-panel/default-configuration-handler.js
new file mode 100644
index 0000000..93c4283
--- /dev/null
+++ b/view/js/selection-panel/default-configuration-handler.js
@@ -0,0 +1,27 @@
+(function(defaultConfigurationHandler, $, undefined) {
+
+ defaultConfigurationHandler.setup = function(hand, subConfig, step) {
+ var baseId = '.selection-panel-body[mainConfig=' + hand + '][subConfig=' +
+ subConfig + '][step=' + step + ']';
+ $(baseId + ' .selection-panel-option').off('click').on(
+ 'click', function() {
+ selectionPanel.selectAnOption(baseId, this);
+ dynworkflow.userSelectedAnOption();
+ });
+ };
+
+ function _startVideoLoop(hand, subConfig, step, timeBetweenLoops) {
+ setTimeout(function(){
+ $('.selection-panel-body[mainConfig=' + hand + '][subConfig=' +
+ subConfig + '][step=' + step + '] video').each(function(){
+ videoHelper.play(this);
+ });
+ _startVideoLoop(hand, subConfig, step, timeBetweenLoops);
+ }, timeBetweenLoops);
+ }
+
+ defaultConfigurationHandler.startVideoLoop = function(hand, subConfig, step, timeBetweenLoops) {
+ _startVideoLoop(hand, subConfig, step, timeBetweenLoops);
+ }
+
+}(window.defaultConfigurationHandler = window.defaultConfigurationHandler || {}, jQuery));
diff --git a/view/js/selection-panel/dynamic-selection-workflow.js b/view/js/selection-panel/dynamic-selection-workflow.js
new file mode 100644
index 0000000..af9987f
--- /dev/null
+++ b/view/js/selection-panel/dynamic-selection-workflow.js
@@ -0,0 +1,369 @@
+(function(dynworkflow, $, undefined) {
+
+ // Workflow configuration
+ var jsonWF = {};
+ var baseUrl = '';
+
+ // Main configurations: right-hand, left-hand and facial
+ var mainConfig = '';
+ // The converted Main Config (right/left-hand) to hand for using the same configuration
+ var preprocessedMainConfig = '';
+ // Subconfigurations: movimento, articulacao, configuracao, orientacao, etc
+ var currentSubconfig = '';
+ var currentSubConfigName = '';
+ var currentSubconfigParent = '';
+ var currentStep = 0;
+
+ function _preprocessMainConfig(config) {
+ config = config.replace('right-hand', 'hand');
+ config = config.replace('left-hand', 'hand');
+ return config;
+ }
+
+ function _getFirstKey(json) {
+ var first_key = undefined;
+ for (first_key in json)
+ break;
+ return first_key;
+ }
+
+ function _getAttributes(json) {
+ var result = [];
+ for (attr in json) {
+ result.push(attr);
+ }
+ return result;
+ }
+
+ function _updateAndGetFirstMovementSubConfig() {
+ var selectedMovement = movement.getPreviousSelectedMovement(mainConfig);
+ if (typeof selectedMovement == 'undefined')
+ return -1;
+
+ currentSubconfigParent = jsonWF[preprocessedMainConfig]['movimento'][selectedMovement];
+ currentSubConfigName = _getFirstKey(currentSubconfigParent);
+ return currentSubConfigName;
+ }
+
+ function _updateAndGetMovementConfig() {
+ currentSubconfigParent = jsonWF[preprocessedMainConfig];
+ currentSubConfigName = _getFirstKey(currentSubconfigParent);
+ return currentSubConfigName;
+ }
+
+ function _getNextSubConfig(toForward) {
+ var attrs = _getAttributes(currentSubconfigParent);
+ for (var i = 0; i < attrs.length; i++) {
+ if (toForward && attrs[i] == currentSubConfigName
+ && i < attrs.length - 1) {
+ return attrs[i + 1];
+ } else if (!toForward && attrs[i] == currentSubConfigName && i >= 1) {
+ return attrs[i - 1];
+ }
+ }
+ if (toForward && currentSubConfigName == 'movimento') {
+ return _updateAndGetFirstMovementSubConfig();
+ } else if (!toForward && preprocessedMainConfig == 'hand') {
+ return _updateAndGetMovementConfig();
+ } else if (!toForward) {
+ return currentSubConfigName;
+ } else {
+ return -1;
+ }
+ }
+
+ function _showCurrentSubconfig() {
+ _showSubconfiguration(mainConfig, currentSubConfigName, currentStep);
+ }
+
+ // It checks if a selection panel is already loaded
+ function _isSubconfigurationPanelLoaded(mainConfig, subConfig, stepNumber) {
+ var stepNumber = stepNumber + 1;
+ return $('.selection-panel-body[mainConfig=' + mainConfig
+ + '][subConfig=' + subConfig + '][step=' + stepNumber + ']').length > 0;
+ }
+
+ function _showLoadedSubconfigurationPanel(mainConfig, subConfig, stepNumber) {
+ var stepNumber = stepNumber + 1;
+ return $(
+ '.selection-panel-body[mainConfig=' + mainConfig
+ + '][subConfig=' + subConfig + '][step=' + stepNumber
+ + ']').show();
+ }
+
+ // It renders or shows the requested selection panel
+ function _showSubconfiguration(mainConfig, subConfig, stepNumber) {
+ $('.selection-panel-body').hide();
+ if (_isSubconfigurationPanelLoaded(mainConfig, subConfig, stepNumber)) {
+ _showLoadedSubconfigurationPanel(mainConfig, subConfig, stepNumber);
+ } else {
+ var step = currentSubconfig[stepNumber];
+ step = typeof step == 'undefined' ? 'passo-1' : step;
+ loadHtmlHelper.append('/' + preprocessedMainConfig + '/'
+ + subConfig + '/' + step + '.html', '#selection-panel',
+ true);
+ }
+ _selectTimelineIcon(mainConfig, subConfig, true);
+ }
+
+ function _selectSubConfig(subConfig) {
+ if (subConfig == 'movimento') {
+ _updateAndGetMovementConfig();
+ } else if (currentSubConfigName == 'movimento') {
+ _updateAndGetFirstMovementSubConfig();
+ }
+ currentSubConfigName = subConfig;
+ currentSubconfig = currentSubconfigParent[currentSubConfigName];
+ currentStep = 0;
+ _showCurrentSubconfig();
+ }
+
+ // It shows the next selection panel on the workflow
+ function _showNextSubConfig() {
+ _walkOnTheWorkflow(true);
+ }
+
+ function _showPreviousSubConfig() {
+ _walkOnTheWorkflow(false);
+ }
+
+ function _walkOnTheWorkflow(toForward) {
+ currentStep = toForward ? currentStep + 1 : currentStep - 1;
+
+ if (currentStep >= 0 && currentStep < currentSubconfig.length) {
+ _showCurrentSubconfig();
+ } else {
+ var nextSubConfig = _getNextSubConfig(toForward);
+ if (nextSubConfig != -1) {
+ _selectSubConfig(nextSubConfig);
+ } else {
+ selectionPanel.hide();
+ }
+ }
+ }
+
+ function _checkIfFinished(mainConfig, currentSubConfigName) {
+ var numberOfSteps = currentSubconfig.length;
+ var completedSteps = $('.selection-panel-body[mainConfig=' + mainConfig
+ + '][subConfig=' + currentSubConfigName
+ + '] .selection-panel-option[select=true]').length;
+ return completedSteps != 0 && completedSteps == numberOfSteps;
+ }
+
+ // A callback function to be called when the user selects a option on a panel
+ function _userSelectedAnOption() {
+ if (_checkIfFinished(mainConfig, currentSubConfigName)) {
+ _setupCheckIcon(mainConfig, currentSubConfigName);
+ }
+ _showNextSubConfig();
+ }
+
+ function _cleanStep(mainConfig, subConfig, step) {
+ var baseId = '.selection-panel-body[mainConfig=' + mainConfig
+ + '][subConfig=' + subConfig + '][step=' + step + ']';
+ $(baseId + ' .selection-panel-option').removeAttr('select');
+ var icon_id = '.subconfiguration-panel[mainConfig=' + mainConfig
+ + '] .icon_container[json_name=' + subConfig + ']';
+ $(icon_id).removeAttr('complete');
+ }
+
+ // Timeline functions
+ function _selectTimelineIcon(mainConfig, subConfig) {
+ var baseId = '.subconfiguration-panel[mainConfig=' + mainConfig
+ + '] .subconfiguration-options';
+ var iconContainer = '.icon_container[json_name=' + subConfig + ']';
+ var iconId = baseId + ' ' + iconContainer;
+
+ var previousSelected = $(baseId + ' .icon_container[select=true]')
+ .attr('json_name');
+ if (typeof previousSelected != 'undefined') {
+ _deselectTimelineIcon(mainConfig, previousSelected);
+ }
+
+ iconHelper.enableIconHover($(iconId), true);
+ $(iconId).attr('select', true);
+ $(baseId).scrollTo(iconContainer, {
+ 'offset' : -60,
+ 'duration' : 750
+ });
+ }
+
+ function _deselectTimelineIcon(mainConfig, subConfig) {
+ var icon_id = '.subconfiguration-panel[mainConfig=' + mainConfig
+ + '] .icon_container[json_name=' + subConfig + ']';
+
+ if ($(icon_id + '[complete=true]').length > 0) {
+ _setupCheckIcon(mainConfig, subConfig);
+ } else {
+ iconHelper.enableIconHover($(icon_id), false);
+ $(icon_id).removeAttr('select');
+ }
+ }
+
+ function _setupCheckIcon(mainConfig, subConfig) {
+ var icon_id = $('.subconfiguration-panel[mainConfig=' + mainConfig
+ + '] .icon_container[json_name=' + subConfig + ']');
+ iconHelper.enableIconCheck(icon_id, true);
+ $(icon_id).attr('complete', true);
+ $(icon_id).attr('select', false);
+ }
+
+ function _isTimelineLoaded() {
+ return $('.subconfiguration-panel[mainConfig=' + mainConfig + ']').length > 0;
+ }
+
+ function _setupTimelineListeners(timelineBaseId) {
+ $(timelineBaseId + ' .icon_container[json_name]').off('click').on(
+ 'click', function() {
+ var subConfig = $(this).attr('json_name');
+ _selectSubConfig(subConfig);
+ });
+ $(timelineBaseId + ' .icon_container[json_name]').off('mouseover').on(
+ 'mouseover', function() {
+ if (iconHelper.canHover(this)) {
+ iconHelper.enableIconHover(this, true);
+ }
+ });
+ $(timelineBaseId + ' .icon_container[json_name]').off('mouseout').on(
+ 'mouseout', function() {
+ if (iconHelper.canHover(this)) {
+ iconHelper.enableIconHover(this, false);
+ }
+ });
+ $(timelineBaseId + ' .arrow[name=right-arrow]').off('click').on(
+ 'click', function() {
+ _showNextSubConfig();
+ });
+ $(timelineBaseId + ' .arrow[name=left-arrow]').off('click').on('click',
+ function() {
+ _showPreviousSubConfig();
+ });
+ }
+
+ function _setupTimelineIcons(timelineBaseId, toUpdate) {
+ if (!toUpdate) {
+ $(timelineBaseId).show();
+ $(timelineBaseId + " .subconfiguration-options").scrollTo(0, 0);
+ return;
+ }
+
+ $(timelineBaseId + ' .icon_container[json_name]').attr("active",
+ "false");
+ for ( var name in currentSubconfigParent) {
+ $(timelineBaseId + ' .icon_container[json_name=' + name + ']')
+ .attr("active", "true");
+ }
+
+ if (preprocessedMainConfig == 'hand') {
+ $(timelineBaseId + ' .icon_container[json_name=movimento]').attr(
+ "active", "true");
+ _setupCheckIcon(mainConfig, 'movimento');
+ }
+ _selectTimelineIcon(mainConfig, currentSubConfigName);
+ _setupTimelineListeners(timelineBaseId);
+ $(timelineBaseId).show();
+ }
+
+ function _setupTimeline(toUpdate) {
+ var timelineBaseId = '.subconfiguration-panel[mainConfig=' + mainConfig
+ + ']';
+ if (_isTimelineLoaded()) {
+ _setupTimelineIcons(timelineBaseId, toUpdate);
+ } else {
+ loadHtmlHelper.append('/' + preprocessedMainConfig
+ + '/timeline.html', '#selection-panel', false, function() {
+ _setupTimelineIcons(timelineBaseId, true);
+ });
+ }
+ }
+
+ function _initTimeline() {
+ if (preprocessedMainConfig != 'hand' || _isTimelineLoaded()) {
+ _setupTimeline(false);
+ }
+ }
+
+ function _cleanTimeline() {
+ $(".subconfiguration-panel").remove();
+ }
+
+ function _cleanPreviousLoadedPanel() {
+ $('.selection-panel-body[mainConfig=' + mainConfig + ']').each(
+ function() {
+ var subConfigName = $(this).attr("subConfig");
+ if (subConfigName.indexOf("articulacao") != -1
+ || subConfigName.indexOf("configuracao") != -1
+ || subConfigName.indexOf("orientacao") != -1
+ || subConfigName.indexOf("movimento") != -1) {
+ return;
+ }
+ $(
+ '.selection-panel-body[mainConfig=' + mainConfig
+ + '][subConfig=' + subConfigName + ']')
+ .remove();
+ });
+ }
+
+ // Public methods
+ dynworkflow.selectMainConfig = function(config) {
+ mainConfig = config;
+ preprocessedMainConfig = _preprocessMainConfig(mainConfig);
+ currentSubconfigParent = jsonWF[preprocessedMainConfig];
+ currentSubConfigName = _getFirstKey(currentSubconfigParent);
+ currentSubconfig = currentSubconfigParent[currentSubConfigName];
+ currentStep = 0;
+
+ _showCurrentSubconfig();
+ };
+
+ dynworkflow.selectMovement = function(movement) {
+ var subconfigJSON = currentSubconfig[movement];
+ currentSubConfigName = _getFirstKey(subconfigJSON);
+ currentSubconfigParent = subconfigJSON;
+ currentSubconfig = subconfigJSON[currentSubConfigName];
+ currentStep = 0;
+
+ _cleanPreviousLoadedPanel();
+ _showCurrentSubconfig();
+ _setupTimeline(true);
+ };
+
+ dynworkflow.selectSubConfig = function(subConfig) {
+ _selectSubConfig(subConfig);
+ };
+
+ dynworkflow.userSelectedAnOption = function() {
+ _userSelectedAnOption();
+ };
+
+ dynworkflow.cleanStep = function(mainConfig, subConfig, step) {
+ _cleanStep(mainConfig, subConfig, step);
+ };
+
+ dynworkflow.getFacialParameters = function() {
+ return _getAttributes(jsonWF['facial']);
+ };
+
+ dynworkflow.getMovementParameters = function(movementName) {
+ return _getAttributes(jsonWF['hand']['movimento'][movementName]);
+ };
+
+ dynworkflow.getMainConfig = function() {
+ return mainConfig;
+ };
+
+ dynworkflow.initTimeline = function() {
+ _initTimeline();
+ };
+
+ dynworkflow.setup = function(url) {
+ baseUrl = url;
+ $.get(baseUrl + '/conf/selection-workflow-json', function(result) {
+ jsonWF = $.parseJSON(result);
+ }).fail(function() {
+ console.log('Failed to load the workflow configuration');
+ });
+ _cleanTimeline();
+ };
+
+}(window.dynworkflow = window.dynworkflow || {}, jQuery));
diff --git a/view/js/selection-panel/facial.js b/view/js/selection-panel/facial.js
new file mode 100644
index 0000000..0958ddb
--- /dev/null
+++ b/view/js/selection-panel/facial.js
@@ -0,0 +1,21 @@
+(function(facial, $, undefined) {
+
+ facial.setup = function(subConfig) {
+ var baseId = '.selection-panel-body[mainConfig=facial][subConfig='
+ + subConfig + ']';
+ $(baseId + ' .selection-panel-option').off('click').on('click',
+ function() {
+ selectionPanel.selectAnOption(baseId, this);
+ dynworkflow.userSelectedAnOption();
+ });
+ $(baseId + ' .video-panel-option').off('mouseenter').on('mouseenter',
+ function(event) {
+ $(this).addClass('video-panel-option-hover');
+ });
+ $(baseId + ' .video-panel-option').off('mouseleave').on('mouseleave',
+ function(event) {
+ $(this).removeClass('video-panel-option-hover');
+ });
+ };
+
+}(window.facial = window.facial || {}, jQuery));
diff --git a/view/js/selection-panel/movement.js b/view/js/selection-panel/movement.js
new file mode 100644
index 0000000..67f5a04
--- /dev/null
+++ b/view/js/selection-panel/movement.js
@@ -0,0 +1,24 @@
+(function(movement, $, undefined) {
+
+ movement.getPreviousSelectedMovement = function(mainConfig) {
+ return typeof mainConfig === "undefined" || mainConfig === "" ? "" : $('.selection-panel-body[mainConfig=' +
+ mainConfig + '][subConfig=movimento][step=1] .selection-panel-option[select=true]').attr('value');
+ };
+
+ movement.setup = function(serverhost, hand) {
+ var baseId = '.selection-panel-body[mainConfig=' + hand + '][subConfig=movimento][step=1]';
+ $(baseId + ' .selection-panel-option').off('click').on(
+ 'click', function() {
+ selectionPanel.selectAnOption(baseId, this);
+ dynworkflow.selectMovement($(this).attr('value'));
+ });
+ $(baseId + ' .video-panel-option').off('mouseenter').on('mouseenter',
+ function(event) {
+ $(this).addClass('video-panel-option-hover');
+ });
+ $(baseId + ' .video-panel-option').off('mouseleave').on('mouseleave',
+ function(event) {
+ $(this).removeClass('video-panel-option-hover');
+ });
+ };
+}(window.movement = window.movement || {}, jQuery));
diff --git a/view/js/selection-panel/orientation.js b/view/js/selection-panel/orientation.js
new file mode 100644
index 0000000..ed3da57
--- /dev/null
+++ b/view/js/selection-panel/orientation.js
@@ -0,0 +1,13 @@
+(function(orientation, $, undefined) {
+
+ orientation.setup = function(hand, subConfig, step) {
+ var baseId = '.selection-panel-body[mainConfig=' + hand + '][subConfig=' +
+ subConfig + '][step=' + step + ']';
+ $(baseId + ' .selection-panel-option').off('click').on(
+ 'click', function() {
+ selectionPanel.selectAnOption(baseId, this);
+ dynworkflow.userSelectedAnOption();
+ });
+ };
+
+}(window.orientation = window.orientation || {}, jQuery));
diff --git a/view/js/selection-panel/selection-panel.js b/view/js/selection-panel/selection-panel.js
new file mode 100644
index 0000000..cfcc8b1
--- /dev/null
+++ b/view/js/selection-panel/selection-panel.js
@@ -0,0 +1,194 @@
+(function(selectionPanel, $, undefined) {
+
+ function _selectAnOption(parentId, el) {
+ $(parentId + ' .selection-panel-option[select=true]').removeAttr(
+ 'select');
+ $(el).attr('select', true);
+
+ var mainConfig = $(parentId).attr('mainConfig');
+ var subConfig = $(parentId).attr('subConfig');
+ var step = $(parentId).attr('step');
+ wikilibras.updateTempParameterJSON(mainConfig, subConfig, step, $(el).attr(
+ 'value'));
+ }
+
+ function _canRenderSignVideo() {
+ return _isConfigurationComplete('facial') &&
+ (_isConfigurationComplete('right-hand') || _isConfigurationComplete('left-hand'));
+ }
+
+ function _isConfigurationComplete(config) {
+ var baseId = '.subconfiguration-panel[mainConfig=' + config + ']';
+ var total_config = $(baseId
+ + ' .icon_container[json_name][active=true]').length;
+ var completed_config = $(baseId
+ + ' .icon_container[active=true][complete=true]').length;
+ return completed_config != 0 && total_config == completed_config;
+ }
+
+ function _clearPreviousSelection() {
+ $('.selection-panel-body').hide();
+ $('.subconfiguration-panel').hide();
+
+ if (configurationScreen.isMenuSelected()) {
+ var current_option = configurationScreen.getCurrentMainConfiguration();
+ iconHelper.selectIcon(current_option, false);
+ if (_isConfigurationComplete(current_option)) {
+ iconHelper.setupCheckIcon(current_option, true);
+ }
+ $('#avatar-' + current_option).fadeOut(500);
+ }
+ }
+
+ function _finishConfiguration(config, toFinish) {
+ iconHelper.setupCheckIcon(config, toFinish);
+ iconHelper.setupCheckIcon('avatar-' + config, toFinish);
+
+ if (toFinish) {
+ $('#' + config + '-edit .check-icon').show();
+ } else {
+ $('#' + config + '-edit .check-icon').hide();
+ }
+ if (_canRenderSignVideo()) {
+ $('#ready-button').removeClass('disabled');
+ } else {
+ $('#ready-button').addClass('disabled');
+ }
+ }
+
+ function _unfinishConfiguration(config, panel) {
+ iconHelper.setupCheckIcon(config, false, panel);
+ iconHelper.setupCheckIcon('avatar-' + config, false, panel);
+ $('#' + config + '-edit .check-icon').hide();
+
+ if (!_canRenderSignVideo()) {
+ $('#ready-button').addClass('disabled');
+ }
+ }
+
+ function _addZoomInToAvatar(option, callback) {
+ $('#avatar-default')
+ .fadeOut(
+ 500,
+ function() {
+ $('#avatar-container').removeClass('col-sm-7');
+ $('#avatar-container').addClass('col-sm-5');
+ $('#selection-container').removeClass('col-sm-2');
+ $('#selection-container').addClass('col-sm-4');
+ $('#avatar-container').removeClass(
+ 'avatar-container-zoom-out');
+ $('#avatar-container').addClass(
+ 'avatar-container-zoom-in');
+ $('#avatar-' + option).removeClass(
+ 'avatar-img-zoom-out');
+ $('#avatar-' + option).fadeIn(
+ 500,
+ function() {
+ $('#avatar-' + option).addClass(
+ 'avatar-' + option
+ + '-img-zoom-in');
+ callback();
+ });
+ });
+ }
+
+ function _addZoomOutToAvatar(option, callback) {
+ $('#avatar-' + option).fadeOut(
+ 500,
+ function() {
+ $('#selection-container').removeClass('col-sm-4');
+ $('#selection-container').addClass('col-sm-2');
+ $('#avatar-container').removeClass('col-sm-5');
+ $('#avatar-container').addClass('col-sm-7');
+ $('#avatar-container').removeClass(
+ 'avatar-container-zoom-in');
+ $('#avatar-container')
+ .addClass('avatar-container-zoom-out');
+ $('#avatar-default').fadeIn(
+ 500,
+ function() {
+ $('#avatar-' + option).removeClass(
+ 'avatar-' + option + '-img-zoom-in');
+ $('#avatar-' + option).addClass(
+ 'avatar-img-zoom-out');
+ callback();
+ });
+ });
+ }
+
+ function _hide() {
+ var config = configurationScreen.getCurrentMainConfiguration();
+ if (config === '') return;
+
+ iconHelper.deselectIcon(config);
+ if (_isConfigurationComplete(config)) {
+ _finishConfiguration(config, true);
+ } else {
+ _finishConfiguration(config, false);
+ }
+
+ _addZoomOutToAvatar(config, function() {
+ $('#ready-button').fadeIn(300);
+ $('.edit-container').fadeIn(300);
+ });
+ $('#selection-panel').fadeOut(300);
+ }
+
+ function _setupGUIOnSelection(option, finishCallback) {
+ $('#ready-button').fadeOut(300);
+ $('.edit-container').fadeOut(300);
+ _addZoomInToAvatar(option, function() {
+ $('#selection-panel').fadeIn(300, function() {
+ finishCallback();
+ });
+ });
+ }
+
+ function _show(option) {
+ _clearPreviousSelection();
+ iconHelper.selectIcon(option, true);
+ dynworkflow.selectMainConfig(option);
+ _setupGUIOnSelection(option, function() {
+ dynworkflow.initTimeline();
+ });
+ }
+
+ selectionPanel.selectAnOption = function (parentId, el) {
+ _selectAnOption(parentId, el);
+ }
+
+ selectionPanel.unfinishConfiguration = function(config, panel) {
+ return _unfinishConfiguration(config, panel);
+ }
+
+ selectionPanel.isConfigurationComplete = function(config) {
+ return _isConfigurationComplete(config);
+ }
+
+ selectionPanel.hide = function() {
+ return _hide();
+ }
+
+ selectionPanel.show = function(option) {
+ _show(option);
+ }
+
+ selectionPanel.clean = function() {
+ articulation.clean();
+ $(".selection-panel-option").removeAttr('select');
+ $(".icon_container").removeAttr("select");
+ $(".icon_container[complete=true]").each(
+ function() {
+ _unfinishConfiguration($(this).attr("name"), $(this).attr(
+ "panel"));
+ });
+ }
+
+ selectionPanel.setup = function(url) {
+ $('#selection-panel .x').off('click').on('click', function() {
+ _hide();
+ });
+ selectionPanel.clean();
+ };
+
+}(window.selectionPanel = window.selectionPanel || {}, jQuery));
diff --git a/view/js/submit-sign.js b/view/js/submit-sign.js
new file mode 100644
index 0000000..22d5933
--- /dev/null
+++ b/view/js/submit-sign.js
@@ -0,0 +1,90 @@
+(function(submitSign, $, undefined) {
+
+ var submitUrl = '';
+
+ function _isEmpty(str) {
+ return (!str || 0 === str.length);
+ }
+
+ function _validadeInputFields() {
+ var signName = $('#input-sign-name').val();
+ var state = $('#input-state').val();
+ var city = $('#input-city').val();
+ var signUpload = $('#input-sign-upload').val();
+ return !_isEmpty(signName) && !_isEmpty(state) && !_isEmpty(city)
+ && !_isEmpty(signUpload);
+ }
+
+ function _updateSubmitButton() {
+ if (_validadeInputFields()) {
+ $('#submit-sign-container button').removeClass('disabled');
+ } else {
+ $('#submit-sign-container button').addClass('disabled');
+ }
+ }
+
+ function _resetFormFields() {
+ $('#input-sign-name').val('');
+ $('#input-state').val('');
+ $('#input-city').val('');
+ $('#input-sign-upload').val('');
+ $("#upload-progress .progress-bar").css("width", "0px");
+ $('#upload-progress-container').hide();
+ $('#input-sign-upload').show();
+ }
+
+ submitSign.show = function() {
+ $(".sub-main-container").hide();
+ $("#submit-sign-container").show();
+ $("#submit-sign-anchor").focus();
+ }
+
+ submitSign.setup = function(uploadSignHost) {
+ submitUrl = uploadSignHost;
+ $('#submit-sign-container form').fileupload(
+ {
+ url : submitUrl,
+ add: function (e, data) {
+ $('#submit-sign-container button').off('click').on('click', function (event) {
+ event.preventDefault();
+
+ $('#submit-sign-container button').addClass('disabled');
+ $('#input-sign-upload').hide();
+ $('#upload-progress-container').show();
+ data.submit();
+ });
+ },
+ done : function(e, data) {
+ $('#upload-success-msg').fadeIn(500);
+ setTimeout(function() {
+ _resetFormFields();
+ $('#upload-success-msg').fadeOut(500);
+ }, 5000);
+ },
+ progressall : function(e, data) {
+ var progress = parseInt(data.loaded / data.total * 100,
+ 10);
+ $("#upload-progress .progress-bar").attr('aria-valuenow', progress).
+ css("width", progress + "%");
+ },
+ error : function(error) {
+ alert(error.responseText);
+ },
+ replaceFileInput: false
+ });
+
+ $('#input-sign-name').on('input', function() {
+ _updateSubmitButton();
+ });
+ $('#input-state').on('input', function() {
+ _updateSubmitButton();
+ });
+ $('#input-city').on('input', function() {
+ _updateSubmitButton();
+ });
+ $('#input-sign-upload').on('change', function() {
+ _updateSubmitButton();
+ });
+ };
+
+}(window.submitSign = window.submitSign || {}, jQuery));
diff --git a/view/js/teached-signs.js b/view/js/teached-signs.js
new file mode 100644
index 0000000..af3e546
--- /dev/null
+++ b/view/js/teached-signs.js
@@ -0,0 +1,78 @@
+(function(teachedSigns, $, undefined) {
+
+ var totalTasks = 0;
+ var doneTasks = 0;
+ var userId = -1;
+ var projectId = -1;
+
+ function _updateTeachedSignsMessage() {
+ $(".teached-signs-msg").hide();
+ if (doneTasks == 0) {
+ $(".teached-signs-msg[type=none]").show();
+ } else if (doneTasks == 1) {
+ $(".teached-signs-msg[type=one]").show();
+ } else {
+ $(".teached-signs-msg[type=more] span").text(doneTasks);
+ $(".teached-signs-msg[type=more]").show();
+ }
+ }
+
+ function _createSigns(answers) {
+ _updateTeachedSignsMessage();
+ $("#signs-list-container").html("");
+ for (i = 0; i < answers.length; i++) {
+ _addSign(answers[i].info);
+ }
+ }
+
+ function _addSign(answer) {
+ var signName = answer.parameter_json.sinal;
+ var apiUserId = answer.parameter_json.userId;
+ var videoUrl = renderSign.getRenderedAvatarUrl(apiUserId, signName);
+ $("#signs-list-container").append(
+ '
'
+ + signName + '
');
+ $("#signs-list-container .col-btn[sign-name=" + signName + "]")
+ .off("click")
+ .on(
+ "click",
+ function() {
+ $('#teached-sign-video-container')
+ .html(
+ "
Sem suporte a vídeos ");
+ $('#teached-sign-name').html(signName);
+ $('#teached-sign-modal').modal('show');
+ });
+ }
+
+ function _updateTeachedSignsContainer() {
+ pybossaApiHelper.getAnswers(projectId, userId).done(function(answers) {
+ _createSigns(answers);
+ });
+ }
+
+ teachedSigns.show = function() {
+ $(".sub-main-container").hide();
+ $("#teached-signs-container").show();
+ }
+
+ teachedSigns.setup = function() {
+ pybossaApiHelper.getProjectId().done(function(response) {
+ if (typeof response == "undefined" || response.length < 1) {
+ return;
+ }
+ projectId = response[0].id;
+ pybossaApiHelper.getUserProgress().done(function(response) {
+ totalTasks = response.total;
+ doneTasks = response.done;
+ userId = response.user_id;
+ _updateTeachedSignsContainer();
+ });
+ });
+ };
+
+}(window.teachedSigns = window.teachedSigns || {}, jQuery));
diff --git a/view/js/wikilibras.js b/view/js/wikilibras.js
new file mode 100644
index 0000000..8e0405d
--- /dev/null
+++ b/view/js/wikilibras.js
@@ -0,0 +1,266 @@
+(function(wikilibras, $, undefined) {
+
+ var videosUrl = '';
+ var baseUrl = '';
+ var serverBackendUrl = '';
+ var apiUrl = '';
+ var uploadSignsUrl = '';
+ var currentTaskId = -1;
+ var tmpParameterJSON = {};
+ var parsedParameterJSON = {};
+ var pybossaEndpoint = '';
+ var projectName = '';
+ var isDemoTask = false;
+
+ function _setupTmpParameterJSON(sign_name) {
+ tmpParameterJSON = {
+ 'sinal' : sign_name,
+ 'userId' : _getLoggedUser(),
+ 'facial' : {},
+ 'right-hand' : {},
+ 'left-hand' : {}
+ };
+ parsedParameterJSON = {};
+ }
+
+ function _getLoggedUser() {
+ var pybossaRememberToken = Cookies.get('remember_token');
+ var splittedTokenId = pybossaRememberToken.split('|');
+ return splittedTokenId.length > 0 ? splittedTokenId[0]
+ : 'anonymous';
+ }
+
+ function _loadTaskInfo(task) {
+ currentTaskId = task.id;
+ var signName = task.info.sign_name;
+ var refVidLink = videosUrl + signName + '_REF.webm';
+ $('.sign-label').text(signName);
+ $('.ref-video').attr('src', refVidLink);
+
+ _setupTmpParameterJSON(task.info.sign_name);
+ }
+
+ function _updateTempParameterJSON(mainConfig, subConfig, step, value) {
+ var subConfigJSON = tmpParameterJSON[mainConfig][subConfig];
+ if (typeof subConfigJSON == 'undefined') {
+ tmpParameterJSON[mainConfig][subConfig] = [];
+ subConfigJSON = tmpParameterJSON[mainConfig][subConfig];
+ }
+ subConfigJSON[parseInt(step) - 1] = value;
+ }
+
+ function _parseTmpParameterJSON() {
+ parsedParameterJSON = tmpJSONParser.parse(tmpParameterJSON,
+ selectionPanel.isConfigurationComplete('right-hand'),
+ selectionPanel.isConfigurationComplete('left-hand'));
+ return parsedParameterJSON;
+ }
+
+ function _showInitialScreen(toShow) {
+ if (toShow) {
+ $("#initial-screen").fadeIn(300);
+ videoHelper.play("#initial-screen video");
+ } else {
+ $("#initial-screen").hide();
+ videoHelper.pause("#initial-screen video");
+ }
+ }
+
+ function _showApprovalScreen(toShow, parameterJSON) {
+ if (toShow) {
+ $("#render-button-container .btn").hide();
+ $("#approval-button").show();
+ $("#approval-msg").show();
+ renderSign.showRenderedAvatar(parameterJSON);
+ } else {
+ $("#approval-button").hide();
+ $("#approval-msg").hide();
+ }
+ }
+
+ function _submitAnswer(task, deferred, status) {
+ if (!isDemoTask) {
+ var answer = _createAnswer(task, status);
+ if (status == "APPROVED") {
+ _finishTask(task, deferred, answer);
+ } else {
+ _saveAnswer(task, deferred, answer);
+ }
+ }
+ renderSign.showRenderScreen(false);
+ $("#thanks-screen").show();
+ }
+
+ function _setupMainScreen(task, deferred) {
+ var lastAnswer = task.info.last_answer;
+ var hasLastAnswer = typeof lastAnswer != "undefined";
+ if (hasLastAnswer) {
+ _showApprovalScreen(true, lastAnswer.parameter_json);
+ } else {
+ _showApprovalScreen(false);
+ _showInitialScreen(true);
+ }
+ $("#start-button").off("click").on("click", function() {
+ _showInitialScreen(false);
+ configurationScreen.show(true);
+ });
+ $("#ready-button").off("click").on("click", function() {
+ if ($(this).hasClass('disabled')) {
+ event.preventDefault();
+ return;
+ }
+ renderSign.submit(_parseTmpParameterJSON());
+ });
+ $("#finish-button").off("click").on("click", function() {
+ if ($(this).hasClass('disabled')) {
+ event.preventDefault();
+ return;
+ }
+ _submitAnswer(task, deferred, "FINISHED");
+ });
+ $("#approval-button").off("click").on("click", function() {
+ _submitAnswer(task, deferred, "APPROVED");
+ });
+ }
+
+ function _setupGUI(task, deferred) {
+ configurationScreen.setup();
+ _setupMainScreen(task, deferred);
+ }
+
+ function _createAnswer(task, status) {
+ var answer = {}
+ answer["status"] = status;
+ var lastAnswer = task.info.last_answer;
+ var hasLastAnswer = typeof lastAnswer != "undefined";
+
+ if (hasLastAnswer && status == "APPROVED") {
+ answer["number_of_approval"] = lastAnswer.number_of_approval + 1;
+ answer["parameter_json"] = lastAnswer.parameter_json;
+ } else {
+ answer["number_of_approval"] = 0;
+ answer["parameter_json"] = parsedParameterJSON;
+ }
+ return answer;
+ }
+
+ function _finishTask(task, deferred, answer) {
+ var lastAnswer = task.info.last_answer;
+ var hasLastAnswer = typeof lastAnswer != "undefined";
+ var toSubmitUserId = hasLastAnswer ? lastAnswer.parameter_json["userId"]
+ : _getLoggedUser();
+ $.ajax({
+ type : "POST",
+ url : serverBackendUrl + "/finish_task",
+ data : {
+ "task_id" : task.id,
+ "project_id" : task.project_id,
+ "user_id" : toSubmitUserId,
+ "sign_name" : task.info.sign_name,
+ "number_of_approval" : answer.number_of_approval
+ },
+ success : function(response) {
+ _saveAnswer(task, deferred, answer);
+ },
+ error : function(xhr, textStatus, error) {
+ alert(xhr.responseText);
+ }
+ });
+ }
+
+ function _saveAnswer(task, deferred, answer) {
+ pybossa.saveTask(task.id, answer).done(function() {
+ setTimeout(function() {
+ $("#thanks-screen").hide();
+ deferred.resolve();
+ }, 2500);
+ });
+ }
+
+ function _showCompletedAllTaskMsg() {
+ $("#completed-task-msg").hide();
+ $("#completed-all-task-msg").show();
+ $("#thanks-screen").fadeIn(300);
+ }
+
+ function _setupLoginContainer() {
+ if ($("#login-container").html() === "") {
+ $("#login-container").html(
+ $("#main-navbar-collapse .navbar-right li").html());
+ }
+ }
+
+ function _loadMainComponents() {
+ pybossaApiHelper.setup(pybossaEndpoint, projectName);
+ loadHtmlHelper.setup(baseUrl);
+ iconHelper.setup(baseUrl);
+ dynworkflow.setup(baseUrl);
+ submitSign.setup(uploadSignsUrl);
+ teachedSigns.setup();
+ renderSign.setup(apiUrl);
+ ranking.setup(baseUrl, pybossaEndpoint, projectName,
+ _getLoggedUser());
+ _setupLoginContainer();
+ }
+
+ function _showDemoTask() {
+ isDemoTask = true;
+ var task = {'info':{'sign_name':'CALAR'}};
+ _startTask(task, function() {});
+ }
+
+ function _startTask(task, deferred) {
+ _loadTaskInfo(task);
+ _setupGUI(task, deferred);
+ $("#thanks-screen").hide();
+ $("#main-container").fadeIn(500);
+ }
+
+ pybossa.presentTask(function(task, deferred) {
+ _loadMainComponents();
+ if (!$.isEmptyObject(task) && currentTaskId != task.id) {
+ _startTask(task, deferred);
+ } else {
+ _showCompletedAllTaskMsg();
+ }
+ });
+
+ // Private methods
+ function _run(projectname) {
+ pybossa.setEndpoint(pybossaEndpoint);
+ pybossa.run(projectname);
+ }
+
+ // Public methods
+ wikilibras.run = function(serverhost, serverbackend, projname, apihost,
+ uploadsignshost) {
+ baseUrl = serverhost;
+ serverBackendUrl = serverbackend;
+ videosUrl = baseUrl + "/videos/";
+ apiUrl = apihost;
+ uploadSignsUrl = uploadsignshost;
+ pybossaEndpoint = '/pybossa';
+ projectName = projname;
+ _run(projectName);
+ };
+
+ wikilibras.updateTempParameterJSON = function(mainConfig, subConfig, step,
+ value) {
+ _updateTempParameterJSON(mainConfig, subConfig, step, value);
+ }
+
+ wikilibras.showTeachContainer = function() {
+ $(".sub-main-container").hide();
+ $("#teach-container").show();
+ }
+
+ wikilibras.showTutorialContainer = function() {
+ $(".sub-main-container").hide();
+ $("#tutorial-container").show();
+ }
+
+ wikilibras.showDemoTask = function() {
+ _showDemoTask();
+ }
+
+}(window.wikilibras = window.wikilibras || {}, jQuery));
\ No newline at end of file
diff --git a/view/ranking/ranking.html b/view/ranking/ranking.html
deleted file mode 100644
index 374e8d4..0000000
--- a/view/ranking/ranking.html
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
WikiRanking
-
Lorem Ipsum é apenas uma simulação de texto da indústria
- tipográfica e de impressos, e vem sendo utilizado desde o século XVI.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #
-
- Membro
-
- Sinais
-
-
-
-
-
-
\ No newline at end of file
diff --git a/view/template.html b/view/template.html
deleted file mode 100755
index 8157de8..0000000
--- a/view/template.html
+++ /dev/null
@@ -1,375 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Ajude a criar o sinal .
-
-
-
-
-
-
-
-
Vídeo de referência " "
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- O sinal " " feito pelo avatar está
- correto?
-
-
-
Vídeo de referência
-
-
-
-
-
-
-
-
-
- Sinal " " construído
-
-
-
-
-
-
-
-
-
-
- Gerando o sinal " "
-
-
-
-
-
-
-
-
-
-
-
-
-
Obrigado,
- você configurou o sinal com sucesso!
-
-
-
- Que pena, não há disponíveis sinais no momento!
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/view/templates/facial/duracao/passo-1.html b/view/templates/facial/duracao/passo-1.html
new file mode 100644
index 0000000..364f707
--- /dev/null
+++ b/view/templates/facial/duracao/passo-1.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
Longa
+
+
+
+
+
+
+
Normal
+
+
+
+
+
+
+
Breve
+
+
+
\ No newline at end of file
diff --git a/view/templates/facial/expressao/passo-1.html b/view/templates/facial/expressao/passo-1.html
new file mode 100644
index 0000000..849b3d4
--- /dev/null
+++ b/view/templates/facial/expressao/passo-1.html
@@ -0,0 +1,54 @@
+
+
\ No newline at end of file
diff --git a/view/templates/facial/timeline.html b/view/templates/facial/timeline.html
new file mode 100644
index 0000000..bea08c9
--- /dev/null
+++ b/view/templates/facial/timeline.html
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
diff --git a/view/templates/facial/transicao/passo-1.html b/view/templates/facial/transicao/passo-1.html
new file mode 100644
index 0000000..b818f59
--- /dev/null
+++ b/view/templates/facial/transicao/passo-1.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
Lento
+
+
+
+
+
+
+
Normal
+
+
+
+
+
+
+
Rápido
+
+
+
\ No newline at end of file
diff --git a/view/templates/hand/articulacao-retilineo/passo-1.html b/view/templates/hand/articulacao-retilineo/passo-1.html
new file mode 100644
index 0000000..1b79a4f
--- /dev/null
+++ b/view/templates/hand/articulacao-retilineo/passo-1.html
@@ -0,0 +1,181 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/templates/hand/articulacao-retilineo/passo-2.html b/view/templates/hand/articulacao-retilineo/passo-2.html
new file mode 100644
index 0000000..e694155
--- /dev/null
+++ b/view/templates/hand/articulacao-retilineo/passo-2.html
@@ -0,0 +1,68 @@
+
+
+
diff --git a/view/templates/hand/articulacao-retilineo/passo-3.html b/view/templates/hand/articulacao-retilineo/passo-3.html
new file mode 100644
index 0000000..137d9e2
--- /dev/null
+++ b/view/templates/hand/articulacao-retilineo/passo-3.html
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/templates/hand/articulacao-retilineo/passo-4.html b/view/templates/hand/articulacao-retilineo/passo-4.html
new file mode 100644
index 0000000..4f571a7
--- /dev/null
+++ b/view/templates/hand/articulacao-retilineo/passo-4.html
@@ -0,0 +1,67 @@
+
+
diff --git a/view/templates/hand/articulacao/passo-1.html b/view/templates/hand/articulacao/passo-1.html
new file mode 100644
index 0000000..5341222
--- /dev/null
+++ b/view/templates/hand/articulacao/passo-1.html
@@ -0,0 +1,180 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/templates/hand/articulacao/passo-2.html b/view/templates/hand/articulacao/passo-2.html
new file mode 100644
index 0000000..8c01a66
--- /dev/null
+++ b/view/templates/hand/articulacao/passo-2.html
@@ -0,0 +1,65 @@
+
+
diff --git a/view/templates/hand/configuracao-retilineo/passo-1.html b/view/templates/hand/configuracao-retilineo/passo-1.html
new file mode 100644
index 0000000..ba2a36c
--- /dev/null
+++ b/view/templates/hand/configuracao-retilineo/passo-1.html
@@ -0,0 +1,30 @@
+
+
diff --git a/view/templates/hand/configuracao-retilineo/passo-2.html b/view/templates/hand/configuracao-retilineo/passo-2.html
new file mode 100644
index 0000000..48ac35c
--- /dev/null
+++ b/view/templates/hand/configuracao-retilineo/passo-2.html
@@ -0,0 +1,214 @@
+
+
diff --git a/view/templates/hand/configuracao-retilineo/passo-3.html b/view/templates/hand/configuracao-retilineo/passo-3.html
new file mode 100644
index 0000000..96da69c
--- /dev/null
+++ b/view/templates/hand/configuracao-retilineo/passo-3.html
@@ -0,0 +1,30 @@
+
+
diff --git a/view/templates/hand/configuracao-retilineo/passo-4.html b/view/templates/hand/configuracao-retilineo/passo-4.html
new file mode 100644
index 0000000..5726508
--- /dev/null
+++ b/view/templates/hand/configuracao-retilineo/passo-4.html
@@ -0,0 +1,214 @@
+
+
diff --git a/view/templates/hand/configuracao/passo-1.html b/view/templates/hand/configuracao/passo-1.html
new file mode 100644
index 0000000..225703f
--- /dev/null
+++ b/view/templates/hand/configuracao/passo-1.html
@@ -0,0 +1,30 @@
+
+
diff --git a/view/templates/hand/configuracao/passo-2.html b/view/templates/hand/configuracao/passo-2.html
new file mode 100644
index 0000000..ee1c6ed
--- /dev/null
+++ b/view/templates/hand/configuracao/passo-2.html
@@ -0,0 +1,214 @@
+
+
diff --git a/view/templates/hand/movimento/passo-1.html b/view/templates/hand/movimento/passo-1.html
new file mode 100644
index 0000000..93c36ba
--- /dev/null
+++ b/view/templates/hand/movimento/passo-1.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+ Pontual
+
+
+ Retilíneo
+
+
+ Circular
+
+
+ Semi-Circular
+
+
+
+
+
diff --git a/view/templates/hand/orientacao-retilineo/passo-1.html b/view/templates/hand/orientacao-retilineo/passo-1.html
new file mode 100644
index 0000000..0622eb5
--- /dev/null
+++ b/view/templates/hand/orientacao-retilineo/passo-1.html
@@ -0,0 +1,36 @@
+
+
diff --git a/view/templates/hand/orientacao-retilineo/passo-2.html b/view/templates/hand/orientacao-retilineo/passo-2.html
new file mode 100644
index 0000000..b8a4777
--- /dev/null
+++ b/view/templates/hand/orientacao-retilineo/passo-2.html
@@ -0,0 +1,36 @@
+
+
diff --git a/view/templates/hand/orientacao/passo-1.html b/view/templates/hand/orientacao/passo-1.html
new file mode 100644
index 0000000..f31860f
--- /dev/null
+++ b/view/templates/hand/orientacao/passo-1.html
@@ -0,0 +1,36 @@
+
+
diff --git a/view/templates/hand/plano/passo-1.html b/view/templates/hand/plano/passo-1.html
new file mode 100644
index 0000000..bfcc507
--- /dev/null
+++ b/view/templates/hand/plano/passo-1.html
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+ Baixo - Direita
+
+
+ Cima - Esquerda
+
+
+ Esquerda - Baixo
+
+
+ Direita - Cima
+
+
+ Baixo - Trás
+
+
+ Cima - Frente
+
+
+ Frente - Baixo
+
+
+ Trás - Cima
+
+
+ Frente - Esquerda
+
+
+ Trás - Direita
+
+
+ Esquerda - Trás
+
+
+ Direita - Frente
+
+
+
+
diff --git a/view/templates/hand/raio/passo-1.html b/view/templates/hand/raio/passo-1.html
new file mode 100644
index 0000000..d13070e
--- /dev/null
+++ b/view/templates/hand/raio/passo-1.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+ Pequeno
+
+
+ Médio
+
+
+ Grande
+
+
+
+
diff --git a/view/templates/hand/sentido_inverso/passo-1.html b/view/templates/hand/sentido_inverso/passo-1.html
new file mode 100644
index 0000000..a79cd1a
--- /dev/null
+++ b/view/templates/hand/sentido_inverso/passo-1.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+ Horário
+
+
+ Anti-horário
+
+
+
+
diff --git a/view/templates/hand/timeline.html b/view/templates/hand/timeline.html
new file mode 100644
index 0000000..9f6cd22
--- /dev/null
+++ b/view/templates/hand/timeline.html
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/templates/hand/velocidade/passo-1.html b/view/templates/hand/velocidade/passo-1.html
new file mode 100644
index 0000000..5469f80
--- /dev/null
+++ b/view/templates/hand/velocidade/passo-1.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+ Lento
+
+
+ Normal
+
+
+ Rápido
+
+
+
+
diff --git a/view/templates/index.html b/view/templates/index.html
new file mode 100755
index 0000000..4c9921a
--- /dev/null
+++ b/view/templates/index.html
@@ -0,0 +1,374 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ajude a criar o sinal .
+
+
+
+
+
+
+
+
Vídeo de referência " "
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ O sinal " " feito pelo avatar está
+ correto?
+
+
+
Vídeo de referência
+
+
+
+
+
+
+
+
+
+ Sinal " " construído
+
+
+
+
+
+
+
+
+
+
+ Gerando o sinal " "
+
+
+
+
+
+
+
+
+
+
+
+
+
Obrigado,
+ você configurou o sinal com sucesso!
+
+
+
+ Que pena, não há disponíveis sinais no momento!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/templates/ranking/ranking.html b/view/templates/ranking/ranking.html
new file mode 100644
index 0000000..374e8d4
--- /dev/null
+++ b/view/templates/ranking/ranking.html
@@ -0,0 +1,47 @@
+
+
WikiRanking
+
Lorem Ipsum é apenas uma simulação de texto da indústria
+ tipográfica e de impressos, e vem sendo utilizado desde o século XVI.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+
+ Membro
+
+ Sinais
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wikilibras.py b/wikilibras.py
index ebf7642..0b7fafd 100644
--- a/wikilibras.py
+++ b/wikilibras.py
@@ -27,7 +27,7 @@ class Wikilibras:
self.__update_project_info(project)
def __update_project_info(self, project):
- template = self.env.get_template('template.html')
+ template = self.env.get_template('index.html')
project.info['task_presenter'] = template.render(server=self.config['HOST_STATIC_FILES_ENDPOINT'], server_backend=self.config['HOST_ENDPOINT'], app_shortname=self.config['PYBOSSA_APP_SHORT_NAME'], api_host=self.config['API_HOST'], homepage_url=self.config['HOMEPAGE_URL'], upload_sign_host=self.config['UPLOAD_SIGN_HOST'])
project.info['thumbnail'] = self.config['HOST_STATIC_FILES_ENDPOINT'] + "/img/thumbnail.png"
project.info['sched'] = "incremental"
--
libgit2 0.21.2