Merge remote-tracking branch 'origin/master'
12
build.gradle
|
@ -60,6 +60,18 @@ dependencies {
|
||||||
|
|
||||||
compile group: 'commons-lang', name: 'commons-lang', version: '2.6'
|
compile group: 'commons-lang', name: 'commons-lang', version: '2.6'
|
||||||
|
|
||||||
|
|
||||||
|
compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20'
|
||||||
|
|
||||||
|
/*activiti start*/
|
||||||
|
compile group: 'org.activiti', name: 'activiti-spring-boot-starter-basic', version: '6.0.0'
|
||||||
|
|
||||||
|
/*activiti在线编辑器相关*/
|
||||||
|
compile group: 'org.activiti', name: 'activiti-json-converter', version: '6.0.0'
|
||||||
|
compile group: 'org.apache.xmlgraphics', name: 'batik-codec', version: '1.7'
|
||||||
|
/*activiti end*/
|
||||||
|
|
||||||
|
|
||||||
compileOnly 'org.springframework.boot:spring-boot-configuration-processor'
|
compileOnly 'org.springframework.boot:spring-boot-configuration-processor'
|
||||||
|
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package cn.palmte.work.config.activiti;
|
||||||
|
|
||||||
|
public class ActConstant {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程启动用户变量
|
||||||
|
*/
|
||||||
|
public static final String START_PROCESS_USERID="startUserId";
|
||||||
|
|
||||||
|
|
||||||
|
public static final String PROC_INS_ID="procInsId";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第一个用户任务 即:发起申请任务
|
||||||
|
*/
|
||||||
|
public static final int TASK_INDEX_FIRST_USER_TASK= 1;
|
||||||
|
|
||||||
|
public static final int TYPE_APPROVE= 1;
|
||||||
|
public static final int TYPE_ROLLBACK= 2;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package cn.palmte.work.config.activiti;
|
||||||
|
|
||||||
|
import org.activiti.spring.SpringProcessEngineConfiguration;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class ActivitiConfig {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
PlatformTransactionManager transactionManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
DataSource dataSource;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public SpringProcessEngineConfiguration getProcessEngineConfiguration() {
|
||||||
|
SpringProcessEngineConfiguration config = new SpringProcessEngineConfiguration();
|
||||||
|
config.setDataSource(dataSource);
|
||||||
|
config.setTransactionManager(transactionManager);
|
||||||
|
config.setDbHistoryUsed(true);
|
||||||
|
config.setHistory("full");
|
||||||
|
config.setActivityFontName("宋体");
|
||||||
|
|
||||||
|
//数据库更新策略
|
||||||
|
//flase: 默认值。activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。(生产环境常用)
|
||||||
|
//true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建。(开发时常用)
|
||||||
|
//create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)。(单元测试常用)
|
||||||
|
//drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)。
|
||||||
|
config.setDatabaseSchemaUpdate("true");
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package cn.palmte.work.config.activiti;
|
||||||
|
|
||||||
|
import org.activiti.engine.impl.cmd.NeedsActiveTaskCmd;
|
||||||
|
import org.activiti.engine.impl.interceptor.CommandContext;
|
||||||
|
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
|
||||||
|
import org.activiti.engine.impl.persistence.entity.TaskEntity;
|
||||||
|
import org.activiti.engine.impl.persistence.entity.TaskEntityManagerImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除当前运行时任务命令,并返回当前任务的执行对象id
|
||||||
|
*/
|
||||||
|
public class DeleteTaskCommand extends NeedsActiveTaskCmd<String> {
|
||||||
|
public DeleteTaskCommand(String taskId) {
|
||||||
|
super(taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String execute(CommandContext commandContext, TaskEntity currentTask) {
|
||||||
|
//获取所需服务
|
||||||
|
TaskEntityManagerImpl taskEntityManager = (TaskEntityManagerImpl) commandContext.getTaskEntityManager();
|
||||||
|
//获取当前任务的来源任务及来源节点信息
|
||||||
|
ExecutionEntity executionEntity = currentTask.getExecution();
|
||||||
|
//删除当前任务,来源任务
|
||||||
|
taskEntityManager.deleteTask(currentTask, "jumpReason", false, false);
|
||||||
|
return executionEntity.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSuspendedTaskException() {
|
||||||
|
return "挂起的任务不能跳转";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package cn.palmte.work.config.activiti;
|
||||||
|
|
||||||
|
import org.activiti.bpmn.model.FlowNode;
|
||||||
|
import org.activiti.bpmn.model.SequenceFlow;
|
||||||
|
import org.activiti.engine.ActivitiException;
|
||||||
|
import org.activiti.engine.impl.interceptor.Command;
|
||||||
|
import org.activiti.engine.impl.interceptor.CommandContext;
|
||||||
|
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据提供节点和执行对象id,进行跳转命令
|
||||||
|
*
|
||||||
|
* @author
|
||||||
|
*/
|
||||||
|
public class JumpCommand implements Command<Void> {
|
||||||
|
private FlowNode flowElement;
|
||||||
|
private String executionId;
|
||||||
|
|
||||||
|
public JumpCommand(FlowNode flowElement, String executionId) {
|
||||||
|
this.flowElement = flowElement;
|
||||||
|
this.executionId = executionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void execute(CommandContext commandContext) {
|
||||||
|
//获取目标节点的来源连线
|
||||||
|
List<SequenceFlow> flows = flowElement.getIncomingFlows();
|
||||||
|
if (flows == null || flows.isEmpty()) {
|
||||||
|
throw new ActivitiException("回退错误,目标节点没有来源连线");
|
||||||
|
}
|
||||||
|
|
||||||
|
//随便选一条连线来执行,当前执行计划为,从连线流转到目标节点,实现跳转
|
||||||
|
ExecutionEntity executionEntity = commandContext.getExecutionEntityManager().findById(executionId);
|
||||||
|
executionEntity.setCurrentFlowElement(flows.get(0));
|
||||||
|
commandContext.getAgenda().planTakeOutgoingSequenceFlowsOperation(executionEntity, true);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
package cn.palmte.work.controller.backend;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.palmte.work.bean.ResponseMsg;
|
||||||
|
import cn.palmte.work.service.ActModelService;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程模型
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/actModel")
|
||||||
|
public class ActModelController extends BaseController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActModelController.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActModelService activitiModelService;
|
||||||
|
|
||||||
|
@RequestMapping("/list")
|
||||||
|
public String list(@RequestParam(value = "keywords", required = false) String keywords,
|
||||||
|
@RequestParam(value = PAGE_NUMBER, defaultValue = DEFAULT_PAGE_NUMBER) int pageNumber,
|
||||||
|
@RequestParam(value = PAGE_SIZE, defaultValue = DEFAULT_PAGE_SIZE) int pageSize,
|
||||||
|
Map<String, Object> model) {
|
||||||
|
ConcurrentHashMap<String, String> searchInfo = getSearchInfo(keywords, model);
|
||||||
|
model.put("pager", activitiModelService.list(searchInfo, pageNumber, pageSize));
|
||||||
|
return "/admin/act_model_list";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/add")
|
||||||
|
public String add(Map<String, Object> model) {
|
||||||
|
return "/admin/act_model_input";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/save")
|
||||||
|
public String save(HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
activitiModelService.createModel(request.getParameter("procDefKey"), request.getParameter("modelName"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("", e);
|
||||||
|
}
|
||||||
|
return "redirect:/actModel/list";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ResponseBody
|
||||||
|
@GetMapping(value = "/delete")
|
||||||
|
public ResponseMsg delete(@RequestParam("ids") String ids) {
|
||||||
|
if ("".equals(ids)) {
|
||||||
|
return ResponseMsg.buildFailedMsg("删除失败,无选中项!");
|
||||||
|
} else {
|
||||||
|
String[] deleteIds = ids.split("#%#");
|
||||||
|
for (String id : deleteIds) {
|
||||||
|
activitiModelService.deleteModel(id);
|
||||||
|
}
|
||||||
|
return ResponseMsg.buildSuccessMsg("删除成功");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ResponseBody
|
||||||
|
@GetMapping(value = "/deploy")
|
||||||
|
public ResponseMsg deploy(@RequestParam("id") String id) {
|
||||||
|
try {
|
||||||
|
activitiModelService.deploy(id);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("", e);
|
||||||
|
return ResponseMsg.buildFailedMsg(e.getMessage());
|
||||||
|
}
|
||||||
|
return ResponseMsg.buildSuccessMsg("部署成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
package cn.palmte.work.controller.backend;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import org.activiti.editor.constants.ModelDataJsonConstants;
|
||||||
|
import org.activiti.engine.ActivitiException;
|
||||||
|
import org.activiti.engine.RepositoryService;
|
||||||
|
import org.activiti.engine.repository.Model;
|
||||||
|
import org.apache.batik.transcoder.TranscoderInput;
|
||||||
|
import org.apache.batik.transcoder.TranscoderOutput;
|
||||||
|
import org.apache.batik.transcoder.image.PNGTranscoder;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程网页编辑器
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class ActModelEditorController implements ModelDataJsonConstants {
|
||||||
|
|
||||||
|
protected static final Logger LOGGER = LoggerFactory.getLogger(ActModelEditorController.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RepositoryService repositoryService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取编辑器汉化文件
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ResponseBody
|
||||||
|
@RequestMapping(value = "/editor/stencilset", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
|
||||||
|
public String getStencilset() {
|
||||||
|
InputStream stencilsetStream = this.getClass().getClassLoader().getResourceAsStream("stencilset.json");
|
||||||
|
try {
|
||||||
|
return IOUtils.toString(stencilsetStream, "utf-8");
|
||||||
|
} catch (Exception e) {
|
||||||
|
//logger.error("an exception happens in try catch statement", e);
|
||||||
|
throw new ActivitiException("Error while loading stencil set", e);
|
||||||
|
} finally {
|
||||||
|
if (stencilsetStream != null) {
|
||||||
|
try {
|
||||||
|
stencilsetStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据模型id获取json格式的数据
|
||||||
|
*
|
||||||
|
* @param modelId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "/model/{modelId}/json", method = RequestMethod.GET, produces = "application/json")
|
||||||
|
public ObjectNode getEditorJson(@PathVariable String modelId) {
|
||||||
|
ObjectNode modelNode = null;
|
||||||
|
Model model = repositoryService.getModel(modelId);
|
||||||
|
if (model != null) {
|
||||||
|
try {
|
||||||
|
if (StringUtils.isNotEmpty(model.getMetaInfo())) {
|
||||||
|
modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
|
||||||
|
} else {
|
||||||
|
modelNode = objectMapper.createObjectNode();
|
||||||
|
modelNode.put(MODEL_NAME, model.getName());
|
||||||
|
}
|
||||||
|
modelNode.put(MODEL_ID, model.getId());
|
||||||
|
String content = new String(repositoryService.getModelEditorSource(model.getId()), "utf-8");
|
||||||
|
ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(content);
|
||||||
|
modelNode.put("model", editorJsonNode);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("an exception happens in try catch statement", e);
|
||||||
|
throw new ActivitiException("Error creating model JSON", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modelNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 报错模型数据
|
||||||
|
*
|
||||||
|
* @param modelId
|
||||||
|
* @param values
|
||||||
|
*/
|
||||||
|
@ResponseStatus(value = HttpStatus.OK)
|
||||||
|
@RequestMapping(value = "/model/{modelId}/save", method = RequestMethod.PUT)
|
||||||
|
public void saveModel(@PathVariable String modelId, @RequestParam MultiValueMap<String, String> values) {
|
||||||
|
try {
|
||||||
|
Model model = repositoryService.getModel(modelId);
|
||||||
|
ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
|
||||||
|
modelJson.put(MODEL_NAME, values.getFirst("name"));
|
||||||
|
modelJson.put(MODEL_DESCRIPTION, values.getFirst("description"));
|
||||||
|
model.setMetaInfo(modelJson.toString());
|
||||||
|
model.setName(values.getFirst("name"));
|
||||||
|
repositoryService.saveModel(model);
|
||||||
|
repositoryService.addModelEditorSource(model.getId(), values.getFirst("json_xml").getBytes("utf-8"));
|
||||||
|
InputStream svgStream = new ByteArrayInputStream(values.getFirst("svg_xml").getBytes("utf-8"));
|
||||||
|
TranscoderInput input = new TranscoderInput(svgStream);
|
||||||
|
PNGTranscoder transcoder = new PNGTranscoder();
|
||||||
|
// Setup output
|
||||||
|
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||||
|
TranscoderOutput output = new TranscoderOutput(outStream);
|
||||||
|
// Do the transformation
|
||||||
|
transcoder.transcode(input, output);
|
||||||
|
final byte[] result = outStream.toByteArray();
|
||||||
|
repositoryService.addModelEditorSourceExtra(model.getId(), result);
|
||||||
|
outStream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("an exception happens in try catch statement", e);
|
||||||
|
throw new ActivitiException("Error saving model", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
package cn.palmte.work.controller.backend;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.palmte.work.bean.ResponseMsg;
|
||||||
|
import cn.palmte.work.service.ActProcDefService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程定义
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/actProcDef")
|
||||||
|
public class ActProcDefController extends BaseController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActProcDefController.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActProcDefService actProcDefService;
|
||||||
|
|
||||||
|
@RequestMapping("/list")
|
||||||
|
public String list(@RequestParam(value = "keywords", required = false) String keywords,
|
||||||
|
@RequestParam(value = PAGE_NUMBER, defaultValue = DEFAULT_PAGE_NUMBER) int pageNumber,
|
||||||
|
@RequestParam(value = PAGE_SIZE, defaultValue = DEFAULT_PAGE_SIZE) int pageSize,
|
||||||
|
Map<String, Object> model) {
|
||||||
|
ConcurrentHashMap<String, String> searchInfo = getSearchInfo(keywords, model);
|
||||||
|
model.put("pager", actProcDefService.list(searchInfo, pageNumber, pageSize));
|
||||||
|
return "/admin/act_proc_def_list";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查看默认的未标红的流程图片
|
||||||
|
*
|
||||||
|
* @param response
|
||||||
|
* @param deploymentId
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@RequestMapping("/procDefPng/{deploymentId}")
|
||||||
|
public void png(HttpServletResponse response, @PathVariable("deploymentId") String deploymentId) throws Exception {
|
||||||
|
actProcDefService.createProcDefPng(response, deploymentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查看流程xml
|
||||||
|
*
|
||||||
|
* @param deploymentId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@RequestMapping("/xml/{deploymentId}")
|
||||||
|
public void xml(HttpServletResponse response, @PathVariable("deploymentId") String deploymentId) throws Exception {
|
||||||
|
actProcDefService.getXmlByDeploymentId(response, deploymentId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除流程
|
||||||
|
*
|
||||||
|
* @param ids
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ResponseBody
|
||||||
|
@GetMapping(value = "/delete")
|
||||||
|
public ResponseMsg delete(@RequestParam("ids") String ids) {
|
||||||
|
if ("".equals(ids)) {
|
||||||
|
return ResponseMsg.buildFailedMsg("删除失败,无选中项!");
|
||||||
|
} else {
|
||||||
|
String[] deleteIds = ids.split("#%#");
|
||||||
|
for (String id : deleteIds) {
|
||||||
|
actProcDefService.deleteDeployment(id);
|
||||||
|
}
|
||||||
|
return ResponseMsg.buildSuccessMsg("删除成功");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 挂起与激活
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* @param status 1-激活 2-挂起
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ResponseBody
|
||||||
|
@GetMapping(value = "/suspend")
|
||||||
|
public String suspend(@RequestParam String id, @RequestParam int status) {
|
||||||
|
actProcDefService.suspend(id, status);
|
||||||
|
return "redirect:/actProcDef/list";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
package cn.palmte.work.controller.backend;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.palmte.work.bean.ResponseMsg;
|
||||||
|
import cn.palmte.work.config.activiti.ActConstant;
|
||||||
|
import cn.palmte.work.service.ActProcInsService;
|
||||||
|
import cn.palmte.work.utils.InterfaceUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实列相关
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/actProcIns")
|
||||||
|
public class ActProcInsController extends BaseController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActProcInsController.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActProcInsService actProcInsService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表
|
||||||
|
* @param keywords
|
||||||
|
* @param pageNumber
|
||||||
|
* @param pageSize
|
||||||
|
* @param model
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@RequestMapping("/list")
|
||||||
|
public String list(@RequestParam(value = "keywords", required = false) String keywords,
|
||||||
|
@RequestParam(value = PAGE_NUMBER, defaultValue = DEFAULT_PAGE_NUMBER) int pageNumber,
|
||||||
|
@RequestParam(value = PAGE_SIZE, defaultValue = DEFAULT_PAGE_SIZE) int pageSize,
|
||||||
|
Map<String, Object> model) {
|
||||||
|
ConcurrentHashMap<String, String> searchInfo = getSearchInfo(keywords, model);
|
||||||
|
model.put("pager", actProcInsService.list(searchInfo, pageNumber, pageSize));
|
||||||
|
return "/admin/act_proc_ins_list";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除流程实例
|
||||||
|
*
|
||||||
|
* @param procInsId
|
||||||
|
* @param reason
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ResponseBody
|
||||||
|
@GetMapping(value = "/deleteProcessInstance")
|
||||||
|
public ResponseMsg deleteProcessInstance(@RequestParam String procInsId, @RequestParam String reason) {
|
||||||
|
actProcInsService.deleteProcessInstance(procInsId, reason);
|
||||||
|
return ResponseMsg.buildSuccessMsg("撤销成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实列图片
|
||||||
|
*
|
||||||
|
* @param response
|
||||||
|
* @param procInstId
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@RequestMapping("/procInsPng/{procInstId}")
|
||||||
|
public void png(HttpServletResponse response, @PathVariable("procInstId") String procInstId) throws Exception {
|
||||||
|
actProcInsService.createProcInsPng(response, procInstId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动流程
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ResponseBody
|
||||||
|
@GetMapping(value = "/startProcIns")
|
||||||
|
public ResponseMsg startProcessInstance(@RequestParam String procDefKey) throws Exception{
|
||||||
|
Map<String, Object> variables = new HashMap<>();
|
||||||
|
variables.put(ActConstant.START_PROCESS_USERID, InterfaceUtil.getAdminId());
|
||||||
|
String procInsId = actProcInsService.startProcessInstance(procDefKey, variables);
|
||||||
|
return ResponseMsg.buildSuccessMsg("流程启动成功", procInsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
package cn.palmte.work.controller.backend;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.palmte.work.bean.ResponseMsg;
|
||||||
|
import cn.palmte.work.model.ActScript;
|
||||||
|
import cn.palmte.work.model.ActScriptRepository;
|
||||||
|
import cn.palmte.work.service.ActScriptService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程脚本管理
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/actScript")
|
||||||
|
public class ActScriptController extends BaseController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActScriptController.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActScriptService actScriptService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActScriptRepository actScriptRepository;
|
||||||
|
|
||||||
|
@RequestMapping("/list")
|
||||||
|
public String list(@RequestParam(value = "keywords", required = false) String keywords,
|
||||||
|
@RequestParam(value = PAGE_NUMBER, defaultValue = DEFAULT_PAGE_NUMBER) int pageNumber,
|
||||||
|
@RequestParam(value = PAGE_SIZE, defaultValue = DEFAULT_PAGE_SIZE) int pageSize,
|
||||||
|
Map<String, Object> model) {
|
||||||
|
ConcurrentHashMap<String, String> searchInfo = getSearchInfo(keywords, model);
|
||||||
|
model.put("pager", actScriptService.list(searchInfo, pageNumber, pageSize));
|
||||||
|
return "/admin/act_script_list";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/add")
|
||||||
|
public String add(Map<String, Object> model) {
|
||||||
|
List<String> list = getScriptList();
|
||||||
|
model.put("actScript", new ActScript());
|
||||||
|
model.put("classList", list);
|
||||||
|
|
||||||
|
List<String> methodList = new ArrayList<>();
|
||||||
|
for (String l : list) {
|
||||||
|
methodList.addAll(getMethodList(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
model.put("methodList", methodList);
|
||||||
|
return "/admin/act_script_input";
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getScriptList() {
|
||||||
|
List<String> list = new ArrayList<>(1);
|
||||||
|
list.add("cn.palmte.work.service.ActCallbackScript");
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getMethodList(String className) {
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Method[] methods = Class.forName(className).getDeclaredMethods();
|
||||||
|
for (Method method : methods) {
|
||||||
|
list.add(method.getName());
|
||||||
|
}
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
logger.error("", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/edit")
|
||||||
|
public String edit(@RequestParam int id, Map<String, Object> model) {
|
||||||
|
List<String> list = getScriptList();
|
||||||
|
model.put("actScript", actScriptRepository.findOne(id));
|
||||||
|
model.put("classList", list);
|
||||||
|
List<String> methodList = new ArrayList<>();
|
||||||
|
for (String l : list) {
|
||||||
|
methodList.addAll(getMethodList(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
model.put("methodList", methodList);
|
||||||
|
return "/admin/act_script_input";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/save")
|
||||||
|
public String save(ActScript actScript) {
|
||||||
|
actScriptService.save(actScript);
|
||||||
|
return "redirect:/actScript/list";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ResponseBody
|
||||||
|
@GetMapping(value = "/delete")
|
||||||
|
public ResponseMsg delete(@RequestParam("ids") String ids){
|
||||||
|
if ("".equals(ids)){
|
||||||
|
return ResponseMsg.buildFailedMsg("删除失败,无选中项!");
|
||||||
|
}else {
|
||||||
|
String[] deleteIds=ids.split("#%#");
|
||||||
|
for (String id : deleteIds) {
|
||||||
|
actScriptService.delete(Integer.parseInt(id));
|
||||||
|
}
|
||||||
|
return ResponseMsg.buildSuccessMsg("删除成功");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
package cn.palmte.work.controller.backend;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.palmte.work.bean.ResponseMsg;
|
||||||
|
import cn.palmte.work.model.ActScriptRepository;
|
||||||
|
import cn.palmte.work.model.ActTaskDef;
|
||||||
|
import cn.palmte.work.model.AdminRepository;
|
||||||
|
import cn.palmte.work.service.ActTaskDefService;
|
||||||
|
import cn.palmte.work.service.SysRoleService;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程任务
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/actTaskDef")
|
||||||
|
public class ActTaskDefController extends BaseController {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActTaskDefController.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AdminRepository adminRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SysRoleService sysRoleService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActScriptRepository actScriptRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActTaskDefService actTaskDefService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 去任务配置页面
|
||||||
|
*
|
||||||
|
* @param procDefId
|
||||||
|
* @param model
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@RequestMapping("/config/{procDefId}")
|
||||||
|
public String list(@PathVariable String procDefId, Map<String, Object> model) {
|
||||||
|
List<ActTaskDef> list = actTaskDefService.findByProcDefId(procDefId);
|
||||||
|
model.put("procDefId", procDefId);
|
||||||
|
model.put("taskList", list);
|
||||||
|
model.put("procDefName", list.get(0).getProcDefName());
|
||||||
|
model.put("roleList", sysRoleService.getAllEnableSysRole());
|
||||||
|
model.put("adminList", adminRepository.getAllEnable());
|
||||||
|
model.put("scriptList", actScriptRepository.findAll());
|
||||||
|
|
||||||
|
return "/admin/act_task_def";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务配置保存
|
||||||
|
*
|
||||||
|
* @param taskDef
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ResponseBody
|
||||||
|
@GetMapping(value = "/saveConfig")
|
||||||
|
public ResponseMsg saveConfig(ActTaskDef taskDef) {
|
||||||
|
actTaskDefService.saveConfig(taskDef);
|
||||||
|
return ResponseMsg.buildSuccessMsg("成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完成某个任务
|
||||||
|
* 审批通过或者驳回
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@ResponseBody
|
||||||
|
@PostMapping(value = "/completeTask")
|
||||||
|
public ResponseMsg completeTask(@RequestBody String json) {
|
||||||
|
JSONObject jsonParam = JSON.parseObject(json);
|
||||||
|
actTaskDefService.completeTask(jsonParam);
|
||||||
|
return ResponseMsg.buildSuccessMsg("处理成功");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package cn.palmte.work.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程脚本
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Entity
|
||||||
|
@Table(name = "act_script")
|
||||||
|
public class ActScript {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
@Column(name = "script_name")
|
||||||
|
private String scriptName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 脚本所在类
|
||||||
|
*/
|
||||||
|
@Column(name = "class_name")
|
||||||
|
private String className;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 脚本方法名
|
||||||
|
*/
|
||||||
|
@Column(name = "class_method")
|
||||||
|
private String classMethod;
|
||||||
|
|
||||||
|
@Column(name = "created_time")
|
||||||
|
private Date createdTime;
|
||||||
|
|
||||||
|
@Column(name = "last_updated_time")
|
||||||
|
private Date lastUpdatedTime;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package cn.palmte.work.model;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
|
||||||
|
public interface ActScriptRepository extends JpaRepository<ActScript, Integer> {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
package cn.palmte.work.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程图里解析出来的任务定义
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Entity
|
||||||
|
@Table(name = "act_task_def")
|
||||||
|
public class ActTaskDef {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务名称
|
||||||
|
*/
|
||||||
|
@Column(name = "task_name")
|
||||||
|
private String taskName;
|
||||||
|
|
||||||
|
@Column(name = "task_key")
|
||||||
|
private String taskKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务类型 0-单实例(或签) 1-多实例(会签)
|
||||||
|
*/
|
||||||
|
@Column(name = "task_type")
|
||||||
|
private int taskType;
|
||||||
|
|
||||||
|
@Column(name = "proc_def_id")
|
||||||
|
private String procDefId;
|
||||||
|
|
||||||
|
@Column(name = "proc_def_name")
|
||||||
|
private String procDefName;
|
||||||
|
|
||||||
|
@Column(name = "proc_def_key")
|
||||||
|
private String procDefKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回退任务key
|
||||||
|
*/
|
||||||
|
@Column(name = "rollback_task_key")
|
||||||
|
private String rollbackTaskKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点位置 -1结束节点 0-开始节点 1-第一个用户任务
|
||||||
|
*/
|
||||||
|
@Column(name = "task_index")
|
||||||
|
private int taskIndex;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 候选人
|
||||||
|
*/
|
||||||
|
@Column(name = "candidate_users")
|
||||||
|
private String candidateUsers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 候选角色
|
||||||
|
*/
|
||||||
|
@Column(name = "candidate_roles")
|
||||||
|
private String candidateRoles;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批通过执行的脚本 act_script表id
|
||||||
|
*/
|
||||||
|
@Column(name = "end_script")
|
||||||
|
private int endScript;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审批驳回执行的脚本 act_script表id
|
||||||
|
*/
|
||||||
|
@Column(name = "rollback_script")
|
||||||
|
private int rollbackScript;
|
||||||
|
|
||||||
|
@Column(name = "created_time")
|
||||||
|
private Date createdTime;
|
||||||
|
|
||||||
|
@Column(name = "last_updated_time")
|
||||||
|
private Date lastUpdatedTime;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private List<String> candidateUserList;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private List<String> candidateRoleList;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package cn.palmte.work.model;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ActTaskDefRepository extends JpaRepository<ActTaskDef, Integer> {
|
||||||
|
|
||||||
|
|
||||||
|
List<ActTaskDef> findByProcDefId(String procDefId);
|
||||||
|
|
||||||
|
|
||||||
|
ActTaskDef findFirstByProcDefIdAndTaskKey(String procDefId, String taskKey);
|
||||||
|
|
||||||
|
void deleteByProcDefId(String procDefId);
|
||||||
|
}
|
|
@ -34,4 +34,13 @@ public interface AdminRepository extends JpaRepository<Admin, Integer> {
|
||||||
|
|
||||||
@Query("from Admin where isDeleted=0 AND telephone=?1")
|
@Query("from Admin where isDeleted=0 AND telephone=?1")
|
||||||
Admin findByTelephone(String phone);
|
Admin findByTelephone(String phone);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有未删除启用的账号
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Query("from Admin where isDeleted=0 AND enabled=1")
|
||||||
|
List<Admin> getAllEnable();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package cn.palmte.work.pojo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ActModel {
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
private String modelName;
|
||||||
|
|
||||||
|
private int rev;
|
||||||
|
|
||||||
|
private String procDefKey;
|
||||||
|
|
||||||
|
private Date createdTime;
|
||||||
|
|
||||||
|
private Date lastUpdatedTime;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package cn.palmte.work.pojo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ActProcDef {
|
||||||
|
private String id;
|
||||||
|
private String procName;
|
||||||
|
private String procKey;
|
||||||
|
private String version;
|
||||||
|
private String deploymentId;
|
||||||
|
private String resourceName;
|
||||||
|
private String dgrmResourceName;
|
||||||
|
private Date deployTime;
|
||||||
|
private int suspensionState;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package cn.palmte.work.pojo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ActProcIns {
|
||||||
|
private String procInsId;
|
||||||
|
private String procName;
|
||||||
|
private String procKey;
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
private String user;
|
||||||
|
private Date startTime;
|
||||||
|
|
||||||
|
private String currentTask;
|
||||||
|
private String currentTaskId;
|
||||||
|
private String candidateUsers;
|
||||||
|
|
||||||
|
private Date endTime;
|
||||||
|
|
||||||
|
}
|
|
@ -17,15 +17,15 @@ import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import top.jfunc.common.db.QueryHelper;
|
import top.jfunc.common.db.QueryHelper;
|
||||||
import top.jfunc.common.db.bean.Page;
|
import top.jfunc.common.db.bean.Page;
|
||||||
|
import top.jfunc.common.db.bean.Record;
|
||||||
import top.jfunc.common.db.utils.Pagination;
|
import top.jfunc.common.db.utils.Pagination;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.beans.Transient;
|
import java.beans.Transient;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by wang.lin@esstx.cn on 2018/4/20.
|
* Created by wang.lin@esstx.cn on 2018/4/20.
|
||||||
|
@ -260,4 +260,38 @@ public class AccountService {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过id查询姓名
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String getNameById(int id) {
|
||||||
|
Admin one = adminRepository.findOne(id);
|
||||||
|
return one == null ? "" : one.getRealName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过角色id查询用户姓名列表
|
||||||
|
* @param roleIds
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<String> getUserIsByRole(List<String> roleIds) {
|
||||||
|
if (roleIds == null || roleIds.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
String sql = "select u.id as id from sys_user_role ur left join sys_user u on u.id=ur.user_id where ur.role_id in (?)";
|
||||||
|
String ids = roleIds.stream().collect(Collectors.joining());
|
||||||
|
List<Record> records = pagination.find(sql, ids);
|
||||||
|
if (records == null || records.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> userIds = new ArrayList<>(roleIds.size());
|
||||||
|
for (Record record : records) {
|
||||||
|
userIds.add(record.getInt("id") + "");
|
||||||
|
}
|
||||||
|
return userIds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package cn.palmte.work.service;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.palmte.work.config.activiti.ActConstant;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程回调脚本 参数必须为Map
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ActCallbackScript {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActCallbackScript.class);
|
||||||
|
|
||||||
|
|
||||||
|
public void endScriptDemo(Map map) {
|
||||||
|
logger.info("--- endScriptDemo--- : {} ", map);
|
||||||
|
String startUserId = (String)map.get(ActConstant.START_PROCESS_USERID);
|
||||||
|
String procInsId = (String)map.get(ActConstant.START_PROCESS_USERID);
|
||||||
|
logger.info(" startUserId:{}, procInsId:{}", startUserId, procInsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void rollbackScriptDemo(Map map) {
|
||||||
|
logger.info("--- rollbackScriptDemo--- : {} ", map);
|
||||||
|
String startUserId = (String)map.get(ActConstant.START_PROCESS_USERID);
|
||||||
|
String procInsId = (String)map.get(ActConstant.START_PROCESS_USERID);
|
||||||
|
logger.info(" startUserId:{}, procInsId:{}", startUserId, procInsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package cn.palmte.work.service;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import org.activiti.engine.delegate.DelegateTask;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程节点创建监听
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class ActListenerService {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActListenerService.class);
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActTaskDefService actTaskDefService;
|
||||||
|
|
||||||
|
public void create(DelegateTask delegateTask) throws Exception {
|
||||||
|
logger.info("--- {}", JSONObject.toJSONString(delegateTask));
|
||||||
|
|
||||||
|
// 每一个任务节点监听运行时都要初始化流程定义规则数据到 流程引擎中
|
||||||
|
String procDefId = delegateTask.getProcessDefinitionId();
|
||||||
|
String procInsId = delegateTask.getProcessInstanceId();
|
||||||
|
String taskDefKey = delegateTask.getTaskDefinitionKey();
|
||||||
|
Set<String> candidateUsers = actTaskDefService.findCandidateUsers(procDefId, procInsId, taskDefKey);
|
||||||
|
logger.info("addCandidateUsers : {}", candidateUsers);
|
||||||
|
delegateTask.addCandidateUsers(candidateUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
package cn.palmte.work.service;
|
||||||
|
|
||||||
|
import cn.palmte.work.config.activiti.ActConstant;
|
||||||
|
import cn.palmte.work.model.ActTaskDef;
|
||||||
|
import cn.palmte.work.model.ActTaskDefRepository;
|
||||||
|
import cn.palmte.work.pojo.ActModel;
|
||||||
|
import cn.palmte.work.utils.InterfaceUtil;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
import org.activiti.bpmn.converter.BpmnXMLConverter;
|
||||||
|
import org.activiti.bpmn.model.*;
|
||||||
|
import org.activiti.bpmn.model.Process;
|
||||||
|
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
|
||||||
|
import org.activiti.engine.RepositoryService;
|
||||||
|
import org.activiti.engine.delegate.TaskListener;
|
||||||
|
import org.activiti.engine.repository.Deployment;
|
||||||
|
import org.activiti.engine.repository.DeploymentBuilder;
|
||||||
|
import org.activiti.engine.repository.Model;
|
||||||
|
import org.activiti.engine.repository.ProcessDefinition;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import top.jfunc.common.db.QueryHelper;
|
||||||
|
import top.jfunc.common.db.bean.Page;
|
||||||
|
import top.jfunc.common.db.utils.Pagination;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ActModelService {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActModelService.class);
|
||||||
|
@Autowired
|
||||||
|
private RepositoryService repositoryService; //管理流程定义 与流程定义和部署对象相关的Service
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActTaskDefRepository actTaskDefRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
Pagination pagination;
|
||||||
|
|
||||||
|
|
||||||
|
public Page<ActModel> list(ConcurrentHashMap<String, String> searchInfo, int pageNumber, int pageSize) {
|
||||||
|
String select = "a.ID_ as id,a.REV_ as rev,a.NAME_ as modelName,a.KEY_ as procDefKey,a.CREATE_TIME_ as createdTime,a.LAST_UPDATE_TIME_ as lastUpdatedTime";
|
||||||
|
QueryHelper queryHelper = new QueryHelper(select, " act_re_model a");
|
||||||
|
String name = searchInfo.get("name");
|
||||||
|
queryHelper.addCondition(StringUtils.isNotEmpty(name), "a.NAME_=? or a.KEY_=?", name, name);
|
||||||
|
queryHelper.addOrderProperty("a.LAST_UPDATE_TIME_", false);
|
||||||
|
return pagination.paginate(queryHelper.getSql(), ActModel.class, pageNumber, pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createModel(String processId, String modelName) throws Exception {
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
ObjectNode editorNode = objectMapper.createObjectNode();
|
||||||
|
editorNode.put("id", "canvs");
|
||||||
|
editorNode.put("resourceId", "canvs");
|
||||||
|
ObjectNode stencilSetNode = objectMapper.createObjectNode();
|
||||||
|
stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#"); //命名空间(禁止修改)
|
||||||
|
stencilSetNode.put("author", ""); //流程节点作者
|
||||||
|
editorNode.set("stencilset", stencilSetNode);
|
||||||
|
ObjectNode propertiesNode = objectMapper.createObjectNode();
|
||||||
|
propertiesNode.put("process_id", processId); //流程唯一标识
|
||||||
|
propertiesNode.put("process_author", InterfaceUtil.getAdmin().getUserName()); //流程作者
|
||||||
|
propertiesNode.put("name", modelName); //流程名称
|
||||||
|
editorNode.set("properties", propertiesNode);
|
||||||
|
|
||||||
|
ObjectNode modelObjectNode = objectMapper.createObjectNode();
|
||||||
|
modelObjectNode.put("name", modelName); //模型名称
|
||||||
|
modelObjectNode.put("revision", 1); //模型版本
|
||||||
|
modelObjectNode.put("description", ""); //模型描述
|
||||||
|
Model modelData = repositoryService.newModel();
|
||||||
|
//modelData.setCategory(category); //模型分类
|
||||||
|
modelData.setDeploymentId(null);
|
||||||
|
modelData.setKey(processId);
|
||||||
|
modelData.setMetaInfo(modelObjectNode.toString());
|
||||||
|
modelData.setName(modelName); //模型名称
|
||||||
|
modelData.setTenantId("");
|
||||||
|
modelData.setVersion(1);
|
||||||
|
|
||||||
|
//保存模型,存储数据到表:act_re_model 流程设计模型部署表
|
||||||
|
repositoryService.saveModel(modelData);
|
||||||
|
|
||||||
|
repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));//保存资源,存储数据到表:act_ge_bytearray 二进制数据表
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除模型
|
||||||
|
* act_re_model 和 act_ge_bytearray 两张表中相关数据都删除
|
||||||
|
*
|
||||||
|
* @param modelId
|
||||||
|
*/
|
||||||
|
public void deleteModel(String modelId) {
|
||||||
|
repositoryService.deleteModel(modelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部署流程
|
||||||
|
*
|
||||||
|
* @param modelId
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public void deploy(String modelId) throws Exception {
|
||||||
|
Model modelData = repositoryService.getModel(modelId);
|
||||||
|
ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
|
||||||
|
byte[] bpmnBytes = null;
|
||||||
|
BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
|
||||||
|
BpmnModel model = jsonConverter.convertToBpmnModel(modelNode);
|
||||||
|
|
||||||
|
ActivitiListener activitiListener = new ActivitiListener();
|
||||||
|
activitiListener.setEvent(TaskListener.EVENTNAME_CREATE);
|
||||||
|
activitiListener.setImplementation("${actListenerService.create(task)}");
|
||||||
|
activitiListener.setImplementationType(ImplementationType.IMPLEMENTATION_TYPE_EXPRESSION);
|
||||||
|
List<ActivitiListener> activitiListenerList = new ArrayList<>(1);
|
||||||
|
activitiListenerList.add(activitiListener);
|
||||||
|
|
||||||
|
List<ActTaskDef> taskList = new ArrayList<>();
|
||||||
|
Process process = model.getMainProcess();
|
||||||
|
Collection<FlowElement> flowElements = process.getFlowElements();
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
ActTaskDef task;
|
||||||
|
ActTaskDef first = null;
|
||||||
|
for (FlowElement element : flowElements) {
|
||||||
|
if (element instanceof UserTask) {
|
||||||
|
UserTask userTask = (UserTask) element;
|
||||||
|
userTask.setTaskListeners(activitiListenerList);
|
||||||
|
|
||||||
|
task = new ActTaskDef();
|
||||||
|
task.setTaskName(element.getName());
|
||||||
|
task.setTaskKey(element.getId());
|
||||||
|
MultiInstanceLoopCharacteristics loopCharacteristics = ((UserTask) element).getLoopCharacteristics();
|
||||||
|
if (loopCharacteristics != null) {
|
||||||
|
task.setTaskType(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 1) {
|
||||||
|
task.setTaskIndex(ActConstant.TASK_INDEX_FIRST_USER_TASK);
|
||||||
|
first = task;
|
||||||
|
}
|
||||||
|
taskList.add(task);
|
||||||
|
}
|
||||||
|
i ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bpmnBytes = new BpmnXMLConverter().convertToXML(model);
|
||||||
|
String processName = modelData.getName() + ".bpmn20.xml";
|
||||||
|
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment().name(modelData.getName()); //部署名称
|
||||||
|
deploymentBuilder.addString(processName, new String(bpmnBytes, "utf-8"));
|
||||||
|
Deployment deployment = deploymentBuilder.deploy(); //完成部署
|
||||||
|
|
||||||
|
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
|
||||||
|
for (ActTaskDef actTaskDef : taskList) {
|
||||||
|
if (first != null) {
|
||||||
|
actTaskDef.setRollbackTaskKey(first.getTaskKey());
|
||||||
|
}
|
||||||
|
actTaskDef.setProcDefId(processDefinition.getId());
|
||||||
|
actTaskDef.setProcDefName(processDefinition.getName());
|
||||||
|
actTaskDef.setProcDefKey(processDefinition.getKey());
|
||||||
|
actTaskDef.setCreatedTime(new Date());
|
||||||
|
actTaskDef.setLastUpdatedTime(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
actTaskDefRepository.save(taskList);
|
||||||
|
|
||||||
|
logger.info("deploy success: deploymentId:{}, procDefName:{}, procDefKey:{}", deployment.getId(), processDefinition.getName(), processDefinition.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,145 @@
|
||||||
|
package cn.palmte.work.service;
|
||||||
|
|
||||||
|
import cn.palmte.work.model.ActTaskDefRepository;
|
||||||
|
import cn.palmte.work.pojo.ActProcDef;
|
||||||
|
import org.activiti.bpmn.model.*;
|
||||||
|
import org.activiti.engine.ProcessEngine;
|
||||||
|
import org.activiti.engine.RepositoryService;
|
||||||
|
import org.activiti.engine.repository.ProcessDefinition;
|
||||||
|
import org.activiti.image.ProcessDiagramGenerator;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import top.jfunc.common.db.QueryHelper;
|
||||||
|
import top.jfunc.common.db.bean.Page;
|
||||||
|
import top.jfunc.common.db.utils.Pagination;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ActProcDefService {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActProcDefService.class);
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ProcessEngine processEngine; //流程引擎对象
|
||||||
|
@Autowired
|
||||||
|
private RepositoryService repositoryService; //管理流程定义 与流程定义和部署对象相关的Service
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActTaskDefRepository actTaskDefRepository;
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
Pagination pagination;
|
||||||
|
|
||||||
|
|
||||||
|
public Page<ActProcDef> list(ConcurrentHashMap<String, String> searchInfo, int pageNumber, int pageSize) {
|
||||||
|
String select = "select p.ID_ as id,p.NAME_ as procName,p.KEY_ as procKey,p.VERSION_ as version,p.DEPLOYMENT_ID_ as deploymentId,p.RESOURCE_NAME_ as resourceName,\n" +
|
||||||
|
" p.DGRM_RESOURCE_NAME_ as dgrmResourceName,p.SUSPENSION_STATE_ as suspensionState, d.DEPLOY_TIME_ as deployTime ";
|
||||||
|
QueryHelper queryHelper = new QueryHelper(select, " act_re_procdef p LEFT JOIN act_re_deployment d on p.DEPLOYMENT_ID_ = d.ID_");
|
||||||
|
String name = searchInfo.get("name");
|
||||||
|
queryHelper.addCondition(StringUtils.isNotEmpty(name), "p.NAME_=? or p.KEY_=?", name, name);
|
||||||
|
queryHelper.addOrderProperty("p.KEY_,p.VERSION_", false);
|
||||||
|
return pagination.paginate(queryHelper.getSql(), ActProcDef.class, pageNumber, pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void getXmlByDeploymentId(HttpServletResponse response, String deploymentId) throws IOException {
|
||||||
|
InputStream pic=null;
|
||||||
|
try {
|
||||||
|
pic= getXmlStreamByDeploymentId(deploymentId);
|
||||||
|
byte[] b = new byte[1024];
|
||||||
|
int len = -1;
|
||||||
|
while ((len = pic.read(b, 0, 1024)) != -1) {
|
||||||
|
response.getOutputStream().write(b, 0, len);
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
logger.error("an exception happens in try catch statement", e);
|
||||||
|
}finally {
|
||||||
|
if(pic!=null) {
|
||||||
|
pic.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getXmlStreamByDeploymentId(String deploymentId) throws IOException{
|
||||||
|
List<String> names = repositoryService.getDeploymentResourceNames(deploymentId);
|
||||||
|
for (String name : names) {
|
||||||
|
if(name.contains("xml") ) {
|
||||||
|
return repositoryService.getResourceAsStream(deploymentId, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建默认的png
|
||||||
|
*
|
||||||
|
* @param response
|
||||||
|
* @param deploymentId
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void createProcDefPng(HttpServletResponse response, String deploymentId) throws IOException {
|
||||||
|
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
|
||||||
|
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); // 获取bpmnModel
|
||||||
|
InputStream inputStream = generateDiagramInputStream(bpmnModel, new ArrayList<>(), new ArrayList<>());
|
||||||
|
responsePng(response, inputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void responsePng(HttpServletResponse response, InputStream inputStream) throws IOException {
|
||||||
|
InputStream pic = null;
|
||||||
|
try {
|
||||||
|
pic = inputStream;
|
||||||
|
byte[] b = new byte[1024];
|
||||||
|
int len = -1;
|
||||||
|
while ((len = pic.read(b, 0, 1024)) != -1) {
|
||||||
|
response.getOutputStream().write(b, 0, len);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("an exception happens in try catch statement", e);
|
||||||
|
} finally {
|
||||||
|
if (pic != null) {
|
||||||
|
pic.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public InputStream generateDiagramInputStream(BpmnModel bpmnModel, List<String> executedActivityIdList, List<String> flowIds) {
|
||||||
|
try {
|
||||||
|
ProcessDiagramGenerator processDiagramGenerator = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
|
||||||
|
return processDiagramGenerator.generateDiagram(bpmnModel, "png", executedActivityIdList,
|
||||||
|
flowIds, "宋体", "微软雅黑", "黑体", null, 2.0); //使用默认配置获得流程图表生成器,并生成追踪图片字符流
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("an exception happens in try catch statement", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void deleteDeployment(String deploymentId) {
|
||||||
|
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
|
||||||
|
actTaskDefRepository.deleteByProcDefId(processDefinition.getId());
|
||||||
|
|
||||||
|
//repositoryService.deleteDeployment(deploymentId); //不带级联的删除,此删除只能删除没有启动的流程,否则抛出异常 .act_re_deployment,act_re_procdef 和 act_ge_bytearray 三张表中相关数据都删除
|
||||||
|
repositoryService.deleteDeployment(deploymentId, true); //级联删除,不管流程是否启动,都可以删除
|
||||||
|
}
|
||||||
|
|
||||||
|
public void suspend(String procDefId, int status) {
|
||||||
|
if (1 == status) {
|
||||||
|
repositoryService.activateProcessDefinitionById(procDefId, true, null);
|
||||||
|
}else{
|
||||||
|
repositoryService.suspendProcessDefinitionById(procDefId, true, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,299 @@
|
||||||
|
package cn.palmte.work.service;
|
||||||
|
|
||||||
|
import cn.palmte.work.config.activiti.ActConstant;
|
||||||
|
import cn.palmte.work.exception.ResponseException;
|
||||||
|
import cn.palmte.work.pojo.ActProcIns;
|
||||||
|
import cn.palmte.work.utils.InterfaceUtil;
|
||||||
|
import org.activiti.bpmn.model.BpmnModel;
|
||||||
|
import org.activiti.bpmn.model.FlowNode;
|
||||||
|
import org.activiti.bpmn.model.SequenceFlow;
|
||||||
|
import org.activiti.engine.HistoryService;
|
||||||
|
import org.activiti.engine.RepositoryService;
|
||||||
|
import org.activiti.engine.RuntimeService;
|
||||||
|
import org.activiti.engine.TaskService;
|
||||||
|
import org.activiti.engine.history.HistoricActivityInstance;
|
||||||
|
import org.activiti.engine.history.HistoricProcessInstance;
|
||||||
|
import org.activiti.engine.repository.ProcessDefinition;
|
||||||
|
import org.activiti.engine.runtime.ProcessInstance;
|
||||||
|
import org.activiti.engine.task.IdentityLink;
|
||||||
|
import org.activiti.engine.task.Task;
|
||||||
|
import org.activiti.image.ProcessDiagramGenerator;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import top.jfunc.common.db.QueryHelper;
|
||||||
|
import top.jfunc.common.db.bean.Page;
|
||||||
|
import top.jfunc.common.db.bean.Record;
|
||||||
|
import top.jfunc.common.db.utils.Pagination;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ActProcInsService {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActProcInsService.class);
|
||||||
|
@Autowired
|
||||||
|
private RepositoryService repositoryService; //管理流程定义 与流程定义和部署对象相关的Service
|
||||||
|
@Autowired
|
||||||
|
private TaskService taskService; //任务管理 与正在执行的任务管理相关的Service
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AccountService accountService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RuntimeService runtimeService; //与正在执行的流程实例和执行对象相关的Service(执行管理,包括启动、推进、删除流程实例等操作)
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
Pagination pagination;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActProcDefService actProcDefService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private HistoryService historyService; //历史管理(执行完的数据的管理)
|
||||||
|
|
||||||
|
|
||||||
|
public Page<ActProcIns> list(ConcurrentHashMap<String, String> searchInfo, int pageNumber, int pageSize) {
|
||||||
|
String select = "select h.proc_inst_id_ as procInsId,h.proc_def_id_ as procDefId," +
|
||||||
|
"h.start_time_ as startTime,h.end_time_ as endTime,p.key_ as procKey," +
|
||||||
|
"p.name_ as procName,p.NAME_ as dgrmResourceName,p.version_ as version, GROUP_CONCAT(t.NAME_) as currentTask, GROUP_CONCAT(t.ID_) as currentTaskId";
|
||||||
|
QueryHelper queryHelper = new QueryHelper(select, " act_hi_procinst h " +
|
||||||
|
"left join ACT_RE_PROCDEF p on h.PROC_DEF_ID_ =p.ID_ " +
|
||||||
|
"LEFT JOIN act_ru_task t on t.PROC_INST_ID_=h.proc_inst_id_ ");
|
||||||
|
queryHelper.addGroupProperty("h.PROC_INST_ID_");
|
||||||
|
queryHelper.addOrderProperty("h.start_time_", false);
|
||||||
|
Page<ActProcIns> paginate = pagination.paginate(queryHelper.getSql(), ActProcIns.class, pageNumber, pageSize);
|
||||||
|
List<ActProcIns> list = paginate.getList();
|
||||||
|
|
||||||
|
for (ActProcIns ins : list) {
|
||||||
|
//查询流程发起人
|
||||||
|
Record record = getVariable(ActConstant.START_PROCESS_USERID, ins.getProcInsId());
|
||||||
|
if (record != null) {
|
||||||
|
String userId = getStartUserId(ins.getProcInsId());
|
||||||
|
ins.setUser(accountService.getNameById(Integer.parseInt(userId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//查询当前任务审批人
|
||||||
|
String currentTaskId = ins.getCurrentTaskId();
|
||||||
|
if (StringUtils.isNotBlank(currentTaskId)) {
|
||||||
|
String[] split = currentTaskId.split(",");
|
||||||
|
String candidateUsers = "";
|
||||||
|
for (String taskId : split) {
|
||||||
|
List<IdentityLink> identityLinksForTask = taskService.getIdentityLinksForTask(taskId);
|
||||||
|
for (IdentityLink identityLink : identityLinksForTask) {
|
||||||
|
if ("assignee".equals(identityLink.getType()) || "candidate".equals(identityLink.getType())) {
|
||||||
|
String userId = identityLink.getUserId();
|
||||||
|
if (StringUtils.isNotBlank(candidateUsers)) {
|
||||||
|
candidateUsers = candidateUsers + ",";
|
||||||
|
}
|
||||||
|
candidateUsers += accountService.getNameById(Integer.parseInt(userId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ins.setCandidateUsers(candidateUsers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return paginate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程实例里的变量
|
||||||
|
*
|
||||||
|
* @param variableName
|
||||||
|
* @param procInsId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Record getVariable(String variableName, String procInsId) {
|
||||||
|
String sql = "select TEXT_ as text from ACT_HI_VARINST where NAME_=? and PROC_INST_ID_=?";
|
||||||
|
return pagination.findFirst(sql, variableName, procInsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getStartUserId(String procInsId) {
|
||||||
|
Record record = getVariable(ActConstant.START_PROCESS_USERID, procInsId);
|
||||||
|
if (record != null) {
|
||||||
|
return record.getStr("text");
|
||||||
|
}
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<Record> getVariables(String procInsId) {
|
||||||
|
String sql = "select NAME_ as name, TEXT_ as text from ACT_HI_VARINST where PROC_INST_ID_=?";
|
||||||
|
return pagination.find(sql, procInsId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void deleteProcessInstance(String procInsId, String reason) {
|
||||||
|
runtimeService.deleteProcessInstance(procInsId, reason); //作废流程
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void createProcInsPng(HttpServletResponse response, String procInsId) throws IOException {
|
||||||
|
try {
|
||||||
|
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(procInsId).singleResult(); //获取历史流程实例
|
||||||
|
//获取流程中已经执行的节点,按照执行先后顺序排序
|
||||||
|
List<HistoricActivityInstance> hai = historyService.createHistoricActivityInstanceQuery().processInstanceId(procInsId).orderByHistoricActivityInstanceStartTime().asc().list();
|
||||||
|
// 历史流程节点中
|
||||||
|
List<HistoricActivityInstance> newHisActInstanceList = new ArrayList<HistoricActivityInstance>();
|
||||||
|
List<HistoricActivityInstance> newHisTaskInstanceList = new ArrayList<HistoricActivityInstance>();
|
||||||
|
if (hai != null && hai.size() > 0) {
|
||||||
|
for (int i = 0; i < hai.size(); i++) {
|
||||||
|
HistoricActivityInstance historicActivityInstance = hai.get(i);
|
||||||
|
String activityType = historicActivityInstance.getActivityType();
|
||||||
|
if (activityType.equals("startEvent") || activityType.equals("endEvent")) {
|
||||||
|
newHisActInstanceList.add(historicActivityInstance);
|
||||||
|
} else if (activityType.equals("serviceTask") || activityType.equals("userTask") || activityType.equals("exclusiveGateway") || activityType.equals("parallelGateway")) {
|
||||||
|
if (newHisTaskInstanceList.size() > 0) {
|
||||||
|
for (int j = 0; j < newHisTaskInstanceList.size(); j++) {
|
||||||
|
HistoricActivityInstance historicTaskInstance = newHisTaskInstanceList.get(j);
|
||||||
|
if (historicTaskInstance.getActivityId().equals(historicActivityInstance.getActivityId())) { //如果列表中已包括
|
||||||
|
newHisTaskInstanceList.clear();
|
||||||
|
newHisTaskInstanceList.add(historicActivityInstance);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
newHisTaskInstanceList.add(historicActivityInstance);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newHisTaskInstanceList.add(historicActivityInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < newHisActInstanceList.size(); i++) {
|
||||||
|
HistoricActivityInstance historicActivityInstance = newHisActInstanceList.get(i);
|
||||||
|
newHisTaskInstanceList.add(historicActivityInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> executedActivityIdList = new ArrayList<String>(); // 构造已执行的节点ID集合
|
||||||
|
for (HistoricActivityInstance activityInstance : newHisTaskInstanceList) {
|
||||||
|
executedActivityIdList.add(activityInstance.getActivityId());
|
||||||
|
}
|
||||||
|
BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId()); // 获取bpmnModel
|
||||||
|
List<String> flowIds = this.getExecutedFlows(bpmnModel, newHisTaskInstanceList); // 获取流程已发生流转的线ID集合
|
||||||
|
InputStream inputStream = actProcDefService.generateDiagramInputStream(bpmnModel, executedActivityIdList, flowIds);
|
||||||
|
actProcDefService.responsePng(response, inputStream);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("an exception happens in try catch statement", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getExecutedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances) {
|
||||||
|
List<String> flowIdList = new ArrayList<String>(); //流转线ID集合
|
||||||
|
List<FlowNode> historicFlowNodeList = new LinkedList<FlowNode>(); //全部活动实例
|
||||||
|
List<HistoricActivityInstance> finishedActivityInstanceList = new LinkedList<HistoricActivityInstance>(); //已完成的历史活动节点
|
||||||
|
List list = new ArrayList();
|
||||||
|
|
||||||
|
for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
|
||||||
|
historicFlowNodeList.add((FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true));
|
||||||
|
if (historicActivityInstance.getEndTime() != null) {
|
||||||
|
finishedActivityInstanceList.add(historicActivityInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
for (int x = 0; x < historicActivityInstances.size(); x++) {
|
||||||
|
HistoricActivityInstance historicActivityInstance = historicActivityInstances.get(x);
|
||||||
|
String activityType = historicActivityInstance.getActivityType();
|
||||||
|
String activityId = historicActivityInstance.getActivityId();
|
||||||
|
if (!list.contains(activityId) && ("userTask".equals(activityType)
|
||||||
|
|| "serviceTask".equals(activityType)
|
||||||
|
|| "endEvent".equals(activityType)
|
||||||
|
|| "exclusiveGateway".equals(activityType)
|
||||||
|
|| "parallelGateway".equals(activityType))) {
|
||||||
|
list.add(activityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的*/
|
||||||
|
FlowNode currentFlowNode = null;
|
||||||
|
for (HistoricActivityInstance currentActivityInstance : finishedActivityInstanceList) {
|
||||||
|
/**获得当前活动对应的节点信息及outgoingFlows信息*/
|
||||||
|
currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
|
||||||
|
List<SequenceFlow> sequenceFlowList = currentFlowNode.getOutgoingFlows();
|
||||||
|
/**
|
||||||
|
* 遍历outgoingFlows并找到已流转的
|
||||||
|
* 满足如下条件任务已流转:
|
||||||
|
* 1.当前节点是并行网关或包含网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转
|
||||||
|
* 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最近的流转节点视为有效流转
|
||||||
|
*/
|
||||||
|
FlowNode targetFlowNode = null;
|
||||||
|
if ("parallelGateway".equals(currentActivityInstance.getActivityType())
|
||||||
|
|| "inclusiveGateway".equals(currentActivityInstance.getActivityType())) {
|
||||||
|
for (SequenceFlow sequenceFlow : sequenceFlowList) { //遍历历史活动节点,找到匹配Flow目标节点的
|
||||||
|
targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
|
||||||
|
if (historicFlowNodeList.contains(targetFlowNode)) {
|
||||||
|
flowIdList.add(sequenceFlow.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
List<Map<String, String>> tempMapList = new LinkedList<Map<String, String>>();
|
||||||
|
// for(SequenceFlow sequenceFlow : sequenceFlowList) { //遍历历史活动节点,找到匹配Flow目标节点的
|
||||||
|
for (int i = 0; i < sequenceFlowList.size(); i++) { //遍历历史活动节点,找到匹配Flow目标节点的
|
||||||
|
SequenceFlow sequenceFlow = sequenceFlowList.get(i);
|
||||||
|
int taskSeq = list.indexOf(sequenceFlow.getSourceRef()); // 获取当前flow目标节点key在审批顺序
|
||||||
|
String nextTaskKey = ""; // 下一个任务节点
|
||||||
|
String beforeTaskKey = sequenceFlow.getSourceRef(); //上一个任务节点
|
||||||
|
|
||||||
|
if ((taskSeq + 1) < list.size()) { // 判断下一个任务节点是否存在
|
||||||
|
nextTaskKey = String.valueOf(list.get((taskSeq + 1)));
|
||||||
|
}
|
||||||
|
if (taskSeq == list.size() - 1) {
|
||||||
|
nextTaskKey = String.valueOf(list.get((taskSeq)));
|
||||||
|
}
|
||||||
|
for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
|
||||||
|
if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef()) && sequenceFlow.getSourceRef().equals(beforeTaskKey) && sequenceFlow.getTargetRef().equals(nextTaskKey)) {
|
||||||
|
Map<String, String> map = new HashMap<>();
|
||||||
|
map.put("flowId", sequenceFlow.getId());
|
||||||
|
map.put("activityStartTime", String.valueOf(historicActivityInstance.getStartTime().getTime()));
|
||||||
|
tempMapList.add(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String flowId = null;
|
||||||
|
for (Map<String, String> map : tempMapList) {
|
||||||
|
flowId = map.get("flowId");
|
||||||
|
flowIdList.add(flowId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flowIdList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String startProcessInstance(String procDefKey, Map<String, Object> variables) {
|
||||||
|
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKey(procDefKey).active().orderByProcessDefinitionVersion().desc().list();
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
throw new ResponseException("procDefKey:" + procDefKey + " 未定义");
|
||||||
|
}
|
||||||
|
|
||||||
|
//取最新版本的流程定义进行启动流程实列
|
||||||
|
ProcessDefinition processDefinition = list.get(0);
|
||||||
|
|
||||||
|
//启动流程
|
||||||
|
ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(), variables);
|
||||||
|
|
||||||
|
Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult();
|
||||||
|
if (task == null) {
|
||||||
|
throw new ResponseException("procDefKey:" + procDefKey + " 启动异常");
|
||||||
|
}
|
||||||
|
|
||||||
|
//设置发起人为办理人 然后完成任务 任务转入下一个审批节点
|
||||||
|
task.setAssignee(InterfaceUtil.getAdminId() + "");
|
||||||
|
taskService.complete(task.getId());
|
||||||
|
return processInstance.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package cn.palmte.work.service;
|
||||||
|
|
||||||
|
import cn.palmte.work.model.ActScript;
|
||||||
|
import cn.palmte.work.model.ActScriptRepository;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import top.jfunc.common.db.QueryHelper;
|
||||||
|
import top.jfunc.common.db.bean.Page;
|
||||||
|
import top.jfunc.common.db.utils.Pagination;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ActScriptService {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActScriptService.class);
|
||||||
|
@Autowired
|
||||||
|
private ActScriptRepository actScriptRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
Pagination pagination;
|
||||||
|
|
||||||
|
|
||||||
|
public Page<ActScript> list(ConcurrentHashMap<String, String> searchInfo, int pageNumber, int pageSize) {
|
||||||
|
QueryHelper queryHelper = new QueryHelper("a.*", " act_script a");
|
||||||
|
String name = searchInfo.get("name");
|
||||||
|
queryHelper.addCondition(StringUtils.isNotEmpty(name), "a.script_name=? ", name);
|
||||||
|
queryHelper.addOrderProperty("a.last_updated_time", false);
|
||||||
|
return pagination.paginate(queryHelper.getSql(), ActScript.class, pageNumber, pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(ActScript actScript) {
|
||||||
|
Date now = new Date();
|
||||||
|
int id = actScript.getId();
|
||||||
|
if (id == 0) {
|
||||||
|
actScript.setCreatedTime(now);
|
||||||
|
}else {
|
||||||
|
ActScript one = actScriptRepository.findOne(id);
|
||||||
|
actScript.setCreatedTime(one.getCreatedTime());
|
||||||
|
}
|
||||||
|
actScript.setLastUpdatedTime(now);
|
||||||
|
actScriptRepository.save(actScript);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void delete(int id) {
|
||||||
|
actScriptRepository.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,240 @@
|
||||||
|
package cn.palmte.work.service;
|
||||||
|
|
||||||
|
import cn.palmte.work.config.activiti.ActConstant;
|
||||||
|
import cn.palmte.work.config.activiti.DeleteTaskCommand;
|
||||||
|
import cn.palmte.work.config.activiti.JumpCommand;
|
||||||
|
import cn.palmte.work.model.ActScript;
|
||||||
|
import cn.palmte.work.model.ActScriptRepository;
|
||||||
|
import cn.palmte.work.model.ActTaskDef;
|
||||||
|
import cn.palmte.work.model.ActTaskDefRepository;
|
||||||
|
import cn.palmte.work.utils.InterfaceUtil;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import org.activiti.bpmn.model.FlowNode;
|
||||||
|
import org.activiti.engine.*;
|
||||||
|
import org.activiti.engine.task.Task;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import top.jfunc.common.db.bean.Record;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ActTaskDefService {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ActTaskDefService.class);
|
||||||
|
@Autowired
|
||||||
|
private RepositoryService repositoryService; //管理流程定义 与流程定义和部署对象相关的Service
|
||||||
|
@Autowired
|
||||||
|
private ProcessEngine processEngine; //流程引擎对象
|
||||||
|
@Autowired
|
||||||
|
private RuntimeService runtimeService; //与正在执行的流程实例和执行对象相关的Service(执行管理,包括启动、推进、删除流程实例等操作)
|
||||||
|
@Autowired
|
||||||
|
private TaskService taskService; //任务管理 与正在执行的任务管理相关的Service
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActTaskDefRepository actTaskDefRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AccountService accountService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActProcInsService actProcInsService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ActScriptRepository actScriptRepository;
|
||||||
|
|
||||||
|
public List<ActTaskDef> findByProcDefId(String procDefId) {
|
||||||
|
List<ActTaskDef> list = actTaskDefRepository.findByProcDefId(procDefId);
|
||||||
|
for (ActTaskDef actTaskDef : list) {
|
||||||
|
ids2List(actTaskDef);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ActTaskDef findFirstByProcDefIdAndTaskKey(String procDefId, String taskKey) {
|
||||||
|
ActTaskDef def = actTaskDefRepository.findFirstByProcDefIdAndTaskKey(procDefId, taskKey);
|
||||||
|
ids2List(def);
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void saveConfig(ActTaskDef taskDef) {
|
||||||
|
ActTaskDef one = actTaskDefRepository.findOne(taskDef.getId());
|
||||||
|
one.setCandidateUsers(taskDef.getCandidateUsers());
|
||||||
|
one.setCandidateRoles(taskDef.getCandidateRoles());
|
||||||
|
one.setRollbackTaskKey(taskDef.getRollbackTaskKey());
|
||||||
|
one.setEndScript(taskDef.getEndScript());
|
||||||
|
one.setRollbackScript(taskDef.getRollbackScript());
|
||||||
|
one.setLastUpdatedTime(new Date());
|
||||||
|
|
||||||
|
actTaskDefRepository.save(one);
|
||||||
|
logger.info("saveTaskConfig uerId:{}, config:{}", InterfaceUtil.getAdminId(), JSONObject.toJSONString(one));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ids2List(ActTaskDef actTaskDef) {
|
||||||
|
String candidateUsers = actTaskDef.getCandidateUsers();
|
||||||
|
List<String> userIdList = new ArrayList<>();
|
||||||
|
if (StringUtils.isNotBlank(candidateUsers)) {
|
||||||
|
userIdList = Arrays.asList(candidateUsers.split("#"));
|
||||||
|
}
|
||||||
|
actTaskDef.setCandidateUserList(userIdList);
|
||||||
|
|
||||||
|
String candidateRoles = actTaskDef.getCandidateRoles();
|
||||||
|
List<String> roleIdList = new ArrayList<>();
|
||||||
|
if (StringUtils.isNotBlank(candidateRoles)) {
|
||||||
|
roleIdList = Arrays.asList(candidateRoles.split("#"));
|
||||||
|
}
|
||||||
|
actTaskDef.setCandidateRoleList(roleIdList);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Set<String> findCandidateUsers(String procDefId, String procInsId, String taskDefKey) {
|
||||||
|
ActTaskDef taskDef = findFirstByProcDefIdAndTaskKey(procDefId, taskDefKey);
|
||||||
|
if (taskDef.getTaskIndex() == ActConstant.TASK_INDEX_FIRST_USER_TASK) {
|
||||||
|
String startUserId = actProcInsService.getStartUserId(procInsId);
|
||||||
|
Set<String> res = new HashSet<>(1);
|
||||||
|
logger.info("findCandidateUsers-0-task:{}, startUserId:{}", taskDef.getTaskName(), startUserId);
|
||||||
|
res.add(startUserId);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> resList = new ArrayList<>();
|
||||||
|
List<String> candidateUserList = taskDef.getCandidateUserList();
|
||||||
|
logger.info("findCandidateUsers-1-task:{}, userList:{}", taskDef.getTaskName(), candidateUserList);
|
||||||
|
if (!candidateUserList.isEmpty()) {
|
||||||
|
resList.addAll(candidateUserList);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> candidateRoleList = taskDef.getCandidateRoleList();
|
||||||
|
logger.info("findCandidateUsers-2-task:{}, roleList:{}", taskDef.getTaskName(), candidateRoleList);
|
||||||
|
List<String> list = accountService.getUserIsByRole(candidateRoleList);
|
||||||
|
logger.info("findCandidateUsers-3-task:{}, userIdListByRole:{}", taskDef.getTaskName(), list);
|
||||||
|
if (!list.isEmpty()) {
|
||||||
|
resList.addAll(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> res = new HashSet<>(resList);
|
||||||
|
logger.info("findCandidateUsers-4-task:{}, resIds:{}", taskDef.getTaskName(), res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理任务
|
||||||
|
* @param json
|
||||||
|
*/
|
||||||
|
public void completeTask(JSONObject json) {
|
||||||
|
String taskId = json.getString("taskId");
|
||||||
|
String procInstId = json.getString("procInsId");
|
||||||
|
String message = json.getString("message");
|
||||||
|
int type = json.getInteger("type");
|
||||||
|
|
||||||
|
taskService.addComment(taskId, procInstId, message);
|
||||||
|
|
||||||
|
Task currentTask = taskService.createTaskQuery().taskId(taskId).singleResult();
|
||||||
|
ActTaskDef actTaskDef = findFirstByProcDefIdAndTaskKey(currentTask.getProcessDefinitionId(), currentTask.getTaskDefinitionKey());
|
||||||
|
|
||||||
|
if (ActConstant.TYPE_APPROVE == type) {
|
||||||
|
//审批通过
|
||||||
|
taskService.complete(taskId);
|
||||||
|
|
||||||
|
//执行配置的审批通过脚本
|
||||||
|
int endScript = actTaskDef.getEndScript();
|
||||||
|
if (endScript != 0) {
|
||||||
|
invokeEventScript(endScript, procInstId);
|
||||||
|
} else {
|
||||||
|
logger.info("未配置审批通过脚本 task:{}", actTaskDef.getTaskName());
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (ActConstant.TYPE_ROLLBACK == type) {
|
||||||
|
//驳回
|
||||||
|
String rollbackTaskKey = actTaskDef.getRollbackTaskKey();
|
||||||
|
jumpToTargetTask(taskId, rollbackTaskKey);
|
||||||
|
|
||||||
|
//执行配置的驳回脚本
|
||||||
|
int rollbackScript = actTaskDef.getRollbackScript();
|
||||||
|
if (rollbackScript != 0) {
|
||||||
|
invokeEventScript(rollbackScript, procInstId);
|
||||||
|
} else {
|
||||||
|
logger.info("未配置驳回脚本 task:{}", actTaskDef.getTaskName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 反射执行脚本
|
||||||
|
*
|
||||||
|
* @param scriptId
|
||||||
|
* @param procInsId
|
||||||
|
*/
|
||||||
|
private void invokeEventScript(int scriptId, String procInsId) {
|
||||||
|
ActScript actScript = actScriptRepository.findOne(scriptId);
|
||||||
|
if (actScript == null) {
|
||||||
|
logger.info("脚本配置错误");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put(ActConstant.PROC_INS_ID, procInsId);
|
||||||
|
List<Record> variables = actProcInsService.getVariables(procInsId);
|
||||||
|
for (Record variable : variables) {
|
||||||
|
map.put(variable.getStr("name"), variable.get("text"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//调用方法传递的参数
|
||||||
|
Object[] args = new Object[1];
|
||||||
|
args[0] = map;
|
||||||
|
|
||||||
|
logger.info("invokeEventScript class:{}, methond:{}, param:{}", actScript.getClassName(), actScript.getClassMethod(), map);
|
||||||
|
try {
|
||||||
|
Class<?> ownerClass = Class.forName(actScript.getClassName());
|
||||||
|
Object bean = applicationContext.getBean(ownerClass);
|
||||||
|
Class<?>[] paramsType = new Class[1];
|
||||||
|
paramsType[0] = Class.forName("java.util.Map");
|
||||||
|
//找到脚本方法对应的方法 注意:有且只有一个以Map为参数的方法
|
||||||
|
Method method = ownerClass.getDeclaredMethod(actScript.getClassMethod(), paramsType);
|
||||||
|
method.invoke(bean, args);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转到指定任务节点
|
||||||
|
*
|
||||||
|
* @param currentTaskId 当前任务id
|
||||||
|
* @param targetTaskDefKey 跳转目的任务key
|
||||||
|
*/
|
||||||
|
public void jumpToTargetTask(String currentTaskId, String targetTaskDefKey) {
|
||||||
|
Task currentTask = taskService.createTaskQuery().taskId(currentTaskId).singleResult();
|
||||||
|
// 获取流程定义
|
||||||
|
org.activiti.bpmn.model.Process process = repositoryService.getBpmnModel(currentTask.getProcessDefinitionId()).getMainProcess();
|
||||||
|
//获取目标节点定义
|
||||||
|
FlowNode targetNode = (FlowNode) process.getFlowElement(targetTaskDefKey);
|
||||||
|
|
||||||
|
ManagementService managementService = processEngine.getManagementService();
|
||||||
|
//删除当前运行任务
|
||||||
|
String executionEntityId = managementService.executeCommand(new DeleteTaskCommand(currentTask.getId()));
|
||||||
|
//流程执行到来源节点
|
||||||
|
managementService.executeCommand(new JumpCommand(targetNode, executionEntityId));
|
||||||
|
|
||||||
|
Task singleResult = taskService.createTaskQuery().processInstanceId(currentTask.getProcessInstanceId()).singleResult();
|
||||||
|
singleResult.setParentTaskId(currentTask.getTaskDefinitionKey());
|
||||||
|
taskService.saveTask(singleResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ fourcal.token.pc.expires=60*60*24
|
||||||
fourcal.excluded.client.urls=
|
fourcal.excluded.client.urls=
|
||||||
fourcal.excluded.pc.urls=
|
fourcal.excluded.pc.urls=
|
||||||
#\u6392\u9664\u67D0\u4E9B\u65E5\u5FD7\u7684\u6253\u5370
|
#\u6392\u9664\u67D0\u4E9B\u65E5\u5FD7\u7684\u6253\u5370
|
||||||
fourcal.log.excluded.urls=
|
fourcal.log.excluded.urls=/editor/stencilset
|
||||||
|
|
||||||
|
|
||||||
fourcal.slideInterval=1800000
|
fourcal.slideInterval=1800000
|
||||||
|
|
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 580 B |
After Width: | Height: | Size: 108 B |
After Width: | Height: | Size: 438 B |
After Width: | Height: | Size: 227 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 830 B |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 410 B |
After Width: | Height: | Size: 367 B |
After Width: | Height: | Size: 344 B |
After Width: | Height: | Size: 601 B |
After Width: | Height: | Size: 361 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 953 B |
After Width: | Height: | Size: 687 B |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 775 B |
|
@ -0,0 +1,130 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="style.css" type="text/css" media="screen">
|
||||||
|
<script src="js/jstools.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="js/raphael.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<script src="js/jquery/jquery.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="js/jquery/jquery.progressbar.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="js/jquery/jquery.asyncqueue.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<script src="js/Color.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="js/Polyline.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="js/ActivityImpl.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="js/ActivitiRest.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="js/LineBreakMeasurer.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="js/ProcessDiagramGenerator.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="js/ProcessDiagramCanvas.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<style type="text/css" media="screen">
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="wrapper">
|
||||||
|
<div id="pb1"></div>
|
||||||
|
<div id="overlayBox" >
|
||||||
|
<div id="diagramBreadCrumbs" class="diagramBreadCrumbs" onmousedown="return false" onselectstart="return false"></div>
|
||||||
|
<div id="diagramHolder" class="diagramHolder"></div>
|
||||||
|
<div class="diagram-info" id="diagramInfo"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script language='javascript'>
|
||||||
|
var DiagramGenerator = {};
|
||||||
|
var pb1;
|
||||||
|
$(document).ready(function(){
|
||||||
|
var query_string = {};
|
||||||
|
var query = window.location.search.substring(1);
|
||||||
|
var vars = query.split("&");
|
||||||
|
for (var i=0;i<vars.length;i++) {
|
||||||
|
var pair = vars[i].split("=");
|
||||||
|
query_string[pair[0]] = pair[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var processDefinitionId = query_string["processDefinitionId"];
|
||||||
|
var processInstanceId = query_string["processInstanceId"];
|
||||||
|
|
||||||
|
console.log("Initialize progress bar");
|
||||||
|
|
||||||
|
pb1 = new $.ProgressBar({
|
||||||
|
boundingBox: '#pb1',
|
||||||
|
label: 'Progressbar!',
|
||||||
|
on: {
|
||||||
|
complete: function() {
|
||||||
|
console.log("Progress Bar COMPLETE");
|
||||||
|
this.set('label', 'complete!');
|
||||||
|
if (processInstanceId) {
|
||||||
|
ProcessDiagramGenerator.drawHighLights(processInstanceId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
valueChange: function(e) {
|
||||||
|
this.set('label', e.newVal + '%');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: 0
|
||||||
|
});
|
||||||
|
console.log("Progress bar inited");
|
||||||
|
|
||||||
|
ProcessDiagramGenerator.options = {
|
||||||
|
diagramBreadCrumbsId: "diagramBreadCrumbs",
|
||||||
|
diagramHolderId: "diagramHolder",
|
||||||
|
diagramInfoId: "diagramInfo",
|
||||||
|
on: {
|
||||||
|
click: function(canvas, element, contextObject){
|
||||||
|
var mouseEvent = this;
|
||||||
|
console.log("[CLICK] mouseEvent: %o, canvas: %o, clicked element: %o, contextObject: %o", mouseEvent, canvas, element, contextObject);
|
||||||
|
|
||||||
|
if (contextObject.getProperty("type") == "callActivity") {
|
||||||
|
var processDefinitonKey = contextObject.getProperty("processDefinitonKey");
|
||||||
|
var processDefinitons = contextObject.getProperty("processDefinitons");
|
||||||
|
var processDefiniton = processDefinitons[0];
|
||||||
|
console.log("Load callActivity '" + processDefiniton.processDefinitionKey + "', contextObject: ", contextObject);
|
||||||
|
|
||||||
|
// Load processDefinition
|
||||||
|
ProcessDiagramGenerator.drawDiagram(processDefiniton.processDefinitionId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rightClick: function(canvas, element, contextObject){
|
||||||
|
var mouseEvent = this;
|
||||||
|
console.log("[RIGHTCLICK] mouseEvent: %o, canvas: %o, clicked element: %o, contextObject: %o", mouseEvent, canvas, element, contextObject);
|
||||||
|
},
|
||||||
|
over: function(canvas, element, contextObject){
|
||||||
|
var mouseEvent = this;
|
||||||
|
//console.log("[OVER] mouseEvent: %o, canvas: %o, clicked element: %o, contextObject: %o", mouseEvent, canvas, element, contextObject);
|
||||||
|
|
||||||
|
// TODO: show tooltip-window with contextObject info
|
||||||
|
ProcessDiagramGenerator.showActivityInfo(contextObject);
|
||||||
|
},
|
||||||
|
out: function(canvas, element, contextObject){
|
||||||
|
var mouseEvent = this;
|
||||||
|
//console.log("[OUT] mouseEvent: %o, canvas: %o, clicked element: %o, contextObject: %o", mouseEvent, canvas, element, contextObject);
|
||||||
|
|
||||||
|
ProcessDiagramGenerator.hideInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var baseUrl = window.document.location.protocol + "//" + window.document.location.host + "/";
|
||||||
|
var shortenedUrl = window.document.location.href.replace(baseUrl, "");
|
||||||
|
baseUrl = baseUrl + shortenedUrl.substring(0, shortenedUrl.indexOf("/"));
|
||||||
|
|
||||||
|
ActivitiRest.options = {
|
||||||
|
processInstanceHighLightsUrl: baseUrl + "/service/process-instance/{processInstanceId}/highlights?callback=?",
|
||||||
|
processDefinitionUrl: baseUrl + "/service/process-definition/{processDefinitionId}/diagram-layout?callback=?",
|
||||||
|
processDefinitionByKeyUrl: baseUrl + "/service/process-definition/{processDefinitionKey}/diagram-layout?callback=?"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (processDefinitionId) {
|
||||||
|
ProcessDiagramGenerator.drawDiagram(processDefinitionId);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
alert("processDefinitionId parameter is required");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,75 @@
|
||||||
|
var ActivitiRest = {
|
||||||
|
options: {},
|
||||||
|
getProcessDefinitionByKey: function(processDefinitionKey, callback) {
|
||||||
|
var url = Lang.sub(this.options.processDefinitionByKeyUrl, {processDefinitionKey: processDefinitionKey});
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
dataType: 'jsonp',
|
||||||
|
cache: false,
|
||||||
|
async: true,
|
||||||
|
success: function(data, textStatus) {
|
||||||
|
var processDefinition = data;
|
||||||
|
if (!processDefinition) {
|
||||||
|
console.error("Process definition '" + processDefinitionKey + "' not found");
|
||||||
|
} else {
|
||||||
|
callback.apply({processDefinitionId: processDefinition.id});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).done(function(data, textStatus) {
|
||||||
|
console.log("ajax done");
|
||||||
|
}).fail(function(jqXHR, textStatus, error){
|
||||||
|
console.error('Get diagram layout['+processDefinitionKey+'] failure: ', textStatus, 'error: ', error, jqXHR);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getProcessDefinition: function(processDefinitionId, callback) {
|
||||||
|
var url = Lang.sub(this.options.processDefinitionUrl, {processDefinitionId: processDefinitionId});
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
dataType: 'jsonp',
|
||||||
|
cache: false,
|
||||||
|
async: true,
|
||||||
|
success: function(data, textStatus) {
|
||||||
|
var processDefinitionDiagramLayout = data;
|
||||||
|
if (!processDefinitionDiagramLayout) {
|
||||||
|
console.error("Process definition diagram layout '" + processDefinitionId + "' not found");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
callback.apply({processDefinitionDiagramLayout: processDefinitionDiagramLayout});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).done(function(data, textStatus) {
|
||||||
|
console.log("ajax done");
|
||||||
|
}).fail(function(jqXHR, textStatus, error){
|
||||||
|
console.log('Get diagram layout['+processDefinitionId+'] failure: ', textStatus, jqXHR);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getHighLights: function(processInstanceId, callback) {
|
||||||
|
var url = Lang.sub(this.options.processInstanceHighLightsUrl, {processInstanceId: processInstanceId});
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
dataType: 'jsonp',
|
||||||
|
cache: false,
|
||||||
|
async: true,
|
||||||
|
success: function(data, textStatus) {
|
||||||
|
console.log("ajax returned data");
|
||||||
|
var highLights = data;
|
||||||
|
if (!highLights) {
|
||||||
|
console.log("highLights not found");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
callback.apply({highLights: highLights});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).done(function(data, textStatus) {
|
||||||
|
console.log("ajax done");
|
||||||
|
}).fail(function(jqXHR, textStatus, error){
|
||||||
|
console.log('Get HighLights['+processInstanceId+'] failure: ', textStatus, jqXHR);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//FHqq-3-1-3-5-9-6-7-9-0
|
|
@ -0,0 +1 @@
|
||||||
|
/**
*
* @author Tom Baeyens
* @author (Javascript) Dmitry Farafonov
*/
var ActivityImpl = function(activityJson){
this.outgoingTransitions = [];
this.outgoingTransitions = [];
this.incomingTransitions = [];
this.activityBehavior = null;
this.parent = null;
this.isScope = false;
this.isAsync = false;
this.isExclusive = false;
this.x = -1;
this.y = -1;
this.width = -1;
this.height = -1;
this.properties = {};
//console.log("activityJson: ", activityJson);
if (activityJson != undefined) {
this.setId(activityJson.activityId);
for (var propertyName in activityJson.properties) {
this.setProperty(propertyName, activityJson.properties[propertyName]);
}
//this.setProperty("name", activityJson.activityName);
//this.setProperty("type", activityJson.activityType);
this.setX(activityJson.x);
this.setY(activityJson.y);
this.setWidth(activityJson.width);
this.setHeight(activityJson.height);
if (activityJson.multiInstance)
this.setProperty("multiInstance", activityJson.multiInstance);
if (activityJson.collapsed) {
this.setProperty("collapsed", activityJson.collapsed);
}
if (activityJson.isInterrupting != undefined)
this.setProperty("isInterrupting", activityJson.isInterrupting);
}
};
ActivityImpl.prototype = {
outgoingTransitions: [],
outgoingTransitions: [],
incomingTransitions: [],
activityBehavior: null,
parent: null,
isScope: false,
isAsync: false,
isExclusive: false,
id: null,
properties: {},
// Graphical information
x: -1,
y: -1,
width: -1,
height: -1,
setId: function(id){
this.id = id;
},
getId: function(){
return this.id;
},
setProperty: function(name, value){
this.properties[name] = value;
},
getProperty: function(name){
return this.properties[name];
},
createOutgoingTransition: function(transitionId){
},
toString: function(id) {
return "Activity("+id+")";
},
getParentActivity: function(){
/*
if (parent instanceof ActivityImpl) {
79 return (ActivityImpl) parent;
80 }
81 return null;
*/
return this.parent;
},
// restricted setters ///////////////////////////////////////////////////////
setOutgoingTransitions: function(outgoingTransitions){
this.outgoingTransitions = outgoingTransitions;
},
setParent: function(parent){
this.parent = parent;
},
setIncomingTransitions: function(incomingTransitions){
this.incomingTransitions = incomingTransitions;
},
// getters and setters //////////////////////////////////////////////////////
getOutgoingTransitions: function(){
return this.outgoingTransitions;
},
getActivityBehavior: function(){
return this.activityBehavior;
},
setActivityBehavior: function(activityBehavior){
this.activityBehavior = activityBehavior;
},
getParent: function(){
return this.parent;
},
getIncomingTransitions: function(){
return this.incomingTransitions;
},
isScope: function(){
return this.isScope;
},
setScope: function(isScope){
this.isScope = isScope;
},
getX: function(){
return this.x;
},
setX: function(x){
this.x = x;
},
getY: function(){
return this.y;
},
setY: function(y){
this.y = y;
},
getWidth: function(){
return this.width;
},
setWidth: function(width){
this.width = width;
},
getHeight: function(){
return this.height;
},
setHeight: function(height){
this.height = height;
},
isAsync: function() {
return this.isAsync;
},
setAsync: function(isAsync) {
this.isAsync = isAsync;
},
isExclusive: function() {
return this.isExclusive;
},
setExclusive: function(isExclusive) {
this.isExclusive = isExclusive;
},
vvoid: function(){}
};
|
|
@ -0,0 +1,603 @@
|
||||||
|
/**
|
||||||
|
* Web color table
|
||||||
|
*
|
||||||
|
* @author Dmitry Farafonov
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Color = {
|
||||||
|
/**
|
||||||
|
* The color white. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
white : Raphael.getRGB("rgb(255,255,255)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color white. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
WHITE : this.white,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color light gray. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
lightGray : Raphael.getRGB("rgb(192, 192, 192)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color light gray. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
LIGHT_GRAY : this.lightGray,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color gray. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
gray : Raphael.getRGB("rgb(128, 128, 128)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color gray. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
GRAY : this.gray,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color dark gray. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
darkGray : Raphael.getRGB("rgb(64, 64, 64)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color dark gray. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
DARK_GRAY : this.darkGray,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color black. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
black : Raphael.getRGB("rgb(0, 0, 0)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color black. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
BLACK : this.black,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color red. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
red : Raphael.getRGB("rgb(255, 0, 0)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color red. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
RED : this.red,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color pink. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
pink : Raphael.getRGB("rgb(255, 175, 175)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color pink. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
PINK : this.pink,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color orange. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
orange : Raphael.getRGB("rgb(255, 200, 0)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color orange. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
ORANGE : this.orange,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color yellow. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
yellow : Raphael.getRGB("rgb(255, 255, 0)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color yellow. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
YELLOW : this.yellow,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color green. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
green : Raphael.getRGB("rgb(0, 255, 0)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color green. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
GREEN : this.green,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color magenta. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
magenta : Raphael.getRGB("rgb(255, 0, 255)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color magenta. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
MAGENTA : this.magenta,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color cyan. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
cyan : Raphael.getRGB("rgb(0, 255, 255)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color cyan. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
CYAN : this.cyan,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color blue. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
blue : Raphael.getRGB("rgb(0, 0, 255)"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color blue. In the default sRGB space.
|
||||||
|
*/
|
||||||
|
BLUE : this.blue,
|
||||||
|
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
// http://www.stm.dp.ua/web-design/color-html.php
|
||||||
|
|
||||||
|
Snow : Raphael.getRGB("#FFFAFA "), // 255 250 250
|
||||||
|
GhostWhite : Raphael.getRGB("#F8F8FF "), // 248 248 255
|
||||||
|
WhiteSmoke : Raphael.getRGB("#F5F5F5 "), // 245 245 245
|
||||||
|
Gainsboro : Raphael.getRGB("#DCDCDC "), // 220 220 220
|
||||||
|
FloralWhite : Raphael.getRGB("#FFFAF0 "), // 255 250 240
|
||||||
|
OldLace : Raphael.getRGB("#FDF5E6 "), // 253 245 230
|
||||||
|
Linen : Raphael.getRGB("#FAF0E6 "), // 250 240 230
|
||||||
|
AntiqueWhite : Raphael.getRGB("#FAEBD7 "), // 250 235 215
|
||||||
|
PapayaWhip : Raphael.getRGB("#FFEFD5 "), // 255 239 213
|
||||||
|
BlanchedAlmond : Raphael.getRGB("#FFEBCD "), // 255 235 205
|
||||||
|
Bisque : Raphael.getRGB("#FFE4C4 "), // 255 228 196
|
||||||
|
PeachPuff : Raphael.getRGB("#FFDAB9 "), // 255 218 185
|
||||||
|
NavajoWhite : Raphael.getRGB("#FFDEAD "), // 255 222 173
|
||||||
|
Moccasin : Raphael.getRGB("#FFE4B5 "), // 255 228 181
|
||||||
|
Cornsilk : Raphael.getRGB("#FFF8DC "), // 255 248 220
|
||||||
|
Ivory : Raphael.getRGB("#FFFFF0 "), // 255 255 240
|
||||||
|
LemonChiffon : Raphael.getRGB("#FFFACD "), // 255 250 205
|
||||||
|
Seashell : Raphael.getRGB("#FFF5EE "), // 255 245 238
|
||||||
|
Honeydew : Raphael.getRGB("#F0FFF0 "), // 240 255 240
|
||||||
|
MintCream : Raphael.getRGB("#F5FFFA "), // 245 255 250
|
||||||
|
Azure : Raphael.getRGB("#F0FFFF "), // 240 255 255
|
||||||
|
AliceBlue : Raphael.getRGB("#F0F8FF "), // 240 248 255
|
||||||
|
lavender : Raphael.getRGB("#E6E6FA "), // 230 230 250
|
||||||
|
LavenderBlush : Raphael.getRGB("#FFF0F5 "), // 255 240 245
|
||||||
|
MistyRose : Raphael.getRGB("#FFE4E1 "), // 255 228 225
|
||||||
|
White : Raphael.getRGB("#FFFFFF "), // 255 255 255
|
||||||
|
Black : Raphael.getRGB("#000000 "), // 0 0 0
|
||||||
|
DarkSlateGray : Raphael.getRGB("#2F4F4F "), // 47 79 79
|
||||||
|
DimGrey : Raphael.getRGB("#696969 "), // 105 105 105
|
||||||
|
SlateGrey : Raphael.getRGB("#708090 "), // 112 128 144
|
||||||
|
LightSlateGray : Raphael.getRGB("#778899 "), // 119 136 153
|
||||||
|
Grey : Raphael.getRGB("#BEBEBE "), // 190 190 190
|
||||||
|
LightGray : Raphael.getRGB("#D3D3D3 "), // 211 211 211
|
||||||
|
MidnightBlue : Raphael.getRGB("#191970 "), // 25 25 112
|
||||||
|
NavyBlue : Raphael.getRGB("#000080 "), // 0 0 128
|
||||||
|
CornflowerBlue : Raphael.getRGB("#6495ED "), // 100 149 237
|
||||||
|
DarkSlateBlue : Raphael.getRGB("#483D8B "), // 72 61 139
|
||||||
|
SlateBlue : Raphael.getRGB("#6A5ACD "), // 106 90 205
|
||||||
|
MediumSlateBlue : Raphael.getRGB("#7B68EE "), // 123 104 238
|
||||||
|
LightSlateBlue : Raphael.getRGB("#8470FF "), // 132 112 255
|
||||||
|
MediumBlue : Raphael.getRGB("#0000CD "), // 0 0 205
|
||||||
|
RoyalBlue : Raphael.getRGB("#4169E1 "), // 65 105 225
|
||||||
|
Blue : Raphael.getRGB("#0000FF "), // 0 0 255
|
||||||
|
DodgerBlue : Raphael.getRGB("#1E90FF "), // 30 144 255
|
||||||
|
DeepSkyBlue : Raphael.getRGB("#00BFFF "), // 0 191 255
|
||||||
|
SkyBlue : Raphael.getRGB("#87CEEB "), // 135 206 235
|
||||||
|
LightSkyBlue : Raphael.getRGB("#87CEFA "), // 135 206 250
|
||||||
|
SteelBlue : Raphael.getRGB("#4682B4 "), // 70 130 180
|
||||||
|
LightSteelBlue : Raphael.getRGB("#B0C4DE "), // 176 196 222
|
||||||
|
LightBlue : Raphael.getRGB("#ADD8E6 "), // 173 216 230
|
||||||
|
PowderBlue : Raphael.getRGB("#B0E0E6 "), // 176 224 230
|
||||||
|
PaleTurquoise : Raphael.getRGB("#AFEEEE "), // 175 238 238
|
||||||
|
DarkTurquoise : Raphael.getRGB("#00CED1 "), // 0 206 209
|
||||||
|
MediumTurquoise : Raphael.getRGB("#48D1CC "), // 72 209 204
|
||||||
|
Turquoise : Raphael.getRGB("#40E0D0 "), // 64 224 208
|
||||||
|
Cyan : Raphael.getRGB("#00FFFF "), // 0 255 255
|
||||||
|
LightCyan : Raphael.getRGB("#E0FFFF "), // 224 255 255
|
||||||
|
CadetBlue : Raphael.getRGB("#5F9EA0 "), // 95 158 160
|
||||||
|
MediumAquamarine: Raphael.getRGB("#66CDAA "), // 102 205 170
|
||||||
|
Aquamarine : Raphael.getRGB("#7FFFD4 "), // 127 255 212
|
||||||
|
DarkGreen : Raphael.getRGB("#006400 "), // 0 100 0
|
||||||
|
DarkOliveGreen : Raphael.getRGB("#556B2F "), // 85 107 47
|
||||||
|
DarkSeaGreen : Raphael.getRGB("#8FBC8F "), // 143 188 143
|
||||||
|
SeaGreen : Raphael.getRGB("#2E8B57 "), // 46 139 87
|
||||||
|
MediumSeaGreen : Raphael.getRGB("#3CB371 "), // 60 179 113
|
||||||
|
LightSeaGreen : Raphael.getRGB("#20B2AA "), // 32 178 170
|
||||||
|
PaleGreen : Raphael.getRGB("#98FB98 "), // 152 251 152
|
||||||
|
SpringGreen : Raphael.getRGB("#00FF7F "), // 0 255 127
|
||||||
|
LawnGreen : Raphael.getRGB("#7CFC00 "), // 124 252 0
|
||||||
|
Green : Raphael.getRGB("#00FF00 "), // 0 255 0
|
||||||
|
Chartreuse : Raphael.getRGB("#7FFF00 "), // 127 255 0
|
||||||
|
MedSpringGreen : Raphael.getRGB("#00FA9A "), // 0 250 154
|
||||||
|
GreenYellow : Raphael.getRGB("#ADFF2F "), // 173 255 47
|
||||||
|
LimeGreen : Raphael.getRGB("#32CD32 "), // 50 205 50
|
||||||
|
YellowGreen : Raphael.getRGB("#9ACD32 "), // 154 205 50
|
||||||
|
ForestGreen : Raphael.getRGB("#228B22 "), // 34 139 34
|
||||||
|
OliveDrab : Raphael.getRGB("#6B8E23 "), // 107 142 35
|
||||||
|
DarkKhaki : Raphael.getRGB("#BDB76B "), // 189 183 107
|
||||||
|
PaleGoldenrod : Raphael.getRGB("#EEE8AA "), // 238 232 170
|
||||||
|
LtGoldenrodYello: Raphael.getRGB("#FAFAD2 "), // 250 250 210
|
||||||
|
LightYellow : Raphael.getRGB("#FFFFE0 "), // 255 255 224
|
||||||
|
Yellow : Raphael.getRGB("#FFFF00 "), // 255 255 0
|
||||||
|
Gold : Raphael.getRGB("#FFD700 "), // 255 215 0
|
||||||
|
LightGoldenrod : Raphael.getRGB("#EEDD82 "), // 238 221 130
|
||||||
|
goldenrod : Raphael.getRGB("#DAA520 "), // 218 165 32
|
||||||
|
DarkGoldenrod : Raphael.getRGB("#B8860B "), // 184 134 11
|
||||||
|
RosyBrown : Raphael.getRGB("#BC8F8F "), // 188 143 143
|
||||||
|
IndianRed : Raphael.getRGB("#CD5C5C "), // 205 92 92
|
||||||
|
SaddleBrown : Raphael.getRGB("#8B4513 "), // 139 69 19
|
||||||
|
Sienna : Raphael.getRGB("#A0522D "), // 160 82 45
|
||||||
|
Peru : Raphael.getRGB("#CD853F "), // 205 133 63
|
||||||
|
Burlywood : Raphael.getRGB("#DEB887 "), // 222 184 135
|
||||||
|
Beige : Raphael.getRGB("#F5F5DC "), // 245 245 220
|
||||||
|
Wheat : Raphael.getRGB("#F5DEB3 "), // 245 222 179
|
||||||
|
SandyBrown : Raphael.getRGB("#F4A460 "), // 244 164 96
|
||||||
|
Tan : Raphael.getRGB("#D2B48C "), // 210 180 140
|
||||||
|
Chocolate : Raphael.getRGB("#D2691E "), // 210 105 30
|
||||||
|
Firebrick : Raphael.getRGB("#B22222 "), // 178 34 34
|
||||||
|
Brown : Raphael.getRGB("#A52A2A "), // 165 42 42
|
||||||
|
DarkSalmon : Raphael.getRGB("#E9967A "), // 233 150 122
|
||||||
|
Salmon : Raphael.getRGB("#FA8072 "), // 250 128 114
|
||||||
|
LightSalmon : Raphael.getRGB("#FFA07A "), // 255 160 122
|
||||||
|
Orange : Raphael.getRGB("#FFA500 "), // 255 165 0
|
||||||
|
DarkOrange : Raphael.getRGB("#FF8C00 "), // 255 140 0
|
||||||
|
Coral : Raphael.getRGB("#FF7F50 "), // 255 127 80
|
||||||
|
LightCoral : Raphael.getRGB("#F08080 "), // 240 128 128
|
||||||
|
Tomato : Raphael.getRGB("#FF6347 "), // 255 99 71
|
||||||
|
OrangeRed : Raphael.getRGB("#FF4500 "), // 255 69 0
|
||||||
|
Red : Raphael.getRGB("#FF0000 "), // 255 0 0
|
||||||
|
HotPink : Raphael.getRGB("#FF69B4 "), // 255 105 180
|
||||||
|
DeepPink : Raphael.getRGB("#FF1493 "), // 255 20 147
|
||||||
|
Pink : Raphael.getRGB("#FFC0CB "), // 255 192 203
|
||||||
|
LightPink : Raphael.getRGB("#FFB6C1 "), // 255 182 193
|
||||||
|
PaleVioletRed : Raphael.getRGB("#DB7093 "), // 219 112 147
|
||||||
|
Maroon : Raphael.getRGB("#B03060 "), // 176 48 96
|
||||||
|
MediumVioletRed : Raphael.getRGB("#C71585 "), // 199 21 133
|
||||||
|
VioletRed : Raphael.getRGB("#D02090 "), // 208 32 144
|
||||||
|
Magenta : Raphael.getRGB("#FF00FF "), // 255 0 255
|
||||||
|
Violet : Raphael.getRGB("#EE82EE "), // 238 130 238
|
||||||
|
Plum : Raphael.getRGB("#DDA0DD "), // 221 160 221
|
||||||
|
Orchid : Raphael.getRGB("#DA70D6 "), // 218 112 214
|
||||||
|
MediumOrchid : Raphael.getRGB("#BA55D3 "), // 186 85 211
|
||||||
|
DarkOrchid : Raphael.getRGB("#9932CC "), // 153 50 204
|
||||||
|
DarkViolet : Raphael.getRGB("#9400D3 "), // 148 0 211
|
||||||
|
BlueViolet : Raphael.getRGB("#8A2BE2 "), // 138 43 226
|
||||||
|
Purple : Raphael.getRGB("#A020F0 "), // 160 32 240
|
||||||
|
MediumPurple : Raphael.getRGB("#9370DB "), // 147 112 219
|
||||||
|
Thistle : Raphael.getRGB("#D8BFD8 "), // 216 191 216
|
||||||
|
Snow1 : Raphael.getRGB("#FFFAFA "), // 255 250 250
|
||||||
|
Snow2 : Raphael.getRGB("#EEE9E9 "), // 238 233 233
|
||||||
|
Snow3 : Raphael.getRGB("#CDC9C9 "), // 205 201 201
|
||||||
|
Snow4 : Raphael.getRGB("#8B8989 "), // 139 137 137
|
||||||
|
Seashell1 : Raphael.getRGB("#FFF5EE "), // 255 245 238
|
||||||
|
Seashell2 : Raphael.getRGB("#EEE5DE "), // 238 229 222
|
||||||
|
Seashell3 : Raphael.getRGB("#CDC5BF "), // 205 197 191
|
||||||
|
Seashell4 : Raphael.getRGB("#8B8682 "), // 139 134 130
|
||||||
|
AntiqueWhite1 : Raphael.getRGB("#FFEFDB "), // 255 239 219
|
||||||
|
AntiqueWhite2 : Raphael.getRGB("#EEDFCC "), // 238 223 204
|
||||||
|
AntiqueWhite3 : Raphael.getRGB("#CDC0B0 "), // 205 192 176
|
||||||
|
AntiqueWhite4 : Raphael.getRGB("#8B8378 "), // 139 131 120
|
||||||
|
Bisque1 : Raphael.getRGB("#FFE4C4 "), // 255 228 196
|
||||||
|
Bisque2 : Raphael.getRGB("#EED5B7 "), // 238 213 183
|
||||||
|
Bisque3 : Raphael.getRGB("#CDB79E "), // 205 183 158
|
||||||
|
Bisque4 : Raphael.getRGB("#8B7D6B "), // 139 125 107
|
||||||
|
PeachPuff1 : Raphael.getRGB("#FFDAB9 "), // 255 218 185
|
||||||
|
PeachPuff2 : Raphael.getRGB("#EECBAD "), // 238 203 173
|
||||||
|
PeachPuff3 : Raphael.getRGB("#CDAF95 "), // 205 175 149
|
||||||
|
PeachPuff4 : Raphael.getRGB("#8B7765 "), // 139 119 101
|
||||||
|
NavajoWhite1 : Raphael.getRGB("#FFDEAD "), // 255 222 173
|
||||||
|
NavajoWhite2 : Raphael.getRGB("#EECFA1 "), // 238 207 161
|
||||||
|
NavajoWhite3 : Raphael.getRGB("#CDB38B "), // 205 179 139
|
||||||
|
NavajoWhite4 : Raphael.getRGB("#8B795E "), // 139 121 94
|
||||||
|
LemonChiffon1 : Raphael.getRGB("#FFFACD "), // 255 250 205
|
||||||
|
LemonChiffon2 : Raphael.getRGB("#EEE9BF "), // 238 233 191
|
||||||
|
LemonChiffon3 : Raphael.getRGB("#CDC9A5 "), // 205 201 165
|
||||||
|
LemonChiffon4 : Raphael.getRGB("#8B8970 "), // 139 137 112
|
||||||
|
Cornsilk1 : Raphael.getRGB("#FFF8DC "), // 255 248 220
|
||||||
|
Cornsilk2 : Raphael.getRGB("#EEE8CD "), // 238 232 205
|
||||||
|
Cornsilk3 : Raphael.getRGB("#CDC8B1 "), // 205 200 177
|
||||||
|
Cornsilk4 : Raphael.getRGB("#8B8878 "), // 139 136 120
|
||||||
|
Ivory1 : Raphael.getRGB("#FFFFF0 "), // 255 255 240
|
||||||
|
Ivory2 : Raphael.getRGB("#EEEEE0 "), // 238 238 224
|
||||||
|
Ivory3 : Raphael.getRGB("#CDCDC1 "), // 205 205 193
|
||||||
|
Ivory4 : Raphael.getRGB("#8B8B83 "), // 139 139 131
|
||||||
|
Honeydew1 : Raphael.getRGB("#F0FFF0 "), // 240 255 240
|
||||||
|
Honeydew2 : Raphael.getRGB("#E0EEE0 "), // 224 238 224
|
||||||
|
Honeydew3 : Raphael.getRGB("#C1CDC1 "), // 193 205 193
|
||||||
|
Honeydew4 : Raphael.getRGB("#838B83 "), // 131 139 131
|
||||||
|
LavenderBlush1 : Raphael.getRGB("#FFF0F5 "), // 255 240 245
|
||||||
|
LavenderBlush2 : Raphael.getRGB("#EEE0E5 "), // 238 224 229
|
||||||
|
LavenderBlush3 : Raphael.getRGB("#CDC1C5 "), // 205 193 197
|
||||||
|
LavenderBlush4 : Raphael.getRGB("#8B8386 "), // 139 131 134
|
||||||
|
MistyRose1 : Raphael.getRGB("#FFE4E1 "), // 255 228 225
|
||||||
|
MistyRose2 : Raphael.getRGB("#EED5D2 "), // 238 213 210
|
||||||
|
MistyRose3 : Raphael.getRGB("#CDB7B5 "), // 205 183 181
|
||||||
|
MistyRose4 : Raphael.getRGB("#8B7D7B "), // 139 125 123
|
||||||
|
Azure1 : Raphael.getRGB("#F0FFFF "), // 240 255 255
|
||||||
|
Azure2 : Raphael.getRGB("#E0EEEE "), // 224 238 238
|
||||||
|
Azure3 : Raphael.getRGB("#C1CDCD "), // 193 205 205
|
||||||
|
Azure4 : Raphael.getRGB("#838B8B "), // 131 139 139
|
||||||
|
SlateBlue1 : Raphael.getRGB("#836FFF "), // 131 111 255
|
||||||
|
SlateBlue2 : Raphael.getRGB("#7A67EE "), // 122 103 238
|
||||||
|
SlateBlue3 : Raphael.getRGB("#6959CD "), // 105 89 205
|
||||||
|
SlateBlue4 : Raphael.getRGB("#473C8B "), // 71 60 139
|
||||||
|
RoyalBlue1 : Raphael.getRGB("#4876FF "), // 72 118 255
|
||||||
|
RoyalBlue2 : Raphael.getRGB("#436EEE "), // 67 110 238
|
||||||
|
RoyalBlue3 : Raphael.getRGB("#3A5FCD "), // 58 95 205
|
||||||
|
RoyalBlue4 : Raphael.getRGB("#27408B "), // 39 64 139
|
||||||
|
Blue1 : Raphael.getRGB("#0000FF "), // 0 0 255
|
||||||
|
Blue2 : Raphael.getRGB("#0000EE "), // 0 0 238
|
||||||
|
Blue3 : Raphael.getRGB("#0000CD "), // 0 0 205
|
||||||
|
Blue4 : Raphael.getRGB("#00008B "), // 0 0 139
|
||||||
|
DodgerBlue1 : Raphael.getRGB("#1E90FF "), // 30 144 255
|
||||||
|
DodgerBlue2 : Raphael.getRGB("#1C86EE "), // 28 134 238
|
||||||
|
DodgerBlue3 : Raphael.getRGB("#1874CD "), // 24 116 205
|
||||||
|
DodgerBlue4 : Raphael.getRGB("#104E8B "), // 16 78 139
|
||||||
|
SteelBlue1 : Raphael.getRGB("#63B8FF "), // 99 184 255
|
||||||
|
SteelBlue2 : Raphael.getRGB("#5CACEE "), // 92 172 238
|
||||||
|
SteelBlue3 : Raphael.getRGB("#4F94CD "), // 79 148 205
|
||||||
|
SteelBlue4 : Raphael.getRGB("#36648B "), // 54 100 139
|
||||||
|
DeepSkyBlue1 : Raphael.getRGB("#00BFFF "), // 0 191 255
|
||||||
|
DeepSkyBlue2 : Raphael.getRGB("#00B2EE "), // 0 178 238
|
||||||
|
DeepSkyBlue3 : Raphael.getRGB("#009ACD "), // 0 154 205
|
||||||
|
DeepSkyBlue4 : Raphael.getRGB("#00688B "), // 0 104 139
|
||||||
|
SkyBlue1 : Raphael.getRGB("#87CEFF "), // 135 206 255
|
||||||
|
SkyBlue2 : Raphael.getRGB("#7EC0EE "), // 126 192 238
|
||||||
|
SkyBlue3 : Raphael.getRGB("#6CA6CD "), // 108 166 205
|
||||||
|
SkyBlue4 : Raphael.getRGB("#4A708B "), // 74 112 139
|
||||||
|
LightSkyBlue1 : Raphael.getRGB("#B0E2FF "), // 176 226 255
|
||||||
|
LightSkyBlue2 : Raphael.getRGB("#A4D3EE "), // 164 211 238
|
||||||
|
LightSkyBlue3 : Raphael.getRGB("#8DB6CD "), // 141 182 205
|
||||||
|
LightSkyBlue4 : Raphael.getRGB("#607B8B "), // 96 123 139
|
||||||
|
SlateGray1 : Raphael.getRGB("#C6E2FF "), // 198 226 255
|
||||||
|
SlateGray2 : Raphael.getRGB("#B9D3EE "), // 185 211 238
|
||||||
|
SlateGray3 : Raphael.getRGB("#9FB6CD "), // 159 182 205
|
||||||
|
SlateGray4 : Raphael.getRGB("#6C7B8B "), // 108 123 139
|
||||||
|
LightSteelBlue1 : Raphael.getRGB("#CAE1FF "), // 202 225 255
|
||||||
|
LightSteelBlue2 : Raphael.getRGB("#BCD2EE "), // 188 210 238
|
||||||
|
LightSteelBlue3 : Raphael.getRGB("#A2B5CD "), // 162 181 205
|
||||||
|
LightSteelBlue4 : Raphael.getRGB("#6E7B8B "), // 110 123 139
|
||||||
|
LightBlue1 : Raphael.getRGB("#BFEFFF "), // 191 239 255
|
||||||
|
LightBlue2 : Raphael.getRGB("#B2DFEE "), // 178 223 238
|
||||||
|
LightBlue3 : Raphael.getRGB("#9AC0CD "), // 154 192 205
|
||||||
|
LightBlue4 : Raphael.getRGB("#68838B "), // 104 131 139
|
||||||
|
LightCyan1 : Raphael.getRGB("#E0FFFF "), // 224 255 255
|
||||||
|
LightCyan2 : Raphael.getRGB("#D1EEEE "), // 209 238 238
|
||||||
|
LightCyan3 : Raphael.getRGB("#B4CDCD "), // 180 205 205
|
||||||
|
LightCyan4 : Raphael.getRGB("#7A8B8B "), // 122 139 139
|
||||||
|
PaleTurquoise1 : Raphael.getRGB("#BBFFFF "), // 187 255 255
|
||||||
|
PaleTurquoise2 : Raphael.getRGB("#AEEEEE "), // 174 238 238
|
||||||
|
PaleTurquoise3 : Raphael.getRGB("#96CDCD "), // 150 205 205
|
||||||
|
PaleTurquoise4 : Raphael.getRGB("#668B8B "), // 102 139 139
|
||||||
|
CadetBlue1 : Raphael.getRGB("#98F5FF "), // 152 245 255
|
||||||
|
CadetBlue2 : Raphael.getRGB("#8EE5EE "), // 142 229 238
|
||||||
|
CadetBlue3 : Raphael.getRGB("#7AC5CD "), // 122 197 205
|
||||||
|
CadetBlue4 : Raphael.getRGB("#53868B "), // 83 134 139
|
||||||
|
Turquoise1 : Raphael.getRGB("#00F5FF "), // 0 245 255
|
||||||
|
Turquoise2 : Raphael.getRGB("#00E5EE "), // 0 229 238
|
||||||
|
Turquoise3 : Raphael.getRGB("#00C5CD "), // 0 197 205
|
||||||
|
Turquoise4 : Raphael.getRGB("#00868B "), // 0 134 139
|
||||||
|
Cyan1 : Raphael.getRGB("#00FFFF "), // 0 255 255
|
||||||
|
Cyan2 : Raphael.getRGB("#00EEEE "), // 0 238 238
|
||||||
|
Cyan3 : Raphael.getRGB("#00CDCD "), // 0 205 205
|
||||||
|
Cyan4 : Raphael.getRGB("#008B8B "), // 0 139 139
|
||||||
|
DarkSlateGray1 : Raphael.getRGB("#97FFFF "), // 151 255 255
|
||||||
|
DarkSlateGray2 : Raphael.getRGB("#8DEEEE "), // 141 238 238
|
||||||
|
DarkSlateGray3 : Raphael.getRGB("#79CDCD "), // 121 205 205
|
||||||
|
DarkSlateGray4 : Raphael.getRGB("#528B8B "), // 82 139 139
|
||||||
|
Aquamarine1 : Raphael.getRGB("#7FFFD4 "), // 127 255 212
|
||||||
|
Aquamarine2 : Raphael.getRGB("#76EEC6 "), // 118 238 198
|
||||||
|
Aquamarine3 : Raphael.getRGB("#66CDAA "), // 102 205 170
|
||||||
|
Aquamarine4 : Raphael.getRGB("#458B74 "), // 69 139 116
|
||||||
|
DarkSeaGreen1 : Raphael.getRGB("#C1FFC1 "), // 193 255 193
|
||||||
|
DarkSeaGreen2 : Raphael.getRGB("#B4EEB4 "), // 180 238 180
|
||||||
|
DarkSeaGreen3 : Raphael.getRGB("#9BCD9B "), // 155 205 155
|
||||||
|
DarkSeaGreen4 : Raphael.getRGB("#698B69 "), // 105 139 105
|
||||||
|
SeaGreen1 : Raphael.getRGB("#54FF9F "), // 84 255 159
|
||||||
|
SeaGreen2 : Raphael.getRGB("#4EEE94 "), // 78 238 148
|
||||||
|
SeaGreen3 : Raphael.getRGB("#43CD80 "), // 67 205 128
|
||||||
|
SeaGreen4 : Raphael.getRGB("#2E8B57 "), // 46 139 87
|
||||||
|
PaleGreen1 : Raphael.getRGB("#9AFF9A "), // 154 255 154
|
||||||
|
PaleGreen2 : Raphael.getRGB("#90EE90 "), // 144 238 144
|
||||||
|
PaleGreen3 : Raphael.getRGB("#7CCD7C "), // 124 205 124
|
||||||
|
PaleGreen4 : Raphael.getRGB("#548B54 "), // 84 139 84
|
||||||
|
SpringGreen1 : Raphael.getRGB("#00FF7F "), // 0 255 127
|
||||||
|
SpringGreen2 : Raphael.getRGB("#00EE76 "), // 0 238 118
|
||||||
|
SpringGreen3 : Raphael.getRGB("#00CD66 "), // 0 205 102
|
||||||
|
SpringGreen4 : Raphael.getRGB("#008B45 "), // 0 139 69
|
||||||
|
Green1 : Raphael.getRGB("#00FF00 "), // 0 255 0
|
||||||
|
Green2 : Raphael.getRGB("#00EE00 "), // 0 238 0
|
||||||
|
Green3 : Raphael.getRGB("#00CD00 "), // 0 205 0
|
||||||
|
Green4 : Raphael.getRGB("#008B00 "), // 0 139 0
|
||||||
|
Chartreuse1 : Raphael.getRGB("#7FFF00 "), // 127 255 0
|
||||||
|
Chartreuse2 : Raphael.getRGB("#76EE00 "), // 118 238 0
|
||||||
|
Chartreuse3 : Raphael.getRGB("#66CD00 "), // 102 205 0
|
||||||
|
Chartreuse4 : Raphael.getRGB("#458B00 "), // 69 139 0
|
||||||
|
OliveDrab1 : Raphael.getRGB("#C0FF3E "), // 192 255 62
|
||||||
|
OliveDrab2 : Raphael.getRGB("#B3EE3A "), // 179 238 58
|
||||||
|
OliveDrab3 : Raphael.getRGB("#9ACD32 "), // 154 205 50
|
||||||
|
OliveDrab4 : Raphael.getRGB("#698B22 "), // 105 139 34
|
||||||
|
DarkOliveGreen1 : Raphael.getRGB("#CAFF70 "), // 202 255 112
|
||||||
|
DarkOliveGreen2 : Raphael.getRGB("#BCEE68 "), // 188 238 104
|
||||||
|
DarkOliveGreen3 : Raphael.getRGB("#A2CD5A "), // 162 205 90
|
||||||
|
DarkOliveGreen4 : Raphael.getRGB("#6E8B3D "), // 110 139 61
|
||||||
|
Khaki1 : Raphael.getRGB("#FFF68F "), // 255 246 143
|
||||||
|
Khaki2 : Raphael.getRGB("#EEE685 "), // 238 230 133
|
||||||
|
Khaki3 : Raphael.getRGB("#CDC673 "), // 205 198 115
|
||||||
|
Khaki4 : Raphael.getRGB("#8B864E "), // 139 134 78
|
||||||
|
LightGoldenrod1 : Raphael.getRGB("#FFEC8B "), // 255 236 139
|
||||||
|
LightGoldenrod2 : Raphael.getRGB("#EEDC82 "), // 238 220 130
|
||||||
|
LightGoldenrod3 : Raphael.getRGB("#CDBE70 "), // 205 190 112
|
||||||
|
LightGoldenrod4 : Raphael.getRGB("#8B814C "), // 139 129 76
|
||||||
|
LightYellow1 : Raphael.getRGB("#FFFFE0 "), // 255 255 224
|
||||||
|
LightYellow2 : Raphael.getRGB("#EEEED1 "), // 238 238 209
|
||||||
|
LightYellow3 : Raphael.getRGB("#CDCDB4 "), // 205 205 180
|
||||||
|
LightYellow4 : Raphael.getRGB("#8B8B7A "), // 139 139 122
|
||||||
|
Yellow1 : Raphael.getRGB("#FFFF00 "), // 255 255 0
|
||||||
|
Yellow2 : Raphael.getRGB("#EEEE00 "), // 238 238 0
|
||||||
|
Yellow3 : Raphael.getRGB("#CDCD00 "), // 205 205 0
|
||||||
|
Yellow4 : Raphael.getRGB("#8B8B00 "), // 139 139 0
|
||||||
|
Gold1 : Raphael.getRGB("#FFD700 "), // 255 215 0
|
||||||
|
Gold2 : Raphael.getRGB("#EEC900 "), // 238 201 0
|
||||||
|
Gold3 : Raphael.getRGB("#CDAD00 "), // 205 173 0
|
||||||
|
Gold4 : Raphael.getRGB("#8B7500 "), // 139 117 0
|
||||||
|
Goldenrod1 : Raphael.getRGB("#FFC125 "), // 255 193 37
|
||||||
|
Goldenrod2 : Raphael.getRGB("#EEB422 "), // 238 180 34
|
||||||
|
Goldenrod3 : Raphael.getRGB("#CD9B1D "), // 205 155 29
|
||||||
|
Goldenrod4 : Raphael.getRGB("#8B6914 "), // 139 105 20
|
||||||
|
DarkGoldenrod1 : Raphael.getRGB("#FFB90F "), // 255 185 15
|
||||||
|
DarkGoldenrod2 : Raphael.getRGB("#EEAD0E "), // 238 173 14
|
||||||
|
DarkGoldenrod3 : Raphael.getRGB("#CD950C "), // 205 149 12
|
||||||
|
DarkGoldenrod4 : Raphael.getRGB("#8B658B "), // 139 101 8
|
||||||
|
RosyBrown1 : Raphael.getRGB("#FFC1C1 "), // 255 193 193
|
||||||
|
RosyBrown2 : Raphael.getRGB("#EEB4B4 "), // 238 180 180
|
||||||
|
RosyBrown3 : Raphael.getRGB("#CD9B9B "), // 205 155 155
|
||||||
|
RosyBrown4 : Raphael.getRGB("#8B6969 "), // 139 105 105
|
||||||
|
IndianRed1 : Raphael.getRGB("#FF6A6A "), // 255 106 106
|
||||||
|
IndianRed2 : Raphael.getRGB("#EE6363 "), // 238 99 99
|
||||||
|
IndianRed3 : Raphael.getRGB("#CD5555 "), // 205 85 85
|
||||||
|
IndianRed4 : Raphael.getRGB("#8B3A3A "), // 139 58 58
|
||||||
|
Sienna1 : Raphael.getRGB("#FF8247 "), // 255 130 71
|
||||||
|
Sienna2 : Raphael.getRGB("#EE7942 "), // 238 121 66
|
||||||
|
Sienna3 : Raphael.getRGB("#CD6839 "), // 205 104 57
|
||||||
|
Sienna4 : Raphael.getRGB("#8B4726 "), // 139 71 38
|
||||||
|
Burlywood1 : Raphael.getRGB("#FFD39B "), // 255 211 155
|
||||||
|
Burlywood2 : Raphael.getRGB("#EEC591 "), // 238 197 145
|
||||||
|
Burlywood3 : Raphael.getRGB("#CDAA7D "), // 205 170 125
|
||||||
|
Burlywood4 : Raphael.getRGB("#8B7355 "), // 139 115 85
|
||||||
|
Wheat1 : Raphael.getRGB("#FFE7BA "), // 255 231 186
|
||||||
|
Wheat2 : Raphael.getRGB("#EED8AE "), // 238 216 174
|
||||||
|
Wheat3 : Raphael.getRGB("#CDBA96 "), // 205 186 150
|
||||||
|
Wheat4 : Raphael.getRGB("#8B7E66 "), // 139 126 102
|
||||||
|
Tan1 : Raphael.getRGB("#FFA54F "), // 255 165 79
|
||||||
|
Tan2 : Raphael.getRGB("#EE9A49 "), // 238 154 73
|
||||||
|
Tan3 : Raphael.getRGB("#CD853F "), // 205 133 63
|
||||||
|
Tan4 : Raphael.getRGB("#8B5A2B "), // 139 90 43
|
||||||
|
Chocolate1 : Raphael.getRGB("#FF7F24 "), // 255 127 36
|
||||||
|
Chocolate2 : Raphael.getRGB("#EE7621 "), // 238 118 33
|
||||||
|
Chocolate3 : Raphael.getRGB("#CD661D "), // 205 102 29
|
||||||
|
Chocolate4 : Raphael.getRGB("#8B4513 "), // 139 69 19
|
||||||
|
Firebrick1 : Raphael.getRGB("#FF3030 "), // 255 48 48
|
||||||
|
Firebrick2 : Raphael.getRGB("#EE2C2C "), // 238 44 44
|
||||||
|
Firebrick3 : Raphael.getRGB("#CD2626 "), // 205 38 38
|
||||||
|
Firebrick4 : Raphael.getRGB("#8B1A1A "), // 139 26 26
|
||||||
|
Brown1 : Raphael.getRGB("#FF4040 "), // 255 64 64
|
||||||
|
Brown2 : Raphael.getRGB("#EE3B3B "), // 238 59 59
|
||||||
|
Brown3 : Raphael.getRGB("#CD3333 "), // 205 51 51
|
||||||
|
Brown4 : Raphael.getRGB("#8B2323 "), // 139 35 35
|
||||||
|
Salmon1 : Raphael.getRGB("#FF8C69 "), // 255 140 105
|
||||||
|
Salmon2 : Raphael.getRGB("#EE8262 "), // 238 130 98
|
||||||
|
Salmon3 : Raphael.getRGB("#CD7054 "), // 205 112 84
|
||||||
|
Salmon4 : Raphael.getRGB("#8B4C39 "), // 139 76 57
|
||||||
|
LightSalmon1 : Raphael.getRGB("#FFA07A "), // 255 160 122
|
||||||
|
LightSalmon2 : Raphael.getRGB("#EE9572 "), // 238 149 114
|
||||||
|
LightSalmon3 : Raphael.getRGB("#CD8162 "), // 205 129 98
|
||||||
|
LightSalmon4 : Raphael.getRGB("#8B5742 "), // 139 87 66
|
||||||
|
Orange1 : Raphael.getRGB("#FFA500 "), // 255 165 0
|
||||||
|
Orange2 : Raphael.getRGB("#EE9A00 "), // 238 154 0
|
||||||
|
Orange3 : Raphael.getRGB("#CD8500 "), // 205 133 0
|
||||||
|
Orange4 : Raphael.getRGB("#8B5A00 "), // 139 90 0
|
||||||
|
DarkOrange1 : Raphael.getRGB("#FF7F00 "), // 255 127 0
|
||||||
|
DarkOrange2 : Raphael.getRGB("#EE7600 "), // 238 118 0
|
||||||
|
DarkOrange3 : Raphael.getRGB("#CD6600 "), // 205 102 0
|
||||||
|
DarkOrange4 : Raphael.getRGB("#8B4500 "), // 139 69 0
|
||||||
|
Coral1 : Raphael.getRGB("#FF7256 "), // 255 114 86
|
||||||
|
Coral2 : Raphael.getRGB("#EE6A50 "), // 238 106 80
|
||||||
|
Coral3 : Raphael.getRGB("#CD5B45 "), // 205 91 69
|
||||||
|
Coral4 : Raphael.getRGB("#8B3E2F "), // 139 62 47
|
||||||
|
Tomato1 : Raphael.getRGB("#FF6347 "), // 255 99 71
|
||||||
|
Tomato2 : Raphael.getRGB("#EE5C42 "), // 238 92 66
|
||||||
|
Tomato3 : Raphael.getRGB("#CD4F39 "), // 205 79 57
|
||||||
|
Tomato4 : Raphael.getRGB("#8B3626 "), // 139 54 38
|
||||||
|
OrangeRed1 : Raphael.getRGB("#FF4500 "), // 255 69 0
|
||||||
|
OrangeRed2 : Raphael.getRGB("#EE4000 "), // 238 64 0
|
||||||
|
OrangeRed3 : Raphael.getRGB("#CD3700 "), // 205 55 0
|
||||||
|
OrangeRed4 : Raphael.getRGB("#8B2500 "), // 139 37 0
|
||||||
|
Red1 : Raphael.getRGB("#FF0000 "), // 255 0 0
|
||||||
|
Red2 : Raphael.getRGB("#EE0000 "), // 238 0 0
|
||||||
|
Red3 : Raphael.getRGB("#CD0000 "), // 205 0 0
|
||||||
|
Red4 : Raphael.getRGB("#8B0000 "), // 139 0 0
|
||||||
|
DeepPink1 : Raphael.getRGB("#FF1493 "), // 255 20 147
|
||||||
|
DeepPink2 : Raphael.getRGB("#EE1289 "), // 238 18 137
|
||||||
|
DeepPink3 : Raphael.getRGB("#CD1076 "), // 205 16 118
|
||||||
|
DeepPink4 : Raphael.getRGB("#8B0A50 "), // 139 10 80
|
||||||
|
HotPink1 : Raphael.getRGB("#FF6EB4 "), // 255 110 180
|
||||||
|
HotPink2 : Raphael.getRGB("#EE6AA7 "), // 238 106 167
|
||||||
|
HotPink3 : Raphael.getRGB("#CD6090 "), // 205 96 144
|
||||||
|
HotPink4 : Raphael.getRGB("#8B3A62 "), // 139 58 98
|
||||||
|
Pink1 : Raphael.getRGB("#FFB5C5 "), // 255 181 197
|
||||||
|
Pink2 : Raphael.getRGB("#EEA9B8 "), // 238 169 184
|
||||||
|
Pink3 : Raphael.getRGB("#CD919E "), // 205 145 158
|
||||||
|
Pink4 : Raphael.getRGB("#8B636C "), // 139 99 108
|
||||||
|
LightPink1 : Raphael.getRGB("#FFAEB9 "), // 255 174 185
|
||||||
|
LightPink2 : Raphael.getRGB("#EEA2AD "), // 238 162 173
|
||||||
|
LightPink3 : Raphael.getRGB("#CD8C95 "), // 205 140 149
|
||||||
|
LightPink4 : Raphael.getRGB("#8B5F65 "), // 139 95 101
|
||||||
|
PaleVioletRed1 : Raphael.getRGB("#FF82AB "), // 255 130 171
|
||||||
|
PaleVioletRed2 : Raphael.getRGB("#EE799F "), // 238 121 159
|
||||||
|
PaleVioletRed3 : Raphael.getRGB("#CD6889 "), // 205 104 137
|
||||||
|
PaleVioletRed4 : Raphael.getRGB("#8B475D "), // 139 71 93
|
||||||
|
Maroon1 : Raphael.getRGB("#FF34B3 "), // 255 52 179
|
||||||
|
Maroon2 : Raphael.getRGB("#EE30A7 "), // 238 48 167
|
||||||
|
Maroon3 : Raphael.getRGB("#CD2990 "), // 205 41 144
|
||||||
|
Maroon4 : Raphael.getRGB("#8B1C62 "), // 139 28 98
|
||||||
|
VioletRed1 : Raphael.getRGB("#FF3E96 "), // 255 62 150
|
||||||
|
VioletRed2 : Raphael.getRGB("#EE3A8C "), // 238 58 140
|
||||||
|
VioletRed3 : Raphael.getRGB("#CD3278 "), // 205 50 120
|
||||||
|
VioletRed4 : Raphael.getRGB("#8B2252 "), // 139 34 82
|
||||||
|
Magenta1 : Raphael.getRGB("#FF00FF "), // 255 0 255
|
||||||
|
Magenta2 : Raphael.getRGB("#EE00EE "), // 238 0 238
|
||||||
|
Magenta3 : Raphael.getRGB("#CD00CD "), // 205 0 205
|
||||||
|
Magenta4 : Raphael.getRGB("#8B008B "), // 139 0 139
|
||||||
|
Orchid1 : Raphael.getRGB("#FF83FA "), // 255 131 250
|
||||||
|
Orchid2 : Raphael.getRGB("#EE7AE9 "), // 238 122 233
|
||||||
|
Orchid3 : Raphael.getRGB("#CD69C9 "), // 205 105 201
|
||||||
|
Orchid4 : Raphael.getRGB("#8B4789 "), // 139 71 137
|
||||||
|
Plum1 : Raphael.getRGB("#FFBBFF "), // 255 187 255
|
||||||
|
Plum2 : Raphael.getRGB("#EEAEEE "), // 238 174 238
|
||||||
|
Plum3 : Raphael.getRGB("#CD96CD "), // 205 150 205
|
||||||
|
Plum4 : Raphael.getRGB("#8B668B "), // 139 102 139
|
||||||
|
MediumOrchid1 : Raphael.getRGB("#E066FF "), // 224 102 255
|
||||||
|
MediumOrchid2 : Raphael.getRGB("#D15FEE "), // 209 95 238
|
||||||
|
MediumOrchid3 : Raphael.getRGB("#B452CD "), // 180 82 205
|
||||||
|
MediumOrchid4 : Raphael.getRGB("#7A378B "), // 122 55 139
|
||||||
|
DarkOrchid1 : Raphael.getRGB("#BF3EFF "), // 191 62 255
|
||||||
|
DarkOrchid2 : Raphael.getRGB("#B23AEE "), // 178 58 238
|
||||||
|
DarkOrchid3 : Raphael.getRGB("#9A32CD "), // 154 50 205
|
||||||
|
DarkOrchid4 : Raphael.getRGB("#68228B "), // 104 34 139
|
||||||
|
Purple1 : Raphael.getRGB("#9B30FF "), // 155 48 255
|
||||||
|
Purple2 : Raphael.getRGB("#912CEE "), // 145 44 238
|
||||||
|
Purple3 : Raphael.getRGB("#7D26CD "), // 125 38 205
|
||||||
|
Purple4 : Raphael.getRGB("#551A8B "), // 85 26 139
|
||||||
|
MediumPurple1 : Raphael.getRGB("#AB82FF "), // 171 130 255
|
||||||
|
MediumPurple2 : Raphael.getRGB("#9F79EE "), // 159 121 238
|
||||||
|
MediumPurple3 : Raphael.getRGB("#8968CD "), // 137 104 205
|
||||||
|
MediumPurple4 : Raphael.getRGB("#5D478B "), // 93 71 139
|
||||||
|
Thistle1 : Raphael.getRGB("#FFE1FF "), // 255 225 255
|
||||||
|
Thistle2 : Raphael.getRGB("#EED2EE "), // 238 210 238
|
||||||
|
Thistle3 : Raphael.getRGB("#CDB5CD "), // 205 181 205
|
||||||
|
Thistle4 : Raphael.getRGB("#8B7B8B "), // 139 123 139
|
||||||
|
grey11 : Raphael.getRGB("#1C1C1C "), // 28 28 28
|
||||||
|
grey21 : Raphael.getRGB("#363636 "), // 54 54 54
|
||||||
|
grey31 : Raphael.getRGB("#4F4F4F "), // 79 79 79
|
||||||
|
grey41 : Raphael.getRGB("#696969 "), // 105 105 105
|
||||||
|
grey51 : Raphael.getRGB("#828282 "), // 130 130 130
|
||||||
|
grey61 : Raphael.getRGB("#9C9C9C "), // 156 156 156
|
||||||
|
grey71 : Raphael.getRGB("#B5B5B5 "), // 181 181 181
|
||||||
|
gray81 : Raphael.getRGB("#CFCFCF "), // 207 207 207
|
||||||
|
gray91 : Raphael.getRGB("#E8E8E8 "), // 232 232 232
|
||||||
|
DarkGrey : Raphael.getRGB("#A9A9A9 "), // 169 169 169
|
||||||
|
DarkBlue : Raphael.getRGB("#00008B "), // 0 0 139
|
||||||
|
DarkCyan : Raphael.getRGB("#008B8B "), // 0 139 139
|
||||||
|
DarkMagenta : Raphael.getRGB("#8B008B "), // 139 0 139
|
||||||
|
DarkRed : Raphael.getRGB("#8B0000 "), // 139 0 0
|
||||||
|
LightGreen : Raphael.getRGB("#90EE90 "), // 144 238 144
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
get: function(R, G, B){
|
||||||
|
return Raphael.getRGB("rgb(" + R + ", " + G + ", " + B + ")");
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,270 @@
|
||||||
|
/**
|
||||||
|
* Word wrapping
|
||||||
|
*
|
||||||
|
* @author (Javascript) Dmitry Farafonov
|
||||||
|
*/
|
||||||
|
|
||||||
|
var AttributedStringIterator = function(text){
|
||||||
|
//this.text = this.rtrim(this.ltrim(text));
|
||||||
|
text = text.replace(/(\s)+/, " ");
|
||||||
|
this.text = this.rtrim(text);
|
||||||
|
/*
|
||||||
|
if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
|
||||||
|
throw new IllegalArgumentException("Invalid substring range");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
this.beginIndex = 0;
|
||||||
|
this.endIndex = this.text.length;
|
||||||
|
this.currentIndex = this.beginIndex;
|
||||||
|
|
||||||
|
//console.group("[AttributedStringIterator]");
|
||||||
|
var i = 0;
|
||||||
|
var string = this.text;
|
||||||
|
var fullPos = 0;
|
||||||
|
|
||||||
|
//console.log("string: \"" + string + "\", length: " + string.length);
|
||||||
|
this.startWordOffsets = [];
|
||||||
|
this.startWordOffsets.push(fullPos);
|
||||||
|
|
||||||
|
// TODO: remove i 1000
|
||||||
|
while (i<1000) {
|
||||||
|
var pos = string.search(/[ \t\n\f-\.\,]/);
|
||||||
|
if (pos == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// whitespace start
|
||||||
|
fullPos += pos;
|
||||||
|
string = string.substr(pos);
|
||||||
|
////console.log("fullPos: " + fullPos + ", pos: " + pos + ", string: ", string);
|
||||||
|
|
||||||
|
// remove whitespaces
|
||||||
|
var pos = string.search(/[^ \t\n\f-\.\,]/);
|
||||||
|
if (pos == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// whitespace end
|
||||||
|
fullPos += pos;
|
||||||
|
string = string.substr(pos);
|
||||||
|
|
||||||
|
////console.log("fullPos: " + fullPos);
|
||||||
|
this.startWordOffsets.push(fullPos);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
//console.log("startWordOffsets: ", this.startWordOffsets);
|
||||||
|
//console.groupEnd();
|
||||||
|
};
|
||||||
|
AttributedStringIterator.prototype = {
|
||||||
|
getEndIndex: function(pos){
|
||||||
|
if (typeof(pos) == "undefined")
|
||||||
|
return this.endIndex;
|
||||||
|
|
||||||
|
var string = this.text.substr(pos, this.endIndex - pos);
|
||||||
|
|
||||||
|
var posEndOfLine = string.search(/[\n]/);
|
||||||
|
if (posEndOfLine == -1)
|
||||||
|
return this.endIndex;
|
||||||
|
else
|
||||||
|
return pos + posEndOfLine;
|
||||||
|
},
|
||||||
|
getBeginIndex: function(){
|
||||||
|
return this.beginIndex;
|
||||||
|
},
|
||||||
|
isWhitespace: function(pos){
|
||||||
|
var str = this.text[pos];
|
||||||
|
var whitespaceChars = " \t\n\f";
|
||||||
|
|
||||||
|
return (whitespaceChars.indexOf(str) != -1);
|
||||||
|
},
|
||||||
|
isNewLine: function(pos){
|
||||||
|
var str = this.text[pos];
|
||||||
|
var whitespaceChars = "\n";
|
||||||
|
|
||||||
|
return (whitespaceChars.indexOf(str) != -1);
|
||||||
|
},
|
||||||
|
preceding: function(pos){
|
||||||
|
//console.group("[AttributedStringIterator.preceding]");
|
||||||
|
for(var i in this.startWordOffsets) {
|
||||||
|
var startWordOffset = this.startWordOffsets[i];
|
||||||
|
if (pos < startWordOffset && i>0) {
|
||||||
|
//console.log("startWordOffset: " + this.startWordOffsets[i-1]);
|
||||||
|
//console.groupEnd();
|
||||||
|
return this.startWordOffsets[i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.log("pos: " + pos);
|
||||||
|
//console.groupEnd();
|
||||||
|
return this.startWordOffsets[i];
|
||||||
|
},
|
||||||
|
following: function(pos){
|
||||||
|
//console.group("[AttributedStringIterator.following]");
|
||||||
|
for(var i in this.startWordOffsets) {
|
||||||
|
var startWordOffset = this.startWordOffsets[i];
|
||||||
|
if (pos < startWordOffset && i>0) {
|
||||||
|
//console.log("startWordOffset: " + this.startWordOffsets[i]);
|
||||||
|
//console.groupEnd();
|
||||||
|
return this.startWordOffsets[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.log("pos: " + pos);
|
||||||
|
//console.groupEnd();
|
||||||
|
return this.startWordOffsets[i];
|
||||||
|
},
|
||||||
|
ltrim: function(str){
|
||||||
|
var patt2=/^\s+/g;
|
||||||
|
return str.replace(patt2, "");
|
||||||
|
},
|
||||||
|
rtrim: function(str){
|
||||||
|
var patt2=/\s+$/g;
|
||||||
|
return str.replace(patt2, "");
|
||||||
|
},
|
||||||
|
getLayout: function(start, limit){
|
||||||
|
return this.text.substr(start, limit - start);
|
||||||
|
},
|
||||||
|
getCharAtPos: function(pos) {
|
||||||
|
return this.text[pos];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var LineBreakMeasurer = function(paper, x, y, text, fontAttrs){
|
||||||
|
this.paper = paper;
|
||||||
|
this.text = new AttributedStringIterator(text);
|
||||||
|
this.fontAttrs = fontAttrs;
|
||||||
|
|
||||||
|
if (this.text.getEndIndex() - this.text.getBeginIndex() < 1) {
|
||||||
|
throw {message: "Text must contain at least one character.", code: "IllegalArgumentException"};
|
||||||
|
}
|
||||||
|
|
||||||
|
//this.measurer = new TextMeasurer(paper, this.text, this.fontAttrs);
|
||||||
|
this.limit = this.text.getEndIndex();
|
||||||
|
this.pos = this.start = this.text.getBeginIndex();
|
||||||
|
|
||||||
|
this.rafaelTextObject = this.paper.text(x, y, this.text.text).attr(fontAttrs).attr("text-anchor", "start");
|
||||||
|
this.svgTextObject = this.rafaelTextObject[0];
|
||||||
|
};
|
||||||
|
LineBreakMeasurer.prototype = {
|
||||||
|
nextOffset: function(wrappingWidth, offsetLimit, requireNextWord) {
|
||||||
|
//console.group("[nextOffset]");
|
||||||
|
var nextOffset = this.pos;
|
||||||
|
if (this.pos < this.limit) {
|
||||||
|
if (offsetLimit <= this.pos) {
|
||||||
|
throw {message: "offsetLimit must be after current position", code: "IllegalArgumentException"};
|
||||||
|
}
|
||||||
|
|
||||||
|
var charAtMaxAdvance = this.getLineBreakIndex(this.pos, wrappingWidth);
|
||||||
|
//charAtMaxAdvance --;
|
||||||
|
//console.log("charAtMaxAdvance:", charAtMaxAdvance, ", [" + this.text.getCharAtPos(charAtMaxAdvance) + "]");
|
||||||
|
|
||||||
|
if (charAtMaxAdvance == this.limit) {
|
||||||
|
nextOffset = this.limit;
|
||||||
|
//console.log("charAtMaxAdvance == this.limit");
|
||||||
|
} else if (this.text.isNewLine(charAtMaxAdvance)) {
|
||||||
|
//console.log("isNewLine");
|
||||||
|
nextOffset = charAtMaxAdvance+1;
|
||||||
|
} else if (this.text.isWhitespace(charAtMaxAdvance)) {
|
||||||
|
// TODO: find next noSpaceChar
|
||||||
|
//return nextOffset;
|
||||||
|
nextOffset = this.text.following(charAtMaxAdvance);
|
||||||
|
} else {
|
||||||
|
// Break is in a word; back up to previous break.
|
||||||
|
/*
|
||||||
|
var testPos = charAtMaxAdvance + 1;
|
||||||
|
if (testPos == this.limit) {
|
||||||
|
console.error("hbz...");
|
||||||
|
} else {
|
||||||
|
nextOffset = this.text.preceding(charAtMaxAdvance);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
nextOffset = this.text.preceding(charAtMaxAdvance);
|
||||||
|
|
||||||
|
if (nextOffset <= this.pos) {
|
||||||
|
nextOffset = Math.max(this.pos+1, charAtMaxAdvance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nextOffset > offsetLimit) {
|
||||||
|
nextOffset = offsetLimit;
|
||||||
|
}
|
||||||
|
//console.log("nextOffset: " + nextOffset);
|
||||||
|
//console.groupEnd();
|
||||||
|
return nextOffset;
|
||||||
|
},
|
||||||
|
nextLayout: function(wrappingWidth) {
|
||||||
|
//console.groupCollapsed("[nextLayout]");
|
||||||
|
if (this.pos < this.limit) {
|
||||||
|
var requireNextWord = false;
|
||||||
|
var layoutLimit = this.nextOffset(wrappingWidth, this.limit, requireNextWord);
|
||||||
|
//console.log("layoutLimit:", layoutLimit);
|
||||||
|
if (layoutLimit == this.pos) {
|
||||||
|
//console.groupEnd();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var result = this.text.getLayout(this.pos, layoutLimit);
|
||||||
|
//console.log("layout: \"" + result + "\"");
|
||||||
|
|
||||||
|
// remove end of line
|
||||||
|
|
||||||
|
//var posEndOfLine = this.text.getEndIndex(this.pos);
|
||||||
|
//if (posEndOfLine < result.length)
|
||||||
|
// result = result.substr(0, posEndOfLine);
|
||||||
|
|
||||||
|
this.pos = layoutLimit;
|
||||||
|
|
||||||
|
//console.groupEnd();
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
//console.groupEnd();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getLineBreakIndex: function(pos, wrappingWidth) {
|
||||||
|
//console.group("[getLineBreakIndex]");
|
||||||
|
//console.log("pos:"+pos + ", text: \""+ this.text.text.replace(/\n/g, "_").substr(pos, 1) + "\"");
|
||||||
|
|
||||||
|
var bb = this.rafaelTextObject.getBBox();
|
||||||
|
|
||||||
|
var charNum = -1;
|
||||||
|
try {
|
||||||
|
var svgPoint = this.svgTextObject.getStartPositionOfChar(pos);
|
||||||
|
//var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.blue});
|
||||||
|
svgPoint.x = svgPoint.x + wrappingWidth;
|
||||||
|
//svgPoint.y = bb.y;
|
||||||
|
//console.log("svgPoint:", svgPoint);
|
||||||
|
|
||||||
|
//var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.red});
|
||||||
|
|
||||||
|
charNum = this.svgTextObject.getCharNumAtPosition(svgPoint);
|
||||||
|
} catch (e){
|
||||||
|
console.warn("getStartPositionOfChar error, pos:" + pos);
|
||||||
|
/*
|
||||||
|
var testPos = pos + 1;
|
||||||
|
if (testPos < this.limit) {
|
||||||
|
return testPos
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
//console.log("charNum:", charNum);
|
||||||
|
if (charNum == -1) {
|
||||||
|
//console.groupEnd();
|
||||||
|
return this.text.getEndIndex(pos);
|
||||||
|
} else {
|
||||||
|
// When case there is new line between pos and charnum then use this new line
|
||||||
|
var newLineIndex = this.text.getEndIndex(pos);
|
||||||
|
if (newLineIndex < charNum ) {
|
||||||
|
console.log("newLineIndex <= charNum, newLineIndex:"+newLineIndex+", charNum:"+charNum, "\"" + this.text.text.substr(newLineIndex+1).replace(/\n/g, "?") + "\"");
|
||||||
|
//console.groupEnd();
|
||||||
|
|
||||||
|
return newLineIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
//var charAtMaxAdvance = this.text.text.substring(charNum, charNum + 1);
|
||||||
|
var charAtMaxAdvance = this.text.getCharAtPos(charNum);
|
||||||
|
//console.log("!!charAtMaxAdvance: " + charAtMaxAdvance);
|
||||||
|
//console.groupEnd();
|
||||||
|
return charNum;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getPosition: function() {
|
||||||
|
return this.pos;
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,387 @@
|
||||||
|
/**
|
||||||
|
* Class to generate polyline
|
||||||
|
*
|
||||||
|
* @author Dmitry Farafonov
|
||||||
|
*/
|
||||||
|
|
||||||
|
var ANCHOR_TYPE= {
|
||||||
|
main: "main",
|
||||||
|
middle: "middle",
|
||||||
|
first: "first",
|
||||||
|
last: "last"
|
||||||
|
};
|
||||||
|
|
||||||
|
function Anchor(uuid, type, x, y) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.x = x
|
||||||
|
this.y = y
|
||||||
|
this.type = (type == ANCHOR_TYPE.middle) ? ANCHOR_TYPE.middle : ANCHOR_TYPE.main;
|
||||||
|
};
|
||||||
|
Anchor.prototype = {
|
||||||
|
uuid: null,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
type: ANCHOR_TYPE.main,
|
||||||
|
isFirst: false,
|
||||||
|
isLast: false,
|
||||||
|
ndex: 0,
|
||||||
|
typeIndex: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
function Polyline(uuid, points, strokeWidth) {
|
||||||
|
/* Array on coordinates:
|
||||||
|
* points: [{x: 410, y: 110}, 1
|
||||||
|
* {x: 570, y: 110}, 1 2
|
||||||
|
* {x: 620, y: 240}, 2 3
|
||||||
|
* {x: 750, y: 270}, 3 4
|
||||||
|
* {x: 650, y: 370}]; 4
|
||||||
|
*/
|
||||||
|
this.points = points;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* path for graph
|
||||||
|
* [["M", x1, y1], ["L", x2, y2], ["C", ax, ay, bx, by, x3, y3], ["L", x3, y3]]
|
||||||
|
*/
|
||||||
|
this.path = [];
|
||||||
|
|
||||||
|
this.anchors = [];
|
||||||
|
|
||||||
|
if (strokeWidth) this.strokeWidth = strokeWidth;
|
||||||
|
|
||||||
|
this.closePath = false;
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
};
|
||||||
|
|
||||||
|
Polyline.prototype = {
|
||||||
|
id: null,
|
||||||
|
points: [],
|
||||||
|
path: [],
|
||||||
|
anchors: [],
|
||||||
|
strokeWidth: 1,
|
||||||
|
radius: 15,
|
||||||
|
showDetails: false,
|
||||||
|
element: null,
|
||||||
|
isDefaultConditionAvailable: false,
|
||||||
|
closePath: false,
|
||||||
|
|
||||||
|
init: function(points){
|
||||||
|
var linesCount = this.getLinesCount();
|
||||||
|
if (linesCount < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.normalizeCoordinates();
|
||||||
|
|
||||||
|
// create anchors
|
||||||
|
|
||||||
|
this.pushAnchor(ANCHOR_TYPE.first, this.getLine(0).x1, this.getLine(0).y1);
|
||||||
|
|
||||||
|
for(var i = 1; i < linesCount; i++){
|
||||||
|
var line1 = this.getLine(i-1),
|
||||||
|
line2 = this.getLine(i);
|
||||||
|
|
||||||
|
//this.pushAnchor(ANCHOR_TYPE.middle, line1.x1 + line1.x2-line1.x1, line1.y1 + line1.y2-line1.y1);
|
||||||
|
this.pushAnchor(ANCHOR_TYPE.main, line1.x2, line1.y2);
|
||||||
|
//this.pushAnchor(ANCHOR_TYPE.middle, line2.x1 + line2.x2-line2.x1, line2.y1 + line2.y2-line2.y1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pushAnchor(ANCHOR_TYPE.last, this.getLine(linesCount-1).x2, this.getLine(linesCount-1).y2);
|
||||||
|
|
||||||
|
this.rebuildPath();
|
||||||
|
},
|
||||||
|
|
||||||
|
normalizeCoordinates: function(){
|
||||||
|
for(var i=0; i < this.points.length; i++){
|
||||||
|
this.points[i].x = parseFloat(this.points[i].x);
|
||||||
|
this.points[i].y = parseFloat(this.points[i].y);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getLinesCount: function(){
|
||||||
|
return this.points.length-1;
|
||||||
|
},
|
||||||
|
_getLine: function(i){
|
||||||
|
return {x1: this.points[i].x, y1: this.points[i].y, x2: this.points[i+1].x, y2: this.points[i+1].y};
|
||||||
|
},
|
||||||
|
getLine: function(i){
|
||||||
|
var line = this._getLine(i);
|
||||||
|
line.angle = this.getLineAngle(i) ;
|
||||||
|
return line;
|
||||||
|
},
|
||||||
|
getLineAngle: function(i){
|
||||||
|
var line = this._getLine(i);
|
||||||
|
return Math.atan2(line.y2 - line.y1, line.x2 - line.x1);
|
||||||
|
},
|
||||||
|
getLineLengthX: function(i){
|
||||||
|
var line = this.getLine(i);
|
||||||
|
return (line.x2 - line.x1);
|
||||||
|
},
|
||||||
|
getLineLengthY: function(i){
|
||||||
|
var line = this.getLine(i);
|
||||||
|
return (line.y2 - line.y1);
|
||||||
|
},
|
||||||
|
getLineLength: function(i){
|
||||||
|
var line = this.getLine(i);
|
||||||
|
return Math.sqrt(Math.pow(this.getLineLengthX(i), 2) + Math.pow(this.getLineLengthY(i), 2));
|
||||||
|
},
|
||||||
|
|
||||||
|
getAnchors: function(){
|
||||||
|
// âåðíóòü îòñîðòèðîâàííûé ìàññèâ
|
||||||
|
// ????
|
||||||
|
return this.anchors;
|
||||||
|
},
|
||||||
|
getAnchorsCount: function(type){
|
||||||
|
if (!type)
|
||||||
|
return this.anchors.length;
|
||||||
|
else {
|
||||||
|
var count = 0;
|
||||||
|
for(var i=0; i < this.getAnchorsCount(); i++){
|
||||||
|
var anchor = this.anchors[i];
|
||||||
|
if (anchor.getType() == type) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
pushAnchor: function(type, x, y, index){
|
||||||
|
if (type == ANCHOR_TYPE.first) {
|
||||||
|
index = 0;
|
||||||
|
typeIndex = 0;
|
||||||
|
} else if (type == ANCHOR_TYPE.last) {
|
||||||
|
index = this.getAnchorsCount();
|
||||||
|
typeIndex = 0;
|
||||||
|
} else if (!index) {
|
||||||
|
index = this.anchors.length;
|
||||||
|
} else {
|
||||||
|
// ïåðåáðàòü anchors, ñäâèíóòü ïîçèöèþ äëÿ êàæäîãî, íà÷èíàÿ ñ index
|
||||||
|
//var anchor = this.getAnchor()
|
||||||
|
for(var i=0; i < this.getAnchorsCount(); i++){
|
||||||
|
var anchor = this.anchors[i];
|
||||||
|
if (anchor.index > index) {
|
||||||
|
anchor.index++;
|
||||||
|
anchor.typeIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var anchor = new Anchor(this.id, ANCHOR_TYPE.main, x, y, index, typeIndex);
|
||||||
|
|
||||||
|
this.anchors.push(anchor);
|
||||||
|
},
|
||||||
|
|
||||||
|
getAnchor: function(position){
|
||||||
|
return this.anchors[position];
|
||||||
|
},
|
||||||
|
|
||||||
|
getAnchorByType: function(type, position){
|
||||||
|
if (type == ANCHOR_TYPE.first)
|
||||||
|
return this.anchors[0];
|
||||||
|
if (type == ANCHOR_TYPE.last)
|
||||||
|
return this.anchors[this.getAnchorsCount()-1];
|
||||||
|
|
||||||
|
for(var i=0; i < this.getAnchorsCount(); i++){
|
||||||
|
var anchor = this.anchors[i];
|
||||||
|
if (anchor.type == type) {
|
||||||
|
if( position == anchor.position)
|
||||||
|
return anchor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
addNewPoint: function(position, x, y){
|
||||||
|
//
|
||||||
|
for(var i = 0; i < this.getLinesCount(); i++){
|
||||||
|
var line = this.getLine(i);
|
||||||
|
if (x > line.x1 && x < line.x2 && y > line.y1 && y < line.y2) {
|
||||||
|
this.points.splice(i+1,0,{x: x, y: y});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.rebuildPath();
|
||||||
|
},
|
||||||
|
|
||||||
|
rebuildPath: function(){
|
||||||
|
var path = [];
|
||||||
|
|
||||||
|
for(var i = 0; i < this.getAnchorsCount(); i++){
|
||||||
|
var anchor = this.getAnchor(i);
|
||||||
|
|
||||||
|
var pathType = ""
|
||||||
|
if (i==0)
|
||||||
|
pathType = "M";
|
||||||
|
else
|
||||||
|
pathType = "L";
|
||||||
|
|
||||||
|
// TODO: save previous points and calculate new path just if points are updated, and then save currents values as previous
|
||||||
|
|
||||||
|
var targetX = anchor.x, targetY = anchor.y;
|
||||||
|
if (i>0 && i < this.getAnchorsCount()-1) {
|
||||||
|
// get new x,y
|
||||||
|
var cx = anchor.x, cy = anchor.y;
|
||||||
|
|
||||||
|
// pivot point of prev line
|
||||||
|
var AO = this.getLineLength(i-1);
|
||||||
|
if (AO < this.radius) {
|
||||||
|
AO = this.radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isDefaultConditionAvailable = (this.isDefaultConditionAvailable || (i == 1 && AO > 10));
|
||||||
|
//console.log("isDefaultConditionAvailable", this.isDefaultConditionAvailable);
|
||||||
|
|
||||||
|
var ED = this.getLineLengthY(i-1) * this.radius / AO;
|
||||||
|
var OD = this.getLineLengthX(i-1) * this.radius / AO;
|
||||||
|
targetX = anchor.x - OD;
|
||||||
|
targetY = anchor.y - ED;
|
||||||
|
|
||||||
|
if (AO < 2*this.radius && i>1) {
|
||||||
|
targetX = anchor.x - this.getLineLengthX(i-1)/2;
|
||||||
|
targetY = anchor.y - this.getLineLengthY(i-1)/2;;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pivot point of next line
|
||||||
|
var AO = this.getLineLength(i);
|
||||||
|
if (AO < this.radius) {
|
||||||
|
AO = this.radius;
|
||||||
|
}
|
||||||
|
var ED = this.getLineLengthY(i) * this.radius / AO;
|
||||||
|
var OD = this.getLineLengthX(i) * this.radius / AO;
|
||||||
|
var nextSrcX = anchor.x + OD;
|
||||||
|
var nextSrcY = anchor.y + ED;
|
||||||
|
|
||||||
|
if (AO < 2*this.radius && i<this.getAnchorsCount()-2) {
|
||||||
|
nextSrcX = anchor.x + this.getLineLengthX(i)/2;
|
||||||
|
nextSrcY = anchor.y + this.getLineLengthY(i)/2;;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var dx0 = (cx - targetX) / 3,
|
||||||
|
dy0 = (cy - targetY) / 3,
|
||||||
|
ax = cx - dx0,
|
||||||
|
ay = cy - dy0,
|
||||||
|
|
||||||
|
dx1 = (cx - nextSrcX) / 3,
|
||||||
|
dy1 = (cy - nextSrcY) / 3,
|
||||||
|
bx = cx - dx1,
|
||||||
|
by = cy - dy1,
|
||||||
|
|
||||||
|
zx=nextSrcX, zy=nextSrcY;
|
||||||
|
|
||||||
|
if (this.showDetails) {
|
||||||
|
var c = ProcessDiagramCanvas.g.path("M"+targetX+","+targetY+"L"+ax+","+ay).attr({stroke: Color.get(255, 153, 51), "stroke-dasharray": "- "});
|
||||||
|
var c = ProcessDiagramCanvas.g.path("M"+nextSrcX+","+nextSrcY+"L"+bx+","+by).attr({stroke: Color.get(255, 153, 51), "stroke-dasharray": "- "});
|
||||||
|
var c = ProcessDiagramCanvas.g.ellipse(ax, ay, 2, 2).attr({stroke: Color.SlateGrey});
|
||||||
|
var c = ProcessDiagramCanvas.g.ellipse(bx, by, 2, 2).attr({stroke: Color.SlateGrey});
|
||||||
|
var c = ProcessDiagramCanvas.g.ellipse(cx, cy, this.radius, this.radius).attr({stroke: Color.Gainsboro});
|
||||||
|
var c = ProcessDiagramCanvas.g.ellipse(targetX, targetY, 2, 2).attr({fill: Color.red});
|
||||||
|
var c = ProcessDiagramCanvas.g.ellipse(nextSrcX, nextSrcY, 2, 2).attr({fill: Color.red});
|
||||||
|
}
|
||||||
|
} else if (i==1 && this.getAnchorsCount() == 2){
|
||||||
|
var AO = this.getLineLength(i-1);
|
||||||
|
if (AO < this.radius) {
|
||||||
|
AO = this.radius;
|
||||||
|
}
|
||||||
|
this.isDefaultConditionAvailable = (this.isDefaultConditionAvailable || (i == 1 && AO > 10));
|
||||||
|
//console.log("-- isDefaultConditionAvailable", this.isDefaultConditionAvailable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// anti smoothing
|
||||||
|
if (this.strokeWidth%2 == 1) {
|
||||||
|
targetX += 0.5;
|
||||||
|
targetY += 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.push([pathType, targetX, targetY]);
|
||||||
|
|
||||||
|
if (i>0 && i < this.getAnchorsCount()-1) {
|
||||||
|
path.push(["C", ax, ay, bx, by, zx, zy]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.closePath) {
|
||||||
|
console.log("closePath:", this.closePath);
|
||||||
|
path.push(["Z"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.path = path;
|
||||||
|
},
|
||||||
|
|
||||||
|
transform: function(transformation){
|
||||||
|
this.element.transform(transformation);
|
||||||
|
},
|
||||||
|
attr: function(attrs){
|
||||||
|
//console.log("attrs: " +attrs, "", this.element);
|
||||||
|
// TODO: foreach and set each
|
||||||
|
this.element.attr(attrs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function Polygone(points, strokeWidth) {
|
||||||
|
/* Array on coordinates:
|
||||||
|
* points: [{x: 410, y: 110}, 1
|
||||||
|
* {x: 570, y: 110}, 1 2
|
||||||
|
* {x: 620, y: 240}, 2 3
|
||||||
|
* {x: 750, y: 270}, 3 4
|
||||||
|
* {x: 650, y: 370}]; 4
|
||||||
|
*/
|
||||||
|
this.points = points;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* path for graph
|
||||||
|
* [["M", x1, y1], ["L", x2, y2], ["C", ax, ay, bx, by, x3, y3], ["L", x3, y3]]
|
||||||
|
*/
|
||||||
|
this.path = [];
|
||||||
|
|
||||||
|
this.anchors = [];
|
||||||
|
|
||||||
|
if (strokeWidth) this.strokeWidth = strokeWidth;
|
||||||
|
|
||||||
|
this.closePath = true;
|
||||||
|
this.init();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Poligone is inherited from Poliline: draws closedPath of polyline
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Foo = function () { };
|
||||||
|
Foo.prototype = Polyline.prototype;
|
||||||
|
|
||||||
|
Polygone.prototype = new Foo();
|
||||||
|
|
||||||
|
Polygone.prototype.rebuildPath = function(){
|
||||||
|
var path = [];
|
||||||
|
//console.log("Polygone rebuildPath");
|
||||||
|
for(var i = 0; i < this.getAnchorsCount(); i++){
|
||||||
|
var anchor = this.getAnchor(i);
|
||||||
|
|
||||||
|
var pathType = ""
|
||||||
|
if (i==0)
|
||||||
|
pathType = "M";
|
||||||
|
else
|
||||||
|
pathType = "L";
|
||||||
|
|
||||||
|
var targetX = anchor.x, targetY = anchor.y;
|
||||||
|
|
||||||
|
// anti smoothing
|
||||||
|
if (this.strokeWidth%2 == 1) {
|
||||||
|
targetX += 0.5;
|
||||||
|
targetY += 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
path.push([pathType, targetX, targetY]);
|
||||||
|
}
|
||||||
|
if (this.closePath)
|
||||||
|
path.push(["Z"]);
|
||||||
|
|
||||||
|
this.path = path;
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
Polygone.prototype.transform = function(transformation){
|
||||||
|
this.element.transform(transformation);
|
||||||
|
};
|
||||||
|
*/
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the jquery plugin "asyncQueue".
|
||||||
|
*FHqq-3-1-3-5-9-6-7-9-0
|
||||||
|
* (c) Sebastien Roch <roch.sebastien@gmail.com>
|
||||||
|
* @author (parallel) Dmitry Farafonov
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
(function($){
|
||||||
|
$.AsyncQueue = function() {
|
||||||
|
var that = this,
|
||||||
|
queue = [],
|
||||||
|
completeFunc,
|
||||||
|
failureFunc,
|
||||||
|
paused = false,
|
||||||
|
lastCallbackData,
|
||||||
|
_run,
|
||||||
|
_complete,
|
||||||
|
inQueue = 0,
|
||||||
|
defaultTimeOut = 10;
|
||||||
|
|
||||||
|
_run = function() {
|
||||||
|
var f = queue.shift();
|
||||||
|
|
||||||
|
if (f) {
|
||||||
|
inQueue++;
|
||||||
|
setTimeout(function(){
|
||||||
|
f.fn.apply(that, [that]);
|
||||||
|
|
||||||
|
if (!f.isParallel)
|
||||||
|
if (paused === false) {
|
||||||
|
_run();
|
||||||
|
}
|
||||||
|
inQueue --;
|
||||||
|
if (inQueue == 0 && queue.length == 0)
|
||||||
|
_complete();
|
||||||
|
}, f.timeOut);
|
||||||
|
|
||||||
|
if (f.isParallel)
|
||||||
|
if (paused === false) {
|
||||||
|
_run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_complete = function(){
|
||||||
|
if (completeFunc)
|
||||||
|
completeFunc.apply(that, [that]);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onComplete = function(func) {
|
||||||
|
completeFunc = func;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onFailure = function(func) {
|
||||||
|
failureFunc = func;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.add = function(func) {
|
||||||
|
// TODO: add callback for queue[i] complete
|
||||||
|
|
||||||
|
var obj = arguments[0];
|
||||||
|
if (obj && Object.prototype.toString.call(obj) === "[object Array]") {
|
||||||
|
var fn = arguments[1];
|
||||||
|
var timeOut = (typeof(arguments[2]) != "undefined")? arguments[2] : defaultTimeOut;
|
||||||
|
if (typeof(fn) == "function") {
|
||||||
|
for(var i = 0; i < obj.length; i++) {
|
||||||
|
var f = function(objx){
|
||||||
|
queue.push({isParallel: true, fn: function(){fn.apply(that, [that, objx]);}, timeOut: timeOut});
|
||||||
|
}(obj[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var fn = arguments[0];
|
||||||
|
var timeOut = (typeof(arguments[1]) != "undefined")? arguments[2] : defaultTimeOut;
|
||||||
|
queue.push({isParallel: false, fn: func, timeOut: timeOut});
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.addParallel = function(func, timeOut) {
|
||||||
|
// TODO: add callback for queue[i] complete
|
||||||
|
|
||||||
|
queue.push({isParallel: true, fn: func, timeOut: timeOut});
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.storeData = function(dataObject) {
|
||||||
|
lastCallbackData = dataObject;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.lastCallbackData = function () {
|
||||||
|
return lastCallbackData;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.run = function() {
|
||||||
|
paused = false;
|
||||||
|
_run();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.pause = function () {
|
||||||
|
paused = true;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.failure = function() {
|
||||||
|
paused = true;
|
||||||
|
if (failureFunc) {
|
||||||
|
var args = [that];
|
||||||
|
for(i = 0; i < arguments.length; i++) {
|
||||||
|
args.push(arguments[i]);
|
||||||
|
}
|
||||||
|
failureFunc.apply(that, args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.size = function(){
|
||||||
|
return queue.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
})(jQuery);
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* @ Dmitry Farafonov
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function($){
|
||||||
|
$.ProgressBar = function(options) {
|
||||||
|
this.element = $(options.boundingBox);
|
||||||
|
if (options.on && options.on.complete){
|
||||||
|
this.onComplete = options.on.complete;
|
||||||
|
}
|
||||||
|
if (options.on && options.on.valueChange){
|
||||||
|
this.onValueChange = options.on.valueChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._create();
|
||||||
|
|
||||||
|
if (options.label)
|
||||||
|
this.set("label", options.label);
|
||||||
|
if (options.value)
|
||||||
|
this.value(options.value);
|
||||||
|
if (options.max)
|
||||||
|
this.set("max", options.max);
|
||||||
|
};
|
||||||
|
$.ProgressBar.prototype = {
|
||||||
|
options: {
|
||||||
|
value: 0,
|
||||||
|
max: 100
|
||||||
|
},
|
||||||
|
|
||||||
|
min: 0,
|
||||||
|
|
||||||
|
_create: function() {
|
||||||
|
this.element
|
||||||
|
.addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
|
||||||
|
.attr({
|
||||||
|
role: "progressbar",
|
||||||
|
"aria-valuemin": this.min,
|
||||||
|
"aria-valuemax": this.options.max,
|
||||||
|
"aria-valuenow": this._value()
|
||||||
|
});
|
||||||
|
|
||||||
|
this.valueDiv = $( "<div class='ui-progressbar-label'></div>" )
|
||||||
|
.appendTo( this.element );
|
||||||
|
|
||||||
|
this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
|
||||||
|
.appendTo( this.element );
|
||||||
|
|
||||||
|
this.oldValue = this._value();
|
||||||
|
this._refreshValue();
|
||||||
|
},
|
||||||
|
|
||||||
|
_destroy: function() {
|
||||||
|
this.element
|
||||||
|
.removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
|
||||||
|
.removeAttr( "role" )
|
||||||
|
.removeAttr( "aria-valuemin" )
|
||||||
|
.removeAttr( "aria-valuemax" )
|
||||||
|
.removeAttr( "aria-valuenow" );
|
||||||
|
|
||||||
|
this.valueDiv.remove();
|
||||||
|
},
|
||||||
|
|
||||||
|
value: function( newValue ) {
|
||||||
|
if ( newValue === undefined ) {
|
||||||
|
return this._value();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._setOption( "value", newValue );
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
_setOption: function( key, value ) {
|
||||||
|
if ( key === "value" ) {
|
||||||
|
//var oldVal = this.options.value;
|
||||||
|
this.options.value = value;
|
||||||
|
this._refreshValue();
|
||||||
|
|
||||||
|
if (this.onValueChange)
|
||||||
|
this.onValueChange.apply(this, [{oldVal: this.oldValue, newVal: value}]);
|
||||||
|
|
||||||
|
if ( this._value() === this.options.max ) {
|
||||||
|
//this._trigger( "complete" );
|
||||||
|
if (this.onComplete)
|
||||||
|
this.onComplete.apply(this);
|
||||||
|
}
|
||||||
|
} else if (key === "label") {
|
||||||
|
$(this.element).find(".ui-progressbar-label").html(value);
|
||||||
|
} else if (key === "max") {
|
||||||
|
this.options.max = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//this._super( key, value );
|
||||||
|
},
|
||||||
|
|
||||||
|
_value: function() {
|
||||||
|
var val = this.options.value;
|
||||||
|
// normalize invalid value
|
||||||
|
if ( typeof val !== "number" ) {
|
||||||
|
val = 0;
|
||||||
|
}
|
||||||
|
return Math.min( this.options.max, Math.max( this.min, val ) );
|
||||||
|
},
|
||||||
|
|
||||||
|
_percentage: function() {
|
||||||
|
return 100 * this._value() / this.options.max;
|
||||||
|
},
|
||||||
|
|
||||||
|
_refreshValue: function() {
|
||||||
|
var value = this.value(),
|
||||||
|
percentage = this._percentage();
|
||||||
|
|
||||||
|
if ( this.oldValue !== value ) {
|
||||||
|
this.oldValue = value;
|
||||||
|
//this._trigger( "change" );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.valueDiv
|
||||||
|
.toggle( value > this.min )
|
||||||
|
.toggleClass( "ui-corner-right", value === this.options.max )
|
||||||
|
.width( percentage.toFixed(0) + "%" );
|
||||||
|
this.element.attr( "aria-valuenow", value );
|
||||||
|
|
||||||
|
//$(this.element).find(".ui-progressbar-label").html(value + "%");
|
||||||
|
},
|
||||||
|
|
||||||
|
set: function(key, value){
|
||||||
|
this._setOption(key, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})( jQuery );
|
|
@ -0,0 +1,23 @@
|
||||||
|
if (typeof(console) == "undefined") {
|
||||||
|
var console = {
|
||||||
|
info: function(){},
|
||||||
|
warn: function(){},
|
||||||
|
error: function(){},
|
||||||
|
log: function(){},
|
||||||
|
time: function(){},
|
||||||
|
timeEnd: function(){}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Array.isArray) {
|
||||||
|
Array.isArray = function (vArg) {
|
||||||
|
return Object.prototype.toString.call(vArg) === "[object Array]";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Object.isSVGElement) {
|
||||||
|
Object.isSVGElement = function(vArg) {
|
||||||
|
var str = Object.prototype.toString.call(vArg);
|
||||||
|
return (str.indexOf("[object SVG") == 0);
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,441 @@
|
||||||
|
window.onload = function () {
|
||||||
|
var paper = Raphael("holder");
|
||||||
|
|
||||||
|
//var curve = paper.ellipse(100, 100, 1, 1).attr({"stroke-width": 0, fill: Color.red});//FHqq-3-1-3-5-9-6-7-9-0
|
||||||
|
|
||||||
|
var text = "Betty Botter bought some butter but, she said, the butter's bitter. If I put it in my batter, it will make my batter bitter. But a bit of better butter will make my batter better. So, she bought a bit of butter, better than her bitter butter, and she put it in her batter, and the batter was not bitter. It was better Betty Botter bought a bit better butter.";
|
||||||
|
var font = {font: "11px Arial", "font-style":"italic", opacity: 1, "fill": LABEL_COLOR, stroke: LABEL_COLOR, "stroke-width":.3};
|
||||||
|
var font = {font: "11px Arial", opacity: 1, "fill": LABEL_COLOR};
|
||||||
|
var boxWidth = 100
|
||||||
|
|
||||||
|
var AttributedStringIterator = function(text){
|
||||||
|
//this.text = this.rtrim(this.ltrim(text));
|
||||||
|
text = text.replace(/(\s)+/, " ");
|
||||||
|
this.text = this.rtrim(text);
|
||||||
|
/*
|
||||||
|
if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
|
||||||
|
throw new IllegalArgumentException("Invalid substring range");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
this.beginIndex = 0;
|
||||||
|
this.endIndex = this.text.length;
|
||||||
|
this.currentIndex = this.beginIndex;
|
||||||
|
|
||||||
|
//console.group("[AttributedStringIterator]");
|
||||||
|
var i = 0;
|
||||||
|
var string = this.text;
|
||||||
|
var fullPos = 0;
|
||||||
|
|
||||||
|
//console.log("string: \"" + string + "\", length: " + string.length);
|
||||||
|
this.startWordOffsets = [];
|
||||||
|
this.startWordOffsets.push(fullPos);
|
||||||
|
|
||||||
|
// TODO: remove i 1000
|
||||||
|
while (i<1000) {
|
||||||
|
var pos = string.search(/[ \t\n\f-\.\,]/);
|
||||||
|
if (pos == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// whitespace start
|
||||||
|
fullPos += pos;
|
||||||
|
string = string.substr(pos);
|
||||||
|
////console.log("fullPos: " + fullPos + ", pos: " + pos + ", string: ", string);
|
||||||
|
|
||||||
|
// remove whitespaces
|
||||||
|
var pos = string.search(/[^ \t\n\f-\.\,]/);
|
||||||
|
if (pos == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// whitespace end
|
||||||
|
fullPos += pos;
|
||||||
|
string = string.substr(pos);
|
||||||
|
|
||||||
|
////console.log("fullPos: " + fullPos);
|
||||||
|
this.startWordOffsets.push(fullPos);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
//console.log("startWordOffsets: ", this.startWordOffsets);
|
||||||
|
//console.groupEnd();
|
||||||
|
};
|
||||||
|
AttributedStringIterator.prototype = {
|
||||||
|
getEndIndex: function(pos){
|
||||||
|
if (typeof(pos) == "undefined")
|
||||||
|
return this.endIndex;
|
||||||
|
|
||||||
|
var string = this.text.substr(pos, this.endIndex - pos);
|
||||||
|
|
||||||
|
var posEndOfLine = string.search(/[\n]/);
|
||||||
|
if (posEndOfLine == -1)
|
||||||
|
return this.endIndex;
|
||||||
|
else
|
||||||
|
return pos + posEndOfLine;
|
||||||
|
},
|
||||||
|
getBeginIndex: function(){
|
||||||
|
return this.beginIndex;
|
||||||
|
},
|
||||||
|
isWhitespace: function(pos){
|
||||||
|
var str = this.text[pos];
|
||||||
|
var whitespaceChars = " \t\n\f";
|
||||||
|
|
||||||
|
return (whitespaceChars.indexOf(str) != -1);
|
||||||
|
},
|
||||||
|
isNewLine: function(pos){
|
||||||
|
var str = this.text[pos];
|
||||||
|
var whitespaceChars = "\n";
|
||||||
|
|
||||||
|
return (whitespaceChars.indexOf(str) != -1);
|
||||||
|
},
|
||||||
|
preceding: function(pos){
|
||||||
|
//console.group("[AttributedStringIterator.preceding]");
|
||||||
|
for(var i in this.startWordOffsets) {
|
||||||
|
var startWordOffset = this.startWordOffsets[i];
|
||||||
|
if (pos < startWordOffset && i>0) {
|
||||||
|
//console.log("startWordOffset: " + this.startWordOffsets[i-1]);
|
||||||
|
//console.groupEnd();
|
||||||
|
return this.startWordOffsets[i-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.log("pos: " + pos);
|
||||||
|
//console.groupEnd();
|
||||||
|
return this.startWordOffsets[i];
|
||||||
|
},
|
||||||
|
following: function(pos){
|
||||||
|
//console.group("[AttributedStringIterator.following]");
|
||||||
|
for(var i in this.startWordOffsets) {
|
||||||
|
var startWordOffset = this.startWordOffsets[i];
|
||||||
|
if (pos < startWordOffset && i>0) {
|
||||||
|
//console.log("startWordOffset: " + this.startWordOffsets[i]);
|
||||||
|
//console.groupEnd();
|
||||||
|
return this.startWordOffsets[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.log("pos: " + pos);
|
||||||
|
//console.groupEnd();
|
||||||
|
return this.startWordOffsets[i];
|
||||||
|
},
|
||||||
|
ltrim: function(str){
|
||||||
|
var patt2=/^\s+/g;
|
||||||
|
return str.replace(patt2, "");
|
||||||
|
},
|
||||||
|
rtrim: function(str){
|
||||||
|
var patt2=/\s+$/g;
|
||||||
|
return str.replace(patt2, "");
|
||||||
|
},
|
||||||
|
getLayout: function(start, limit){
|
||||||
|
return this.text.substr(start, limit - start);
|
||||||
|
},
|
||||||
|
getCharAtPos: function(pos) {
|
||||||
|
return this.text[pos];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
var TextMeasurer = function(paper, text, fontAttrs){
|
||||||
|
this.text = text;
|
||||||
|
this.paper = paper;
|
||||||
|
this.fontAttrs = fontAttrs;
|
||||||
|
|
||||||
|
this.fStart = this.text.getBeginIndex();
|
||||||
|
|
||||||
|
};
|
||||||
|
TextMeasurer.prototype = {
|
||||||
|
getLineBreakIndex: function(start, maxAdvance){
|
||||||
|
var localStart = start - this.fStart;
|
||||||
|
},
|
||||||
|
getLayout: function(){
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
var LineBreakMeasurer = function(paper, text, fontAttrs){
|
||||||
|
this.paper = paper;
|
||||||
|
this.text = new AttributedStringIterator(text);
|
||||||
|
this.fontAttrs = fontAttrs;
|
||||||
|
|
||||||
|
if (this.text.getEndIndex() - this.text.getBeginIndex() < 1) {
|
||||||
|
throw {message: "Text must contain at least one character.", code: "IllegalArgumentException"};
|
||||||
|
}
|
||||||
|
|
||||||
|
//this.measurer = new TextMeasurer(paper, this.text, this.fontAttrs);
|
||||||
|
this.limit = this.text.getEndIndex();
|
||||||
|
this.pos = this.start = this.text.getBeginIndex();
|
||||||
|
|
||||||
|
this.rafaelTextObject = this.paper.text(100, 100, this.text.text).attr(fontAttrs).attr("text-anchor", "start");
|
||||||
|
this.svgTextObject = this.rafaelTextObject[0];
|
||||||
|
};
|
||||||
|
LineBreakMeasurer.prototype = {
|
||||||
|
nextOffset: function(wrappingWidth, offsetLimit, requireNextWord) {
|
||||||
|
//console.group("[nextOffset]");
|
||||||
|
var nextOffset = this.pos;
|
||||||
|
if (this.pos < this.limit) {
|
||||||
|
if (offsetLimit <= this.pos) {
|
||||||
|
throw {message: "offsetLimit must be after current position", code: "IllegalArgumentException"};
|
||||||
|
}
|
||||||
|
|
||||||
|
var charAtMaxAdvance = this.getLineBreakIndex(this.pos, wrappingWidth);
|
||||||
|
//charAtMaxAdvance --;
|
||||||
|
//console.log("charAtMaxAdvance:", charAtMaxAdvance, ", [" + this.text.getCharAtPos(charAtMaxAdvance) + "]");
|
||||||
|
|
||||||
|
if (charAtMaxAdvance == this.limit) {
|
||||||
|
nextOffset = this.limit;
|
||||||
|
//console.log("charAtMaxAdvance == this.limit");
|
||||||
|
} else if (this.text.isNewLine(charAtMaxAdvance)) {
|
||||||
|
console.log("isNewLine");
|
||||||
|
nextOffset = charAtMaxAdvance+1;
|
||||||
|
} else if (this.text.isWhitespace(charAtMaxAdvance)) {
|
||||||
|
// TODO: find next noSpaceChar
|
||||||
|
//return nextOffset;
|
||||||
|
nextOffset = this.text.following(charAtMaxAdvance);
|
||||||
|
} else {
|
||||||
|
// Break is in a word; back up to previous break.
|
||||||
|
/*
|
||||||
|
var testPos = charAtMaxAdvance + 1;
|
||||||
|
if (testPos == this.limit) {
|
||||||
|
console.error("hbz...");
|
||||||
|
} else {
|
||||||
|
nextOffset = this.text.preceding(charAtMaxAdvance);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
nextOffset = this.text.preceding(charAtMaxAdvance);
|
||||||
|
|
||||||
|
if (nextOffset <= this.pos) {
|
||||||
|
nextOffset = Math.max(this.pos+1, charAtMaxAdvance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nextOffset > offsetLimit) {
|
||||||
|
nextOffset = offsetLimit;
|
||||||
|
}
|
||||||
|
//console.log("nextOffset: " + nextOffset);
|
||||||
|
//console.groupEnd();
|
||||||
|
return nextOffset;
|
||||||
|
},
|
||||||
|
nextLayout: function(wrappingWidth) {
|
||||||
|
//console.groupCollapsed("[nextLayout]");
|
||||||
|
if (this.pos < this.limit) {
|
||||||
|
var requireNextWord = false;
|
||||||
|
var layoutLimit = this.nextOffset(wrappingWidth, this.limit, requireNextWord);
|
||||||
|
//console.log("layoutLimit:", layoutLimit);
|
||||||
|
if (layoutLimit == this.pos) {
|
||||||
|
//console.groupEnd();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var result = this.text.getLayout(this.pos, layoutLimit);
|
||||||
|
//console.log("layout: \"" + result + "\"");
|
||||||
|
|
||||||
|
// remove end of line
|
||||||
|
|
||||||
|
//var posEndOfLine = this.text.getEndIndex(this.pos);
|
||||||
|
//if (posEndOfLine < result.length)
|
||||||
|
// result = result.substr(0, posEndOfLine);
|
||||||
|
|
||||||
|
this.pos = layoutLimit;
|
||||||
|
|
||||||
|
//console.groupEnd();
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
//console.groupEnd();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getLineBreakIndex: function(pos, wrappingWidth) {
|
||||||
|
//console.group("[getLineBreakIndex]");
|
||||||
|
//console.log("pos:"+pos + ", text: \""+ this.text.text.replace(/\n/g, "_").substr(pos, 1) + "\"");
|
||||||
|
|
||||||
|
var bb = this.rafaelTextObject.getBBox();
|
||||||
|
|
||||||
|
var charNum = -1;
|
||||||
|
try {
|
||||||
|
var svgPoint = this.svgTextObject.getStartPositionOfChar(pos);
|
||||||
|
//var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.blue});
|
||||||
|
svgPoint.x = svgPoint.x + wrappingWidth;
|
||||||
|
//svgPoint.y = bb.y;
|
||||||
|
//console.log("svgPoint:", svgPoint);
|
||||||
|
|
||||||
|
//var dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.red});
|
||||||
|
|
||||||
|
charNum = this.svgTextObject.getCharNumAtPosition(svgPoint);
|
||||||
|
} catch (e){
|
||||||
|
console.warn("getStartPositionOfChar error, pos:" + pos);
|
||||||
|
/*
|
||||||
|
var testPos = pos + 1;
|
||||||
|
if (testPos < this.limit) {
|
||||||
|
return testPos
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
//console.log("charNum:", charNum);
|
||||||
|
if (charNum == -1) {
|
||||||
|
//console.groupEnd();
|
||||||
|
return this.text.getEndIndex(pos);
|
||||||
|
} else {
|
||||||
|
// When case there is new line between pos and charnum then use this new line
|
||||||
|
var newLineIndex = this.text.getEndIndex(pos);
|
||||||
|
if (newLineIndex < charNum ) {
|
||||||
|
console.log("newLineIndex <= charNum, newLineIndex:"+newLineIndex+", charNum:"+charNum, "\"" + this.text.text.substr(newLineIndex+1).replace(/\n/g, "↵") + "\"");
|
||||||
|
//console.groupEnd();
|
||||||
|
|
||||||
|
return newLineIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
//var charAtMaxAdvance = this.text.text.substring(charNum, charNum + 1);
|
||||||
|
var charAtMaxAdvance = this.text.getCharAtPos(charNum);
|
||||||
|
//console.log("!!charAtMaxAdvance: " + charAtMaxAdvance);
|
||||||
|
//console.groupEnd();
|
||||||
|
return charNum;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getPosition: function() {
|
||||||
|
return this.pos;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ******
|
||||||
|
function drawMultilineText(text, x, y, boxWidth, boxHeight, options) {
|
||||||
|
var TEXT_PADDING = 3;
|
||||||
|
var width = boxWidth - (2 * TEXT_PADDING);
|
||||||
|
if (boxHeight)
|
||||||
|
var height = boxHeight - (2 * TEXT_PADDING);
|
||||||
|
|
||||||
|
var layouts = [];
|
||||||
|
|
||||||
|
var measurer = new LineBreakMeasurer(paper, text, font);
|
||||||
|
var lineHeight = measurer.rafaelTextObject.getBBox().height;
|
||||||
|
console.log("text: ", text.replace(/\n/g, "↵"));
|
||||||
|
|
||||||
|
if (height) {
|
||||||
|
var availableLinesCount = parseInt(height/lineHeight);
|
||||||
|
console.log("availableLinesCount: " + availableLinesCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = 1;
|
||||||
|
while (measurer.getPosition() < measurer.text.getEndIndex()) {
|
||||||
|
var layout = measurer.nextLayout(width);
|
||||||
|
//console.log("LAYOUT: " + layout + ", getPosition: " + measurer.getPosition());
|
||||||
|
|
||||||
|
if (layout != null) {
|
||||||
|
if (!availableLinesCount || i < availableLinesCount) {
|
||||||
|
layouts.push(layout);
|
||||||
|
} else {
|
||||||
|
layouts.push(fitTextToWidth(layout + "...", boxWidth));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
};
|
||||||
|
console.log(layouts);
|
||||||
|
|
||||||
|
measurer.rafaelTextObject.attr({"text": layouts.join("\n")});
|
||||||
|
//measurer.rafaelTextObject.attr({"text-anchor": "end"});
|
||||||
|
//measurer.rafaelTextObject.attr({"text-anchor": "middle"});
|
||||||
|
if (options)
|
||||||
|
measurer.rafaelTextObject.attr({"text-anchor": options["text-anchor"]});
|
||||||
|
|
||||||
|
var bb = measurer.rafaelTextObject.getBBox();
|
||||||
|
//measurer.rafaelTextObject.attr({"x": x + boxWidth/2});
|
||||||
|
if (options["vertical-align"] == "top")
|
||||||
|
measurer.rafaelTextObject.attr({"y": y + bb.height/2 + TEXT_PADDING});
|
||||||
|
else
|
||||||
|
measurer.rafaelTextObject.attr({"y": y + height/2});
|
||||||
|
//var bb = measurer.rafaelTextObject.getBBox();
|
||||||
|
|
||||||
|
if (measurer.rafaelTextObject.attr("text-anchor") == "middle" )
|
||||||
|
measurer.rafaelTextObject.attr("x", x + boxWidth/2 + TEXT_PADDING/2);
|
||||||
|
else if (measurer.rafaelTextObject.attr("text-anchor") == "end" )
|
||||||
|
measurer.rafaelTextObject.attr("x", x + boxWidth + TEXT_PADDING/2);
|
||||||
|
else
|
||||||
|
measurer.rafaelTextObject.attr("x", x + boxWidth/2 - bb.width/2 + TEXT_PADDING/2);
|
||||||
|
|
||||||
|
var boxStyle = {stroke: Color.LightSteelBlue2, "stroke-width": 1.0, "stroke-dasharray": "- "};
|
||||||
|
/*
|
||||||
|
var box = paper.rect(x+.0 + boxWidth/2 - bb.width/2+ TEXT_PADDING/2, y + .5 + boxHeight/2 - bb.height/2, width, height).attr(boxStyle);
|
||||||
|
box.attr("height", bb.height);
|
||||||
|
*/
|
||||||
|
//var box = paper.rect(bb.x - .5 + bb.width/2 + TEXT_PADDING, bb.y + bb.height/2, bb.width, bb.height).attr(boxStyle);
|
||||||
|
|
||||||
|
var textAreaCX = x + boxWidth/2;
|
||||||
|
var textAreaCY = y + height/2;
|
||||||
|
var dotLeftTop = paper.ellipse(x, y, 3, 3).attr({"stroke-width": 0, fill: Color.LightSteelBlue, stroke: "none"});
|
||||||
|
var dotCenter = paper.ellipse(textAreaCX, textAreaCY, 3, 3).attr({fill: Color.LightSteelBlue2, stroke: "none"});
|
||||||
|
|
||||||
|
/*
|
||||||
|
// real bbox
|
||||||
|
var bb = measurer.rafaelTextObject.getBBox();
|
||||||
|
var rect = paper.rect(bb.x+.5, bb.y + .5, bb.width, bb.height).attr({"stroke-width": 1});
|
||||||
|
*/
|
||||||
|
var boxStyle = {stroke: Color.LightSteelBlue2, "stroke-width": 1.0, "stroke-dasharray": "- "};
|
||||||
|
var rect = paper.rect(x+.5, y + .5, boxWidth, boxHeight).attr(boxStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (var i=0; i<1; i++) {
|
||||||
|
var t = text;
|
||||||
|
//var t = "Высококвалифицирова";
|
||||||
|
|
||||||
|
var text = paper.text(300, 100, t).attr(font).attr("text-anchor", "start");
|
||||||
|
var bbText = text.getBBox();
|
||||||
|
paper.rect(300+.5, 100 + .5, bbText.width, bbText.height).attr({"stroke-width": 1});
|
||||||
|
console.log("t: ", t.replace(/\n/g, "↵"));
|
||||||
|
|
||||||
|
while (measurer.getPosition() < measurer.text.getEndIndex()) {
|
||||||
|
var layout = measurer.nextLayout(width);
|
||||||
|
//console.log("LAYOUT: " + layout + ", getPosition: " + measurer.getPosition());
|
||||||
|
if (layout != null)
|
||||||
|
layouts.push(layout);
|
||||||
|
};
|
||||||
|
|
||||||
|
measurer.rafaelTextObject.attr("text", layouts.join("\n"));
|
||||||
|
var bb = measurer.rafaelTextObject.getBBox();
|
||||||
|
var rect = paper.rect(bb.x+.5, bb.y + .5, bb.width, bb.height).attr({"stroke-width": 1});
|
||||||
|
|
||||||
|
lay.push(layouts);
|
||||||
|
console.log(layouts);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
var fitTextToWidth = function(original, width) {
|
||||||
|
var text = original;
|
||||||
|
|
||||||
|
// TODO: move attr on parameters
|
||||||
|
var attr = {font: "11px Arial", opacity: 0};
|
||||||
|
|
||||||
|
// remove length for "..."
|
||||||
|
var dots = paper.text(0, 0, "...").attr(attr).hide();
|
||||||
|
var dotsBB = dots.getBBox();
|
||||||
|
|
||||||
|
var maxWidth = width - dotsBB.width;
|
||||||
|
|
||||||
|
var textElement = paper.text(0, 0, text).attr(attr).hide();
|
||||||
|
var bb = textElement.getBBox();
|
||||||
|
|
||||||
|
// it's a little bit incorrect with "..."
|
||||||
|
while (bb.width > maxWidth && text.length > 0) {
|
||||||
|
text = text.substring(0, text.length - 1);
|
||||||
|
textElement.attr({"text": text});
|
||||||
|
bb = textElement.getBBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove element from paper
|
||||||
|
textElement.remove();
|
||||||
|
|
||||||
|
if (text != original) {
|
||||||
|
text = text + "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var x=100, y=90, height=20;
|
||||||
|
var options = {"text-anchor": "middle", "boxHeight": 150, "vertical-align": "top"};
|
||||||
|
var options = {"boxHeight": 150, "vertical-align": "top"};
|
||||||
|
drawMultilineText(text, x, y, 150, 100, options);
|
||||||
|
};
|
|
@ -0,0 +1 @@
|
||||||
|
body {
background: #fafafa;
color: #708090;
/* font: 300 100.1% "Helvetica Neue", Helvetica, "Arial Unicode MS", Arial, sans-serif; */
font-family: Verdana, sans-serif, Arial;
font-size: 10px;
}
.wrapper{
height: 100%;
position: relative;
width: 100%;
}
/*
#holder {
height: 480px;
width: 640px;
b_ackground: #F8F8FF;
//FHqq-3-1-3-5-9-6-7-9-0
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
-webkit-box-shadow: 0 1px 3px #666;
background: #DDD url(./images/bg.png);
/* background: #DDD url(./images/checker-bg.png); * /
b_order:0px solid #dedede;
}
*/
div.diagramHolder {
float:left;
}
div.diagram{
border:1px solid #dedede;
margin: 5px;
padding: 5px;
background: #FFF;
}
div.diagram.hidden{
display:none;
}
svg {
background: #DDD url(./images/bg.png);
}
div.diagram-info {
float:left;
position: relative;
padding: 5px;
}
/* Breadcrumbs */
#diagramBreadCrumbs {
margin-left: 2px;
margin-right: 2px;
margin-top: 10px;
}
#diagramBreadCrumbs ul {
list-style: none;
background-color: white;
border: 1px solid #DEDEDE;
border-color: #C0C2C5;
margin: 0;
margin-bottom: 10px;
margin-left: 0;
-webkit-padding-start: 0px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
#diagramBreadCrumbs li {
/*text-decoration: underline;*/
display: inline-block;
vertical-align: middle;
padding-left: .75em;
padding-right: 0;
cursor: pointer;
}
#diagramBreadCrumbs li.selected {
color: #9370DB;
color: #4876FF;
color: #4F94CD;
font-weight: bold;
}
#diagramBreadCrumbs li span {
background: url(images/breadcrumbs.png) no-repeat 100% 50%;
display: block;
padding: .5em 15px .5em 0;
}
/* Progress bar */
.ui-progressbar {
height: 25px;
/*height:2em; text-align: left; overflow: hidden; */
background: white;
border: 1px solid #949DAD;
margin: 2px;
overflow: hidden;
padding: 1px;
position: relative;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
.ui-progressbar .ui-progressbar-value {
m_argin: -1px;
height:100%;
background: #D4E4FF;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
}
.ui-widget-header a { color: #222222/*{fcHeader}*/; }
.ui-progressbar .ui-progressbar-label{
position: absolute;
margin-top: 7px;
border:0px solid red;
width: 100%;
text-align: center;
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
* //FHqq-3-1-3-5-9-6-7-9-0
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var aclocat = (window.location+'').split('/');
|
||||||
|
if('activiti-editor'== aclocat[3]){aclocat = aclocat[0]+'//'+aclocat[2];}else{aclocat = aclocat[0]+'//'+aclocat[2]+'/'+aclocat[3];};
|
||||||
|
|
||||||
|
var ACTIVITI = ACTIVITI || {};
|
||||||
|
|
||||||
|
ACTIVITI.CONFIG = {
|
||||||
|
'contextRoot' : '/fourcal',
|
||||||
|
};
|
|
@ -0,0 +1,435 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
* //FHqq-313596790
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var activitiModeler = angular.module('activitiModeler', [
|
||||||
|
'ngCookies',
|
||||||
|
'ngResource',
|
||||||
|
'ngSanitize',
|
||||||
|
'ngRoute',
|
||||||
|
'ngDragDrop',
|
||||||
|
'mgcrea.ngStrap',
|
||||||
|
'ngGrid',
|
||||||
|
'ngAnimate',
|
||||||
|
'pascalprecht.translate',
|
||||||
|
'duScroll'
|
||||||
|
]);
|
||||||
|
|
||||||
|
var activitiModule = activitiModeler;
|
||||||
|
|
||||||
|
activitiModeler
|
||||||
|
// Initialize routes
|
||||||
|
.config(['$selectProvider', '$translateProvider', function ($selectProvider, $translateProvider) {
|
||||||
|
|
||||||
|
// Override caret for bs-select directive
|
||||||
|
angular.extend($selectProvider.defaults, {
|
||||||
|
caretHtml: ' <i class="icon icon-caret-down"></i>'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize angular-translate
|
||||||
|
$translateProvider.useStaticFilesLoader({
|
||||||
|
prefix: './editor-app/i18n/',
|
||||||
|
suffix: '.json'
|
||||||
|
});
|
||||||
|
|
||||||
|
$translateProvider.preferredLanguage('en');
|
||||||
|
|
||||||
|
// remember language
|
||||||
|
$translateProvider.useCookieStorage();
|
||||||
|
|
||||||
|
}])
|
||||||
|
.run(['$rootScope', '$timeout', '$modal', '$translate', '$location', '$window', '$http', '$q',
|
||||||
|
function($rootScope, $timeout, $modal, $translate, $location, $window, $http, $q) {
|
||||||
|
|
||||||
|
$rootScope.config = ACTIVITI.CONFIG;
|
||||||
|
|
||||||
|
$rootScope.editorInitialized = false;
|
||||||
|
|
||||||
|
$rootScope.editorFactory = $q.defer();
|
||||||
|
|
||||||
|
$rootScope.forceSelectionRefresh = false;
|
||||||
|
|
||||||
|
$rootScope.ignoreChanges = false; // by default never ignore changes
|
||||||
|
|
||||||
|
$rootScope.validationErrors = [];
|
||||||
|
|
||||||
|
$rootScope.staticIncludeVersion = Date.now();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A 'safer' apply that avoids concurrent updates (which $apply allows).
|
||||||
|
*/
|
||||||
|
$rootScope.safeApply = function(fn) {
|
||||||
|
var phase = this.$root.$$phase;
|
||||||
|
if(phase == '$apply' || phase == '$digest') {
|
||||||
|
if(fn && (typeof(fn) === 'function')) {
|
||||||
|
fn();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.$apply(fn);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the event bus: couple all Oryx events with a dispatch of the
|
||||||
|
* event of the event bus. This way, it gets much easier to attach custom logic
|
||||||
|
* to any event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Helper method to fetch model from server (always needed) */
|
||||||
|
function fetchModel(modelId) {
|
||||||
|
|
||||||
|
var modelUrl = KISBPM.URL.getModel(modelId);
|
||||||
|
$http({method: 'GET', url: modelUrl}).
|
||||||
|
success(function (data, status, headers, config) {
|
||||||
|
$rootScope.editor = new ORYX.Editor(data);
|
||||||
|
$rootScope.modelData = angular.fromJson(data);
|
||||||
|
$rootScope.editorFactory.resolve();
|
||||||
|
}).
|
||||||
|
error(function (data, status, headers, config) {
|
||||||
|
console.log('Error loading model with id ' + modelId + ' ' + data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function initScrollHandling() {
|
||||||
|
var canvasSection = jQuery('#canvasSection');
|
||||||
|
canvasSection.scroll(function() {
|
||||||
|
|
||||||
|
// Hides the resizer and quick menu items during scrolling
|
||||||
|
|
||||||
|
var selectedElements = $rootScope.editor.selection;
|
||||||
|
var subSelectionElements = $rootScope.editor._subSelection;
|
||||||
|
|
||||||
|
$rootScope.selectedElements = selectedElements;
|
||||||
|
$rootScope.subSelectionElements = subSelectionElements;
|
||||||
|
if (selectedElements && selectedElements.length > 0) {
|
||||||
|
$rootScope.selectedElementBeforeScrolling = selectedElements[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery('.Oryx_button').each(function(i, obj) {
|
||||||
|
$rootScope.orginalOryxButtonStyle = obj.style.display;
|
||||||
|
obj.style.display = 'none';
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery('.resizer_southeast').each(function(i, obj) {
|
||||||
|
$rootScope.orginalResizerSEStyle = obj.style.display;
|
||||||
|
obj.style.display = 'none';
|
||||||
|
});
|
||||||
|
jQuery('.resizer_northwest').each(function(i, obj) {
|
||||||
|
$rootScope.orginalResizerNWStyle = obj.style.display;
|
||||||
|
obj.style.display = 'none';
|
||||||
|
});
|
||||||
|
$rootScope.editor.handleEvents({type:ORYX.CONFIG.EVENT_CANVAS_SCROLL});
|
||||||
|
});
|
||||||
|
|
||||||
|
canvasSection.scrollStopped(function(){
|
||||||
|
|
||||||
|
// Puts the quick menu items and resizer back when scroll is stopped.
|
||||||
|
|
||||||
|
$rootScope.editor.setSelection([]); // needed cause it checks for element changes and does nothing if the elements are the same
|
||||||
|
$rootScope.editor.setSelection($rootScope.selectedElements, $rootScope.subSelectionElements);
|
||||||
|
$rootScope.selectedElements = undefined;
|
||||||
|
$rootScope.subSelectionElements = undefined;
|
||||||
|
|
||||||
|
function handleDisplayProperty(obj) {
|
||||||
|
if (jQuery(obj).position().top > 0) {
|
||||||
|
obj.style.display = 'block';
|
||||||
|
} else {
|
||||||
|
obj.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery('.Oryx_button').each(function(i, obj) {
|
||||||
|
handleDisplayProperty(obj);
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery('.resizer_southeast').each(function(i, obj) {
|
||||||
|
handleDisplayProperty(obj);
|
||||||
|
});
|
||||||
|
jQuery('.resizer_northwest').each(function(i, obj) {
|
||||||
|
handleDisplayProperty(obj);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the Oryx Editor when the content has been loaded
|
||||||
|
*/
|
||||||
|
$rootScope.$on('$includeContentLoaded', function (event) {
|
||||||
|
if (!$rootScope.editorInitialized) {
|
||||||
|
|
||||||
|
ORYX._loadPlugins();
|
||||||
|
|
||||||
|
var modelId = EDITOR.UTIL.getParameterByName('modelId');
|
||||||
|
|
||||||
|
modelId=modelId.substr(1);
|
||||||
|
// modelId=userModelerId;
|
||||||
|
// alert(modelId);
|
||||||
|
fetchModel(modelId);
|
||||||
|
|
||||||
|
$rootScope.window = {};
|
||||||
|
var updateWindowSize = function() {
|
||||||
|
$rootScope.window.width = $window.innerWidth;
|
||||||
|
$rootScope.window.height = $window.innerHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Window resize hook
|
||||||
|
angular.element($window).bind('resize', function() {
|
||||||
|
$rootScope.safeApply(updateWindowSize());
|
||||||
|
});
|
||||||
|
|
||||||
|
$rootScope.$watch('window.forceRefresh', function(newValue) {
|
||||||
|
if(newValue) {
|
||||||
|
$timeout(function() {
|
||||||
|
updateWindowSize();
|
||||||
|
$rootScope.window.forceRefresh = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
updateWindowSize();
|
||||||
|
|
||||||
|
// Hook in resizing of main panels when window resizes
|
||||||
|
// TODO: perhaps move to a separate JS-file?
|
||||||
|
jQuery(window).resize(function () {
|
||||||
|
|
||||||
|
// Calculate the offset based on the bottom of the module header
|
||||||
|
var offset = jQuery("#editor-header").offset();
|
||||||
|
var propSectionHeight = jQuery('#propertySection').height();
|
||||||
|
var canvas = jQuery('#canvasSection');
|
||||||
|
var mainHeader = jQuery('#main-header');
|
||||||
|
|
||||||
|
if (offset == undefined || offset === null
|
||||||
|
|| propSectionHeight === undefined || propSectionHeight === null
|
||||||
|
|| canvas === undefined || canvas === null || mainHeader === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($rootScope.editor)
|
||||||
|
{
|
||||||
|
var selectedElements = $rootScope.editor.selection;
|
||||||
|
var subSelectionElements = $rootScope.editor._subSelection;
|
||||||
|
|
||||||
|
$rootScope.selectedElements = selectedElements;
|
||||||
|
$rootScope.subSelectionElements = subSelectionElements;
|
||||||
|
if (selectedElements && selectedElements.length > 0)
|
||||||
|
{
|
||||||
|
$rootScope.selectedElementBeforeScrolling = selectedElements[0];
|
||||||
|
|
||||||
|
$rootScope.editor.setSelection([]); // needed cause it checks for element changes and does nothing if the elements are the same
|
||||||
|
$rootScope.editor.setSelection($rootScope.selectedElements, $rootScope.subSelectionElements);
|
||||||
|
$rootScope.selectedElements = undefined;
|
||||||
|
$rootScope.subSelectionElements = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalAvailable = jQuery(window).height() - offset.top - mainHeader.height() - 21;
|
||||||
|
canvas.height(totalAvailable - propSectionHeight);
|
||||||
|
jQuery('#paletteSection').height(totalAvailable);
|
||||||
|
|
||||||
|
// Update positions of the resize-markers, according to the canvas
|
||||||
|
|
||||||
|
var actualCanvas = null;
|
||||||
|
if (canvas && canvas[0].children[1]) {
|
||||||
|
actualCanvas = canvas[0].children[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
var canvasTop = canvas.position().top;
|
||||||
|
var canvasLeft = canvas.position().left;
|
||||||
|
var canvasHeight = canvas[0].clientHeight;
|
||||||
|
var canvasWidth = canvas[0].clientWidth;
|
||||||
|
var iconCenterOffset = 8;
|
||||||
|
var widthDiff = 0;
|
||||||
|
|
||||||
|
var actualWidth = 0;
|
||||||
|
if(actualCanvas) {
|
||||||
|
// In some browsers, the SVG-element clientwidth isn't available, so we revert to the parent
|
||||||
|
actualWidth = actualCanvas.clientWidth || actualCanvas.parentNode.clientWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(actualWidth < canvas[0].clientWidth) {
|
||||||
|
widthDiff = actualWidth - canvas[0].clientWidth;
|
||||||
|
// In case the canvas is smaller than the actual viewport, the resizers should be moved
|
||||||
|
canvasLeft -= widthDiff / 2;
|
||||||
|
canvasWidth += widthDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
var iconWidth = 17;
|
||||||
|
var iconOffset = 20;
|
||||||
|
|
||||||
|
var north = jQuery('#canvas-grow-N');
|
||||||
|
north.css('top', canvasTop + iconOffset + 'px');
|
||||||
|
north.css('left', canvasLeft - 10 + (canvasWidth - iconWidth) / 2 + 'px');
|
||||||
|
|
||||||
|
var south = jQuery('#canvas-grow-S');
|
||||||
|
south.css('top', (canvasTop + canvasHeight - iconOffset - iconCenterOffset) + 'px');
|
||||||
|
south.css('left', canvasLeft - 10 + (canvasWidth - iconWidth) / 2 + 'px');
|
||||||
|
|
||||||
|
var east = jQuery('#canvas-grow-E');
|
||||||
|
east.css('top', canvasTop - 10 + (canvasHeight - iconWidth) / 2 + 'px');
|
||||||
|
east.css('left', (canvasLeft + canvasWidth - iconOffset - iconCenterOffset) + 'px');
|
||||||
|
|
||||||
|
var west = jQuery('#canvas-grow-W');
|
||||||
|
west.css('top', canvasTop -10 + (canvasHeight - iconWidth) / 2 + 'px');
|
||||||
|
west.css('left', canvasLeft + iconOffset + 'px');
|
||||||
|
|
||||||
|
north = jQuery('#canvas-shrink-N');
|
||||||
|
north.css('top', canvasTop + iconOffset + 'px');
|
||||||
|
north.css('left', canvasLeft + 10 + (canvasWidth - iconWidth) / 2 + 'px');
|
||||||
|
|
||||||
|
south = jQuery('#canvas-shrink-S');
|
||||||
|
south.css('top', (canvasTop + canvasHeight - iconOffset - iconCenterOffset) + 'px');
|
||||||
|
south.css('left', canvasLeft +10 + (canvasWidth - iconWidth) / 2 + 'px');
|
||||||
|
|
||||||
|
east = jQuery('#canvas-shrink-E');
|
||||||
|
east.css('top', canvasTop + 10 + (canvasHeight - iconWidth) / 2 + 'px');
|
||||||
|
east.css('left', (canvasLeft + canvasWidth - iconOffset - iconCenterOffset) + 'px');
|
||||||
|
|
||||||
|
west = jQuery('#canvas-shrink-W');
|
||||||
|
west.css('top', canvasTop + 10 + (canvasHeight - iconWidth) / 2 + 'px');
|
||||||
|
west.css('left', canvasLeft + iconOffset + 'px');
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery(window).trigger('resize');
|
||||||
|
|
||||||
|
jQuery.fn.scrollStopped = function(callback) {
|
||||||
|
jQuery(this).scroll(function(){
|
||||||
|
var self = this, $this = jQuery(self);
|
||||||
|
if ($this.data('scrollTimeout')) {
|
||||||
|
clearTimeout($this.data('scrollTimeout'));
|
||||||
|
}
|
||||||
|
$this.data('scrollTimeout', setTimeout(callback,50,self));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Always needed, cause the DOM element on which the scroll event listeners are attached are changed for every new model
|
||||||
|
initScrollHandling();
|
||||||
|
|
||||||
|
$rootScope.editorInitialized = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the event bus: couple all Oryx events with a dispatch of the
|
||||||
|
* event of the event bus. This way, it gets much easier to attach custom logic
|
||||||
|
* to any event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$rootScope.editorFactory.promise.then(function() {
|
||||||
|
|
||||||
|
KISBPM.eventBus.editor = $rootScope.editor;
|
||||||
|
|
||||||
|
var eventMappings = [
|
||||||
|
{ oryxType : ORYX.CONFIG.EVENT_SELECTION_CHANGED, kisBpmType : KISBPM.eventBus.EVENT_TYPE_SELECTION_CHANGE },
|
||||||
|
{ oryxType : ORYX.CONFIG.EVENT_DBLCLICK, kisBpmType : KISBPM.eventBus.EVENT_TYPE_DOUBLE_CLICK },
|
||||||
|
{ oryxType : ORYX.CONFIG.EVENT_MOUSEOUT, kisBpmType : KISBPM.eventBus.EVENT_TYPE_MOUSE_OUT },
|
||||||
|
{ oryxType : ORYX.CONFIG.EVENT_MOUSEOVER, kisBpmType : KISBPM.eventBus.EVENT_TYPE_MOUSE_OVER }
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
eventMappings.forEach(function(eventMapping) {
|
||||||
|
$rootScope.editor.registerOnEvent(eventMapping.oryxType, function(event) {
|
||||||
|
KISBPM.eventBus.dispatch(eventMapping.kisBpmType, event);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$rootScope.editor.registerOnEvent(ORYX.CONFIG.EVENT_SHAPEREMOVED, function (event) {
|
||||||
|
var validateButton = document.getElementById(event.shape.resourceId + "-validate-button");
|
||||||
|
if (validateButton)
|
||||||
|
{
|
||||||
|
validateButton.style.display = 'none';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// The Oryx canvas is ready (we know since we're in this promise callback) and the
|
||||||
|
// event bus is ready. The editor is now ready for use
|
||||||
|
KISBPM.eventBus.dispatch(KISBPM.eventBus.EVENT_TYPE_EDITOR_READY, {type : KISBPM.eventBus.EVENT_TYPE_EDITOR_READY});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Alerts
|
||||||
|
$rootScope.alerts = {
|
||||||
|
queue: []
|
||||||
|
};
|
||||||
|
|
||||||
|
$rootScope.showAlert = function(alert) {
|
||||||
|
if(alert.queue.length > 0) {
|
||||||
|
alert.current = alert.queue.shift();
|
||||||
|
// Start timout for message-pruning
|
||||||
|
alert.timeout = $timeout(function() {
|
||||||
|
if (alert.queue.length == 0) {
|
||||||
|
alert.current = undefined;
|
||||||
|
alert.timeout = undefined;
|
||||||
|
} else {
|
||||||
|
$rootScope.showAlert(alert);
|
||||||
|
}
|
||||||
|
}, (alert.current.type == 'error' ? 5000 : 1000));
|
||||||
|
} else {
|
||||||
|
$rootScope.alerts.current = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$rootScope.addAlert = function(message, type) {
|
||||||
|
var newAlert = {message: message, type: type};
|
||||||
|
if (!$rootScope.alerts.timeout) {
|
||||||
|
// Timeout for message queue is not running, start one
|
||||||
|
$rootScope.alerts.queue.push(newAlert);
|
||||||
|
$rootScope.showAlert($rootScope.alerts);
|
||||||
|
} else {
|
||||||
|
$rootScope.alerts.queue.push(newAlert);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$rootScope.dismissAlert = function() {
|
||||||
|
if (!$rootScope.alerts.timeout) {
|
||||||
|
$rootScope.alerts.current = undefined;
|
||||||
|
} else {
|
||||||
|
$timeout.cancel($rootScope.alerts.timeout);
|
||||||
|
$rootScope.alerts.timeout = undefined;
|
||||||
|
$rootScope.showAlert($rootScope.alerts);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$rootScope.addAlertPromise = function(promise, type) {
|
||||||
|
if (promise) {
|
||||||
|
promise.then(function(data) {
|
||||||
|
$rootScope.addAlert(data, type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
// Moment-JS date-formatting filter
|
||||||
|
.filter('dateformat', function() {
|
||||||
|
return function(date, format) {
|
||||||
|
if (date) {
|
||||||
|
if (format) {
|
||||||
|
return moment(date).format(format);
|
||||||
|
} else {
|
||||||
|
return moment(date).calendar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
});
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assignment
|
||||||
|
*/
|
||||||
|
var KisBpmAssignmentCtrl = [ '$scope', '$modal', function($scope, $modal) {
|
||||||
|
|
||||||
|
// Config for the modal window
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/assignment-popup.html?version=' + Date.now(),
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the dialog
|
||||||
|
$modal(opts);
|
||||||
|
}];
|
||||||
|
|
||||||
|
var KisBpmAssignmentPopupCtrl = [ '$scope', function($scope) {
|
||||||
|
|
||||||
|
// Put json representing assignment on scope
|
||||||
|
if ($scope.property.value !== undefined && $scope.property.value !== null
|
||||||
|
&& $scope.property.value.assignment !== undefined
|
||||||
|
&& $scope.property.value.assignment !== null)
|
||||||
|
{
|
||||||
|
$scope.assignment = $scope.property.value.assignment;
|
||||||
|
} else {
|
||||||
|
$scope.assignment = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($scope.assignment.candidateUsers == undefined || $scope.assignment.candidateUsers.length == 0)
|
||||||
|
{
|
||||||
|
$scope.assignment.candidateUsers = [{value: ''}];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Click handler for + button after enum value
|
||||||
|
var userValueIndex = 1;
|
||||||
|
$scope.addCandidateUserValue = function(index) {
|
||||||
|
$scope.assignment.candidateUsers.splice(index + 1, 0, {value: 'value ' + userValueIndex++});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for - button after enum value
|
||||||
|
$scope.removeCandidateUserValue = function(index) {
|
||||||
|
$scope.assignment.candidateUsers.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($scope.assignment.candidateGroups == undefined || $scope.assignment.candidateGroups.length == 0)
|
||||||
|
{
|
||||||
|
$scope.assignment.candidateGroups = [{value: ''}];
|
||||||
|
}
|
||||||
|
|
||||||
|
var groupValueIndex = 1;
|
||||||
|
$scope.addCandidateGroupValue = function(index) {
|
||||||
|
$scope.assignment.candidateGroups.splice(index + 1, 0, {value: 'value ' + groupValueIndex++});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for - button after enum value
|
||||||
|
$scope.removeCandidateGroupValue = function(index) {
|
||||||
|
$scope.assignment.candidateGroups.splice(index, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.save = function() {
|
||||||
|
|
||||||
|
$scope.property.value = {};
|
||||||
|
handleAssignmentInput($scope);
|
||||||
|
$scope.property.value.assignment = $scope.assignment;
|
||||||
|
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
$scope.close = function() {
|
||||||
|
handleAssignmentInput($scope);
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
var handleAssignmentInput = function($scope) {
|
||||||
|
if ($scope.assignment.candidateUsers)
|
||||||
|
{
|
||||||
|
var emptyUsers = true;
|
||||||
|
var toRemoveIndexes = [];
|
||||||
|
for (var i = 0; i < $scope.assignment.candidateUsers.length; i++)
|
||||||
|
{
|
||||||
|
if ($scope.assignment.candidateUsers[i].value != '')
|
||||||
|
{
|
||||||
|
emptyUsers = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toRemoveIndexes[toRemoveIndexes.length] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < toRemoveIndexes.length; i++)
|
||||||
|
{
|
||||||
|
$scope.assignment.candidateUsers.splice(toRemoveIndexes[i], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emptyUsers)
|
||||||
|
{
|
||||||
|
$scope.assignment.candidateUsers = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($scope.assignment.candidateGroups)
|
||||||
|
{
|
||||||
|
var emptyGroups = true;
|
||||||
|
var toRemoveIndexes = [];
|
||||||
|
for (var i = 0; i < $scope.assignment.candidateGroups.length; i++)
|
||||||
|
{
|
||||||
|
if ($scope.assignment.candidateGroups[i].value != '')
|
||||||
|
{
|
||||||
|
emptyGroups = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toRemoveIndexes[toRemoveIndexes.length] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < toRemoveIndexes.length; i++)
|
||||||
|
{
|
||||||
|
$scope.assignment.candidateGroups.splice(toRemoveIndexes[i], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (emptyGroups)
|
||||||
|
{
|
||||||
|
$scope.assignment.candidateGroups = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}];
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Condition expression
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmConditionExpressionCtrl = [ '$scope', '$modal', function($scope, $modal) {
|
||||||
|
|
||||||
|
// Config for the modal window
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/condition-expression-popup.html?version=' + Date.now(),
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the dialog
|
||||||
|
$modal(opts);
|
||||||
|
}];
|
||||||
|
|
||||||
|
var KisBpmConditionExpressionPopupCtrl = [ '$scope', '$translate', '$http', function($scope, $translate, $http) {
|
||||||
|
|
||||||
|
// Put json representing condition on scope
|
||||||
|
if ($scope.property.value !== undefined && $scope.property.value !== null) {
|
||||||
|
|
||||||
|
$scope.conditionExpression = {value: $scope.property.value};
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$scope.conditionExpression = {value: ''};
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.save = function() {
|
||||||
|
console.log("条件表达式设置");
|
||||||
|
$scope.property.value = $scope.conditionExpression.value;
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
$scope.close = function() {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
}];
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* String controller
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmStringPropertyCtrl = [ '$scope', function ($scope) {
|
||||||
|
|
||||||
|
$scope.shapeId = $scope.selectedShape.id;
|
||||||
|
$scope.valueFlushed = false;
|
||||||
|
/** Handler called when input field is blurred */
|
||||||
|
$scope.inputBlurred = function() {
|
||||||
|
$scope.valueFlushed = true;
|
||||||
|
if ($scope.property.value) {
|
||||||
|
$scope.property.value = $scope.property.value.replace(/(<([^>]+)>)/ig,"");
|
||||||
|
}
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.enterPressed = function(keyEvent) {
|
||||||
|
if (keyEvent && keyEvent.which === 13) {
|
||||||
|
keyEvent.preventDefault();
|
||||||
|
$scope.inputBlurred(); // we want to do the same as if the user would blur the input field
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.$on('$destroy', function controllerDestroyed() {
|
||||||
|
if(!$scope.valueFlushed) {
|
||||||
|
if ($scope.property.value) {
|
||||||
|
$scope.property.value = $scope.property.value.replace(/(<([^>]+)>)/ig,"");
|
||||||
|
}
|
||||||
|
$scope.updatePropertyInModel($scope.property, $scope.shapeId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Boolean controller
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmBooleanPropertyCtrl = ['$scope', function ($scope) {
|
||||||
|
|
||||||
|
$scope.changeValue = function() {
|
||||||
|
if ($scope.property.key === 'oryx-defaultflow' && $scope.property.value) {
|
||||||
|
var selectedShape = $scope.selectedShape;
|
||||||
|
if (selectedShape) {
|
||||||
|
var incomingNodes = selectedShape.getIncomingShapes();
|
||||||
|
if (incomingNodes && incomingNodes.length > 0) {
|
||||||
|
// get first node, since there can be only one for a sequence flow
|
||||||
|
var rootNode = incomingNodes[0];
|
||||||
|
var flows = rootNode.getOutgoingShapes();
|
||||||
|
if (flows && flows.length > 1) {
|
||||||
|
// in case there are more flows, check if another flow is already defined as default
|
||||||
|
for (var i = 0; i < flows.length; i++) {
|
||||||
|
if (flows[i].resourceId != selectedShape.resourceId) {
|
||||||
|
var defaultFlowProp = flows[i].properties['oryx-defaultflow'];
|
||||||
|
if (defaultFlowProp) {
|
||||||
|
flows[i].setProperty('oryx-defaultflow', false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
};
|
||||||
|
|
||||||
|
}];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Text controller
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmTextPropertyCtrl = [ '$scope', '$modal', function($scope, $modal) {
|
||||||
|
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/text-popup.html?version=' + Date.now(),
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the dialog
|
||||||
|
$modal(opts);
|
||||||
|
}];
|
||||||
|
|
||||||
|
var KisBpmTextPropertyPopupCtrl = ['$scope', function($scope) {
|
||||||
|
|
||||||
|
$scope.save = function() {
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.close = function() {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
}];
|
|
@ -0,0 +1,266 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Execution listeners
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmEventListenersCtrl = [ '$scope', '$modal', '$timeout', '$translate', function($scope, $modal, $timeout, $translate) {
|
||||||
|
|
||||||
|
// Config for the modal window
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/event-listeners-popup.html?version=' + Date.now(),
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the dialog
|
||||||
|
$modal(opts);
|
||||||
|
}];
|
||||||
|
|
||||||
|
//Need a separate controller for the modal window due to https://github.com/angular-ui/bootstrap/issues/259
|
||||||
|
// Will be fixed in a newer version of Angular UI
|
||||||
|
var KisBpmEventListenersPopupCtrl = [ '$scope', '$q', '$translate', function($scope, $q, $translate) {
|
||||||
|
|
||||||
|
// Put json representing form properties on scope
|
||||||
|
if ($scope.property.value !== undefined && $scope.property.value !== null
|
||||||
|
&& $scope.property.value.eventListeners !== undefined
|
||||||
|
&& $scope.property.value.eventListeners !== null) {
|
||||||
|
|
||||||
|
if ($scope.property.value.eventListeners.constructor == String)
|
||||||
|
{
|
||||||
|
$scope.eventListeners = JSON.parse($scope.property.value.eventListeners);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Note that we clone the json object rather then setting it directly,
|
||||||
|
// this to cope with the fact that the user can click the cancel button and no changes should have happened
|
||||||
|
$scope.eventListeners = angular.copy($scope.property.value.eventListeners);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$scope.eventListeners = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
|
||||||
|
$scope.selectedListeners = [];
|
||||||
|
$scope.translationsRetrieved = false;
|
||||||
|
|
||||||
|
$scope.labels = {};
|
||||||
|
|
||||||
|
var eventPromise = $translate('PROPERTY.EXECUTIONLISTENERS.EVENT');
|
||||||
|
var implementationPromise = $translate('PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION');
|
||||||
|
var namePromise = $translate('PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME');
|
||||||
|
|
||||||
|
$q.all([eventPromise, implementationPromise, namePromise]).then(function(results) {
|
||||||
|
$scope.labels.eventLabel = results[0];
|
||||||
|
$scope.labels.implementationLabel = results[1];
|
||||||
|
$scope.labels.nameLabel = results[2];
|
||||||
|
$scope.translationsRetrieved = true;
|
||||||
|
|
||||||
|
// Config for grid
|
||||||
|
$scope.gridOptions = {
|
||||||
|
data: 'eventListeners',
|
||||||
|
enableRowReordering: true,
|
||||||
|
headerRowHeight: 28,
|
||||||
|
multiSelect: false,
|
||||||
|
keepLastSelected : false,
|
||||||
|
selectedItems: $scope.selectedListeners,
|
||||||
|
afterSelectionChange: function (rowItem, event) {
|
||||||
|
|
||||||
|
if ($scope.selectedListeners.length > 0)
|
||||||
|
{
|
||||||
|
var fields = $scope.selectedListeners[0].fields;
|
||||||
|
if (fields !== undefined && fields !== null)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < fields.length; i++)
|
||||||
|
{
|
||||||
|
var field = fields[i];
|
||||||
|
if (field.stringValue !== undefined && field.stringValue !== '')
|
||||||
|
{
|
||||||
|
field.implementation = field.stringValue;
|
||||||
|
}
|
||||||
|
else if (field.expression !== undefined && field.expression !== '')
|
||||||
|
{
|
||||||
|
field.implementation = field.expression;
|
||||||
|
}
|
||||||
|
else if (field.string !== undefined && field.string !== '')
|
||||||
|
{
|
||||||
|
field.implementation = field.string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$scope.selectedListeners[0].events || $scope.selectedListeners[0].events.length == 0)
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].events = [{event: ''}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
columnDefs: [{ field: 'event', displayName: $scope.labels.eventLabel },
|
||||||
|
{ field: 'implementation', displayName: $scope.labels.implementationLabel }]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click handler for + button after enum value
|
||||||
|
$scope.addEventValue = function(index) {
|
||||||
|
$scope.selectedListeners[0].events.splice(index + 1, 0, {event: ''});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for - button after enum value
|
||||||
|
$scope.removeEventValue = function(index) {
|
||||||
|
$scope.selectedListeners[0].events.splice(index, 1);
|
||||||
|
$scope.listenerDetailsChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.listenerDetailsChanged = function() {
|
||||||
|
var listener = $scope.selectedListeners[0];
|
||||||
|
if (listener.events)
|
||||||
|
{
|
||||||
|
var eventText = '';
|
||||||
|
for (var i = 0; i < listener.events.length; i++)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
eventText += ", ";
|
||||||
|
}
|
||||||
|
eventText += listener.events[i].event;
|
||||||
|
}
|
||||||
|
$scope.selectedListeners[0].event = eventText;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listener.rethrowEvent)
|
||||||
|
{
|
||||||
|
var implementationText = '';
|
||||||
|
if (listener.rethrowType && listener.rethrowType.length > 0)
|
||||||
|
{
|
||||||
|
if (listener.rethrowType === 'error' && listener.errorcode !== '')
|
||||||
|
{
|
||||||
|
implementationText = "Rethrow as error " + listener.errorcode;
|
||||||
|
}
|
||||||
|
else if (listener.rethrowType === 'message' && listener.messagename !== '')
|
||||||
|
{
|
||||||
|
implementationText = "Rethrow as message " + listener.messagename;
|
||||||
|
}
|
||||||
|
else if ((listener.rethrowType === 'signal' || listener.rethrowType === 'globalSignal') && listener.signalname !== '')
|
||||||
|
{
|
||||||
|
implementationText = "Rethrow as signal " + listener.signalname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$scope.selectedListeners[0].implementation = implementationText;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ($scope.selectedListeners[0].className !== '')
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].implementation = $scope.selectedListeners[0].className;
|
||||||
|
}
|
||||||
|
else if ($scope.selectedListeners[0].delegateExpression !== '')
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].implementation = $scope.selectedListeners[0].delegateExpression;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].implementation = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for add button
|
||||||
|
$scope.addNewListener = function() {
|
||||||
|
$scope.eventListeners.push({ event : '',
|
||||||
|
implementation : '',
|
||||||
|
className : '',
|
||||||
|
delegateExpression: '',
|
||||||
|
retrowEvent: false});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for remove button
|
||||||
|
$scope.removeListener = function() {
|
||||||
|
if ($scope.selectedListeners.length > 0) {
|
||||||
|
var index = $scope.eventListeners.indexOf($scope.selectedListeners[0]);
|
||||||
|
$scope.gridOptions.selectItem(index, false);
|
||||||
|
$scope.eventListeners.splice(index, 1);
|
||||||
|
|
||||||
|
$scope.selectedListeners.length = 0;
|
||||||
|
if (index < $scope.eventListeners.length) {
|
||||||
|
$scope.gridOptions.selectItem(index + 1, true);
|
||||||
|
} else if ($scope.eventListeners.length > 0) {
|
||||||
|
$scope.gridOptions.selectItem(index - 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for up button
|
||||||
|
$scope.moveListenerUp = function() {
|
||||||
|
if ($scope.selectedListeners.length > 0) {
|
||||||
|
var index = $scope.eventListeners.indexOf($scope.selectedListeners[0]);
|
||||||
|
if (index != 0) { // If it's the first, no moving up of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.eventListeners[index];
|
||||||
|
$scope.eventListeners.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.eventListeners.splice(index + -1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for down button
|
||||||
|
$scope.moveListenerDown = function() {
|
||||||
|
if ($scope.selectedListeners.length > 0) {
|
||||||
|
var index = $scope.eventListeners.indexOf($scope.selectedListeners[0]);
|
||||||
|
if (index != $scope.eventListeners.length - 1) { // If it's the last element, no moving down of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.eventListeners[index];
|
||||||
|
$scope.eventListeners.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.eventListeners.splice(index + 1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for save button
|
||||||
|
$scope.save = function() {
|
||||||
|
|
||||||
|
if ($scope.eventListeners.length > 0) {
|
||||||
|
$scope.property.value = {};
|
||||||
|
$scope.property.value.eventListeners = $scope.eventListeners;
|
||||||
|
} else {
|
||||||
|
$scope.property.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function() {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
$scope.close = function() {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
}];
|
|
@ -0,0 +1,326 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Execution listeners
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmExecutionListenersCtrl = [ '$scope', '$modal', '$timeout', '$translate', function($scope, $modal, $timeout, $translate) {
|
||||||
|
|
||||||
|
// Config for the modal window
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/execution-listeners-popup.html?version=' + Date.now(),
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the dialog
|
||||||
|
$modal(opts);
|
||||||
|
}];
|
||||||
|
|
||||||
|
var KisBpmExecutionListenersPopupCtrl = [ '$scope', '$q', '$translate', function($scope, $q, $translate) {
|
||||||
|
|
||||||
|
// Put json representing form properties on scope
|
||||||
|
if ($scope.property.value !== undefined && $scope.property.value !== null
|
||||||
|
&& $scope.property.value.executionListeners !== undefined
|
||||||
|
&& $scope.property.value.executionListeners !== null) {
|
||||||
|
|
||||||
|
if ($scope.property.value.executionListeners.constructor == String)
|
||||||
|
{
|
||||||
|
$scope.executionListeners = JSON.parse($scope.property.value.executionListeners);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Note that we clone the json object rather then setting it directly,
|
||||||
|
// this to cope with the fact that the user can click the cancel button and no changes should have happened
|
||||||
|
$scope.executionListeners = angular.copy($scope.property.value.executionListeners);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < $scope.executionListeners.length; i++)
|
||||||
|
{
|
||||||
|
var executionListener = $scope.executionListeners[i];
|
||||||
|
if (executionListener.className !== undefined && executionListener.className !== '')
|
||||||
|
{
|
||||||
|
executionListener.implementation = executionListener.className;
|
||||||
|
}
|
||||||
|
else if (executionListener.expression !== undefined && executionListener.expression !== '')
|
||||||
|
{
|
||||||
|
executionListener.implementation = executionListener.expression;
|
||||||
|
}
|
||||||
|
else if (executionListener.delegateExpression !== undefined && executionListener.delegateExpression !== '')
|
||||||
|
{
|
||||||
|
executionListener.implementation = executionListener.delegateExpression;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$scope.executionListeners = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
|
||||||
|
$scope.selectedListeners = [];
|
||||||
|
$scope.selectedFields = [];
|
||||||
|
$scope.translationsRetrieved = false;
|
||||||
|
|
||||||
|
$scope.labels = {};
|
||||||
|
|
||||||
|
var eventPromise = $translate('PROPERTY.EXECUTIONLISTENERS.EVENT');
|
||||||
|
var implementationPromise = $translate('PROPERTY.EXECUTIONLISTENERS.FIELDS.IMPLEMENTATION');
|
||||||
|
var namePromise = $translate('PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME');
|
||||||
|
|
||||||
|
$q.all([eventPromise, implementationPromise, namePromise]).then(function(results) {
|
||||||
|
$scope.labels.eventLabel = results[0];
|
||||||
|
$scope.labels.implementationLabel = results[1];
|
||||||
|
$scope.labels.nameLabel = results[2];
|
||||||
|
$scope.translationsRetrieved = true;
|
||||||
|
|
||||||
|
// Config for grid
|
||||||
|
$scope.gridOptions = {
|
||||||
|
data: 'executionListeners',
|
||||||
|
enableRowReordering: true,
|
||||||
|
headerRowHeight: 28,
|
||||||
|
multiSelect: false,
|
||||||
|
keepLastSelected : false,
|
||||||
|
selectedItems: $scope.selectedListeners,
|
||||||
|
afterSelectionChange: function (rowItem, event) {
|
||||||
|
$scope.selectedFields.length = 0;
|
||||||
|
if ($scope.selectedListeners.length > 0)
|
||||||
|
{
|
||||||
|
var fields = $scope.selectedListeners[0].fields;
|
||||||
|
if (fields !== undefined && fields !== null)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < fields.length; i++)
|
||||||
|
{
|
||||||
|
var field = fields[i];
|
||||||
|
if (field.stringValue !== undefined && field.stringValue !== '')
|
||||||
|
{
|
||||||
|
field.implementation = field.stringValue;
|
||||||
|
}
|
||||||
|
else if (field.expression !== undefined && field.expression !== '')
|
||||||
|
{
|
||||||
|
field.implementation = field.expression;
|
||||||
|
}
|
||||||
|
else if (field.string !== undefined && field.string !== '')
|
||||||
|
{
|
||||||
|
field.implementation = field.string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
columnDefs: [{ field: 'event', displayName: $scope.labels.eventLabel },
|
||||||
|
{ field: 'implementation', displayName: $scope.labels.implementationLabel }]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Config for field grid
|
||||||
|
$scope.gridFieldOptions = {
|
||||||
|
data: 'selectedListeners[0].fields',
|
||||||
|
enableRowReordering: true,
|
||||||
|
headerRowHeight: 28,
|
||||||
|
multiSelect: false,
|
||||||
|
keepLastSelected : false,
|
||||||
|
selectedItems: $scope.selectedFields,
|
||||||
|
columnDefs: [{ field: 'name', displayName: $scope.labels.nameLabel },
|
||||||
|
{ field: 'implementation', displayName: $scope.labels.implementationLabel}]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.listenerDetailsChanged = function() {
|
||||||
|
if ($scope.selectedListeners[0].className !== '')
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].implementation = $scope.selectedListeners[0].className;
|
||||||
|
}
|
||||||
|
else if ($scope.selectedListeners[0].expression !== '')
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].implementation = $scope.selectedListeners[0].expression;
|
||||||
|
}
|
||||||
|
else if ($scope.selectedListeners[0].delegateExpression !== '')
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].implementation = $scope.selectedListeners[0].delegateExpression;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].implementation = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for add button
|
||||||
|
$scope.addNewListener = function() {
|
||||||
|
$scope.executionListeners.push({ event : 'start',
|
||||||
|
implementation : '',
|
||||||
|
className : '',
|
||||||
|
expression: '',
|
||||||
|
delegateExpression: ''});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for remove button
|
||||||
|
$scope.removeListener = function() {
|
||||||
|
if ($scope.selectedListeners.length > 0) {
|
||||||
|
var index = $scope.executionListeners.indexOf($scope.selectedListeners[0]);
|
||||||
|
$scope.gridOptions.selectItem(index, false);
|
||||||
|
$scope.executionListeners.splice(index, 1);
|
||||||
|
|
||||||
|
$scope.selectedListeners.length = 0;
|
||||||
|
if (index < $scope.executionListeners.length) {
|
||||||
|
$scope.gridOptions.selectItem(index + 1, true);
|
||||||
|
} else if ($scope.executionListeners.length > 0) {
|
||||||
|
$scope.gridOptions.selectItem(index - 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for up button
|
||||||
|
$scope.moveListenerUp = function() {
|
||||||
|
if ($scope.selectedListeners.length > 0) {
|
||||||
|
var index = $scope.executionListeners.indexOf($scope.selectedListeners[0]);
|
||||||
|
if (index != 0) { // If it's the first, no moving up of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.executionListeners[index];
|
||||||
|
$scope.executionListeners.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.executionListeners.splice(index + -1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for down button
|
||||||
|
$scope.moveListenerDown = function() {
|
||||||
|
if ($scope.selectedListeners.length > 0) {
|
||||||
|
var index = $scope.executionListeners.indexOf($scope.selectedListeners[0]);
|
||||||
|
if (index != $scope.executionListeners.length - 1) { // If it's the last element, no moving down of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.executionListeners[index];
|
||||||
|
$scope.executionListeners.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.executionListeners.splice(index + 1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.fieldDetailsChanged = function() {
|
||||||
|
if ($scope.selectedFields[0].stringValue !== '')
|
||||||
|
{
|
||||||
|
$scope.selectedFields[0].implementation = $scope.selectedFields[0].stringValue;
|
||||||
|
}
|
||||||
|
else if ($scope.selectedFields[0].expression !== '')
|
||||||
|
{
|
||||||
|
$scope.selectedFields[0].implementation = $scope.selectedFields[0].expression;
|
||||||
|
}
|
||||||
|
else if ($scope.selectedFields[0].string !== '')
|
||||||
|
{
|
||||||
|
$scope.selectedFields[0].implementation = $scope.selectedFields[0].string;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$scope.selectedFields[0].implementation = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for add button
|
||||||
|
$scope.addNewField = function() {
|
||||||
|
if ($scope.selectedListeners.length > 0)
|
||||||
|
{
|
||||||
|
if ($scope.selectedListeners[0].fields == undefined)
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].fields = [];
|
||||||
|
}
|
||||||
|
$scope.selectedListeners[0].fields.push({ name : 'fieldName',
|
||||||
|
implementation : '',
|
||||||
|
stringValue : '',
|
||||||
|
expression: '',
|
||||||
|
string: ''});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for remove button
|
||||||
|
$scope.removeField = function() {
|
||||||
|
if ($scope.selectedFields.length > 0) {
|
||||||
|
var index = $scope.selectedListeners[0].fields.indexOf($scope.selectedFields[0]);
|
||||||
|
$scope.gridFieldOptions.selectItem(index, false);
|
||||||
|
$scope.selectedListeners[0].fields.splice(index, 1);
|
||||||
|
|
||||||
|
$scope.selectedFields.length = 0;
|
||||||
|
if (index < $scope.selectedListeners[0].fields.length) {
|
||||||
|
$scope.gridFieldOptions.selectItem(index + 1, true);
|
||||||
|
} else if ($scope.selectedListeners[0].fields.length > 0) {
|
||||||
|
$scope.gridFieldOptions.selectItem(index - 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for up button
|
||||||
|
$scope.moveFieldUp = function() {
|
||||||
|
if ($scope.selectedFields.length > 0) {
|
||||||
|
var index = $scope.selectedListeners[0].fields.indexOf($scope.selectedFields[0]);
|
||||||
|
if (index != 0) { // If it's the first, no moving up of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.selectedListeners[0].fields[index];
|
||||||
|
$scope.selectedListeners[0].fields.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.selectedListeners[0].fields.splice(index + -1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for down button
|
||||||
|
$scope.moveFieldDown = function() {
|
||||||
|
if ($scope.selectedFields.length > 0) {
|
||||||
|
var index = $scope.selectedListeners[0].fields.indexOf($scope.selectedFields[0]);
|
||||||
|
if (index != $scope.selectedListeners[0].fields.length - 1) { // If it's the last element, no moving down of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.selectedListeners[0].fields[index];
|
||||||
|
$scope.selectedListeners[0].fields.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.selectedListeners[0].fields.splice(index + 1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for save button
|
||||||
|
$scope.save = function() {
|
||||||
|
|
||||||
|
if ($scope.executionListeners.length > 0) {
|
||||||
|
$scope.property.value = {};
|
||||||
|
$scope.property.value.executionListeners = $scope.executionListeners;
|
||||||
|
} else {
|
||||||
|
$scope.property.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function() {
|
||||||
|
$scope.$hide();
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
$scope.close = function() {
|
||||||
|
$scope.$hide();
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
};
|
||||||
|
|
||||||
|
}];
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Task listeners
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmFieldsCtrl = [ '$scope', '$modal', '$timeout', '$translate', function($scope, $modal, $timeout, $translate) {
|
||||||
|
|
||||||
|
// Config for the modal window
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/fields-popup.html',
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the dialog
|
||||||
|
$modal(opts);
|
||||||
|
}];
|
||||||
|
|
||||||
|
var KisBpmFieldsPopupCtrl = [ '$scope', '$q', '$translate', function($scope, $q, $translate) {
|
||||||
|
|
||||||
|
// Put json representing form properties on scope
|
||||||
|
if ($scope.property.value !== undefined && $scope.property.value !== null
|
||||||
|
&& $scope.property.value.fields !== undefined
|
||||||
|
&& $scope.property.value.fields !== null) {
|
||||||
|
// Note that we clone the json object rather then setting it directly,
|
||||||
|
// this to cope with the fact that the user can click the cancel button and no changes should have happened
|
||||||
|
$scope.fields = angular.copy($scope.property.value.fields);
|
||||||
|
|
||||||
|
for (var i = 0; i < $scope.fields.length; i++)
|
||||||
|
{
|
||||||
|
var field = $scope.fields[i];
|
||||||
|
if (field.stringValue !== undefined && field.stringValue !== '')
|
||||||
|
{
|
||||||
|
field.implementation = field.stringValue;
|
||||||
|
}
|
||||||
|
else if (field.expression !== undefined && field.expression !== '')
|
||||||
|
{
|
||||||
|
field.implementation = field.expression;
|
||||||
|
}
|
||||||
|
else if (field.string !== undefined && field.string !== '')
|
||||||
|
{
|
||||||
|
field.implementation = field.string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$scope.fields = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
|
||||||
|
$scope.selectedFields = [];
|
||||||
|
$scope.translationsRetrieved = false;
|
||||||
|
$scope.labels = {};
|
||||||
|
|
||||||
|
var namePromise = $translate('PROPERTY.FIELDS.NAME');
|
||||||
|
var implementationPromise = $translate('PROPERTY.FIELDS.IMPLEMENTATION');
|
||||||
|
|
||||||
|
$q.all([namePromise, implementationPromise]).then(function(results) {
|
||||||
|
$scope.labels.nameLabel = results[0];
|
||||||
|
$scope.labels.implementationLabel = results[1];
|
||||||
|
$scope.translationsRetrieved = true;
|
||||||
|
|
||||||
|
// Config for grid
|
||||||
|
$scope.gridOptions = {
|
||||||
|
data: 'fields',
|
||||||
|
enableRowReordering: true,
|
||||||
|
headerRowHeight: 28,
|
||||||
|
multiSelect: false,
|
||||||
|
keepLastSelected: false,
|
||||||
|
selectedItems: $scope.selectedFields,
|
||||||
|
columnDefs: [{field: 'name', displayName: $scope.labels.nameLabel},
|
||||||
|
{field: 'implementation', displayName: $scope.labels.implementationLabel}]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.fieldDetailsChanged = function() {
|
||||||
|
if ($scope.selectedFields[0].stringValue != '')
|
||||||
|
{
|
||||||
|
$scope.selectedFields[0].implementation = $scope.selectedFields[0].stringValue;
|
||||||
|
}
|
||||||
|
else if ($scope.selectedFields[0].expression != '')
|
||||||
|
{
|
||||||
|
$scope.selectedFields[0].implementation = $scope.selectedFields[0].expression;
|
||||||
|
}
|
||||||
|
else if ($scope.selectedFields[0].string != '')
|
||||||
|
{
|
||||||
|
$scope.selectedFields[0].implementation = $scope.selectedFields[0].string;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$scope.selectedFields[0].implementation = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for add button
|
||||||
|
$scope.addNewField = function() {
|
||||||
|
$scope.fields.push({ name : 'fieldName',
|
||||||
|
implementation : '',
|
||||||
|
stringValue : '',
|
||||||
|
expression: '',
|
||||||
|
string: ''});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for remove button
|
||||||
|
$scope.removeField = function() {
|
||||||
|
if ($scope.selectedFields.length > 0) {
|
||||||
|
var index = $scope.fields.indexOf($scope.selectedFields[0]);
|
||||||
|
$scope.gridOptions.selectItem(index, false);
|
||||||
|
$scope.fields.splice(index, 1);
|
||||||
|
|
||||||
|
$scope.selectedFields.length = 0;
|
||||||
|
if (index < $scope.fields.length) {
|
||||||
|
$scope.gridOptions.selectItem(index + 1, true);
|
||||||
|
} else if ($scope.fields.length > 0) {
|
||||||
|
$scope.gridOptions.selectItem(index - 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for up button
|
||||||
|
$scope.moveFieldUp = function() {
|
||||||
|
if ($scope.selectedFields.length > 0) {
|
||||||
|
var index = $scope.fields.indexOf($scope.selectedFields[0]);
|
||||||
|
if (index != 0) { // If it's the first, no moving up of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.fields[index];
|
||||||
|
$scope.fields.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.fields.splice(index + -1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for down button
|
||||||
|
$scope.moveFieldDown = function() {
|
||||||
|
if ($scope.selectedFields.length > 0) {
|
||||||
|
var index = $scope.fields.indexOf($scope.selectedFields[0]);
|
||||||
|
if (index != $scope.fields.length - 1) { // If it's the last element, no moving down of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.fields[index];
|
||||||
|
$scope.fields.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.fields.splice(index + 1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for save button
|
||||||
|
$scope.save = function() {
|
||||||
|
|
||||||
|
if ($scope.fields.length > 0) {
|
||||||
|
$scope.property.value = {};
|
||||||
|
$scope.property.value.fields = $scope.fields;
|
||||||
|
} else {
|
||||||
|
$scope.property.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function() {
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
$scope.close = function() {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
}];
|
|
@ -0,0 +1,276 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Form Properties
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmFormPropertiesCtrl = [ '$scope', '$modal', '$timeout', '$translate', function($scope, $modal, $timeout, $translate) {
|
||||||
|
|
||||||
|
// Config for the modal window
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/form-properties-popup.html?version=' + Date.now(),
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the dialog
|
||||||
|
$modal(opts);
|
||||||
|
}];
|
||||||
|
|
||||||
|
var KisBpmFormPropertiesPopupCtrl = ['$scope', '$q', '$translate', '$timeout', function($scope, $q, $translate, $timeout) {
|
||||||
|
|
||||||
|
// Put json representing form properties on scope
|
||||||
|
if ($scope.property.value !== undefined && $scope.property.value !== null
|
||||||
|
&& $scope.property.value.formProperties !== undefined
|
||||||
|
&& $scope.property.value.formProperties !== null) {
|
||||||
|
// Note that we clone the json object rather then setting it directly,
|
||||||
|
// this to cope with the fact that the user can click the cancel button and no changes should have happended
|
||||||
|
$scope.formProperties = angular.copy($scope.property.value.formProperties);
|
||||||
|
|
||||||
|
for (var i = 0; i < $scope.formProperties.length; i++) {
|
||||||
|
var formProperty = $scope.formProperties[i];
|
||||||
|
if (formProperty.enumValues && formProperty.enumValues.length > 0) {
|
||||||
|
for (var j = 0; j < formProperty.enumValues.length; j++) {
|
||||||
|
var enumValue = formProperty.enumValues[j];
|
||||||
|
if (!enumValue.id && !enumValue.name && enumValue.value) {
|
||||||
|
enumValue.id = enumValue.value;
|
||||||
|
enumValue.name = enumValue.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$scope.formProperties = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
|
||||||
|
$scope.selectedProperties = [];
|
||||||
|
$scope.selectedEnumValues = [];
|
||||||
|
|
||||||
|
$scope.translationsRetrieved = false;
|
||||||
|
|
||||||
|
$scope.labels = {};
|
||||||
|
|
||||||
|
var idPromise = $translate('PROPERTY.FORMPROPERTIES.ID');
|
||||||
|
var namePromise = $translate('PROPERTY.FORMPROPERTIES.NAME');
|
||||||
|
var typePromise = $translate('PROPERTY.FORMPROPERTIES.TYPE');
|
||||||
|
|
||||||
|
$q.all([idPromise, namePromise, typePromise]).then(function(results) {
|
||||||
|
$scope.labels.idLabel = results[0];
|
||||||
|
$scope.labels.nameLabel = results[1];
|
||||||
|
$scope.labels.typeLabel = results[2];
|
||||||
|
$scope.translationsRetrieved = true;
|
||||||
|
|
||||||
|
// Config for grid
|
||||||
|
$scope.gridOptions = {
|
||||||
|
data: 'formProperties',
|
||||||
|
enableRowReordering: true,
|
||||||
|
headerRowHeight: 28,
|
||||||
|
multiSelect: false,
|
||||||
|
keepLastSelected : false,
|
||||||
|
selectedItems: $scope.selectedProperties,
|
||||||
|
columnDefs: [{ field: 'id', displayName: $scope.labels.idLabel },
|
||||||
|
{ field: 'name', displayName: $scope.labels.nameLabel},
|
||||||
|
{ field: 'type', displayName: $scope.labels.typeLabel}]
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.enumGridOptions = {
|
||||||
|
data: 'selectedProperties[0].enumValues',
|
||||||
|
enableRowReordering: true,
|
||||||
|
headerRowHeight: 28,
|
||||||
|
multiSelect: false,
|
||||||
|
keepLastSelected : false,
|
||||||
|
selectedItems: $scope.selectedEnumValues,
|
||||||
|
columnDefs: [{ field: 'id', displayName: $scope.labels.idLabel },
|
||||||
|
{ field: 'name', displayName: $scope.labels.nameLabel}]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handler for when the value of the type dropdown changes
|
||||||
|
$scope.propertyTypeChanged = function() {
|
||||||
|
|
||||||
|
// Check date. If date, show date pattern
|
||||||
|
if ($scope.selectedProperties[0].type === 'date') {
|
||||||
|
$scope.selectedProperties[0].datePattern = 'MM-dd-yyyy hh:mm';
|
||||||
|
|
||||||
|
} else {
|
||||||
|
delete $scope.selectedProperties[0].datePattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check enum. If enum, show list of options
|
||||||
|
if ($scope.selectedProperties[0].type === 'enum') {
|
||||||
|
$scope.selectedProperties[0].enumValues = [ {id: 'value1', name: 'Value 1'}, {id: 'value2', name: 'Value 2'}];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
delete $scope.selectedProperties[0].enumValues;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for add button
|
||||||
|
var propertyIndex = 1;
|
||||||
|
$scope.addNewProperty = function() {
|
||||||
|
$scope.formProperties.push({ id : 'new_property_' + propertyIndex++,
|
||||||
|
name : '',
|
||||||
|
type : 'string',
|
||||||
|
readable: true,
|
||||||
|
writable: true});
|
||||||
|
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.gridOptions.selectItem($scope.formProperties.length - 1, true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for remove button
|
||||||
|
$scope.removeProperty = function() {
|
||||||
|
if ($scope.selectedProperties.length > 0) {
|
||||||
|
var index = $scope.formProperties.indexOf($scope.selectedProperties[0]);
|
||||||
|
$scope.gridOptions.selectItem(index, false);
|
||||||
|
$scope.formProperties.splice(index, 1);
|
||||||
|
|
||||||
|
$scope.selectedProperties.length = 0;
|
||||||
|
if (index < $scope.formProperties.length) {
|
||||||
|
$scope.gridOptions.selectItem(index + 1, true);
|
||||||
|
} else if ($scope.formProperties.length > 0) {
|
||||||
|
$scope.gridOptions.selectItem(index - 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for up button
|
||||||
|
$scope.movePropertyUp = function() {
|
||||||
|
if ($scope.selectedProperties.length > 0) {
|
||||||
|
var index = $scope.formProperties.indexOf($scope.selectedProperties[0]);
|
||||||
|
if (index != 0) { // If it's the first, no moving up of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.formProperties[index];
|
||||||
|
$scope.formProperties.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.formProperties.splice(index + -1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for down button
|
||||||
|
$scope.movePropertyDown = function() {
|
||||||
|
if ($scope.selectedProperties.length > 0) {
|
||||||
|
var index = $scope.formProperties.indexOf($scope.selectedProperties[0]);
|
||||||
|
if (index != $scope.formProperties.length - 1) { // If it's the last element, no moving down of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.formProperties[index];
|
||||||
|
$scope.formProperties.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.formProperties.splice(index + 1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.addNewEnumValue = function() {
|
||||||
|
if ($scope.selectedProperties.length > 0) {
|
||||||
|
$scope.selectedProperties[0].enumValues.push({ id : '', name : ''});
|
||||||
|
}
|
||||||
|
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.enumGridOptions.selectItem($scope.selectedProperties[0].enumValues.length - 1, true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for remove button
|
||||||
|
$scope.removeEnumValue = function() {
|
||||||
|
if ($scope.selectedProperties.length > 0 && $scope.selectedEnumValues.length > 0) {
|
||||||
|
var index = $scope.selectedProperties[0].enumValues.indexOf($scope.selectedEnumValues[0]);
|
||||||
|
$scope.enumGridOptions.selectItem(index, false);
|
||||||
|
$scope.selectedProperties[0].enumValues.splice(index, 1);
|
||||||
|
|
||||||
|
$scope.selectedEnumValues.length = 0;
|
||||||
|
if (index < $scope.selectedProperties[0].enumValues.length) {
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.enumGridOptions.selectItem(index + 1, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if ($scope.selectedProperties[0].enumValues.length > 0) {
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.enumGridOptions.selectItem(index - 1, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for up button
|
||||||
|
$scope.moveEnumValueUp = function() {
|
||||||
|
if ($scope.selectedProperties.length > 0 && $scope.selectedEnumValues.length > 0) {
|
||||||
|
var index = $scope.selectedProperties[0].enumValues.indexOf($scope.selectedEnumValues[0]);
|
||||||
|
if (index != 0) { // If it's the first, no moving up of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.selectedProperties[0].enumValues[index];
|
||||||
|
$scope.selectedProperties[0].enumValues.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.selectedProperties[0].enumValues.splice(index + -1, 0, temp);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for down button
|
||||||
|
$scope.moveEnumValueDown = function() {
|
||||||
|
if ($scope.selectedProperties.length > 0 && $scope.selectedEnumValues.length > 0) {
|
||||||
|
var index = $scope.selectedProperties[0].enumValues.indexOf($scope.selectedEnumValues[0]);
|
||||||
|
if (index != $scope.selectedProperties[0].enumValues.length - 1) { // If it's the last element, no moving down of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.selectedProperties[0].enumValues[index];
|
||||||
|
$scope.selectedProperties[0].enumValues.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.selectedProperties[0].enumValues.splice(index + 1, 0, temp);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for save button
|
||||||
|
$scope.save = function() {
|
||||||
|
|
||||||
|
if ($scope.formProperties.length > 0) {
|
||||||
|
$scope.property.value = {};
|
||||||
|
$scope.property.value.formProperties = $scope.formProperties;
|
||||||
|
} else {
|
||||||
|
$scope.property.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function() {
|
||||||
|
$scope.$hide();
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
$scope.close = function() {
|
||||||
|
$scope.$hide();
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
};
|
||||||
|
|
||||||
|
}];
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Input parameters for call activity
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmInParametersCtrl = [ '$scope', '$modal', '$timeout', '$translate', function($scope, $modal, $timeout, $translate) {
|
||||||
|
|
||||||
|
// Config for the modal window
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/in-parameters-popup.html?version=' + Date.now(),
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the dialog
|
||||||
|
$modal(opts);
|
||||||
|
}];
|
||||||
|
|
||||||
|
var KisBpmInParametersPopupCtrl = ['$scope', '$q', '$translate', function($scope, $q, $translate) {
|
||||||
|
|
||||||
|
// Put json representing form properties on scope
|
||||||
|
if ($scope.property.value !== undefined && $scope.property.value !== null
|
||||||
|
&& $scope.property.value.inParameters !== undefined
|
||||||
|
&& $scope.property.value.inParameters !== null) {
|
||||||
|
// Note that we clone the json object rather then setting it directly,
|
||||||
|
// this to cope with the fact that the user can click the cancel button and no changes should have happened
|
||||||
|
$scope.parameters = angular.copy($scope.property.value.inParameters);
|
||||||
|
} else {
|
||||||
|
$scope.parameters = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
|
||||||
|
$scope.selectedParameters = [];
|
||||||
|
$scope.translationsRetrieved = false;
|
||||||
|
|
||||||
|
$scope.labels = {};
|
||||||
|
|
||||||
|
var sourcePromise = $translate('PROPERTY.PARAMETER.SOURCE');
|
||||||
|
var sourceExpressionPromise = $translate('PROPERTY.PARAMETER.SOURCEEXPRESSION');
|
||||||
|
var targetPromise = $translate('PROPERTY.PARAMETER.TARGET');
|
||||||
|
|
||||||
|
$q.all([sourcePromise, sourceExpressionPromise, targetPromise]).then(function(results) {
|
||||||
|
$scope.labels.sourceLabel = results[0];
|
||||||
|
$scope.labels.sourceExpressionLabel = results[1];
|
||||||
|
$scope.labels.targetLabel = results[2];
|
||||||
|
$scope.translationsRetrieved = true;
|
||||||
|
|
||||||
|
// Config for grid
|
||||||
|
$scope.gridOptions = {
|
||||||
|
data: 'parameters',
|
||||||
|
enableRowReordering: true,
|
||||||
|
headerRowHeight: 28,
|
||||||
|
multiSelect: false,
|
||||||
|
keepLastSelected : false,
|
||||||
|
selectedItems: $scope.selectedParameters,
|
||||||
|
columnDefs: [{ field: 'source', displayName: $scope.labels.sourceLabel },
|
||||||
|
{ field: 'sourceExpression', displayName: $scope.labels.sourceExpressionLabel },
|
||||||
|
{ field: 'target', displayName: $scope.labels.targetLabel }]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click handler for add button
|
||||||
|
$scope.addNewParameter = function() {
|
||||||
|
$scope.parameters.push({ source : '',
|
||||||
|
sourceExpression : '',
|
||||||
|
target : ''});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for remove button
|
||||||
|
$scope.removeParameter = function() {
|
||||||
|
if ($scope.selectedParameters.length > 0) {
|
||||||
|
var index = $scope.parameters.indexOf($scope.selectedParameters[0]);
|
||||||
|
$scope.gridOptions.selectItem(index, false);
|
||||||
|
$scope.parameters.splice(index, 1);
|
||||||
|
|
||||||
|
$scope.selectedParameters.length = 0;
|
||||||
|
if (index < $scope.parameters.length) {
|
||||||
|
$scope.gridOptions.selectItem(index + 1, true);
|
||||||
|
} else if ($scope.parameters.length > 0) {
|
||||||
|
$scope.gridOptions.selectItem(index - 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for up button
|
||||||
|
$scope.moveParameterUp = function() {
|
||||||
|
if ($scope.selectedParameters.length > 0) {
|
||||||
|
var index = $scope.parameters.indexOf($scope.selectedParameters[0]);
|
||||||
|
if (index != 0) { // If it's the first, no moving up of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.parameters[index];
|
||||||
|
$scope.parameters.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.parameters.splice(index + -1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for down button
|
||||||
|
$scope.moveParameterDown = function() {
|
||||||
|
if ($scope.selectedParameters.length > 0) {
|
||||||
|
var index = $scope.parameters.indexOf($scope.selectedParameters[0]);
|
||||||
|
if (index != $scope.parameters.length - 1) { // If it's the last element, no moving down of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.parameters[index];
|
||||||
|
$scope.parameters.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.parameters.splice(index + 1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for save button
|
||||||
|
$scope.save = function() {
|
||||||
|
|
||||||
|
if ($scope.parameters.length > 0) {
|
||||||
|
$scope.property.value = {};
|
||||||
|
$scope.property.value.inParameters = $scope.parameters;
|
||||||
|
} else {
|
||||||
|
$scope.property.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function() {
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
$scope.close = function() {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
}];
|
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Execution listeners
|
||||||
|
*/
|
||||||
|
|
||||||
|
angular.module('activitiModeler').controller('ActivitiMessageDefinitionsCtrl', ['$scope', '$modal', function ($scope, $modal) {
|
||||||
|
|
||||||
|
// Config for the modal window
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/message-definitions-popup.html?version=' + Date.now(),
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the dialog
|
||||||
|
$modal(opts);
|
||||||
|
}]);
|
||||||
|
|
||||||
|
//Need a separate controller for the modal window due to https://github.com/angular-ui/bootstrap/issues/259
|
||||||
|
// Will be fixed in a newer version of Angular UI
|
||||||
|
angular.module('activitiModeler').controller('ActivitiMessageDefinitionsPopupCtrl',
|
||||||
|
['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) {
|
||||||
|
|
||||||
|
// Put json representing mesage definitions on scope
|
||||||
|
if ($scope.property.value !== undefined && $scope.property.value !== null && $scope.property.value.length > 0) {
|
||||||
|
|
||||||
|
if ($scope.property.value.constructor == String) {
|
||||||
|
$scope.messageDefinitions = JSON.parse($scope.property.value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Note that we clone the json object rather then setting it directly,
|
||||||
|
// this to cope with the fact that the user can click the cancel button and no changes should have happened
|
||||||
|
$scope.messageDefinitions = angular.copy($scope.property.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$scope.messageDefinitions = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array to contain selected mesage definitions (yes - we only can select one, but ng-grid isn't smart enough)
|
||||||
|
$scope.selectedMessages = [];
|
||||||
|
$scope.translationsRetrieved = false;
|
||||||
|
|
||||||
|
$scope.labels = {};
|
||||||
|
|
||||||
|
var idPromise = $translate('PROPERTY.MESSAGEDEFINITIONS.ID');
|
||||||
|
var namePromise = $translate('PROPERTY.MESSAGEDEFINITIONS.NAME');
|
||||||
|
|
||||||
|
$q.all([idPromise, namePromise]).then(function (results) {
|
||||||
|
|
||||||
|
$scope.labels.idLabel = results[0];
|
||||||
|
$scope.labels.nameLabel = results[1];
|
||||||
|
$scope.translationsRetrieved = true;
|
||||||
|
|
||||||
|
// Config for grid
|
||||||
|
$scope.gridOptions = {
|
||||||
|
data: 'messageDefinitions',
|
||||||
|
headerRowHeight: 28,
|
||||||
|
enableRowSelection: true,
|
||||||
|
enableRowHeaderSelection: false,
|
||||||
|
multiSelect: false,
|
||||||
|
keepLastSelected : false,
|
||||||
|
selectedItems: $scope.selectedMessages,
|
||||||
|
columnDefs: [
|
||||||
|
{field: 'id', displayName: $scope.labels.idLabel},
|
||||||
|
{field: 'name', displayName: $scope.labels.nameLabel}]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click handler for add button
|
||||||
|
$scope.addNewMessageDefinition = function () {
|
||||||
|
var newMessageDefinition = {id: '', name: ''};
|
||||||
|
|
||||||
|
$scope.messageDefinitions.push(newMessageDefinition);
|
||||||
|
$timeout(function () {
|
||||||
|
$scope.gridOptions.selectItem($scope.messageDefinitions.length - 1, true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for remove button
|
||||||
|
$scope.removeMessageDefinition = function () {
|
||||||
|
if ($scope.selectedMessages && $scope.selectedMessages.length > 0) {
|
||||||
|
var index = $scope.messageDefinitions.indexOf($scope.selectedMessages[0]);
|
||||||
|
$scope.gridOptions.selectItem(index, false);
|
||||||
|
$scope.messageDefinitions.splice(index, 1);
|
||||||
|
|
||||||
|
$scope.selectedMessages.length = 0;
|
||||||
|
if (index < $scope.messageDefinitions.length) {
|
||||||
|
$scope.gridOptions.selectItem(index + 1, true);
|
||||||
|
} else if ($scope.messageDefinitions.length > 0) {
|
||||||
|
$scope.gridOptions.selectItem(index - 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for save button
|
||||||
|
$scope.save = function () {
|
||||||
|
|
||||||
|
if ($scope.messageDefinitions.length > 0) {
|
||||||
|
$scope.property.value = $scope.messageDefinitions;
|
||||||
|
} else {
|
||||||
|
$scope.property.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function () {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
$scope.close = function () {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
}]);
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
angular.module('activitiModeler').controller('ActivitiMessageRefCtrl', [ '$scope', function($scope) {
|
||||||
|
|
||||||
|
// Find the parent shape on which the message definitions are defined
|
||||||
|
var messageDefinitionsProperty = undefined;
|
||||||
|
var parent = $scope.selectedShape;
|
||||||
|
while (parent !== null && parent !== undefined && messageDefinitionsProperty === undefined) {
|
||||||
|
if (parent.properties && parent.properties['oryx-messagedefinitions']) {
|
||||||
|
messageDefinitionsProperty = parent.properties['oryx-messagedefinitions'];
|
||||||
|
} else {
|
||||||
|
parent = parent.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
messageDefinitionsProperty = JSON.parse(messageDefinitionsProperty);
|
||||||
|
if (typeof messageDefinitionsProperty == 'string') {
|
||||||
|
messageDefinitionsProperty = JSON.parse(messageDefinitionsProperty);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Do nothing here, just to be sure we try-catch it
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.messageDefinitions = messageDefinitionsProperty;
|
||||||
|
|
||||||
|
|
||||||
|
$scope.messageChanged = function() {
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Execution listeners
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmMultiInstanceCtrl = [ '$scope', function($scope) {
|
||||||
|
|
||||||
|
if ($scope.property.value == undefined && $scope.property.value == null)
|
||||||
|
{
|
||||||
|
$scope.property.value = 'None';
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.multiInstanceChanged = function() {
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
};
|
||||||
|
}];
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Input parameters for call activity
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmOutParametersCtrl = [ '$scope' , '$modal', '$timeout', '$translate', function($scope, $modal, $timeout, $translate) {
|
||||||
|
|
||||||
|
// Config for the modal window
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/out-parameters-popup.html?version=' + Date.now(),
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the dialog
|
||||||
|
$modal(opts);
|
||||||
|
}];
|
||||||
|
|
||||||
|
var KisBpmOutParametersPopupCtrl = [ '$scope', '$q', '$translate', function($scope, $q, $translate) {
|
||||||
|
|
||||||
|
// Put json representing form properties on scope
|
||||||
|
if ($scope.property.value !== undefined && $scope.property.value !== null
|
||||||
|
&& $scope.property.value.outParameters !== undefined
|
||||||
|
&& $scope.property.value.outParameters !== null) {
|
||||||
|
// Note that we clone the json object rather then setting it directly,
|
||||||
|
// this to cope with the fact that the user can click the cancel button and no changes should have happened
|
||||||
|
$scope.parameters = angular.copy($scope.property.value.outParameters);
|
||||||
|
} else {
|
||||||
|
$scope.parameters = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
|
||||||
|
$scope.selectedParameters = [];
|
||||||
|
$scope.translationsRetrieved = false;
|
||||||
|
|
||||||
|
$scope.labels = {};
|
||||||
|
|
||||||
|
var sourcePromise = $translate('PROPERTY.PARAMETER.SOURCE');
|
||||||
|
var sourceExpressionPromise = $translate('PROPERTY.PARAMETER.SOURCEEXPRESSION');
|
||||||
|
var targetPromise = $translate('PROPERTY.PARAMETER.TARGET');
|
||||||
|
|
||||||
|
$q.all([sourcePromise, sourceExpressionPromise, targetPromise]).then(function(results) {
|
||||||
|
$scope.labels.sourceLabel = results[0];
|
||||||
|
$scope.labels.sourceExpressionLabel = results[1];
|
||||||
|
$scope.labels.targetLabel = results[2];
|
||||||
|
$scope.translationsRetrieved = true;
|
||||||
|
|
||||||
|
// Config for grid
|
||||||
|
$scope.gridOptions = {
|
||||||
|
data: 'parameters',
|
||||||
|
enableRowReordering: true,
|
||||||
|
headerRowHeight: 28,
|
||||||
|
multiSelect: false,
|
||||||
|
keepLastSelected : false,
|
||||||
|
selectedItems: $scope.selectedParameters,
|
||||||
|
columnDefs: [{ field: 'source', displayName: $scope.labels.sourceLabel },
|
||||||
|
{ field: 'sourceExpression', displayName: $scope.labels.sourceExpressionLabel },
|
||||||
|
{ field: 'target', displayName: $scope.labels.targetLabel }]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click handler for add button
|
||||||
|
$scope.addNewParameter = function() {
|
||||||
|
$scope.parameters.push({ source : '',
|
||||||
|
sourceExpression : '',
|
||||||
|
target : ''});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for remove button
|
||||||
|
$scope.removeParameter = function() {
|
||||||
|
if ($scope.selectedParameters.length > 0) {
|
||||||
|
var index = $scope.parameters.indexOf($scope.selectedParameters[0]);
|
||||||
|
$scope.gridOptions.selectItem(index, false);
|
||||||
|
$scope.parameters.splice(index, 1);
|
||||||
|
|
||||||
|
$scope.selectedParameters.length = 0;
|
||||||
|
if (index < $scope.parameters.length) {
|
||||||
|
$scope.gridOptions.selectItem(index + 1, true);
|
||||||
|
} else if ($scope.parameters.length > 0) {
|
||||||
|
$scope.gridOptions.selectItem(index - 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for up button
|
||||||
|
$scope.moveParameterUp = function() {
|
||||||
|
if ($scope.selectedParameters.length > 0) {
|
||||||
|
var index = $scope.parameters.indexOf($scope.selectedParameters[0]);
|
||||||
|
if (index != 0) { // If it's the first, no moving up of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.parameters[index];
|
||||||
|
$scope.parameters.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.parameters.splice(index + -1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for down button
|
||||||
|
$scope.moveParameterDown = function() {
|
||||||
|
if ($scope.selectedParameters.length > 0) {
|
||||||
|
var index = $scope.parameters.indexOf($scope.selectedParameters[0]);
|
||||||
|
if (index != $scope.parameters.length - 1) { // If it's the last element, no moving down of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.parameters[index];
|
||||||
|
$scope.parameters.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.parameters.splice(index + 1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for save button
|
||||||
|
$scope.save = function() {
|
||||||
|
|
||||||
|
if ($scope.parameters.length > 0) {
|
||||||
|
$scope.property.value = {};
|
||||||
|
$scope.property.value.outParameters = $scope.parameters;
|
||||||
|
} else {
|
||||||
|
$scope.property.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function() {
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
$scope.close = function() {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
}];
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sequence flow order controller
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmSequenceFlowOrderCtrl = [ '$scope', '$modal', '$timeout', '$translate', function($scope, $modal, $timeout, $translate) {
|
||||||
|
|
||||||
|
// Config for the modal window
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/sequenceflow-order-popup.html?version=' + Date.now(),
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
$modal(opts);
|
||||||
|
}];
|
||||||
|
|
||||||
|
var KisBpmSequenceFlowOrderPopupCtrl = ['$scope', '$translate', function($scope, $translate) {
|
||||||
|
|
||||||
|
// Find the outgoing sequence flow of the current selected shape
|
||||||
|
var outgoingSequenceFlow = [];
|
||||||
|
var selectedShape = $scope.selectedShape;
|
||||||
|
if (selectedShape) {
|
||||||
|
var outgoingNodes = selectedShape.getOutgoingShapes();
|
||||||
|
for (var i=0; i<outgoingNodes.length; i++) {
|
||||||
|
if (outgoingNodes[i].getStencil().title() === 'Sequence flow') {
|
||||||
|
var targetActivity = outgoingNodes[i].getTarget();
|
||||||
|
// We need the resourceId of a sequence flow, not the id because that will change with every editor load
|
||||||
|
outgoingSequenceFlow.push({
|
||||||
|
id : outgoingNodes[i].resourceId,
|
||||||
|
targetTitle : targetActivity.properties['oryx-name'],
|
||||||
|
targetType : targetActivity.getStencil().title()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Programmatic error: no selected shape found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can apply the order which was (possibly) previously saved
|
||||||
|
var orderedOutgoingSequenceFlow = [];
|
||||||
|
if ($scope.property.value && $scope.property.value.sequenceFlowOrder) {
|
||||||
|
|
||||||
|
var sequenceFlowOrderList = $scope.property.value.sequenceFlowOrder;
|
||||||
|
|
||||||
|
// Loop the list of sequence flow that was saved in the json model and match them with the outgoing sequence flow found above
|
||||||
|
for (var flowIndex=0; flowIndex < sequenceFlowOrderList.length; flowIndex++) {
|
||||||
|
|
||||||
|
// find the sequence flow in the outgoing sequence flows.
|
||||||
|
|
||||||
|
for (var outgoingFlowIndex=0; outgoingFlowIndex < outgoingSequenceFlow.length; outgoingFlowIndex++) {
|
||||||
|
if (outgoingSequenceFlow[outgoingFlowIndex].id === sequenceFlowOrderList[flowIndex]) {
|
||||||
|
orderedOutgoingSequenceFlow.push(outgoingSequenceFlow[outgoingFlowIndex]);
|
||||||
|
outgoingSequenceFlow.splice(outgoingFlowIndex, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now all the matching sequence flow we're removed from the outgoing sequence flow list
|
||||||
|
// We can simply apply the remaining ones (these are new vs. the time when the values were saved to the model)
|
||||||
|
orderedOutgoingSequenceFlow = orderedOutgoingSequenceFlow.concat(outgoingSequenceFlow);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
orderedOutgoingSequenceFlow = outgoingSequenceFlow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we can put it on the scope
|
||||||
|
$scope.outgoingSequenceFlow = orderedOutgoingSequenceFlow;
|
||||||
|
|
||||||
|
// Move up click handler
|
||||||
|
$scope.moveUp = function(index) {
|
||||||
|
var temp = $scope.outgoingSequenceFlow[index];
|
||||||
|
$scope.outgoingSequenceFlow[index] = $scope.outgoingSequenceFlow[index - 1];
|
||||||
|
$scope.outgoingSequenceFlow[index - 1] = temp;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Move down click handler
|
||||||
|
$scope.moveDown = function(index) {
|
||||||
|
var temp = $scope.outgoingSequenceFlow[index];
|
||||||
|
$scope.outgoingSequenceFlow[index] = $scope.outgoingSequenceFlow[index + 1];
|
||||||
|
$scope.outgoingSequenceFlow[index + 1] = temp;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Save click handler
|
||||||
|
$scope.save = function() {
|
||||||
|
if ($scope.outgoingSequenceFlow.length > 0) {
|
||||||
|
$scope.property.value = {};
|
||||||
|
$scope.property.value.sequenceFlowOrder = [];
|
||||||
|
|
||||||
|
for (var flowIndex=0; flowIndex < $scope.outgoingSequenceFlow.length; flowIndex++) {
|
||||||
|
$scope.property.value.sequenceFlowOrder.push($scope.outgoingSequenceFlow[flowIndex].id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$scope.property.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Cancel click handler
|
||||||
|
$scope.cancel = function() {
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
$scope.close = function() {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
}];
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
angular.module('activitiModeler').controller('ActivitiSignalDefinitionsCtrl', ['$scope', '$modal', function ($scope, $modal) {
|
||||||
|
|
||||||
|
// Config for the modal window
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/signal-definitions-popup.html?version=' + Date.now(),
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the dialog
|
||||||
|
$modal(opts);
|
||||||
|
}]);
|
||||||
|
|
||||||
|
//Need a separate controller for the modal window due to https://github.com/angular-ui/bootstrap/issues/259
|
||||||
|
// Will be fixed in a newer version of Angular UI
|
||||||
|
angular.module('activitiModeler').controller('ActivitiSignalDefinitionsPopupCtrl',
|
||||||
|
['$scope', '$q', '$translate', '$timeout', function ($scope, $q, $translate, $timeout) {
|
||||||
|
|
||||||
|
// Put json representing signal definitions on scope
|
||||||
|
if ($scope.property.value !== undefined && $scope.property.value !== null && $scope.property.value.length > 0) {
|
||||||
|
|
||||||
|
if ($scope.property.value.constructor == String) {
|
||||||
|
$scope.signalDefinitions = JSON.parse($scope.property.value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Note that we clone the json object rather then setting it directly,
|
||||||
|
// this to cope with the fact that the user can click the cancel button and no changes should have happened
|
||||||
|
$scope.signalDefinitions = angular.copy($scope.property.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$scope.signalDefinitions = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array to contain selected signal definitions (yes - we only can select one, but ng-grid isn't smart enough)
|
||||||
|
$scope.selectedSignals = [];
|
||||||
|
$scope.translationsRetrieved = false;
|
||||||
|
|
||||||
|
$scope.labels = {};
|
||||||
|
|
||||||
|
var idPromise = $translate('PROPERTY.SIGNALDEFINITIONS.ID');
|
||||||
|
var namePromise = $translate('PROPERTY.SIGNALDEFINITIONS.NAME');
|
||||||
|
var scopePromise = $translate('PROPERTY.SIGNALDEFINITIONS.SCOPE');
|
||||||
|
|
||||||
|
$q.all([idPromise, namePromise, scopePromise]).then(function (results) {
|
||||||
|
|
||||||
|
$scope.labels.idLabel = results[0];
|
||||||
|
$scope.labels.nameLabel = results[1];
|
||||||
|
$scope.labels.scopeLabel = results[2];
|
||||||
|
$scope.translationsRetrieved = true;
|
||||||
|
|
||||||
|
// Config for grid
|
||||||
|
$scope.gridOptions = {
|
||||||
|
data: 'signalDefinitions',
|
||||||
|
headerRowHeight: 28,
|
||||||
|
enableRowSelection: true,
|
||||||
|
enableRowHeaderSelection: false,
|
||||||
|
multiSelect: false,
|
||||||
|
keepLastSelected : false,
|
||||||
|
selectedItems: $scope.selectedSignals,
|
||||||
|
columnDefs: [
|
||||||
|
{field: 'id', displayName: $scope.labels.idLabel},
|
||||||
|
{field: 'name', displayName: $scope.labels.nameLabel},
|
||||||
|
{field: 'scope', displayName: $scope.labels.scopeLabel}]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click handler for add button
|
||||||
|
$scope.addNewSignalDefinition = function () {
|
||||||
|
var newSignalDefinition = {id: '', name: '', scope: 'global'};
|
||||||
|
|
||||||
|
$scope.signalDefinitions.push(newSignalDefinition);
|
||||||
|
$timeout(function () {
|
||||||
|
$scope.gridOptions.selectItem($scope.signalDefinitions.length - 1, true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for remove button
|
||||||
|
$scope.removeSignalDefinition = function () {
|
||||||
|
if ($scope.selectedSignals && $scope.selectedSignals.length > 0) {
|
||||||
|
var index = $scope.signalDefinitions.indexOf($scope.selectedSignals[0]);
|
||||||
|
$scope.gridOptions.selectItem(index, false);
|
||||||
|
$scope.signalDefinitions.splice(index, 1);
|
||||||
|
|
||||||
|
$scope.selectedSignals.length = 0;
|
||||||
|
if (index < $scope.signalDefinitions.length) {
|
||||||
|
$scope.gridOptions.selectItem(index + 1, true);
|
||||||
|
} else if ($scope.signalDefinitions.length > 0) {
|
||||||
|
$scope.gridOptions.selectItem(index - 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for save button
|
||||||
|
$scope.save = function () {
|
||||||
|
|
||||||
|
if ($scope.signalDefinitions.length > 0) {
|
||||||
|
$scope.property.value = $scope.signalDefinitions;
|
||||||
|
} else {
|
||||||
|
$scope.property.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function () {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
$scope.close = function () {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
}]);
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
angular.module('activitiModeler').controller('ActivitiSignalRefCtrl', [ '$scope', function($scope) {
|
||||||
|
|
||||||
|
// Find the parent shape on which the signal definitions are defined
|
||||||
|
var signalDefinitionsProperty = undefined;
|
||||||
|
var parent = $scope.selectedShape;
|
||||||
|
while (parent !== null && parent !== undefined && signalDefinitionsProperty === undefined) {
|
||||||
|
if (parent.properties && parent.properties['oryx-signaldefinitions']) {
|
||||||
|
signalDefinitionsProperty = parent.properties['oryx-signaldefinitions'];
|
||||||
|
} else {
|
||||||
|
parent = parent.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
signalDefinitionsProperty = JSON.parse(signalDefinitionsProperty);
|
||||||
|
if (typeof signalDefinitionsProperty == 'string') {
|
||||||
|
signalDefinitionsProperty = JSON.parse(signalDefinitionsProperty);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Do nothing here, just to be sure we try-catch it
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.signalDefinitions = signalDefinitionsProperty;
|
||||||
|
|
||||||
|
|
||||||
|
$scope.signalChanged = function() {
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
};
|
||||||
|
}]);
|
|
@ -0,0 +1,325 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Task listeners
|
||||||
|
*/
|
||||||
|
|
||||||
|
var KisBpmTaskListenersCtrl = [ '$scope', '$modal', '$timeout', '$translate', function($scope, $modal, $timeout, $translate) {
|
||||||
|
|
||||||
|
// Config for the modal window
|
||||||
|
var opts = {
|
||||||
|
template: 'editor-app/configuration/properties/task-listeners-popup.html?version=' + Date.now(),
|
||||||
|
scope: $scope
|
||||||
|
};
|
||||||
|
|
||||||
|
// Open the dialog
|
||||||
|
$modal(opts);
|
||||||
|
}];
|
||||||
|
|
||||||
|
var KisBpmTaskListenersPopupCtrl = [ '$scope', '$q', '$translate', function($scope, $q, $translate) {
|
||||||
|
|
||||||
|
// Put json representing form properties on scope
|
||||||
|
if ($scope.property.value !== undefined && $scope.property.value !== null
|
||||||
|
&& $scope.property.value.taskListeners !== undefined
|
||||||
|
&& $scope.property.value.taskListeners !== null) {
|
||||||
|
|
||||||
|
if ($scope.property.value.taskListeners.constructor == String)
|
||||||
|
{
|
||||||
|
$scope.taskListeners = JSON.parse($scope.property.value.taskListeners);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Note that we clone the json object rather then setting it directly,
|
||||||
|
// this to cope with the fact that the user can click the cancel button and no changes should have happened
|
||||||
|
$scope.taskListeners = angular.copy($scope.property.value.taskListeners);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < $scope.taskListeners.length; i++)
|
||||||
|
{
|
||||||
|
var taskListener = $scope.taskListeners[i];
|
||||||
|
if (taskListener.className !== undefined && taskListener.className !== '')
|
||||||
|
{
|
||||||
|
taskListener.implementation = taskListener.className;
|
||||||
|
}
|
||||||
|
else if (taskListener.expression !== undefined && taskListener.expression !== '')
|
||||||
|
{
|
||||||
|
taskListener.implementation = taskListener.expression;
|
||||||
|
}
|
||||||
|
else if (taskListener.delegateExpression !== undefined && taskListener.delegateExpression !== '')
|
||||||
|
{
|
||||||
|
taskListener.implementation = taskListener.delegateExpression;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$scope.taskListeners = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array to contain selected properties (yes - we only can select one, but ng-grid isn't smart enough)
|
||||||
|
$scope.selectedListeners = [];
|
||||||
|
$scope.selectedFields = [];
|
||||||
|
$scope.translationsRetrieved = false;
|
||||||
|
|
||||||
|
$scope.labels = {};
|
||||||
|
|
||||||
|
var eventPromise = $translate('PROPERTY.TASKLISTENERS.EVENT');
|
||||||
|
var implementationPromise = $translate('PROPERTY.TASKLISTENERS.FIELDS.IMPLEMENTATION');
|
||||||
|
var namePromise = $translate('PROPERTY.TASKLISTENERS.FIELDS.NAME');
|
||||||
|
|
||||||
|
$q.all([eventPromise, implementationPromise, namePromise]).then(function(results) {
|
||||||
|
$scope.labels.eventLabel = results[0];
|
||||||
|
$scope.labels.implementationLabel = results[1];
|
||||||
|
$scope.labels.nameLabel = results[2];
|
||||||
|
$scope.translationsRetrieved = true;
|
||||||
|
|
||||||
|
// Config for grid
|
||||||
|
$scope.gridOptions = {
|
||||||
|
data: 'taskListeners',
|
||||||
|
enableRowReordering: true,
|
||||||
|
headerRowHeight: 28,
|
||||||
|
multiSelect: false,
|
||||||
|
keepLastSelected : false,
|
||||||
|
selectedItems: $scope.selectedListeners,
|
||||||
|
afterSelectionChange: function (rowItem, event) {
|
||||||
|
$scope.selectedFields.length = 0;
|
||||||
|
if ($scope.selectedListeners.length > 0)
|
||||||
|
{
|
||||||
|
var fields = $scope.selectedListeners[0].fields;
|
||||||
|
if (fields !== undefined && fields !== null)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < fields.length; i++)
|
||||||
|
{
|
||||||
|
var field = fields[i];
|
||||||
|
if (field.stringValue !== undefined && field.stringValue !== '')
|
||||||
|
{
|
||||||
|
field.implementation = field.stringValue;
|
||||||
|
}
|
||||||
|
else if (field.expression !== undefined && field.expression !== '')
|
||||||
|
{
|
||||||
|
field.implementation = field.expression;
|
||||||
|
}
|
||||||
|
else if (field.string !== undefined && field.string !== '')
|
||||||
|
{
|
||||||
|
field.implementation = field.string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
columnDefs: [{ field: 'event', displayName: $scope.labels.eventLabel },
|
||||||
|
{ field: 'implementation', displayName: $scope.labels.implementationLabel}]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Config for field grid
|
||||||
|
$scope.gridFieldOptions = {
|
||||||
|
data: 'selectedListeners[0].fields',
|
||||||
|
enableRowReordering: true,
|
||||||
|
headerRowHeight: 28,
|
||||||
|
multiSelect: false,
|
||||||
|
keepLastSelected : false,
|
||||||
|
selectedItems: $scope.selectedFields,
|
||||||
|
columnDefs: [{ field: 'name', displayName: $scope.labels.name },
|
||||||
|
{ field: 'implementation', displayName: $scope.labels.implementationLabel}]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.listenerDetailsChanged = function() {
|
||||||
|
if ($scope.selectedListeners[0].className !== '')
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].implementation = $scope.selectedListeners[0].className;
|
||||||
|
}
|
||||||
|
else if ($scope.selectedListeners[0].expression !== '')
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].implementation = $scope.selectedListeners[0].expression;
|
||||||
|
}
|
||||||
|
else if ($scope.selectedListeners[0].delegateExpression !== '')
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].implementation = $scope.selectedListeners[0].delegateExpression;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].implementation = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for add button
|
||||||
|
$scope.addNewListener = function() {
|
||||||
|
$scope.taskListeners.push({ event : 'create',
|
||||||
|
implementation : '',
|
||||||
|
className : '',
|
||||||
|
expression: '',
|
||||||
|
delegateExpression: ''});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for remove button
|
||||||
|
$scope.removeListener = function() {
|
||||||
|
if ($scope.selectedListeners.length > 0) {
|
||||||
|
var index = $scope.taskListeners.indexOf($scope.selectedListeners[0]);
|
||||||
|
$scope.gridOptions.selectItem(index, false);
|
||||||
|
$scope.taskListeners.splice(index, 1);
|
||||||
|
|
||||||
|
$scope.selectedListeners.length = 0;
|
||||||
|
if (index < $scope.taskListeners.length) {
|
||||||
|
$scope.gridOptions.selectItem(index + 1, true);
|
||||||
|
} else if ($scope.taskListeners.length > 0) {
|
||||||
|
$scope.gridOptions.selectItem(index - 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for up button
|
||||||
|
$scope.moveListenerUp = function() {
|
||||||
|
if ($scope.selectedListeners.length > 0) {
|
||||||
|
var index = $scope.taskListeners.indexOf($scope.selectedListeners[0]);
|
||||||
|
if (index != 0) { // If it's the first, no moving up of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.taskListeners[index];
|
||||||
|
$scope.taskListeners.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.taskListeners.splice(index + -1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for down button
|
||||||
|
$scope.moveListenerDown = function() {
|
||||||
|
if ($scope.selectedListeners.length > 0) {
|
||||||
|
var index = $scope.taskListeners.indexOf($scope.selectedListeners[0]);
|
||||||
|
if (index != $scope.taskListeners.length - 1) { // If it's the last element, no moving down of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.taskListeners[index];
|
||||||
|
$scope.taskListeners.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.taskListeners.splice(index + 1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.fieldDetailsChanged = function() {
|
||||||
|
if ($scope.selectedFields[0].stringValue != '')
|
||||||
|
{
|
||||||
|
$scope.selectedFields[0].implementation = $scope.selectedFields[0].stringValue;
|
||||||
|
}
|
||||||
|
else if ($scope.selectedFields[0].expression != '')
|
||||||
|
{
|
||||||
|
$scope.selectedFields[0].implementation = $scope.selectedFields[0].expression;
|
||||||
|
}
|
||||||
|
else if ($scope.selectedFields[0].string != '')
|
||||||
|
{
|
||||||
|
$scope.selectedFields[0].implementation = $scope.selectedFields[0].string;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$scope.selectedFields[0].implementation = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for add button
|
||||||
|
$scope.addNewField = function() {
|
||||||
|
if ($scope.selectedListeners.length > 0)
|
||||||
|
{
|
||||||
|
if ($scope.selectedListeners[0].fields == undefined)
|
||||||
|
{
|
||||||
|
$scope.selectedListeners[0].fields = [];
|
||||||
|
}
|
||||||
|
$scope.selectedListeners[0].fields.push({ name : 'fieldName',
|
||||||
|
implementation : '',
|
||||||
|
stringValue : '',
|
||||||
|
expression: '',
|
||||||
|
string: ''});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for remove button
|
||||||
|
$scope.removeField = function() {
|
||||||
|
if ($scope.selectedFields.length > 0) {
|
||||||
|
var index = $scope.selectedListeners[0].fields.indexOf($scope.selectedFields[0]);
|
||||||
|
$scope.gridFieldOptions.selectItem(index, false);
|
||||||
|
$scope.selectedListeners[0].fields.splice(index, 1);
|
||||||
|
|
||||||
|
$scope.selectedFields.length = 0;
|
||||||
|
if (index < $scope.selectedListeners[0].fields.length) {
|
||||||
|
$scope.gridFieldOptions.selectItem(index + 1, true);
|
||||||
|
} else if ($scope.selectedListeners[0].fields.length > 0) {
|
||||||
|
$scope.gridFieldOptions.selectItem(index - 1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for up button
|
||||||
|
$scope.moveFieldUp = function() {
|
||||||
|
if ($scope.selectedFields.length > 0) {
|
||||||
|
var index = $scope.selectedListeners[0].fields.indexOf($scope.selectedFields[0]);
|
||||||
|
if (index != 0) { // If it's the first, no moving up of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.selectedListeners[0].fields[index];
|
||||||
|
$scope.selectedListeners[0].fields.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.selectedListeners[0].fields.splice(index + -1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for down button
|
||||||
|
$scope.moveFieldDown = function() {
|
||||||
|
if ($scope.selectedFields.length > 0) {
|
||||||
|
var index = $scope.selectedListeners[0].fields.indexOf($scope.selectedFields[0]);
|
||||||
|
if (index != $scope.selectedListeners[0].fields.length - 1) { // If it's the last element, no moving down of course
|
||||||
|
// Reason for funny way of swapping, see https://github.com/angular-ui/ng-grid/issues/272
|
||||||
|
var temp = $scope.selectedListeners[0].fields[index];
|
||||||
|
$scope.selectedListeners[0].fields.splice(index, 1);
|
||||||
|
$timeout(function(){
|
||||||
|
$scope.selectedListeners[0].fields.splice(index + 1, 0, temp);
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Click handler for save button
|
||||||
|
$scope.save = function() {
|
||||||
|
|
||||||
|
if ($scope.taskListeners.length > 0) {
|
||||||
|
$scope.property.value = {};
|
||||||
|
$scope.property.value.taskListeners = $scope.taskListeners;
|
||||||
|
} else {
|
||||||
|
$scope.property.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.updatePropertyInModel($scope.property);
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.cancel = function() {
|
||||||
|
$scope.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
$scope.close = function() {
|
||||||
|
$scope.property.mode = 'read';
|
||||||
|
$scope.$hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
}];
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* Activiti Modeler component part of the Activiti project
|
||||||
|
* Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var KISBPM = KISBPM || {};
|
||||||
|
KISBPM.PROPERTY_CONFIG =
|
||||||
|
{
|
||||||
|
"string": {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/string-property-write-mode-template.html"
|
||||||
|
},
|
||||||
|
"boolean": {
|
||||||
|
"templateUrl": "editor-app/configuration/properties/boolean-property-template.html"
|
||||||
|
},
|
||||||
|
"text" : {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/text-property-write-template.html"
|
||||||
|
},
|
||||||
|
"kisbpm-multiinstance" : {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/multiinstance-property-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-formproperties-complex": {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/form-properties-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/form-properties-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-executionlisteners-multiplecomplex": {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/execution-listeners-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/execution-listeners-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-tasklisteners-multiplecomplex": {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/task-listeners-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/task-listeners-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-eventlisteners-multiplecomplex": {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/event-listeners-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/event-listeners-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-usertaskassignment-complex": {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/assignment-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/assignment-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-servicetaskfields-complex": {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/fields-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/fields-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-callactivityinparameters-complex": {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/in-parameters-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/in-parameters-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-callactivityoutparameters-complex": {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/out-parameters-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/out-parameters-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-subprocessreference-complex": {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/subprocess-reference-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/subprocess-reference-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-sequencefloworder-complex" : {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/sequenceflow-order-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/sequenceflow-order-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-conditionsequenceflow-complex" : {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/condition-expression-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/condition-expression-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-signaldefinitions-multiplecomplex" : {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/signal-definitions-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/signal-definitions-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-signalref-string" : {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/signal-property-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-messagedefinitions-multiplecomplex" : {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/message-definitions-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/message-definitions-write-template.html"
|
||||||
|
},
|
||||||
|
"oryx-messageref-string" : {
|
||||||
|
"readModeTemplateUrl": "editor-app/configuration/properties/default-value-display-template.html",
|
||||||
|
"writeModeTemplateUrl": "editor-app/configuration/properties/message-property-write-template.html"
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,4 @@
|
||||||
|
<span ng-if="property.value.assignment.assignee">{{'PROPERTY.ASSIGNMENT.ASSIGNEE_DISPLAY' | translate:property.value.assignment }} </span>
|
||||||
|
<span ng-if="property.value.assignment.candidateUsers.length > 0">{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS_DISPLAY' | translate:property.value.assignment.candidateUsers}} </span>
|
||||||
|
<span ng-if="property.value.assignment.candidateGroups.length > 0">{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS_DISPLAY' | translate:property.value.assignment.candidateGroups}} </span>
|
||||||
|
<span ng-if="!property.value.assignment.assignee && (!property.value.assignment.candidateUsers || property.value.assignment.candidateUsers.length == 0) && (!property.value.assignment.candidateGroups || property.value.assignment.candidateGroups.length == 0)" translate>PROPERTY.ASSIGNMENT.EMPTY</span>
|
|
@ -0,0 +1,44 @@
|
||||||
|
<div class="modal" ng-controller="KisBpmAssignmentPopupCtrl">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">×</button>
|
||||||
|
<h2 translate>PROPERTY.ASSIGNMENT.TITLE</h2>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<div class="row row-no-gutter">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="assigneeField">{{'PROPERTY.ASSIGNMENT.ASSIGNEE' | translate}}</label>
|
||||||
|
<input type="text" id="assigneeField" class="form-control" ng-model="assignment.assignee" placeholder="{{'PROPERTY.ASSIGNMENT.ASSIGNEE_PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row row-no-gutter">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="userField">{{'PROPERTY.ASSIGNMENT.CANDIDATE_USERS' | translate}}</label>
|
||||||
|
<div ng-repeat="candidateUser in assignment.candidateUsers">
|
||||||
|
<input id="userField" class="form-control" type="text" ng-model="candidateUser.value" />
|
||||||
|
<i class="glyphicon glyphicon-minus clickable-property" ng-click="removeCandidateUserValue($index)"></i>
|
||||||
|
<i ng-if="$index == (assignment.candidateUsers.length - 1)" class="glyphicon glyphicon-plus clickable-property" ng-click="addCandidateUserValue($index)"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="groupField">{{'PROPERTY.ASSIGNMENT.CANDIDATE_GROUPS' | translate}}</label>
|
||||||
|
<div ng-repeat="candidateGroup in assignment.candidateGroups">
|
||||||
|
<input id="groupField" class="form-control" type="text" ng-model="candidateGroup.value" />
|
||||||
|
<i class="glyphicon glyphicon-minus clickable-property" ng-click="removeCandidateGroupValue($index)"></i>
|
||||||
|
<i ng-if="$index == (assignment.candidateGroups.length - 1)" class="glyphicon glyphicon-plus clickable-property" ng-click="addCandidateGroupValue($index)"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button ng-click="close()" class="btn btn-primary" translate>ACTION.CANCEL</button>
|
||||||
|
<button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
|
||||||
|
<span ng-controller="KisBpmAssignmentCtrl">
|
||||||
|
</span>
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
<div ng-controller="KisBpmBooleanPropertyCtrl">
|
||||||
|
<input type="checkbox" ng-model="property.value" ng-change="changeValue()"/>
|
||||||
|
</div>
|
|
@ -0,0 +1,2 @@
|
||||||
|
<span ng-if="property.value">{{property.value|limitTo:20}}</span>
|
||||||
|
<span ng-if="!property.value">{{'PROPERTY.SEQUENCEFLOW.CONDITION.NO-CONDITION-DISPLAY' | translate}}</span>
|
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
<div class="modal" ng-controller="KisBpmConditionExpressionPopupCtrl">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">×</button>
|
||||||
|
<h2 translate>PROPERTY.SEQUENCEFLOW.CONDITION.TITLE</h2>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<div class="detail-group clearfix">
|
||||||
|
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<label class="col-xs-3">{{'PROPERTY.SEQUENCEFLOW.CONDITION.STATIC' | translate}}</label>
|
||||||
|
<div class="col-xs-9">
|
||||||
|
<textarea class="form-control" ng-model="conditionExpression.value" style="width:90%; height:100%; max-width: 100%; max-height: 100%; min-height: 100px"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button ng-click="close()" class="btn btn-primary" translate>ACTION.CANCEL</button>
|
||||||
|
<button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
|
||||||
|
<span ng-controller="KisBpmConditionExpressionCtrl">
|
||||||
|
</span>
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
<span ng-if="!property.noValue">{{property.value|limitTo:20}}</span>
|
||||||
|
<span ng-if="!property.noValue && property.value != null && property.value.length > 20">...</span>
|
||||||
|
<span ng-if="property.noValue" translate>PROPERTY.EMPTY</span>
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
<span ng-if="!property.noValue">{{'PROPERTY.EVENTLISTENERS.DISPLAY' | translate:property.value.eventListeners}}</span>
|
||||||
|
<span ng-if="property.noValue" translate>PROPERTY.EVENTLISTENERS.EMPTY</span>
|
|
@ -0,0 +1,115 @@
|
||||||
|
|
||||||
|
<div class="modal" ng-controller="KisBpmEventListenersPopupCtrl">
|
||||||
|
<div class="modal-dialog modal-wide">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">×</button>
|
||||||
|
<h2>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate:property}}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<div class="row row-no-gutter">
|
||||||
|
<div class="col-xs-10">
|
||||||
|
<div ng-if="translationsRetrieved" class="kis-listener-grid" ng-grid="gridOptions"></div>
|
||||||
|
<div class="pull-right">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.UP | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveListenerUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
|
||||||
|
<a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.DOWN | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveListenerDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
|
<a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.ADD | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewListener()"><i class="glyphicon glyphicon-plus"></i></a>
|
||||||
|
<a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.REMOVE | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeListener()"><i class="glyphicon glyphicon-minus"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row row-no-gutter">
|
||||||
|
<div ng-if="translationsRetrieved" ng-show="selectedListeners.length > 0" class="col-xs-6">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="userField">{{'PROPERTY.EVENTLISTENERS.EVENTS' | translate}}</label>
|
||||||
|
<div ng-repeat="eventDefinition in selectedListeners[0].events">
|
||||||
|
<select id="eventField" class="form-control" ng-model="eventDefinition.event" ng-change="listenerDetailsChanged()">
|
||||||
|
<option title="{{'EVENT_TYPE.ACTIVITY.COMPENSATE.TOOLTIP' | translate}}">ACTIVITY_COMPENSATE</option>
|
||||||
|
<option title="{{'EVENT_TYPE.ACTIVITY.COMPLETED.TOOLTIP' | translate}}">ACTIVITY_COMPLETED</option>
|
||||||
|
<option title="bla">ACTIVITY_ERROR_RECEIVED</option>
|
||||||
|
<option>ACTIVITY_MESSAGE_RECEIVED</option>
|
||||||
|
<option>ACTIVITY_SIGNALED</option>
|
||||||
|
<option>ACTIVITY_STARTED</option>
|
||||||
|
<option>ENGINE_CLOSED</option>
|
||||||
|
<option>ENGINE_CREATED</option>
|
||||||
|
<option>ENTITY_ACTIVATED</option>
|
||||||
|
<option>ENTITY_CREATED</option>
|
||||||
|
<option>ENTITY_DELETED</option>
|
||||||
|
<option>ENTITY_INITIALIZED</option>
|
||||||
|
<option>ENTITY_SUSPENDED</option>
|
||||||
|
<option>ENTITY_UPDATED</option>
|
||||||
|
<option>JOB_EXECUTION_FAILURE</option>
|
||||||
|
<option>JOB_EXECUTION_SUCCESS</option>
|
||||||
|
<option>JOB_RETRIES_DECREMENTED</option>
|
||||||
|
<option title="{{'EVENT_TYPE.MEMBERSHIP.CREATED.TOOLTIP' | translate}}">MEMBERSHIP_CREATED</option>
|
||||||
|
<option title="{{'EVENT_TYPE.MEMBERSHIP.DELETED.TOOLTIP' | translate}}">MEMBERSHIP_DELETED</option>
|
||||||
|
<option title="{{'EVENT_TYPE.MEMBERSHIPS.DELETED.TOOLTIP' | translate}}">MEMBERSHIPS_DELETED</option>
|
||||||
|
<option title="{{'EVENT_TYPE.TASK.ASSIGNED.TOOLTIP' | translate}}">TASK_ASSIGNED</option>
|
||||||
|
<option title="{{'EVENT_TYPE.TASK.COMPLETED.TOOLTIP' | translate}}">TASK_COMPLETED</option>
|
||||||
|
<option>TIMER_FIRED</option>
|
||||||
|
<option title="{{'EVENT_TYPE.UNCAUGHT.BPMNERROR.TOOLTIP' | translate}}">UNCAUGHT_BPMN_ERROR</option>
|
||||||
|
<option title="{{'EVENT_TYPE.VARIABLE.CREATED.TOOLTIP' | translate}}">VARIABLE_CREATED</option>
|
||||||
|
<option title="{{'EVENT_TYPE.VARIABLE.DELETED.TOOLTIP' | translate}}">VARIABLE_DELETED</option>
|
||||||
|
<option title="{{'EVENT_TYPE.VARIABLE.UPDATED.TOOLTIP' | translate}}">VARIABLE_UPDATED</option>
|
||||||
|
</select>
|
||||||
|
<i ng-if="$index > 0" class="glyphicon glyphicon-minus clickable-property" ng-click="removeEventValue($index)"></i>
|
||||||
|
<i class="glyphicon glyphicon-plus clickable-property" ng-click="addEventValue($index)"></i>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="classField">{{'PROPERTY.EVENTLISTENERS.RETHROW' | translate}}</label>
|
||||||
|
<input type="checkbox" id="rethrowField" class="form-control" ng-model="selectedListeners[0].rethrowEvent" ng-change="listenerDetailsChanged()" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-show="selectedListeners.length > 0 && selectedListeners[0].events[0].event" class="col-xs-6">
|
||||||
|
<div class="form-group" ng-if="!selectedListeners[0].rethrowEvent">
|
||||||
|
<label for="classField">{{'PROPERTY.EVENTLISTENERS.CLASS' | translate}}</label>
|
||||||
|
<input type="text" id="classField" class="form-control" ng-model="selectedListeners[0].className" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.CLASS.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group" ng-if="!selectedListeners[0].rethrowEvent">
|
||||||
|
<label for="delegateExpressionField">{{'PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION' | translate}}</label>
|
||||||
|
<input type="text" id="delegateExpressionField" class="form-control" ng-model="selectedListeners[0].delegateExpression" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group" ng-if="!selectedListeners[0].rethrowEvent">
|
||||||
|
<label for="entityTypeField">{{'PROPERTY.EVENTLISTENERS.ENTITYTYPE' | translate}}</label>
|
||||||
|
<input type="text" id="entityTypeField" class="form-control" ng-model="selectedListeners[0].entityType" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.ENTITYTYPE.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group" ng-if="selectedListeners[0].rethrowEvent">
|
||||||
|
<label for="delegateExpressionField">{{'PROPERTY.EVENTLISTENERS.RETHROWTYPE' | translate}}</label>
|
||||||
|
<select id="rethrowTypeField" class="form-control" ng-model="selectedListeners[0].rethrowType" ng-change="rethrowTypeChanged()">
|
||||||
|
<option>error</option>
|
||||||
|
<option>message</option>
|
||||||
|
<option>signal</option>
|
||||||
|
<option>globalSignal</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" ng-if="selectedListeners[0].rethrowType === 'error'">
|
||||||
|
<label for="errorCodeField">{{'PROPERTY.EVENTLISTENERS.ERRORCODE' | translate}}</label>
|
||||||
|
<input type="text" id="errorCodeField" class="form-control" ng-model="selectedListeners[0].errorcode" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.ERRORCODE.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group" ng-if="selectedListeners[0].rethrowType === 'message'">
|
||||||
|
<label for="messageNameField">{{'PROPERTY.EVENTLISTENERS.MESSAGENAME' | translate}}</label>
|
||||||
|
<input type="text" id="messageNameField" class="form-control" ng-model="selectedListeners[0].messagename" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.MESSAGENAME.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group" ng-if="selectedListeners[0].rethrowType === 'signal' || selectedListeners[0].rethrowType === 'globalSignal'">
|
||||||
|
<label for="messageNameField">{{'PROPERTY.EVENTLISTENERS.SIGNALNAME' | translate}}</label>
|
||||||
|
<input type="text" id="signalNameField" class="form-control" ng-model="selectedListeners[0].signalname" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EVENTLISTENERS.SIGNALNAME.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-show="selectedListeners.length == 0" class="col-xs-6 muted no-property-selected" translate>PROPERTY.EVENTLISTENERS.UNSELECTED</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
|
||||||
|
<button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
|
||||||
|
<span ng-controller="KisBpmEventListenersCtrl">
|
||||||
|
</span>
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
<span ng-if="!property.noValue">{{'PROPERTY.EXECUTIONLISTENERS.DISPLAY' | translate:property.value.executionListeners}}</span>
|
||||||
|
<span ng-if="property.noValue" translate>PROPERTY.EXECUTIONLISTENERS.EMPTY</span>
|
|
@ -0,0 +1,101 @@
|
||||||
|
|
||||||
|
<div class="modal" ng-controller="KisBpmExecutionListenersPopupCtrl">
|
||||||
|
<div class="modal-dialog modal-wide">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">×</button>
|
||||||
|
<h2>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate:property}}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<div class="row row-no-gutter">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div ng-if="translationsRetrieved" class="kis-listener-grid" ng-grid="gridOptions"></div>
|
||||||
|
<div class="pull-right">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.UP | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveListenerUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
|
||||||
|
<a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.DOWN | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveListenerDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
|
<a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.ADD | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewListener()"><i class="glyphicon glyphicon-plus"></i></a>
|
||||||
|
<a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.REMOVE | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeListener()"><i class="glyphicon glyphicon-minus"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div ng-show="selectedListeners.length > 0">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="eventField">{{'PROPERTY.EXECUTIONLISTENERS.EVENT' | translate}}</label>
|
||||||
|
<select id="eventField" class="form-control" ng-model="selectedListeners[0].event">
|
||||||
|
<option>start</option>
|
||||||
|
<option>end</option>
|
||||||
|
<option>take</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="classField">{{'PROPERTY.EXECUTIONLISTENERS.CLASS' | translate}}</label>
|
||||||
|
<input type="text" id="classField" class="form-control" ng-model="selectedListeners[0].className" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.CLASS.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="expressionField">{{'PROPERTY.EXECUTIONLISTENERS.EXPRESSION' | translate}}</label>
|
||||||
|
<input type="text" id="expressionField" class="form-control" ng-model="selectedListeners[0].expression" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.EXPRESSION.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="delegateExpressionField">{{'PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION' | translate}}</label>
|
||||||
|
<input type="text" id="delegateExpressionField" class="form-control" ng-model="selectedListeners[0].delegateExpression" ng-change="listenerDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.DELEGATEEXPRESSION.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ng-show="selectedListeners.length == 0" class="muted no-property-selected" translate>PROPERTY.EXECUTIONLISTENERS.UNSELECTED</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row row-no-gutter">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div ng-if="translationsRetrieved" class="kis-field-grid" ng-grid="gridFieldOptions"></div>
|
||||||
|
<div class="pull-right">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.UP | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveFieldUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
|
||||||
|
<a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.MOVE.DOWN | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveFieldDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
|
<a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.ADD | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewField()"><i class="glyphicon glyphicon-plus"></i></a>
|
||||||
|
<a class="btn btn-icon btn-lg" rel="tooltip" data-title="{{ACTION.REMOVE | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeField()"><i class="glyphicon glyphicon-minus"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div ng-show="selectedFields.length > 0">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="nameField">{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME' | translate}}</label>
|
||||||
|
<input type="text" id="nameField" class="form-control" ng-model="selectedFields[0].name" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.NAME.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="stringValueField">{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE' | translate}}</label>
|
||||||
|
<input type="text" id="stringValueField" class="form-control" ng-model="selectedFields[0].stringValue" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.STRINGVALUE.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="expressionField">{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION' | translate}}</label>
|
||||||
|
<input type="text" id="expressionField" class="form-control" ng-model="selectedFields[0].expression" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.EXPRESSION.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="stringField">{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING' | translate}}</label>
|
||||||
|
<textarea id="stringField" class="form-control" ng-model="selectedFields[0].string" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.EXECUTIONLISTENERS.FIELDS.STRING.PLACEHOLDER' | translate}}"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div ng-show="selectedFields.length == 0" class="muted no-property-selected"translate>PROPERTY.EXECUTIONLISTENERS.FIELDS.EMPTY</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
|
||||||
|
<button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
<!-- Just need to instantiate the controller, and it will take care of showing the modal dialog -->
|
||||||
|
<span ng-controller="KisBpmExecutionListenersCtrl">
|
||||||
|
</span>
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
<div class="modal" ng-controller="BpmnFeedbackPopupCtrl">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h2>{{'PROPERTY.FEEDBACK.TITLE' | translate:property}}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p><textarea auto-focus class="form-control" ng-model="model.feedback" style="width:90%; height:100%; max-width: 100%; max-height: 100%; min-height: 300px"/></p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button ng-click="cancel()" class="btn btn-primary" translate >ACTION.CANCEL</button>
|
||||||
|
<button ng-click="send()" ng-disabled="model.feedback.length === 0" class="btn btn-primary" translate >ACTION.SEND</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
<span ng-if="!property.noValue">{{'PROPERTY.FIELDS' | translate:property.value.fields}}</span>
|
||||||
|
<span ng-if="property.noValue">{{'PROPERTY.FIELDS.EMPTY' | translate}}</span>
|
|
@ -0,0 +1,61 @@
|
||||||
|
|
||||||
|
<div class="modal" ng-controller="KisBpmFieldsPopupCtrl">
|
||||||
|
<div class="modal-dialog modal-wide">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" ng-click="close()">×</button>
|
||||||
|
<h3>{{'PROPERTY.PROPERTY.EDIT.TITLE' | translate:property}}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
|
||||||
|
<div class="row row-no-gutter">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div ng-if="translationsRetrieved" class="kis-listener-grid" ng-grid="gridOptions"></div>
|
||||||
|
<div class="pull-right">
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="#" class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.MOVE.UP' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveFieldUp()"><i class="glyphicon glyphicon-arrow-up"></i></a>
|
||||||
|
<a href="#" class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.MOVE.DOWN' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="moveFieldDown()"><i class="glyphicon glyphicon-arrow-down"></i></a>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
|
<a href="#" class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.ADD' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="addNewField()"><i class="glyphicon glyphicon-plus"></i></a>
|
||||||
|
<a href="#" class="btn btn-icon btn-lg" rel="tooltip" data-title="{{'ACTION.REMOVE' | translate}}" data-placement="bottom" data-original-title="" title="" ng-click="removeField()"><i class="glyphicon glyphicon-minus"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<div ng-show="selectedFields.length > 0">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="fieldName">{{'PROPERTY.FIELDS.NAME' | translate}}</label>
|
||||||
|
<input type="text" id="fieldName" class="form-control" ng-model="selectedFields[0].name" placeholder="{{'PROPERTY.FIELDS.NAME.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="fieldStringValue">{{'PROPERTY.FIELDS.STRINGVALUE' | translate}}</label>
|
||||||
|
<input type="text" id="fieldStringValue" class="form-control" ng-model="selectedFields[0].stringValue" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.FIELDS.STRINGVALUE.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="fieldExpression">{{'PROPERTY.FIELDS.EXPRESSION' | translate}}</label>
|
||||||
|
<input type="text" id="fieldExpression" class="form-control" ng-model="selectedFields[0].expression" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.FIELDS.EXPRESSION.PLACEHOLDER' | translate}}" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="fieldString">{{'PROPERTY.FIELDS.STRING' | translate}}</label>
|
||||||
|
<textarea type="text" id="fieldString" class="form-control" ng-model="selectedFields[0].string" ng-change="fieldDetailsChanged()" placeholder="{{'PROPERTY.FIELDS.STRING.PLACEHOLDER' | translate}}"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div ng-show="selectedFields.length == 0" class="muted no-property-selected" translate>PROPERTY.FIELDS.EMPTY</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button ng-click="cancel()" class="btn btn-primary" translate>ACTION.CANCEL</button>
|
||||||
|
<button ng-click="save()" class="btn btn-primary" translate>ACTION.SAVE</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|